From 0b36bccc3d407a4d0de80095c409679c351e5fb1 Mon Sep 17 00:00:00 2001 From: Akiko Date: Sun, 7 Jun 2015 14:37:23 +0200 Subject: [PATCH 1/1] - initial commit of Genesis3D 1.6 --- ActView/ActView.dsp | 250 + ActView/ActView.dsw | 29 + ActView/ActView.mak | 250 + ActView/Doc/ACTVIEW.HLP | Bin 0 -> 16112 bytes ActView/Doc/ActView.CNT | 15 + ActView/Doc/ActView.doc | Bin 0 -> 47616 bytes ActView/Doc/ActView.err | 17 + ActView/Doc/ActView.hpj | 97 + ActView/Doc/ActView.rbh | 33 + ActView/Doc/ActView.rta | Bin 0 -> 59 bytes ActView/Doc/ActView.rtf | 68 + ActView/Doc/ActView.rtk | Bin 0 -> 1093 bytes ActView/Doc/ActView.rts | Bin 0 -> 1633 bytes ActView/Doc/ffend.bmp | Bin 0 -> 246 bytes ActView/Doc/ffframe.bmp | Bin 0 -> 246 bytes ActView/Doc/frame.bmp | Bin 0 -> 438 bytes ActView/Doc/move.bmp | Bin 0 -> 566 bytes ActView/Doc/pan.bmp | Bin 0 -> 246 bytes ActView/Doc/pause.bmp | Bin 0 -> 246 bytes ActView/Doc/play.bmp | Bin 0 -> 246 bytes ActView/Doc/rotate.bmp | Bin 0 -> 246 bytes ActView/Doc/rrframe.bmp | Bin 0 -> 246 bytes ActView/Doc/rrstart.bmp | Bin 0 -> 246 bytes ActView/Doc/stop.bmp | Bin 0 -> 246 bytes ActView/Doc/zoom.bmp | Bin 0 -> 246 bytes ActView/Main/ActView.aps | Bin 0 -> 87444 bytes ActView/Main/ActView.rc | 372 + ActView/Main/Blender.h | 57 + ActView/Main/actview.c | 2123 ++++ ActView/Main/actview.clw | 14 + ActView/Main/blender.c | 1808 +++ ActView/Main/resource.h | 133 + ActView/Util/About.c | 70 + ActView/Util/FilePath.c | 272 + ActView/Util/FilePath.h | 78 + ActView/Util/InstCheck.c | 97 + ActView/Util/InstCheck.h | 46 + ActView/Util/WinUtil.c | 97 + ActView/Util/WinUtil.h | 53 + ActView/Util/about.h | 35 + ActView/Util/drvlist.c | 240 + ActView/Util/drvlist.h | 40 + ActView/Util/rcstring.c | 56 + ActView/Util/rcstring.h | 50 + ActView/Util/units.h | 55 + ActView/res/actview.bmp | Bin 0 -> 19478 bytes ActView/res/actview.ico | Bin 0 -> 2238 bytes ActView/res/blend.ico | Bin 0 -> 766 bytes ActView/res/ffend.ico | Bin 0 -> 1078 bytes ActView/res/ffframe.ico | Bin 0 -> 1078 bytes ActView/res/irotate.ico | Bin 0 -> 766 bytes ActView/res/mainicon.ico | Bin 0 -> 766 bytes ActView/res/pan.cur | Bin 0 -> 326 bytes ActView/res/pan.ico | Bin 0 -> 766 bytes ActView/res/pause.ico | Bin 0 -> 1078 bytes ActView/res/play.ico | Bin 0 -> 1078 bytes ActView/res/rotate.cur | Bin 0 -> 326 bytes ActView/res/rotate.ico | Bin 0 -> 766 bytes ActView/res/rrframe.ico | Bin 0 -> 1078 bytes ActView/res/rrstart.ico | Bin 0 -> 1078 bytes ActView/res/stop.ico | Bin 0 -> 1078 bytes ActView/res/zoom.cur | Bin 0 -> 326 bytes ActView/res/zoom.ico | Bin 0 -> 766 bytes Exporters/3dseres.h | 53 + Exporters/3dsimp.h | 588 + Exporters/3dsires.h | 58 + Exporters/3dsmtl.cpp | 178 + Exporters/Cfile.h | 302 + Exporters/Kfio.h | 55 + Exporters/Mtldef.h | 223 + Exporters/Ofile.h | 270 + Exporters/Savemli.cpp | 516 + Exporters/gexp.cpp | 3937 ++++++ Exporters/gexp.def | 7 + Exporters/gexp.dsp | 293 + Exporters/gexp.h | 190 + Exporters/gexp.mak | 384 + Exporters/gexp.rc | 246 + Exporters/max2sdk/readme.txt | 1 + Exporters/max3sdk/readme.txt | 1 + Exporters/mssccprj.scc | 4 + G3D/Actor/QKFrame.c | 1182 ++ G3D/Actor/QKFrame.h | 151 + G3D/Actor/XFArray.c | 101 + G3D/Actor/actor.c | 2001 ++++ G3D/Actor/actor.h | 478 + G3D/Actor/body._h | 124 + G3D/Actor/body.c | 1283 ++ G3D/Actor/body.h | 136 + G3D/Actor/bodyinst.c | 369 + G3D/Actor/bodyinst.h | 128 + G3D/Actor/motion.c | 2190 ++++ G3D/Actor/motion.h | 180 + G3D/Actor/path.c | 1657 +++ G3D/Actor/path.h | 153 + G3D/Actor/pose.c | 1120 ++ G3D/Actor/pose.h | 169 + G3D/Actor/puppet.c | 1901 +++ G3D/Actor/puppet.h | 118 + G3D/Actor/strblock.c | 622 + G3D/Actor/strblock.h | 61 + G3D/Actor/tkarray.c | 411 + G3D/Actor/tkarray.h | 126 + G3D/Actor/tkevents.c | 688 ++ G3D/Actor/tkevents.h | 102 + G3D/Actor/vkframe.c | 845 ++ G3D/Actor/vkframe.h | 126 + G3D/Actor/xfarray.h | 64 + G3D/Afxres.h | 774 ++ G3D/Basetype.h | 85 + G3D/Bitmap/Compression/palcreate.c | 899 ++ G3D/Bitmap/Compression/palcreate.h | 50 + G3D/Bitmap/Compression/palettize.c | 563 + G3D/Bitmap/Compression/palettize.h | 54 + G3D/Bitmap/Compression/paloptimize.c | 247 + G3D/Bitmap/Compression/paloptimize.h | 42 + G3D/Bitmap/Compression/utility.h | 109 + G3D/Bitmap/Compression/yuv.c | 219 + G3D/Bitmap/Compression/yuv.h | 89 + G3D/Bitmap/bitmap.__h | 141 + G3D/Bitmap/bitmap._h | 71 + G3D/Bitmap/bitmap.c | 5681 +++++++++ G3D/Bitmap/bitmap.h | 627 + G3D/Bitmap/bitmap_blitdata.c | 1847 +++ G3D/Bitmap/bitmap_blitdata.h | 37 + G3D/Bitmap/bitmap_gamma.c | 604 + G3D/Bitmap/bitmap_gamma.h | 35 + G3D/Bitmap/pixelformat.c | 890 ++ G3D/Bitmap/pixelformat.h | 152 + G3D/CSNetMgr.c | 653 + G3D/CSNetMgr.h | 97 + G3D/Camera.c | 732 ++ G3D/Camera.h | 102 + G3D/Engine/BitmapList.c | 382 + G3D/Engine/BitmapList.h | 58 + G3D/Engine/Drivers/Bmp.c | 141 + G3D/Engine/Drivers/D3D7xDrv/D3DDrv.mak | 284 + G3D/Engine/Drivers/D3D7xDrv/D3DDrv.ncb | Bin 0 -> 214016 bytes G3D/Engine/Drivers/D3D7xDrv/D3DDrv.opt | Bin 0 -> 51712 bytes G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsp | 206 + G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsw | 29 + G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.ncb | Bin 0 -> 230400 bytes G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.opt | Bin 0 -> 50688 bytes G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.plg | 44 + G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.CPP | 271 + G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.H | 34 + G3D/Engine/Drivers/D3D7xDrv/D3d_fx.cpp | 308 + G3D/Engine/Drivers/D3D7xDrv/D3d_fx.h | 59 + G3D/Engine/Drivers/D3D7xDrv/D3d_main.cpp | 3071 +++++ G3D/Engine/Drivers/D3D7xDrv/D3d_main.h | 257 + G3D/Engine/Drivers/D3D7xDrv/D3dcache.cpp | 823 ++ G3D/Engine/Drivers/D3D7xDrv/D3dcache.h | 73 + G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.cpp | 377 + G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.h | 34 + G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.c | 195 + G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.h | 51 + G3D/Engine/Drivers/D3D7xDrv/GSPAN.H | 68 + G3D/Engine/Drivers/D3D7xDrv/Gspan.cpp | 287 + G3D/Engine/Drivers/D3D7xDrv/Pcache.cpp | 1547 +++ G3D/Engine/Drivers/D3D7xDrv/Pcache.h | 35 + G3D/Engine/Drivers/D3D7xDrv/RENDER.H | 34 + G3D/Engine/Drivers/D3D7xDrv/Render.cpp | 336 + G3D/Engine/Drivers/D3D7xDrv/SCENE.H | 46 + G3D/Engine/Drivers/D3D7xDrv/Scene.cpp | 232 + G3D/Engine/Drivers/D3D7xDrv/THandle.cpp | 886 ++ G3D/Engine/Drivers/D3D7xDrv/THandle.h | 116 + G3D/Engine/Drivers/D3D7xDrv/TPage.h | 98 + G3D/Engine/Drivers/D3D7xDrv/mssccprj.scc | 4 + G3D/Engine/Drivers/D3D7xDrv/tpage.cpp | 739 ++ G3D/Engine/Drivers/D3D8Drv/D3DDRV.H | 34 + G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsp | 199 + G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsw | 29 + G3D/Engine/Drivers/D3D8Drv/D3DDriver.ncb | Bin 0 -> 115712 bytes G3D/Engine/Drivers/D3D8Drv/D3DDriver.opt | Bin 0 -> 49664 bytes G3D/Engine/Drivers/D3D8Drv/D3DDriver.plg | 44 + G3D/Engine/Drivers/D3D8Drv/D3D_ERR.CPP | 273 + G3D/Engine/Drivers/D3D8Drv/D3D_ERR.H | 34 + G3D/Engine/Drivers/D3D8Drv/D3D_FX.H | 53 + G3D/Engine/Drivers/D3D8Drv/D3d_fx.cpp | 214 + G3D/Engine/Drivers/D3D8Drv/D3d_main.cpp | 2605 ++++ G3D/Engine/Drivers/D3D8Drv/D3d_main.h | 227 + G3D/Engine/Drivers/D3D8Drv/D3dcache.cpp | 694 ++ G3D/Engine/Drivers/D3D8Drv/D3dcache.h | 64 + G3D/Engine/Drivers/D3D8Drv/D3ddrv.cpp | 386 + G3D/Engine/Drivers/D3D8Drv/DDMemMgr.cpp | 174 + G3D/Engine/Drivers/D3D8Drv/DDMemMgr.h | 44 + G3D/Engine/Drivers/D3D8Drv/GSPAN.CPP | 279 + G3D/Engine/Drivers/D3D8Drv/GSPAN.H | 68 + G3D/Engine/Drivers/D3D8Drv/Pcache.cpp | 1273 ++ G3D/Engine/Drivers/D3D8Drv/Pcache.h | 35 + G3D/Engine/Drivers/D3D8Drv/RENDER.H | 34 + G3D/Engine/Drivers/D3D8Drv/Render.cpp | 246 + G3D/Engine/Drivers/D3D8Drv/SCENE.H | 46 + G3D/Engine/Drivers/D3D8Drv/Scene.cpp | 205 + G3D/Engine/Drivers/D3D8Drv/THandle.cpp | 743 ++ G3D/Engine/Drivers/D3D8Drv/THandle.h | 101 + G3D/Engine/Drivers/D3D8Drv/TPage.h | 69 + G3D/Engine/Drivers/D3D8Drv/tpage.cpp | 577 + G3D/Engine/Drivers/D3DDrv/D3DDRV.H | 34 + G3D/Engine/Drivers/D3DDrv/D3DDrv.dsp | 207 + G3D/Engine/Drivers/D3DDrv/D3DDrv.dsw | 29 + G3D/Engine/Drivers/D3DDrv/D3DDrv.mak | 284 + G3D/Engine/Drivers/D3DDrv/D3DDrv.ncb | Bin 0 -> 345088 bytes G3D/Engine/Drivers/D3DDrv/D3DDrv.opt | Bin 0 -> 50688 bytes G3D/Engine/Drivers/D3DDrv/D3DDrv.plg | 44 + G3D/Engine/Drivers/D3DDrv/D3D_ERR.CPP | 271 + G3D/Engine/Drivers/D3DDrv/D3D_ERR.H | 34 + G3D/Engine/Drivers/D3DDrv/D3d_fx.cpp | 211 + G3D/Engine/Drivers/D3DDrv/D3d_fx.h | 53 + G3D/Engine/Drivers/D3DDrv/D3d_main.cpp | 2817 +++++ G3D/Engine/Drivers/D3DDrv/D3d_main.h | 227 + G3D/Engine/Drivers/D3DDrv/D3dcache.cpp | 785 ++ G3D/Engine/Drivers/D3DDrv/D3dcache.h | 64 + G3D/Engine/Drivers/D3DDrv/D3ddrv.cpp | 368 + G3D/Engine/Drivers/D3DDrv/DDMemMgr.c | 195 + G3D/Engine/Drivers/D3DDrv/DDMemMgr.h | 51 + G3D/Engine/Drivers/D3DDrv/GSPAN.CPP | 281 + G3D/Engine/Drivers/D3DDrv/GSPAN.H | 68 + G3D/Engine/Drivers/D3DDrv/Pcache.cpp | 1463 +++ G3D/Engine/Drivers/D3DDrv/Pcache.h | 35 + G3D/Engine/Drivers/D3DDrv/README.NOW | 22 + G3D/Engine/Drivers/D3DDrv/RENDER.H | 34 + G3D/Engine/Drivers/D3DDrv/Render.cpp | 316 + G3D/Engine/Drivers/D3DDrv/SCENE.H | 46 + G3D/Engine/Drivers/D3DDrv/Scene.cpp | 217 + G3D/Engine/Drivers/D3DDrv/THandle.cpp | 846 ++ G3D/Engine/Drivers/D3DDrv/THandle.h | 106 + G3D/Engine/Drivers/D3DDrv/TPage.h | 69 + G3D/Engine/Drivers/D3DDrv/mssccprj.scc | 4 + G3D/Engine/Drivers/D3DDrv/tpage.cpp | 677 ++ G3D/Engine/Drivers/Dcommon.h | 502 + G3D/Engine/Drivers/GlideDrv/GCache.c | 716 ++ G3D/Engine/Drivers/GlideDrv/GCache.h | 66 + G3D/Engine/Drivers/GlideDrv/GLIDEDRV.H | 33 + G3D/Engine/Drivers/GlideDrv/GMain.c | 405 + G3D/Engine/Drivers/GlideDrv/GMain.h | 68 + G3D/Engine/Drivers/GlideDrv/GMemMgr.c | 148 + G3D/Engine/Drivers/GlideDrv/GMemMgr.h | 47 + G3D/Engine/Drivers/GlideDrv/GSpan.cpp | 278 + G3D/Engine/Drivers/GlideDrv/GSpan.h | 78 + G3D/Engine/Drivers/GlideDrv/GTHandle.h | 125 + G3D/Engine/Drivers/GlideDrv/GThandle.c | 843 ++ G3D/Engine/Drivers/GlideDrv/GlideDrv.c | 299 + G3D/Engine/Drivers/GlideDrv/GlideDrv.dsp | 229 + G3D/Engine/Drivers/GlideDrv/GlideDrv.dsw | 29 + G3D/Engine/Drivers/GlideDrv/GlideDrv.mak | 245 + G3D/Engine/Drivers/GlideDrv/GlideDrv.ncb | Bin 0 -> 107520 bytes G3D/Engine/Drivers/GlideDrv/GlideDrv.opt | Bin 0 -> 49664 bytes G3D/Engine/Drivers/GlideDrv/Render.c | 1407 +++ G3D/Engine/Drivers/GlideDrv/Render.h | 80 + G3D/Engine/Drivers/GlideDrv/mssccprj.scc | 4 + G3D/Engine/Drivers/OpenGl/OGLDrv.c | 411 + G3D/Engine/Drivers/OpenGl/OGLDrv.h | 59 + G3D/Engine/Drivers/OpenGl/OglDrv.dsp | 209 + G3D/Engine/Drivers/OpenGl/OglDrv.dsw | 29 + G3D/Engine/Drivers/OpenGl/OglMisc.c | 133 + G3D/Engine/Drivers/OpenGl/OglMisc.h | 29 + G3D/Engine/Drivers/OpenGl/Render.c | 641 + G3D/Engine/Drivers/OpenGl/Render.h | 65 + G3D/Engine/Drivers/OpenGl/THandle.c | 492 + G3D/Engine/Drivers/OpenGl/THandle.h | 69 + G3D/Engine/Drivers/OpenGl/Win32.c | 323 + G3D/Engine/Drivers/OpenGl/Win32.h | 42 + G3D/Engine/Drivers/OpenGl/glext.h | 255 + G3D/Engine/Drivers/SoftDrv/3dnowspan.h | 83 + G3D/Engine/Drivers/SoftDrv/REGISTER.H | 64 + G3D/Engine/Drivers/SoftDrv/RENDER.H | 128 + G3D/Engine/Drivers/SoftDrv/SAL.H | 308 + G3D/Engine/Drivers/SoftDrv/SCENE.H | 46 + G3D/Engine/Drivers/SoftDrv/SOFTDRV.H | 104 + G3D/Engine/Drivers/SoftDrv/SPAN.H | 59 + G3D/Engine/Drivers/SoftDrv/SYSTEM.H | 31 + G3D/Engine/Drivers/SoftDrv/SoftDrv.dsp | 304 + G3D/Engine/Drivers/SoftDrv/SoftDrv.mak | 319 + G3D/Engine/Drivers/SoftDrv/W32SAL.CPP | 1858 +++ G3D/Engine/Drivers/SoftDrv/amdspan.asm | 13922 ++++++++++++++++++++++ G3D/Engine/Drivers/SoftDrv/dmodes.c | 1506 +++ G3D/Engine/Drivers/SoftDrv/dmodes.h | 42 + G3D/Engine/Drivers/SoftDrv/drawspan.c | 1263 ++ G3D/Engine/Drivers/SoftDrv/drawspan.h | 69 + G3D/Engine/Drivers/SoftDrv/mssccprj.scc | 4 + G3D/Engine/Drivers/SoftDrv/register.c | 401 + G3D/Engine/Drivers/SoftDrv/render.c | 3418 ++++++ G3D/Engine/Drivers/SoftDrv/scene.c | 251 + G3D/Engine/Drivers/SoftDrv/softdrv.c | 946 ++ G3D/Engine/Drivers/SoftDrv/span.c | 103 + G3D/Engine/Drivers/SoftDrv/system.c | 67 + G3D/Engine/Drivers/SoftDrv/x86span555.c | 12561 +++++++++++++++++++ G3D/Engine/Drivers/SoftDrv/x86span555.h | 67 + G3D/Engine/Drivers/SoftDrv/x86span565.c | 13862 +++++++++++++++++++++ G3D/Engine/Drivers/SoftDrv/x86span565.h | 67 + G3D/Engine/Drivers/SoftDrv2/CPUInfo.c | 207 + G3D/Engine/Drivers/SoftDrv2/CPUInfo.h | 43 + G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.c | 891 ++ G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.h | 75 + G3D/Engine/Drivers/SoftDrv2/DIBDisplay.c | 834 ++ G3D/Engine/Drivers/SoftDrv2/DIBDisplay.h | 89 + G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.c | 128 + G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.h | 76 + G3D/Engine/Drivers/SoftDrv2/DrawDecal.c | 310 + G3D/Engine/Drivers/SoftDrv2/DrawDecal.h | 40 + G3D/Engine/Drivers/SoftDrv2/SWTHandle.c | 483 + G3D/Engine/Drivers/SoftDrv2/SWTHandle.h | 59 + G3D/Engine/Drivers/SoftDrv2/SoftDrv2.dsp | 297 + G3D/Engine/Drivers/SoftDrv2/SoftDrv2.mak | 292 + G3D/Engine/Drivers/SoftDrv2/Softdrv.h | 47 + G3D/Engine/Drivers/SoftDrv2/Span.h | 61 + G3D/Engine/Drivers/SoftDrv2/SpanBuffer.c | 279 + G3D/Engine/Drivers/SoftDrv2/SpanBuffer.h | 62 + G3D/Engine/Drivers/SoftDrv2/SpanEdges_Factory.h | 189 + G3D/Engine/Drivers/SoftDrv2/Span_AffineLoop.h | 179 + G3D/Engine/Drivers/SoftDrv2/Span_Factory.h | 273 + G3D/Engine/Drivers/SoftDrv2/TRaster.c | 344 + G3D/Engine/Drivers/SoftDrv2/Triangle.c | 394 + G3D/Engine/Drivers/SoftDrv2/display.c | 271 + G3D/Engine/Drivers/SoftDrv2/display.h | 98 + G3D/Engine/Drivers/SoftDrv2/mssccprj.scc | 4 + G3D/Engine/Drivers/SoftDrv2/rop.h | 78 + G3D/Engine/Drivers/SoftDrv2/softdrv.c | 1089 ++ G3D/Engine/Drivers/SoftDrv2/span.c | 471 + G3D/Engine/Drivers/SoftDrv2/traster.h | 76 + G3D/Engine/Drivers/SoftDrv2/triangle.h | 344 + G3D/Engine/Drivers/WireFrame/D3DDrv.dsp | 207 + G3D/Engine/Drivers/WireFrame/D3DDrv.dsw | 29 + G3D/Engine/Drivers/WireFrame/D3DDrv.mak | 284 + G3D/Engine/Drivers/WireFrame/D3DDrv.ncb | Bin 0 -> 377856 bytes G3D/Engine/Drivers/WireFrame/D3DDrv.opt | Bin 0 -> 48640 bytes G3D/Engine/Drivers/WireFrame/D3DDrv.plg | 44 + G3D/Engine/Drivers/WireFrame/D3d_err.cpp | 271 + G3D/Engine/Drivers/WireFrame/D3d_err.h | 34 + G3D/Engine/Drivers/WireFrame/D3d_fx.cpp | 211 + G3D/Engine/Drivers/WireFrame/D3d_fx.h | 53 + G3D/Engine/Drivers/WireFrame/D3d_main.cpp | 2749 +++++ G3D/Engine/Drivers/WireFrame/D3d_main.h | 227 + G3D/Engine/Drivers/WireFrame/D3dcache.cpp | 785 ++ G3D/Engine/Drivers/WireFrame/D3dcache.h | 64 + G3D/Engine/Drivers/WireFrame/D3ddrv.cpp | 368 + G3D/Engine/Drivers/WireFrame/D3ddrv.h | 34 + G3D/Engine/Drivers/WireFrame/DDMemMgr.c | 195 + G3D/Engine/Drivers/WireFrame/DDMemMgr.h | 51 + G3D/Engine/Drivers/WireFrame/Gspan.cpp | 281 + G3D/Engine/Drivers/WireFrame/Gspan.h | 68 + G3D/Engine/Drivers/WireFrame/Pcache.cpp | 1445 +++ G3D/Engine/Drivers/WireFrame/Pcache.h | 35 + G3D/Engine/Drivers/WireFrame/Readme.now | 22 + G3D/Engine/Drivers/WireFrame/Render.cpp | 316 + G3D/Engine/Drivers/WireFrame/Render.h | 34 + G3D/Engine/Drivers/WireFrame/Scene.cpp | 217 + G3D/Engine/Drivers/WireFrame/Scene.h | 46 + G3D/Engine/Drivers/WireFrame/THandle.cpp | 846 ++ G3D/Engine/Drivers/WireFrame/THandle.h | 106 + G3D/Engine/Drivers/WireFrame/TPage.h | 69 + G3D/Engine/Drivers/WireFrame/mssccprj.scc | 4 + G3D/Engine/Drivers/WireFrame/tpage.cpp | 677 ++ G3D/Engine/Logo/A_CORONA.c | 899 ++ G3D/Engine/Logo/A_STREAK.c | 899 ++ G3D/Engine/Logo/CORONA.c | 899 ++ G3D/Engine/Logo/LogoActor.c | 7356 ++++++++++++ G3D/Engine/Logo/WebUrl.c | 3356 ++++++ G3D/Engine/Logo/electric.c | 333 + G3D/Engine/Logo/electric.h | 88 + G3D/Engine/Logo/logo.c | 513 + G3D/Engine/Logo/poweredby.c | 3308 +++++ G3D/Engine/Logo/streak.c | 899 ++ G3D/Engine/Sound.c | 1068 ++ G3D/Engine/System.c | 504 + G3D/Engine/System.h | 235 + G3D/Engine/engine.c | 2199 ++++ G3D/Engine/engine.h | 124 + G3D/Engine/fontbmp.c | 849 ++ G3D/Engine/genesis3d.c | 12588 +++++++++++++++++++ G3D/Entities/ENTITIES.H | 142 + G3D/Entities/Entities.c | 1117 ++ G3D/Font/font.H | 269 + G3D/Font/font.c | 1366 +++ G3D/Font/wgClip.H | 47 + G3D/Font/wgClip.c | 118 + G3D/Ge.c | 368 + G3D/Genesis.aps | Bin 0 -> 17656 bytes G3D/Genesis.dsp | 790 ++ G3D/Genesis.dsw | 29 + G3D/Genesis.h | 664 ++ G3D/Genesis.mak | 925 ++ G3D/GenesisDLL.dsp | 802 ++ G3D/GenesisDLL.dsw | 29 + G3D/GenesisDLL.mak | 960 ++ G3D/Math/Box.c | 209 + G3D/Math/Box.h | 63 + G3D/Math/ExtBox.c | 496 + G3D/Math/ExtBox.h | 94 + G3D/Math/VEC3D.C | 298 + G3D/Math/VEC3D.H | 70 + G3D/Math/Xform3d.c | 848 ++ G3D/Math/Xform3d.h | 225 + G3D/Math/crc32.c | 159 + G3D/Math/crc32.h | 45 + G3D/Math/quatern.c | 808 ++ G3D/Math/quatern.h | 237 + G3D/Netplay.c | 863 ++ G3D/Netplay.h | 76 + G3D/Physics/PhysicsJoint.c | 268 + G3D/Physics/PhysicsJoint.h | 68 + G3D/Physics/PhysicsObject.c | 864 ++ G3D/Physics/PhysicsObject.h | 137 + G3D/Physics/PhysicsSystem.c | 841 ++ G3D/Physics/PhysicsSystem.h | 54 + G3D/Physics/matrix33.c | 201 + G3D/Physics/matrix33.h | 51 + G3D/Ptrtypes.h | 67 + G3D/RCa24739 | Bin 0 -> 5060 bytes G3D/RCb24739 | Bin 0 -> 5060 bytes G3D/RCc24739 | Bin 0 -> 5060 bytes G3D/RCd24739 | Bin 0 -> 5060 bytes G3D/Sound.c | 1083 ++ G3D/Sound.h | 76 + G3D/Sound3d.c | 214 + G3D/Sound3d.h | 60 + G3D/Support/ERRORLOG.C | 189 + G3D/Support/Errorlog.h | 238 + G3D/Support/RAM.H | 140 + G3D/Support/Ram.c | 550 + G3D/Support/geAssert.c | 134 + G3D/Support/geAssert.h | 67 + G3D/Support/log.c | 56 + G3D/Support/log.h | 48 + G3D/Support/mempool.c | 331 + G3D/Support/mempool.h | 48 + G3D/Support/ramdll.c | 25 + G3D/Tclip.c | 571 + G3D/VFile/FSMEMORY.C | 505 + G3D/VFile/FSMEMORY.H | 28 + G3D/VFile/dirtree-common.c | 106 + G3D/VFile/dirtree-common.h | 53 + G3D/VFile/dirtree.c | 732 ++ G3D/VFile/dirtree.h | 90 + G3D/VFile/fsdos.c | 922 ++ G3D/VFile/fsdos.h | 28 + G3D/VFile/fsvfs.c | 899 ++ G3D/VFile/fsvfs.h | 30 + G3D/VFile/vfile._h | 103 + G3D/VFile/vfile.c | 618 + G3D/VFile/vfile.h | 192 + G3D/VFile/vfile_structs.h | 52 + G3D/Winres.h | 45 + G3D/Winresrc.h | 27 + G3D/World/FRUSTUM.H | 111 + G3D/World/Fog.c | 111 + G3D/World/Fog.h | 83 + G3D/World/Frustum.c | 1223 ++ G3D/World/Gbspfile.c | 617 + G3D/World/Gbspfile.h | 355 + G3D/World/Light.c | 2020 ++++ G3D/World/Light.h | 114 + G3D/World/PLANE.H | 57 + G3D/World/Plane.c | 226 + G3D/World/SURFACE.H | 116 + G3D/World/Surface.c | 646 + G3D/World/TRACE.H | 141 + G3D/World/Trace.c | 2359 ++++ G3D/World/USER.H | 124 + G3D/World/User.c | 1104 ++ G3D/World/VIS.H | 52 + G3D/World/Vis.c | 510 + G3D/World/WBitmap.c | 570 + G3D/World/WBitmap.h | 86 + G3D/World/World.c | 3505 ++++++ G3D/World/World.h | 315 + G3D/drawbbox.c | 67 + G3D/genesis.rc | 109 + G3D/getypes.h | 140 + G3D/list.c | 1415 +++ G3D/list.h | 234 + G3D/mssccprj.scc | 7 + G3D/resource.h | 15 + G3D/sprite.c | 1430 +++ G3D/sprite.h | 210 + G3D/tclip.h | 76 + G3D/timer.c | 41 + G3D/timer.h | 118 + G3D/tsc.c | 135 + G3D/tsc.h | 65 + GBSPLib/BRUSH2.H | 94 + GBSPLib/BSP.CPP | 432 + GBSPLib/Brush2.cpp | 1382 +++ GBSPLib/Bsp.h | 267 + GBSPLib/Bsp2.cpp | 1521 +++ GBSPLib/Fill.Cpp | 436 + GBSPLib/Fill.h | 31 + GBSPLib/GBSPFILE.CPP | 625 + GBSPLib/GBSPLib.dsp | 247 + GBSPLib/GBSPLib.dsw | 29 + GBSPLib/GBSPLib.mak | 352 + GBSPLib/GBSPPREP.CPP | 1131 ++ GBSPLib/GBSPPREP.H | 35 + GBSPLib/Gbspfile.h | 353 + GBSPLib/Gbsplib.cpp | 274 + GBSPLib/Gbsplib.h | 118 + GBSPLib/Leaf.cpp | 612 + GBSPLib/Leaf.h | 43 + GBSPLib/Light.cpp | 2411 ++++ GBSPLib/Light.h | 187 + GBSPLib/MATHLIB.CPP | 145 + GBSPLib/MATHLIB.H | 56 + GBSPLib/Map.cpp | 758 ++ GBSPLib/Map.h | 122 + GBSPLib/POLY.CPP | 1827 +++ GBSPLib/POLY.H | 72 + GBSPLib/PORTALS.CPP | 687 ++ GBSPLib/PORTALS.H | 41 + GBSPLib/PortFile.cpp | 410 + GBSPLib/RAD.CPP | 1848 +++ GBSPLib/TEXTURE.CPP | 445 + GBSPLib/TEXTURE.H | 62 + GBSPLib/TJunct.cpp | 512 + GBSPLib/Utils.cpp | 135 + GBSPLib/Utils.h | 40 + GBSPLib/VIS.CPP | 675 ++ GBSPLib/VISFLOOD.CPP | 596 + GBSPLib/Vis.h | 82 + GBSPLib/build.bat | 55 + GBSPLib/mssccprj.scc | 4 + crafty102/Crafty.exe | Bin 0 -> 3391488 bytes crafty102/DevIL.dll | Bin 0 -> 864256 bytes crafty102/Fonts/CourierNew.csf | 13 + crafty102/Fonts/CourierNew.tga | Bin 0 -> 49196 bytes crafty102/Fonts/FontSchema.csf | 41 + crafty102/HLLib.dll | Bin 0 -> 237568 bytes crafty102/ILU.dll | Bin 0 -> 81920 bytes crafty102/Readme.txt | 304 + crafty102/SketchUpReader.dll | Bin 0 -> 3817472 bytes crafty102/Specifications/GameInfo.csf | 1045 ++ crafty102/Specifications/GameInfoCustom.csf | 246 + crafty102/Specifications/GameInfoSchema.csf | 203 + crafty102/VTFLib.dll | Bin 0 -> 585728 bytes crafty102/gdal12.dll | Bin 0 -> 2560000 bytes crafty102/xerces-c_2_6.dll | Bin 0 -> 2359296 bytes include/Basetype.h | 85 + include/Errorlog.h | 238 + include/ExtBox.h | 94 + include/Genesis.h | 664 ++ include/PhysicsJoint.h | 68 + include/PhysicsObject.h | 137 + include/PhysicsSystem.h | 54 + include/RAM.H | 140 + include/VEC3D.H | 70 + include/Xform3d.h | 225 + include/actor.h | 478 + include/bitmap.h | 627 + include/body.h | 136 + include/font.H | 269 + include/getypes.h | 140 + include/matrix33.h | 51 + include/motion.h | 180 + include/path.h | 153 + include/pixelformat.h | 152 + include/quatern.h | 237 + include/sprite.h | 210 + include/vfile.h | 192 + mkactor/AStudio.dsp | 421 + mkactor/AStudio.dsw | 29 + mkactor/AStudio/AOptions.c | 145 + mkactor/AStudio/AOptions.h | 57 + mkactor/AStudio/AProject.c | 1593 +++ mkactor/AStudio/AProject.h | 182 + mkactor/AStudio/AStudio.cpp | 249 + mkactor/AStudio/AStudio.h | 71 + mkactor/AStudio/AStudio.rc | 546 + mkactor/AStudio/BodyDlg.cpp | 266 + mkactor/AStudio/BodyDlg.h | 92 + mkactor/AStudio/HLP/ASTUDIO.HLP | Bin 0 -> 5992 bytes mkactor/AStudio/HLP/AStudio.LOG | 46 + mkactor/AStudio/HLP/AStudio.cnt | 3 + mkactor/AStudio/HLP/AStudio.hm | 40 + mkactor/AStudio/HLP/AStudio.hpj | 58 + mkactor/AStudio/HLP/AStudio.ph | 0 mkactor/AStudio/HLP/AfxDlg.rtf | 20 + mkactor/AStudio/LogoPage.cpp | 64 + mkactor/AStudio/LogoPage.h | 71 + mkactor/AStudio/MakeHelp.bat | 39 + mkactor/AStudio/MakeHelp.cpp | 216 + mkactor/AStudio/MakeHelp.h | 46 + mkactor/AStudio/MaterialsDlg.cpp | 632 + mkactor/AStudio/MaterialsDlg.h | 108 + mkactor/AStudio/MotionsDlg.cpp | 732 ++ mkactor/AStudio/MotionsDlg.h | 114 + mkactor/AStudio/MyFileDlg.cpp | 55 + mkactor/AStudio/MyFileDlg.h | 38 + mkactor/AStudio/NewPrjDlg.cpp | 80 + mkactor/AStudio/NewPrjDlg.h | 68 + mkactor/AStudio/PathsDlg.cpp | 141 + mkactor/AStudio/PathsDlg.h | 84 + mkactor/AStudio/PropPage.cpp | 80 + mkactor/AStudio/PropPage.h | 68 + mkactor/AStudio/PropSheet.cpp | 1024 ++ mkactor/AStudio/PropSheet.h | 136 + mkactor/AStudio/RCa91691 | Bin 0 -> 35540 bytes mkactor/AStudio/RES/ACTVIEW.BMP | Bin 0 -> 19478 bytes mkactor/AStudio/RES/AStudio.ico | Bin 0 -> 766 bytes mkactor/AStudio/RES/AStudio.rc2 | 13 + mkactor/AStudio/SettingsDlg.cpp | 193 + mkactor/AStudio/SettingsDlg.h | 91 + mkactor/AStudio/StdAfx.cpp | 27 + mkactor/AStudio/StdAfx.h | 46 + mkactor/AStudio/TargetDlg.cpp | 188 + mkactor/AStudio/TargetDlg.h | 89 + mkactor/AStudio/TextInputDlg.cpp | 79 + mkactor/AStudio/TextInputDlg.h | 70 + mkactor/AStudio/Util/ARRAY.H | 96 + mkactor/AStudio/Util/Array.c | 500 + mkactor/AStudio/Util/FilePath.c | 272 + mkactor/AStudio/Util/FilePath.h | 79 + mkactor/AStudio/Util/RCSTRING.C | 58 + mkactor/AStudio/Util/RCSTRING.H | 52 + mkactor/AStudio/Util/UTIL.C | 268 + mkactor/AStudio/Util/UTIL.H | 49 + mkactor/AStudio/make.c | 1833 +++ mkactor/AStudio/make.h | 53 + mkactor/AStudio/mxscript.c | 302 + mkactor/AStudio/mxscript.h | 54 + mkactor/AStudio/resource.h | 173 + mkactor/ActBuild.dsp | 242 + mkactor/ActBuild.dsw | 29 + mkactor/ActBuild/ActBuild.c | 213 + mkactor/ActBuild/ActBuild.h | 46 + mkactor/common/TDBody.c | 180 + mkactor/common/TDBody.h | 46 + mkactor/common/maxmath.c | 355 + mkactor/common/maxmath.h | 39 + mkactor/common/mkutil.c | 289 + mkactor/common/mkutil.h | 56 + mkactor/fmtactor/fmtactor.c | 407 + mkactor/fmtactor/fmtactor.h | 43 + mkactor/mkactor/mkactor.c | 361 + mkactor/mkactor/mkactor.h | 46 + mkactor/mkbody/mkbody.cpp | 2427 ++++ mkactor/mkbody/mkbody.h | 46 + mkactor/mkbody/vph.c | 523 + mkactor/mkbody/vph.h | 35 + mkactor/mkmotion/mkmotion.c | 1113 ++ mkactor/mkmotion/mkmotion.h | 46 + mkactor/mop/Log.c | 296 + mkactor/mop/Log.h | 80 + mkactor/mop/mopshell.c | 540 + mkactor/mop/mopshell.h | 46 + mkactor/mop/pop.c | 563 + mkactor/mop/pop.h | 44 + rfPack/BUILD.BAT | 46 + rfPack/PULL.BAT | 37 + rfPack/RES/MAINICON.ICO | Bin 0 -> 766 bytes rfPack/RES/rfpack.ico | Bin 0 -> 2238 bytes rfPack/Source/TPack.aps | Bin 0 -> 43868 bytes rfPack/Source/TPack.c | 1449 +++ rfPack/Source/TPack.rc | 149 + rfPack/Source/resource.h | 142 + rfPack/rfPack.dsp | 183 + rfPack/rfPack.dsw | 29 + rfvfs/Delete.cpp | 43 + rfvfs/Delete.h | 46 + rfvfs/EllepticalButton.cpp | 422 + rfvfs/EllepticalButton.h | 82 + rfvfs/EncryptKey.cpp | 44 + rfvfs/EncryptKey.h | 46 + rfvfs/FileTreeCtrl.cpp | 1427 +++ rfvfs/FileTreeCtrl.h | 185 + rfvfs/MFileDlg.cpp | 49 + rfvfs/MFileDlg.h | 34 + rfvfs/MakeDir.cpp | 45 + rfvfs/MakeDir.h | 47 + rfvfs/ReadMe.txt | 293 + rfvfs/Rename.cpp | 52 + rfvfs/Rename.h | 49 + rfvfs/SortedArray.h | 276 + rfvfs/StdAfx.cpp | 8 + rfvfs/StdAfx.h | 27 + rfvfs/res/icon1.ico | Bin 0 -> 2238 bytes rfvfs/res/rfvfs.ico | Bin 0 -> 1078 bytes rfvfs/res/rfvfs.rc2 | 13 + rfvfs/res/tfdropcopy.cur | Bin 0 -> 326 bytes rfvfs/res/tfnodropcopy.cur | Bin 0 -> 326 bytes rfvfs/res/tfnodropmove.cur | Bin 0 -> 326 bytes rfvfs/resource.h | 36 + rfvfs/rfvfs.aps | Bin 0 -> 41392 bytes rfvfs/rfvfs.clw | 134 + rfvfs/rfvfs.cpp | 80 + rfvfs/rfvfs.dsp | 220 + rfvfs/rfvfs.dsw | 29 + rfvfs/rfvfs.h | 50 + rfvfs/rfvfs.rc | 279 + rfvfs/rfvfsDlg.cpp | 873 ++ rfvfs/rfvfsDlg.h | 88 + ttf2pcx/ColorButton.cpp | 446 + ttf2pcx/ColorButton.h | 186 + ttf2pcx/ColourPopup.cpp | 911 ++ ttf2pcx/ColourPopup.h | 129 + ttf2pcx/character.cpp | 98 + ttf2pcx/character.h | 22 + ttf2pcx/previewbutton.cpp | 59 + ttf2pcx/previewbutton.h | 39 + ttf2pcx/readme.txt | 36 + ttf2pcx/res/ttf2font.ico | Bin 0 -> 2238 bytes ttf2pcx/res/ttf2pcx.ico | Bin 0 -> 766 bytes ttf2pcx/res/ttf2pcx.rc2 | 13 + ttf2pcx/resource.h | 34 + ttf2pcx/stdafx.cpp | 6 + ttf2pcx/stdafx.h | 16 + ttf2pcx/ttf2pcx.aps | Bin 0 -> 38564 bytes ttf2pcx/ttf2pcx.clw | 115 + ttf2pcx/ttf2pcx.cpp | 61 + ttf2pcx/ttf2pcx.dsp | 176 + ttf2pcx/ttf2pcx.dsw | 29 + ttf2pcx/ttf2pcx.h | 35 + ttf2pcx/ttf2pcx.ncb | Bin 0 -> 123904 bytes ttf2pcx/ttf2pcx.opt | Bin 0 -> 49664 bytes ttf2pcx/ttf2pcx.plg | 39 + ttf2pcx/ttf2pcx.rc | 290 + ttf2pcx/ttf2pcxdlg.cpp | 707 ++ ttf2pcx/ttf2pcxdlg.h | 71 + 717 files changed, 286843 insertions(+) create mode 100644 ActView/ActView.dsp create mode 100644 ActView/ActView.dsw create mode 100644 ActView/ActView.mak create mode 100644 ActView/Doc/ACTVIEW.HLP create mode 100644 ActView/Doc/ActView.CNT create mode 100644 ActView/Doc/ActView.doc create mode 100644 ActView/Doc/ActView.err create mode 100644 ActView/Doc/ActView.hpj create mode 100644 ActView/Doc/ActView.rbh create mode 100644 ActView/Doc/ActView.rta create mode 100644 ActView/Doc/ActView.rtf create mode 100644 ActView/Doc/ActView.rtk create mode 100644 ActView/Doc/ActView.rts create mode 100644 ActView/Doc/ffend.bmp create mode 100644 ActView/Doc/ffframe.bmp create mode 100644 ActView/Doc/frame.bmp create mode 100644 ActView/Doc/move.bmp create mode 100644 ActView/Doc/pan.bmp create mode 100644 ActView/Doc/pause.bmp create mode 100644 ActView/Doc/play.bmp create mode 100644 ActView/Doc/rotate.bmp create mode 100644 ActView/Doc/rrframe.bmp create mode 100644 ActView/Doc/rrstart.bmp create mode 100644 ActView/Doc/stop.bmp create mode 100644 ActView/Doc/zoom.bmp create mode 100644 ActView/Main/ActView.aps create mode 100644 ActView/Main/ActView.rc create mode 100644 ActView/Main/Blender.h create mode 100644 ActView/Main/actview.c create mode 100644 ActView/Main/actview.clw create mode 100644 ActView/Main/blender.c create mode 100644 ActView/Main/resource.h create mode 100644 ActView/Util/About.c create mode 100644 ActView/Util/FilePath.c create mode 100644 ActView/Util/FilePath.h create mode 100644 ActView/Util/InstCheck.c create mode 100644 ActView/Util/InstCheck.h create mode 100644 ActView/Util/WinUtil.c create mode 100644 ActView/Util/WinUtil.h create mode 100644 ActView/Util/about.h create mode 100644 ActView/Util/drvlist.c create mode 100644 ActView/Util/drvlist.h create mode 100644 ActView/Util/rcstring.c create mode 100644 ActView/Util/rcstring.h create mode 100644 ActView/Util/units.h create mode 100644 ActView/res/actview.bmp create mode 100644 ActView/res/actview.ico create mode 100644 ActView/res/blend.ico create mode 100644 ActView/res/ffend.ico create mode 100644 ActView/res/ffframe.ico create mode 100644 ActView/res/irotate.ico create mode 100644 ActView/res/mainicon.ico create mode 100644 ActView/res/pan.cur create mode 100644 ActView/res/pan.ico create mode 100644 ActView/res/pause.ico create mode 100644 ActView/res/play.ico create mode 100644 ActView/res/rotate.cur create mode 100644 ActView/res/rotate.ico create mode 100644 ActView/res/rrframe.ico create mode 100644 ActView/res/rrstart.ico create mode 100644 ActView/res/stop.ico create mode 100644 ActView/res/zoom.cur create mode 100644 ActView/res/zoom.ico create mode 100644 Exporters/3dseres.h create mode 100644 Exporters/3dsimp.h create mode 100644 Exporters/3dsires.h create mode 100644 Exporters/3dsmtl.cpp create mode 100644 Exporters/Cfile.h create mode 100644 Exporters/Kfio.h create mode 100644 Exporters/Mtldef.h create mode 100644 Exporters/Ofile.h create mode 100644 Exporters/Savemli.cpp create mode 100644 Exporters/gexp.cpp create mode 100644 Exporters/gexp.def create mode 100644 Exporters/gexp.dsp create mode 100644 Exporters/gexp.h create mode 100644 Exporters/gexp.mak create mode 100644 Exporters/gexp.rc create mode 100644 Exporters/max2sdk/readme.txt create mode 100644 Exporters/max3sdk/readme.txt create mode 100644 Exporters/mssccprj.scc create mode 100644 G3D/Actor/QKFrame.c create mode 100644 G3D/Actor/QKFrame.h create mode 100644 G3D/Actor/XFArray.c create mode 100644 G3D/Actor/actor.c create mode 100644 G3D/Actor/actor.h create mode 100644 G3D/Actor/body._h create mode 100644 G3D/Actor/body.c create mode 100644 G3D/Actor/body.h create mode 100644 G3D/Actor/bodyinst.c create mode 100644 G3D/Actor/bodyinst.h create mode 100644 G3D/Actor/motion.c create mode 100644 G3D/Actor/motion.h create mode 100644 G3D/Actor/path.c create mode 100644 G3D/Actor/path.h create mode 100644 G3D/Actor/pose.c create mode 100644 G3D/Actor/pose.h create mode 100644 G3D/Actor/puppet.c create mode 100644 G3D/Actor/puppet.h create mode 100644 G3D/Actor/strblock.c create mode 100644 G3D/Actor/strblock.h create mode 100644 G3D/Actor/tkarray.c create mode 100644 G3D/Actor/tkarray.h create mode 100644 G3D/Actor/tkevents.c create mode 100644 G3D/Actor/tkevents.h create mode 100644 G3D/Actor/vkframe.c create mode 100644 G3D/Actor/vkframe.h create mode 100644 G3D/Actor/xfarray.h create mode 100644 G3D/Afxres.h create mode 100644 G3D/Basetype.h create mode 100644 G3D/Bitmap/Compression/palcreate.c create mode 100644 G3D/Bitmap/Compression/palcreate.h create mode 100644 G3D/Bitmap/Compression/palettize.c create mode 100644 G3D/Bitmap/Compression/palettize.h create mode 100644 G3D/Bitmap/Compression/paloptimize.c create mode 100644 G3D/Bitmap/Compression/paloptimize.h create mode 100644 G3D/Bitmap/Compression/utility.h create mode 100644 G3D/Bitmap/Compression/yuv.c create mode 100644 G3D/Bitmap/Compression/yuv.h create mode 100644 G3D/Bitmap/bitmap.__h create mode 100644 G3D/Bitmap/bitmap._h create mode 100644 G3D/Bitmap/bitmap.c create mode 100644 G3D/Bitmap/bitmap.h create mode 100644 G3D/Bitmap/bitmap_blitdata.c create mode 100644 G3D/Bitmap/bitmap_blitdata.h create mode 100644 G3D/Bitmap/bitmap_gamma.c create mode 100644 G3D/Bitmap/bitmap_gamma.h create mode 100644 G3D/Bitmap/pixelformat.c create mode 100644 G3D/Bitmap/pixelformat.h create mode 100644 G3D/CSNetMgr.c create mode 100644 G3D/CSNetMgr.h create mode 100644 G3D/Camera.c create mode 100644 G3D/Camera.h create mode 100644 G3D/Engine/BitmapList.c create mode 100644 G3D/Engine/BitmapList.h create mode 100644 G3D/Engine/Drivers/Bmp.c create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3DDrv.mak create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3DDrv.ncb create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3DDrv.opt create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsw create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.ncb create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.opt create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.plg create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.CPP create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.H create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3d_fx.cpp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3d_fx.h create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3d_main.cpp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3d_main.h create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3dcache.cpp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3dcache.h create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.cpp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.h create mode 100644 G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.c create mode 100644 G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.h create mode 100644 G3D/Engine/Drivers/D3D7xDrv/GSPAN.H create mode 100644 G3D/Engine/Drivers/D3D7xDrv/Gspan.cpp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/Pcache.cpp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/Pcache.h create mode 100644 G3D/Engine/Drivers/D3D7xDrv/RENDER.H create mode 100644 G3D/Engine/Drivers/D3D7xDrv/Render.cpp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/SCENE.H create mode 100644 G3D/Engine/Drivers/D3D7xDrv/Scene.cpp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/THandle.cpp create mode 100644 G3D/Engine/Drivers/D3D7xDrv/THandle.h create mode 100644 G3D/Engine/Drivers/D3D7xDrv/TPage.h create mode 100644 G3D/Engine/Drivers/D3D7xDrv/mssccprj.scc create mode 100644 G3D/Engine/Drivers/D3D7xDrv/tpage.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3DDRV.H create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsp create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsw create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3DDriver.ncb create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3DDriver.opt create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3DDriver.plg create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3D_ERR.CPP create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3D_ERR.H create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3D_FX.H create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3d_fx.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3d_main.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3d_main.h create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3dcache.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3dcache.h create mode 100644 G3D/Engine/Drivers/D3D8Drv/D3ddrv.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/DDMemMgr.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/DDMemMgr.h create mode 100644 G3D/Engine/Drivers/D3D8Drv/GSPAN.CPP create mode 100644 G3D/Engine/Drivers/D3D8Drv/GSPAN.H create mode 100644 G3D/Engine/Drivers/D3D8Drv/Pcache.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/Pcache.h create mode 100644 G3D/Engine/Drivers/D3D8Drv/RENDER.H create mode 100644 G3D/Engine/Drivers/D3D8Drv/Render.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/SCENE.H create mode 100644 G3D/Engine/Drivers/D3D8Drv/Scene.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/THandle.cpp create mode 100644 G3D/Engine/Drivers/D3D8Drv/THandle.h create mode 100644 G3D/Engine/Drivers/D3D8Drv/TPage.h create mode 100644 G3D/Engine/Drivers/D3D8Drv/tpage.cpp create mode 100644 G3D/Engine/Drivers/D3DDrv/D3DDRV.H create mode 100644 G3D/Engine/Drivers/D3DDrv/D3DDrv.dsp create mode 100644 G3D/Engine/Drivers/D3DDrv/D3DDrv.dsw create mode 100644 G3D/Engine/Drivers/D3DDrv/D3DDrv.mak create mode 100644 G3D/Engine/Drivers/D3DDrv/D3DDrv.ncb create mode 100644 G3D/Engine/Drivers/D3DDrv/D3DDrv.opt create mode 100644 G3D/Engine/Drivers/D3DDrv/D3DDrv.plg create mode 100644 G3D/Engine/Drivers/D3DDrv/D3D_ERR.CPP create mode 100644 G3D/Engine/Drivers/D3DDrv/D3D_ERR.H create mode 100644 G3D/Engine/Drivers/D3DDrv/D3d_fx.cpp create mode 100644 G3D/Engine/Drivers/D3DDrv/D3d_fx.h create mode 100644 G3D/Engine/Drivers/D3DDrv/D3d_main.cpp create mode 100644 G3D/Engine/Drivers/D3DDrv/D3d_main.h create mode 100644 G3D/Engine/Drivers/D3DDrv/D3dcache.cpp create mode 100644 G3D/Engine/Drivers/D3DDrv/D3dcache.h create mode 100644 G3D/Engine/Drivers/D3DDrv/D3ddrv.cpp create mode 100644 G3D/Engine/Drivers/D3DDrv/DDMemMgr.c create mode 100644 G3D/Engine/Drivers/D3DDrv/DDMemMgr.h create mode 100644 G3D/Engine/Drivers/D3DDrv/GSPAN.CPP create mode 100644 G3D/Engine/Drivers/D3DDrv/GSPAN.H create mode 100644 G3D/Engine/Drivers/D3DDrv/Pcache.cpp create mode 100644 G3D/Engine/Drivers/D3DDrv/Pcache.h create mode 100644 G3D/Engine/Drivers/D3DDrv/README.NOW create mode 100644 G3D/Engine/Drivers/D3DDrv/RENDER.H create mode 100644 G3D/Engine/Drivers/D3DDrv/Render.cpp create mode 100644 G3D/Engine/Drivers/D3DDrv/SCENE.H create mode 100644 G3D/Engine/Drivers/D3DDrv/Scene.cpp create mode 100644 G3D/Engine/Drivers/D3DDrv/THandle.cpp create mode 100644 G3D/Engine/Drivers/D3DDrv/THandle.h create mode 100644 G3D/Engine/Drivers/D3DDrv/TPage.h create mode 100644 G3D/Engine/Drivers/D3DDrv/mssccprj.scc create mode 100644 G3D/Engine/Drivers/D3DDrv/tpage.cpp create mode 100644 G3D/Engine/Drivers/Dcommon.h create mode 100644 G3D/Engine/Drivers/GlideDrv/GCache.c create mode 100644 G3D/Engine/Drivers/GlideDrv/GCache.h create mode 100644 G3D/Engine/Drivers/GlideDrv/GLIDEDRV.H create mode 100644 G3D/Engine/Drivers/GlideDrv/GMain.c create mode 100644 G3D/Engine/Drivers/GlideDrv/GMain.h create mode 100644 G3D/Engine/Drivers/GlideDrv/GMemMgr.c create mode 100644 G3D/Engine/Drivers/GlideDrv/GMemMgr.h create mode 100644 G3D/Engine/Drivers/GlideDrv/GSpan.cpp create mode 100644 G3D/Engine/Drivers/GlideDrv/GSpan.h create mode 100644 G3D/Engine/Drivers/GlideDrv/GTHandle.h create mode 100644 G3D/Engine/Drivers/GlideDrv/GThandle.c create mode 100644 G3D/Engine/Drivers/GlideDrv/GlideDrv.c create mode 100644 G3D/Engine/Drivers/GlideDrv/GlideDrv.dsp create mode 100644 G3D/Engine/Drivers/GlideDrv/GlideDrv.dsw create mode 100644 G3D/Engine/Drivers/GlideDrv/GlideDrv.mak create mode 100644 G3D/Engine/Drivers/GlideDrv/GlideDrv.ncb create mode 100644 G3D/Engine/Drivers/GlideDrv/GlideDrv.opt create mode 100644 G3D/Engine/Drivers/GlideDrv/Render.c create mode 100644 G3D/Engine/Drivers/GlideDrv/Render.h create mode 100644 G3D/Engine/Drivers/GlideDrv/mssccprj.scc create mode 100644 G3D/Engine/Drivers/OpenGl/OGLDrv.c create mode 100644 G3D/Engine/Drivers/OpenGl/OGLDrv.h create mode 100644 G3D/Engine/Drivers/OpenGl/OglDrv.dsp create mode 100644 G3D/Engine/Drivers/OpenGl/OglDrv.dsw create mode 100644 G3D/Engine/Drivers/OpenGl/OglMisc.c create mode 100644 G3D/Engine/Drivers/OpenGl/OglMisc.h create mode 100644 G3D/Engine/Drivers/OpenGl/Render.c create mode 100644 G3D/Engine/Drivers/OpenGl/Render.h create mode 100644 G3D/Engine/Drivers/OpenGl/THandle.c create mode 100644 G3D/Engine/Drivers/OpenGl/THandle.h create mode 100644 G3D/Engine/Drivers/OpenGl/Win32.c create mode 100644 G3D/Engine/Drivers/OpenGl/Win32.h create mode 100644 G3D/Engine/Drivers/OpenGl/glext.h create mode 100644 G3D/Engine/Drivers/SoftDrv/3dnowspan.h create mode 100644 G3D/Engine/Drivers/SoftDrv/REGISTER.H create mode 100644 G3D/Engine/Drivers/SoftDrv/RENDER.H create mode 100644 G3D/Engine/Drivers/SoftDrv/SAL.H create mode 100644 G3D/Engine/Drivers/SoftDrv/SCENE.H create mode 100644 G3D/Engine/Drivers/SoftDrv/SOFTDRV.H create mode 100644 G3D/Engine/Drivers/SoftDrv/SPAN.H create mode 100644 G3D/Engine/Drivers/SoftDrv/SYSTEM.H create mode 100644 G3D/Engine/Drivers/SoftDrv/SoftDrv.dsp create mode 100644 G3D/Engine/Drivers/SoftDrv/SoftDrv.mak create mode 100644 G3D/Engine/Drivers/SoftDrv/W32SAL.CPP create mode 100644 G3D/Engine/Drivers/SoftDrv/amdspan.asm create mode 100644 G3D/Engine/Drivers/SoftDrv/dmodes.c create mode 100644 G3D/Engine/Drivers/SoftDrv/dmodes.h create mode 100644 G3D/Engine/Drivers/SoftDrv/drawspan.c create mode 100644 G3D/Engine/Drivers/SoftDrv/drawspan.h create mode 100644 G3D/Engine/Drivers/SoftDrv/mssccprj.scc create mode 100644 G3D/Engine/Drivers/SoftDrv/register.c create mode 100644 G3D/Engine/Drivers/SoftDrv/render.c create mode 100644 G3D/Engine/Drivers/SoftDrv/scene.c create mode 100644 G3D/Engine/Drivers/SoftDrv/softdrv.c create mode 100644 G3D/Engine/Drivers/SoftDrv/span.c create mode 100644 G3D/Engine/Drivers/SoftDrv/system.c create mode 100644 G3D/Engine/Drivers/SoftDrv/x86span555.c create mode 100644 G3D/Engine/Drivers/SoftDrv/x86span555.h create mode 100644 G3D/Engine/Drivers/SoftDrv/x86span565.c create mode 100644 G3D/Engine/Drivers/SoftDrv/x86span565.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/CPUInfo.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/CPUInfo.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/DIBDisplay.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/DIBDisplay.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/DrawDecal.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/DrawDecal.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/SWTHandle.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/SWTHandle.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/SoftDrv2.dsp create mode 100644 G3D/Engine/Drivers/SoftDrv2/SoftDrv2.mak create mode 100644 G3D/Engine/Drivers/SoftDrv2/Softdrv.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/Span.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/SpanBuffer.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/SpanBuffer.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/SpanEdges_Factory.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/Span_AffineLoop.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/Span_Factory.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/TRaster.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/Triangle.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/display.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/display.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/mssccprj.scc create mode 100644 G3D/Engine/Drivers/SoftDrv2/rop.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/softdrv.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/span.c create mode 100644 G3D/Engine/Drivers/SoftDrv2/traster.h create mode 100644 G3D/Engine/Drivers/SoftDrv2/triangle.h create mode 100644 G3D/Engine/Drivers/WireFrame/D3DDrv.dsp create mode 100644 G3D/Engine/Drivers/WireFrame/D3DDrv.dsw create mode 100644 G3D/Engine/Drivers/WireFrame/D3DDrv.mak create mode 100644 G3D/Engine/Drivers/WireFrame/D3DDrv.ncb create mode 100644 G3D/Engine/Drivers/WireFrame/D3DDrv.opt create mode 100644 G3D/Engine/Drivers/WireFrame/D3DDrv.plg create mode 100644 G3D/Engine/Drivers/WireFrame/D3d_err.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/D3d_err.h create mode 100644 G3D/Engine/Drivers/WireFrame/D3d_fx.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/D3d_fx.h create mode 100644 G3D/Engine/Drivers/WireFrame/D3d_main.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/D3d_main.h create mode 100644 G3D/Engine/Drivers/WireFrame/D3dcache.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/D3dcache.h create mode 100644 G3D/Engine/Drivers/WireFrame/D3ddrv.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/D3ddrv.h create mode 100644 G3D/Engine/Drivers/WireFrame/DDMemMgr.c create mode 100644 G3D/Engine/Drivers/WireFrame/DDMemMgr.h create mode 100644 G3D/Engine/Drivers/WireFrame/Gspan.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/Gspan.h create mode 100644 G3D/Engine/Drivers/WireFrame/Pcache.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/Pcache.h create mode 100644 G3D/Engine/Drivers/WireFrame/Readme.now create mode 100644 G3D/Engine/Drivers/WireFrame/Render.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/Render.h create mode 100644 G3D/Engine/Drivers/WireFrame/Scene.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/Scene.h create mode 100644 G3D/Engine/Drivers/WireFrame/THandle.cpp create mode 100644 G3D/Engine/Drivers/WireFrame/THandle.h create mode 100644 G3D/Engine/Drivers/WireFrame/TPage.h create mode 100644 G3D/Engine/Drivers/WireFrame/mssccprj.scc create mode 100644 G3D/Engine/Drivers/WireFrame/tpage.cpp create mode 100644 G3D/Engine/Logo/A_CORONA.c create mode 100644 G3D/Engine/Logo/A_STREAK.c create mode 100644 G3D/Engine/Logo/CORONA.c create mode 100644 G3D/Engine/Logo/LogoActor.c create mode 100644 G3D/Engine/Logo/WebUrl.c create mode 100644 G3D/Engine/Logo/electric.c create mode 100644 G3D/Engine/Logo/electric.h create mode 100644 G3D/Engine/Logo/logo.c create mode 100644 G3D/Engine/Logo/poweredby.c create mode 100644 G3D/Engine/Logo/streak.c create mode 100644 G3D/Engine/Sound.c create mode 100644 G3D/Engine/System.c create mode 100644 G3D/Engine/System.h create mode 100644 G3D/Engine/engine.c create mode 100644 G3D/Engine/engine.h create mode 100644 G3D/Engine/fontbmp.c create mode 100644 G3D/Engine/genesis3d.c create mode 100644 G3D/Entities/ENTITIES.H create mode 100644 G3D/Entities/Entities.c create mode 100644 G3D/Font/font.H create mode 100644 G3D/Font/font.c create mode 100644 G3D/Font/wgClip.H create mode 100644 G3D/Font/wgClip.c create mode 100644 G3D/Ge.c create mode 100644 G3D/Genesis.aps create mode 100644 G3D/Genesis.dsp create mode 100644 G3D/Genesis.dsw create mode 100644 G3D/Genesis.h create mode 100644 G3D/Genesis.mak create mode 100644 G3D/GenesisDLL.dsp create mode 100644 G3D/GenesisDLL.dsw create mode 100644 G3D/GenesisDLL.mak create mode 100644 G3D/Math/Box.c create mode 100644 G3D/Math/Box.h create mode 100644 G3D/Math/ExtBox.c create mode 100644 G3D/Math/ExtBox.h create mode 100644 G3D/Math/VEC3D.C create mode 100644 G3D/Math/VEC3D.H create mode 100644 G3D/Math/Xform3d.c create mode 100644 G3D/Math/Xform3d.h create mode 100644 G3D/Math/crc32.c create mode 100644 G3D/Math/crc32.h create mode 100644 G3D/Math/quatern.c create mode 100644 G3D/Math/quatern.h create mode 100644 G3D/Netplay.c create mode 100644 G3D/Netplay.h create mode 100644 G3D/Physics/PhysicsJoint.c create mode 100644 G3D/Physics/PhysicsJoint.h create mode 100644 G3D/Physics/PhysicsObject.c create mode 100644 G3D/Physics/PhysicsObject.h create mode 100644 G3D/Physics/PhysicsSystem.c create mode 100644 G3D/Physics/PhysicsSystem.h create mode 100644 G3D/Physics/matrix33.c create mode 100644 G3D/Physics/matrix33.h create mode 100644 G3D/Ptrtypes.h create mode 100644 G3D/RCa24739 create mode 100644 G3D/RCb24739 create mode 100644 G3D/RCc24739 create mode 100644 G3D/RCd24739 create mode 100644 G3D/Sound.c create mode 100644 G3D/Sound.h create mode 100644 G3D/Sound3d.c create mode 100644 G3D/Sound3d.h create mode 100644 G3D/Support/ERRORLOG.C create mode 100644 G3D/Support/Errorlog.h create mode 100644 G3D/Support/RAM.H create mode 100644 G3D/Support/Ram.c create mode 100644 G3D/Support/geAssert.c create mode 100644 G3D/Support/geAssert.h create mode 100644 G3D/Support/log.c create mode 100644 G3D/Support/log.h create mode 100644 G3D/Support/mempool.c create mode 100644 G3D/Support/mempool.h create mode 100644 G3D/Support/ramdll.c create mode 100644 G3D/Tclip.c create mode 100644 G3D/VFile/FSMEMORY.C create mode 100644 G3D/VFile/FSMEMORY.H create mode 100644 G3D/VFile/dirtree-common.c create mode 100644 G3D/VFile/dirtree-common.h create mode 100644 G3D/VFile/dirtree.c create mode 100644 G3D/VFile/dirtree.h create mode 100644 G3D/VFile/fsdos.c create mode 100644 G3D/VFile/fsdos.h create mode 100644 G3D/VFile/fsvfs.c create mode 100644 G3D/VFile/fsvfs.h create mode 100644 G3D/VFile/vfile._h create mode 100644 G3D/VFile/vfile.c create mode 100644 G3D/VFile/vfile.h create mode 100644 G3D/VFile/vfile_structs.h create mode 100644 G3D/Winres.h create mode 100644 G3D/Winresrc.h create mode 100644 G3D/World/FRUSTUM.H create mode 100644 G3D/World/Fog.c create mode 100644 G3D/World/Fog.h create mode 100644 G3D/World/Frustum.c create mode 100644 G3D/World/Gbspfile.c create mode 100644 G3D/World/Gbspfile.h create mode 100644 G3D/World/Light.c create mode 100644 G3D/World/Light.h create mode 100644 G3D/World/PLANE.H create mode 100644 G3D/World/Plane.c create mode 100644 G3D/World/SURFACE.H create mode 100644 G3D/World/Surface.c create mode 100644 G3D/World/TRACE.H create mode 100644 G3D/World/Trace.c create mode 100644 G3D/World/USER.H create mode 100644 G3D/World/User.c create mode 100644 G3D/World/VIS.H create mode 100644 G3D/World/Vis.c create mode 100644 G3D/World/WBitmap.c create mode 100644 G3D/World/WBitmap.h create mode 100644 G3D/World/World.c create mode 100644 G3D/World/World.h create mode 100644 G3D/drawbbox.c create mode 100644 G3D/genesis.rc create mode 100644 G3D/getypes.h create mode 100644 G3D/list.c create mode 100644 G3D/list.h create mode 100644 G3D/mssccprj.scc create mode 100644 G3D/resource.h create mode 100644 G3D/sprite.c create mode 100644 G3D/sprite.h create mode 100644 G3D/tclip.h create mode 100644 G3D/timer.c create mode 100644 G3D/timer.h create mode 100644 G3D/tsc.c create mode 100644 G3D/tsc.h create mode 100644 GBSPLib/BRUSH2.H create mode 100644 GBSPLib/BSP.CPP create mode 100644 GBSPLib/Brush2.cpp create mode 100644 GBSPLib/Bsp.h create mode 100644 GBSPLib/Bsp2.cpp create mode 100644 GBSPLib/Fill.Cpp create mode 100644 GBSPLib/Fill.h create mode 100644 GBSPLib/GBSPFILE.CPP create mode 100644 GBSPLib/GBSPLib.dsp create mode 100644 GBSPLib/GBSPLib.dsw create mode 100644 GBSPLib/GBSPLib.mak create mode 100644 GBSPLib/GBSPPREP.CPP create mode 100644 GBSPLib/GBSPPREP.H create mode 100644 GBSPLib/Gbspfile.h create mode 100644 GBSPLib/Gbsplib.cpp create mode 100644 GBSPLib/Gbsplib.h create mode 100644 GBSPLib/Leaf.cpp create mode 100644 GBSPLib/Leaf.h create mode 100644 GBSPLib/Light.cpp create mode 100644 GBSPLib/Light.h create mode 100644 GBSPLib/MATHLIB.CPP create mode 100644 GBSPLib/MATHLIB.H create mode 100644 GBSPLib/Map.cpp create mode 100644 GBSPLib/Map.h create mode 100644 GBSPLib/POLY.CPP create mode 100644 GBSPLib/POLY.H create mode 100644 GBSPLib/PORTALS.CPP create mode 100644 GBSPLib/PORTALS.H create mode 100644 GBSPLib/PortFile.cpp create mode 100644 GBSPLib/RAD.CPP create mode 100644 GBSPLib/TEXTURE.CPP create mode 100644 GBSPLib/TEXTURE.H create mode 100644 GBSPLib/TJunct.cpp create mode 100644 GBSPLib/Utils.cpp create mode 100644 GBSPLib/Utils.h create mode 100644 GBSPLib/VIS.CPP create mode 100644 GBSPLib/VISFLOOD.CPP create mode 100644 GBSPLib/Vis.h create mode 100644 GBSPLib/build.bat create mode 100644 GBSPLib/mssccprj.scc create mode 100755 crafty102/Crafty.exe create mode 100755 crafty102/DevIL.dll create mode 100755 crafty102/Fonts/CourierNew.csf create mode 100755 crafty102/Fonts/CourierNew.tga create mode 100755 crafty102/Fonts/FontSchema.csf create mode 100755 crafty102/HLLib.dll create mode 100755 crafty102/ILU.dll create mode 100755 crafty102/Readme.txt create mode 100755 crafty102/SketchUpReader.dll create mode 100755 crafty102/Specifications/GameInfo.csf create mode 100755 crafty102/Specifications/GameInfoCustom.csf create mode 100755 crafty102/Specifications/GameInfoSchema.csf create mode 100755 crafty102/VTFLib.dll create mode 100755 crafty102/gdal12.dll create mode 100755 crafty102/xerces-c_2_6.dll create mode 100644 include/Basetype.h create mode 100644 include/Errorlog.h create mode 100644 include/ExtBox.h create mode 100644 include/Genesis.h create mode 100644 include/PhysicsJoint.h create mode 100644 include/PhysicsObject.h create mode 100644 include/PhysicsSystem.h create mode 100644 include/RAM.H create mode 100644 include/VEC3D.H create mode 100644 include/Xform3d.h create mode 100644 include/actor.h create mode 100644 include/bitmap.h create mode 100644 include/body.h create mode 100644 include/font.H create mode 100644 include/getypes.h create mode 100644 include/matrix33.h create mode 100644 include/motion.h create mode 100644 include/path.h create mode 100644 include/pixelformat.h create mode 100644 include/quatern.h create mode 100644 include/sprite.h create mode 100644 include/vfile.h create mode 100644 mkactor/AStudio.dsp create mode 100644 mkactor/AStudio.dsw create mode 100644 mkactor/AStudio/AOptions.c create mode 100644 mkactor/AStudio/AOptions.h create mode 100644 mkactor/AStudio/AProject.c create mode 100644 mkactor/AStudio/AProject.h create mode 100644 mkactor/AStudio/AStudio.cpp create mode 100644 mkactor/AStudio/AStudio.h create mode 100644 mkactor/AStudio/AStudio.rc create mode 100644 mkactor/AStudio/BodyDlg.cpp create mode 100644 mkactor/AStudio/BodyDlg.h create mode 100644 mkactor/AStudio/HLP/ASTUDIO.HLP create mode 100644 mkactor/AStudio/HLP/AStudio.LOG create mode 100644 mkactor/AStudio/HLP/AStudio.cnt create mode 100644 mkactor/AStudio/HLP/AStudio.hm create mode 100644 mkactor/AStudio/HLP/AStudio.hpj create mode 100644 mkactor/AStudio/HLP/AStudio.ph create mode 100644 mkactor/AStudio/HLP/AfxDlg.rtf create mode 100644 mkactor/AStudio/LogoPage.cpp create mode 100644 mkactor/AStudio/LogoPage.h create mode 100644 mkactor/AStudio/MakeHelp.bat create mode 100644 mkactor/AStudio/MakeHelp.cpp create mode 100644 mkactor/AStudio/MakeHelp.h create mode 100644 mkactor/AStudio/MaterialsDlg.cpp create mode 100644 mkactor/AStudio/MaterialsDlg.h create mode 100644 mkactor/AStudio/MotionsDlg.cpp create mode 100644 mkactor/AStudio/MotionsDlg.h create mode 100644 mkactor/AStudio/MyFileDlg.cpp create mode 100644 mkactor/AStudio/MyFileDlg.h create mode 100644 mkactor/AStudio/NewPrjDlg.cpp create mode 100644 mkactor/AStudio/NewPrjDlg.h create mode 100644 mkactor/AStudio/PathsDlg.cpp create mode 100644 mkactor/AStudio/PathsDlg.h create mode 100644 mkactor/AStudio/PropPage.cpp create mode 100644 mkactor/AStudio/PropPage.h create mode 100644 mkactor/AStudio/PropSheet.cpp create mode 100644 mkactor/AStudio/PropSheet.h create mode 100644 mkactor/AStudio/RCa91691 create mode 100644 mkactor/AStudio/RES/ACTVIEW.BMP create mode 100644 mkactor/AStudio/RES/AStudio.ico create mode 100644 mkactor/AStudio/RES/AStudio.rc2 create mode 100644 mkactor/AStudio/SettingsDlg.cpp create mode 100644 mkactor/AStudio/SettingsDlg.h create mode 100644 mkactor/AStudio/StdAfx.cpp create mode 100644 mkactor/AStudio/StdAfx.h create mode 100644 mkactor/AStudio/TargetDlg.cpp create mode 100644 mkactor/AStudio/TargetDlg.h create mode 100644 mkactor/AStudio/TextInputDlg.cpp create mode 100644 mkactor/AStudio/TextInputDlg.h create mode 100644 mkactor/AStudio/Util/ARRAY.H create mode 100644 mkactor/AStudio/Util/Array.c create mode 100644 mkactor/AStudio/Util/FilePath.c create mode 100644 mkactor/AStudio/Util/FilePath.h create mode 100644 mkactor/AStudio/Util/RCSTRING.C create mode 100644 mkactor/AStudio/Util/RCSTRING.H create mode 100644 mkactor/AStudio/Util/UTIL.C create mode 100644 mkactor/AStudio/Util/UTIL.H create mode 100644 mkactor/AStudio/make.c create mode 100644 mkactor/AStudio/make.h create mode 100644 mkactor/AStudio/mxscript.c create mode 100644 mkactor/AStudio/mxscript.h create mode 100644 mkactor/AStudio/resource.h create mode 100644 mkactor/ActBuild.dsp create mode 100644 mkactor/ActBuild.dsw create mode 100644 mkactor/ActBuild/ActBuild.c create mode 100644 mkactor/ActBuild/ActBuild.h create mode 100644 mkactor/common/TDBody.c create mode 100644 mkactor/common/TDBody.h create mode 100644 mkactor/common/maxmath.c create mode 100644 mkactor/common/maxmath.h create mode 100644 mkactor/common/mkutil.c create mode 100644 mkactor/common/mkutil.h create mode 100644 mkactor/fmtactor/fmtactor.c create mode 100644 mkactor/fmtactor/fmtactor.h create mode 100644 mkactor/mkactor/mkactor.c create mode 100644 mkactor/mkactor/mkactor.h create mode 100644 mkactor/mkbody/mkbody.cpp create mode 100644 mkactor/mkbody/mkbody.h create mode 100644 mkactor/mkbody/vph.c create mode 100644 mkactor/mkbody/vph.h create mode 100644 mkactor/mkmotion/mkmotion.c create mode 100644 mkactor/mkmotion/mkmotion.h create mode 100644 mkactor/mop/Log.c create mode 100644 mkactor/mop/Log.h create mode 100644 mkactor/mop/mopshell.c create mode 100644 mkactor/mop/mopshell.h create mode 100644 mkactor/mop/pop.c create mode 100644 mkactor/mop/pop.h create mode 100644 rfPack/BUILD.BAT create mode 100644 rfPack/PULL.BAT create mode 100644 rfPack/RES/MAINICON.ICO create mode 100644 rfPack/RES/rfpack.ico create mode 100644 rfPack/Source/TPack.aps create mode 100644 rfPack/Source/TPack.c create mode 100644 rfPack/Source/TPack.rc create mode 100644 rfPack/Source/resource.h create mode 100644 rfPack/rfPack.dsp create mode 100644 rfPack/rfPack.dsw create mode 100644 rfvfs/Delete.cpp create mode 100644 rfvfs/Delete.h create mode 100644 rfvfs/EllepticalButton.cpp create mode 100644 rfvfs/EllepticalButton.h create mode 100644 rfvfs/EncryptKey.cpp create mode 100644 rfvfs/EncryptKey.h create mode 100644 rfvfs/FileTreeCtrl.cpp create mode 100644 rfvfs/FileTreeCtrl.h create mode 100644 rfvfs/MFileDlg.cpp create mode 100644 rfvfs/MFileDlg.h create mode 100644 rfvfs/MakeDir.cpp create mode 100644 rfvfs/MakeDir.h create mode 100644 rfvfs/ReadMe.txt create mode 100644 rfvfs/Rename.cpp create mode 100644 rfvfs/Rename.h create mode 100644 rfvfs/SortedArray.h create mode 100644 rfvfs/StdAfx.cpp create mode 100644 rfvfs/StdAfx.h create mode 100644 rfvfs/res/icon1.ico create mode 100644 rfvfs/res/rfvfs.ico create mode 100644 rfvfs/res/rfvfs.rc2 create mode 100644 rfvfs/res/tfdropcopy.cur create mode 100644 rfvfs/res/tfnodropcopy.cur create mode 100644 rfvfs/res/tfnodropmove.cur create mode 100644 rfvfs/resource.h create mode 100644 rfvfs/rfvfs.aps create mode 100644 rfvfs/rfvfs.clw create mode 100644 rfvfs/rfvfs.cpp create mode 100644 rfvfs/rfvfs.dsp create mode 100644 rfvfs/rfvfs.dsw create mode 100644 rfvfs/rfvfs.h create mode 100644 rfvfs/rfvfs.rc create mode 100644 rfvfs/rfvfsDlg.cpp create mode 100644 rfvfs/rfvfsDlg.h create mode 100644 ttf2pcx/ColorButton.cpp create mode 100644 ttf2pcx/ColorButton.h create mode 100644 ttf2pcx/ColourPopup.cpp create mode 100644 ttf2pcx/ColourPopup.h create mode 100644 ttf2pcx/character.cpp create mode 100644 ttf2pcx/character.h create mode 100644 ttf2pcx/previewbutton.cpp create mode 100644 ttf2pcx/previewbutton.h create mode 100644 ttf2pcx/readme.txt create mode 100644 ttf2pcx/res/ttf2font.ico create mode 100644 ttf2pcx/res/ttf2pcx.ico create mode 100644 ttf2pcx/res/ttf2pcx.rc2 create mode 100644 ttf2pcx/resource.h create mode 100644 ttf2pcx/stdafx.cpp create mode 100644 ttf2pcx/stdafx.h create mode 100644 ttf2pcx/ttf2pcx.aps create mode 100644 ttf2pcx/ttf2pcx.clw create mode 100644 ttf2pcx/ttf2pcx.cpp create mode 100644 ttf2pcx/ttf2pcx.dsp create mode 100644 ttf2pcx/ttf2pcx.dsw create mode 100644 ttf2pcx/ttf2pcx.h create mode 100644 ttf2pcx/ttf2pcx.ncb create mode 100644 ttf2pcx/ttf2pcx.opt create mode 100644 ttf2pcx/ttf2pcx.plg create mode 100644 ttf2pcx/ttf2pcx.rc create mode 100644 ttf2pcx/ttf2pcxdlg.cpp create mode 100644 ttf2pcx/ttf2pcxdlg.h diff --git a/ActView/ActView.dsp b/ActView/ActView.dsp new file mode 100644 index 0000000..68866c4 --- /dev/null +++ b/ActView/ActView.dsp @@ -0,0 +1,250 @@ +# Microsoft Developer Studio Project File - Name="ActView" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ActView - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ActView.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ActView.mak" CFG="ActView - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ActView - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ActView - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Tools/Actview", ASFBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ActView - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W4 /GX /O2 /Ob2 /I ".\Util" /I ".\Main" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /FD /c +# SUBTRACT CPP /X /Fr /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +# SUBTRACT RSC /x +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib comctl32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib vfw32.lib dxguid.lib genesis.lib /nologo /subsystem:windows /machine:I386 +# SUBTRACT LINK32 /nodefaultlib + +!ELSEIF "$(CFG)" == "ActView - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G5 /MTd /W4 /Gm /GX /ZI /Od /I ".\Util" /I ".\Main" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /FD /c +# SUBTRACT CPP /X /Fr /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +# SUBTRACT RSC /x +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib comctl32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib vfw32.lib dxguid.lib genesisd.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "ActView - Win32 Release" +# Name "ActView - Win32 Debug" +# Begin Group "Util" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Util\About.c +# End Source File +# Begin Source File + +SOURCE=.\Util\about.h +# End Source File +# Begin Source File + +SOURCE=.\Util\drvlist.c +# End Source File +# Begin Source File + +SOURCE=.\Util\drvlist.h +# End Source File +# Begin Source File + +SOURCE=.\Util\FilePath.c +# End Source File +# Begin Source File + +SOURCE=.\Util\FilePath.h +# End Source File +# Begin Source File + +SOURCE=.\Util\InstCheck.c +# End Source File +# Begin Source File + +SOURCE=.\Util\InstCheck.h +# End Source File +# Begin Source File + +SOURCE=.\Util\rcstring.c +# End Source File +# Begin Source File + +SOURCE=.\Util\rcstring.h +# End Source File +# Begin Source File + +SOURCE=.\Util\units.h +# End Source File +# Begin Source File + +SOURCE=.\Util\WinUtil.c +# End Source File +# Begin Source File + +SOURCE=.\Util\WinUtil.h +# End Source File +# End Group +# Begin Group "Resources" + +# PROP Default_Filter ".bmp;.cur;.ico" +# Begin Source File + +SOURCE=.\res\actview.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\actview.ico +# End Source File +# Begin Source File + +SOURCE=.\res\blend.ico +# End Source File +# Begin Source File + +SOURCE=.\res\ffend.ico +# End Source File +# Begin Source File + +SOURCE=.\res\ffframe.ico +# End Source File +# Begin Source File + +SOURCE=.\res\mainicon.ico +# End Source File +# Begin Source File + +SOURCE=.\res\pan.cur +# End Source File +# Begin Source File + +SOURCE=.\res\pan.ico +# End Source File +# Begin Source File + +SOURCE=.\res\pause.ico +# End Source File +# Begin Source File + +SOURCE=.\res\play.ico +# End Source File +# Begin Source File + +SOURCE=.\res\rotate.cur +# End Source File +# Begin Source File + +SOURCE=.\res\rotate.ico +# End Source File +# Begin Source File + +SOURCE=.\res\rrframe.ico +# End Source File +# Begin Source File + +SOURCE=.\res\rrstart.ico +# End Source File +# Begin Source File + +SOURCE=.\res\stop.ico +# End Source File +# Begin Source File + +SOURCE=.\res\zoom.cur +# End Source File +# Begin Source File + +SOURCE=.\res\zoom.ico +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Main\actview.c +# End Source File +# Begin Source File + +SOURCE=.\ActView.mak +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Main\actview.rc +# End Source File +# Begin Source File + +SOURCE=.\Main\Blender.c +# End Source File +# Begin Source File + +SOURCE=.\Main\Blender.h +# End Source File +# Begin Source File + +SOURCE=.\Main\resource.h +# End Source File +# End Target +# End Project diff --git a/ActView/ActView.dsw b/ActView/ActView.dsw new file mode 100644 index 0000000..de5f91e --- /dev/null +++ b/ActView/ActView.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ActView"=.\ActView.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/ActView/ActView.mak b/ActView/ActView.mak new file mode 100644 index 0000000..892bf8b --- /dev/null +++ b/ActView/ActView.mak @@ -0,0 +1,250 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on ActView.dsp +!IF "$(CFG)" == "" +CFG=ActView - Win32 Debug +!MESSAGE No configuration specified. Defaulting to ActView - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "ActView - Win32 Release" && "$(CFG)" != "ActView - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ActView.mak" CFG="ActView - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ActView - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ActView - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ActView - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +ALL : "$(OUTDIR)\ActView.exe" + + +CLEAN : + -@erase "$(INTDIR)\About.obj" + -@erase "$(INTDIR)\actview.obj" + -@erase "$(INTDIR)\actview.res" + -@erase "$(INTDIR)\Blender.obj" + -@erase "$(INTDIR)\drvlist.obj" + -@erase "$(INTDIR)\FilePath.obj" + -@erase "$(INTDIR)\InstCheck.obj" + -@erase "$(INTDIR)\rcstring.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\WinUtil.obj" + -@erase "$(OUTDIR)\ActView.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /G5 /MT /W4 /GX /O2 /X /I ".\Util" /I ".\Main" /I ".\GenesisSDK\Include" /I "..\..\msdev60\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /Fp"$(INTDIR)\ActView.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\actview.res" /i "..\..\msdev60\include" /d "NDEBUG" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\ActView.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=genesis.lib libcmt.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib oldnames.lib winmm.lib comctl32.lib ole32.lib uuid.lib urlmon.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\ActView.pdb" /machine:I386 /nodefaultlib /out:"$(OUTDIR)\ActView.exe" /libpath:".\GenesisSDK\lib" /libpath:"..\..\msdev60\lib" +LINK32_OBJS= \ + "$(INTDIR)\About.obj" \ + "$(INTDIR)\drvlist.obj" \ + "$(INTDIR)\FilePath.obj" \ + "$(INTDIR)\InstCheck.obj" \ + "$(INTDIR)\rcstring.obj" \ + "$(INTDIR)\WinUtil.obj" \ + "$(INTDIR)\actview.obj" \ + "$(INTDIR)\Blender.obj" \ + "$(INTDIR)\actview.res" + +"$(OUTDIR)\ActView.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "ActView - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\ActView.exe" + + +CLEAN : + -@erase "$(INTDIR)\About.obj" + -@erase "$(INTDIR)\actview.obj" + -@erase "$(INTDIR)\actview.res" + -@erase "$(INTDIR)\Blender.obj" + -@erase "$(INTDIR)\drvlist.obj" + -@erase "$(INTDIR)\FilePath.obj" + -@erase "$(INTDIR)\InstCheck.obj" + -@erase "$(INTDIR)\rcstring.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(INTDIR)\WinUtil.obj" + -@erase "$(OUTDIR)\ActView.exe" + -@erase "$(OUTDIR)\ActView.ilk" + -@erase "$(OUTDIR)\ActView.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /G5 /MTd /W4 /Gm /GX /ZI /Od /X /I ".\Util" /I ".\Main" /I ".\GenesisSDK\Include" /I "..\..\msdev60\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /Fp"$(INTDIR)\ActView.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\actview.res" /i "..\..\msdev60\include" /d "_DEBUG" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\ActView.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=genesisd.lib libcmtd.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib oldnames.lib winmm.lib comctl32.lib ole32.lib uuid.lib urlmon.lib /nologo /subsystem:windows /incremental:yes /pdb:"$(OUTDIR)\ActView.pdb" /debug /machine:I386 /nodefaultlib /out:"$(OUTDIR)\ActView.exe" /pdbtype:sept /libpath:".\GenesisSDK\lib" /libpath:"..\..\msdev60\lib" +LINK32_OBJS= \ + "$(INTDIR)\About.obj" \ + "$(INTDIR)\drvlist.obj" \ + "$(INTDIR)\FilePath.obj" \ + "$(INTDIR)\InstCheck.obj" \ + "$(INTDIR)\rcstring.obj" \ + "$(INTDIR)\WinUtil.obj" \ + "$(INTDIR)\actview.obj" \ + "$(INTDIR)\Blender.obj" \ + "$(INTDIR)\actview.res" + +"$(OUTDIR)\ActView.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("ActView.dep") +!INCLUDE "ActView.dep" +!ELSE +!MESSAGE Warning: cannot find "ActView.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "ActView - Win32 Release" || "$(CFG)" == "ActView - Win32 Debug" +SOURCE=.\Util\About.c + +"$(INTDIR)\About.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Util\drvlist.c + +"$(INTDIR)\drvlist.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Util\FilePath.c + +"$(INTDIR)\FilePath.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Util\InstCheck.c + +"$(INTDIR)\InstCheck.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Util\rcstring.c + +"$(INTDIR)\rcstring.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Util\WinUtil.c + +"$(INTDIR)\WinUtil.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Main\actview.c + +"$(INTDIR)\actview.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Main\actview.rc + +!IF "$(CFG)" == "ActView - Win32 Release" + + +"$(INTDIR)\actview.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /x /fo"$(INTDIR)\actview.res" /i "..\..\msdev60\include" /i "Main" /d "NDEBUG" $(SOURCE) + + +!ELSEIF "$(CFG)" == "ActView - Win32 Debug" + + +"$(INTDIR)\actview.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /x /fo"$(INTDIR)\actview.res" /i "..\..\msdev60\include" /i "Main" /d "_DEBUG" $(SOURCE) + + +!ENDIF + +SOURCE=.\Main\Blender.c + +"$(INTDIR)\Blender.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + + +!ENDIF + diff --git a/ActView/Doc/ACTVIEW.HLP b/ActView/Doc/ACTVIEW.HLP new file mode 100644 index 0000000000000000000000000000000000000000..8d46c6328bddbe13b775f0eac3d02f27c10b920f GIT binary patch literal 16112 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 literal 0 HcmV?d00001 diff --git a/ActView/Doc/ActView.CNT b/ActView/Doc/ActView.CNT new file mode 100644 index 0000000..6892e0e --- /dev/null +++ b/ActView/Doc/ActView.CNT @@ -0,0 +1,15 @@ +:Base ActView.HLP +1 ActView +2 Introduction=Introduction +2 Loading an Actor=Loading_an_Actor +2 Setting the Actor's Front Position=Setting_the_Actor_s_Front_Position +2 Selecting a Motion=Selecting_a_Motion +2 Controlling Playback=Controlling_Playback +2 Adjusting Playback Speed=Adjusting_Playback_Speed +2 Adjusting Frame Step Time=Adjusting_Frame_Step_Time +2 Moving the Actor=Moving_the_Actor +2 Adjusting Actor Size=Adjusting_Actor_Size +2 Displaying Frame Rate=Displaying_Frame_Rate +2 Shortcut Keys=Shortcut_Keys +2 Setting Texture Maps Location=Setting_Texture_Maps_Location +2 Creating a Custom Actor Viewer Level=Creating_a_Custom_Actor_Viewer_Level diff --git a/ActView/Doc/ActView.doc b/ActView/Doc/ActView.doc new file mode 100644 index 0000000000000000000000000000000000000000..46f06f32e0e004092f5e6b2ae64ed01acde8de5d GIT binary patch literal 47616 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 W6MRo}pk>KG>4nPSP`ST93H*Oxy(Sz0 literal 0 HcmV?d00001 diff --git a/ActView/Doc/ActView.err b/ActView/Doc/ActView.err new file mode 100644 index 0000000..92e2edc --- /dev/null +++ b/ActView/Doc/ActView.err @@ -0,0 +1,17 @@ +Microsoft (R) Help Compiler +HCRTF 4.02.0034 +Copyright (c) Microsoft Corp 1990 - 1995. All rights reserved. +actview.hpj + HC1012: Note: topic #12 of c:\project\actview\doc\ActView.rtf : + Table cell borders are not supported. +13 Topics +1 Jump +13 Keywords +7 Bitmaps + + +Created c:\project\actview\doc\actview.hlp, 16,040 bytes +Bitmaps: 1,588 bytes +Hall+Zeck compression decreased help file by 4,371 bytes. +Compile time: 0 minutes, 0 seconds +1 note, 0 warnings diff --git a/ActView/Doc/ActView.hpj b/ActView/Doc/ActView.hpj new file mode 100644 index 0000000..b3b926d --- /dev/null +++ b/ActView/Doc/ActView.hpj @@ -0,0 +1,97 @@ +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; Help Project File for ActView +; +; This file is maintained by RoboHELP. Do not modify this file directly. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +[OPTIONS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Options section contains the following information: +; +; The optional BMROOT=entry sets the directories in which the Help Compiler +; will look for graphics. +; +; The CONTENTS=tells WinHelp which topic contains the contents. +; +; The TITLE=is displayed in the Title Bar of WINHELP.EXE +; +; The BUILD=setting allows you to create different Help systems from +; the same source file. +; +; The COMPRESS=option tells the Help Compiler how much to compress +; the Help file. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +;BMROOT=C:\Project\ActView\Doc +TITLE=Genesis3D Actor Viewer +BUILD=WINDOWS +NOTES=1 + + +COMPRESS=12 +OLDKEYPHRASE=NO +REPORT=YES +OPTCDROM=0 +DBCS=0 +CONTENTS=Introduction +COPYRIGHT=Copyright © 1999, WildTangent Inc. +ERRORLOG=C:\project\actview\doc\ActView.err +[BUILDTAGS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Build Tags section specifies to the Help Compiler the names +; of all the valid build tags used in this Help project. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +WINDOWS + + +[WINDOWS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Windows section contains all of the information about the windows +; in a Help project. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +;Gloss="Glossary",(100,100,350,350),0,(255,255,255),(255,255,255) + + +(w95sec)=,,20740,(r14745599),(r14745599),f2 +main="",(255,0,511,511),29188,(128,255,255),(255,255,128),f0 +[CONFIG] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Config section defines macros which will run at startup. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + + + +[FILES] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Files section specifies the RTF files for a project. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +ActView.rtf +[ALIAS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Alias section sets up aliases for Topic IDs in your Help system. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +[MAP] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Map section specifies the project HH files. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +[BITMAPS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Bitmaps section specifies the referenced bitmaps used in +; your help system. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +[BAGGAGE] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Baggage section specifies any additional files. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +[Config-(w95sec)] diff --git a/ActView/Doc/ActView.rbh b/ActView/Doc/ActView.rbh new file mode 100644 index 0000000..d71582a --- /dev/null +++ b/ActView/Doc/ActView.rbh @@ -0,0 +1,33 @@ +[Project] +Help Compiler=HCW.EXE +Remove Unused=0 +Version=512 +ConvertedFromV1=0 +HasGlossary=0 +Automatic Map Files=0 +NextFile=2 +WH2RH=0 +Extra Language=0 + +[Document Files] +ActView.doc=1 + +[File Properties] +HasProperties=1 +BrowseType=0 +AutoMapFile=0 +StartingWith=0 +IncrementBy=20 +NextTopicNumber=0 +StartingNumber=1 +BrowseString=ActView:0 +DefaultBuildTag= + +[VERSION] +RHFile=4.1 + +[.rbh] +CopyTo=0 +PreBatch= +PostBatch= +AutoFixRTF=0 diff --git a/ActView/Doc/ActView.rta b/ActView/Doc/ActView.rta new file mode 100644 index 0000000000000000000000000000000000000000..32a857f9c1c6d63698594b85e03f552a1873e6ec GIT binary patch literal 59 vcmWFvaWwD`H!#p=U|;~zPCy#OW@Q2ra1a#Y=It68?jPg=6k4JB4=e!y0C@) and Back Frame (<) buttons. +\par +\par }\pard\plain \s1\li115\ri130\sb80\sa120\keepn\nowidctlpar\widctlpar\outlinelevel0\adjustright \b\f1\fs32\kerning28\cgrid {\page }{\cs23\super #{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super #}{ Adjusting_Playback_Speed}}}{ }{\cs23\super ${\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super $}{ Adjusting Playback Speed}}}{ }{\cs23\super K{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super K}{ Adjusting Playback Speed}}}{ }{\cs23\super +{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super +}{ ACTVIEW:0}}}{ Adjusting Playback Speed +\par }\pard\plain \s24\li115\ri130\sa120\nowidctlpar\widctlpar\adjustright \f1\cgrid {You can adjust the speed at which the motion is played by changing the Speed value. This value is expressed as a percentage of the motion's normal speed, with the value 100 representing normal speed (i.e. 100 percent). Valid values here are from 1 to 10,000 (100 times normal speed). +\par +\par }\pard\plain \s1\li115\ri130\sb80\sa120\keepn\nowidctlpar\widctlpar\outlinelevel0\adjustright \b\f1\fs32\kerning28\cgrid {\page }{\cs23\super #{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super #}{ Adjusting_Frame_Step_Time}}}{ }{\cs23\super ${\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super $}{ Adjusting Frame Step Time}}}{ }{\cs23\super K{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super K}{ Adjusting Frame Step Time}}}{ }{\cs23\super +{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super +}{ ACTVIEW:0}}}{ Adjusting Frame Step Time +\par }\pard\plain \s24\li115\ri130\sa120\nowidctlpar\widctlpar\adjustright \f1\cgrid {The frame step time used when displaying a motion frame-by-frame is controlled by changing the value in the Frame Time edit box. This value is expressed in 100ths of a second. The default value of 5 will step the animation by 5/100 second every time the Forward Frame or Back Frame button is pressed. +\par The minimum frame step value is 1/100 second. The maximum is 1 second (100). +\par }\pard\plain \li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\cgrid { +\par }\pard\plain \s1\li115\ri130\sb80\sa120\keepn\nowidctlpar\widctlpar\outlinelevel0\adjustright \b\f1\fs32\kerning28\cgrid {\page }{\cs23\super #{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super #}{ Moving_the_Actor}}}{ }{\cs23\super ${\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super $}{ Moving the Actor}}}{ }{\cs23\super K{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super K}{ Moving the Actor}}}{ }{\cs23\super +{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super +}{ ACTVIEW:0}}}{ Moving the Actor +\par }\pard\plain \s24\li115\ri130\sa120\nowidctlpar\widctlpar\adjustright \f1\cgrid {{{{{{\pard\plain \li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\cgrid {\object\objemb\objw885\objh345{\*\objclass PBrush}{\*\objdata 01050000020000000700000050427275736800000000000000000040020000424d3602000000000000760000002800000034000000100000000100040000000000c0010000c40e0000ce0e0000000000000000000000000000000080000080000000808000800000008000800080800000c0c0c000808080000000ff0000ff000000ffff00ff000000ff00ff00ffff0000ffffff0077777700000077770077777777777777770077777777777777770000777770ffffff0777007000777777777777007777777777777077000077770fffffff07770070477777777777770077777777777704c700007770fffffffff077007074770000777777007777777777704c870000770ffffffffff07700777740777708777700777777777704c8770000770fffffffffff070077770477777077770077777777704c8777000070ffffffffffff0700777077477777070700777700004860777700000fff0fffffffff0700777077744444440000778077780807777700000ff00ffffffffff00077707774777707070077477666707777770000700fff0fffff0ff000777077747777077700747777766807777700007770ff0ff0ff0ff000777707747770777700747777776707777700007770ff0f00ff00f000777780747708777700747677777707777700007700f00ff0ff07070077777704007777770074766777770777770000770ff00ff0ff077700777777747777777700774766677077777700007770070ff00077770077777700077777770077847777487777770000777777700777777700777777707777777700777744447777777700000000000000000000000001050000050000000d0000004d45544146494c455049435400190600009ffdffff780200000800190661020000010009000003380100000000220100000000050000000b0200000000050000000c021000340022010000430f2000cc000000100034000000000010003400000000002800000034000000100000000100040000000000c0010000030d0000430a0000100000001000000000000000000080000080000000808000800000008000800080800000c0c0c000808080000000ff0000ff000000ffff00ff000000ff00ff00ffff0000ffffff007777770000007777007777777777777777007777777777777777ffff777770ffffff0777007000777777777777007777777777777077ffff77770fffffff07770070477777777777770077777777777704c7ffff7770fffffffff077007074770000777777007777777777704c87ffff770ffffffffff07700777740777708777700777777777704c877ffff770fffffffffff070077770477777077770077777777704c8777ffff70ffffffffffff07007770774777770707007777000048607777ffff0fff0fffffffff07007770777444444400007780777808077777ffff0ff00ffffffffff0007770777477770707007747766670777777ffff700fff0fffff0ff0007770777477770777007477777668077777ffff7770ff0ff0ff0ff0007777077477707777007477777767077777ffff7770ff0f00ff00f0007777807477087777007476777777077777ffff7700f00ff0ff0707007777770400777777007476677777077777ffff770ff00ff0ff0777007777777477777777007747666770777777ffff7770070ff0007777007777770007777777007784777748777777ffff7777777007777777007777777077777777007777444477777777ffff030000000000}{\result {{\nonshppict{\pict\picscalex100\picscaley100\piccropl0\piccropr0\piccropt0\piccropb0\picw1561\pich609\picwgoal885\pichgoal345\wmetafile8\bliptag2105607992\blipupi79 0100090000034401000000002201000000000400000003010800050000000b0200000000050000000c0210003400040000000701040022010000430f2000cc000000100034000000000010003400000000002800000034000000100000000100040000000000c0010000030d0000430a000010000000100000000000000080000000ff00000000008000800080000000ff00ff00ff0000800000808000000080800080808000c0c0c00000ff0000ffff000000ffff00ffffff00bbbbbb000000bbbb00bbbbbbbbbbbbbbbb00bbbbbbbbbbbbbbbb0000bbbbb0ffffff0bbb00b000bbbbbbbbbbbb00bbbbbbbbbbbbb0bb0000bbbb0fffffff0bbb00b01bbbbbbbbbbbbb00bbbbbbbbbbbb012b0000bbb0fffffffff0bb00b0b1bb0000bbbbbb00bbbbbbbbbbb012ab0000bb0ffffffffff0bb00bbbb10bbbb0abbbb00bbbbbbbbbb012abb3810bb0fffffffffff0b00bbbb01bbbbb0bbbb00bbbbbbbbb012abbbffffb0ffffffffffff0b00bbb0bb1bbbbb0b0b00bbbb00001a80bbbbffff0fff0fffffffff0b00bbb0bbb11111110000bba0bbba0a0bbbbbffff0ff00ffffffffff000bbb0bbb1bbbb0b0b00bb1bb888b0bbbbbbffffb00fff0fffff0ff000bbb0bbb1bbbb0bbb00b1bbbbb88a0bbbbbffffbbb0ff0ff0ff0ff000bbbb0bb1bbb0bbbb00b1bbbbbb8b0bbbbbffffbbb0ff0f00ff00f000bbbba0b1bb0abbbb00b1b8bbbbbb0bbbbbffffbb00f00ff0ff0b0b00bbbbbb0100bbbbbb00b1b88bbbbb0bbbbbffffbb0ff00ff0ff0bbb00bbbbbbb1bbbbbbbb00bb1b888bb0bbbbbbffffbbb00b0ff000bbbb00bbbbbb000bbbbbbb00bba1bbbb1abbbbbbffffbbbbbbb00bbbbbbb00bbbbbbb0bbbbbbbb00bbbb1111bbbbbbbbffff0400000007010100030000000000}}}}}}{ +\par }}\dpx0\dpy0\dpxsize885\dpysize345\dpfillfgcr255\dpfillfgcg255\dpfillfgcb255\dpfillbgcr255\dpfillbgcg255\dpfillbgcb255\dpfillpat0\dplinehollow}}}You can move the actor around in the world (Pan) and change its orientation (Rotate). You can also move the camera to get closer to or further from the actor (Zoom). +\par There are also six built-in orientation buttons that will display the actor's Front, Back, Left, Right, Top, and Bottom views, and a Center button that will snap the actor back to the origin (which is very useful if you Pan the actor out of view). +\par +\par }\pard\plain \s1\li115\ri130\sb80\sa120\keepn\nowidctlpar\widctlpar\outlinelevel0\adjustright \b\f1\fs32\kerning28\cgrid {\page }{\cs23\super #{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super #}{ Adjusting_Actor_Size}}}{ }{\cs23\super ${\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super $}{ Adjusting Actor Size}}}{ }{\cs23\super K{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super K}{ Adjusting Actor Size}}}{ }{\cs23\super +{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super +}{ ACTVIEW:0}}}{ Adjusting Actor Size +\par }\pard\plain \s24\li115\ri130\sa120\nowidctlpar\widctlpar\adjustright \f1\cgrid {You can control the size at which an actor is displayed by changing the Size value. The displayed value is expressed as a percentage of the actor's normal size. The valid values for this field are from 1 to 10,000 percent (100 times normal size). +\par }\pard\plain \li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\cgrid { +\par }\pard\plain \s1\li115\ri130\sb80\sa120\keepn\nowidctlpar\widctlpar\outlinelevel0\adjustright \b\f1\fs32\kerning28\cgrid {\page }{\cs23\super #{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super #}{ Displaying_Frame_Rate}}}{ }{\cs23\super ${\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super $}{ Displaying Frame Rate}}}{ }{\cs23\super K{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super K}{ Displaying Frame Rate}}}{ }{\cs23\super +{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super +}{ ACTVIEW:0}}}{ Displaying Frame Rate +\par }\pard\plain \s24\li115\ri130\sa120\nowidctlpar\widctlpar\adjustright \f1\cgrid {In many cases, it's useful to see how many animation frames are being played by the engine every second. If you wish to view this information, select Options|Show Frame Rate. The frame rate is displayed in the upper left corner of the screen along with some other information about the number of polygons displayed, etc. +\par You can toggle the frame rate display on and off quickly by pressing the E key. +\par +\par }\pard\plain \s1\li115\ri130\sb80\sa120\keepn\nowidctlpar\widctlpar\outlinelevel0\adjustright \b\f1\fs32\kerning28\cgrid {\page }{\cs23\super #{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super #}{ Setting_Texture_Maps_Location}}}{ }{\cs23\super ${\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super $}{ Setting Texture Maps Location}}}{ }{\cs23\super K{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super K}{ Setting Texture Maps Location}}}{ }{\cs23\super +{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super +}{ ACTVIEW:0}}}{ Setting Texture Maps Location +\par }\pard\plain \s24\li115\ri130\sa120\nowidctlpar\widctlpar\adjustright \f1\cgrid {To load an actor, the program requires not only the actor definition in the .act file, but also the actor's texture maps, which are stored in a directory that's specified in the actor file. Normally, this directory is a Maps subdirectory of the current working directory, but the actor creation tools allow it to be set to any arbitrary directory. +\par In an attempt to accommodate most setups, Actor Viewer will try to load an actor using three different "current directory" settings. The settings used, in order, are: +\par \tab The value set by Options|Set Working Directory \line \tab The program's Current Working Directory\line \tab The directory that contains the actor being loaded +\par If Actor Viewer can't load the actor after trying all three "current directory" settings, it will report an error. +\par }\pard\plain \s1\li115\ri130\sb80\sa120\keepn\nowidctlpar\widctlpar\outlinelevel0\adjustright \b\f1\fs32\kerning28\cgrid {\page }{\cs23\super #{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super #}{ Shortcut_Keys}}}{ }{\cs23\super ${\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super $}{ Shortcut Keys}}}{ }{\cs23\super K{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super K}{ Shortcut Keys}}}{ }{\cs23\super +{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super +}{ ACTVIEW:0}}}{ Shortcut Keys +\par }\pard\plain \li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\cgrid {Almost all of Actor Viewer's commands can be accessed by pressing hot keys. The commands and their associated hot keys are: +\par }\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \cltxlrtb \cellx4320\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \cltxlrtb \cellx8748\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {\b Command\cell Hot Key\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \clvertalt\cltxlrtb \cellx4320\clvertalt\cltxlrtb \cellx8748\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Help\cell F1\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Open file\cell Ctrl+O\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Toggle frame rate display\cell E\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Pan (move) actor\cell A\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Rotate actor\cell R\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Zoom camera\cell Z\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Play motion\cell P\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Pause motion\cell U\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Stop motion\cell S\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Rewind motion\cell 0\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Fast forward motion\cell 9\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Back frame\cell <\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Forward frame\cell >\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Front view\cell N\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Back view\cell B\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Left side view\cell L\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Right side view\cell I\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Top view\cell T\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Bottom view\cell M\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\trowd \trgaph108\trleft-108\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \clvertalt\cltxlrtb \cellx4320\clvertalt\cltxlrtb \cellx8748\pard \ri130\sa48\nowidctlpar\widctlpar\intbl\adjustright {Center actor\cell C\cell }\pard \nowidctlpar\widctlpar\intbl\adjustright {\row }\pard \li115\ri130\sa48\nowidctlpar\widctlpar\adjustright { +\par }\pard\plain \s1\li115\ri130\sb80\sa120\nowidctlpar\widctlpar\outlinelevel0\adjustright \b\f1\fs32\kerning28\cgrid {\page }{\cs23\super #{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super #}{ Creating_a_Custom_Actor_Viewer_Level}}}{ }{\cs23\super ${\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super $}{ Creating a Custom Actor Viewer Level}}}{ }{\cs23\super K{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super K}{ Creating a Custom Actor Viewer Level}}}{ }{\cs23\super +{\footnote \pard\plain \s22\li115\ri130\sa48\nowidctlpar\widctlpar\adjustright \f1\fs20\cgrid {\cs23\super +}{ ACTVIEW:0}}}{ Creating a Custom Actor Viewer Level +\par }\pard\plain \s24\li115\ri130\sa120\nowidctlpar\widctlpar\adjustright \f1\cgrid {If you want to customize the level in which Actor Viewer displays the actors, you can modify the supplied ActView.3dt file using the Genesis World Editor, compile the new level, and copy the resulting ActView.bsp and ActView.mot files to Actor Viewer's program directory. If you then restart Actor Viewer, actors will be displayed in the new level. +\par You can display actors in any level, providing you name the level ActView.bsp and copy it to the program directory. +\par Note that actors are always displayed at the world origin (position 0,0,0 as displayed in the World Editor). To maintain an acceptable frame rate, you should make your custom Actor Viewer level as simple as possible}{{\field{\*\fldinst SYMBOL 45 \\f "Symbol" \\s 12}{\fldrslt\f3\fs24\'2d}}}{preferably a hollow box or cylinder. +\par +\par +\par }} \ No newline at end of file diff --git a/ActView/Doc/ActView.rtk b/ActView/Doc/ActView.rtk new file mode 100644 index 0000000000000000000000000000000000000000..887ea08c5cbe10375ac52a577812ce68eea52f86 GIT binary patch literal 1093 zcmd^-ze^lJ6vyYzGyY7G(n1(*tfJQhLW+PnvmkeevUjLy0_*M&*X->qvvWqREG%s7 zL=d#Gv#`)kYnycX7ib|tNN4K_e&6ie1@B+Tz-QmUyw7`Ych;?!i*t*`;uK?y;ul2P z_vU+YdG_(X#g-mg%&j}+uiqBu+!-8gAGO#h%bA1OSSuMceI3f!9K6Q?Q2_6N3kGsI zXbd~XD$)zW_y_l5KJ9C%jI@j+;sbEN0cfv0HZ`F&NqR+O)u51GVw zux_nK8~b2a<=U$cW~ARpAP&K)O-8O+{doSH*IW&+g_~Ko0$z-`f%Kom2e{CGZzJ0-Uv96m+@T!-jydr(Cb4gpsCL9o0)0Dwuh$^f| zrTwPnWwDW(w>?J|u>dXgRe*=NV? z`$oJ^0vUkgcLq2Xs3@#=JmrUhc8J; z0h8Er0a7-FBgGWh9dn(+)0DHe;@1PFVh$B|(I$0zQ{o6{2ci<{3KZH3yvStP8q1=B zrEr&9%5#Ki4^suBI10sO`0fKmv>S!ZCTY$!-R^nUyQG8X5Oko~8z%9Tv<<~b_0UzL zx&f*mK+eHGTff+eb)N}cIBhBGn(zuFG6%$AqoGMt(@NZ=uGo6du9gC7SJQ<9kzu1Q_1y8oe39f#@+d>(MbkK4FF z>eC!T)m2hQcOpu58AG_vvIn49->mM`W23tn>|5}?1(GSR$z|1vq^P*H0)#FF3 z6(F%>z%82-o2TsL%U^qH>P#Rlhpx5*gXT2CNO>J4PRMSo89xSV*eKUg%A=G1{l;k0 zKTR2Wt3WZ5Xj6YKMGR!vvL`<8%Ox3!vRsr+O+Gl#K$3(H$RybtFiG4b4R-r~{m)O} E4;$n{kpKVy literal 0 HcmV?d00001 diff --git a/ActView/Doc/ffend.bmp b/ActView/Doc/ffend.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8501339be8f67e3399c56b4c890860f2835b5d4a GIT binary patch literal 246 zcmaJ)u?>JQ3^Ni^HpCg+!Okz4$ePnSFmn!Tandp%B;43e<5pR>3k^GMA?MBkV+Kw= zCg3FBaDWB(W>mH)rO+d&S*SHSk|#zK`vqe$HKW5+(nXODg~U7&-tSM|-#`Cz&v)Go D_d-K& literal 0 HcmV?d00001 diff --git a/ActView/Doc/ffframe.bmp b/ActView/Doc/ffframe.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f06a4d8f8120adef90f179a3950cf97d7ee2e31e GIT binary patch literal 246 zcmah>ISzm@3^Ni^H^eh|2RnbsMAkg512fNIEp{nFNJzMG4#&;B9JsKuOytq;7~aFma5Eox5bhYfjZU12b1jpPh&Z$^dTu_wTopIM>@cDdG-a zz!{vtqysE1)E`Ib3Em@1Ealu1j8rLw?1dUjwYma)Zb8;#2o3ov{^cdJ*<_K-xQ}D_ u4bQ22Nv7~3w>~L#Z}x4zH$mNNq7`<1H15y)c5fT(W4?IlczDeGleYm%CwKt> literal 0 HcmV?d00001 diff --git a/ActView/Doc/move.bmp b/ActView/Doc/move.bmp new file mode 100644 index 0000000000000000000000000000000000000000..fd4cd3846e59a879686cedd167a3b5adc65cc8ef GIT binary patch literal 566 zcmY+AF;2xW42JzsrM!u73=V*p5vtTTz#W)g88bvNV+SOz)d2}6&XOC1&rS<^Y3x}3 z{M%_BpYN~4SHa(6ci0VfkO42U9z;H`MSif$wTQ4~S^9w|lyzM>4K&}x0H0&HOR z#*o3hC6}SOGBH?@$mzv=Y%X+`$8n_7qHo9GtoDJX%Uw5>Grg^+3uE1x3Kiwmb^JrD zY{rD_cY*2r$9O_xOZI=r1=yKXbbdV@D4=JVcNU%bb67Wm={)zlXbL{eC3J$ltDY>d ORO%^z6=OP%WMRLsT*@v0 literal 0 HcmV?d00001 diff --git a/ActView/Doc/pan.bmp b/ActView/Doc/pan.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8da4c9c7f591e1c1b157581f90ff54decc47b31b GIT binary patch literal 246 zcmY+7u?+(;2t|LSNbcf{kvY=eE?0%tqq(>`vrwhw9yp2=8+d%c=DB^e&I>&7``0hJ zR$~y4oAk#2&yX;Uu|Oo%oD*gv$`p|q&dn0R%%~7;M>g0OQ-&}3W3(zW*dynl7k#fn YcfRS4C0XMpN4I7SLe}u4_K~se1bQlBX8-^I literal 0 HcmV?d00001 diff --git a/ActView/Doc/pause.bmp b/ActView/Doc/pause.bmp new file mode 100644 index 0000000000000000000000000000000000000000..dec2f0f3a35e4f773fbb76ae2c1acd233ef1d301 GIT binary patch literal 246 zcmZ?r{l)+RWk5;;hy|dSk%0v)(Eucm@G&r)17cLrz`y`R3=Its3P=K(3wcmN42VB4g4096S^XTHr_67^04D25i~s-t literal 0 HcmV?d00001 diff --git a/ActView/Doc/rotate.bmp b/ActView/Doc/rotate.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b3474c87ae3b5897b8b50a9a93d9a6b51f10113e GIT binary patch literal 246 zcmY*Ru?+$+3^P)tG9k|341_8%@k@pZuQ{y)Gv}}trzrz&9jA_)+v9`8Q*sf{n+KFN zaMjldc#HpVKo{;Qs%kODkj7xHi#ekcb;45NhV9PoX;>%Hx{}B63TYCf617TuYYm~l Xw^V`JSB~EEAIn~?+yWvc#5R5bpnFRT literal 0 HcmV?d00001 diff --git a/ActView/Doc/rrframe.bmp b/ActView/Doc/rrframe.bmp new file mode 100644 index 0000000000000000000000000000000000000000..02c0a261f26642d6e3767bf3a9c4c2e032d10ee9 GIT binary patch literal 246 zcmah>u?>JQ3^NiE8{!P^VCR=iWX)+Em^p{F*exIs18!`mb((43QL)fQayZ$bEkRJ% z9@xk?0$?Gc8kH?lN^}Le6mnKa^5}`;|1kGXQ*e_T9CE<_JBim4e)g+@X&QXz;ecws3 CoI`H_ literal 0 HcmV?d00001 diff --git a/ActView/Doc/stop.bmp b/ActView/Doc/stop.bmp new file mode 100644 index 0000000000000000000000000000000000000000..25bb7a0c75ca14ef0b736d56a66597607b9dcc1d GIT binary patch literal 246 zcmZ?r{l)+RWk5;;hy|dSk%0v)(Eucm@G&r)17cLrz`y`R3=Its3P=K(326}dEi3jitnMN0qx literal 0 HcmV?d00001 diff --git a/ActView/Doc/zoom.bmp b/ActView/Doc/zoom.bmp new file mode 100644 index 0000000000000000000000000000000000000000..78190aa6ce0691d0140e0db413730527f5f7045e GIT binary patch literal 246 zcmY+6F%H5o5Cj*=Qm7Em;2lw5;f-kc4xdT3$b!9+}oM%X7QA!bQQN2;CIgO58Nw}(MN#W&YIzF7?{TG4Z kteAP*He#Pfdvzt#MOkDtCK+dRvLB=WekTX5$gVT}0kXeNYXATM literal 0 HcmV?d00001 diff --git a/ActView/Main/ActView.aps b/ActView/Main/ActView.aps new file mode 100644 index 0000000000000000000000000000000000000000..27d0ec959b1e44d3c48b49a27f7a3a434e4bf1e0 GIT binary patch literal 87444 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 cp^YYg{{K~gi3v?J1B;7Xte~pe(jsO4v literal 0 HcmV?d00001 diff --git a/ActView/Main/ActView.rc b/ActView/Main/ActView.rc new file mode 100644 index 0000000..69a679c --- /dev/null +++ b/ActView/Main/ActView.rc @@ -0,0 +1,372 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MAINICON ICON DISCARDABLE "..\\res\\actview.ico" +IDI_PLAY ICON DISCARDABLE "..\\res\\play.ico" +IDI_RRSTART ICON DISCARDABLE "..\\res\\rrstart.ico" +IDI_RRFRAME ICON DISCARDABLE "..\\res\\rrframe.ico" +IDI_STOP ICON DISCARDABLE "..\\res\\stop.ico" +IDI_FFFRAME ICON DISCARDABLE "..\\res\\ffframe.ico" +IDI_FFEND ICON DISCARDABLE "..\\res\\ffend.ico" +IDI_PAUSE ICON DISCARDABLE "..\\res\\pause.ico" +IDI_ZOOM ICON DISCARDABLE "..\\res\\zoom.ico" +IDI_PAN ICON DISCARDABLE "..\\res\\pan.ico" +IDI_ROTATE ICON DISCARDABLE "..\\res\\rotate.ico" +IDI_BLEND ICON DISCARDABLE "..\\res\\blend.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_ACTVIEW BITMAP DISCARDABLE "..\\res\\actview.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU1 MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Open\tCtrl+O", ID_FILE_OPEN + MENUITEM "E&xit", ID_FILE_EXIT + END + POPUP "&Options" + BEGIN + MENUITEM "&Save as front", ID_OPTIONS_FRONT + MENUITEM "Show &Frame Rate\tE", ID_OPTIONS_FRAMERATE + END + POPUP "&Help" + BEGIN + MENUITEM "&Contents\tF1", ID_HELP_CONTENTS + MENUITEM SEPARATOR + MENUITEM "&About", ID_HELP_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ACTOR DIALOGEX 0, 0, 328, 138 +STYLE WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Genesis3D Actor Viewer" +MENU IDR_MENU1 +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "Initializing Genesis3D Engine...",IDC_RENDERWIN,5,4,114, + 14 + LTEXT "0.0",IDC_STATICSTART,13,25,73,8 + CTEXT "Static",IDC_STATICCURRENTTIME,142,25,42,8,SS_SUNKEN + LTEXT "0.0",IDC_STATICEND,266,25,45,8,0,WS_EX_RIGHT + CONTROL "Slider1",IDC_SLIDERTIME,"msctls_trackbar32",TBS_TOP | + WS_TABSTOP,5,35,316,19 + PUSHBUTTON "P&an",IDC_PAN,5,64,20,20,BS_ICON | WS_GROUP + PUSHBUTTON "&Rotate",IDC_ROTATE,26,64,20,20,BS_ICON + PUSHBUTTON "&Zoom",IDC_ZOOM,47,64,20,20,BS_ICON + LTEXT "Motion",IDC_STATICMOTION,73,60,22,8 + COMBOBOX IDC_MOTIONCOMBO,73,70,74,80,CBS_DROPDOWNLIST | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + CONTROL "Loop",IDC_LOOPED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 152,73,30,10 + LTEXT "Scale:",IDC_STATICSCALE,186,60,21,8 + EDITTEXT IDC_EDITSCALE,186,70,40,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPINSCALE,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | + UDS_NOTHOUSANDS,220,70,11,14 + LTEXT "Speed:",IDC_STATICSPEED,231,60,24,8 + EDITTEXT IDC_EDITSPEED,231,70,40,14,ES_NUMBER + CONTROL "Spin2",IDC_SPINSPEED,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | + UDS_NOTHOUSANDS,264,70,11,14 + LTEXT "Frame step:",IDC_STATICFRAME,276,60,38,8 + EDITTEXT IDC_EDITFRAMETIME,276,70,40,14,ES_NUMBER + CONTROL "Spin2",IDC_SPINFRAMETIME,"msctls_updown32", + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS | UDS_NOTHOUSANDS,310,70,11,14 + PUSHBUTTON "Fro&nt",IDC_FRONT,5,90,30,13,WS_GROUP + PUSHBUTTON "&Back",IDC_BACK,37,90,30,13 + PUSHBUTTON "&Left",IDC_LEFT,5,104,30,13 + PUSHBUTTON "R&ight",IDC_RIGHT,37,104,30,13 + PUSHBUTTON "&Top",IDC_TOP,5,118,30,13 + PUSHBUTTON "Botto&m",IDC_BOTTOM,37,118,30,13 + PUSHBUTTON "&Center",IDC_CENTER,69,90,30,13 + PUSHBUTTON "&Play",IDI_PLAY,238,90,41,20,BS_ICON | WS_GROUP + PUSHBUTTON "Pa&use",IDI_PAUSE,280,90,20,20,BS_ICON + PUSHBUTTON "&Stop",IDI_STOP,301,90,20,20,BS_ICON + PUSHBUTTON "RRStart&0",IDI_RRSTART,238,111,20,20,BS_ICON + PUSHBUTTON "RRFrame&<",IDI_RRFRAME,259,111,20,20,BS_ICON + PUSHBUTTON "FFFrame&>",IDI_FFFRAME,280,111,20,20,BS_ICON + PUSHBUTTON "FFEnd&9",IDI_FFEND,301,111,20,20,BS_ICON + PUSHBUTTON "Blen&d",IDC_BLEND,138,105,50,20,BS_ICON +END + +IDD_DRIVERDIALOG DIALOG DISCARDABLE 0, 0, 253, 130 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Genesis3D Actor Viewer" +FONT 8, "MS Sans Serif" +BEGIN + LISTBOX IDC_DRIVERLIST,11,25,231,67,LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + LTEXT "Select a video mode",IDC_STATIC,13,11,164,12 + DEFPUSHBUTTON "OK",IDOK,50,103,50,14 + PUSHBUTTON "Cancel",IDCANCEL,146,103,50,14 +END + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 145, 119 +STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "About Actor Viewer" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,98,50,14 + LTEXT "Genesis3D Actor Viewer Version 2.0",IDC_STATIC,15,76, + 115,8 + LTEXT "Copyright © 1999, WildTangent, Inc.",IDC_STATIC,8,86, + 128,8 + CONTROL 126,IDB_ACTVIEW,"Static",SS_BITMAP | SS_SUNKEN | + WS_BORDER,10,7,125,64 +END + +IDD_BLENDER DIALOG DISCARDABLE 0, 0, 322, 207 +STYLE WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Motion Blender" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Motions:",IDC_STATIC,7,125,34,8 + LISTBOX IDC_MOTIONSLIST,7,134,93,66,LBS_SORT | + LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add",IDC_ADD,104,134,50,14 + PUSHBUTTON "Remove",IDC_REMOVE,266,55,50,14 + PUSHBUTTON "Move up",IDC_MOVEUP,266,10,50,14 + PUSHBUTTON "Move Down",IDC_MOVEDOWN,266,31,50,14 + CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | SS_SUNKEN,7,121, + 309,1 + LTEXT "Time Offset",IDC_STATIC,165,151,37,8 + EDITTEXT IDC_EDITTIMEOFFSET,209,149,26,12,ES_AUTOHSCROLL + LTEXT "Start Time",IDC_STATIC,165,170,37,8 + EDITTEXT IDC_EDITSTARTTIME,209,168,26,12,ES_AUTOHSCROLL + LTEXT "End Time",IDC_STATIC,165,188,37,8 + EDITTEXT IDC_EDITENDTIME,209,187,26,12,ES_AUTOHSCROLL + LTEXT "Time Scale",IDC_STATIC,242,151,37,8 + EDITTEXT IDC_EDITTIMESCALE,284,149,26,12,ES_AUTOHSCROLL + LTEXT "Start Blend",IDC_STATIC,243,170,37,8 + EDITTEXT IDC_EDITSTARTBLEND,284,168,26,12,ES_AUTOHSCROLL | + ES_NUMBER + LTEXT "End Blend",IDC_STATIC,243,188,37,8 + EDITTEXT IDC_EDITENDBLEND,284,187,26,12,ES_AUTOHSCROLL | + ES_NUMBER + PUSHBUTTON "Test Output",IDC_TESTOUT,266,90,50,14 + CONTROL "",IDC_STATICBLEND,"Static",SS_BLACKFRAME,7,7,253,110 + CTEXT "Submotion",IDC_STATICSUBMOTION,169,132,140,10,SS_SUNKEN +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Cursor +// + +IDC_ZOOM CURSOR DISCARDABLE "..\\res\\zoom.cur" +IDC_PAN CURSOR DISCARDABLE "..\\res\\pan.cur" +IDC_ROTATE CURSOR DISCARDABLE "..\\res\\rotate.cur" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE +BEGIN + "E", ID_OPTIONS_FRAMERATE, VIRTKEY, NOINVERT + "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT + VK_ESCAPE, IDC_NOTHING, VIRTKEY, NOINVERT + VK_F1, ID_HELP_CONTENTS, VIRTKEY, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 138 + TOPMARGIN, 7 + BOTTOMMARGIN, 112 + END + + IDD_BLENDER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 316 + TOPMARGIN, 7 + BOTTOMMARGIN, 200 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_CLASSNAME "MOTION_BLENDER_WINDOW_CLASS" + IDS_PROGRAMNAME "Genesis3D Actor Viewer" + IDS_UNIQUEMESSAGE "ActorViewerUniqueMessageString" + IDS_DEFAULTPOSE "(Default Pose)" + IDS_BLENDEDMOTION "(Blended Motion)" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_FILE_EXIT "Exit the program" + ID_FILE_OPEN "Open a file" + ID_MOTION_SELECT "Select motion" + ID_OPTIONS_FRONT "Save current orientation as front" + ID_OPTIONS_FRAMERATE "Toggle frame rate counter" + IDS_CANTADDWORLD "Can't add world to engine." + IDS_CANTSTARTTIMER "Can't start timer. Animations will not function." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDC_PAN "Pan A" + IDC_ROTATE "Rotate R" + IDC_ZOOM "Zoom Z" + IDI_PLAY "Play P" + IDI_PAUSE "Pause U" + IDI_RRSTART "Go to start 0" + IDI_RRFRAME "Back frame <" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDI_STOP "Stop S" + IDI_FFFRAME "Forward frame >" + IDI_FFEND "Go to end 9" + IDC_FRONT "Front view N" + IDC_EDITSCALE "Actor scale (percent of normal)" + IDC_BACK "Back view B" + IDC_EDITSPEED "Animation speed (percent of normal)" + IDC_LEFT "Left side view L" + IDC_RIGHT "Right side view I" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_CANTCREATEENGINE "Could not create engine" + IDS_CANTCREATECAMERA "Could not create camera" + IDS_CANTCREATEWORLD "Could not create world" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDC_EDITFRAMETIME "Frame step time (1/100 second)" + IDC_TOP "Top view T" + IDC_BOTTOM "Bottom view B" + IDC_STATICEND "Animation ending time" + IDS_STATICSTART "Animation start time" + IDC_STATICCURRENTTIME "Current animation time (in seconds)" + IDC_CENTER "Center actor at origin C" + IDC_BLEND "Blend Motion D" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_CANTLOADDRIVER "Couldn't load graphics driver" + IDS_CANTINITENGINE "Unable to initialize engine" + IDS_CANTLOADACTOR "Couldn't load actor file '%s'" + IDS_BEGINFRAMEFAIL "EngineBeginFrame failed." + IDS_RENDERFAIL "Could not render the world." + IDS_INIFILENAME "ActView.ini" + IDS_ENDFRAMEFAIL "EngineEndFrame failed." + IDS_HELPFILENAME "ActView.hlp" + IDS_PROGRAMBASENAME "ActView" + IDS_ACTFILEFILTER "*.act" + IDS_ACTFILEEXT "act" + IDS_ACTFILEFILTERDESC "Genesis3D Actor Files (.act)" + IDS_UNNAMED "(Unnamed %d)" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ActView/Main/Blender.h b/ActView/Main/Blender.h new file mode 100644 index 0000000..c325a2a --- /dev/null +++ b/ActView/Main/Blender.h @@ -0,0 +1,57 @@ +/****************************************************************************************/ +/* BLENDER.H */ +/* */ +/* Author: Jim Mischel */ +/* Description: Actor Viewer's motion blender dialog box. */ +/* */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef BLENDER_H +#define BLENDER_H + +#include +#include "genesis.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#define WM_BLENDERCLOSING WM_USER + 1 +#define WM_BLENDERMOTIONCHANGED WM_USER + 2 + +#define DEFAULT_POSE_INDEX -1 + +HWND Blender_Create + ( + HWND hwndParent, + HINSTANCE hinst, + geActor_Def *ActorDef, + geMotion *BlendedMotion + ); + +void Blender_UpdateActor + ( + HWND hwndBlender, + geActor_Def *ActorDef, + geMotion *BlendedMotion + ); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/ActView/Main/actview.c b/ActView/Main/actview.c new file mode 100644 index 0000000..0db7d85 --- /dev/null +++ b/ActView/Main/actview.c @@ -0,0 +1,2123 @@ +/****************************************************************************************/ +/* ACTVIEW.C */ +/* */ +/* Author: Jim Mischel */ +/* Description: Actor Viewer and Motion Blender. Main module. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include +#pragma warning(disable : 4201 4214 4115) +#include +#include +#include +#include +#pragma warning(default : 4201 4214 4115) + +#include +#include +#include +#include "genesis.h" +#include "rcstring.h" +#include "resource.h" +#include "InstCheck.h" +#include "FilePath.h" +#include "ram.h" +#include +#include "drvlist.h" +#include "about.h" +#include "units.h" +#include "blender.h" + +#pragma warning (disable:4514) // unreferenced inline function + +#pragma message ("Need to disable buttons when no actor selected") + +#define USER_ALL 0xffffffff + +#define ACTOR_WINDOW_WIDTH 480 +#define ACTOR_WINDOW_HEIGHT 360 + +#define RENDER_BORDER 5 + +#define DEFAULT_POSE_INDEX -1 +#define BLENDED_MOTION_INDEX -2 + +// Message string used to create a custom message for the multimedia timer stuff. +static const char ActViewMessageString[] = "ActorViewerMessageString"; + +#define DESIRED_MMTIMER_FREQUENCY 33 +#define DESIRED_MMTIMER_RESOLUTION (DESIRED_MMTIMER_FREQUENCY/5) +#define LORES_TIMER_NUMBER 1 + +typedef enum +{ + AWM_NONE, + AWM_PAN, + AWM_ROTATE, + AWM_ZOOM +} ActView_Mode; + +typedef enum +{ + PLAYMODE_STOP, + PLAYMODE_PLAY, + PLAYMODE_PAUSE +} ActView_PlayMode; + +typedef struct +{ + HINSTANCE Instance; + HWND hwnd; + char ActorFilename[MAX_PATH]; + char IniFilename[MAX_PATH]; + char LastDir[MAX_PATH]; + ActView_Mode MouseMode; // Mouse mode (none, pan, rotate, zoom) + HWND hwndTT; // tooltips window + HWND hwndBlender; // motion blender dialog + + // Engine and such + geEngine *Engine; + geWorld *World; + geCamera *Camera; + GE_Rect Rect; + geFloat XRotCam, YRotCam, Dist, Height; + BOOL ShowFrameRate; + + // animation stuff + DWORD MotionStartTime; + geFloat LastFrameTime; + ActView_PlayMode PlayMode; + int Scale; + int Speed; + int FrameDelta; + geFloat StartExtent, EndExtent, MotionLength; + geBoolean Loop; + + // actor stuff + geActor_Def *ActorDef; + geActor *Actor; + geFloat InitialXRot, InitialYRot; + geFloat XRotActor, YRotActor; + geVec3d ActorPos, ActorDefaultPos; + geMotion *Motion; + int LastX, LastY; // for mouse movement... + int CurrentMotion; + geMotion *BlendedMotion; + + // timer stuff + UINT loresTimer; + MMRESULT hiresTimer; + UINT TimerMessageId; + BOOL ProcessingTimerMessage; +} ActView_WindowData; + +/* + There's some serious ugliness here, but I don't know a way around it. + The ActView_ToolHook and ActView_DlgHandle variables must be global + in order for the tooltips to work. I don't have to like it... +*/ +static HHOOK ActView_ToolHook = NULL; +static HWND ActView_DlgHandle = NULL; + +static ActView_WindowData *ActView_GetWindowData (HWND hwnd) +{ + return (ActView_WindowData *)GetWindowLong (hwnd, GWL_USERDATA); +} + +// Turn an integer value into a percentage expressed in floating point. (Divides by 100) +static geFloat floatPercent (int Val) +{ + geFloat fPercent = ((geFloat)Val)/100.0f; + + return fPercent; +} + +// Turn a floating point value into an integer percentage. (Multiplies by 100). +static int MakePercent (geFloat fVal) +{ + int iPercent; + + iPercent = (int)floor((fVal * 100.0f) + 0.5f); + return iPercent; +} + +// returns GE_TRUE if the requested key is currently being pressed +static geBoolean IsKeyDown(int KeyCode) +{ + return (GetAsyncKeyState (KeyCode) & 0x8000) ? GE_TRUE : GE_FALSE; +} + +/* + Formats an error message and displays a message box with that error. + The passed FormatStringID is the resource identifier of the format string. +*/ +static void MyError + ( + HWND hwnd, + HINSTANCE hinst, + int FormatStringID, + ... + ) +{ + char Buffer[1024]; + const char *FormatString; + va_list argptr; + + va_start (argptr, FormatStringID); + FormatString = rcstring_Load (hinst, FormatStringID); + vsprintf (Buffer, FormatString, argptr); + va_end (argptr); + + MessageBox (hwnd, Buffer, rcstring_Load (hinst, IDS_PROGRAMNAME), MB_ICONEXCLAMATION | MB_OK); +} + +// Set up the dialog's title bar. +static void ActView_SetupTitle + ( + ActView_WindowData *pData + ) +{ + char Title[MAX_PATH+100]; + const char *ProgramName = rcstring_Load (pData->Instance, IDS_PROGRAMNAME); + + // If there's an actor loaded, display the file name in the title bar. + if (pData->ActorFilename[0] == '\0') + { + strcpy (Title, ProgramName); + } + else + { + sprintf (Title, "%s - %s", ProgramName, pData->ActorFilename); + } + SetWindowText (pData->hwnd, Title); +} + +// Sets the menu option to indicate state of frame rate display. +// Instructs engine to enable/disable frame rate counter. +static void ActView_SetFrameRateToggle + ( + ActView_WindowData *pData + ) +{ + HMENU Menu = GetMenu (pData->hwnd); + if (Menu != NULL) + { + CheckMenuItem + ( + Menu, + ID_OPTIONS_FRAMERATE, + MF_BYCOMMAND | (pData->ShowFrameRate ? MF_CHECKED : MF_UNCHECKED) + ); + } + // tell engine not to show frame rate + geEngine_EnableFrameRateCounter (pData->Engine, pData->ShowFrameRate); +} + +// Hook procedure for checking on mouse messages passed to the dialog box. +// This is required in order to make the tooltips work. +static LRESULT CALLBACK ActView_HookProc + ( + int nCode, + WPARAM wParam, + LPARAM lParam + ) +{ + MSG *pMsg; + + pMsg = (MSG *)lParam; + // We're only interested in mouse messages for windows that are children of the main dialog. + if ((nCode >= 0) && (IsChild (ActView_DlgHandle, pMsg->hwnd))) + { + switch (pMsg->message) + { + case WM_MOUSEMOVE : + case WM_LBUTTONDOWN : + case WM_LBUTTONUP : + case WM_RBUTTONDOWN : + case WM_RBUTTONUP : + { + ActView_WindowData *pData = (ActView_WindowData *)GetWindowLong (ActView_DlgHandle, GWL_USERDATA); + + // if we find such a message, we relay it to the tooltip control, + // which in turn sends a TTN_NEEDTEXT query to the dialog + if (pData->hwndTT != NULL) + { + MSG msg; + + msg.lParam = pMsg->lParam; + msg.wParam = pMsg->wParam; + msg.message = pMsg->message; + msg.hwnd = pMsg->hwnd; + SendMessage (pData->hwndTT, TTM_RELAYEVENT, 0, (LPARAM)&msg); + } + break; + } + + default : + break; + } + } + + return CallNextHookEx (ActView_ToolHook, nCode, wParam, lParam); +} + +static void SetSpinnerRange (HWND hwnd, int Spinner, short low, short high) +{ + SendDlgItemMessage (hwnd, Spinner, UDM_SETRANGE, 0, MAKELONG (high, low)); +} + +// Sets the value of an edit control and updates the associated spinner's value. +static void SetEditControlValue (HWND hwnd, int Edit, int Spinner, int ValuePercent) +{ + int Pos = ValuePercent; + + SetDlgItemInt (hwnd, Edit, Pos, FALSE); + SendDlgItemMessage (hwnd, Spinner, UDM_SETPOS, 0, MAKELONG (Pos, 0)); +} + +// Sets up the slider's range and displays the the ending time value +static void SetSliderRange (ActView_WindowData *pData, int SliderId) +{ + int StartRange, EndRange; + char sTime[100]; + + StartRange = MakePercent (pData->StartExtent); + EndRange = MakePercent (pData->EndExtent); + SendDlgItemMessage (pData->hwnd, SliderId, TBM_SETRANGEMIN, FALSE, StartRange); + SendDlgItemMessage (pData->hwnd, SliderId, TBM_SETRANGEMAX, TRUE, EndRange); + + sprintf (sTime, "%.2f", pData->StartExtent); + SetDlgItemText (pData->hwnd, IDC_STATICSTART, sTime); + + sprintf (sTime, "%.2f", pData->EndExtent); + SetDlgItemText (pData->hwnd, IDC_STATICEND, sTime); +} + +// Sets the slider's current position and displays the current slider time +// in the box above the slider. +static void SetSliderTime (HWND hwnd, int SliderId, geFloat FTime) +{ + char sTime[100]; + int iPercent; + + iPercent = MakePercent (FTime); + SendDlgItemMessage (hwnd, SliderId, TBM_SETPOS, TRUE, iPercent); + + sprintf (sTime, "%.2f", FTime); + SetDlgItemText (hwnd, IDC_STATICCURRENTTIME, sTime); +} + +// Set the engine's camera attributes from the passed transform and rectangle +static void SetupCamera(geCamera *Camera, GE_Rect *Rect, geXForm3d *XForm) +{ + geCamera_SetWorldSpaceXForm (Camera, XForm); + geCamera_SetAttributes (Camera, 2.0f, Rect); +} + +// Create a transform from the passed rotations and distance +static void SetupXForm (geXForm3d *XForm, geFloat XRot, geFloat YRot, geFloat Dist) +{ + geXForm3d_SetTranslation (XForm, 0.0f, 0.0f, Dist); + + geXForm3d_RotateX(XForm, XRot); + geXForm3d_RotateY(XForm, YRot); +} + +static void ActView_UpdateFrame (ActView_WindowData *pData) +{ + // do frame update + if (pData == NULL) + { + return; + } + + if ((pData->Engine == NULL) || (pData->World == NULL) || (pData->Camera == NULL)) + { + return; + } + + // Always begin frame (last parameter is clear screen flag) + if (!geEngine_BeginFrame (pData->Engine, pData->Camera, GE_TRUE)) + { + MyError (pData->hwnd, pData->Instance, IDS_BEGINFRAMEFAIL); + } + + { + geXForm3d XForm; + + // Set up the render camera + SetupXForm (&XForm, pData->XRotCam, pData->YRotCam, pData->Dist); + geXForm3d_Translate (&XForm, 0.0f, pData->Height, 0.0f); + SetupCamera (pData->Camera, &pData->Rect, &XForm); + + // Set up transform for actor motion + SetupXForm (&XForm, pData->XRotActor, pData->YRotActor, 0.0f); + + // adjust position based on default pos, current rotation, and X,Y panning... + { + geXForm3d XFormPos; + + geXForm3d_SetTranslation (&XFormPos, pData->ActorDefaultPos.X, pData->ActorDefaultPos.Y, pData->ActorDefaultPos.Z); + geXForm3d_Translate (&XForm, pData->ActorPos.X, pData->ActorPos.Y, pData->ActorPos.Z); + geXForm3d_Multiply (&XForm, &XFormPos, &XForm); + } + + // If we have a current motion, then display the actor at + // the proper key time. Otherwise clear the pose. + if (pData->Actor != NULL) + { + if (pData->Motion != NULL) + { + geFloat MotionTime = 0.0f; + switch (pData->PlayMode) + { + case PLAYMODE_PLAY : + { + // playing, so update current frame time... + DWORD CurrentTime; + geFloat ElapsedSeconds; + + CurrentTime = timeGetTime (); + // Convert elapsed milliseconds from timeGetTime to seconds. + ElapsedSeconds = ((geFloat)(CurrentTime - pData->MotionStartTime))/1000.0f; + // And then apply speed factor + ElapsedSeconds *= ((geFloat)pData->Speed)/100.0f; + + // check for looping... + if (pData->Loop) + { + MotionTime = pData->StartExtent + (geFloat)fmod (ElapsedSeconds, pData->MotionLength); + } + else + { + // and stop animation if not looping + if (ElapsedSeconds > pData->MotionLength) + { + pData->PlayMode = PLAYMODE_STOP; + MotionTime = pData->EndExtent; + } + else + { + MotionTime = pData->StartExtent + ElapsedSeconds; + } + } + break; + } + + case PLAYMODE_STOP : + case PLAYMODE_PAUSE : + MotionTime = pData->LastFrameTime; + break; + } + + // Update frame time + pData->LastFrameTime = MotionTime; + // Set actor's pose + geActor_SetPose (pData->Actor, pData->Motion, MotionTime, &XForm); + // and update the slider + SetSliderTime (pData->hwnd, IDC_SLIDERTIME, pData->LastFrameTime); + } + else + { + geActor_ClearPose (pData->Actor, &XForm); + } + } + } + + // All world changes are made...render the results. + if (!geEngine_RenderWorld (pData->Engine, pData->World, pData->Camera, 0.0f)) + { + MyError (pData->hwnd, pData->Instance, IDS_RENDERFAIL); + } + + // Always end frame + if (!geEngine_EndFrame (pData->Engine)) + { + MyError (pData->hwnd, pData->Instance, IDS_ENDFRAMEFAIL); + } +} + +// Load an actor from the passed filename. +// returns TRUE if the actor is loaded successfully. +// This will unload any currently-loaded actor. +BOOL ActView_LoadActor + ( + HWND hwnd, + const char *ActorFilename + ) +{ + ActView_WindowData *pData = (ActView_WindowData *)GetWindowLong (hwnd, GWL_USERDATA); + + { + geActor_Def *ActorDef = NULL; + geActor *Actor; + + { + // Open VFS directory... + geVFile *ActorDir; + char ActorPath[MAX_PATH]; + + FilePath_GetDriveAndDir (ActorFilename, ActorPath); + // OpenNewSystem doesn't like the path to have a trailing '\' + if (ActorPath [strlen (ActorPath)-1] =='\\') + { + ActorPath[strlen (ActorPath)-1] = '\0'; + } + + ActorDir = geVFile_OpenNewSystem (NULL, GE_VFILE_TYPE_DOS, ActorPath, NULL, GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_READONLY); + + if (ActorDir != NULL) + { + // open actor file + geVFile *ActorFile; + char ActorName[MAX_PATH]; + + FilePath_GetNameAndExt (ActorFilename, ActorName); + ActorFile = geVFile_Open (ActorDir, ActorName, GE_VFILE_OPEN_READONLY); + if (ActorFile != NULL) + { + // and load the actor from that file + ActorDef = geActor_DefCreateFromFile (ActorFile); + // close the VFS file + geVFile_Close (ActorFile); + } + } + + if (ActorDef == NULL) + { + return GE_FALSE; + } + } + + // Actor definition is loaded. + // Create it and place it in the world. + Actor = geActor_Create (ActorDef); + if (Actor == NULL) + { + geActor_DefDestroy (&ActorDef); + return GE_FALSE; + } + + // and add the new actor to the world... + if (geWorld_AddActor (pData->World, Actor, GE_ACTOR_RENDER_ALWAYS | GE_ACTOR_COLLIDE, USER_ALL) == GE_FALSE) + { + geActor_Destroy (&Actor); + geActor_DefDestroy (&ActorDef); + return GE_FALSE; + } + + // got the actor. Remove previous actor from world. + if (pData->Actor != NULL) + { + geWorld_RemoveActor (pData->World, pData->Actor); + geActor_Destroy (&pData->Actor); + pData->Actor = NULL; + } + + if (pData->ActorDef != NULL) + { + geActor_DefDestroy (&pData->ActorDef); + pData->ActorDef = NULL; + } + + pData->ActorDef = ActorDef; + pData->Actor = Actor; + + pData->Motion = NULL; + + // copy the new filename + strcpy (pData->ActorFilename, ActorFilename); + } + + + { + // Set the actor's position and default pose. + + geVec3d BoxPos; + geXForm3d XForm; + geExtBox ExtBox; + + pData->XRotActor = pData->InitialXRot; + pData->YRotActor = pData->InitialYRot; + + // Get the actor's bounding box, + // and place the center of the bounding box at the origin... + geXForm3d_SetIdentity (&XForm); + + // set the actor's default pose + geActor_ClearPose (pData->Actor, &XForm); + geActor_GetDynamicExtBox (pData->Actor, &ExtBox); + + geVec3d_Add (&ExtBox.Min, &ExtBox.Max, &BoxPos); + // save position for centering... + geVec3d_Scale (&BoxPos, -0.5f, &pData->ActorDefaultPos); + // current offsets from center are 0 + geVec3d_Clear (&pData->ActorPos); + } + + { + // Fill motion combo box with the actor's motions. + int NumMotions; + int iMotion; + HWND hwndCombo; + int Index; + + hwndCombo = GetDlgItem (hwnd, IDC_MOTIONCOMBO); + SendMessage (hwndCombo, CB_RESETCONTENT, 0, 0); + + NumMotions = geActor_GetMotionCount (pData->ActorDef); + for (iMotion = 0; iMotion < NumMotions; ++iMotion) + { + const char *MotionName = geActor_GetMotionName (pData->ActorDef, iMotion); + char TempName[MAX_PATH]; + + // The motion API allows unnamed motions. + // So if MotionName comes back NULL, we have to create a name for this item + if (MotionName == NULL) + { + geMotion *MyMotion; + + MyMotion = geActor_GetMotionByIndex (pData->ActorDef, iMotion); + sprintf (TempName, rcstring_Load (pData->Instance, IDS_UNNAMED), iMotion); + MotionName = TempName; + geMotion_SetName (MyMotion, MotionName); + } + + Index = SendMessage (hwndCombo, CB_ADDSTRING, 0, (LONG)MotionName); + SendMessage (hwndCombo, CB_SETITEMDATA, Index, iMotion); + } + + // Add blended motion to list. + if (pData->BlendedMotion != NULL) + { + Index = SendMessage (hwndCombo, CB_ADDSTRING, 0, (LONG)rcstring_Load (pData->Instance, IDS_BLENDEDMOTION)); + SendMessage (hwndCombo, CB_SETITEMDATA, Index, BLENDED_MOTION_INDEX); + } + + // Add Default Pose selection + pData->CurrentMotion = DEFAULT_POSE_INDEX; + Index = SendMessage (hwndCombo, CB_ADDSTRING, 0, (LONG)rcstring_Load (pData->Instance, IDS_DEFAULTPOSE)); + SendMessage (hwndCombo, CB_SETITEMDATA, Index, DEFAULT_POSE_INDEX); + + // and select it as current item + SendMessage (hwndCombo, CB_SETCURSEL, Index, 0); + } + + return TRUE; +} + +static void ActView_DoLoadActor + ( + ActView_WindowData *pData, + const char *Filename + ) +{ + // show wait cursor while loading... + HCURSOR OldCursor = SetCursor (LoadCursor (NULL, IDC_WAIT)); + + // We got a filename, so load the actor. + if (!ActView_LoadActor (pData->hwnd, Filename)) + { + MyError (pData->hwnd, pData->Instance, IDS_CANTLOADACTOR, Filename); + return; + } + { + // give the actor some cool(?) lighting effects + geVec3d FillLightNormal; + + geVec3d_Set (&FillLightNormal, -0.3f, 1.0f, 0.4f); + geVec3d_Normalize (&FillLightNormal); + + geActor_SetLightingOptions + ( + pData->Actor, GE_TRUE, &FillLightNormal, + 128.0f, 128.0f, 128.0f, // Fill light + 128.0f, 128.0f, 128.0f, // Ambient light + GE_FALSE, // Ambient light from floor + 0, // no dynamic lights, + NULL, FALSE + ); + } + + ActView_SetupTitle (pData); + + // Set last directory... + FilePath_GetDriveAndDir (Filename, pData->LastDir); + + // Clear blended motion and notify blend dialog (if one) + // that the actor has changed. + if (pData->BlendedMotion != NULL) + { + geMotion_Destroy (&pData->BlendedMotion); + } + pData->BlendedMotion = geMotion_Create (GE_TRUE); + if (pData->hwndBlender != NULL) + { + Blender_UpdateActor (pData->hwndBlender, pData->ActorDef, pData->BlendedMotion); + } + SetCursor (OldCursor); +} + +/* + Prompts user for actor filename, and creates a new window + in which the actor is displayed. +*/ +static void PromptForActorWindow (ActView_WindowData *pData) +{ + OPENFILENAME ofn; // Windows open filename structure... + char Filename[MAX_PATH]; + char Filter[MAX_PATH]; + + Filename[0] = '\0'; + + ofn.lStructSize = sizeof (OPENFILENAME); + ofn.hwndOwner = pData->hwnd; + ofn.hInstance = pData->Instance; + { + char *c; + + // build actor file filter string + strcpy (Filter, rcstring_Load (ofn.hInstance, IDS_ACTFILEFILTERDESC)); + c = &Filter[strlen (Filter)] + 1; + // c points one beyond end of string + strcpy (c, rcstring_Load (ofn.hInstance, IDS_ACTFILEFILTER)); + c = &c[strlen (c)] + 1; + *c = '\0'; // 2nd terminating nul character + } + ofn.lpstrFilter = Filter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = Filename; + ofn.nMaxFile = sizeof (Filename); + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = pData->LastDir; + ofn.lpstrTitle = NULL; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = rcstring_Load (ofn.hInstance, IDS_ACTFILEEXT); + ofn.lCustData = 0; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; + + if (GetOpenFileName (&ofn)) + { + ActView_DoLoadActor (pData, Filename); + } +} + +// Load program options. +// Searches the current directory, and then the executable's directory +// for the ini file. +// Saves the filename and loads the options from that file. +static void ActView_LoadOptions + ( + ActView_WindowData *pData + ) +{ + char FName[MAX_PATH]; + + // Rotation options defaults. + pData->InitialXRot = 0.0f; + pData->InitialYRot = 0.0f; + + // search current directory first... + GetCurrentDirectory (sizeof (FName), FName); + FilePath_AppendName (FName, rcstring_Load (pData->Instance, IDS_INIFILENAME), FName); + strcpy (pData->IniFilename, FName); + + if (_access (FName, 0) != 0) + { + char ModuleFilename[MAX_PATH]; + + GetModuleFileName (NULL, ModuleFilename, sizeof (ModuleFilename)); + FilePath_GetDriveAndDir (ModuleFilename, FName); + FilePath_AppendName (FName, rcstring_Load (pData->Instance, IDS_INIFILENAME), FName); + if (_access (FName, 0) != 0) + { + // no ini file. Set defaults and exit. + return; + } + strcpy (pData->IniFilename, FName); + } + // pData->IniFilename has full path to .INI file + + // load rotation values + { + char sRot[100]; + + GetPrivateProfileString ("Options", "XRot", "0", sRot, sizeof (sRot), FName); + pData->InitialXRot = (geFloat)atof (sRot); + + GetPrivateProfileString ("Options", "YRot", "0", sRot, sizeof (sRot), FName); + pData->InitialYRot = (geFloat)atof (sRot); + + GetPrivateProfileString ("Options", "LastDir", "", pData->LastDir, sizeof (pData->LastDir), FName); + } +} + +// Saves the current rotations to the ini file as the "Front" rotations. +static void ActView_SaveFront + ( + ActView_WindowData *pData + ) +{ + // Set front rotations... + pData->InitialXRot = pData->XRotActor; + pData->InitialYRot = pData->YRotActor; + + // IniFilename should have been setup by LoadOptions function... + if (pData->IniFilename[0] != '\0') + { + char sRot[100]; + + sprintf (sRot, "%f", pData->InitialXRot); + WritePrivateProfileString ("Options", "XRot", sRot, pData->IniFilename); + sprintf (sRot, "%f", pData->InitialYRot); + WritePrivateProfileString ("Options", "YRot", sRot, pData->IniFilename); + } +} + +static BOOL SetRenderCursor (ActView_WindowData *pData, int Mode) +{ + // If the mouse is in the render window, then set the cursor to reflect + // the current mouse mode. + RECT WindowRect; + POINT pt; + + pData->MouseMode = Mode; + + GetCursorPos (&pt); + + GetWindowRect (GetDlgItem (pData->hwnd, IDC_RENDERWIN), &WindowRect); + if (PtInRect (&WindowRect, pt)) + { + int CursorId = -1; + + // determine which cursor to load + switch (pData->MouseMode) + { + case AWM_ZOOM : + CursorId = IDC_ZOOM; + break; + case AWM_PAN : + CursorId = IDC_PAN; + break; + case AWM_ROTATE : + CursorId = IDC_ROTATE; + break; + default : + break; + } + // If mouse mode is set, then load and display the proper cursor. + if (CursorId != -1) + { + SetCursor ((HCURSOR)LoadCursor (pData->Instance, MAKEINTRESOURCE (CursorId))); + return TRUE; + } + } + + return FALSE; +} + +// Sets the current frame time to NewFrameTime +// This will clamp the values to the range StartExtent..EndExtent +static void ActView_SetFrameTime (ActView_WindowData *pData, const geFloat fTime) +{ + geFloat NewFrameTime = fTime; + + if (NewFrameTime < pData->StartExtent) + { + NewFrameTime = pData->StartExtent; + } + if (NewFrameTime > pData->EndExtent) + { + NewFrameTime = pData->EndExtent; + } + // Set current frame time + pData->LastFrameTime = NewFrameTime; + // adjust motion start time so that it's consistent with current time + pData->MotionStartTime = + (DWORD)(timeGetTime() - + (1000.0f * (pData->LastFrameTime - pData->StartExtent)/floatPercent (pData->Speed))); + // and set the slider to reflect the new time + SetSliderTime (pData->hwnd, IDC_SLIDERTIME, pData->LastFrameTime); +} + +// Update the speed value +// Gets the value from the edit control, validates it, and if good sets the value +// in the spinner and in the program data. +static void ActView_UpdateSpeed (ActView_WindowData *pData) +{ + UINT NewValue; + BOOL IsOk; + + // Get the value + NewValue = GetDlgItemInt (pData->hwnd, IDC_EDITSPEED, &IsOk, FALSE); + if (IsOk && (NewValue > 0) && (NewValue <= 10000)) + { + // Got a new speed value. + // We need to adjust the speed, but keep the current time the same. + // So update the speed value and then change the motion start time + // to reflect the new value. + pData->Speed = NewValue; + ActView_SetFrameTime (pData, pData->LastFrameTime); + } + // Be sure that the edit control matches stored data values + SetEditControlValue (pData->hwnd, IDC_EDITSPEED, IDC_SPINSPEED, pData->Speed); +} + +// Add TimeDelta (expressed in 100ths of a second) to the current frame time +static void ActView_AdjustFrameTime (ActView_WindowData *pData, int TimeDelta) +{ + geFloat fDelta = floatPercent (TimeDelta); + + ActView_SetFrameTime (pData, pData->LastFrameTime + fDelta); +} + +// Update the actor scale value. +// Gets the value from the edit control, validates it, and if good sets the value +// in the spinner and in the program data, and changes the actor's scale. +static void ActView_UpdateScale (ActView_WindowData *pData) +{ + UINT NewValue; + BOOL IsOk; + + // Get the value + NewValue = GetDlgItemInt (pData->hwnd, IDC_EDITSCALE, &IsOk, FALSE); + if (IsOk && (NewValue > 0) && (NewValue <= 10000)) + { + // if it's good, update everything + pData->Scale = NewValue; + // If an actor is loaded, change its size + if (pData->Actor != NULL) + { + geFloat fScale = floatPercent (pData->Scale); + geActor_SetScale (pData->Actor, fScale, fScale, fScale); + } + } + // in any case, make sure that the edit control matches our value. + SetEditControlValue (pData->hwnd, IDC_EDITSCALE, IDC_SPINSCALE, pData->Scale); +} + +// Updates the FrameDelta value +static void ActView_UpdateFrameDelta (ActView_WindowData *pData) +{ + UINT NewValue; + BOOL IsOk; + + NewValue = GetDlgItemInt (pData->hwnd, IDC_EDITFRAMETIME, &IsOk, FALSE); + if (IsOk && (NewValue > 0) && (NewValue <= 100)) + { + pData->FrameDelta = NewValue; + } + // make sure that edit control always reflects current data value + SetEditControlValue (pData->hwnd, IDC_EDITFRAMETIME, IDC_SPINFRAMETIME, pData->FrameDelta); +} + + +// Select a new motion. +static void ActView_SelectMotion + ( + ActView_WindowData *pData, + int NewMotion + ) +{ + pData->CurrentMotion = NewMotion; + switch (pData->CurrentMotion) + { + case DEFAULT_POSE_INDEX : + // selected the default pose + pData->Motion = NULL; + break; + + case BLENDED_MOTION_INDEX : + pData->Motion = pData->BlendedMotion; + break; + + default : + pData->Motion = geActor_GetMotionByIndex (pData->ActorDef, pData->CurrentMotion); + break; + } + if (pData->Motion != NULL) + { + geMotion_GetTimeExtents (pData->Motion, &pData->StartExtent, &pData->EndExtent); + } + else + { + pData->StartExtent = 0.0f; + pData->EndExtent = 0.0f; + } + pData->MotionLength = pData->EndExtent - pData->StartExtent; + SetSliderRange (pData, IDC_SLIDERTIME); +} + +#pragma warning (disable:4100) +static LRESULT wm_Command + ( + HWND hwnd, + ActView_WindowData *pData, + WORD wNotifyCode, + WORD wID, + HWND hwndCtl + ) +{ + switch (wID) + { + case ID_FILE_OPEN : + PromptForActorWindow (pData); + return 0; + + case ID_FILE_EXIT : + case IDCANCEL : + DestroyWindow (hwnd); + return 0; + + case ID_OPTIONS_FRONT : + ActView_SaveFront (pData); + return 0; + + case ID_OPTIONS_FRAMERATE : + pData->ShowFrameRate = !(pData->ShowFrameRate); + ActView_SetFrameRateToggle (pData); + return 0; + + case ID_HELP_CONTENTS : + WinHelp (hwnd, rcstring_Load (pData->Instance, IDS_HELPFILENAME), HELP_FINDER, 0); + return 0; + + case ID_HELP_ABOUT : + About_DoDialog (hwnd, pData->Instance); + return 0; + + // Pan, Rotate, and Zoom just set the mouse mode. + // No processing is done with these modes until a click+mouse move in the render window. + case IDC_PAN : + SetRenderCursor (pData, AWM_PAN); + return 0; + + case IDC_ROTATE : + SetRenderCursor (pData, AWM_ROTATE); + return 0; + + case IDC_ZOOM : + SetRenderCursor (pData, AWM_ZOOM); + return 0; + + // If a new motion is selected, then get the extents and reset the slider + case IDC_MOTIONCOMBO : + if (wNotifyCode == CBN_SELENDOK) + { + int Index = SendMessage (hwndCtl, CB_GETCURSEL, 0, 0); + int NewMotion = SendMessage (hwndCtl, CB_GETITEMDATA, Index, 0); + ActView_SelectMotion (pData, NewMotion); + ActView_SetFrameTime (pData, pData->StartExtent); + } + return 0; + + case IDC_LOOPED : + pData->Loop = (SendDlgItemMessage (hwnd, IDC_LOOPED, BM_GETCHECK, 0, 0) == 1) ? GE_TRUE : GE_FALSE; + return 0; + + case IDC_EDITSPEED : + if (wNotifyCode == EN_KILLFOCUS) + { + ActView_UpdateSpeed (pData); + } + return 0; + + case IDC_EDITSCALE : + if (wNotifyCode == EN_KILLFOCUS) + { + ActView_UpdateScale (pData); + } + return 0; + + case IDC_EDITFRAMETIME : + if (wNotifyCode == EN_KILLFOCUS) + { + ActView_UpdateFrameDelta (pData); + } + return 0; + + case IDI_PLAY : + if (pData->Motion != NULL) + { + switch (pData->PlayMode) + { + case PLAYMODE_STOP : + // if stopped, then restart at the beginning + pData->PlayMode = PLAYMODE_PLAY; + ActView_SetFrameTime (pData, pData->StartExtent); + break; + + case PLAYMODE_PAUSE : + // if paused, then continue... + pData->PlayMode = PLAYMODE_PLAY; + ActView_SetFrameTime (pData, pData->LastFrameTime); + break; + } + } + return 0; + + case IDI_STOP : + if (pData->Motion != NULL) + { + if (pData->PlayMode != PLAYMODE_STOP) + { + pData->PlayMode = PLAYMODE_STOP; + } + } + return 0; + + case IDI_PAUSE : + if (pData->Motion != NULL) + { + switch (pData->PlayMode) + { + case PLAYMODE_PLAY : // animation playing...pause it + pData->PlayMode = PLAYMODE_PAUSE; + break; + + case PLAYMODE_STOP : + case PLAYMODE_PAUSE : // animation paused...restart it + pData->PlayMode = PLAYMODE_PLAY; + ActView_SetFrameTime (pData, pData->LastFrameTime); + break; + } + } + return 0; + + case IDI_RRFRAME : + ActView_AdjustFrameTime (pData, -(pData->FrameDelta)); + return 0; + + case IDI_FFFRAME : + ActView_AdjustFrameTime (pData, pData->FrameDelta); + return 0; + + case IDI_RRSTART : // rewind to start of animation + ActView_SetFrameTime (pData, pData->StartExtent); + return 0; + + case IDI_FFEND : // go to end of animation + ActView_SetFrameTime (pData, pData->EndExtent); + return 0; + + // Set predefined orientation. + // All of these are rotational only...translations remain + case IDC_FRONT : + pData->XRotActor = pData->InitialXRot; + pData->YRotActor = pData->InitialYRot; + return 0; + + case IDC_BACK : + pData->XRotActor = pData->InitialXRot; + pData->YRotActor = pData->InitialYRot + GE_PI; + return 0; + + case IDC_LEFT : + pData->XRotActor = pData->InitialXRot; + pData->YRotActor = pData->InitialYRot - GE_PI/2.0f; + return 0; + + case IDC_RIGHT : + pData->XRotActor = pData->InitialXRot; + pData->YRotActor = pData->InitialYRot + GE_PI/2.0f; + return 0; + + case IDC_TOP : + pData->XRotActor = pData->InitialXRot + GE_PI/2.0f; + pData->YRotActor = pData->InitialYRot; + return 0; + + case IDC_BOTTOM : + pData->XRotActor = pData->InitialXRot - GE_PI/2.0f; + pData->YRotActor = pData->InitialYRot; + return 0; + + case IDC_CENTER : + // Put actor back at default position + geVec3d_Clear (&pData->ActorPos); + return 0; + + case IDC_BLEND : + if ((pData->ActorDef != NULL) && (pData->Actor != NULL)) + { + // if blender window exists, then display it. + if (pData->hwndBlender != NULL) + { + SetForegroundWindow (pData->hwndBlender); + } + else + { + // otherwise create it + pData->hwndBlender = Blender_Create (pData->hwnd, pData->Instance, pData->ActorDef, pData->BlendedMotion); + if (pData->hwndBlender != NULL) + { + ShowWindow (pData->hwndBlender, SW_SHOW); + UpdateWindow (pData->hwndBlender); + } + } + // and select the blended motion if not already selected + if (pData->CurrentMotion != BLENDED_MOTION_INDEX) + { + int Item, nItems; + HWND hwndCombo = GetDlgItem (pData->hwnd, IDC_MOTIONCOMBO); + + nItems = SendMessage (hwndCombo, CB_GETCOUNT, 0, 0); + for (Item = 0; Item < nItems; ++Item) + { + int iMotion = SendMessage (hwndCombo, CB_GETITEMDATA, 0, 0); + if (iMotion == BLENDED_MOTION_INDEX) + { + SendMessage (hwndCombo, CB_SETCURSEL, Item, 0); + ActView_SelectMotion (pData, BLENDED_MOTION_INDEX); + ActView_SetFrameTime (pData, pData->StartExtent); + break; + } + } + } + } + return 0; + } + return 0; +} +#pragma warning (default:4100) + +// Moves the control specified by id by changing the control's vertical position +// as indicated by the DeltaY value. +static void ActView_MoveControl + ( + HWND hdlg, + int id, + int DeltaY, + int *MaxX + ) +{ + HWND hwndCtrl; + + // get the control's window handle. + hwndCtrl = GetDlgItem (hdlg, id); + if (hwndCtrl != NULL) + { + RECT WindowRect; + POINT pt; + + // get its current position + GetWindowRect (hwndCtrl, &WindowRect); + // position is in screen coordinates, and we need dialog window relative + pt.x = WindowRect.left; + pt.y = WindowRect.top + DeltaY; + ScreenToClient (hdlg, &pt); + + // and move the control + SetWindowPos (hwndCtrl, NULL, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + + // and check right side for max X + pt.x = WindowRect.right; + pt.y = WindowRect.bottom + DeltaY; + ScreenToClient (hdlg, &pt); + if (pt.x > *MaxX) + { + *MaxX = pt.x; + } + } +} + +// Creates tooltips window and returns its handle +static HWND CreateTooltipsWindow (HWND hwnd) +{ + + // Controls that will be tipped... + static const int TooltipButtons[] = + { + IDI_PLAY, IDI_PAUSE, IDI_STOP, IDI_RRSTART, IDI_RRFRAME, + IDI_FFFRAME, IDI_FFEND, IDC_ZOOM, IDC_PAN, IDC_ROTATE, + IDC_FRONT, IDC_BACK, IDC_LEFT, IDC_RIGHT, IDC_TOP, + IDC_BOTTOM, IDC_CENTER, IDC_STATICCURRENTTIME, IDC_STATICEND, + IDC_EDITSCALE, IDC_EDITSPEED, IDC_EDITFRAMETIME, IDC_BLEND, + IDC_STATICSTART + }; + static const int nTooltipButtons = sizeof (TooltipButtons) / sizeof (int); + + int iButton; + HWND hwndTT; + HINSTANCE hInst = (HINSTANCE)GetWindowLong (hwnd, GWL_HINSTANCE); + + // Create tooltip control's window + hwndTT = CreateWindowEx + ( + 0, + TOOLTIPS_CLASS, + NULL, + TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + hwnd, + (HMENU)NULL, + hInst, + NULL + ); + + if (hwndTT == NULL) + { + return NULL; + } + + // Add each of the controls in the array to the tooltip + for (iButton = 0; iButton < nTooltipButtons; ++iButton) + { + TOOLINFO ti; + char TipBuffer[MAX_PATH]; + + TipBuffer[0] = '\0'; + LoadString (hInst, TooltipButtons[iButton], TipBuffer, sizeof (TipBuffer)); + ti.cbSize = sizeof (TOOLINFO); + ti.uFlags = TTF_IDISHWND; + ti.hwnd = hwnd; + ti.uId = (UINT)GetDlgItem (hwnd, TooltipButtons[iButton]); + ti.hinst = 0; + ti.lpszText = LPSTR_TEXTCALLBACK; + SendMessage (hwndTT, TTM_ADDTOOL, 0, (LPARAM)&ti); + } + return hwndTT; +} + +// Process hi resolution timer messages. +#pragma warning (disable:4100) +static void CALLBACK hiresTimerProc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +{ + // The user data should be the window handle. + HWND hwnd = (HWND)dwUser; + // get the data + ActView_WindowData *pData = (ActView_WindowData *)GetWindowLong (hwnd, GWL_USERDATA); + + // if there's no user data, then this message isn't for us. + // Don't know how to handle it, so just quit. + if (pData == NULL) + { + return; + } + + // Well, if the timer id matches the timer id we created, then go for it. + if ((pData->hiresTimer != 0) && (uID == (UINT)pData->hiresTimer)) + { + if (pData->ProcessingTimerMessage == FALSE) + { + // we use a flag to prevent overflowing the queue on a slow machine + pData->ProcessingTimerMessage = TRUE; + PostMessage (hwnd, pData->TimerMessageId, uID, 0); + } + } +} +#pragma warning (default:4100) + +static BOOL ActView_InitializeDialog (HWND hwnd) +{ + ActView_WindowData *pData; + + // allocate window local data structure + pData = GE_RAM_ALLOCATE_STRUCT (ActView_WindowData); + if (pData == NULL) + { + DestroyWindow (hwnd); + return TRUE; + } + + // and initialize it + pData->Instance = (HINSTANCE)GetWindowLong (hwnd, GWL_HINSTANCE); + pData->hwnd = hwnd; + *pData->ActorFilename = '\0'; + *pData->LastDir = '\0'; + pData->Camera = NULL; + pData->World = NULL; + pData->Engine = NULL; + pData->Actor = NULL; + pData->ActorDef = NULL; + pData->LastX = 0; + pData->LastY = 0; + pData->Motion = 0; + pData->PlayMode = PLAYMODE_STOP; + pData->MouseMode = AWM_NONE; + pData->Scale = 100; + pData->Speed = 100; + pData->FrameDelta = 5; + pData->LastFrameTime = 0.0f; + pData->Loop = GE_FALSE; + pData->hwndTT = NULL; + pData->hwndBlender = NULL; + pData->ShowFrameRate = FALSE; + pData->loresTimer = 0; + pData->hiresTimer = 0; + pData->ProcessingTimerMessage = FALSE; + + // create an empty motion for the blender + pData->BlendedMotion = geMotion_Create (GE_TRUE); + if (pData->BlendedMotion == NULL) + { + return FALSE; + } + + // Load program options. + ActView_LoadOptions (pData); + + // Set the window data pointer in the GWL_USERDATA field + SetWindowLong (hwnd, GWL_USERDATA, (LPARAM)pData); + + // set the program icon on the dialog window + SendMessage (hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon (pData->Instance, MAKEINTRESOURCE (IDI_MAINICON))); + + + // Set scale, speed, and frame time values + SetSpinnerRange (hwnd, IDC_SPINSCALE, 1, 10000); + SetEditControlValue (hwnd, IDC_EDITSCALE, IDC_SPINSCALE, pData->Scale); + + SetSpinnerRange (hwnd, IDC_SPINSPEED, 1, 10000); + SetEditControlValue (hwnd, IDC_EDITSPEED, IDC_SPINSPEED, pData->Speed); + + SetSpinnerRange (hwnd, IDC_SPINFRAMETIME, 1, 100); + SetEditControlValue (hwnd, IDC_EDITFRAMETIME, IDC_SPINFRAMETIME, pData->FrameDelta); + + // Setup slider + SetSliderRange (pData, IDC_SLIDERTIME); + SetSliderTime (hwnd, IDC_SLIDERTIME, 0.0f); + + { + // position render window and the rest of the controls. + int DeltaY; + int RenderWindowWidth; + + HWND hwndRender = GetDlgItem (hwnd, IDC_RENDERWIN); + + // Initialize the dialog box. + // Set render window to proper size and position. + // Resize dialog box to fit + // Move all the other controls to the bottom of the dialog + // Initialize the engine in the render window + { + // Size the render window. + // When done, ClientRect will contain the required width of + // the main window's client rect. + int Style = GetWindowLong (hwndRender, GWL_STYLE); + int OldBottom; + RECT WindowRect, ClientRect; + + GetWindowRect (hwndRender, &WindowRect); + OldBottom = WindowRect.bottom; + + // compute window size for client rect + ClientRect.left = 0; + ClientRect.top = 0; + ClientRect.right = ACTOR_WINDOW_WIDTH - 1; + ClientRect.bottom = ACTOR_WINDOW_HEIGHT - 1; + + AdjustWindowRect (&ClientRect, Style, FALSE); // FALSE == No menu + { + int WindowWidth = ClientRect.right - ClientRect.left + 1; + int WindowHeight = ClientRect.bottom - ClientRect.top + 1; + + SetWindowPos + ( + hwndRender, 0, + RENDER_BORDER, RENDER_BORDER, WindowWidth, WindowHeight, + SWP_NOCOPYBITS | SWP_NOZORDER + ); + + // Compute DeltaY--the vertical position difference between the old + // bottom of render window and new bottom of render window. + GetWindowRect (hwndRender, &WindowRect); + DeltaY = WindowRect.bottom - OldBottom; + RenderWindowWidth = WindowRect.right - WindowRect.left - 1; + } + } + + + { + RECT ClientRect; + int ClientWidth, ClientHeight; + int Style; + static int MoveableControls[] = + { + IDC_STATICSTART, IDC_STATICCURRENTTIME, IDC_STATICEND, IDC_SLIDERTIME, + IDC_PAN, IDC_ROTATE, IDC_ZOOM, + IDC_STATICMOTION, IDC_MOTIONCOMBO, + IDC_LOOPED, + IDC_STATICSCALE, IDC_EDITSCALE, IDC_SPINSCALE, + IDC_STATICSPEED, IDC_EDITSPEED, IDC_SPINSPEED, + IDC_STATICFRAME, IDC_EDITFRAMETIME, IDC_SPINFRAMETIME, + IDC_FRONT, IDC_BACK, IDC_LEFT, IDC_RIGHT, IDC_TOP, IDC_BOTTOM, IDC_CENTER, + IDI_PLAY, IDI_STOP, IDI_PAUSE, IDI_RRFRAME, IDI_FFFRAME, IDI_RRSTART, IDI_FFEND, + IDC_BLEND + }; + static int NumControls = sizeof (MoveableControls) / sizeof (int); + int i, MaxX; + + MaxX = RenderWindowWidth; + // Add the DeltaY value (computed above) to the position of all dialog controls + // except the render window. + for (i = 0; i < NumControls; ++i) + { + ActView_MoveControl (hwnd, MoveableControls[i], DeltaY, &MaxX); + } + + GetClientRect (hwnd, &ClientRect); + // add border for render window + ClientRect.bottom += DeltaY + RENDER_BORDER; + ClientRect.right = 2*RENDER_BORDER + MaxX; + + // adjust the dialog window's size. + Style = GetWindowLong (hwnd, GWL_STYLE); + AdjustWindowRect (&ClientRect, Style, TRUE); + ClientWidth = ClientRect.right - ClientRect.left + 1; + ClientHeight = ClientRect.bottom - ClientRect.top + 1; + { + int left, top; + + // Center the dialog on the screen + left = (GetSystemMetrics (SM_CXSCREEN) - ClientWidth)/2; + top = (GetSystemMetrics (SM_CYSCREEN) - ClientHeight)/2; + + SetWindowPos + ( + hwnd, NULL, + left, top, ClientWidth, ClientHeight, + SWP_NOCOPYBITS | SWP_NOZORDER + ); + } + + // Now center the rendered window horizontally in the dialog + { + RECT rectRender; + RECT rectParent; + POINT pt; + + GetWindowRect (hwnd, &rectParent); + GetWindowRect (hwndRender, &rectRender); + + pt.x = rectRender.left; + pt.y = rectRender.top; + ScreenToClient (hwnd, &pt); + + pt.x = (rectParent.right - rectParent.left)/2 - RenderWindowWidth/2; + SetWindowPos (hwndRender, NULL, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } + } + + { + // Add images to the buttons. + + // Array of button ids and image identifiers + static const int ButtonImages[][2] = + { + {IDI_PLAY, IDI_PLAY}, // Button ID, image ID + {IDI_PAUSE, IDI_PAUSE}, + {IDI_STOP, IDI_STOP}, + {IDI_RRFRAME, IDI_RRFRAME}, + {IDI_FFFRAME, IDI_FFFRAME}, + {IDI_RRSTART, IDI_RRSTART}, + {IDI_FFEND, IDI_FFEND}, + {IDC_ZOOM, IDI_ZOOM}, + {IDC_PAN, IDI_PAN}, + {IDC_ROTATE, IDI_ROTATE}, + {IDC_BLEND, IDI_BLEND} + }; + static const int nButtons = sizeof (ButtonImages) / (2*sizeof (int)); + int iButton; + + for (iButton = 0; iButton < nButtons; ++iButton) + { + // set the button image + SendDlgItemMessage + ( + hwnd, + ButtonImages[iButton][0], + BM_SETIMAGE, + IMAGE_ICON, + (LPARAM)LoadIcon (pData->Instance, MAKEINTRESOURCE (ButtonImages[iButton][1])) + ); + } + } + + /* + Create the tooltips window so we can do flyby hints. + If the window is created successfully, then we install a message filter hook + so the dialog can capture and respond to mouse movement messages and thus + provide the tooltips. + */ + pData->hwndTT = CreateTooltipsWindow (hwnd); + if (pData->hwndTT != NULL) + { + ActView_ToolHook = SetWindowsHookEx (WH_GETMESSAGE, (HOOKPROC)ActView_HookProc, NULL, GetCurrentThreadId ()); + } + } + + DragAcceptFiles (hwnd, TRUE); + + return TRUE; +} + +static void ActView_ShutdownAll + ( + HWND hwnd, + ActView_WindowData *pData + ) +{ + // don't want no more files. + DragAcceptFiles (hwnd, FALSE); + + // Uninstall the message hook (ugliness ensues if you forget this) + if (ActView_ToolHook != NULL) + { + UnhookWindowsHookEx (ActView_ToolHook); + ActView_ToolHook = NULL; + } + + // save last directory + if (*pData->IniFilename != '\0') + { + WritePrivateProfileString ("Options", "LastDir", pData->LastDir, pData->IniFilename); + } + + // When the window is closed, we need to notify the parent + // so that it can remove us from its list. + // We also need to free our local data. + if (pData != NULL) + { + // Free all allocated data + + // shut down timers first thing... + if (pData->loresTimer != 0) + { + KillTimer (hwnd, pData->loresTimer); + pData->loresTimer = 0; + } + if (pData->hiresTimer != 0) + { + timeKillEvent (pData->hiresTimer); + pData->hiresTimer = 0; + timeEndPeriod (DESIRED_MMTIMER_RESOLUTION); + } + + // Shut down the engine and all its associated stuff + if (pData->BlendedMotion != NULL) + { + geMotion_Destroy (&pData->BlendedMotion); + pData->BlendedMotion = NULL; + } + + if (pData->Actor != NULL) + { + geWorld_RemoveActor (pData->World, pData->Actor); + geActor_Destroy (&pData->Actor); + pData->Actor = NULL; + } + + if (pData->ActorDef != NULL) + { + geActor_DefDestroy (&pData->ActorDef); + pData->ActorDef = NULL; + } + + if (pData->Camera != NULL) + { + geCamera_Destroy (&pData->Camera); + pData->Camera = NULL; + } + if (pData->World != NULL) + { + geWorld_Free (pData->World); + pData->World = NULL; + } + + if (pData->Engine != NULL) + { + geEngine_Free (pData->Engine); + pData->Engine = NULL; + } + } + + if (pData != NULL) + { + geRam_Free (pData); + } + SetWindowLong (hwnd, GWL_USERDATA, (LPARAM)NULL); +} + +#pragma warning (disable:4100) +static BOOL CALLBACK ActView_DlgProc + ( + HWND hwnd, + UINT msg, + WPARAM wParam, + LPARAM lParam + ) +{ + ActView_WindowData *pData = ActView_GetWindowData (hwnd); + + // if the message is a wakeup call, then wake up and return. + if (msg == InstCheck_GetUniqueMessageId ()) + { + if (IsIconic(hwnd)) + { + ShowWindow(hwnd, SW_RESTORE); + } + SetForegroundWindow (hwnd); + return 0; + } + + // Process our timer messages. + if ((pData != NULL) && (msg == pData->TimerMessageId)) + { + if (((pData->hiresTimer != 0) && ((MMRESULT)wParam == pData->hiresTimer)) || + ((pData->loresTimer != 0) && ((UINT)wParam == pData->loresTimer))) + { + ActView_UpdateFrame (pData); + // clear the flag so another timer message can come through + pData->ProcessingTimerMessage = FALSE; + return FALSE; + } + } + + switch (msg) + { + case WM_INITDIALOG : + return ActView_InitializeDialog (hwnd); + + case WM_DESTROY : + ActView_ShutdownAll (hwnd, pData); + PostQuitMessage (0); + break; + + case WM_COMMAND : + { + WORD wNotifyCode = HIWORD (wParam); + WORD wID = LOWORD (wParam); + HWND hwndCtl = (HWND)lParam; + + return wm_Command (hwnd, pData, wNotifyCode, wID, hwndCtl); + } + + case WM_DROPFILES : + { + // Files dropped. Only take the first one. + HDROP hDrop; + UINT FileCount; + char Buff[MAX_PATH]; + + hDrop = (HDROP)wParam; + FileCount = DragQueryFile (hDrop, 0xffffffff, Buff, sizeof (Buff)); + if (FileCount > 0) + { + // get the first one and open it... + DragQueryFile (hDrop, 0, Buff, sizeof (Buff)); + } + DragFinish (hDrop); + ActView_DoLoadActor (pData, Buff); + return 0; + } + + case WM_MOUSEMOVE : + { + /* + If the mouse moves in the render window and the left mouse button + is down, then we need to move the actor or the camera based on + the MouseMode state (Pan, Rotate, Zoom). + */ + RECT WindowRect; + POINT pt; + + pt.x = LOWORD (lParam); + pt.y = HIWORD (lParam); + /* + The mouse coordinates we're given are window-relative. + But the window rect that we use to determine if we're within the + render window is in screen coordinates, so we convert the mouse pos. + */ + ClientToScreen (hwnd, &pt); + GetWindowRect (GetDlgItem (hwnd, IDC_RENDERWIN), &WindowRect); + if (PtInRect (&WindowRect, pt) && IsKeyDown (VK_LBUTTON)) + { + static geFloat Velocity = 1.0f; + static geFloat ActorAdjust = 1.0f; + // compute movement deltas. + geFloat dx = (geFloat)(pt.x - pData->LastX); + geFloat dy = (geFloat)(pt.y - pData->LastY); + + switch (pData->MouseMode) + { + case AWM_PAN : + // pan moves the actor's position + pData->ActorPos.X += (ActorAdjust * dx); + pData->ActorPos.Y -= (ActorAdjust * dy); + break; + + case AWM_ROTATE : + // Rotate changes the actor's orientation. + // 150.0f is an emperically derived value. + pData->XRotActor += (dy/150.0f); + pData->YRotActor += (dx/150.0f); + break; + + case AWM_ZOOM : + // zoom just moves the camera. + pData->Dist += (Velocity * dy); + // don't let camera go beyond origin... + if (pData->Dist < Velocity) + { + pData->Dist = Velocity; + } + break; + } + } + // in any case, we update the current position + pData->LastX = pt.x; + pData->LastY = pt.y; + + return 0; + } + + case WM_SETCURSOR : + return SetRenderCursor (pData, pData->MouseMode); + + case WM_VSCROLL : + { + // handle spinners + HWND hwndScrollbar = (HWND)lParam; +// int nPos = HIWORD (wParam); + + if (hwndScrollbar == GetDlgItem (hwnd, IDC_SPINSCALE)) + { + ActView_UpdateScale (pData); + } + else if (hwndScrollbar == GetDlgItem (hwnd, IDC_SPINSPEED)) + { + ActView_UpdateSpeed (pData); + } + else if (hwndScrollbar == GetDlgItem (hwnd, IDC_SPINFRAMETIME)) + { + ActView_UpdateFrameDelta (pData); + } + return 0; + } + + case WM_HSCROLL : + { + // handle slider + HWND hwndScrollbar = (HWND)lParam; + + if (hwndScrollbar == GetDlgItem (hwnd, IDC_SLIDERTIME)) + { + int nPos = SendMessage (hwndScrollbar, TBM_GETPOS, 0, 0); + ActView_SetFrameTime (pData, floatPercent (nPos)); + } + return 0; + } + + case WM_NOTIFY : + { + NMHDR *pHdr = (NMHDR *)lParam; + + + if (pHdr->code == TTN_NEEDTEXT) + { + // The tooltip control will pass a TTN_NEEDTEXT message to the + // parent (us) when the mouse passes over one of the controls that + // has a hint associated with it. + TOOLTIPTEXT *ptt = (TOOLTIPTEXT *)lParam; + int idCtrl = GetDlgCtrlID ((HWND)pHdr->idFrom); + + ptt->lpszText = (char *)rcstring_Load (pData->Instance, idCtrl); + } + return 0; + } + + case WM_BLENDERCLOSING : + // Message passed when the child dialog is closed. + // If this is the same as the blender dialog, then clear our blender + // dialog value. + if ((HWND)wParam == pData->hwndBlender) + { + pData->hwndBlender = NULL; + } + return 0; + + case WM_BLENDERMOTIONCHANGED : + // Message passed when the blender dialog changes the motion. + // Parent must reload motion because its time extents may have changed. + if (pData->CurrentMotion == BLENDED_MOTION_INDEX) + { + // load blended motion and redraw the UI + ActView_SelectMotion (pData, BLENDED_MOTION_INDEX); + } + return 0; + + default : + break; + + } + return FALSE; +} +#pragma warning (default:4100) + + +// Loads the Genesis3D engine. Returns GE_TRUE if successful. +// returns GE_FALSE if something failed. +static geBoolean StartTheEngine + ( + HWND hwndParent, + int ControlID, + ActView_WindowData *pData + ) +{ + HWND hwnd = GetDlgItem (hwndParent, ControlID); + assert (hwnd != NULL); + + // + // Start up the engine + // + pData->Engine = geEngine_Create + ( + hwnd, + rcstring_Load (pData->Instance, IDS_PROGRAMBASENAME), + "." // driver directory + ); + + if (pData->Engine == NULL) + { + MyError (hwndParent, pData->Instance, IDS_CANTCREATEENGINE); + return GE_FALSE; + } + + // + // Setup the viewing rect + // + pData->Rect.Left = 0; + pData->Rect.Right = ACTOR_WINDOW_WIDTH - 1; + pData->Rect.Top = 0; + pData->Rect.Bottom = ACTOR_WINDOW_HEIGHT - 1; + + // Initial position is 100 from origin along the Z axis... + pData->XRotCam = 0.0f; + pData->YRotCam = 0.0f; + pData->Dist = 100.0f; + pData->Height = 25.0f; + + // + // Create a camera + // + pData->Camera = geCamera_Create(GE_PI/2.0f, &pData->Rect); + + if (pData->Camera == NULL) + { + MyError (hwndParent, pData->Instance, IDS_CANTCREATECAMERA); + return GE_FALSE; + } + + // Create an empty world (this is cool, huh?) + pData->World = geWorld_Create (NULL); + + if (pData->World == NULL) + { + MyError (hwndParent, pData->Instance, IDS_CANTCREATEWORLD); + return GE_FALSE; + } + + if (geEngine_AddWorld (pData->Engine, pData->World) == GE_FALSE) + { + MyError (hwndParent, pData->Instance, IDS_CANTADDWORLD); + return GE_FALSE; + } + + // Set some light type defaults + geWorld_SetLTypeTable (pData->World, 0, "z"); + geWorld_SetLTypeTable (pData->World, 1, "mmnmmommommnonmmonqnmmo"); + geWorld_SetLTypeTable (pData->World, 2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); + geWorld_SetLTypeTable (pData->World, 3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); + geWorld_SetLTypeTable (pData->World, 4, "mamamamamama"); + geWorld_SetLTypeTable (pData->World, 5, "jklmnopqrstuvwxyzyxwvutsrqponmlkj"); + geWorld_SetLTypeTable (pData->World, 6, "nmonqnmomnmomomno"); + geWorld_SetLTypeTable (pData->World, 7, "mmmaaaabcdefgmmmmaaaammmaamm"); + geWorld_SetLTypeTable (pData->World, 8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); + geWorld_SetLTypeTable (pData->World, 9, "aaaaaaaazzzzzzzz"); + geWorld_SetLTypeTable (pData->World, 10,"mmamammmmammamamaaamammma"); + geWorld_SetLTypeTable (pData->World, 11,"abcdefghijklmnopqrrqponmlkjihgfedcba"); + + { + // Select driver from list. + // In this case, DrvList has been modified to present only + // those drivers that have a windowed mode. + geDriver *Driver; + geDriver_Mode *Mode; + + DrvList_PickDriver (pData->Instance, hwndParent, pData->Engine, &Driver, &Mode); + if ((Driver == NULL) || (Mode == NULL)) + { + MyError (hwndParent, pData->Instance, IDS_CANTLOADDRIVER); + return GE_FALSE; + } + // disable frame rate when displaying splash screen... + geEngine_EnableFrameRateCounter (pData->Engine, GE_FALSE); + + if (geEngine_SetDriverAndMode (pData->Engine, Driver, Mode) == GE_FALSE) + { + MyError (hwndParent, pData->Instance, IDS_CANTLOADDRIVER); + return GE_FALSE; + } + + } + + return GE_TRUE; +} + + +#pragma warning (disable:4100) +int CALLBACK WinMain + ( + HINSTANCE instance, + HINSTANCE prev_instance, + LPSTR cmd_line, + int cmd_show + ) +{ + ActView_WindowData *pData; + + { + HWND prev_hwnd; + + // Check for previous instance and exit if one found + prev_hwnd = InstCheck_CheckForPreviousInstance + ( + instance, + rcstring_Load (instance, IDS_PROGRAMNAME), + rcstring_Load (instance, IDS_UNIQUEMESSAGE) + ); + + if (prev_hwnd != NULL) + { + // send wakeup call to the previous instance + SendMessage (prev_hwnd, InstCheck_GetUniqueMessageId (), 0, 0); + return 0; + } + } + + InitCommonControls (); + + // create main window. + // This is the controlling dialog. + ActView_DlgHandle = CreateDialog + ( + instance, + MAKEINTRESOURCE (IDD_ACTOR), + NULL, + ActView_DlgProc + ); + + if (ActView_DlgHandle == NULL) + { + return 0; + } + + pData = ActView_GetWindowData (ActView_DlgHandle); + + ShowWindow (ActView_DlgHandle, SW_SHOWNORMAL); + UpdateWindow (ActView_DlgHandle); + + // The window's created the right size, so startup the engine + if (!StartTheEngine (ActView_DlgHandle, IDC_RENDERWIN, pData)) + { + MyError (ActView_DlgHandle, pData->Instance, IDS_CANTINITENGINE); + DestroyWindow (ActView_DlgHandle); + return 0; + } + + // clear render window's text + // (otherwise it might show through at times...trust me) + SetDlgItemText (ActView_DlgHandle, IDC_RENDERWIN, ""); + + ActView_SetupTitle (pData); + ActView_SetFrameRateToggle (pData); + + // Check the command line. If a filename specified, try to load it. + { + if (*cmd_line != '\0') + { + ActView_DoLoadActor (pData, cmd_line); + } + } + + // Set up timer stuff + // Register custom window message for timer stuff + pData->TimerMessageId = RegisterWindowMessage (ActViewMessageString); + if (pData->TimerMessageId != 0) + { + if (timeBeginPeriod (DESIRED_MMTIMER_RESOLUTION) == TIMERR_NOERROR) + { + pData->hiresTimer = timeSetEvent (DESIRED_MMTIMER_FREQUENCY, DESIRED_MMTIMER_RESOLUTION, hiresTimerProc, (DWORD)ActView_DlgHandle, TIME_PERIODIC); + if (pData->hiresTimer == 0) + { + timeEndPeriod (DESIRED_MMTIMER_RESOLUTION); + } + } + } + + if (pData->hiresTimer == 0) + { + pData->TimerMessageId = WM_TIMER; + pData->loresTimer = SetTimer (ActView_DlgHandle, LORES_TIMER_NUMBER, 50, NULL); + if (pData->loresTimer == 0) + { + MyError (ActView_DlgHandle, pData->Instance, IDS_CANTSTARTTIMER); + } + } + + { + // the application's message loop + MSG Msg; + HACCEL accel = LoadAccelerators (instance, MAKEINTRESOURCE (IDR_ACCELERATOR1)); + + // do the message loop thing... + while (GetMessage( &Msg, NULL, 0, 0)) + { + /* + This is kind of weird. + The main window is a dialog that has a menu. + In order for accelerators to work, we have to check the accelerators + first, then IsDialogMessage, then standard Windows message processing. + Any other order causes some weird behavior. + */ + if ((pData->hwndBlender == NULL) || !IsDialogMessage (pData->hwndBlender, &Msg)) + { + if ((accel == NULL) || !TranslateAccelerator (ActView_DlgHandle, accel, &Msg)) + { + if (!IsDialogMessage (ActView_DlgHandle, &Msg)) + { + TranslateMessage(&Msg); + DispatchMessage(&Msg); + } + } + } + } + } + + return 0; +} + +#pragma warning (default:4100) diff --git a/ActView/Main/actview.clw b/ActView/Main/actview.clw new file mode 100644 index 0000000..2d6ea42 --- /dev/null +++ b/ActView/Main/actview.clw @@ -0,0 +1,14 @@ +; CLW file contains information for the MFC ClassWizard + +[General Info] +Version=1 +LastClass= +LastTemplate=CDialog +NewFileInclude1=#include "stdafx.h" +NewFileInclude2=#include "actview.h" +LastPage=0 + +ClassCount=0 + +ResourceCount=0 + diff --git a/ActView/Main/blender.c b/ActView/Main/blender.c new file mode 100644 index 0000000..2d7a669 --- /dev/null +++ b/ActView/Main/blender.c @@ -0,0 +1,1808 @@ +/****************************************************************************************/ +/* BLENDER.C */ +/* */ +/* Author: Jim Mischel */ +/* Description: Actor Viewer's motion blender dialog box. */ +/* */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "Blender.h" +#pragma warning(disable : 4201 4214 4115) +#include +#pragma warning(default : 4201 4214 4115) +#include "resource.h" +#include "ram.h" +#include "rcstring.h" +#include "units.h" +#include +#include "motion.h" +#include "winutil.h" + +#pragma warning (disable:4514) // unreferenced inline function (stupid compiler) + +// Margins and motion spacing in window +#define TOP_MARGIN 5 +#define DOT_MARGIN 2 +#define LEFT_MARGIN 20 +#define LINE_HEIGHT 15 +#define SPACE_BETWEEN_LINES 20 +#define HANDLE_SIZE (LINE_HEIGHT/2) + +#define NO_MOTION (-1) + +// For first cut, MAX_SUBMOTIONS is as many motions as will fit in the rendering window. +// Since we don't have a scrollbar right now, we limit a blend to this many submotions. +// +#define MAX_SUBMOTIONS 7 + +typedef enum +{ + mieNONE, // not on item + mieMOTION, // within motion bounds + mieSTARTBLEND, // on start handle + mieENDBLEND, // on end handle + mieMOTIONOFFSET,// on left-hand scaling handle + mieMOTIONEND // on right-hand scaling handle +} MotionItemEnum; + + +// Data attached to window. +typedef struct +{ + HWND hwnd; // my window handle + HWND hwndParent; // parent window handle + HINSTANCE Instance; // instance + geActor_Def *ActorDef; // Current actor def + geMotion *BlendedMotion; // Compound motion being constructed + int CurrentBlendItem; // Index of current submotion + MotionItemEnum MouseMode; // Mouse state + POINT StartDragPoint; // Point at which drag was started + POINT LastDragPoint; // Last point where drag processed + geFloat PixelsPerSecond; // Pixels per second scale in window +} Blender_WindowData; + + +// Submotion structure holds all pertinent information about a submotion. +typedef struct +{ + geFloat TimeOffset; // motion starting time (parent-relative) + geFloat StartExtent; // Time of first key in submotion (submotion relative) + geFloat EndExtent; // Time of last key in submotion + geFloat TimeScale; // Scale to apply to submotion-relative times + geFloat StartBlendTime; // Time (submotion relative) to start blend + geFloat EndBlendTime; // Time (submotion relative) to stop blend + geFloat StartBlend; // Start blend value (percent 0..1) + geFloat EndBlend; // End blend value (0..1) + geBoolean SmoothBlend; // Set to TRUE to automatically create blend path. + // Currently this is forced + gePath *BlendPath; // Blend path + geMotion *Motion; // Motion information + geXForm3d BaseTransform; // Submotion base transform +} Blender_Submotion; + + +// Usage counter used for initialization/destruction of common resources +static int Blender_UsageCount = 0; + +// Pens and brushes used for drawing +static HPEN RedPen = NULL; +static HPEN GreenPen = NULL; +static HPEN BluePen = NULL; +static HBRUSH RedBrush = NULL; +static HBRUSH GreenBrush = NULL; +static HBRUSH BlueBrush = NULL; +static HFONT Blender_Font = NULL; + +// return pointer to Blender window's local data +static Blender_WindowData *Blender_GetWindowData (HWND hwnd) +{ + return (Blender_WindowData *)GetWindowLong (hwnd, GWL_USERDATA); +} + +// shutdown the blender window... +static void Blender_ShutdownAll (Blender_WindowData *pData) +{ + SendMessage (pData->hwndParent, WM_BLENDERCLOSING, (WPARAM)pData->hwnd, 0); + + SetWindowLong (pData->hwnd, GWL_USERDATA, (LONG)NULL); + geRam_Free (pData); + + --Blender_UsageCount; + if (Blender_UsageCount == 0) + { + // destroy pens and brushes if we're the last user + DeleteObject (RedPen); + DeleteObject (GreenPen); + DeleteObject (BluePen); + DeleteObject (RedBrush); + DeleteObject (GreenBrush); + DeleteObject (BlueBrush); + if (Blender_Font != NULL) + { + DeleteObject (Blender_Font); + } + } +} + +// Gets all data about a submotion and returns it in a Blender_Submotion structure +static Blender_Submotion Blender_GetCompleteSubmotion + ( + geMotion *BlendedMotion, + int SubmotionIndex + ) +{ + Blender_Submotion SubInfo; + + assert (SubmotionIndex >= 0); + assert (SubmotionIndex < geMotion_GetSubMotionCount (BlendedMotion)); + + SubInfo.TimeOffset = 0.0f; + SubInfo.StartExtent = 0.0f; + SubInfo.EndExtent = 0.0f; + SubInfo.StartBlendTime = 0.0f; + SubInfo.EndBlendTime = 0.0f; + SubInfo.TimeScale = 1.0f; + SubInfo.StartBlend = 0.0f; + SubInfo.EndBlend = 1.0f; + SubInfo.SmoothBlend = GE_TRUE; + SubInfo.BlendPath = NULL; + SubInfo.Motion = NULL; + + // Get selected submotion from blended motion + SubInfo.Motion = geMotion_GetSubMotion (BlendedMotion, SubmotionIndex); + + if (SubInfo.Motion != NULL) + { + SubInfo.TimeOffset = geMotion_GetTimeOffset (BlendedMotion, SubmotionIndex); + geMotion_GetTimeExtents (SubInfo.Motion, &SubInfo.StartExtent, &SubInfo.EndExtent); + + SubInfo.TimeScale = geMotion_GetTimeScale (BlendedMotion, SubmotionIndex); + SubInfo.BlendPath = geMotion_GetBlendPath (BlendedMotion, SubmotionIndex); + if (SubInfo.BlendPath != NULL) + { + // get starting and ending times and keyframes + int nKeyframes; + geXForm3d XfmFrame; + geFloat KeyTime; + + nKeyframes = gePath_GetKeyframeCount (SubInfo.BlendPath, GE_PATH_TRANSLATION_CHANNEL); +#pragma message ("Smooth blends only, for now") + assert ((nKeyframes == 1) || (nKeyframes == 2)); + + SubInfo.SmoothBlend = GE_TRUE; + + // Motion start and end times + gePath_GetTimeExtents (SubInfo.BlendPath, &SubInfo.StartBlendTime, &SubInfo.EndBlendTime); + + // get blend amount at first keyframe + gePath_GetKeyframe (SubInfo.BlendPath, 0, GE_PATH_TRANSLATION_CHANNEL, &KeyTime, &XfmFrame); + SubInfo.StartBlend = XfmFrame.Translation.X; + + // and at last keyframe + gePath_GetKeyframe (SubInfo.BlendPath, nKeyframes-1, GE_PATH_TRANSLATION_CHANNEL, &KeyTime, &XfmFrame); + SubInfo.EndBlend = XfmFrame.Translation.X; + } + SubInfo.BaseTransform = *geMotion_GetBaseTransform (BlendedMotion, SubmotionIndex); + } + return SubInfo; +} + +// get current blend listbox item +static int Blender_GetCurrentBlendItem (HWND hwnd) +{ + Blender_WindowData *pData = Blender_GetWindowData (hwnd); + + return pData->CurrentBlendItem; +} + +// returns data for current submotion +static Blender_Submotion Blender_GetCurrentSubmotion (Blender_WindowData *pData) +{ + Blender_Submotion SubInfo; + int SubmotionIndex = Blender_GetCurrentBlendItem (pData->hwnd); + + // If there's no current submotion, then give some reasonable defaults. + if (SubmotionIndex == LB_ERR) + { + SubInfo.TimeOffset = 0.0f; + SubInfo.StartBlendTime = 0.0f; + SubInfo.EndBlendTime = 0.0f; + SubInfo.TimeScale = 1.0f; + SubInfo.StartBlend = 0.0f; + SubInfo.EndBlend = 1.0f; + SubInfo.SmoothBlend = GE_TRUE; + SubInfo.BlendPath = NULL; + SubInfo.Motion = NULL; + } + else + { + SubInfo = Blender_GetCompleteSubmotion (pData->BlendedMotion, SubmotionIndex); + } + return SubInfo; +} + +// Return Y position of item's top pixel +static int GetTopPixelPos (int Index) +{ + return TOP_MARGIN + ((Index + 1) * SPACE_BETWEEN_LINES); +} + +// Return Y position of item's bottom pixel +static int GetBottomPixelPos (int Index) +{ + return GetTopPixelPos (Index) + LINE_HEIGHT; +} + +// Return X pixel position that corresponds to item's start time +static int GetStartPixelPos (geMotion *pMotion, int Index, geFloat PixelScale) +{ + geFloat MotionStart, MotionEnd; + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pMotion, Index); + geMotion_GetTimeExtents (pMotion, &MotionStart, &MotionEnd); + + return LEFT_MARGIN + Units_Round((SubInfo.TimeOffset - MotionStart) * PixelScale); +} + +// Return X pixel position that corresponds to item's end time +static int GetEndPixelPos (geMotion *pMotion, int Index, geFloat PixelScale) +{ + geFloat MotionStart, MotionEnd; + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pMotion, Index); + geMotion_GetTimeExtents (pMotion, &MotionStart, &MotionEnd); + + return GetStartPixelPos (pMotion, Index, PixelScale) + + Units_Round (((SubInfo.EndExtent - SubInfo.StartExtent) / SubInfo.TimeScale) * PixelScale); +} + +// return starting scale handle rectangle +static RECT GetStartHandleRect + ( + geMotion *pMotion, + int Index, + geFloat PixelScale + ) +{ + RECT ItemRect; + + ItemRect.left = GetStartPixelPos (pMotion, Index, PixelScale) - HANDLE_SIZE/2; + ItemRect.right = ItemRect.left + HANDLE_SIZE; + ItemRect.bottom = GetBottomPixelPos (Index); + ItemRect.top = ItemRect.bottom - HANDLE_SIZE; + + return ItemRect; +} + + +// return ending scale handle rectangle +static RECT GetEndHandleRect + ( + geMotion *pMotion, + int Index, + geFloat PixelScale + ) +{ + RECT ItemRect; + + ItemRect.left = GetEndPixelPos (pMotion, Index, PixelScale) - HANDLE_SIZE/2; + ItemRect.right = ItemRect.left + HANDLE_SIZE; + ItemRect.bottom = GetBottomPixelPos (Index); + ItemRect.top = ItemRect.bottom - HANDLE_SIZE; + + return ItemRect; +} + + +// Return rectangle that encloses the entire item +static RECT GetItemRect + ( + geMotion *pMotion, + int Index, + geFloat PixelScale + ) +{ + RECT ItemRect; + + ItemRect.left = GetStartPixelPos (pMotion, Index, PixelScale); + ItemRect.top = GetTopPixelPos (Index); + ItemRect.right = GetEndPixelPos (pMotion, Index, PixelScale); + ItemRect.bottom = GetBottomPixelPos (Index); + + if (ItemRect.left > ItemRect.right) + { + int Temp = ItemRect.left; + ItemRect.left = ItemRect.right; + ItemRect.right = Temp; + } + return ItemRect; +} + +// Get X pixel position that corresponds to item's start blend time +int GetStartBlendPixelPos (geMotion *pMotion, int Index, geFloat PixelScale) +{ + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pMotion, Index); + geFloat MotionStart, MotionEnd; + + geMotion_GetTimeExtents (pMotion, &MotionStart, &MotionEnd); + return LEFT_MARGIN + Units_Round (((SubInfo.TimeOffset - MotionStart) + (SubInfo.StartBlendTime/SubInfo.TimeScale)) * PixelScale); +} + +// Return rectangle of the start "handle" +static RECT GetStartBlendHandleRect + ( + geMotion *pMotion, + int Index, + geFloat PixelScale + ) +{ + RECT ItemRect; + + ItemRect.left = GetStartBlendPixelPos (pMotion, Index, PixelScale) - HANDLE_SIZE/2; + ItemRect.top = TOP_MARGIN + ((Index + 1) * SPACE_BETWEEN_LINES); + ItemRect.right = ItemRect.left + HANDLE_SIZE; + ItemRect.bottom = ItemRect.top + HANDLE_SIZE; + + return ItemRect; +} + +// Get X pixel position that corresponds to item's end blend time +int GetEndBlendPixelPos (geMotion *pMotion, int Index, geFloat PixelScale) +{ + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pMotion, Index); + geFloat MotionStart, MotionEnd; + + geMotion_GetTimeExtents (pMotion, &MotionStart, &MotionEnd); + return LEFT_MARGIN + Units_Round (((SubInfo.TimeOffset - MotionStart) + (SubInfo.EndBlendTime/SubInfo.TimeScale)) * PixelScale); +} + +// return end "handle" rectangle +static RECT GetEndBlendHandleRect + ( + geMotion *pMotion, + int Index, + geFloat PixelScale + ) +{ + RECT ItemRect; + + ItemRect.right = GetEndBlendPixelPos (pMotion, Index, PixelScale) + HANDLE_SIZE/2; + ItemRect.top = TOP_MARGIN + ((Index + 1) * SPACE_BETWEEN_LINES); + ItemRect.left = ItemRect.right - HANDLE_SIZE; + ItemRect.bottom = ItemRect.top + HANDLE_SIZE; + + return ItemRect; +} + +// Return rectangle for the specified item. +static RECT GetHandleRect + ( + geMotion *pMotion, + int Index, + geFloat PixelScale, + MotionItemEnum Item + ) +{ + switch (Item) + { + case mieMOTION : return GetItemRect (pMotion, Index, PixelScale); + case mieSTARTBLEND : return GetStartBlendHandleRect (pMotion, Index, PixelScale); + case mieENDBLEND : return GetEndBlendHandleRect (pMotion, Index, PixelScale); + case mieMOTIONOFFSET : return GetStartHandleRect (pMotion, Index, PixelScale); + case mieMOTIONEND: return GetEndHandleRect (pMotion, Index, PixelScale); + default : + { + RECT Trash = {-1, -1, -1, -1}; + assert (0); + return Trash; + } + } +} + +// this draws the time line for a single motion. +// This includes the start and ending bars, the line between them, +// and the start and ending times. +static void Blender_DrawTimeLine + ( + HDC dc, + geFloat StartTime, + geFloat EndTime, + geFloat PixelScale + ) +{ + const int LineLength = Units_Round((EndTime - StartTime) * PixelScale); + const int LineStartX = LEFT_MARGIN; + const int LineStartY = TOP_MARGIN; + HPEN OldPen = SelectObject (dc, GetStockObject (BLACK_PEN)); + + // draw vertical bars at start and end of time line + MoveToEx (dc, LineStartX, LineStartY, NULL); + LineTo (dc, LineStartX, LineStartY + LINE_HEIGHT); + + MoveToEx (dc, LineStartX + LineLength, LineStartY, NULL); + LineTo (dc, LineStartX + LineLength, LineStartY + LINE_HEIGHT); + + // draw horizontal line between vertical bars + MoveToEx (dc, LineStartX, LineStartY + LINE_HEIGHT/2, NULL); + LineTo (dc, LineStartX + LineLength, LineStartY + LINE_HEIGHT/2); + + // Display starting and ending times next to bars + { + char sTime[100]; + SIZE tSize; + #define RED (RGB (255, 0, 0)) + #define BLACK (RGB (0, 0, 0)) + COLORREF OldColor = SetTextColor (dc, BLACK); + + sprintf (sTime, "%.2f", StartTime); + GetTextExtentPoint32 (dc, sTime, lstrlen (sTime), &tSize); + + SetTextColor (dc, (StartTime < 0) ? RED : BLACK); + TextOut (dc, LineStartX + 2, LineStartY, sTime, lstrlen (sTime)); + + sprintf (sTime, "%.2f", EndTime); + GetTextExtentPoint32 (dc, sTime, lstrlen (sTime), &tSize); + + SetTextColor (dc, (EndTime < 0) ? RED : BLACK); + TextOut (dc, LineStartX + LineLength - 2 - tSize.cx, LineStartY, sTime, lstrlen (sTime)); + + SetTextColor (dc, OldColor); + } + + SelectObject (dc, OldPen); +} + +// Draw a specified handle. +static void Blender_DrawHandle + ( + HDC dc, + geMotion *pMotion, + int Index, + geFloat PixelScale, + MotionItemEnum Item, + HBRUSH Brush, + HPEN Pen + ) +{ + RECT HandleRect = GetHandleRect (pMotion, Index, PixelScale, Item); + + if ((Item == mieSTARTBLEND) || (Item == mieENDBLEND)) + { + // draw the line... + SelectObject (dc, Pen); + MoveToEx (dc, HandleRect.left + HANDLE_SIZE/2, HandleRect.top, NULL); + LineTo (dc, HandleRect.left + HANDLE_SIZE/2, HandleRect.top + LINE_HEIGHT); + } + + // and the rectangle + SelectObject (dc, Brush); + SelectObject (dc, GetStockObject (BLACK_PEN)); + Rectangle (dc, HandleRect.left, HandleRect.top, HandleRect.right, HandleRect.bottom); +} + +// Draw a single submotion +static void Blender_DrawMotion + ( + HDC dc, + geMotion *BlendedMotion, + int Index, + geFloat PixelScale + ) +{ + RECT ItemRect = GetItemRect (BlendedMotion, Index, PixelScale); + geMotion *pSubmotion = geMotion_GetSubMotion (BlendedMotion, Index); + + SelectObject (dc, GetStockObject (BLACK_PEN)); + SelectObject (dc, GetStockObject (WHITE_BRUSH)); + + // Display vertical lines at start and end of motion + MoveToEx (dc, ItemRect.left, ItemRect.top, NULL); + LineTo (dc, ItemRect.left, ItemRect.bottom); + + MoveToEx (dc, ItemRect.right, ItemRect.top, NULL); + LineTo (dc, ItemRect.right, ItemRect.bottom); + + // draw horizontal line between vertical bars + MoveToEx (dc, ItemRect.left, (ItemRect.top + ItemRect.bottom)/2, NULL); + LineTo (dc, ItemRect.right, (ItemRect.top + ItemRect.bottom)/2); + + // Center motion name on line... + { + RECT TextRect; + const char *SubmotionName = geMotion_GetName (pSubmotion); + TextRect.left = ItemRect.left + 1; + TextRect.top = ItemRect.top; + TextRect.right = ItemRect.right - 1; + TextRect.bottom = ItemRect.bottom - 1; + + DrawText (dc, SubmotionName, lstrlen (SubmotionName), &TextRect, DT_CENTER | DT_VCENTER); + } + + { + // Draw arrow indicating direction + #define ARROW_HEIGHT HANDLE_SIZE + #define ARROW_WIDTH HANDLE_SIZE + #define ARROW_SHAFT_LENGTH 10 + + const int Start = GetStartPixelPos (BlendedMotion, Index, PixelScale); + const int End = GetEndPixelPos (BlendedMotion, Index, PixelScale); + const int Sign = (Start <= End) ? 1 : -1; + const int ArrowBaseX = Start + (Sign * ARROW_SHAFT_LENGTH); + const int ArrowPointX = ArrowBaseX + (Sign * ARROW_WIDTH); + const int ShaftY = GetBottomPixelPos (Index) - ARROW_HEIGHT/2; + POINT ArrowPoints[3]; + + ArrowPoints[0].x = ArrowBaseX; + ArrowPoints[0].y = ShaftY - ARROW_HEIGHT/2; + ArrowPoints[1].x = ArrowPointX; + ArrowPoints[1].y = ShaftY; + ArrowPoints[2].x = ArrowBaseX; + ArrowPoints[2].y = ShaftY + ARROW_HEIGHT/2; + + MoveToEx (dc, Start, ShaftY, NULL); + LineTo (dc, ArrowBaseX, ShaftY); + Polygon (dc, ArrowPoints, 3); + } + + // and draw the handles that can be grabbed by the mouse + Blender_DrawHandle (dc, BlendedMotion, Index, PixelScale, mieSTARTBLEND, GreenBrush, GreenPen); + Blender_DrawHandle (dc, BlendedMotion, Index, PixelScale, mieENDBLEND, RedBrush, RedPen); + Blender_DrawHandle (dc, BlendedMotion, Index, PixelScale, mieMOTIONOFFSET, GetStockObject (WHITE_BRUSH), GetStockObject (BLACK_PEN)); + Blender_DrawHandle (dc, BlendedMotion, Index, PixelScale, mieMOTIONEND, GetStockObject (WHITE_BRUSH), GetStockObject (BLACK_PEN)); +} + + +// Paints the motion window +static void Blender_PaintMotionWindow + ( + Blender_WindowData *pData + ) +{ + HDC dc; + RECT ClientRect; + HWND hwndChild; + HBRUSH OldBrush; + HPEN OldPen; + HFONT OldFont = NULL; + int iMotion, NumMotions; + geFloat CompoundMotionStart, CompoundMotionEnd; + HRGN ClipRgn; + + // Get motion list window handle and DC + hwndChild = GetDlgItem (pData->hwnd, IDC_STATICBLEND); + + GetClientRect (hwndChild, &ClientRect); + dc = GetDC (hwndChild); + if (Blender_Font != NULL) + { + OldFont = SelectObject (dc, Blender_Font); + } + + // set clipping region so we don't draw outside here... + ClipRgn = CreateRectRgn (ClientRect.left, ClientRect.top, ClientRect.right, ClientRect.bottom); + SelectClipRgn (dc, ClipRgn); + + // Fill with white + OldBrush = SelectObject (dc, GetStockObject (WHITE_BRUSH)); + OldPen = SelectObject (dc, GetStockObject (WHITE_PEN)); + Rectangle (dc, ClientRect.left, ClientRect.top, ClientRect.right, ClientRect.bottom); + + // Draw compound motion time line at the top of the window + if (!geMotion_GetTimeExtents (pData->BlendedMotion, &CompoundMotionStart, &CompoundMotionEnd)) + { + CompoundMotionStart = 0.0f; + CompoundMotionEnd = 0.0f; + } + Blender_DrawTimeLine (dc, CompoundMotionStart, CompoundMotionEnd, pData->PixelsPerSecond); + + NumMotions = geMotion_GetSubMotionCount (pData->BlendedMotion); + + // Draw the individual motions + for (iMotion = 0; iMotion < NumMotions; ++iMotion) + { + Blender_DrawMotion (dc, pData->BlendedMotion, iMotion, pData->PixelsPerSecond); + } + + // Draw a circle to the left of the current motion + if (pData->CurrentBlendItem != NO_MOTION) + { + int CurPos = ((1 + pData->CurrentBlendItem) * SPACE_BETWEEN_LINES) + LINE_HEIGHT; + + SelectObject (dc, GetStockObject (WHITE_BRUSH)); + SelectObject (dc, GetStockObject (BLACK_PEN)); + + Ellipse (dc, DOT_MARGIN, CurPos-HANDLE_SIZE/2, DOT_MARGIN+HANDLE_SIZE, CurPos+HANDLE_SIZE/2); + } + + // restore the DC + SelectClipRgn (dc, NULL); + DeleteObject (ClipRgn); + + SelectObject (dc, OldBrush); + SelectObject (dc, OldPen); + if (OldFont != NULL) + { + SelectObject (dc, OldFont); + } + ReleaseDC (hwndChild, dc); +} + +// Display current submotion information in the edit fields +static void Blender_SetBlendMotionData (Blender_WindowData *pData) +{ + Blender_Submotion SubInfo = Blender_GetCurrentSubmotion (pData); + geFloat BlendedMotionStart, BlendedMotionEnd; + + // get time extents for blended motion... + geMotion_GetTimeExtents (pData->BlendedMotion, &BlendedMotionStart, &BlendedMotionEnd); + + // compute pixels per second + // Rather than allowing motion to always fill window, we'll do it by halving, with + // the default being 100 pixels per second. + { + const geFloat BlendedMotionLength = BlendedMotionEnd - BlendedMotionStart; + RECT ClientRect; + + GetClientRect (GetDlgItem (pData->hwnd, IDC_STATICBLEND), &ClientRect); + + pData->PixelsPerSecond = 100.0f; + while ((pData->PixelsPerSecond * BlendedMotionLength) > (geFloat)(ClientRect.right - LEFT_MARGIN)) + { + if (pData->PixelsPerSecond <= 2.0f) + { + // we need some limit, don't you think? + break; + } + pData->PixelsPerSecond /= 2.0f; + } + } + + // Set the values in the dialog controls + WinUtil_SetDlgItemFloat (pData->hwnd, IDC_EDITTIMEOFFSET, SubInfo.TimeOffset); + WinUtil_SetDlgItemFloat (pData->hwnd, IDC_EDITSTARTTIME, SubInfo.StartBlendTime); + WinUtil_SetDlgItemFloat (pData->hwnd, IDC_EDITENDTIME, SubInfo.EndBlendTime); + WinUtil_SetDlgItemFloat (pData->hwnd, IDC_EDITTIMESCALE, SubInfo.TimeScale); + + // start and end magnitude values are in percent + SetDlgItemInt (pData->hwnd, IDC_EDITSTARTBLEND, Units_MakePercent (SubInfo.StartBlend), FALSE); + SetDlgItemInt (pData->hwnd, IDC_EDITENDBLEND, Units_MakePercent (SubInfo.EndBlend), FALSE); + + { + // display current submotion name + const char *SubmotionName = (SubInfo.Motion == NULL) ? "" : geMotion_GetName (SubInfo.Motion); + char *Name = geRam_Allocate (lstrlen (SubmotionName) + 100); + + if (Name == NULL) + { + SetDlgItemText (pData->hwnd, IDC_STATICSUBMOTION, SubmotionName); + } + else + { + sprintf (Name, "%s (%.2f sec.)", SubmotionName, fabs(SubInfo.EndExtent - SubInfo.StartExtent)); + SetDlgItemText (pData->hwnd, IDC_STATICSUBMOTION, Name); + geRam_Free (Name); + } + } + +#pragma message ("Add path display") + // here we'll do the path... + + Blender_PaintMotionWindow (pData); + + // Enable/disable buttons as appropriate + { + int nSubmotions = geMotion_GetSubMotionCount (pData->BlendedMotion); + WinUtil_EnableDlgItem (pData->hwnd, IDC_ADD, (nSubmotions < MAX_SUBMOTIONS)); + WinUtil_EnableDlgItem (pData->hwnd, IDC_REMOVE, (nSubmotions > 0)); + WinUtil_EnableDlgItem (pData->hwnd, IDC_MOVEUP, (pData->CurrentBlendItem > 0)); + WinUtil_EnableDlgItem (pData->hwnd, IDC_MOVEDOWN, ((pData->CurrentBlendItem >= 0) && (pData->CurrentBlendItem < nSubmotions-1))); + } +} + +// Called to notify parent of a change in the motion +static void Blender_NotifyParentOfChange (Blender_WindowData *pData) +{ + SendMessage (pData->hwndParent, WM_BLENDERMOTIONCHANGED, 0, 0); +} + +// Add a submotion to the blended motion. +// This adds a copy of the passed motion. +// returns listbox index of added item +static int Blender_AddMotionToBlend + ( + geMotion *BlendedMotion, + geMotion *NewMotion + ) +{ + int SubmotionIndex; + geXForm3d XfmIdentity; + geFloat StartTime, EndTime; + geBoolean rslt; + + assert (geMotion_GetSubMotionCount (BlendedMotion) < MAX_SUBMOTIONS); + + if (NewMotion == NULL) + { + // do I need an error message here? + return GE_FALSE; + } + + // add it to the motion... + StartTime = 0.0f; + EndTime = 0.0f; + geMotion_GetTimeExtents (NewMotion, &StartTime, &EndTime); + geXForm3d_SetIdentity (&XfmIdentity); // Base transform is identity + rslt = geMotion_AddSubMotion + ( + BlendedMotion, // parent motion + 1.0f, // time scale + 0.0f, // motion offset (parent relative) + NewMotion, // motion to be added + StartTime, 0.0f, // start blend time (submotion relative) and blend value + EndTime, 1.0f, // end blend time (submotion relative) and blend value + &XfmIdentity, // Base transform + &SubmotionIndex // returned submotion index + ); + + return (rslt == GE_FALSE) ? -1 : SubmotionIndex; +} + +// Add the motion that's selected in the Motion list box to the list +// of motions to blend in the Blend list box. +static void Blender_AddSelectedMotionToBlend + ( + Blender_WindowData *pData + ) +{ + // get current selection + int CurSel = SendDlgItemMessage (pData->hwnd, IDC_MOTIONSLIST, LB_GETCURSEL, 0, 0); + if (CurSel != LB_ERR) + { + int SubmotionIndex; + // motion index is stored in list box's item data. + // get the index and then obtain the motion from the actor. + int MotionIndex = SendDlgItemMessage (pData->hwnd, IDC_MOTIONSLIST, LB_GETITEMDATA, CurSel, 0); + geMotion *Motion = geActor_GetMotionByIndex (pData->ActorDef, MotionIndex); + + assert (Motion != NULL); + // Add it to the blended motion + SubmotionIndex = Blender_AddMotionToBlend (pData->BlendedMotion, Motion); + if (SubmotionIndex != -1) + { + // set new item as current and update the UI + pData->CurrentBlendItem = SubmotionIndex; + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } + } +} + + +// remove from the compound motion the submotion that's selected in the Blend window +void Blender_RemoveSelectedMotionFromBlend + ( + Blender_WindowData *pData + ) +{ + // get currently-selected item (if any) + + int CurSel = Blender_GetCurrentBlendItem (pData->hwnd); + + if (CurSel != NO_MOTION) + { + int nItems; + + // remove it from the compound motion + geMotion_RemoveSubMotion (pData->BlendedMotion, CurSel); + + nItems = geMotion_GetSubMotionCount (pData->BlendedMotion); + // if there are still items, set the new selection + if (nItems > 0) + { + if (CurSel >= nItems) + { + CurSel = nItems - 1; + } + } + else + { + CurSel = NO_MOTION; + } + pData->CurrentBlendItem = CurSel; + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } +} + +// return the time offset of the currently-selected item +// returns 0.0f if there is no current item +// Time is parent motion relative +static geFloat Blender_GetTimeOffset (Blender_WindowData *pData) +{ + Blender_Submotion SubInfo = Blender_GetCurrentSubmotion (pData); + return SubInfo.TimeOffset; +} + +// returns the starting time of the currently-selected submotion +// This is submotion relative +static geFloat Blender_GetStartTime (Blender_WindowData *pData) +{ + Blender_Submotion SubInfo = Blender_GetCurrentSubmotion (pData); + return SubInfo.StartBlendTime; +} + +// returns the ending time of the currently-selected submotion +// submotion relative +static geFloat Blender_GetEndTime (Blender_WindowData *pData) +{ + Blender_Submotion SubInfo = Blender_GetCurrentSubmotion (pData); + return SubInfo.EndBlendTime; +} + +// Returns time scale for current submotion +static geFloat Blender_GetTimeScale (Blender_WindowData *pData) +{ + Blender_Submotion SubInfo = Blender_GetCurrentSubmotion (pData); + return SubInfo.TimeScale; +} + +// Returns current submotion start blend value +static geFloat Blender_GetStartBlend (Blender_WindowData *pData) +{ + Blender_Submotion SubInfo = Blender_GetCurrentSubmotion (pData); + return SubInfo.StartBlend; +} + +// Returns current submotion end blend value +static geFloat Blender_GetEndBlend (Blender_WindowData *pData) +{ + Blender_Submotion SubInfo = Blender_GetCurrentSubmotion (pData); + return SubInfo.EndBlend; +} + +// Set the time offset for a submotion, and update UI to reflect new value. +// Time offset is parent relative +static void Blender_SetTimeOffset + ( + Blender_WindowData *pData, + geFloat TimeOffset + ) +{ + int SubmotionIndex = Blender_GetCurrentBlendItem (pData->hwnd); + if (SubmotionIndex != LB_ERR) + { + // set it and update the UI + geMotion_SetTimeOffset (pData->BlendedMotion, SubmotionIndex, TimeOffset); + } +} + +// Create new smooth blending path from StartTime to EndTime with +// given starting and ending magnitudes. +// Times are submotion relative +static void Blender_CreateNewPath + ( + geMotion *BlendedMotion, + int SubmotionIndex, + geFloat StartTime, geFloat StartMagnitude, + geFloat EndTime, geFloat EndMagnitude + ) +{ + geXForm3d XfmBlend; + gePath *Path; + + // if times are identical, then we just can't do this... + if (StartTime == EndTime) + { + return; + } + + Path = gePath_Create + ( + GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV, // default for blending + GE_PATH_INTERPOLATE_SQUAD, // anything...not used for blending + GE_FALSE // not looped + ); + + // Program's probably going to not like it if the path is NULL. + // But there isn't much I can do about it... + if (Path != NULL) + { + // add starting and ending keyframes + + // only the X value of the translation part of the transform is used. + XfmBlend.Translation.X = StartMagnitude; + gePath_InsertKeyframe (Path, GE_PATH_TRANSLATION_CHANNEL, StartTime, &XfmBlend); + + // and the end keyframe + XfmBlend.Translation.X = EndMagnitude; + gePath_InsertKeyframe (Path, GE_PATH_TRANSLATION_CHANNEL, EndTime, &XfmBlend); + + // set blend path for this submotion + geMotion_SetBlendPath (BlendedMotion, SubmotionIndex, Path); + + // and delete our local copy + gePath_Destroy (&Path); + } +} + +// Set submotion start blend time +static void Blender_SetStartTime + ( + Blender_WindowData *pData, + geFloat StartBlendTime + ) +{ + int SubmotionIndex = Blender_GetCurrentBlendItem (pData->hwnd); + if (SubmotionIndex != LB_ERR) + { + // Get ending time and create new blend path + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pData->BlendedMotion, SubmotionIndex); + Blender_CreateNewPath (pData->BlendedMotion, SubmotionIndex, StartBlendTime, SubInfo.StartBlend, SubInfo.EndBlendTime, SubInfo.EndBlend); + } +} + +// Set submotion end blend time +static void Blender_SetEndTime + ( + Blender_WindowData *pData, + geFloat EndBlendTime + ) +{ + int SubmotionIndex = Blender_GetCurrentBlendItem (pData->hwnd); + if (SubmotionIndex != LB_ERR) + { + // Get starting time and create new blend path + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pData->BlendedMotion, SubmotionIndex); + Blender_CreateNewPath (pData->BlendedMotion, SubmotionIndex, SubInfo.StartBlendTime, SubInfo.StartBlend, EndBlendTime, SubInfo.EndBlend); + } +} + +// Set submotion time scale +static void Blender_SetTimeScale + ( + Blender_WindowData *pData, + geFloat TimeScale + ) +{ + int SubmotionIndex = Blender_GetCurrentBlendItem (pData->hwnd); + if (SubmotionIndex != LB_ERR) + { + geMotion_SetTimeScale (pData->BlendedMotion, SubmotionIndex, TimeScale); + } + +} + +// Set submotion start blend value +static void Blender_SetStartBlend + ( + Blender_WindowData *pData, + geFloat StartBlend + ) +{ + int SubmotionIndex = Blender_GetCurrentBlendItem (pData->hwnd); + if (SubmotionIndex != LB_ERR) + { + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pData->BlendedMotion, SubmotionIndex); + Blender_CreateNewPath (pData->BlendedMotion, SubmotionIndex, SubInfo.StartBlendTime, StartBlend, SubInfo.EndBlendTime, SubInfo.EndBlend); + } +} + +// Set submotion end blend value +static void Blender_SetEndBlend + ( + Blender_WindowData *pData, + geFloat EndBlend + ) +{ + int SubmotionIndex = Blender_GetCurrentBlendItem (pData->hwnd); + if (SubmotionIndex != LB_ERR) + { + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pData->BlendedMotion, SubmotionIndex); + Blender_CreateNewPath (pData->BlendedMotion, SubmotionIndex, SubInfo.StartBlendTime, SubInfo.StartBlend, SubInfo.EndBlendTime, EndBlend); + } +} + + +// Output test data to blender.txt. +// This is a debugging function. +static void Blender_OutputTestData (Blender_WindowData *pData) +{ + FILE *f; + int nMotions, iSubmotion; + geFloat StartExtent, EndExtent; + static const geFloat TimeDelta = 0.10f; + + f = fopen ("blender.txt", "wt"); + fprintf (f, "Blender data output\n"); + + nMotions = geMotion_GetSubMotionCount (pData->BlendedMotion); + fprintf (f, "Number of submotions = %d\n", nMotions); + + geMotion_GetTimeExtents (pData->BlendedMotion, &StartExtent, &EndExtent); + fprintf (f, "Extents: %.2f to %.2f\n", StartExtent, EndExtent); + + for (iSubmotion = 0; iSubmotion < nMotions; ++iSubmotion) + { + geFloat mStart, mEnd; + geMotion *Motion = geMotion_GetSubMotion (pData->BlendedMotion, iSubmotion); + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pData->BlendedMotion, iSubmotion); + + fprintf (f, "Submotion %d (%s)\n", iSubmotion, geMotion_GetName (Motion)); + geMotion_GetTimeExtents (Motion, &mStart, &mEnd); + fprintf (f, " Extents: %.2f to %.2f\n", mStart, mEnd); + fprintf (f, " Time Offset = %.2f\n", SubInfo.TimeOffset); + fprintf (f, " Time Scale = %.2f\n", SubInfo.TimeScale); + fprintf (f, " Start Blend Time = %.2f\n", SubInfo.StartBlendTime); + fprintf (f, " Start Blend = %.2f\n", SubInfo.StartBlend); + fprintf (f, " End Blend Time = %.2f\n", SubInfo.EndBlendTime); + fprintf (f, " End Blend = %.2f\n", SubInfo.EndBlend); + fprintf (f, " Num path keys = %d\n", gePath_GetKeyframeCount (SubInfo.BlendPath, GE_PATH_TRANSLATION_CHANNEL)); + fprintf (f, " Blend amounts at %.2f second intervals\n", TimeDelta); + { + geFloat CurrentTime; + + CurrentTime = StartExtent; + + while (CurrentTime <= EndExtent) + { + geFloat BlendAmount; + + BlendAmount = geMotion_GetBlendAmount (pData->BlendedMotion, iSubmotion, CurrentTime); + fprintf (f, "\t%.2f\t\t%.2f\n", CurrentTime, BlendAmount); + CurrentTime += TimeDelta; + } + } + } + fclose (f); + MessageBox (pData->hwnd, "Data output to blender.txt", "Blender", MB_OK); +} + +// Move a submotion up or down in the list +static void Blender_MoveSubMotion + ( + Blender_WindowData *pData, + int MoveFrom, + int MoveTo + ) +{ + // Move a submotion from its current place in the compound motion to + // a new place. + // Since the motion API doesn't have the primitives to insert submotions, + // we'll get info for all the submotions, remove them, and then add + // them in the proper order. + const int SubmotionCount = geMotion_GetSubMotionCount (pData->BlendedMotion); + Blender_Submotion *SubInfo = GE_RAM_ALLOCATE_ARRAY (Blender_Submotion, SubmotionCount); + int iMotion; + + if (SubInfo == NULL) + { + return; + } + + // get each submotion, and then remove it from the compound motion + for (iMotion = SubmotionCount; iMotion > 0; --iMotion) + { + SubInfo[iMotion-1] = Blender_GetCompleteSubmotion (pData->BlendedMotion, iMotion-1); + // need to copy the path because RemoveSubMotion is going to trash it... + SubInfo[iMotion-1].BlendPath = gePath_CreateCopy (SubInfo[iMotion-1].BlendPath); + + geMotion_RemoveSubMotion (pData->BlendedMotion, iMotion-1); + } + + assert (geMotion_GetSubMotionCount (pData->BlendedMotion) == 0); + + // re-order the SubInfo in the array... + { + Blender_Submotion SubInfoTemp; + + // Yeah, memmove is ugly, but it's easier than 2 separate loops... + SubInfoTemp = SubInfo[MoveFrom]; + memmove (&SubInfo[MoveFrom], &SubInfo[MoveTo], sizeof (Blender_Submotion) * abs (MoveFrom - MoveTo)); + SubInfo[MoveTo] = SubInfoTemp; + } + + // now add the newly-ordered submotions back to the compound motion + for (iMotion = 0; iMotion < SubmotionCount; ++iMotion) + { + Blender_Submotion *pInfo = &SubInfo[iMotion]; + int Index; + + geMotion_AddSubMotion + ( + pData->BlendedMotion, + pInfo->TimeScale, + pInfo->TimeOffset, + pInfo->Motion, + pInfo->StartBlendTime, pInfo->StartBlend, + pInfo->EndBlendTime, pInfo->EndBlend, + &pInfo->BaseTransform, + &Index + ); + assert (Index == iMotion); + // Set the blend path and then destroy our copy of the path + geMotion_SetBlendPath (pData->BlendedMotion, iMotion, pInfo->BlendPath); + gePath_Destroy (&(pInfo->BlendPath)); + } + + assert (geMotion_GetSubMotionCount (pData->BlendedMotion) == SubmotionCount); + + geRam_Free (SubInfo); +} + +// Don't you just love these big switch statements? +#pragma warning (disable:4100) +static BOOL wm_Command + ( + Blender_WindowData *pData, + WORD wNotifyCode, + WORD wID, + HWND hwndCtl + ) +{ + switch (wID) + { + geFloat TimeValue; + BOOL rslt; + + case IDC_TESTOUT : + Blender_OutputTestData (pData); + return 0; + + case IDCANCEL : + DestroyWindow (pData->hwnd); + return 0; + + case IDC_MOTIONSLIST : + // if double-click an item in the motions list, add it to + // the blended list. + if (wNotifyCode == LBN_DBLCLK) + { + Blender_AddSelectedMotionToBlend (pData); + } + return 0; + + case IDC_ADD : + Blender_AddSelectedMotionToBlend (pData); + return 0; + + case IDC_REMOVE : + // remove currently-selected item from blended motion + Blender_RemoveSelectedMotionFromBlend (pData); + return 0; + + case IDC_MOVEUP : + if (pData->CurrentBlendItem > 0) + { + Blender_MoveSubMotion (pData, pData->CurrentBlendItem, pData->CurrentBlendItem-1); + --(pData->CurrentBlendItem); + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } + return 0; + + case IDC_MOVEDOWN : + if ((pData->CurrentBlendItem >= 0) && + (pData->CurrentBlendItem < geMotion_GetSubMotionCount (pData->BlendedMotion)-1)) + { + Blender_MoveSubMotion (pData, pData->CurrentBlendItem, pData->CurrentBlendItem+1); + ++(pData->CurrentBlendItem); + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } + return 0; + + case IDC_EDITTIMEOFFSET : + if (wNotifyCode == EN_KILLFOCUS) + { + rslt = WinUtil_GetDlgItemFloat (pData->hwnd, IDC_EDITTIMEOFFSET, &TimeValue); + if (!rslt) + { + TimeValue = Blender_GetTimeOffset (pData); + } + Blender_SetTimeOffset (pData, TimeValue); + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } + return 0; + + case IDC_EDITSTARTTIME : + if (wNotifyCode == EN_KILLFOCUS) + { + rslt = WinUtil_GetDlgItemFloat (pData->hwnd, IDC_EDITSTARTTIME, &TimeValue); + // don't allow Start > End + if (!rslt || (TimeValue > Blender_GetEndTime (pData))) + { + TimeValue = Blender_GetStartTime (pData); + } + Blender_SetStartTime (pData, TimeValue); + // update UI + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } + return 0; + + case IDC_EDITENDTIME : + if (wNotifyCode == EN_KILLFOCUS) + { + rslt = WinUtil_GetDlgItemFloat (pData->hwnd, IDC_EDITENDTIME, &TimeValue); + // don't allow End < Start + if (!rslt || (TimeValue < Blender_GetStartTime (pData))) + { + TimeValue = Blender_GetEndTime (pData); + } + Blender_SetEndTime (pData, TimeValue); + // update UI + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } + return 0; + + case IDC_EDITTIMESCALE : + if (wNotifyCode == EN_KILLFOCUS) + { + geFloat Scale; + + rslt = WinUtil_GetDlgItemFloat (pData->hwnd, IDC_EDITTIMESCALE, &Scale); + if (!rslt || (Scale == 0.0f)) + { + Scale = Blender_GetTimeScale (pData); + } + Blender_SetTimeScale (pData, Scale); + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } + return 0; + + case IDC_EDITSTARTBLEND : + if (wNotifyCode == EN_KILLFOCUS) + { + BOOL IsOk; + UINT NewValue = GetDlgItemInt (pData->hwnd, IDC_EDITSTARTBLEND, &IsOk, FALSE); + geFloat fValue; + + if (IsOk && (NewValue >= 0) && (NewValue <= 100)) + { + fValue = Units_FloatFromPercent (NewValue); + } + else + { + fValue = Blender_GetStartBlend (pData); + } + Blender_SetStartBlend (pData, fValue); + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } + return 0; + + case IDC_EDITENDBLEND : + if (wNotifyCode == EN_KILLFOCUS) + { + BOOL IsOk; + UINT NewValue = GetDlgItemInt (pData->hwnd, IDC_EDITENDBLEND, &IsOk, FALSE); + geFloat fValue; + + if (IsOk && (NewValue >= 0) && (NewValue <= 100)) + { + fValue = Units_FloatFromPercent (NewValue); + } + else + { + fValue = Blender_GetEndBlend (pData); + } + Blender_SetEndBlend (pData, fValue); + Blender_SetBlendMotionData (pData); + Blender_NotifyParentOfChange (pData); + } + return 0; + + default : + break; + } + return 0; +} +#pragma warning (default:4100) + + +// Initialize the dialog +static BOOL Blender_Initialize (Blender_WindowData *pData) +{ + if (Blender_UsageCount == 0) + { + // Create pens & brushes + RedPen = CreatePen (PS_SOLID, 1, RGB (255, 0, 0)); + GreenPen = CreatePen (PS_SOLID, 1, RGB (0, 255, 0)); + BluePen = CreatePen (PS_SOLID, 1, RGB (0, 0, 255)); + RedBrush = CreateSolidBrush (RGB (255, 0, 0)); + GreenBrush = CreateSolidBrush (RGB (0, 255, 0)); + BlueBrush = CreateSolidBrush (RGB (0, 0, 255)); + + // Create font for motion names + Blender_Font = CreateFont + ( + 6, // logical height of font + 0, // logical average character width + 0, // angle of escapement + 0, // base-line orientation angle + FW_NORMAL, // font weight + 0, // italic attribute flag + 0, // underline attribute flag + 0, // strikeout attribute flag + ANSI_CHARSET, // character set identifier + OUT_DEFAULT_PRECIS, // output precision + CLIP_DEFAULT_PRECIS, // clipping precision + DRAFT_QUALITY, // output quality + DEFAULT_PITCH, // pitch and family + "MS Sans Serif" // pointer to typeface name string + ); + } + ++Blender_UsageCount; + + // set window icon + SendMessage (pData->hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon (pData->Instance, MAKEINTRESOURCE (IDI_BLEND))); + + // Fill motions list box with actor's motions + { + int iMotion; + HWND hwndListbox; + int NumMotions; + + hwndListbox = GetDlgItem (pData->hwnd, IDC_MOTIONSLIST); + SendMessage (hwndListbox, LB_RESETCONTENT, 0, 0); + + NumMotions = geActor_GetMotionCount (pData->ActorDef); + for (iMotion = 0; iMotion < NumMotions; ++iMotion) + { + const char *MotionName = geActor_GetMotionName (pData->ActorDef, iMotion); + int Index; + + // Although the motion API allows unnamed motions, our code that sets + // up the combo box in ActView is supposed to give names to any unnamed motions. + // So MotionName should never come back NULL here. + assert (MotionName != NULL); + + Index = SendMessage (hwndListbox, LB_ADDSTRING, 0, (LONG)MotionName); + if (Index != LB_ERR) + { + SendMessage (hwndListbox, LB_SETITEMDATA, Index, iMotion); + } + } + // Set selection to first motion + SendMessage (hwndListbox, LB_SETCURSEL, 0, 0); + } + Blender_SetBlendMotionData (pData); + + return TRUE; +} + +// Returns a value indicating the type of item the mouse is over +static MotionItemEnum ItemMousePos + ( + geMotion *pMotion, + int iMotion, + geFloat PixelScale, + int MouseX, + int MouseY + ) +{ + RECT ItemRect; + POINT pt; + + pt.x = MouseX; + pt.y = MouseY; + + ItemRect = GetStartBlendHandleRect (pMotion, iMotion, PixelScale); + if (PtInRect (&ItemRect, pt)) + { + return mieSTARTBLEND; + } + + ItemRect = GetEndBlendHandleRect (pMotion, iMotion, PixelScale); + if (PtInRect (&ItemRect, pt)) + { + return mieENDBLEND; + } + + ItemRect = GetStartHandleRect (pMotion, iMotion, PixelScale); + if (PtInRect (&ItemRect, pt)) + { + return mieMOTIONOFFSET; + } + + ItemRect = GetEndHandleRect (pMotion, iMotion, PixelScale); + if (PtInRect (&ItemRect, pt)) + { + return mieMOTIONEND; + } + + // then check the entire item + ItemRect = GetItemRect (pMotion, iMotion, PixelScale); + if (PtInRect (&ItemRect, pt)) + { + return mieMOTION; + } + + return mieNONE; +} + +// Determine which item (if any) the passed X,Y coordinates is on. +// Returns NO_MOTION if none. +// If on an item, returns the item index, and *pMouseItem describes which +// of the parts of the item (handle, etc.) +static int GetMouseItem + ( + Blender_WindowData *pData, + int MouseX, + int MouseY, + MotionItemEnum *pMouseItem + ) +{ + int iMotion; + const int NumMotions = geMotion_GetSubMotionCount (pData->BlendedMotion); + + for (iMotion = 0; iMotion < NumMotions; ++iMotion) + { + const MotionItemEnum MousePos = ItemMousePos (pData->BlendedMotion, iMotion, pData->PixelsPerSecond, MouseX, MouseY); + if (MousePos != mieNONE) + { + *pMouseItem = MousePos; + return iMotion; + } + } + return NO_MOTION; +} + +// Convert mouse position, which is dialog-relative to blender window coordinates and return. +static POINT MousePosToBlender (HWND hwnd, int xPos, int yPos) +{ + POINT ptMouse; + + ptMouse.x = xPos; + ptMouse.y = yPos; + // convert to screen + ClientToScreen (hwnd, &ptMouse); + // and then to blender window + ScreenToClient (GetDlgItem (hwnd, IDC_STATICBLEND), &ptMouse); + + return ptMouse; +} + +// Check for and respond to mouse down messages in blender window +static void wm_LButtonDown + ( + Blender_WindowData *pData, + int xPos, + int yPos + ) +{ + const POINT ptMouse = MousePosToBlender (pData->hwnd, xPos, yPos); + RECT BlenderClientRect; + int Index; + MotionItemEnum MouseItem; + + GetClientRect (GetDlgItem (pData->hwnd, IDC_STATICBLEND), &BlenderClientRect); + + // quick test to see if it's in the rect + if (!PtInRect (&BlenderClientRect, ptMouse)) + { + return; + } + + Index = GetMouseItem (pData, ptMouse.x, ptMouse.y, &MouseItem); + if (Index != NO_MOTION) + { + // selecting an item...change current pos + if (Index != pData->CurrentBlendItem) + { + pData->CurrentBlendItem = Index; + Blender_SetBlendMotionData (pData); + } + pData->MouseMode = MouseItem; + pData->StartDragPoint = ptMouse; + pData->LastDragPoint = ptMouse; + } +} + +#pragma warning (disable:4100) +static void wm_LButtonUp + ( + Blender_WindowData *pData, + int xPos, + int yPos + ) +{ + // When the left button is released, clear movement mode. + if (pData->MouseMode != mieNONE) + { + pData->MouseMode = mieNONE; + if (pData->CurrentBlendItem != NO_MOTION) + { + Blender_SetBlendMotionData (pData); + } + } +} +#pragma warning (default:4100) + + +// Determine new scale factor given old scale factor, extents, and new delta in pixels +static geFloat ComputeNewTimeScale + ( + geFloat StartExtent, + geFloat EndExtent, + geFloat OldScale, + int DeltaPixels, + geFloat PixelScale + ) +{ + geFloat Length = EndExtent - StartExtent; // Length of motion (seconds) + int ScaledPixelLength = Units_Round (Length * PixelScale / OldScale); + int NewPixelLength = ScaledPixelLength + DeltaPixels; + geFloat NewScaledLength = ((geFloat)NewPixelLength) / PixelScale; + geFloat NewScaleValue = Length / NewScaledLength; + + return NewScaleValue; +} + + +// Handle mouse movements +// We're really only interested in mouse movements when one of the handles has been grabbed. +// +static void wm_MouseMove + ( + Blender_WindowData *pData, + int xPos, + int yPos + ) +{ + const POINT ptMouse = MousePosToBlender (pData->hwnd, xPos, yPos); + RECT BlenderClientRect; + HWND hwndBlender = GetDlgItem (pData->hwnd, IDC_STATICBLEND); + GetClientRect (hwndBlender, &BlenderClientRect); + + // just ignore it if not dragging. + if (pData->MouseMode == mieNONE) + { + return; + } + + // If the mouse has been dragged outside the window, then clear the current mode and return. + if (!PtInRect (&BlenderClientRect, ptMouse)) + { + pData->MouseMode = mieNONE; + if (pData->CurrentBlendItem != NO_MOTION) + { + Blender_SetBlendMotionData (pData); + } + return; + } + + + // If there's a current motion, then update the value based on which handle is being dragged. + if (pData->CurrentBlendItem != NO_MOTION) + { + int DeltaX = ptMouse.x - pData->LastDragPoint.x; + geFloat DeltaTime = ((geFloat)DeltaX)/pData->PixelsPerSecond; + Blender_Submotion SubInfo = Blender_GetCompleteSubmotion (pData->BlendedMotion, pData->CurrentBlendItem); + + switch (pData->MouseMode) + { + case mieMOTION : // moving motion + Blender_SetTimeOffset (pData, (SubInfo.TimeOffset+DeltaTime)); + Blender_NotifyParentOfChange (pData); + break; + + case mieMOTIONOFFSET : // moving left-hand scaling handle + { + // make sure we're not moving beyond right boundary... + RECT ItemRect = GetItemRect (pData->BlendedMotion, pData->CurrentBlendItem, pData->PixelsPerSecond); + if (ptMouse.x != ItemRect.right) + { + const geFloat NewScaleValue = ComputeNewTimeScale (SubInfo.StartExtent, SubInfo.EndExtent, SubInfo.TimeScale, -DeltaX, pData->PixelsPerSecond); + Blender_SetTimeScale (pData, NewScaleValue); + + // left handle also moves time offset... + Blender_SetTimeOffset (pData, (SubInfo.TimeOffset+DeltaTime)); + Blender_NotifyParentOfChange (pData); + } + break; + } + + case mieMOTIONEND :// moving right-hand scaling handle + { + // make sure we're not moving beyond left boundary... + RECT ItemRect = GetItemRect (pData->BlendedMotion, pData->CurrentBlendItem, pData->PixelsPerSecond); + if (ptMouse.x != ItemRect.left) + { + const geFloat NewScaleValue = ComputeNewTimeScale (SubInfo.StartExtent, SubInfo.EndExtent, SubInfo.TimeScale, DeltaX, pData->PixelsPerSecond); + Blender_SetTimeScale (pData, NewScaleValue); + Blender_NotifyParentOfChange (pData); + } + break; + } + + case mieSTARTBLEND : // moving start handle + { + // Make sure we're not moving the start position beyond the end position + const geFloat NewStartTime = SubInfo.StartBlendTime + (DeltaTime * SubInfo.TimeScale); + if (NewStartTime < SubInfo.EndBlendTime) + { + Blender_CreateNewPath (pData->BlendedMotion, pData->CurrentBlendItem, NewStartTime, SubInfo.StartBlend, SubInfo.EndBlendTime, SubInfo.EndBlend); + Blender_NotifyParentOfChange (pData); + } + break; + } + case mieENDBLEND : // moving end handle + { + // Make sure we're not moving the end position to a point before the start position + const geFloat NewEndTime = SubInfo.EndBlendTime + (DeltaTime * SubInfo.TimeScale); + if (NewEndTime > SubInfo.StartBlendTime) + { + Blender_CreateNewPath (pData->BlendedMotion, pData->CurrentBlendItem, SubInfo.StartBlendTime, SubInfo.StartBlend, NewEndTime, SubInfo.EndBlend); + Blender_NotifyParentOfChange (pData); + } + break; + } + + default : + assert (0); + } + // update the UI to reflect the change + Blender_SetBlendMotionData (pData); + pData->LastDragPoint = ptMouse; + } +} + +// Another cool switch statement. +static BOOL CALLBACK Blender_DlgProc + ( + HWND hwnd, + UINT msg, + WPARAM wParam, + LPARAM lParam + ) +{ + // Get window data. + Blender_WindowData *pData = Blender_GetWindowData (hwnd); + + switch (msg) + { + case WM_INITDIALOG : + { + // Need to set up data structure in WM_INITDIALOG. + pData = (Blender_WindowData *)lParam; + SetWindowLong (hwnd, GWL_USERDATA, (LONG)pData); + pData->hwnd = hwnd; + + return Blender_Initialize (pData); + } + + case WM_DESTROY : + Blender_ShutdownAll (pData); + break; + + case WM_PAINT : + Blender_PaintMotionWindow (pData); + return 0; + + case WM_COMMAND : + { + WORD wNotifyCode = HIWORD(wParam); // notification code + WORD wID = LOWORD(wParam); // item, control, or accelerator identifier + HWND hwndCtl = (HWND) lParam; // handle of control + + return wm_Command (pData, wNotifyCode, wID, hwndCtl); + } + + case WM_VKEYTOITEM : + { + // respond to space pressed in list box by adding that item + WORD nKey = LOWORD(wParam); // key value + HWND hwndListBox = (HWND) lParam; // handle of list box + + if (hwndListBox == GetDlgItem (hwnd, IDC_MOTIONSLIST)) + { + if (nKey == VK_SPACE) // don't quite know why VK_RETURN won't work + { + if (geMotion_GetSubMotionCount (pData->BlendedMotion) < MAX_SUBMOTIONS) + { + Blender_AddSelectedMotionToBlend (pData); + } + } + } + return -1; + } + + case WM_LBUTTONDOWN : + wm_LButtonDown (pData, LOWORD (lParam), HIWORD (lParam)); + return 0; + + case WM_LBUTTONUP : + wm_LButtonUp (pData, LOWORD (lParam), HIWORD (lParam)); + return 0; + + case WM_MOUSEMOVE : + wm_MouseMove (pData, LOWORD (lParam), HIWORD (lParam)); + return 0; + + default : + break; + } + return FALSE; +} + + +// Create a blender window and return its window handle. +HWND Blender_Create + ( + HWND hwndParent, + HINSTANCE hinst, + geActor_Def *ActorDef, + geMotion *BlendedMotion + ) +{ + HWND hwndBlender; + Blender_WindowData *pData; + + // allocate and initialize the window's local data + pData = GE_RAM_ALLOCATE_STRUCT (Blender_WindowData); + if (pData == NULL) + { + return NULL; + } + pData->hwnd = NULL; + pData->hwndParent = hwndParent; + pData->Instance = hinst; + pData->ActorDef = ActorDef; + pData->BlendedMotion = BlendedMotion; + if (geMotion_GetSubMotionCount (BlendedMotion) > 0) + { + pData->CurrentBlendItem = 0; + } + else + { + pData->CurrentBlendItem = NO_MOTION; + } + pData->MouseMode = mieNONE; + + // and create the dialog + hwndBlender = CreateDialogParam + ( + hinst, + MAKEINTRESOURCE (IDD_BLENDER), + hwndParent, + Blender_DlgProc, + (LONG)pData + ); + + return hwndBlender; +} + +// Called by parent when a new actor is loaded. +// This function clears current context and displays new blended motion +void Blender_UpdateActor + ( + HWND hwndBlender, + geActor_Def *ActorDef, + geMotion *BlendedMotion + ) +{ + Blender_WindowData *pData = Blender_GetWindowData (hwndBlender); + + pData->ActorDef = ActorDef; + pData->BlendedMotion = BlendedMotion; + pData->CurrentBlendItem = NO_MOTION; + pData->MouseMode = mieNONE; + Blender_Initialize (pData); +} diff --git a/ActView/Main/resource.h b/ActView/Main/resource.h new file mode 100644 index 0000000..f5ba886 --- /dev/null +++ b/ActView/Main/resource.h @@ -0,0 +1,133 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ActView.rc +// +#define IDS_CLASSNAME 1 +#define IDS_PROGRAMNAME 2 +#define IDS_UNIQUEMESSAGE 3 +#define IDS_DEFAULTPOSE 4 +#define IDS_BLENDEDMOTION 5 +#define IDR_MENU1 101 +#define IDD_DRIVERDIALOG 102 +#define IDD_ACTOR 103 +#define IDD_BLENDER 105 +#define IDI_FRAME 106 +#define IDI_MAINICON 107 +#define IDI_ZOOM 108 +#define IDS_CANTCREATEENGINE 109 +#define IDS_CANTCREATECAMERA 110 +#define IDI_PAN 111 +#define IDS_CANTCREATEWORLD 111 +#define IDS_CANTLOADDRIVER 112 +#define IDI_ROTATE 113 +#define IDS_CANTINITENGINE 113 +#define IDS_CANTLOADACTOR 114 +#define IDR_ACCELERATOR1 115 +#define IDD_ABOUT 116 +#define IDS_BEGINFRAMEFAIL 116 +#define IDS_RENDERFAIL 117 +#define IDS_INIFILENAME 118 +#define IDS_ENDFRAMEFAIL 119 +#define IDS_HELPFILENAME 120 +#define IDS_PROGRAMBASENAME 121 +#define IDS_ACTFILEFILTER 122 +#define IDS_ACTFILEEXT 123 +#define IDS_ACTFILEFILTERDESC 124 +#define IDS_UNNAMED 125 +#define IDB_ACTVIEW 126 +#define IDD_NEWDIALOG 127 +#define IDI_BLEND 128 +#define IDC_DRIVERLIST 1000 +#define IDC_MOTIONLIST 1000 +#define IDC_PAN 1001 +#define IDC_ROTATE 1002 +#define IDC_ZOOM 1003 +#define IDI_PLAY 1004 +#define IDI_PAUSE 1005 +#define IDI_RRSTART 1006 +#define IDI_RRFRAME 1007 +#define IDI_STOP 1008 +#define IDI_FFFRAME 1009 +#define IDI_FFEND 1010 +#define IDC_FRONT 1011 +#define IDC_MOTIONCOMBO 1012 +#define IDC_EDITSCALE 1013 +#define IDC_BACK 1014 +#define IDC_SLIDERTIME 1015 +#define IDC_EDITSPEED 1016 +#define IDC_LEFT 1017 +#define IDC_STATICSCALE 1018 +#define IDC_STATICMOTION 1019 +#define IDC_RENDERWIN 1020 +#define IDC_STATICSPEED 1021 +#define IDC_RIGHT 1022 +#define IDC_SPINSCALE 1023 +#define IDC_SPINSPEED 1024 +#define IDC_EDITFRAMETIME 1025 +#define IDC_SPINFRAMETIME 1026 +#define IDC_STATICFRAME 1027 +#define IDC_TOP 1028 +#define IDC_BOTTOM 1029 +#define IDC_STATICEND 1030 +#define IDC_STATICSTART 1031 +#define IDS_STATICSTART 1031 +#define IDC_STATICCURRENTTIME 1032 +#define IDC_LOOPED 1033 +#define IDC_CENTER 1034 +#define IDC_EDITDIR 1035 +#define IDC_STATICMOTION2 1035 +#define IDC_TAB1 1036 +#define IDC_LIST1 1037 +#define IDC_MOTIONSLIST 1037 +#define IDC_LIST2 1038 +#define IDC_BLENDLIST 1038 +#define IDC_BUTTON1 1039 +#define IDC_BLEND 1039 +#define IDC_ADD 1039 +#define IDC_BUTTON2 1040 +#define IDC_MOVEUP 1040 +#define IDC_BUTTON3 1041 +#define IDC_REMOVE 1041 +#define IDC_BUTTON4 1042 +#define IDC_MOVEDOWN 1042 +#define IDC_EDITTIMEOFFSET 1043 +#define IDC_SLIDERTIMEOFFSET 1044 +#define IDC_EDITTIMESCALE 1045 +#define IDC_EDITSTARTTIME 1046 +#define IDC_SLIDERSTARTTIME 1047 +#define IDC_EDITENDTIME 1048 +#define IDC_SLIDERENDTIME 1049 +#define IDC_EDITSTARTBLEND 1050 +#define IDC_EDITENDBLEND 1051 +#define IDC_SPINSTARTBLEND 1052 +#define IDC_SPINENDBLEND 1053 +#define IDC_CHECKSMOOTHBLEND 1054 +#define IDC_BLENDPATH 1055 +#define IDC_STATICMOTIONEND 1056 +#define IDC_TESTOUT 1057 +#define IDC_STATICBLEND 1060 +#define IDC_STATICSUBMOTION 1061 +#define ID_FILE_EXIT 40001 +#define ID_FILE_OPEN 40002 +#define ID_MOTION_SELECT 40003 +#define ID_START 40004 +#define ID_OPTIONS_FRONT 40005 +#define ID_HELP_CONTENTS 40006 +#define ID_HELP_ABOUT 40007 +#define ID_OPTIONS_FRAMERATE 40008 +#define IDS_CANTADDWORLD 40009 +#define IDS_CANTSTARTTIMER 40010 +#define IDC_NOTHING 40011 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 132 +#define _APS_NEXT_COMMAND_VALUE 40012 +#define _APS_NEXT_CONTROL_VALUE 1062 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/ActView/Util/About.c b/ActView/Util/About.c new file mode 100644 index 0000000..19f1e4f --- /dev/null +++ b/ActView/Util/About.c @@ -0,0 +1,70 @@ +/****************************************************************************************/ +/* ABOUT.C */ +/* */ +/* Author: Jim Mischel */ +/* Description: Actor Viewer's About dialog. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "about.h" +#include "resource.h" + +#pragma warning (disable:4514) // unreferenced inline function + +// AboutDlgProc -- Dialog procedure for simple about dialog box. +#pragma warning (disable:4100) +static BOOL CALLBACK About_DlgProc + ( + HWND hwnd, + UINT msg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch (msg) + { + case WM_INITDIALOG : + return TRUE; + case WM_COMMAND : + { + int wID = LOWORD (wParam); + + if ((wID == IDOK) || (wID == IDCANCEL)) + { + EndDialog (hwnd, wID); + } + } + } + return FALSE; +} +#pragma warning (default:4100) + + +// Just display the dialog box... +void About_DoDialog + ( + HWND hwndParent, + HINSTANCE hinst + ) +{ + DialogBox + ( + hinst, + MAKEINTRESOURCE (IDD_ABOUT), + hwndParent, + About_DlgProc + ); +} diff --git a/ActView/Util/FilePath.c b/ActView/Util/FilePath.c new file mode 100644 index 0000000..1811c36 --- /dev/null +++ b/ActView/Util/FilePath.c @@ -0,0 +1,272 @@ +/****************************************************************************************/ +/* FILEPATH.C */ +/* */ +/* Author: Jim Mischel */ +/* Description: Commonly used file and path name functions. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "FilePath.h" + +#include + +#include +#include +#include + +geBoolean FilePath_GetDrive + ( + char const *pPath, + char *pDrive + ) +{ + assert (pPath != NULL); + assert (pDrive != NULL); + + _splitpath (pPath, pDrive, NULL, NULL, NULL); + return (*pDrive != '\0'); +} + +geBoolean FilePath_GetDir + ( + char const *pPath, + char *pDir + ) +{ + assert (pPath != NULL); + assert (pDir != NULL); + + _splitpath (pPath, NULL, pDir, NULL, NULL); + return (*pDir != '\0'); + +} + +geBoolean FilePath_GetName + ( + char const *pPath, + char *pName + ) +{ + assert (pPath != NULL); + assert (pName != NULL); + + _splitpath (pPath, NULL, NULL, pName, NULL); + return (*pName != '\0'); +} + +geBoolean FilePath_GetExt + ( + char const *pPath, + char *pExt + ) +{ + assert (pPath != NULL); + assert (pExt != NULL); + + _splitpath (pPath, NULL, NULL, NULL, pExt); + return (*pExt != '\0'); +} + + +geBoolean FilePath_GetDriveAndDir + ( + char const *pPath, + char *pDriveDir + ) +{ + char Drive[_MAX_PATH]; + char Dir[_MAX_PATH]; + + assert (pPath != NULL); + assert (pDriveDir != NULL); + + _splitpath (pPath, Drive, Dir, NULL, NULL); + _makepath (pDriveDir, Drive, Dir, NULL, NULL); + return (*pDriveDir != '\0'); +} + +geBoolean FilePath_GetNameAndExt + ( + char const *pPath, + char *pNameExt + ) +{ + char Name[_MAX_PATH]; + char Ext[_MAX_PATH]; + + assert (pPath != NULL); + assert (pNameExt != NULL); + + _splitpath (pPath, NULL, NULL, Name, Ext); + _makepath (pNameExt, NULL, NULL, Name, Ext); + return (*pNameExt != '\0'); +} + +geBoolean FilePath_SetExt + ( + char const *pSrcFile, + char const *pExt, + char *pDestFile + ) +{ + + char Drive[_MAX_PATH]; + char Dir[_MAX_PATH]; + char Name[_MAX_PATH]; + + assert (pSrcFile != NULL); + assert (pExt != NULL); + assert (pDestFile != NULL); + + _splitpath (pSrcFile, Drive, Dir, Name, NULL); + _makepath (pDestFile, Drive, Dir, Name, pExt); + return GE_TRUE; // what's reasonable here??? + +} + +geBoolean FilePath_SlashTerminate + ( + char const *pPath, + char *pDest + ) +{ + char *c; + + assert (pPath != NULL); + assert (pDest != NULL); + + if (pDest != pPath) + { + strcpy (pDest, pPath); + } + + c = &(pDest[strlen (pDest)]); + if ((c == pDest) || (*(c-1) != '\\')) + { + *c = '\\'; + *(c+1) = '\0'; + } + return GE_TRUE; +} + + +geBoolean FilePath_AppendName + ( + char const *pPath, + char const *pName, + char *pDest + ) +{ + assert (pPath != NULL); + assert (pName != NULL); + assert (pDest != NULL); + + if (*pPath == '\0') + { + strcpy (pDest, pName); + } + else + { + FilePath_SlashTerminate (pPath, pDest); + strcat (pDest, pName); + } + + return GE_TRUE; +} + +// Search for a Filename in the semicolon-separated paths specified in SearchPath. +// If found, returns GE_TRUE and the full path name of the file in FoundPath. +// Returns GE_FALSE if unsuccessful. +geBoolean FilePath_SearchForFile (const char *Filename, const char *SearchPath, char *FoundPath) +{ + const char *c, *pPath; + char WorkPath[MAX_PATH]; + + c = SearchPath; + + do + { + pPath = c; + c = strchr (pPath, ';'); + if (c == NULL) + { + strcpy (WorkPath, pPath); + } + else + { + strncpy (WorkPath, pPath, (c-pPath)); + WorkPath[c-pPath] = '\0'; + ++c; + } + + FilePath_AppendName (WorkPath, Filename, WorkPath); + + if (_access (WorkPath, 0) == 0) + { + strcpy (FoundPath, WorkPath); + return GE_TRUE; + } + } while ((c != NULL) && (*c != '\0')); + + return GE_FALSE; +} + +geBoolean FilePath_AppendSearchDir (char *SearchList, const char *NewDir) +{ + if (*NewDir != '\0') + { + if (*SearchList != '\0') + { + strcat (SearchList, ";"); + } + strcat (SearchList, NewDir); + } + return GE_TRUE; +} + +geBoolean FilePath_ResolveRelativePath (const char *Relative, char *Resolved) +{ + GetFullPathName (Relative, MAX_PATH, Resolved, NULL); + return GE_TRUE; +} +/* +geBoolean FilePath_ResolveRelativePathList (const char *RelativeList, char *ResolvedList) +{ + char *PathString = Util_Strdup (RelativeList); + char *c; + + *ResolvedList = '\0'; + + if (PathString == NULL) + { + return GE_FALSE; + } + + c = strtok (PathString, ";"); + while (c != NULL) + { + char WorkPath[MAX_PATH]; + + GetFullPathName (c, sizeof (WorkPath), WorkPath, NULL); + FilePath_AppendSearchDir (ResolvedList, WorkPath); + c = strtok (NULL, ";"); + } + + geRam_Free (PathString); + + return GE_TRUE; +} +*/ \ No newline at end of file diff --git a/ActView/Util/FilePath.h b/ActView/Util/FilePath.h new file mode 100644 index 0000000..dfa8208 --- /dev/null +++ b/ActView/Util/FilePath.h @@ -0,0 +1,78 @@ +/****************************************************************************************/ +/* FILEPATH.H */ +/* */ +/* Author: Jim Mischel */ +/* Description: Commonly used file and path name functions. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef FILEPATH_H +#define FILEPATH_H + +#include "basetype.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// Extract drive (d:\) from pPath and place in pDrive +geBoolean FilePath_GetDrive (char const *pPath, char *pDrive); + +// Extract directory from pPath and place in pDir +geBoolean FilePath_GetDir (char const *pPath, char *pDir); + +// Extract Name from pPath and place in pName +geBoolean FilePath_GetName (char const *pPath, char *pName); + +// Extract Extension from pPath and place in pExt +geBoolean FilePath_GetExt (char const *pPath, char *pExt); + +// Extract drive and directory from pPath and place in pDriveDir +// pDriveDir may be the same as pPath +geBoolean FilePath_GetDriveAndDir (char const *pPath, char *pDriveDir); + +// Extract Name and extension from pPath and place in pName +// pName may be the same as pPath +geBoolean FilePath_GetNameAndExt (char const *pPath, char *pName); + +// set extension of pSourceFile to pExt and place result in pDestFile +// pDestFile may be the same as pSourceFile +geBoolean FilePath_SetExt (char const *pSourceFile, char const *pExt, char *pDestFile); + +// Terminate pPath with a slash (by appending if necessary), and return result in pDest. +// pPath and pDest may be the same. +geBoolean FilePath_SlashTerminate (const char *pPath, char *pDest); + +// Append pName to pPath and return result in pDest. +// pDest may be the same as pPath or pName. +geBoolean FilePath_AppendName (char const *pPath, char const *pName, char *pDest); + +// Search for a Filename in the semicolon-separated paths specified in SearchPath. +// If found, returns GE_TRUE and the full path name of the file in FoundPath. +// Returns GE_FALSE if unsuccessful. +geBoolean FilePath_SearchForFile (const char *Filename, const char *SearchPath, char *FoundPath); + + +geBoolean FilePath_AppendSearchDir (char *SearchList, const char *NewDir); +geBoolean FilePath_ResolveRelativePath (const char *Relative, char *Resolved); +geBoolean FilePath_ResolveRelativePathList (const char *RelativeList, char *ResolvedList); + +#ifdef __cplusplus + } +#endif + + +#endif diff --git a/ActView/Util/InstCheck.c b/ActView/Util/InstCheck.c new file mode 100644 index 0000000..c8529c2 --- /dev/null +++ b/ActView/Util/InstCheck.c @@ -0,0 +1,97 @@ +/****************************************************************************************/ +/* INSTCHECK.C */ +/* */ +/* Author: Jim Mischel */ +/* Description: Function to check for previous program instances. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "InstCheck.h" + +#pragma warning (disable:4514) + +static UINT InstCheck_UniqueMessage = 0; + +// data structure passed to previous instance callback function +typedef struct +{ + HWND prev_hwnd; + const char *TitleText; + HINSTANCE hinst; +} InstCheck_FindStruct; + +// Callback called by EnumWindows to find previous instance of application. +static BOOL CALLBACK InstCheck_FindPrevInstance + ( + HWND hwnd, + LPARAM lParam + ) +{ + InstCheck_FindStruct *fs = (InstCheck_FindStruct *)lParam; + const char *ProgramName; + char WindowName[1000]; + + // Since the window is a dialog that uses the standard dialog class, + // we can't use FindWindow to find a window with the class name. + // And we can't use FindWindow to find a window with a specific title + // because the title changes based on the loaded file. + // So we get each window's title and check the beginning of it for + // the program name, which should be there. + ProgramName = fs->TitleText; + GetWindowText (hwnd, WindowName, sizeof (WindowName)); + + if (strncmp (ProgramName, WindowName, strlen (ProgramName)) == 0) + { + // Found it. + // Set the callback data and tell EnumWindows to stop enumerating. + fs->prev_hwnd = hwnd; + return FALSE; + } + return TRUE; +} + +HWND InstCheck_CheckForPreviousInstance + ( + HINSTANCE instance, + const char *TitleText, + const char *UniqueMessageString + ) +{ + // Previous instance check. + + // If an instance of this program is already running, then + // bring it to the front and shut down this instance. + InstCheck_FindStruct fs; + BOOL FoundIt; + + fs.hinst = instance; + fs.TitleText = TitleText; + fs.prev_hwnd = NULL; + + // Register a unique windows message for this application + InstCheck_UniqueMessage = RegisterWindowMessage (UniqueMessageString); + + // go see if there is already a window of this type + // EnumWindows will return FALSE if our callback function finds the window. + FoundIt = !(EnumWindows (InstCheck_FindPrevInstance, (LPARAM)&fs)); + + return fs.prev_hwnd; +} + +UINT InstCheck_GetUniqueMessageId (void) +{ + return InstCheck_UniqueMessage; +} diff --git a/ActView/Util/InstCheck.h b/ActView/Util/InstCheck.h new file mode 100644 index 0000000..47c8279 --- /dev/null +++ b/ActView/Util/InstCheck.h @@ -0,0 +1,46 @@ +/****************************************************************************************/ +/* INSTCHECK.H */ +/* */ +/* Author: Jim Mischel */ +/* Description: Function to check for previous program instances. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef INSTCHECK_H +#define INSTCHECK_H + +#ifdef __cplusplus + extern "C" { +#endif + +#pragma warning(disable : 4201 4214 4115) +#include +#pragma warning(default : 4201 4214 4115) + +HWND InstCheck_CheckForPreviousInstance + ( + HINSTANCE instance, + const char *TitleText, + const char *UniqueMessageString + ); + +UINT InstCheck_GetUniqueMessageId (void); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/ActView/Util/WinUtil.c b/ActView/Util/WinUtil.c new file mode 100644 index 0000000..ae5b433 --- /dev/null +++ b/ActView/Util/WinUtil.c @@ -0,0 +1,97 @@ +/****************************************************************************************/ +/* WINUTIL.C */ +/* */ +/* Author: Jim Mischel */ +/* Description: Windows helper functions. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "WinUtil.h" +#include + +#pragma warning (disable:4514) + +// Set an edit box with floating point value +void WinUtil_SetDlgItemFloat + ( + HWND hwnd, + int ControlId, + geFloat fVal + ) +{ + char sVal[100]; + + sprintf (sVal, "%.2f", fVal); + SetDlgItemText (hwnd, ControlId, sVal); +} + +// Get geFloat from a dialog box. +BOOL WinUtil_GetDlgItemFloat + ( + HWND hwnd, + int ControlId, + geFloat *pVal + ) +{ + char sVal[100]; + geFloat fVal; + + GetDlgItemText (hwnd, ControlId, sVal, sizeof (sVal)); + if (sscanf (sVal, "%f", &fVal) != 1) + { + return FALSE; + } + *pVal = fVal; + return TRUE; +} + +// Convert a screen-relative rectangle to client coordinates. +BOOL WinUtil_ScreenRectToClient + ( + HWND hwnd, + RECT *pRect + ) +{ + POINT ptLT, ptRB; + + ptLT.x = pRect->left; + ptLT.y = pRect->top; + if (ScreenToClient (hwnd, &ptLT)) + { + ptRB.x = pRect->right; + ptRB.y = pRect->bottom; + if (ScreenToClient (hwnd, &ptRB)) + { + pRect->left = ptLT.x; + pRect->top = ptLT.y; + pRect->right = ptRB.x; + pRect->bottom = ptRB.y; + return TRUE; + } + } + return FALSE; +} + +// Enable a dialog box item. +void WinUtil_EnableDlgItem + ( + HWND hwnd, + int ControlId, + BOOL Enable + ) +{ + EnableWindow (GetDlgItem (hwnd, ControlId), Enable); +} diff --git a/ActView/Util/WinUtil.h b/ActView/Util/WinUtil.h new file mode 100644 index 0000000..3ae9610 --- /dev/null +++ b/ActView/Util/WinUtil.h @@ -0,0 +1,53 @@ +/****************************************************************************************/ +/* WINUTIL.H */ +/* */ +/* Author: Jim Mischel */ +/* Description: Windows helper functions. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef WINUTIL_H +#define WINUTIL_H + + +#pragma warning(disable : 4201 4214 4115) +#include +#pragma warning(default : 4201 4214 4115) +#include "basetype.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +// Set an edit box with floating point value +void WinUtil_SetDlgItemFloat (HWND hwnd, int ControlId, geFloat fVal); + +// Get a floating point value from an edit box +BOOL WinUtil_GetDlgItemFloat (HWND hwnd, int ControlId, geFloat *pVal); + +// Convert a screen-relative rectangle to client-relative coordinates +BOOL WinUtil_ScreenRectToClient (HWND hwnd, RECT *pRect); + +// EnableWindow for dialog items. +void WinUtil_EnableDlgItem (HWND hwnd, int ControlId, BOOL Enable); + +#ifdef __cplusplus + } +#endif + + +#endif diff --git a/ActView/Util/about.h b/ActView/Util/about.h new file mode 100644 index 0000000..3558c2f --- /dev/null +++ b/ActView/Util/about.h @@ -0,0 +1,35 @@ +/****************************************************************************************/ +/* ABOUT.H */ +/* */ +/* Author: Jim Mischel */ +/* Description: Actor Viewer's About dialog. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef ABOUT_H +#define ABOUT_H + +#pragma warning(disable : 4201 4214 4115) +#include +#pragma warning(default : 4201 4214 4115) + +void About_DoDialog + ( + HWND hwndParent, + HINSTANCE hinst + ); + +#endif diff --git a/ActView/Util/drvlist.c b/ActView/Util/drvlist.c new file mode 100644 index 0000000..8106d9a --- /dev/null +++ b/ActView/Util/drvlist.c @@ -0,0 +1,240 @@ +/****************************************************************************************/ +/* DRVLIST.C */ +/* */ +/* Author: Modified by Jim Mischel */ +/* Description: Actor Viewer's driver picker. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + + +/* + NOTE: This version has been modified to list only those drivers that + have a windowed mode. +*/ +#include +#include +#include +#include + +#include "genesis.h" + +#include "resource.h" +#include "drvlist.h" + +#pragma warning(disable : 4514) + +typedef struct DriverInfo +{ + geDriver * diDriver; + geDriver_Mode * diMode; + struct DriverInfo * diNext; +} DriverInfo; + +static geDriver * PickedDriver; +static geDriver_Mode * PickedMode; + +static void DestroyDriverList(DriverInfo *dlist) +{ + DriverInfo * temp; + + while (dlist) + { + temp = dlist->diNext; + free(dlist); + dlist = temp; + } +} + +static DriverInfo *BuildDriverList(geEngine *Engine) +{ + geDriver_System * DriverSystem; + geDriver * Driver; + geDriver_Mode * Mode; + DriverInfo * DriverList; + + DriverSystem = geEngine_GetDriverSystem(Engine); + if (DriverSystem == NULL) + return NULL; + + DriverList = NULL; + + Driver = geDriver_SystemGetNextDriver(DriverSystem, NULL); + while (Driver != NULL) + { + DriverInfo * dinfo; + const char * DriverName; + + geDriver_GetName(Driver, &DriverName); + + Mode = geDriver_GetNextMode(Driver, NULL); + while (Mode != NULL) + { + const char * ModeName; + + geDriver_ModeGetName(Mode, &ModeName); + + OutputDebugString (DriverName); + OutputDebugString (" : "); + OutputDebugString(ModeName); + OutputDebugString("\r\n"); + + // looking for all drivers that have window mode... + if(!strnicmp(ModeName, "Window", 6)) + { + dinfo = malloc(sizeof(*dinfo)); + if (!dinfo) + { + DestroyDriverList(DriverList); + return NULL; + } + dinfo->diNext = DriverList; + DriverList = dinfo; + dinfo->diDriver = Driver; + dinfo->diMode = Mode; + } + Mode = geDriver_GetNextMode(Driver, Mode); + } + Driver = geDriver_SystemGetNextDriver(DriverSystem, Driver); + } + + return DriverList; +} + +static void SetSelectedDriver (HWND hwndDlg, DriverInfo * DriverList) +{ + int DriverIdx; + + if (DriverList) + { + DriverInfo * Temp; + DriverIdx = SendDlgItemMessage(hwndDlg, IDC_DRIVERLIST, LB_GETCURSEL, (WPARAM)0, (LPARAM)0); + Temp = DriverList; + while (DriverIdx--) + { + Temp = Temp->diNext; + assert(Temp != NULL); + } + PickedDriver = Temp->diDriver; + PickedMode = Temp->diMode; + } +} + +static BOOL CALLBACK DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static DriverInfo * DriverList; + + switch (uMsg) + { + case WM_INITDIALOG: + DriverList = (DriverInfo *)lParam; + if (DriverList) + { + DriverInfo * temp; + HWND DriverListBox; + HDC hDC; + int MaxCX; + + DriverListBox = GetDlgItem(hwndDlg, IDC_DRIVERLIST); + hDC = GetDC(DriverListBox); + + MaxCX = 0; + + temp = DriverList; + while (temp) + { + char buff[256]; + SIZE extents; + const char * DriverName; + const char * ModeName; + + geDriver_GetName(temp->diDriver, &DriverName); + geDriver_ModeGetName(temp->diMode, &ModeName); + sprintf(buff, "%s %s", DriverName, ModeName); + SendDlgItemMessage(hwndDlg, IDC_DRIVERLIST, LB_ADDSTRING, 0, (LPARAM)buff); + GetTextExtentPoint32(hDC, buff, strlen(buff), &extents); + if (extents.cx > MaxCX) + MaxCX = extents.cx; + temp = temp->diNext; + } + + SendDlgItemMessage(hwndDlg, IDC_DRIVERLIST, LB_SETCURSEL, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_DRIVERLIST, LB_SETHORIZONTALEXTENT, MaxCX, 0); + + ReleaseDC(DriverListBox, hDC); + + return TRUE; + } + break; + + + case WM_COMMAND : + switch (LOWORD (wParam)) + { + case IDC_DRIVERLIST : + if (HIWORD (wParam) != LBN_DBLCLK) + { + break; + } + // double click, so fall through to OK + case IDOK : + { + SetSelectedDriver (hwndDlg, DriverList); + EndDialog(hwndDlg, 1); + break; + } + + case IDCANCEL : + EndDialog (hwndDlg, 0); + break; + + default : + break; + } + } + + return 0; +} + +void DrvList_PickDriver(HANDLE hInstance, HWND hwndParent, geEngine *Engine, geDriver **Driver, geDriver_Mode **Mode) +{ + DriverInfo * DriverList; + int res; + + PickedDriver = NULL; + PickedMode = NULL; + + DriverList = BuildDriverList(Engine); + res = DialogBoxParam(hInstance, + MAKEINTRESOURCE(IDD_DRIVERDIALOG), + hwndParent, + DlgProc, + (LPARAM)DriverList); + + DestroyDriverList(DriverList); + DriverList = NULL; + + if (res == 1) + { + *Driver = PickedDriver; + *Mode = PickedMode; + } + else + { + *Driver = NULL; + *Mode = NULL; + } +} diff --git a/ActView/Util/drvlist.h b/ActView/Util/drvlist.h new file mode 100644 index 0000000..9d4c272 --- /dev/null +++ b/ActView/Util/drvlist.h @@ -0,0 +1,40 @@ +/****************************************************************************************/ +/* DRVLIST.H */ +/* */ +/* Author: Modified by Jim Mischel */ +/* Description: Actor Viewer's driver picker. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DRVLIST_H +#define DRVLIST_H + + +#ifdef __cplusplus + extern "C" { +#endif + + +void DrvList_PickDriver(HANDLE hInstance, HWND hwndParent, geEngine *Engine, geDriver **Driver, geDriver_Mode **Mode); + + +#ifdef __cplusplus + } +#endif + + +#endif + diff --git a/ActView/Util/rcstring.c b/ActView/Util/rcstring.c new file mode 100644 index 0000000..26ed1ca --- /dev/null +++ b/ActView/Util/rcstring.c @@ -0,0 +1,56 @@ +/****************************************************************************************/ +/* RCSTRING.C */ +/* */ +/* Author: Jim Mischel */ +/* Description: Resource string wrapper function. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "rcstring.h" + +/* + Gets a resource string and returns a pointer to it. + This function maintains a static array of strings into which the resource strings + are placed. This function returns pointers to items in that static array. + The array is maintained as a circular queue, so if you want to keep the contents + of a resource string around, you should make a copy of it yourself after loading + it from GetResourceString. +*/ +const char *rcstring_Load + ( + HINSTANCE hinst, + int StringID + ) +{ + #define NUMSTRINGS 10 + #define STRINGSIZE 100 + static char Strings[NUMSTRINGS][STRINGSIZE]; + static int CurrentString = 0; + const char *TheString; + + // load the string into the current spot in the array + LoadString (hinst, StringID, Strings[CurrentString], STRINGSIZE); + TheString = Strings[CurrentString]; + + // Update current string pointer + ++CurrentString; + if (CurrentString >= NUMSTRINGS) + { + CurrentString = 0; + } + + return TheString; +} diff --git a/ActView/Util/rcstring.h b/ActView/Util/rcstring.h new file mode 100644 index 0000000..d2c22d5 --- /dev/null +++ b/ActView/Util/rcstring.h @@ -0,0 +1,50 @@ +/****************************************************************************************/ +/* RCSTRING.H */ +/* */ +/* Author: Jim Mischel */ +/* Description: Resource string wrapper function. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef RCSTRING_H +#define RCSTRING_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/* + Gets a resource string and returns a pointer to it. + This function maintains a static array of strings into which the resource strings + are placed. This function returns pointers to items in that static array. + The array is maintained as a circular queue, so if you want to keep the contents + of a resource string around, you should make a copy of it yourself after loading + it. +*/ +const char *rcstring_Load + ( + HINSTANCE hinst, + int StringID + ); + + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/ActView/Util/units.h b/ActView/Util/units.h new file mode 100644 index 0000000..c4fc972 --- /dev/null +++ b/ActView/Util/units.h @@ -0,0 +1,55 @@ +/****************************************************************************************/ +/* UNITS.H */ +/* */ +/* Author: Jim Mischel */ +/* Description: Common constants and unit conversions. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef UNITS_H +#define UNITS_H + +#include "basetype.h" +#include + +#ifdef __cplusplus + extern "C" { +#endif + + +#define PI2 ((geFloat)(2.0f * (GE_PI))) +#define ONE_OVER_2PI ((geFloat)(1.0f/(PI2))) + +// some useful unit conversions +#define UNITS_DEGREES_TO_RADIANS(d) Units_DegreesToRadians(d) +#define UNITS_RADIANS_TO_DEGREES(r) Units_RadiansToDegrees(r) + +#define Units_DegreesToRadians(d) ((((geFloat)(d)) * GE_PI) / 180.0f) +#define Units_RadiansToDegrees(r) ((((geFloat)(r)) * 180.0f) / GE_PI) + +#define Units_Round(n) ((int)Units_FRound((n))) +#define Units_Trunc(n) ((int)(n)) +#define Units_FRound(n) ((geFloat)floor((n)+0.5f)) + +#define Units_MakePercent(fVal) (Units_Round(fVal*100.0f)) +#define Units_FloatFromPercent(iVal) (((geFloat)iVal)/100.0f) + +#ifdef __cplusplus + } +#endif + +#endif + diff --git a/ActView/res/actview.bmp b/ActView/res/actview.bmp new file mode 100644 index 0000000000000000000000000000000000000000..684066a16430bae973302ddbc9b3a7f5f34204e1 GIT binary patch literal 19478 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 literal 0 HcmV?d00001 diff --git a/ActView/res/actview.ico b/ActView/res/actview.ico new file mode 100644 index 0000000000000000000000000000000000000000..4328bc6a8e30cd788c74810a396d6bb97af19d22 GIT binary patch literal 2238 zcmaKte@vU@7RSF6+#Dj?0-@5;v?-NY(h9Bx0;6l86)Y+1fLPL|P)1=b*cY&DWw6$c zHgea}4s1gU=*BFp+3F@{Kg5f~UGJ{C$sZdkQCzaHTs6_KJB`L&uXFXOii|F~&ztZ2 zocDa5bDsB{ynPC+BNvN>-^a;EfOKL#NyH+O5Um4o#zx{FQ~W&|jUsQ`HqroXE5LLEG;It<{bk+c46)hLCC^tkaA1P7l&4 z7jnF(!S3=vaP%U!kvM*@AJ0t9queur$J*T3(&E2Putnhpv&s&R$_uvg5OSMFu*)%v?!QM-X+8?+UJq)!0$}rtU~wM@YquNxrU`JA z4)9cN@ahgDS3~-s^FdHQgc2%@!lnR9S_0U$ZvuOrli1f!_I|DrsWK<{+EECaLdesO zkeD&>YWh*wGJyhJ07C5$q~?ovE2syGAly`<9*83qf1W?{K3YGmFG>*4WT)Q9C z$j4B1Pe9#!0xtwU1m%4Tp4S&3u2cgY4KgY`$f|N-Tcs7k#&Pg#-6+-{M^1$q;?@bs zI;K!&I*DrA4CK@}YI@$pbJh!J@h_mh{~|o^L}7AFAR$|aO#%v;ieb=Y{m861j7(As zqpTO%wWDBFIKWYONiU8fuRa8R-6(SFMv%@e2aohiNNO(B4x>QrgVZzyi6I1up7b{M z4n&omQxNNhpgA;)>aLTpo&EvV6W^fK`#!Y2r{H-ziYk3SUW)u1;@u|b4<08UzXo8c zu#R1iM6Lm}f;OdS)PbwIr_^n{p{^<~1Ty@)8&&JtUtG%pwZez3ROq~^9EL*xRdVh|j$6;kpY=&bLc zmef|GH6tl|FCNPw`)1XGDRzTSdd?QvQJ{1qgR26&umg&wqmb7w+?} znqQ1GzY@9-dZl^fi&f{U#VeyeD>Z&7J{ zOCCwdV5M;BX4U-iojZ4y=T&ApH-(jv^5>z3BqlA1!4!Qxck|}-^z_Y}b6<;?j3gQ} zX(h!*IxAT?Gd=zC%hPkQ+w_bunML2Yg0V4$k=%E6d3pYt{#pIC`Q_!SeaVcJRnFK< z%ahLr<;TLxYGwGCJUA=QqitsV6^|!%;nH`F&D4R$p~eGLv+>>1ur780uZ+C+D5t!# zITAU0_G~25Tq$=_@8zvPGAA2DUj>dSZr`1;%-p@LI2QOSWK6z~!}z>i-|QIs<=+49 z{W9ig*4v*q-jA_3`{kH}(nc14T#RTb$Jm#%i)*;>`)iK&>+PWiT|j%(iw*Km5Z zvwh$G>%KYvobUSneeKR_`Wl`hqI3s88Ypd0Hk1y0bWlf$Qr2+nSZpYp>OFPDdgN5^ zR9VB~jduKVPME)YYHA-D3$B#c`n`IDYH4smfJlx_xUrs90M*kS|h9 zdahi4R%&tk7_cGy^y{^fw%y^6q zPiqIfX9i`1XS@U2r#C#nktL|=K6gVlc&@uj@IZF5Je|XTs#vy5R{Rv76Z?aIa6Gl6GZwr+j=LA2r_3s%fO=jcB+ME}yEgy>zsz65NF={s`Lt?0jictx=_@wx{@|DU2* TM@}0evd8aQ+7yl6wMTygQ5I*7 literal 0 HcmV?d00001 diff --git a/ActView/res/blend.ico b/ActView/res/blend.ico new file mode 100644 index 0000000000000000000000000000000000000000..5c124f8c424425e9f73a0d01a3b4da5cd4515a8e GIT binary patch literal 766 zcmb_ayHdk25L^ewa%dbknWVyHK7&t5<)L)v64B&QC2cw;U*b=3NvV>8;n=e+TX<41 z3@5Gbc2}<%35eM8d;yL38L(vD5IONgM7Zb3pm#egzz%D>#E~WHx@J~G+71z|2sV{; z_(N1(3@fMHly6Pbl!I@o3NRz5@o*hn7I9G&+fbO+&YnUkiL#Xogd02yeJrxqV7f8q z%ds5qL%yEyssDo~$NBtn9@i)PG!^%M{7^bRP2z9t3)>48yLcNH&tCW0`+#1>^t0P! u;6fVIJV?YE{)9XELNq{mtJkTBqIv9c$aURs(C_`pFQ;d;`+dCV$?^^VETR7Z literal 0 HcmV?d00001 diff --git a/ActView/res/ffend.ico b/ActView/res/ffend.ico new file mode 100644 index 0000000000000000000000000000000000000000..cf8abb0741fafff2d9683b9d776c9f2899d7463b GIT binary patch literal 1078 zcmeH`yA6Xt5JU%XY$3UUi!5>)a8ERFrJV=}DS_BI1+3qI$O!DvvWJ_U{Tu;kR;pAh zrB=qXmhNcV?sZp5*GB5-CHR1qE=0iHb7YC5oOdCTs+59y5Zh6NGsxqX!yiBW2k^iL zSR)oV4-r!zG2S9dv#V?OJrDCe*ynbBf``vD`8hHkXM(3UA(DQD&-Z=v&cRh$;5|6muvNTgeT`RB;P>Gjg;X1;hXwM|ib)Vq;;fS|@&fzbSHnfC?!^2wMfb zs4;ro2jKYtdiE0eCIf0lg1gtq055WOVPuL@3RMF;F3gmXJZdTY@zXCr58T5(nyrJ` z(wWVz+0?kIR$ucQkk94(M4mp+%&(E@aZc#zLl~KUh0p!J>CZX$5m*Oc>43Qfrp8sZ J`kJ4+(hn(Wy9@vT literal 0 HcmV?d00001 diff --git a/ActView/res/irotate.ico b/ActView/res/irotate.ico new file mode 100644 index 0000000000000000000000000000000000000000..57c92d25b5b11ac10fa63af7b3ba6f03820130ef GIT binary patch literal 766 zcmdUtF%H5o3`Jekfsu)ojNF0@9D>_4H{mL|2UJW5mWq`HeV)q_1yr#ie)9dDZ@a3L zm^G{r7UsCl%$DdH1{h&uEfG-rjAX{PlwLw4wVX5R1&!Mz&mhY!4}XZZ{^wX3-jGT! zmIv~;FKj{CQx8m^=Uh`N$H!|cje5SU{WRwde1{cn8@TJF%O0Mj!yp}bMm^f!qyg_t M?cPZbq0n^#Pbl1zM*si- literal 0 HcmV?d00001 diff --git a/ActView/res/mainicon.ico b/ActView/res/mainicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a62508684a48445f0d952d7efc8538df151ff2f8 GIT binary patch literal 766 zcmcgqF%H5o47@g#SSpo?wHXcGBPqCnKP}_xI(I6;F7a_wl7@@ zR6O4Ap}5t+f%!;!@@tR5JkspHU_*Zowx6jx*fw``D=7{{$AAn&l;5g93E^5NeI0T%l|Mo8i$iN>YUqi2=-aagZp|q(pG`y?cL^b(Vq}r4(h{ z8|jS3SnDoGhgRz7C3uBFJ0f6r9a-Wk=PE=}^?i?eQ0A*roI#FT4uAag3*domc(VR5 zFYpN4MP1YPd;{!rJ3qm<&olWtG9G7wr)MFOeudBLfAgQKoX`;tw^D`^+%HN!@_rNi F#0ze;)lvWe literal 0 HcmV?d00001 diff --git a/ActView/res/rotate.cur b/ActView/res/rotate.cur new file mode 100644 index 0000000000000000000000000000000000000000..3e660966dd3f9c956309d08a427cafba6b22a64b GIT binary patch literal 326 zcmb7;F$w}P6hvQyB~`GqStThgy}^2nz0KxmIm#X*jeIAuun5RHpZDi8OdxQ=krG`G z2Nzv;k;GFtO;hfBTxK?gM-rdG7npar>cLIk2nD9hKhhtLDXO-Jbu-)JhZ4*RqWSro MS9Mu8hI)%^kG~v&W`mLNlFpVvi9o(|6my^wTa_bZLL8$<%f_{`aSb*)vcZ6OwRvJ=VXRswety3xa)5veDMbkH z3TUY@dff%!Spyw=iF}a(4@QE!*T?`ba&}>4ic$(y13NCvl#x7YDg5!%FF+66!@ihp zli50$&Ar*!xT;oP^Ba)Q<@`jRKF`drk?CpS#iz+(X4I literal 0 HcmV?d00001 diff --git a/ActView/res/rrstart.ico b/ActView/res/rrstart.ico new file mode 100644 index 0000000000000000000000000000000000000000..14730d9d46e08c1257c7cbe144ea2421406295b0 GIT binary patch literal 1078 zcmeH`y$ypv422(%I%0&YBKj;4iBTAVlE$N5Nr7OEY~g(7l8%BlN*-rF{}sr3mMYas zsa4=vOE8FgzK-t8;6C^6xhWiZ)T1ABClNXi6p>aBBdM7;LSLnRln`z_Zw#l@P Z(lVIlp8sz$Y~;SzS>Zm%3g35nuV1HD!14e9 literal 0 HcmV?d00001 diff --git a/ActView/res/stop.ico b/ActView/res/stop.ico new file mode 100644 index 0000000000000000000000000000000000000000..5e1ba43c0b8d1837daa0001556ef98b51a8ee4e3 GIT binary patch literal 1078 zcmds$O%B2!5QQJDNq444U}bs?kK)R6a5RqNk_(ven-ZhJZb(=4!JA(oA$cPO4T^D= z<1t7V{5;ou3DS9#7HSb*VbBQ+IJ=D`v6WJFSVHBT@!qg?%giIl@{*gs!L9kp-u&MA zUUU2)DH`ZQnaqATerkQMnd{t@AK_c)iFg|cjnhHXtHTl=Lg#hfeCDL*B$bxTd};W7 F=LKcZyMF)x literal 0 HcmV?d00001 diff --git a/ActView/res/zoom.cur b/ActView/res/zoom.cur new file mode 100644 index 0000000000000000000000000000000000000000..29708943f1c6366c9603cb65b709605d0991df1d GIT binary patch literal 326 zcma*hu?@m76old5C Copyright (c) 1994, All Rights Reserved. + **********************************************************************/ + +#pragma pack(1) + + +/* 3DS Shape point structure */ + +struct shppt +{ +float x; /* Control point */ +float y; +float z; +float inx; /* Incoming vector */ +float iny; +float inz; +float outx; /* Outgoing vector */ +float outy; +float outz; +unsigned short flags; +}; +typedef struct shppt Shppt; + +#include "ofile.h" // 3DS Object file header +#include "cfile.h" // 3DS Project file header +//#include "3dsshape.h" // 3DS shape file header +#include "kfio.h" // 3DS KF header +#pragma pack() + +struct Bkgrad { + float midpct; + Color botcolor; + Color midcolor; + Color topcolor; + }; + +struct Fogdata { + float nearplane; + float neardens; + float farplane; + float fardens; + Color color; + }; + +struct LFogData { + float zmin,zmax; + float density; + short type; + short fog_bg; + Color color; + }; + +struct Distcue { + float nearplane; + float neardim; + float farplane; + float fardim; + }; + +#define ENV_DISTCUE 1 +#define ENV_FOG 2 +#define ENV_LAYFOG 3 + +#define BG_SOLID 1 +#define BG_GRADIENT 2 +#define BG_BITMAP 3 + +struct BGdata { + int bgType; + int envType; + Color bkgd_solid; + Color amb_light; + Bkgrad bkgd_gradient; + Fogdata fog_data; + Distcue distance_cue; + int fog_bg,dim_bg; + char bkgd_map[81]; + LFogData lfog_data; + }; + +class StudioImport : public SceneImport { +public: + StudioImport(); + ~StudioImport(); + int ExtCount(); // Number of extensions supported + const TCHAR * Ext(int n); // Extension #n (i.e. "3DS") + const TCHAR * LongDesc(); // Long ASCII description (i.e. "Autodesk 3D Studio File") + const TCHAR * ShortDesc(); // Short ASCII description (i.e. "3D Studio") + const TCHAR * AuthorName(); // ASCII Author name + const TCHAR * CopyrightMessage(); // ASCII Copyright message + const TCHAR * OtherMessage1(); // Other message #1 + const TCHAR * OtherMessage2(); // Other message #2 + unsigned int Version(); // Version number * 100 (i.e. v3.01 = 301) + void ShowAbout(HWND hWnd); // Show DLL's "About..." box + int DoImport(const TCHAR *name,ImpInterface *i,Interface *gi); // Import file + }; + +#define SINGLE_SHAPE 0 +#define MULTIPLE_SHAPES 1 + +class StudioShapeImport : public SceneImport { + friend BOOL CALLBACK ShapeImportOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + +public: + static int importType; + int shapeNumber; + StudioShapeImport(); + ~StudioShapeImport(); + int ExtCount(); // Number of extensions supported + const TCHAR * Ext(int n); // Extension #n (i.e. "3DS") + const TCHAR * LongDesc(); // Long ASCII description (i.e. "Autodesk 3D Studio File") + const TCHAR * ShortDesc(); // Short ASCII description (i.e. "3D Studio") + const TCHAR * AuthorName(); // ASCII Author name + const TCHAR * CopyrightMessage(); // ASCII Copyright message + const TCHAR * OtherMessage1(); // Other message #1 + const TCHAR * OtherMessage2(); // Other message #2 + unsigned int Version(); // Version number * 100 (i.e. v3.01 = 301) + void ShowAbout(HWND hWnd); // Show DLL's "About..." box + int DoImport(const TCHAR *name,ImpInterface *i,Interface *gi); // Import file + }; + +// Handy file class + +class WorkFile { +private: + FILE *stream; +public: + WorkFile(const TCHAR *filename,const TCHAR *mode) { stream = _tfopen(filename,mode); }; + ~WorkFile() { if(stream) fclose(stream); stream = NULL; }; + FILE * Stream() { return stream; }; + }; + +// Some 3DS structures + +#pragma pack(1) +typedef struct { + float r,g,b; + } Color_f; + +typedef struct { + unsigned char r,g,b; + } Color_24; + +typedef struct { + unsigned short tag; + long size; + } Chunk_hdr; + +typedef struct { + float x; + float y; + float z; + unsigned short flags; + } Verts; + +typedef struct { + float u; + float v; + } Texverts; + +typedef struct { + unsigned short a; + unsigned short b; + unsigned short c; + unsigned char material; + unsigned char filler; + unsigned long sm_group; + unsigned short flags; + } Faces; + +typedef struct { + float x; + float y; + float z; + float tx; + float ty; + float tz; + float bank; + float focal; + unsigned short flags; + float nearplane; + float farplane; + void *appdata; + } Camera3DS; + +typedef struct dirlight{ + float x; + float y; + float z; + float tx; + float ty; + float tz; + unsigned short flags; + Color color; + float hotsize; + float fallsize; + float lo_bias; +// Object_list *exclude; + int shadsize; + float in_range,out_range; /* Attenuation range */ + float shadfilter; /* size of filter box*/ + char imgfile[13]; + float ray_bias; + float bank,aspect; /* Spotlight bank angle, aspect ratio */ + float mult; /* Light multiplier */ + void *appdata; + NameTab excList; + } Dirlight; + +typedef struct + { + float lo_bias,hi_bias; + short shadsize,shadsamp,shadrange; + } Locshad; + +typedef struct { + float bias,shadfilter; + short shadsize; + } LocShad2; + +#pragma pack() + +// 3DS face edge vis flags +#define ABLINE (1<<2) +#define BCLINE (1<<1) +#define CALINE 1 + +#define VWRAP (1<<11) /* Texture coord V wraps on this face */ +#define UWRAP (1<<3) /* Texture coord U wraps on this face */ + +// Node list structure + +#define OBJ_MESH 0 +#define OBJ_OMNILIGHT 1 +#define OBJ_SPOTLIGHT 2 +#define OBJ_CAMERA 3 +#define OBJ_DUMMY 4 +#define OBJ_TARGET 5 +#define OBJ_OTHER 6 // generated from app data + +// 3DS Key structures + +#pragma pack(1) +#define KEYHDR \ + TimeValue time; \ + float tens,cont,bias; \ + float easeTo,easeFrom; + +typedef struct { float p,ds,dd; } PosElem; +typedef struct { + KEYHDR + PosElem e[8]; /* enough to be bigger than the biggest key, + including RotKey */ + } Key; + +typedef struct { + KEYHDR + PosElem e[1]; + } ScalarKey; + +typedef struct { + KEYHDR + PosElem e[3]; + } PosKey; + +typedef struct { + KEYHDR + float angle; /* angle of rotation in radians (always >0) */ + float axis[3]; /* axis of rotation (unit vector) */ + float q[4]; /* quaternion describing orientation */ + float b[4]; /* incoming tangent term */ + float a[4]; /* outgoing tangent term */ + } RotKey; + +#ifdef LATER +typedef struct { + KEYHDR + Namedobj *object; + } MorphKey; + +typedef struct { + KEYHDR + } HideKey; +#endif // LATER + +typedef struct { + KEYHDR + FLOAT c[3]; + } ColorKey; +#pragma pack() + +// key types +#define KEY_FLOAT 0 +#define KEY_POS 1 +#define KEY_ROT 2 +#define KEY_SCL 3 +#define KEY_COLOR 4 + +#define NUMTRACKS 8 + +#define POS_TRACK_INDEX 0 +#define ROT_TRACK_INDEX 1 +#define SCL_TRACK_INDEX 2 +#define FOV_TRACK_INDEX 3 +#define ROLL_TRACK_INDEX 4 +#define COL_TRACK_INDEX 5 +#define HOT_TRACK_INDEX 6 +#define FALL_TRACK_INDEX 7 + + +typedef struct { + union { + Key key; + PosKey pos; + RotKey rot; + ColorKey col; + ScalarKey sc; + } key; + void *next; + } KeyList; + +// A list of 3DS objects with their names and types +typedef struct { + void *object; + Point3 srcPos; + Point3 targPos; + TSTR name; + int type; + int used; + int cstShad; + int rcvShad; + int mtln; + void *next; + } WkObjList; + +// A list of the nodes and their various keys +typedef struct { + ImpNode *node; + short id; + int type; + int mnum; + TSTR name; + TSTR owner; + Mesh *mesh; + ImpNode *parent; + Matrix3 tm; + KeyList *posList; + KeyList *rotList; + KeyList *scList; + KeyList *colList; + KeyList *hotList; + KeyList *fallList; + KeyList *fovList; + KeyList *rollList; + SHORT trackFlags[NUMTRACKS]; + void *next; + } WkNodeList; + +/* Camera flag bit meanings */ + +#define NO_CAM_CONE 0x0001 +#define NO_CAM_TEMP_APPDATA 0x0002 /* Free appdata after rendering complete */ + +#define NO_CAM_CONE_OFF (~NO_CAM_CONE) + +/* Light flag bit meanings */ + +#define NO_LT_ON 0x0001 +#define NO_LT_SHAD 0x0002 +#define NO_LT_LOCAL 0x0004 +#define NO_LT_CONE 0x0008 +#define NO_LT_RECT 0x0010 +#define NO_LT_PROJ 0x0020 +#define NO_LT_OVER 0x0040 +#define NO_LT_ATTEN 0x0080 +#define NO_LT_RAYTR 0x0100 +#define NO_LT_TEMP_APPDATA 0x0200 /* Free appdata after rendering complete */ + +#define NO_LT_OFF (~NO_LT_ON) +#define NO_LT_SHAD_OFF (~NO_LT_SHAD) +#define NO_LT_LOCAL_OFF (~NO_LT_LOCAL) +#define NO_LT_CONE_OFF (~NO_LT_CONE) +#define NO_LT_RECT_OFF (~NO_LT_RECT) +#define NO_LT_PROJ_OFF (~NO_LT_PROJ) +#define NO_LT_OVER_OFF (~NO_LT_OVER) +#define NO_LT_ATTEN_OFF (~NO_LT_ATTEN) + +/*--------- Track flags bits------------ */ + +/*-- This bit causes the spline to be cyclic */ +#define ANIM_CYCLIC 1 +/*-- This bit causes a track to continue "modulo" its duration */ +#define ANIM_LOOP (1<<1) +/*-- This bit is used by anim.c, but clients need not worry about it*/ +#define ANIM_NEGWRAP (1<<2) + +#define X_LOCKED (1<<3) +#define Y_LOCKED (1<<4) +#define Z_LOCKED (1<<5) +#define ALL_LOCKED (X_LOCKED|Y_LOCKED|Z_LOCKED) +#define TRACK_ATKEY (1<<6) + +/* these flags specify which coords are NOT inherited from parent */ +#define LNKSHFT 7 +#define NO_LNK_X (1<newTV; + + float hook_x, hook_y; + ObjWorker(ImpInterface *iptr,Interface *ip); + ~ObjWorker() { FinishUp(); FreeObjList(); FreeNodeList(); i->RedrawViews(); } + int StartMesh(const char *name); + int StartLight(const char *name); + int CreateLight(int type); + int StartCamera(const char *name); + int CreateCamera(int type); + int StartKF(ImpNode *node); + int StartShape(); + int StartSpline(); + int AddShapePoint(Shppt *p); + int CloseSpline(); + int FinishShape(); + int FinishUp(); + void SetTm(Matrix3 *transform) { tm = *transform; } + int SetVerts(int count); + int SetTVerts(int count); + int GetVerts() { return verts; } + int SetFaces(int count); + int GetFaces() { return faces; } + int PutVertex(int index,Verts *v); + int PutTVertex(int index,UVVert *v); + int PutFace(int index,Faces *f); + int PutSmooth(int index,unsigned long smooth); + int PutFaceMtl(int index, int imtl); + void SetTVerts(int nf, Faces *f); + DWORD AddNewTVert(UVVert p); + void Reset(); + void Abandon(); + int AddObject(Object *obj,int type,const TCHAR *name, int mtlNum=-1); + int AddNode(ImpNode *node,const TCHAR *name,int type,Mesh *mesh,char *owner,int mtlNum=-1); + int SetNodeId(ImpNode *node,short id); + int SetNodesParent(ImpNode *node,ImpNode *parent); + void * FindObject(char *name, int &type, int &cstShad, int &rcvShad, int &mtlNum); + int UseObject(char *name); + int CompleteScene(); + int SetupEnvironment(); + ImpNode * FindNode(char *name); + ImpNode * FindNodeFromId(short id); + WkNodeList * FindEntry(char *name); + WkNodeList * FindEntryFromId(short id); + WkNodeList * FindNodeListEntry(ImpNode *node); + WkObjList * FindObjListEntry(TSTR &name); + void * FindObjFromNode(ImpNode *node); + int FindTypeFromNode(ImpNode *node, Mesh **mesh); + TCHAR * NodeName(ImpNode *node); + void FreeObjList(); + void FreeNodeList(); + ImpNode * ThisNode() { return thisNode; } + ImpNode * ParentNode() { return parentNode; } + void SetParentNode(ImpNode *node) { parentNode = node; } + void SetPivot(Point3 p) { pivot = p; } + int AddPositionKey(PosKey *key) { return AddKey(&workNode->posList,(Key *)key); } + int AddRotationKey(RotKey *key) { return AddKey(&workNode->rotList,(Key *)key); } + int AddScaleKey(PosKey *key) { return AddKey(&workNode->scList,(Key *)key); } + int AddColorKey(ColorKey *key) { return AddKey(&workNode->colList,(Key *)key); } + int AddHotKey(ScalarKey *key) { return AddKey(&workNode->hotList,(Key *)key); } + int AddFallKey(ScalarKey *key) { return AddKey(&workNode->fallList,(Key *)key); } + int AddFOVKey(ScalarKey *key) { return AddKey(&workNode->fovList,(Key *)key); } + int AddRollKey(ScalarKey *key) { return AddKey(&workNode->rollList,(Key *)key); } + int AddKey(KeyList **list,Key *data); + void FreeKeyList(KeyList **list); + int SetTransform(ImpNode *node,Matrix3& m); + Matrix3 GetTransform(ImpNode *node); + int ReadyDummy(); + ImpNode * MakeDummy(const TCHAR *name); + ImpNode * MakeANode(const TCHAR *name, BOOL target,char *owner); + void SetDummy(int x) { isDummy = x; } + int IsDummy() { return isDummy; } + int SetDummyBounds(Point3& min,Point3& max); + void SetNodeName(const TCHAR *name) { nodename = name; } + void SetInstanceName(ImpNode *node, const TCHAR *iname); + void SetAnimLength(TimeValue l) { length = l; lengthSet = TRUE; } + void SetSegment(Interval seg) { segment = seg; segmentSet = TRUE; } + void SetControllerKeys(Control *cont,KeyList *keys,int type,float f=1.0f,float aspect=-1.0f); + void MakeControlsTCB(Control *tmCont,SHORT *tflags); + Mtl* GetMaxMtl(int i); + void AssignMtl(INode *theINode, Mesh *mesh); + void AssignMtl(WkNodeList* wkNode); + int GetMatNum(char *name); + void AddMeshMtl(SMtl *mtl); + void FreeUnusedMtls(); + int LoadAppData(FILE *stream,DWORD chunkSize); + void ParseIKData(INode *node); + }; + + +int skip_chunk(FILE *stream); +int get_next_chunk(FILE *stream,Chunk_hdr *hdr); +int SkipRead(FILE *stream,long bytes); +int read_string(char *string,FILE *stream,int maxsize); +int load_app_data(FILE *stream,void **pdata, int size); + +#define RDERR(ptr,count) { if(!fread(ptr,count,1,stream)) return 0; } +#define RD3FLOAT(p) RDERR(p,3*sizeof(FLOAT)) +#define RDFLOAT(p) RDERR(p,sizeof(FLOAT)) +#define RDLONG(p) RDERR(p,sizeof(LONG)) +#define RDSHORT(p) RDERR(p,sizeof(SHORT)) +#define DUMNUM 0x7fff diff --git a/Exporters/3dsires.h b/Exporters/3dsires.h new file mode 100644 index 0000000..9bd66d0 --- /dev/null +++ b/Exporters/3dsires.h @@ -0,0 +1,58 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by 3dsimp.rc +// +#define IDS_MATCHANIMLENGTH 1 +#define IDS_3DSIMP 2 +#define IDS_DB_MISSING_SHAPE 3 +#define IDS_DB_LIGHT_ERROR 4 +#define IDS_DB_CAMERA_ERROR 5 +#define IDS_DB_NO_OBJECT 6 +#define IDS_DB_HAS_VERTS 7 +#define IDS_DB_NUMVERTS_FAIL 8 +#define IDS_DB_HAS_TVERTS 9 +#define IDS_DB_HAS_FACES 10 +#define IDS_DB_NUMFACES_FAIL 11 +#define IDS_DB_NUMTVFACES_FAIL 12 +#define IDS_DB_PUT_NO_VERTS 13 +#define IDS_DB_3DSIMP 14 +#define IDS_DB_VERTS_OR 15 +#define IDS_DB_PUT_NO_TVERTS 16 +#define IDS_DB_TVERTS_OR 17 +#define IDS_DB_PUT_NO_FACES 18 +#define IDS_DB_FACES_OR 19 +#define IDS_DB_SMOOTH_NO_FACES 20 +#define IDS_DB_SMFACE_OR 21 +#define IDS_DB_SHAPE_NUM 22 +#define IDS_DB_NOT_LINKED 23 +#define IDD_SHAPEIMPORTOPTIONS 101 +#define IDD_MERGEORREPL 102 +#define IDC_SINGLEOBJECT 1000 +#define IDC_MULTIPLEOBJECTS 1001 +#define IDC_3DS_MERGE 1002 +#define IDC_3DS_REPLACE 1003 +#define IDS_TH_3DSTUDIO 40216 +#define IDS_TH_SCENEIMPORT 40217 +#define IDS_TH_3DSTUDIOSHAPE 40218 +#define IDS_TH_3DSIMPORTDLL 40219 +#define IDS_TH_3DSSCENEFILE 40220 +#define IDS_TH_3DSMESH 40221 +#define IDS_TH_TOM_HUDSON 40222 +#define IDS_TH_COPYRIGHT_YOST_GROUP 40223 +#define IDS_TH_3DSSHAPEFILE 40224 +#define IDS_TH_ERR_OPENING_FILE 40225 +#define IDS_TH_3DSIMP 40226 +#define IDS_TH_3DSREADERROR 40227 +#define IDS_TH_INVALIDFILE 40228 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Exporters/3dsmtl.cpp b/Exporters/3dsmtl.cpp new file mode 100644 index 0000000..fb7581e --- /dev/null +++ b/Exporters/3dsmtl.cpp @@ -0,0 +1,178 @@ +/****************************************************************************************/ +/* 3DSMTL.CPP */ +/* */ +/* Author: */ +/* Description: 3dsr4 material utilities */ +/* Sources originally drawn from the 3DS MAX SDK examples plugin code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "Max.h" +#include +#include +#include +#include "splshape.h" +#include "3dsires.h" +#include "imtl.h" +#include "dummy.h" +#include "3dsimp.h" +#include "mtldef.h" +#include "gamma.h" + + +void XMFree(void *p) { if (p) free(p); } + +void XMFreeAndZero(void **p) { + if (p) { + if (*p) { + free(*p); + *p = NULL; + } + } + } + +void *XMAlloc(int size) { return malloc(size); } + +void *XMAllocZero(int size) { + void *p = malloc(size); + memset(p,0,size); + return p; + } + + +static Color_24 blackcol = {0,0,0}; +static Color_24 whitecol = {255,255,255}; + +int TexBlurToPct(float tb) { + return((int)(tb*100.0+.5)); + } + +float PctToTexBlur(int p) { + return((float)p/100.0f); + } + +void ResetMapData(MapData *md, int n, int ismask) { + memset(md,0,sizeof(MapData)); + if ((!ismask)&&(n==Nrefl)) { + md->kind = 1; + md->p.ref.acb.shade = REND_METAL; + md->p.ref.acb.aalevel = 0; + md->p.ref.acb.flags = 0; + md->p.ref.acb.size = 100; + md->p.ref.acb.nth = 1; + } + else { + md->p.tex.texblur = PctToTexBlur(10 /*P.texture_blur_default*/); + md->p.tex.uscale = 1.0f; + md->p.tex.vscale = 1.0f; + md->p.tex.uoffset = 0.0f; + md->p.tex.voffset = 0.0f; + md->p.tex.ang_sin = 0.0f; + md->p.tex.ang_cos = 1.0f; + md->p.tex.col1 = blackcol; + md->p.tex.col2 = whitecol; + md->p.tex.rcol = md->p.tex.gcol = md->p.tex.bcol = blackcol; + md->p.tex.rcol.r = 255; + md->p.tex.gcol.g = 255; + md->p.tex.bcol.b = 255; + } + } + +void InitMappingValues(Mapping *m, int n, int isRmtl) { + if (isRmtl) m->amt.f = 1.0f; + else m->amt.pct = 100; + ResetMapData(&m->map,n,0); + ResetMapData(&m->mask,n,1); + } + + +void FreeMapDataRefs(MapData *md) { +// Cubmap *cm,*nextcm; + switch(md->kind) { + case 0: + XMFreeAndZero(&md->p.tex.sxp_data); + break; + case 1: +#if 0 + if (md->p.ref.acb.flags&AC_ON) { + for (cm =(Cubmap *)md->p.ref.bm; cm!=NULL; cm=nextcm) { + nextcm = cm->next; + XMFree(cm); + } + } + else{ + char ext[5]; + split_fext(md->name,NULL,ext); + if(stricmp(ext,".CUB")==0) { + if (md->p.ref .bm!=NULL) + XMFree(md->p.ref.bm); + } + } +#endif + break; + } + } + +void FreeMatRefs(SMtl *m) { + int k; + if (m->appdata) XMFreeAndZero(&m->appdata); + for (k=0; kmap[k]) { + FreeMapDataRefs(&m->map[k]->map); + FreeMapDataRefs(&m->map[k]->mask); + XMFreeAndZero((void **)&m->map[k]); + } + } + } + + +void ResetMapping(Mapping *m, int n, int isRmtl) { + FreeMapDataRefs(&m->map); + FreeMapDataRefs(&m->mask); + memset(m,0,sizeof(Mapping)); + InitMappingValues(m,n,isRmtl); + } + +Mapping *NewMapping(int n,int isRmtl) { + Mapping *m; + m = (Mapping*)XMAllocZero(sizeof(Mapping)); + if (m==NULL) return(NULL); + InitMappingValues(m,n,isRmtl); + return(m); + } + + +void init_mtl_struct(SMtl *mtl) { + memset(mtl,0,sizeof(SMtl)); + mtl->shininess=50; + mtl->shin2pct = 255; /* undefined */ + mtl->transparency=0; + mtl->shading=3; + mtl->wiresize = 1.0f; + } + +void set_mtl_decal(SMtl *mtl) { + int i; + Mapping *m; + for (i=0; imap[i])!=NULL) { + if (m->map.kind==0) + m->map.p.tex.texflags |= TEX_DECAL|TEX_NOWRAP; + if (m->mask.kind==0) + m->mask.p.tex.texflags |= TEX_DECAL|TEX_NOWRAP; + } + } + } diff --git a/Exporters/Cfile.h b/Exporters/Cfile.h new file mode 100644 index 0000000..5a50f8a --- /dev/null +++ b/Exporters/Cfile.h @@ -0,0 +1,302 @@ + +/* Configuration file data chunks */ + +#define CMAGIC 0xC23D /* Configuration magic */ + +#define C_MDRAWER 0xC010 +#define C_TDRAWER 0xC020 +#define C_SHPDRAWER 0xC030 +#define C_MODDRAWER 0xC040 +#define C_RIPDRAWER 0xC050 +#define C_TXDRAWER 0xC060 +#define C_PDRAWER 0xC062 +#define C_MTLDRAWER 0xC064 +#define C_FLIDRAWER 0xC066 +#define C_CUBDRAWER 0xC067 +#define C_MFILE 0xC070 +#define C_SHPFILE 0xC080 +#define C_MODFILE 0xC090 +#define C_RIPFILE 0xC0A0 +#define C_TXFILE 0xC0B0 +#define C_PFILE 0xC0B2 +#define C_MTLFILE 0xC0B4 +#define C_FLIFILE 0xC0B6 +#define C_PALFILE 0xC0B8 +#define C_TX_STRING 0xC0C0 +#define C_CONSTS 0xC0D0 +#define C_SNAPS 0xC0E0 +#define C_GRIDS 0xC0F0 +#define C_ASNAPS 0xC100 +#define C_GRID_RANGE 0xC110 +#define C_RENDTYPE 0xC120 +#define C_PROGMODE 0xC130 +#define C_PREVMODE 0xC140 +#define C_MODWMODE 0xC150 +#define C_MODMODEL 0xC160 +#define C_ALL_LINES 0xC170 +#define C_BACK_TYPE 0xC180 +#define C_MD_CS 0xC190 +#define C_MD_CE 0xC1A0 +#define C_MD_SML 0xC1B0 +#define C_MD_SMW 0xC1C0 +#define C_LOFT_WITH_TEXTURE 0xC1C3 +#define C_LOFT_L_REPEAT 0xC1C4 +#define C_LOFT_W_REPEAT 0xC1C5 +#define C_LOFT_UV_NORMALIZE 0xC1C6 +#define C_WELD_LOFT 0xC1C7 +#define C_MD_PDET 0xC1D0 +#define C_MD_SDET 0xC1E0 +#define C_RGB_RMODE 0xC1F0 +#define C_RGB_HIDE 0xC200 +#define C_RGB_MAPSW 0xC202 +#define C_RGB_TWOSIDE 0xC204 +#define C_RGB_SHADOW 0xC208 +#define C_RGB_AA 0xC210 +#define C_RGB_OVW 0xC220 +#define C_RGB_OVH 0xC230 +#define C_RGB_PICTYPE 0xC240 +#define C_RGB_OUTPUT 0xC250 +#define C_RGB_TODISK 0xC253 +#define C_RGB_COMPRESS 0xC254 +#define C_JPEG_COMPRESSION 0xC255 +#define C_RGB_DISPDEV 0xC256 +#define C_RGB_HARDDEV 0xC259 +#define C_RGB_PATH 0xC25A +#define C_BITMAP_DRAWER 0xC25B +#define C_RGB_FILE 0xC260 +#define C_RGB_OVASPECT 0xC270 + +#define C_RGB_ANIMTYPE 0xC271 +#define C_RENDER_ALL 0xC272 +#define C_REND_FROM 0xC273 +#define C_REND_TO 0xC274 +#define C_REND_NTH 0xC275 +#define C_PAL_TYPE 0xC276 +#define C_RND_TURBO 0xC277 +#define C_RND_MIP 0xC278 +#define C_BGND_METHOD 0xC279 +#define C_AUTO_REFLECT 0xC27A +#define C_VP_FROM 0xC27B +#define C_VP_TO 0xC27C +#define C_VP_NTH 0xC27D + +#define C_SRDIAM 0xC280 +#define C_SRDEG 0xC290 +#define C_SRSEG 0xC2A0 +#define C_SRDIR 0xC2B0 +#define C_HETOP 0xC2C0 +#define C_HEBOT 0xC2D0 +#define C_HEHT 0xC2E0 +#define C_HETURNS 0xC2F0 +#define C_HEDEG 0xC300 +#define C_HESEG 0xC310 +#define C_HEDIR 0xC320 +#define C_QUIKSTUFF 0xC330 +#define C_SEE_LIGHTS 0xC340 +#define C_SEE_CAMERAS 0xC350 +#define C_SEE_3D 0xC360 +#define C_MESHSEL 0xC370 +#define C_MESHUNSEL 0xC380 +#define C_POLYSEL 0xC390 +#define C_POLYUNSEL 0xC3A0 +#define C_SHPLOCAL 0xC3A2 +#define C_MSHLOCAL 0xC3A4 +#define C_NUM_FORMAT 0xC3B0 +#define C_ARCH_DENOM 0xC3C0 +#define C_IN_DEVICE 0xC3D0 +#define C_MSCALE 0xC3E0 +#define C_COMM_PORT 0xC3F0 +#define C_TAB_BASES 0xC400 +#define C_TAB_DIVS 0xC410 +#define C_MASTER_SCALES 0xC420 +#define C_SHOW_1STVERT 0xC430 +#define C_SHAPER_OK 0xC440 +#define C_LOFTER_OK 0xC450 +#define C_EDITOR_OK 0xC460 +#define C_KEYFRAMER_OK 0xC470 +#define C_PICKSIZE 0xC480 +#define C_MAPTYPE 0xC490 +#define C_MAP_DISPLAY 0xC4A0 +#define C_TILE_XY 0xC4B0 +#define C_MAP_XYZ 0xC4C0 +#define C_MAP_SCALE 0xC4D0 +#define C_MAP_MATRIX_OLD 0xC4E0 +#define C_MAP_MATRIX 0xC4E1 +#define C_MAP_WID_HT 0xC4F0 +#define C_OBNAME 0xC500 +#define C_CAMNAME 0xC510 +#define C_LTNAME 0xC520 +#define C_CUR_MNAME 0xC525 +#define C_CURMTL_FROM_MESH 0xC526 +#define C_GET_SHAPE_MAKE_FACES 0xC527 +#define C_DETAIL 0xC530 +#define C_VERTMARK 0xC540 +#define C_MSHAX 0xC550 +#define C_MSHCP 0xC560 +#define C_USERAX 0xC570 +#define C_SHOOK 0xC580 +#define C_RAX 0xC590 +#define C_STAPE 0xC5A0 +#define C_LTAPE 0xC5B0 +#define C_ETAPE 0xC5C0 +#define C_KTAPE 0xC5C8 +#define C_SPHSEGS 0xC5D0 +#define C_GEOSMOOTH 0xC5E0 +#define C_HEMISEGS 0xC5F0 +#define C_PRISMSEGS 0xC600 +#define C_PRISMSIDES 0xC610 +#define C_TUBESEGS 0xC620 +#define C_TUBESIDES 0xC630 +#define C_TORSEGS 0xC640 +#define C_TORSIDES 0xC650 +#define C_CONESIDES 0xC660 +#define C_CONESEGS 0xC661 +#define C_NGPARMS 0xC670 +#define C_PTHLEVEL 0xC680 +#define C_MSCSYM 0xC690 +#define C_MFTSYM 0xC6A0 +#define C_MTTSYM 0xC6B0 +#define C_SMOOTHING 0xC6C0 +#define C_MODICOUNT 0xC6D0 +#define C_FONTSEL 0xC6E0 +#define C_TESS_TYPE 0xC6f0 +#define C_TESS_TENSION 0xC6f1 + +#define C_SEG_START 0xC700 +#define C_SEG_END 0xC705 +#define C_CURTIME 0xC710 +#define C_ANIMLENGTH 0xC715 +#define C_PV_FROM 0xC720 +#define C_PV_TO 0xC725 +#define C_PV_DOFNUM 0xC730 +#define C_PV_RNG 0xC735 +#define C_PV_NTH 0xC740 +#define C_PV_TYPE 0xC745 +#define C_PV_METHOD 0xC750 +#define C_PV_FPS 0xC755 +#define C_VTR_FRAMES 0xC765 +#define C_VTR_HDTL 0xC770 +#define C_VTR_HD 0xC771 +#define C_VTR_TL 0xC772 +#define C_VTR_IN 0xC775 +#define C_VTR_PK 0xC780 +#define C_VTR_SH 0xC785 + +/* Material chunks */ + +#define C_WORK_MTLS 0xC790 /* Old-style -- now ignored */ +#define C_WORK_MTLS_2 0xC792 /* Old-style -- now ignored */ +#define C_WORK_MTLS_3 0xC793 /* Old-style -- now ignored */ +#define C_WORK_MTLS_4 0xC794 /* Old-style -- now ignored */ +#define C_WORK_MTLS_5 0xCB00 /* Old-style -- now ignored */ +#define C_WORK_MTLS_6 0xCB01 /* Old-style -- now ignored */ +#define C_WORK_MTLS_7 0xCB02 /* Old-style -- now ignored */ +#define C_WORK_MTLS_8 0xCB03 /* Old-style -- now ignored */ +#define C_WORKMTL 0xCB04 +#define C_SXP_TEXT_DATA 0xCB10 +#define C_SXP_TEXT2_DATA 0xCB20 +#define C_SXP_OPAC_DATA 0xCB11 +#define C_SXP_BUMP_DATA 0xCB12 +#define C_SXP_SPEC_DATA 0xCB24 +#define C_SXP_SHIN_DATA 0xCB13 +#define C_SXP_SELFI_DATA 0xCB28 +#define C_SXP_TEXT_MASKDATA 0xCB30 +#define C_SXP_TEXT2_MASKDATA 0xCB32 +#define C_SXP_OPAC_MASKDATA 0xCB34 +#define C_SXP_BUMP_MASKDATA 0xCB36 +#define C_SXP_SPEC_MASKDATA 0xCB38 +#define C_SXP_SHIN_MASKDATA 0xCB3A +#define C_SXP_SELFI_MASKDATA 0xC3C +#define C_SXP_REFL_MASKDATA 0xCB3E + +#define C_BGTYPE 0xC7A1 +#define C_MEDTILE 0xC7B0 + +/* Contrast */ + +#define C_LO_CONTRAST 0xC7D0 +#define C_HI_CONTRAST 0xC7D1 + +/* 3d frozen display */ + +#define C_FROZ_DISPLAY 0xC7E0 + +/* Booleans */ +#define C_BOOLWELD 0xc7f0 +#define C_BOOLTYPE 0xc7f1 + +#define C_ANG_THRESH 0xC900 +#define C_SS_THRESH 0xC901 +#define C_TEXTURE_BLUR_DEFAULT 0xC903 + +#define C_MAPDRAWER 0xCA00 +#define C_MAPDRAWER1 0xCA01 +#define C_MAPDRAWER2 0xCA02 +#define C_MAPDRAWER3 0xCA03 +#define C_MAPDRAWER4 0xCA04 +#define C_MAPDRAWER5 0xCA05 +#define C_MAPDRAWER6 0xCA06 +#define C_MAPDRAWER7 0xCA07 +#define C_MAPDRAWER8 0xCA08 +#define C_MAPDRAWER9 0xCA09 +#define C_MAPDRAWER_ENTRY 0xCA10 + +/* system options */ +#define C_BACKUP_FILE 0xCA20 +#define C_DITHER_256 0xCA21 +#define C_SAVE_LAST 0xCA22 +#define C_USE_ALPHA 0xCA23 +#define C_TGA_DEPTH 0xCA24 +#define C_REND_FIELDS 0xCA25 +#define C_REFLIP 0xCA26 +#define C_SEL_ITEMTOG 0xCA27 +#define C_SEL_RESET 0xCA28 +#define C_STICKY_KEYINF 0xCA29 +#define C_WELD_THRESHOLD 0xCA2A +#define C_ZCLIP_POINT 0xCA2B +#define C_ALPHA_SPLIT 0xCA2C +#define C_KF_SHOW_BACKFACE 0xCA30 +#define C_OPTIMIZE_LOFT 0xCA40 +#define C_TENS_DEFAULT 0xCA42 +#define C_CONT_DEFAULT 0xCA44 +#define C_BIAS_DEFAULT 0xCA46 + +#define C_DXFNAME_SRC 0xCA50 +#define C_AUTO_WELD 0xCA60 +#define C_AUTO_UNIFY 0xCA70 +#define C_AUTO_SMOOTH 0xCA80 +#define C_DXF_SMOOTH_ANG 0xCA90 +#define C_SMOOTH_ANG 0xCAA0 + +/* Special network-use chunks */ + +#define C_NET_USE_VPOST 0xCC00 +#define C_NET_USE_GAMMA 0xCC10 +#define C_NET_FIELD_ORDER 0xCC20 + +#define C_BLUR_FRAMES 0xCD00 +#define C_BLUR_SAMPLES 0xCD10 +#define C_BLUR_DUR 0xCD20 +#define C_HOT_METHOD 0xCD30 +#define C_HOT_CHECK 0xCD40 +#define C_PIXEL_SIZE 0xCD50 +#define C_DISP_GAMMA 0xCD60 +#define C_FBUF_GAMMA 0xCD70 +#define C_FILE_OUT_GAMMA 0xCD80 +#define C_FILE_IN_GAMMA 0xCD82 +#define C_GAMMA_CORRECT 0xCD84 +#define C_APPLY_DISP_GAMMA 0xCD90 /* OBSOLETE */ +#define C_APPLY_FBUF_GAMMA 0xCDA0 /* OBSOLETE */ +#define C_APPLY_FILE_GAMMA 0xCDB0 /* OBSOLETE */ +#define C_FORCE_WIRE 0xCDC0 +#define C_RAY_SHADOWS 0xCDD0 +#define C_MASTER_AMBIENT 0xCDE0 +#define C_SUPER_SAMPLE 0xCDF0 +#define C_OBJECT_MBLUR 0xCE00 +#define C_MBLUR_DITHER 0xCE10 +#define C_DITHER_24 0xCE20 +#define C_SUPER_BLACK 0xCE30 +#define C_SAFE_FRAME 0xCE40 +#define C_VIEW_PRES_RATIO 0xCE50 +#define C_BGND_PRES_RATIO 0xCE60 +#define C_NTH_SERIAL_NUM 0xCE70 diff --git a/Exporters/Kfio.h b/Exporters/Kfio.h new file mode 100644 index 0000000..abf118e --- /dev/null +++ b/Exporters/Kfio.h @@ -0,0 +1,55 @@ +#ifndef __kfio__ +#define __kfio__ + + +#define DOGIO +#define KFVERSION 5 + +/* kfio.h: defs for saving and loading .KFB files */ + +#define UNREC_OBJECT_NAME 0xff00 +#define BAD_PARENT_REF 0xff01 +#define BAD_OBJ_NAME 0xff02 + +#define NO_PARENT 0xFFFF + +#define M3DMAGIC 0x4D4D +#define M3D_VERSION 0x0002 + +#define KFDATA 0xB000 +#define KFHDR 0xB00A +#define AMBIENT_NODE_TAG 0xB001 +#define OBJECT_NODE_TAG 0xB002 +#define CAMERA_NODE_TAG 0xB003 +#define TARGET_NODE_TAG 0xB004 /* for cameras only */ +#define LIGHT_NODE_TAG 0xB005 +#define L_TARGET_NODE_TAG 0xB006 /* for lights only */ +#define SPOTLIGHT_NODE_TAG 0xB007 +#define KFSEG 0xB008 +#define KFCURTIME 0xB009 +#define NODE_HDR 0xB010 +#define INSTANCE_NAME 0xB011 +#define PRESCALE 0xB012 +#define PIVOT 0xB013 +#define BOUNDBOX 0xB014 +#define MORPH_SMOOTH 0xB015 +#define POS_TRACK_TAG 0xB020 +#define ROT_TRACK_TAG 0xB021 +#define SCL_TRACK_TAG 0xB022 +#define FOV_TRACK_TAG 0xB023 +#define ROLL_TRACK_TAG 0xB024 +#define COL_TRACK_TAG 0xB025 +#define MORPH_TRACK_TAG 0xB026 +#define HOT_TRACK_TAG 0xB027 +#define FALL_TRACK_TAG 0xB028 +#define HIDE_TRACK_TAG 0xB029 +#define NODE_ID 0xB030 + +#define W_TENS 1 +#define W_CONT (1<<1) +#define W_BIAS (1<<2) +#define W_EASETO (1<<3) +#define W_EASEFROM (1<<4) + + +#endif diff --git a/Exporters/Mtldef.h b/Exporters/Mtldef.h new file mode 100644 index 0000000..fc3856d --- /dev/null +++ b/Exporters/Mtldef.h @@ -0,0 +1,223 @@ +/******************************************************************* + * + * DESCRIPTION: 3DStudio R4 Material definitions + * + * AUTHOR: + * + * HISTORY: + * + *******************************************************************/ + +#ifndef __MTLDEF__H +#define __MTLDEF__H + +#define REND_WIRE 0 +#define REND_FLAT 1 +#define REND_GOURAUD 2 +#define REND_PHONG 3 +#define REND_METAL 4 + +/* Material flags field bit definitions */ +#define MF_TWOSIDE (1<<0) /* Material seen from both sides */ +#define MF_SELF (1<<1) /* Material self-illuminated */ +#define MF_DECAL (1<<2) /* Material maps act as decals (transparent color) */ +#define MF_ADDITIVE (1<<3) /* Material uses additive transparency */ +#define MF_WIRE (1<<4) /* Material renders as wire frame */ +#define MF_NEEDUV (1<<5) /* Material has some UV type maps */ +#define MF_NEED3D (1<<6) /* Material needs 3D coords for SXP */ +#define MF_XPFALLIN (1<<7) /* Transparency fall-off to inside */ +#define MF_MATTE (1<<8) /* Material used as a matte */ +#define MF_CUBICMAP (1<<9) /* Reflection map is cubic */ +#define MF_XPFALL (1<<10) /* Do Transparency fall-off */ +#define MF_SUPERSMP (1<<11) /* Super sample material */ +#define MF_FACEMAP (1<<12) /* Face-texture-coords */ +#define MF_PHONGSOFT (1<<13) /* Soften phong hilites */ +#define MF_WIREABS (1<<14) /* Absolute wire size */ +#define MF_REFBLUR (1<<15) /* blurred reflection map */ +/* for clearing temporary flags */ +#define MF_CLEAR_TEMPFLAGS ~(MF_NEEDUV|MF_NEED3D|MF_REFBLUR|MF_CUBICMAP) + +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef unsigned int uint; + + +typedef struct { + uchar shade; /* shading level for auto-cubic */ + uchar aalevel; /* anti-alias level for auto-cubic */ + ushort flags; /* auto cubic flags */ + int size; /* bitmap size for auto-cubic */ + int nth; /* do nth frame for auto-cubic */ + } AutoCubicParams; + + +#define CM_UP 0 +#define CM_DOWN 1 +#define CM_LEFT 2 +#define CM_RIGHT 3 +#define CM_FRONT 4 +#define CM_BACK 5 +#define CUBMAP_READY 1 + +typedef struct cubmap { + // Bitmap *mapptr[6]; + char mapname[6][13]; + short flags; + short objnum; /* for auto-cubic= point-of-view object: -1 for user defined*/ + short mtlobj; /* object referred to to find which face is mapped (morphing)*/ + struct cubmap *next; + // Bitmap *blurmap; + int x,y; /* location for mirrors */ + } Cubmap; + +/* Auto-cubic flags */ +#define AC_ON 1 /* if ON this is an auto-cubic mapped material */ +#define AC_SHADOW (1<<1) +#define AC_2SIDE (1<<2) +#define AC_FIRSTONLY (1<<3) +#define AC_MIRROR (1<<4) + +/* rmtl.use flags */ +#define MATUSE_XPFALL (1<<0) +#define MATUSE_REFBLUR (1<<1) + +/* TextureParam.texflags */ +#define TEX_DECAL (1) +#define TEX_MIRROR (1<<1) +#define TEX_UNUSED1 (1<<2) +#define TEX_INVERT (1<<3) +#define TEX_NOWRAP (1<<4) +#define TEX_SAT (1<<5) /* summed area table */ +#define TEX_ALPHA_SOURCE (1<<6) /* use ALPHA instead of RGB of map */ +#define TEX_TINT (1<<7) /* tint for color */ +#define TEX_DONT_USE_ALPHA (1<<8) /* don't use map alpha */ +#define TEX_RGB_TINT (1<<9) /* Do RGB color transform */ + +typedef struct sxpent { + char name[13]; + ULONG handle; + void *pdata; + struct sxpent *next; + } SXPentry; + +#define NMAPTYPES 8 +#define Ntex 0 +#define Ntex2 1 +#define Nopac 2 +#define Nbump 3 +#define Nspec 4 +#define Nshin 5 +#define Nselfi 6 +#define Nrefl 7 + +#define USE_tex (1< +#include +#include +#include "splshape.h" +#include "3dsires.h" +#include "dummy.h" +#include "imtl.h" +#include "3dsimp.h" +#include "mtldef.h" +#include "gamma.h" + +extern int dump_(ushort tag,FILE *stream,void *data); + +#define WRITEF(ptr,size) fwrite((char *)ptr,1,size,stream) +#define WERR(ptr,sz) {if (WRITEF(ptr,(sz))!=(sz)) return(0);} +#define WRTERR(ptr,sz) {if (WRITEF(ptr,(sz))!=(sz)) return(0);} +#define WRFLOAT(ptr) WERR(ptr,sizeof(FLOAT)) +#define WR3FLOAT(ptr) WERR(ptr,3*sizeof(FLOAT)) +#define WRLONG(ptr) WERR(ptr,sizeof(LONG)) +#define WRSHORT(ptr) WERR(ptr,sizeof(SHORT)) +#define WRSTRING(ptr) WERR(ptr,strlen(ptr)+1) + +//extern Mliblist *mlib; +Mmtllist *mmtl; +SMtl *savemtl,*savemlist; +int savecount; + + +static ULONG map_chunks[8] = { + MAT_TEXMAP,MAT_TEX2MAP,MAT_OPACMAP,MAT_BUMPMAP, + MAT_SPECMAP,MAT_SHINMAP,MAT_SELFIMAP,MAT_REFLMAP + }; +static ULONG mask_chunks[8] = { + MAT_TEXMASK,MAT_TEX2MASK,MAT_OPACMASK,MAT_BUMPMASK, + MAT_SPECMASK,MAT_SHINMASK,MAT_SELFIMASK,MAT_REFLMASK + }; +static ULONG map_sxp_chunks[8] = { + MAT_SXP_TEXT_DATA,MAT_SXP_TEXT2_DATA,MAT_SXP_OPAC_DATA,MAT_SXP_BUMP_DATA, + MAT_SXP_SPEC_DATA,MAT_SXP_SHIN_DATA,MAT_SXP_SELFI_DATA,0 + }; +static ULONG mask_sxp_chunks[8] = { + MAT_SXP_TEXT_MASKDATA,MAT_SXP_TEXT2_MASKDATA,MAT_SXP_OPAC_MASKDATA,MAT_SXP_BUMP_MASKDATA, + MAT_SXP_SPEC_MASKDATA,MAT_SXP_SHIN_MASKDATA,MAT_SXP_SELFI_MASKDATA,MAT_SXP_REFL_MASKDATA + }; + +int libtype; + +#ifdef LATER +/* Save materials (0=lib, 1=current) to file */ +int +save_mli(char *fname,int type) + { + FILE *stream; + int error; + + libtype=type; + + if((stream=GOpen(fname,"wb"))==NULL) + { + cant_create(); + return(0); + } + + error=0; + + if(dump_mtlchunk(MLIBMAGIC,stream,NULL)==0) + error=1; + + if(GClose(stream)) + error=1; + + if(error) { + write_err(); + remove(fname); + } + + if(debug) + { + getchar(); + redraw(0,0,320,200); + } + + if(error) + return(0); + return(1); + } + +#endif //LATER + +/* Main routine for writing a file! */ +/* Recursive chunk writer -- keeps track of each chunk */ + +#define DMP_MATCHUNK(id,data) { if(dump_mtlchunk((ushort)id,stream,data)==0) return(0);} + +#define DMP_IFNOT_NULL(id,ptr) if (ptr) DMP_MATCHUNK(id,&ptr) + + +isSXPname(char *name) { + char ext[5]; + strncpy(ext, name+strlen(name)-4, 5); + strupr(ext); + return(strcmp(".SXP",ext)==0); + } + + +int dmp_map_params(FILE *stream,MapParams *mp) { + DMP_MATCHUNK(MAT_MAP_TILING,&mp->texflags); + DMP_MATCHUNK(MAT_MAP_TEXBLUR,&mp->texblur); + if (mp->uscale!=1.0) + DMP_MATCHUNK(MAT_MAP_USCALE,&mp->uscale); + if (mp->vscale!=1.0) + DMP_MATCHUNK(MAT_MAP_VSCALE,&mp->vscale); + if (mp->uoffset!=0.0) + DMP_MATCHUNK(MAT_MAP_UOFFSET,&mp->uoffset); + if (mp->voffset!=0.0) + DMP_MATCHUNK(MAT_MAP_VOFFSET,&mp->voffset); + if (mp->ang_sin!=0.0) { + DMP_MATCHUNK(MAT_MAP_ANG,mp); + } + if (mp->col1.r!=0||mp->col1.g!=0||mp->col1.b!=0) + DMP_MATCHUNK(MAT_MAP_COL1,&mp->col1); + if (mp->col2.r!=255||mp->col2.g!=255||mp->col2.b!=255) + DMP_MATCHUNK(MAT_MAP_COL2,&mp->col2); + if (mp->rcol.r!=255||mp->rcol.g!=0 ||mp->rcol.b!=0 ) + DMP_MATCHUNK(MAT_MAP_RCOL,&mp->rcol); + if (mp->gcol.r!=0 ||mp->gcol.g!=255||mp->gcol.b!=0 ) + DMP_MATCHUNK(MAT_MAP_GCOL,&mp->gcol); + if (mp->bcol.r!=0 ||mp->bcol.g!=0 ||mp->bcol.b!=255) + DMP_MATCHUNK(MAT_MAP_BCOL,&mp->bcol); + return(1); + } + +int dmp_map(FILE *stream, int i) { + Mapping *m = savemtl->map[i]; + if (i==Nbump) { + int t = m->amt.pct/4; /* for old versions */ + DMP_MATCHUNK(INT_PERCENTAGE,&t); + DMP_MATCHUNK(MAT_MAPNAME,m->map.name); + DMP_MATCHUNK(MAT_BUMP_PERCENT,&m->amt.pct); /* new version of bump percent*/ + } + else { + DMP_MATCHUNK(INT_PERCENTAGE,&m->amt.pct); + DMP_MATCHUNK(MAT_MAPNAME,m->map.name); + } + if (m->map.kind==0) + return(dmp_map_params(stream,&m->map.p.tex)); + else + return(1); + } + + +int dmp_mask(FILE *stream, int i) { + Mapping *m = savemtl->map[i]; + DMP_MATCHUNK(MAT_MAPNAME,m->mask.name); + if (m->mask.kind==0) + return(dmp_map_params(stream,&m->mask.p.tex)); + else + return(1); + } + +int isSXPMap(MapData *md) { + return(md->kind==0&&md->p.tex.sxp_data!=NULL); + } + +int +dump_mtlchunk(ushort tag,FILE *stream,void *data) + { + long chunkptr,chunkbase,curpos,chunksize; + Color_f *cf; + Color_24 *c24; + char *string; + Mmtllist *ml; +// Mliblist *mlb; + + chunkbase=ftell(stream); + WRTERR(&tag,2); + chunkptr=ftell(stream); /* Save file ptr for chunk size */ + WRTERR(&chunkptr,4); + switch(tag) + { + case MLIBMAGIC: + switch(libtype) + { + case 0: +// if(mlib) +// { +// mlb=mlib; +// while(mlb) +// { +// savemtl= &mlb->material; +// if(dump_mtlchunk(MAT_ENTRY,stream,NULL)==0) +// return(0); +// mlb=mlb->next; +// } +// } + break; + case 1: + if(mmtl) + { +// tag_used_mmtls(); // for our purposes, they're ALL used + ml=mmtl; + while(ml) + { +// if(ml->flags & MMTLUSED) + { + savemtl= &ml->material; + if(dump_mtlchunk(MAT_ENTRY,stream,NULL)==0) + return(0); + } + ml=ml->next; + } + } + break; + } + break; + case MAT_ENTRY: + case MATMAGIC: + { + if(dump_mtlchunk(MAT_NAME,stream,savemtl->name)==0) return(0); + if(dump_mtlchunk(MAT_AMBIENT,stream,&savemtl->amb)==0) return(0); + if(dump_mtlchunk(MAT_DIFFUSE,stream,&savemtl->diff)==0) return(0); + if(dump_mtlchunk(MAT_SPECULAR,stream,&savemtl->spec)==0)return(0); + if(dump_mtlchunk(MAT_SHININESS,stream,NULL)==0) return(0); + if(dump_mtlchunk(MAT_SHIN2PCT,stream,NULL)==0) return(0); + if(dump_mtlchunk(MAT_TRANSPARENCY,stream,NULL)==0) return(0); + if(dump_mtlchunk(MAT_XPFALL,stream,NULL)==0) return(0); + if(dump_mtlchunk(MAT_REFBLUR,stream,NULL)==0) return(0); + if(dump_mtlchunk(MAT_SHADING,stream,NULL)==0) return(0); + if(dump_mtlchunk(MAT_SELF_ILPCT,stream,NULL)==0) return(0); + + if(savemtl->use&MATUSE_XPFALL) { + if(dump_mtlchunk(MAT_USE_XPFALL,stream,NULL)==0) + return(0); + } + if(savemtl->use&MATUSE_REFBLUR) { + if(dump_mtlchunk(MAT_USE_REFBLUR,stream,NULL)==0) + return(0); + } + if(savemtl->flags & MF_TWOSIDE) { + if(dump_mtlchunk(MAT_TWO_SIDE,stream,NULL)==0) + return(0); + } + if(savemtl->flags & MF_ADDITIVE) { + if(dump_mtlchunk(MAT_ADDITIVE,stream,NULL)==0) + return(0); + } + if(savemtl->flags & MF_WIRE) { + if(dump_mtlchunk(MAT_WIRE,stream,NULL)==0) + return(0); + } + if(savemtl->flags & MF_FACEMAP) { + if(dump_mtlchunk(MAT_FACEMAP,stream,NULL)==0) + return(0); + } + + if(savemtl->flags & MF_XPFALLIN) { + if(dump_mtlchunk(MAT_XPFALLIN,stream,NULL)==0) + return(0); + } + + if(savemtl->flags & MF_PHONGSOFT) { + if(dump_mtlchunk(MAT_PHONGSOFT,stream,NULL)==0) + return(0); + } + + if(savemtl->flags & MF_WIREABS) { + if(dump_mtlchunk(MAT_WIREABS,stream,NULL)==0) + return(0); + } + + if(dump_mtlchunk(MAT_WIRESIZE,stream,&savemtl->wiresize)==0) + return(0); + + /* Save out any texture maps, masks, sxp's */ + for (int k=0; kmap[k]; + if (mp==NULL) continue; + if (mp->use) { + DMP_MATCHUNK(map_chunks[k],NULL); + if (k!=Nrefl) { + if (isSXPMap(&mp->map)) + DMP_MATCHUNK(map_sxp_chunks[k],mp->map.p.tex.sxp_data); + } + if (mp->mask.name[0]!=0) { + DMP_MATCHUNK(mask_chunks[k],NULL); + if (isSXPMap(&mp->mask)) + DMP_MATCHUNK(mask_sxp_chunks[k],mp->mask.p.tex.sxp_data); + } + } + } + /* dump auto-cubic chunk */ + { + Mapping *rm = savemtl->map[Nrefl]; + if (rm&&rm->use&&rm->map.p.ref.acb.flags & AC_ON) DMP_MATCHUNK(MAT_ACUBIC,&rm->map.p.ref.acb); + } + if (savemtl->appdata) + if(dump_mtlchunk(APP_DATA,stream,savemtl->appdata)==0) + return(0); + } + break; + + case APP_DATA: + { + ULONG *plong = (ULONG *)data; + WRTERR(&plong[1],plong[0]); + } + break; + case MAT_AMBIENT: + case MAT_DIFFUSE: + case MAT_SPECULAR: + if (gammaMgr.enable) { + Color_24 gc; + c24 = (Color_24 *)data; + gc.r = gammaMgr.file_in_gamtab[c24->r]; + gc.g = gammaMgr.file_in_gamtab[c24->g]; + gc.b = gammaMgr.file_in_gamtab[c24->b]; + if(dump_mtlchunk(COLOR_24,stream,&gc)==0) return(0); + if(dump_mtlchunk(LIN_COLOR_24,stream,data)==0)return(0); + } + else { + if(dump_mtlchunk(COLOR_24,stream,data)==0) return(0); + } + break; + case MAT_SHININESS: + if(dump_mtlchunk(INT_PERCENTAGE,stream,&savemtl->shininess)==0) + return(0); + break; + case MAT_SHIN2PCT: + if(dump_mtlchunk(INT_PERCENTAGE,stream,&savemtl->shin2pct)==0) + return(0); + break; + case MAT_SHIN3PCT: + if(dump_mtlchunk(INT_PERCENTAGE,stream,&savemtl->shin3pct)==0) + return(0); + break; + case MAT_TRANSPARENCY: + if(dump_mtlchunk(INT_PERCENTAGE,stream,&savemtl->transparency)==0) + return(0); + break; + case MAT_XPFALL: + if(dump_mtlchunk(INT_PERCENTAGE,stream,&savemtl->xpfall)==0) + return(0); + break; + case MAT_REFBLUR: + if(dump_mtlchunk(INT_PERCENTAGE,stream,&savemtl->refblur)==0) + return(0); + break; + case MAT_SELF_ILPCT: + if(dump_mtlchunk(INT_PERCENTAGE,stream,&savemtl->selfipct)==0) + return(0); + break; + case MAT_SHADING: + WRTERR(&savemtl->shading,2); + break; + + case MAT_TEXMAP: if (!dmp_map(stream,Ntex)) return(0); break; + case MAT_TEX2MAP: if (!dmp_map(stream,Ntex2)) return(0); break; + case MAT_OPACMAP: if (!dmp_map(stream,Nopac)) return(0); break; + case MAT_BUMPMAP: if (!dmp_map(stream,Nbump)) return(0); break; + case MAT_SPECMAP: if (!dmp_map(stream,Nspec)) return(0); break; + case MAT_SHINMAP: if (!dmp_map(stream,Nshin)) return(0); break; + case MAT_SELFIMAP: if (!dmp_map(stream,Nselfi)) return(0); break; + case MAT_REFLMAP: if (!dmp_map(stream,Nrefl)) return(0); break; + + case MAT_TEXMASK: if (!dmp_mask(stream,Ntex)) return(0); break; + case MAT_TEX2MASK: if (!dmp_mask(stream,Ntex2)) return(0); break; + case MAT_OPACMASK: if (!dmp_mask(stream,Nopac)) return(0); break; + case MAT_BUMPMASK: if (!dmp_mask(stream,Nbump)) return(0); break; + case MAT_SPECMASK: if (!dmp_mask(stream,Nspec)) return(0); break; + case MAT_SHINMASK: if (!dmp_mask(stream,Nshin)) return(0); break; + case MAT_SELFIMASK:if (!dmp_mask(stream,Nselfi)) return(0); break; + case MAT_REFLMASK: if (!dmp_mask(stream,Nrefl)) return(0); break; + + case MAT_MAP_TILING: + WRTERR(data,2); + break; + case MAT_MAP_TEXBLUR: + case MAT_MAP_USCALE: + case MAT_MAP_VSCALE: + case MAT_MAP_UOFFSET: + case MAT_MAP_VOFFSET: + WRTERR(data,4); + break; + case MAT_MAP_COL1: + case MAT_MAP_COL2: + case MAT_MAP_RCOL: + case MAT_MAP_GCOL: + case MAT_MAP_BCOL: + c24=(Color_24 *)data; + WRTERR(c24,3); + break; + case MAT_MAP_ANG: + { + MapParams *mp = (MapParams *)data; + float ang,dang; + ang = (float)atan2(mp->ang_sin,mp->ang_cos); + dang = RadToDeg(ang); +#if 0 + printf("Saving MAT_MAP_ANG sin = %.4f , cos = %.4f, ang = %.4f \n", + mp->ang_sin, mp->ang_cos, ang); +#endif + WRTERR(&dang,4); + } + break; + + case COLOR_F: + cf=(Color_f *)data; + WRTERR(cf,12); + break; + case COLOR_24: + c24=(Color_24 *)data; + WRTERR(c24,3); + break; + case LIN_COLOR_24: + c24 = (Color_24 *)data; + WRTERR(c24,3); + break; + case MAT_NAME: /* Simple strings */ + case MAT_MAPNAME: + string=(char *)data; + WRTERR(string,strlen(string)+1); + break; + case MAT_BUMP_PERCENT: + case INT_PERCENTAGE: + WRTERR(data,2); + break; + case MAT_WIRESIZE: + WRTERR(data,4); + break; + case MAT_TWO_SIDE: + case MAT_SUPERSMP: + case MAT_ADDITIVE: + case MAT_WIRE: + case MAT_FACEMAP: + case MAT_XPFALLIN: + case MAT_USE_XPFALL: + case MAT_USE_REFBLUR: + case MAT_PHONGSOFT: + case MAT_WIREABS: + case DUMMY: + break; + case MAT_ACUBIC: { + AutoCubicParams *ac = (AutoCubicParams *)data; + WRTERR(&ac->shade,1); + WRTERR(&ac->aalevel,1); + WRTERR(&ac->flags,2); + WRTERR(&ac->size,4); + WRTERR(&ac->nth,4); + } + break; + case MAT_SXP_TEXT_DATA: + case MAT_SXP_TEXT2_DATA: + case MAT_SXP_OPAC_DATA: + case MAT_SXP_BUMP_DATA: + case MAT_SXP_SPEC_DATA: + case MAT_SXP_SHIN_DATA: + case MAT_SXP_SELFI_DATA: + + case MAT_SXP_TEXT_MASKDATA: + case MAT_SXP_TEXT2_MASKDATA: + case MAT_SXP_OPAC_MASKDATA: + case MAT_SXP_BUMP_MASKDATA: + case MAT_SXP_SPEC_MASKDATA: + case MAT_SXP_SHIN_MASKDATA: + case MAT_SXP_SELFI_MASKDATA: + case MAT_SXP_REFL_MASKDATA: + { + ULONG *plong = (ULONG *)data; + if (plong!=NULL) + WRTERR(&plong[1],plong[0]); + } + break; + } + + /* Save file ptr */ + + curpos=ftell(stream); + + /* Point back to chunk size location */ + + fseek(stream,chunkptr,SEEK_SET); + + /* Calc & write chunk size */ + + chunksize=curpos-chunkbase; + WRTERR(&chunksize,4); + + /* Point back to file end */ + + fseek(stream,curpos,SEEK_SET); + return(1); + } + diff --git a/Exporters/gexp.cpp b/Exporters/gexp.cpp new file mode 100644 index 0000000..0f56b22 --- /dev/null +++ b/Exporters/gexp.cpp @@ -0,0 +1,3937 @@ +/****************************************************************************************/ +/* GEXP.CPP */ +/* */ +/* Author: */ +/* Description: 3DS Max exporter code for Genesis3D Actors */ +/* ADAPTED FROM Tom Hudsons origional MAX 2 3DS... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include + +#include "Max.h" +#include "3dseres.h" +#include "gexp.h" +#include "istdplug.h" +#include "mtldef.h" +#include "stdmat.h" +#include "notetrck.h" +#include "dummy.h" + +// R1 doesn't have the interfaces +#ifndef USE_MAX1SDK +#include "phyexp.h" +#endif + +#define LOTS_OF_STRINGS 2000 +char *FullNameList[LOTS_OF_STRINGS]; +int FullNameListSize=0; + +static char ExportVersion[1024] = "\0"; + + +#define BIP_BONE_CLASS_ID 0x00009125 + + +BOOL operator==(const Matrix3 &m1, const Matrix3 &m2) +{ + for (int i=0; i<4; i++) + { + if (m1.GetRow(i) != m2.GetRow(i)) return FALSE; + } + return TRUE; +} + +static Point3 colorVal; +static float floatVal; +short Get3DSTVerts(Mesh& mesh, Point2 *tv); + +#define EXPORT_MTLS + +#pragma pack(1) + +struct LocShad2 { + float bias,shadfilter; + short shadsize; + }; + +struct Camera3DS { + float x; + float y; + float z; + float tx; + float ty; + float tz; + float bank; + float focal; + WORD flags; + float nearplane; + float farplane; + void *appdata; + }; +#pragma pack() + +#define PRIMARY_NODE (1<<14) + +#define RDERR(ptr,sz) if (fread((void *)ptr,1,sz,stream)!=(sz)) return(0) +#define WRTERR(ptr,sz) if (fwrite((void *)ptr,1,sz,stream)!=(sz)) return(0) +#define GREAD(ptr,sz) ((fread((void *)ptr,1,sz,stream)!=(sz)) ? 0:1) +#define GWRITE(ptr,sz) ((fwrite((void *)ptr,1,sz,stream)!=(sz)) ? 0:1) + +#include + +#if 0 +void DebugPrint(const TCHAR *format, ...) { + TCHAR buf[512]; + va_list args; + va_start(args,format); + _vsntprintf(buf,512,format,args); + va_end(args); + OutputDebugString(buf); + } +#endif + +HINSTANCE hInstance; + +TCHAR *GetString(int id) + { + static TCHAR buf[256]; + if (hInstance) + return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL; + return NULL; + } + +static void MessageBox(int s1, int s2) { + TSTR str1(GetString(s1)); + TSTR str2(GetString(s2)); + MessageBox(GetActiveWindow(), str1.data(), str2.data(), MB_OK); + } + +static int MessageBox(int s1, int s2, int option = MB_OK) { + TSTR str1(GetString(s1)); + TSTR str2(GetString(s2)); + return MessageBox(GetActiveWindow(), str1, str2, option); + } + +static int Alert(int s1, int s2 = IDS_TH_EXP, int option = MB_OK) { + return MessageBox(s1, s2, option); + } + +#define no_RAM() Alert(IDS_TH_OUTOFMEMORY) + +#define LAYERS_BY_OBJECT 0 +#define LAYERS_BY_MATERIAL 1 +#define LAYERS_ONE_LAYER 2 + +#define NUM_SOURCES 3 // # of sources in dialog + +class _3DSExport : public SceneExport +{ + +#ifdef MAYBE + friend BOOL CALLBACK ExportOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +#endif // MAYBE + +public: + _3DSExport(); + ~_3DSExport(); + int ExtCount(); // Number of extensions supported + const TCHAR * Ext(int n); // Extension #n (i.e. "NFO") + const TCHAR * LongDesc(); // Long ASCII description (i.e. "Autodesk 3D Studio File") + const TCHAR * ShortDesc(); // Short ASCII description (i.e. "3D Studio") + const TCHAR * AuthorName(); // ASCII Author name + const TCHAR * CopyrightMessage(); // ASCII Copyright message + const TCHAR * OtherMessage1(); // Other message #1 + const TCHAR * OtherMessage2(); // Other message #2 + unsigned int Version(); // Version number * 100 (i.e. v3.01 = 301) + void ShowAbout(HWND hWnd); // Show DLL's "About..." box + +#ifdef USE_MAX1SDK +int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i); // Export file +#else +#if (MAX_RELEASE >= 3000) +// For Max3, the options bitfield argument only supports SCENE_EXPORT_SELECTED +// (export selected nodes only). This feature is ignored for now. Another +// new function, SupportsOptions, queries the exporter for supported options. +// The default implementation of SupportsOptions returns false for no support. +// SupportsOptions is not overridden, so no options are supported in this exporter. +int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0); +#else // (MAX_RELEASE >= 2000) +int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE); +// Export file +#endif +#endif // !USE_MAX1SDK + + + +}; + +// Statics + +// Handy file class + +class WorkFile { +private: + FILE *stream; + +public: + WorkFile(const TCHAR *filename,const TCHAR *mode) { stream = NULL; Open(filename, mode); }; + ~WorkFile() { Close(); }; + FILE * Stream() { return stream; }; + int Close() { int result=0; if(stream) result=fclose(stream); stream = NULL; return result; } + void Open(const TCHAR *filename,const TCHAR *mode) { Close(); stream = _tfopen(filename,mode); } + }; + +// Handy memory worker + +class Memory { + void *ptr; +public: + Memory() { ptr = NULL; } + Memory(int amount, BOOL zero = FALSE) { ptr = NULL; Alloc(amount, zero); } + ~Memory() { Free(); } + void * Ptr() { return ptr; } + void * Realloc(int amount); + void * Alloc(int amount, BOOL zero = FALSE); + void Free() { if(ptr) free(ptr); ptr = NULL; } + }; + +void *Memory::Realloc(int amount) { + if(ptr) + ptr = realloc(ptr, amount); + else + ptr = malloc(amount); + return ptr; + } + +void *Memory::Alloc(int amount, BOOL zero) { + Free(); + ptr = malloc(amount); + if(ptr && zero) { + char *p = (char *)ptr; + for(int i = 0; i < amount; ++i) + *p++ = 0; + } + return ptr; + } + +// Jaguar interface code + +int controlsInit = FALSE; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) +{ + hInstance = hinstDLL; + + if(ExportVersion[0] == 0) + { + char Filename[1024]; + void* pBuffer; + UINT NumBytes; + DWORD dw; + char* pVersion = NULL; + + if(GetModuleFileName(hinstDLL, Filename, 1024) > 0) + { + NumBytes = GetFileVersionInfoSize(Filename, &dw); + pBuffer = malloc(NumBytes); + if(pBuffer != NULL) + { + if(GetFileVersionInfo(Filename, dw, NumBytes, pBuffer)) + { + VerQueryValue( pBuffer, + TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), + (void**)&pVersion, + &NumBytes); + if(pVersion != NULL) + { + strcpy(ExportVersion, pVersion); + } + } + + free(pBuffer); + } + } + } + + if ( !controlsInit ) + { + controlsInit = TRUE; + + // jaguar controls + InitCustomControls(hInstance); + + // initialize Chicago controls + InitCommonControls(); + } + + switch(fdwReason) + { + case DLL_PROCESS_ATTACH: + //MessageBox(NULL,_T("3DSIMP.DLL: John Pollard is COOL"),_T("3DSIMP"),MB_OK); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + break; + } + + return(TRUE); +} + + +//------------------------------------------------------ + +class _3DSClassDesc:public ClassDesc { + public: + int IsPublic() { return 1; } + void * Create(BOOL loading = FALSE) { return new _3DSExport; } + const TCHAR * ClassName() { return GetString(IDS_TH_CLASS); } + SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } +#ifdef NFOEXP + Class_ID ClassID() { return Class_ID(0x5f2748e4, 0x49de544c); } +#endif +#ifdef KEYEXP + Class_ID ClassID() { return Class_ID(0x6d2d1c15, 0x7d39056a); } +#endif +#ifdef BVHEXP + Class_ID ClassID() { return Class_ID(0x1c411d6a, 0x3a12069f); } +#endif + const TCHAR* Category() { return GetString(IDS_TH_SCENEEXPORT); } + }; + +static _3DSClassDesc _3DSDesc; + +//------------------------------------------------------ +// This is the interface to Jaguar: +//------------------------------------------------------ + +__declspec( dllexport ) const TCHAR * +LibDescription() { return GetString(IDS_TH_EXPORTDLL); } + +__declspec( dllexport ) int +LibNumberClasses() { return 1; } + +__declspec( dllexport ) ClassDesc * +LibClassDesc(int i) { + switch(i) { + case 0: return &_3DSDesc; break; + default: return 0; break; + } + } + +// Return version so can detect obsolete DLLs +__declspec( dllexport ) ULONG +LibVersion() { return VERSION_3DSMAX; } + +// +// ._3DS export module functions follow: +// + +_3DSExport::_3DSExport() { + } + +_3DSExport::~_3DSExport() { + } + +int +_3DSExport::ExtCount() { + return 1; + } + +const TCHAR * +_3DSExport::Ext(int n) { // Extensions supported for import/export modules + switch(n) { + case 0: +#ifdef NFOEXP + return GetString(IDS_NFO_EXT); +#endif +#ifdef KEYEXP + return GetString(IDS_KEY_EXT); +#endif +#ifdef BVHEXP + return GetString(IDS_BVH_EXT); +#endif + } + return _T(""); + } + +const TCHAR * +_3DSExport::LongDesc() { // Long ASCII description (i.e. "Targa 2.0 Image File") + return GetString(IDS_TH_SCENEFILE); + } + +const TCHAR * +_3DSExport::ShortDesc() { // Short ASCII description (i.e. "Targa") + return GetString(IDS_TH_MESH); + } + +const TCHAR * +_3DSExport::AuthorName() { // ASCII Author name + return GetString(IDS_TH_AUTHOR); + } + +const TCHAR * +_3DSExport::CopyrightMessage() { // ASCII Copyright message + return GetString(IDS_TH_COPYRIGHT_ECLIPSE); + } + +const TCHAR * +_3DSExport::OtherMessage1() { // Other message #1 + return _T(""); + } + +const TCHAR * +_3DSExport::OtherMessage2() { // Other message #2 + return _T(""); + } + +unsigned int +_3DSExport::Version() { // Version number * 100 (i.e. v3.01 = 301) + return 100; + } + +void +_3DSExport::ShowAbout(HWND hWnd) { // Optional + } + +#ifdef MAYBE +static BOOL CALLBACK +ExportOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { + static _3DSExport *exp; + + switch(message) { + case WM_INITDIALOG: + exp = (_3DSExport *)lParam; + return FALSE; + case WM_DESTROY: + return FALSE; + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hDlg, 1); + return TRUE; + case IDCANCEL: + EndDialog(hDlg, 0); + return TRUE; + } + } + return FALSE; + } +#endif // MAYBE + +#define OBTYPE_MESH 0 +#define OBTYPE_CAMERA 1 +#define OBTYPE_OMNILIGHT 2 +#define OBTYPE_SPOTLIGHT 3 +#define OBTYPE_DUMMY 5 +#define OBTYPE_CTARGET 6 +#define OBTYPE_LTARGET 7 +#define OBTYPE_BONE 8 + +class SceneEntry { + public: + TSTR name; + INode *node,*tnode; + Object *obj; + int type; // See above + int id; + SceneEntry *next; + SceneEntry(INode *n, Object *o, int t); + void SetID(int id) { this->id = id; } + }; + +SceneEntry::SceneEntry(INode *n, Object *o, int t) { + node = n; obj = o; type = t; next = NULL; + tnode = n->GetTarget(); + } + + +//- Material Export ------------------------------------------------------------- + +struct MEntry +{ + SMtl *sm; + Mtl *m; +}; + +class MeshMtlList: public Tab { + public: + void AddMtl(Mtl *m); + void ReallyAddMtl(Mtl *m); + int FindMtl(Mtl *m); + int FindSName(char *nam); + ~MeshMtlList() { + for (int i=0; iClassID()==Class_ID(MULTI_CLASS_ID,0))?1:0; + } + +int MeshMtlList::FindSName(char *name) { + for (int i=0; iname)==0) return i; + return -1; + } + +void MeshMtlList::AddMtl(Mtl *m) { + if (m==NULL) return; + Interval v; + m->Update(0,v); + if (IsStdMulti(m)) { + for (int i=0; iNumSubMtls(); i++) { + Mtl *sub = m->GetSubMtl(i); + if (sub&&FindMtl(sub)<0) + ReallyAddMtl(sub); + } + } + else { + if (FindMtl(m)<0) + ReallyAddMtl(m); + } + } + +inline Color_24 C24(Color c) { + Color_24 a; + a.r = (int)(255.0f*c.r); + a.g = (int)(255.0f*c.g); + a.b = (int)(255.0f*c.b); + return a; + } + +static int MAXMapIndex(int i) { + switch(i) { + case Ntex: return ID_DI; + case Ntex2: return ID_DI; + case Nopac: return ID_OP; + case Nbump: return ID_BU; + case Nspec: return ID_SP; + case Nshin: return ID_SH; + case Nselfi:return ID_SI; + case Nrefl: return ID_RL; + default: return ID_DI; + } + } + +int Pcnt(float f) { return (int)(f*100.0f+.5f); } + +static void ConvertMaxMtlToSMtl(SMtl *s, Mtl *m) { + Mapping *mp; + Interval v; + + + /*if (FullNameList==(char **)NULL) + { + FullNameList = (char **)malloc( sizeof(char *) * 2000); + memset(FullNameList,0,sizeof(char *) * 2000); + } + */ + FullNameListSize++; + + + + m->Update(0,v); + s->amb = C24(m->GetAmbient()); + s->diff = C24(m->GetDiffuse()); + s->spec = C24(m->GetSpecular()); + s->shading = 3; + s->shininess = Pcnt(m->GetShininess()); + s->shin2pct = Pcnt(m->GetShinStr()); + s->shin3pct = 0; + s->transparency = Pcnt(m->GetXParency()); + s->wiresize = m->WireSize(); + if (m->ClassID()==Class_ID(DMTL_CLASS_ID,0)) { + StdMat* std = (StdMat *)m; + switch(std->GetShading()) { + case SHADE_CONST: s->shading = 1; break; + case SHADE_PHONG: s->shading = 3; break; + case SHADE_METAL: s->shading = 4; break; + } + s->xpfall = Pcnt(std->GetOpacFalloff(0)); + s->selfipct = Pcnt(std->GetSelfIllum(0)); + if (std->GetTwoSided()) s->flags |= MF_TWOSIDE; + if (std->GetWire()) s->flags |= MF_WIRE; + if (!std->GetFalloffOut()) s->flags |= MF_XPFALLIN; + if (std->GetFaceMap()) s->flags |= MF_FACEMAP; + if (std->GetSoften()) s->flags |= MF_PHONGSOFT; + if (std->GetWireUnits()) s->flags |= MF_WIREABS; + switch (std->GetTransparencyType()) { + case TRANSP_FILTER: + case TRANSP_SUBTRACTIVE: break; + case TRANSP_ADDITIVE: s->flags |= MF_ADDITIVE; + } + + for (int i=0; i<8; i++) { + if (i==Ntex2) continue; + int n = MAXMapIndex(i); + Texmap *tx; + if ((tx=std->GetSubTexmap(n))==NULL) + continue; + if (i==Nrefl) { + if (tx->ClassID()==Class_ID(ACUBIC_CLASS_ID,0)) { + StdCubic *stdcub = (StdCubic*)tx; + s->map[i] = mp = NewMapping(i,0); + mp->amt.pct = Pcnt(std->GetTexmapAmt(n,0)); + mp->use = std->MapEnabled(n); + AutoCubicParams &ac = mp->map.p.ref.acb; + ac.flags=AC_ON; + if (!stdcub->GetDoNth()) ac.flags |= AC_FIRSTONLY; + ac.nth = stdcub->GetNth(); + ac.size = stdcub->GetSize(0); + continue; + } + else + if (tx->ClassID()==Class_ID(MIRROR_CLASS_ID,0)) { + StdMirror *stdmir = (StdMirror*)tx; + s->map[i] = mp = NewMapping(i,0); + mp->amt.pct = Pcnt(std->GetTexmapAmt(n,0)); + mp->use = std->MapEnabled(n); + AutoCubicParams &ac = mp->map.p.ref.acb; + if (!stdmir->GetDoNth()) ac.flags |= AC_FIRSTONLY; + ac.nth = stdmir->GetNth(); + ac.flags= AC_MIRROR|AC_ON; + continue; + } + } + // just do bitmap textures for now + if (tx->ClassID()!=Class_ID(BMTEX_CLASS_ID,0)) + continue; + BitmapTex *bmt = (BitmapTex*)tx; + s->map[i] = mp = NewMapping(i,0); + mp->amt.pct = Pcnt(std->GetTexmapAmt(n,0)); + if (i==Nbump) + mp->amt.pct = abs(mp->amt.pct)/100; + mp->use = std->MapEnabled(n); + TSTR filename; + SplitPathFile(TSTR(bmt->GetMapName()),NULL,&filename); + CStr name(filename); + + //MLS + FullNameList[FullNameListSize-1] = (char *)malloc(strlen(name.data())+1); + strcpy(FullNameList[FullNameListSize-1],name.data()); + + strncpy(mp->map.name,name.data(),12); + if (i==Nrefl) { + + } + else { + StdUVGen *uv = bmt->GetUVGen(); + MapParams &par = mp->map.p.tex; + par.type = MAP_TYPE_UV; + par.uoffset = uv->GetUOffs(0); + par.voffset = -uv->GetVOffs(0); + par.uscale = uv->GetUScl(0); + par.vscale = uv->GetVScl(0); + float ang = uv->GetAng(0); + par.ang_sin = -(float)sin(ang); + par.ang_cos = (float)cos(ang); + par.texblur = uv->GetBlur(0)-1.0f; + int tile = uv->GetTextureTiling(); + if (tile&(U_MIRROR|V_MIRROR)) + par.texflags|= TEX_MIRROR; + if (tile&(U_WRAP|V_WRAP)) + par.texflags &= ~TEX_NOWRAP; + else + par.texflags |= TEX_NOWRAP; + TextureOutput* texout = bmt->GetTexout(); + if (texout->GetInvert()) + par.texflags |= TEX_INVERT; + if (bmt->GetFilterType()==FILTER_SAT) + par.texflags |= TEX_SAT; + } + } + } + + } + +static void IncrName(char *name, char *inm, int n) { + char buf[20]; + strncpy(buf,name,13); + sprintf(inm,"%s%3d",buf,n); + } + +void MeshMtlList::ReallyAddMtl(Mtl *m) { + MEntry me; + me.sm = NULL; + me.m = m; + SMtl *s = new SMtl; + memset(s,0,sizeof(SMtl)); + me.sm = s; + char buf[20]; + strncpy(buf,me.m->GetName(),16); + if (strlen(buf)==0) strcpy(buf, "Matl"); + buf[16] = 0; + strcpy(s->name,buf); + int n=0; + while (FindSName(s->name)>=0) + IncrName(buf,s->name,++n); + ConvertMaxMtlToSMtl(s,m); + Append(1,&me,20); + } + +//-------------------------------------------------------------- + +class SceneEnumProc : public ITreeEnumProc { + public: + Interface *i; + SceneEntry *head; + SceneEntry *tail; + IScene *theScene; + int count; + MeshMtlList *mtlList; + TimeValue time; + SceneEnumProc(IScene *scene, TimeValue t, Interface *i, MeshMtlList *ml); + ~SceneEnumProc(); + int Count() { return count; } + void Append(INode *node, Object *obj, int type); + int callback( INode *node ); + Box3 Bound(); + SceneEntry *Find(INode *node); +// SceneEntry *operator[](int index); + void BuildNames(); + }; + +SceneEnumProc::SceneEnumProc(IScene *scene, TimeValue t, Interface *i, MeshMtlList *ml) { + time = t; + theScene = scene; + count = 0; + head = tail = NULL; + this->i = i; + mtlList = ml; + theScene->EnumTree(this); + } + +SceneEnumProc::~SceneEnumProc() { + while(head) { + SceneEntry *next = head->next; + delete head; + head = next; + } + head = tail = NULL; + count = 0; + } + +int SceneEnumProc::callback(INode *node) +{ + char line[1024]; + Object *obj = node->EvalWorldState(time).obj; + + strcpy(line, node->GetName()); + //if(strstr(line, "Bip") != NULL) + { + sprintf(line, "%08X %08X", obj->SuperClassID(), obj->ClassID()); +// MessageBox(NULL, line, node->GetName(), MB_OK); + } + + if( (obj->SuperClassID() == GEOMOBJECT_CLASS_ID) && + (obj->ClassID() == Class_ID(BIP_BONE_CLASS_ID, 0)) ) + { + Append(node, obj, OBTYPE_BONE); + return TREE_CONTINUE; + } + + if (obj->CanConvertToType(triObjectClassID)) + { + Append(node, obj, OBTYPE_MESH); + mtlList->AddMtl(node->GetMtl()); + return TREE_CONTINUE; + } + + if (node->IsTarget()) + { + INode* ln = node->GetLookatNode(); + if (ln) + { + Object *lobj = ln->EvalWorldState(time).obj; + switch(lobj->SuperClassID()) + { + case LIGHT_CLASS_ID: Append(node, obj, OBTYPE_LTARGET); break; + case CAMERA_CLASS_ID: Append(node, obj, OBTYPE_CTARGET); break; + } + } + return TREE_CONTINUE; + } + switch (obj->SuperClassID()) + { + case HELPER_CLASS_ID: + if ( obj->ClassID()==Class_ID(DUMMY_CLASS_ID,0)) + Append(node, obj, OBTYPE_DUMMY); + if(obj->ClassID() == Class_ID(BONE_CLASS_ID,0)) + Append(node, obj, OBTYPE_BONE); + break; + case LIGHT_CLASS_ID: + if (obj->ClassID()==Class_ID(OMNI_LIGHT_CLASS_ID,0)) + Append(node, obj, OBTYPE_OMNILIGHT); + else + if (obj->ClassID()==Class_ID(SPOT_LIGHT_CLASS_ID,0)) + Append(node, obj, OBTYPE_SPOTLIGHT); + //export DIR_LIGHT and FSPOT_LIGHT???? + break; + case CAMERA_CLASS_ID: + if (obj->ClassID()==Class_ID(LOOKAT_CAM_CLASS_ID,0)) + Append(node, obj, OBTYPE_CAMERA); + break; + } + return TREE_CONTINUE; // Keep on enumeratin'! +} + + +void SceneEnumProc::Append(INode *node, Object *obj, int type) { + SceneEntry *entry = new SceneEntry(node, obj, type); + + if(tail) + tail->next = entry; + tail = entry; + if(!head) + head = entry; + count++; + } + +Box3 SceneEnumProc::Bound() { + Box3 bound; + bound.Init(); + SceneEntry *e = head; + ViewExp *vpt = i->GetViewport(NULL); + while(e) { + Box3 bb; + e->obj->GetWorldBoundBox(time, e->node, vpt, bb); + bound += bb; + e = e->next; + } + return bound; + } + +SceneEntry *SceneEnumProc::Find(INode *node) { + SceneEntry *e = head; + while(e) { + if(e->node == node) + return e; + e = e->next; + } + return NULL; + } + + + +SceneEnumProc *theSceneEnum = NULL; +MeshMtlList *theMtls = NULL; + +// We need to maintain a list of the unique objects in the scene + +class ObjectEntry { + public: + TriObject *tri; + SceneEntry *entry; + ObjectEntry *next; + ObjectEntry(SceneEntry *e) { entry = e; next = NULL; tri = NULL; } + }; + +class ObjectList { + public: + ObjectEntry *head; + ObjectEntry *tail; + int count; + ObjectList(SceneEnumProc &scene); + ~ObjectList(); + int Count() { return count; } + void Append(SceneEntry *e); + ObjectEntry *Contains(Object *obj); + ObjectEntry *Contains(INode *node); + ObjectEntry *FindLookatNode(INode *node); + }; + +ObjectList::ObjectList(SceneEnumProc &scene) { + head = tail = NULL; + count = 0; + // Zip thru the object list and record all unique objects (Some may be used by more than one node) + int scount = scene.Count(); + for(SceneEntry *se = scene.head; se!=NULL; se = se->next) { + // can't multiple instance lights and cameras in 3DS + // so make them all unique--DS 4/6/96 + if ( (se->type!=OBTYPE_MESH)|| !Contains(se->obj)) + Append(se); + } + } + +ObjectList::~ObjectList() { + while(head) { + ObjectEntry *next = head->next; + delete head; + head = next; + } + head = tail = NULL; + count = 0; + } + +ObjectEntry *ObjectList::Contains(Object *obj) { + ObjectEntry *e; + for (e=head; e!=NULL; e = e->next) { + if(e->entry->obj == obj) + return e; + } + return NULL; + } + +class FindDepNodeEnum: public DependentEnumProc { + public: + ReferenceTarget *targ; + INode *depNode; + FindDepNodeEnum() { targ = NULL; depNode = NULL; } + // proc should return 1 when it wants enumeration to halt. + virtual int proc(ReferenceMaker *rmaker); + }; + +int FindDepNodeEnum::proc(ReferenceMaker *rmaker) { + if (rmaker->SuperClassID()!=BASENODE_CLASS_ID) return 0; + INode* node = (INode *)rmaker; + if (node->GetTarget()==targ) { + depNode = node; + return 1; + } + return 0; + } + +ObjectEntry *ObjectList::FindLookatNode(INode *node) { + FindDepNodeEnum finder; + ObjectEntry *e; + for (e=head; e!=NULL; e = e->next) { + finder.targ = node; + e->entry->node->EnumDependents(&finder); + if (finder.depNode) return e; + } + return NULL; + } + + +ObjectEntry *ObjectList::Contains(INode *node) { + ObjectEntry *e; + for (e=head; e!=NULL; e = e->next) { + if(e->entry->node == node) + return e; + } + return NULL; + } + +void ObjectList::Append(SceneEntry *e) { + ObjectEntry *entry = new ObjectEntry(e); + if(tail) + tail->next = entry; + tail = entry; + if(!head) + head = entry; + count++; + } + +ObjectList *theObjects = NULL; + +class ObjName { + public: + TSTR name; + ObjName *next; + ObjName(TSTR n) { name = n; next = NULL; } + }; + +class ObjNameList { + public: + ObjName *head; + ObjName *tail; + int count; + ObjNameList() { head = tail = NULL; count = 0; } + ~ObjNameList(); + int Count() { return count; } + int Contains(TSTR &n); + void Append(TSTR &n); + void MakeUnique(TSTR &n); + }; + +ObjNameList::~ObjNameList() { + while(head) { + ObjName *next = head->next; + delete head; + head = next; + } + head = tail = NULL; + count = 0; + } + +int ObjNameList::Contains(TSTR &n) { + ObjName *e = head; + int index = 0; + while(e) { + if(e->name == n) + return index; + e = e->next; + index++; + } + return -1; + } + +void ObjNameList::Append(TSTR &n) { + ObjName *entry = new ObjName(n); + if(tail) + tail->next = entry; + tail = entry; + if(!head) + head = entry; + count++; + } + +void ObjNameList::MakeUnique(TSTR &n) { + // First make it less than 10 chars. + if (n.Length()>10) n.Resize(10); + + if(Contains(n) < 0) { + Append(n); + return; + } + // Make it unique and keep it 10 chars or less + for(int i = 0; i < 100000; ++i) { + char buf[12]; + sprintf(buf,"%d",i); + TSTR num(buf); + TSTR work = n; + int totlen = num.Length() + work.Length(); + if(totlen > 10) + work.Resize(10 - (totlen - 10)); + work = work + num; + if(Contains(work) < 0) { + Append(work); + n = work; + return; + } + } + // Forget it! + } + +ObjNameList theObjNames; +Tab mtlNumMap; +int mtlnum; +BOOL multiMtl; + + +// RB: +// Here's what I've done to handle names. After the scene has been +// traversed but before it is actually written to disk, I make +// a unique <10 character name for evey node name. This name is +// then used in place of the node name. +void SceneEnumProc::BuildNames() + { + ObjNameList nameList; + SceneEntry *ptr = head; + + while (ptr) { +// if (ptr->node->IsTarget()) { +// ptr->name = _T(""); +// } +// else { + ptr->name = ptr->node->GetName(); + nameList.MakeUnique(ptr->name); +// } + ptr = ptr->next; + } + } + + + +typedef struct { + Matrix3 *tm; + Mesh *mesh; + INode *node; + } MeshAndTMAndNode; + +static short wrapFlags; + +/* Main routine for writing a mesh file! */ +/* Recursive chunk writer -- keeps track of each chunk */ + +int +dump_mchunk(USHORT tag,FILE *stream,void *data) { + USHORT count,temp; + int ox,ix; + int *intptr; + long chunkptr,chunkbase,curpos,chunksize,lval; + SceneEntry *se = (SceneEntry *)data; + Interval valid; + Color_f *cf; + ObjectEntry *oe; + INode *node; + Object *obj; + Mesh *m; + +// DebugPrint(_T("dump_mchunk: tag = %X\n"),tag); + + chunkbase=ftell(stream); + WRTERR(&tag,2); + chunkptr=ftell(stream); /* Save file ptr for chunk size */ + WRTERR(&chunkptr,4); + switch(tag) + { + case MMAGIC: /* Mesh editor */ + if(dump_mchunk(MESH_VERSION,stream,NULL)==0) + return(0); + +#ifdef EXPORT_MTLS + // Save out the Materials... + for (ix=0; ix<(*theMtls).Count(); ix++) { + savemtl= (*theMtls)[ix].sm; + if(dump_mtlchunk(MAT_ENTRY,stream,NULL)==0) + return(0); + } +#endif + if(dump_mchunk(MASTER_SCALE,stream,NULL)==0) + return(0); + +// if(dump_mchunk(O_CONSTS,stream,&const_x)==0) +// return(0); +// if(dump_mchunk(AMBIENT_LIGHT,stream,NULL)==0) +// return(0); +// if(dump_mchunk(DISTANCE_CUE,stream,NULL)==0) +// return(0); +// if(ENVFLAG==FOG) { +// if(dump_mchunk(USE_FOG,stream,NULL)==0) +// return(0); +// } +// else +// if(ENVFLAG==DISTANCE_CUE) { +// if(dump_mchunk(USE_DISTANCE_CUE,stream,NULL)==0) +// return(0); +// } +// else +// if(ENVFLAG==LAYER_FOG) { +// if(dump_mchunk(USE_LAYER_FOG,stream,NULL)==0) +// return(0); +// } +// if(default_view!=CAMERA && default_view!=SPOTLIGHT) { +// if(dump_mchunk(DEFAULT_VIEW,stream,NULL)==0) +// return(0); +// } + for(ox = 0,oe = theObjects->head; oe != NULL; oe = oe->next,ox++) { + int type = oe->entry->type; + if (type!=OBTYPE_DUMMY&&type!=OBTYPE_LTARGET&&type!=OBTYPE_CTARGET) { + if (type==OBTYPE_MESH) { + obj = oe->entry->obj; + oe->tri = (TriObject *)obj->ConvertToType(theSceneEnum->i->GetTime(), triObjectClassID); + Mesh &mesh = oe->tri->mesh; + if (mesh.numFaces>65530||mesh.numVerts>65530) { + TCHAR buf[80]; + _stprintf(buf,GetString(IDS_OBJ_TOO_LARGE),oe->entry->name); + MessageBox(GetActiveWindow(), buf, GetString(IDS_EXPORT_ERROR), MB_OK); + continue; + } + } + + int status = dump_mchunk(NAMED_OBJECT,stream,oe); + if(!status) + return 0; + } + } +// if (MSHappdata!=NULL) +// if(dump_mchunk(APP_DATA,stream,MSHappdata)==0) +// return(0); + break; + case MESH_VERSION: + lval=0x00000003; /* Current version Number */ + WRTERR(&lval,4); + break; + case LIN_COLOR_F: + case COLOR_F: + cf=(Color_f *)data; + WRTERR(cf,12); + break; + case MASTER_SCALE: { + int type; + float scale; + GetMasterUnitInfo(&type, &scale); + float msc_factor = (float)GetMasterScale(type); + WRTERR(&msc_factor,sizeof(float)); + } + break; +// case SOLID_BGND: +// if (P.gamma_correct) { +// Color gamcol; +// disp_gammify(&gamcol, &BG.bkgd_solid); +// if(dump_mchunk(COLOR_F,stream,&gamcol)==0) return(0); +// if(dump_mchunk(LIN_COLOR_F,stream,&BG.bkgd_solid)==0) return(0); +// } +// else +// if(dump_mchunk(COLOR_F,stream,&BG.bkgd_solid)==0) return(0); +// break; + case RAY_BIAS: /* Simple floats */ + case LO_SHADOW_BIAS: /* Simple floats */ + case SHADOW_FILTER: + case DL_OUTER_RANGE: + case DL_INNER_RANGE: + case DL_MULTIPLIER: + WRTERR(data,sizeof(float)); + break; + case SHADOW_SAMPLES: /* Simple ints, written as shorts */ + case SHADOW_RANGE: + case SHADOW_MAP_SIZE: + intptr=(int *)data; + temp=(USHORT) *intptr; + WRTERR(&temp,2); + break; +// case BIT_MAP: +// string=(char *)data; +// split_fn(NULL,gp_buffer,string); +// WRTERR(gp_buffer,strlen(gp_buffer)+1); +// break; + + /* Simple strings */ + +// case DL_EXCLUDE: +// case VIEW_CAMERA: +// string=(char *)data; +// WRTERR(string,strlen(string)+1); +// break; +// case O_CONSTS: +// WRTERR(data,sizeof(float)*3); +// break; +// case AMBIENT_LIGHT: +// unload_ambient_light(0); +// if(dump_mchunk(COLOR_F,stream,&BG.amb_light)==0) +// return(0); +// break; + case NAMED_OBJECT: { + oe=(ObjectEntry *)data; + node = oe->entry->node; + //CStr name(node->GetName()); + CStr name(oe->entry->name); // RB + if(name.Length()>10) + name.Resize(10); + WRTERR(name.data(),(size_t)(name.Length()+1)); + switch(oe->entry->type) { + case OBTYPE_MESH: + if(dump_mchunk(N_TRI_OBJECT,stream,oe)==0) + return(0); + break; + case OBTYPE_CAMERA: + if(dump_mchunk(N_CAMERA,stream,oe)==0) + return(0); + break; + case OBTYPE_OMNILIGHT: + if(dump_mchunk(N_DIRECT_LIGHT,stream,oe)==0) + return(0); + break; + case OBTYPE_SPOTLIGHT: + if(dump_mchunk(N_DIRECT_LIGHT,stream,oe)==0) + return(0); + break; + default: + assert(0); + break; + } +// if(n->flags & NO_HIDDEN) { +// if(dump_mchunk(OBJ_HIDDEN,stream,n)==0) +// return(0); +// } +// if(n->flags & NO_DOESNT_CAST) { +// if(dump_mchunk(OBJ_DOESNT_CAST,stream,n)==0) +// return(0); +// } +// if(n->flags & NO_MATTE) { +// if(dump_mchunk(OBJ_MATTE,stream,n)==0) +// return(0); +// } +// if(n->flags & NO_DONT_RCVSHADOW) { +// if(dump_mchunk(OBJ_DONT_RCVSHADOW,stream,n)==0) +// return(0); +// } +// if(n->flags & NO_FAST) { +// if(dump_mchunk(OBJ_FAST,stream,n)==0) +// return(0); +// } +// if(n->flags & NO_FROZEN) { +// if(dump_mchunk(OBJ_FROZEN,stream,n)==0) +// return(0); +// } + } + break; + case OBJ_HIDDEN: /* Special null chunk */ +// case OBJ_VIS_LOFTER: /* Special null chunk */ + case OBJ_DOESNT_CAST: /* Special null chunk */ + case OBJ_DONT_RCVSHADOW: /* Special null chunk */ + case OBJ_MATTE: /* Special null chunk */ +// case OBJ_PROCEDURAL: /* Special null chunk */ + case OBJ_FAST: /* Special null chunk */ + case OBJ_FROZEN: /* Special null chunk */ + break; + case APP_DATA: { + ULONG *plong = (ULONG *)data; + WRTERR(&plong[1],plong[0]); + } + break; + case N_TRI_OBJECT: { + oe = (ObjectEntry *)data; + node = oe->entry->node; + Matrix3 ident(1), mat = node->GetNodeTM(theSceneEnum->time); + + // RB: For some reason this fixes a problem where + // the pivot gets screwed up if the object is at + // the origin. ???!!! + Point3 pos = mat.GetRow(3); + if (pos.x==0.0f && pos.y==0.0f && pos.z==0.0f) { + pos.x = 0.001f; + pos.y = 0.001f; + pos.z = 0.001f; + mat.SetTrans(pos); + } + + obj = oe->entry->obj; + Mesh &mesh = oe->tri->mesh; + MeshAndTMAndNode mt; + mt.tm = &mat; + mt.mesh = &mesh; + mt.node = node; + + // RB 6/11/96: This is kindof a hack, but if the node has + // WSMs applied then it will already be transformed into + // world space and so it doesn't need to be transformed again. + if (node->GetProperty(PROPID_HAS_WSM)) { + mt.tm = &ident; + } + +// if( (t->flags & TRI_HAS_PROCDATA) && t->proc_data!=NULL) { +// if(dump_mchunk(PROC_DATA,stream,t)==0) +// return(0); +// } +// if(strlen(t->proc_name)>0) { +// if(dump_mchunk(PROC_NAME,stream,t)==0) +// return(0); +// } + if(mesh.getNumVerts()) { + if(dump_mchunk(POINT_ARRAY,stream,&mt)==0) { + error: + // Delete the working object, if necessary + if(obj != (Object *)(oe->tri)) { + oe->tri->DeleteThis(); + oe->tri = NULL; + } + return(0); + } + if (mesh.numTVerts>0 && mesh.tvFace && mesh.tVerts) { + if(dump_mchunk(TEX_VERTS,stream, oe)==0) + goto error; +// if(dump_mchunk(MESH_TEXTURE_INFO,stream,t)==0) +// goto error; + } +// if(dump_mchunk(POINT_FLAG_ARRAY,stream,t)==0) +// return(0); + + if(dump_mchunk(MESH_MATRIX,stream,mat.GetAddr())==0) + goto error; +// if(dump_mchunk(MESH_COLOR,stream,t)==0) +// return(0); + } + if(mesh.getNumFaces()) { + if(dump_mchunk(FACE_ARRAY,stream,&mt)==0) + goto error; + } +// if(t->appdata!=NULL) { +// if(dump_mchunk(APP_DATA,stream,t->appdata)==0) +// return(0); +// } + // Delete the working object, if necessary + if(obj != (Object *)(oe->tri)) { + oe->tri->DeleteThis(); + oe->tri = NULL; + } + } + break; + case POINT_ARRAY: { + MeshAndTMAndNode *mt = (MeshAndTMAndNode *)data; + count=mt->mesh->getNumVerts(); + WRTERR(&count,2); + for(ix=0; ixmesh->verts[ix] * *mt->tm; + WRTERR(&v[0],sizeof(float)); + WRTERR(&v[1],sizeof(float)); + WRTERR(&v[2],sizeof(float)); + } + } + break; + + case TEX_VERTS: { + oe = (ObjectEntry *)data; + Mesh &mesh = oe->tri->mesh; + int nverts = mesh.getNumVerts(); + if (nverts>65535) + nverts = 65535; + Point2 *tv = new Point2[nverts]; + wrapFlags = Get3DSTVerts(mesh,tv); + UWORD nv = (UWORD)nverts; + WRTERR(&nv,2); + for(ix=0; ixmaptype; +// Mapinfo.tile_x=t->tile_x; +// Mapinfo.tile_y=t->tile_y; +// Mapinfo.map_x=t->map_x; +// Mapinfo.map_y=t->map_y; +// Mapinfo.map_z=t->map_z; +// Mapinfo.map_scale=t->map_scale; +// memcpy(Mapinfo.map_matrix,t->map_matrix,sizeof(float)*12); +// Mapinfo.map_pw=t->map_pw; +// Mapinfo.map_ph=t->map_ph; +// Mapinfo.map_ch=t->map_ch; +// WRTERR(&Mapinfo,sizeof(Mapinfo)); +// break; +// case POINT_FLAG_ARRAY: +// t=(Tri_obj *)data; +// count=t->verts; +// WRTERR(&count,2); +// for(ix=0; ixverts; ++ix) { +// get_vert(t,ix,&v); +// WRTERR(&v.flags,sizeof(short)); +// } +// break; + case MESH_MATRIX: + WRTERR(data,sizeof(float)*12); + break; +// case MESH_COLOR: +// t=(Tri_obj *)data; +// WRTERR(&t->color,sizeof(uchar)); +// break; + case FACE_ARRAY: { + MeshAndTMAndNode *mt = (MeshAndTMAndNode*)data; + m = mt->mesh; + count=m->getNumFaces(); + WRTERR(&count,2); + BOOL anySmooth = FALSE; + for(ix=0; ixfaces[ix]; + if(f.smGroup) + anySmooth = TRUE; + Fc_wrt.a=(unsigned short)f.v[0]; + Fc_wrt.b=(unsigned short)f.v[1]; + Fc_wrt.c=(unsigned short)f.v[2]; + Fc_wrt.flags = wrapFlags; // TEX_VERTS + if(f.flags & EDGE_A) Fc_wrt.flags |= ABLINE; + if(f.flags & EDGE_B) Fc_wrt.flags |= BCLINE; + if(f.flags & EDGE_C) Fc_wrt.flags |= CALINE; + WRTERR(&Fc_wrt,8); + } +#ifdef EXPORT_MTLS + Mtl *mtl; + if (NULL!=(mtl=mt->node->GetMtl())) { + if (IsStdMulti(mtl)) { + multiMtl = TRUE; + // make a table that maps sub-mtl number to the proper index + // into theMtls. + mtlNumMap.SetCount(mtl->NumSubMtls()); + for (int i=0; iNumSubMtls(); i++) { + Mtl *sub = mtl->GetSubMtl(i); + if (sub) mtlNumMap[i] = theMtls->FindMtl(sub); + else mtlNumMap[i] = 0; + } + for (i=0; iNumSubMtls(); i++) { + Mtl *sub = mtl->GetSubMtl(i); + if (sub) { + mtlnum = mtlNumMap[i]; + if (dump_mchunk(MSH_MAT_GROUP,stream,mt)==0) + return 0; + } + } + } + else { + mtlnum = theMtls->FindMtl(mtl); + multiMtl = FALSE; + if (dump_mchunk(MSH_MAT_GROUP,stream,mt)==0) + return 0; + } + } +#endif + + /* Save smoothing groups if any */ + + if(anySmooth) { + if(dump_mchunk(SMOOTH_GROUP,stream,m)==0) + return(0); + } +// if (t->flags&TRI_BOX_MAP) +// if(dump_mchunk(MSH_BOXMAP,stream,t)==0) +// return(0); + } + break; +// case MSH_BOXMAP: { +// int i; +// for (i=0; i<6; i++) { +// if (t->boxmtl[i]==255) +// WRTERR(sdefault,8); +// else { +// if (!mtl_pointer(t->boxmtl[i],&mtl)) +// return(0); +// WRTERR(mtl->name,strlen(mtl->name)+1); +// } +// } +// } +// break; +#ifdef EXPORT_MTLS + case MSH_MAT_GROUP: + { + MeshAndTMAndNode *mt = (MeshAndTMAndNode*)data; + m = mt->mesh; + SMtl *mtl; + short temp; + assert(mtlnum>=0 && mtlnumCount()); + mtl = (*theMtls)[mtlnum].sm; + assert(mtl); + + if (multiMtl) { + count = 0; + for (ix=0; ixnumFaces; ix++) { + int mtlIndex = mtlNumMap[m->getFaceMtlIndex(ix)]; + if (mtlIndex==mtlnum) + count++; + } + } + else + count = m->numFaces; + + WRTERR(mtl->name,strlen(mtl->name)+1); + temp = (short)count; + WRTERR(&temp,2); + + if (multiMtl) { + for(ix=0; ixnumFaces; ++ix) { + int mtlIndex = mtlNumMap[m->getFaceMtlIndex(ix)]; + if (mtlIndex==mtlnum) { + temp = (short)ix; + WRTERR(&temp,2); + if(--count==0) + break; + } + } + } + else { + for(ix=0; ixnumFaces; ++ix) { + temp = (short)ix; + WRTERR(&temp,2); + } + } + } + break; +#endif + case SMOOTH_GROUP: + m=(Mesh *)data; + + /* Now dump all object faces' smoothing group flags */ + count = m->getNumFaces(); + for(ix=0; ixfaces[ix]; + WRTERR(&f.smGroup,4); + } + break; + case N_DIRECT_LIGHT:{ + oe = (ObjectEntry *)data; + node = oe->entry->node; + obj = oe->entry->obj; + LightObject *lt= (LightObject *)obj; + GenLight *gl = (GenLight *)obj; + LightState ls; + lt->EvalLightState(theSceneEnum->time, valid, &ls); + Matrix3 mat = node->GetNodeTM(theSceneEnum->time); + Point3 pos = mat.GetRow(3); + WRTERR(&pos.x,sizeof(float)); + WRTERR(&pos.y,sizeof(float)); + WRTERR(&pos.z,sizeof(float)); + if(dump_mchunk(COLOR_F,stream,&ls.color)==0) + return(0); + if(dump_mchunk(DL_OUTER_RANGE,stream,&ls.attenEnd)==0) + return(0); + if(dump_mchunk(DL_INNER_RANGE,stream,&ls.attenStart)==0) + return(0); + if(dump_mchunk(DL_MULTIPLIER,stream,&ls.intens)==0) + return(0); +#if 0 + if(d->exclude) { + Object_list *o=d->exclude; + while(o) { + if(dump_mchunk(DL_EXCLUDE,stream,o->name)==0) + return(0); + o=o->next; + } + } +#endif + if (oe->entry->type==OBTYPE_SPOTLIGHT) { + if(dump_mchunk(DL_SPOTLIGHT,stream,data)==0) + return(0); + } + if (!ls.on) { + if(dump_mchunk(DL_OFF,stream,data)==0) + return(0); + } + if(ls.useAtten) { + if(dump_mchunk(DL_ATTENUATE,stream,data)==0) + return(0); + } +// if(d->appdata!=NULL) { +// if(dump_mchunk(APP_DATA,stream,d->appdata)==0) +// return(0); +// } + } + break; + case DL_SPOTLIGHT: { + oe = (ObjectEntry *)data; + INode *tnode = oe->entry->tnode; + obj = oe->entry->obj; + LightObject *lt= (LightObject *)obj; + GenLight *gl = (GenLight *)obj; + LightState ls; + lt->EvalLightState(theSceneEnum->time, valid, &ls); + Matrix3 mat = tnode->GetNodeTM(theSceneEnum->time); + Point3 pos = mat.GetRow(3); + WRTERR(&pos.x,sizeof(float)); + WRTERR(&pos.y,sizeof(float)); + WRTERR(&pos.z,sizeof(float)); + WRTERR(&ls.hotsize,sizeof(float)); + WRTERR(&ls.fallsize,sizeof(float)); + if(dump_mchunk(DL_SPOT_ROLL,stream,data)==0) + return(0); + if(ls.shadow) { + if(dump_mchunk(DL_SHADOWED,stream,NULL)==0) + return(0); + } + if(!gl->GetUseGlobal()) { + if(dump_mchunk(DL_LOCAL_SHADOW2,stream,gl)==0) + return(0); + } + if(gl->GetConeDisplay()) { + if(dump_mchunk(DL_SEE_CONE,stream,NULL)==0) + return(0); + } +// if(d->flags & NO_LT_PROJ) { +// if(dump_mchunk(DL_SPOT_PROJECTOR,stream,d)==0) +// return(0); +// } + if(gl->GetSpotShape()==RECT_LIGHT) { + if(dump_mchunk(DL_SPOT_RECTANGULAR,stream,NULL)==0) + return(0); + if(dump_mchunk(DL_SPOT_ASPECT,stream,gl)==0) + return(0); + } + if(ls.overshoot) { + if(dump_mchunk(DL_SPOT_OVERSHOOT,stream,NULL)==0) + return(0); + } + if (dump_mchunk(DL_RAY_BIAS,stream,gl)==0) + return(0); + if (gl->GetShadowType()) { + if(dump_mchunk(DL_RAYSHAD,stream,data)==0) + return(0); + } + } + break; + case DL_OFF: /* Special null chunk */ + case DL_ATTENUATE: /* Special null chunk */ + case DL_SHADOWED: /* Special null chunk */ + + break; + + case DL_SPOT_ROLL:{ + oe = (ObjectEntry *)data; + INode *node = oe->entry->node; + Control *tmCont = node->GetTMController(); + Control *rollCont = tmCont->GetRollController(); + float v; + rollCont->GetValue(0,&v,valid); + WRTERR(&v,sizeof(float)); + break; + } + + case DL_SPOT_ASPECT: { + GenLight *gl = (GenLight *)data; + float f = gl->GetAspect(0); + WRTERR(&f,sizeof(float)); + break; + } + case DL_RAY_BIAS:{ + GenLight *gl = (GenLight *)data; + float f = gl->GetRayBias(0); + WRTERR(&f,sizeof(float)); + break; + } + case PROC_NAME: /* external procedure name */ +// t=(Tri_obj *)data; +// WRTERR(t->proc_name,strlen(t->proc_name)+1); + break; + case PROC_DATA: /* external procedure data chunk */ +// t=(Tri_obj *)data; +// { +// ULONG *plong = (ULONG *)t->proc_data; +// WRTERR(&plong[1],plong[0]); +// } + break; + case DL_LOCAL_SHADOW2: + { + GenLight *gl = (GenLight *)data; + LocShad2 locshad; + locshad.bias = gl->GetMapBias(0); + locshad.shadsize = gl->GetMapSize(0); + locshad.shadfilter = gl->GetMapRange(0); + WRTERR(&locshad,sizeof(LocShad2)); + } + break; + case N_CAMERA: { + oe = (ObjectEntry *)data; + node = oe->entry->node; + CameraObject* camobj = (CameraObject *)oe->entry->obj; + GenCamera *gc = (GenCamera*)oe->entry->obj; + CameraState cs; + camobj->EvalCameraState(theSceneEnum->time, valid, &cs); + Camera3DS c; + Matrix3 mat = node->GetNodeTM(theSceneEnum->time); + Point3 pos = mat.GetRow(3); + c.x = pos.x; + c.y = pos.y; + c.z = pos.z; + if (oe->entry->tnode) { + mat = oe->entry->tnode->GetNodeTM(theSceneEnum->time); + pos = mat.GetRow(3); + } + c.tx = pos.x; + c.ty = pos.y; + c.tz = pos.z; + c.bank = 0.0f; + c.focal = 2400.0f/RadToDeg(cs.fov); + c.flags = 0; + c.nearplane = gc->GetClipDist(0,0); + c.farplane = gc->GetClipDist(0,1); + WRTERR(&c,32); +// if(c->flags & NO_CAM_CONE) { +// if(dump_mchunk(CAM_SEE_CONE,stream,NULL)==0) +// return(0); +// } + if(dump_mchunk(CAM_RANGES,stream,gc)==0) + return(0); +// if(c->appdata!=NULL) { +// if(dump_mchunk(APP_DATA,stream,c->appdata)==0) +// return(0); +// } + } + break; + case CAM_RANGES:{ + GenCamera *gc = (GenCamera *)data; + float cnear = gc->GetEnvRange(0,0); + float cfar = gc->GetEnvRange(0,1); + WRTERR(&cnear,sizeof(float)); + WRTERR(&cfar,sizeof(float)); + } + break; +// case DL_SPOT_PROJECTOR: +// d=(Dirlight *)data; +// WRTERR(d->imgfile,13); +// break; + + /* Dummy chunks -- no data, just their tag */ + + case RAY_SHADOWS: + case USE_BIT_MAP: + case USE_SOLID_BGND: + case USE_V_GRADIENT: + case USE_FOG: + case USE_DISTANCE_CUE: + case USE_LAYER_FOG: + case FOG_BGND: + case DCUE_BGND: + case CAM_SEE_CONE: + case DL_SEE_CONE: + case DL_SPOT_OVERSHOOT: + case DL_SPOT_RECTANGULAR: + case DL_RAYSHAD: + case DUMMY: + break; + default: // Unknown chunk! + assert(0); + break; + } + + /* Save file ptr */ + + curpos=ftell(stream); + + /* Point back to chunk size location */ + + fseek(stream,chunkptr,SEEK_SET); + + /* Calc & write chunk size */ + + chunksize=curpos-chunkbase; + WRTERR(&chunksize,4); + + /* Point back to file end */ + + fseek(stream,curpos,SEEK_SET); + return(1); + } + + +#define WRITEF(ptr,size) fwrite((char *)ptr,1,size,wstream) +#define WERR(ptr,sz) {if (WRITEF(ptr,(sz))!=(sz)) return(0);} +#define WRFLOAT(ptr) WERR(ptr,sizeof(FLOAT)) +#define WR3FLOAT(ptr) WERR(ptr,3*sizeof(FLOAT)) +#define WRLONG(ptr) WERR(ptr,sizeof(LONG)) +#define WRSHORT(ptr) WERR(ptr,sizeof(SHORT)) +#define WRSTRING(ptr) WERR(ptr,strlen(ptr)+1) + +#define EPS (1.0e-7) +#define NotZero(f) (f<-EPS || f>EPS) + +static FILE *wstream; + +int WriteStd1KeyHdr() { + short trackflags = 0; + WRSHORT(&trackflags); + long lwork = 0; + WRLONG(&lwork); // Track min + WRLONG(&lwork); // Track max + long nkeys = 1; + WRLONG(&nkeys); + long keytime = 0; + WRLONG(&keytime); + short wflags = 0; // Ignoring tension, continuity, bias, eases + WRSHORT(&wflags); + return 1; + } + + +static BOOL IsTCBContol(Control *cont) + { + return ( + cont->ClassID()==Class_ID(TCBINTERP_FLOAT_CLASS_ID,0) || + cont->ClassID()==Class_ID(TCBINTERP_POSITION_CLASS_ID,0) || + cont->ClassID()==Class_ID(TCBINTERP_ROTATION_CLASS_ID,0) || + cont->ClassID()==Class_ID(TCBINTERP_POINT3_CLASS_ID,0) || + cont->ClassID()==Class_ID(TCBINTERP_SCALE_CLASS_ID,0)); + } + +static BOOL WriteControllerChunk(Control *cont,int type, float scale=1.0f) + { + ITCBFloatKey fkey; + ITCBPoint3Key pkey; + ITCBRotKey rkey; + ITCBScaleKey skey; + ITCBKey *k; + int num = cont->NumKeys(); + float fval; + Point3 pval; + Quat q, qLast = IdentQuat(); + AngAxis rval; + ScaleValue sval; + Interval valid; + TimeValue t; + + // Set up 'k' to point at the right derived class + switch (type) { + case KEY_FLOAT: k = &fkey; break; + case KEY_POS: k = &pkey; break; + case KEY_ROT: k = &rkey; break; + case KEY_SCL: k = &skey; break; + case KEY_COLOR: k = &pkey; break; + default: return FALSE; + } + + // Get the keyframe interface + IKeyControl *ikeys = GetKeyControlInterface(cont); + + // Gotta have some keys + if (num==NOT_KEYFRAMEABLE || num==0) { + return FALSE; + } + + // Write track some stuff + short trackflags = 0; + WRSHORT(&trackflags); + long lwork = cont->GetKeyTime(0)/GetTicksPerFrame(); + WRLONG(&lwork); // Track min + lwork = cont->GetKeyTime(num-1)/GetTicksPerFrame(); + WRLONG(&lwork); // Track max + long nkeys = num; + WRLONG(&nkeys); + + for (int i=0; iGetKey(i,k); + + + // Write key time + long keytime = k->time/GetTicksPerFrame(); + WRLONG(&keytime); + + // Write flags + short wflags = 0; + if (k->tens != 0.0f) wflags |= W_TENS; + if (k->cont != 0.0f) wflags |= W_CONT; + if (k->bias != 0.0f) wflags |= W_BIAS; + if (k->easeIn != 0.0f) wflags |= W_EASETO; + if (k->easeOut!= 0.0f) wflags |= W_EASEFROM; + WRSHORT(&wflags); + + // Write TCB and ease + if (k->tens != 0.0f) WRFLOAT(&k->tens); + if (k->cont != 0.0f) WRFLOAT(&k->cont); + if (k->bias != 0.0f) WRFLOAT(&k->bias); + if (k->easeIn != 0.0f) WRFLOAT(&k->easeIn); + if (k->easeOut!= 0.0f) WRFLOAT(&k->easeOut); + + // Write values + switch (type) { + case KEY_FLOAT: + fkey.val*=scale; + WRFLOAT(&fkey.val); + break; + + case KEY_SCL: + WRFLOAT(&skey.val.s.x); + WRFLOAT(&skey.val.s.y); + WRFLOAT(&skey.val.s.z); + break; + + case KEY_COLOR: + case KEY_POS: + WRFLOAT(&pkey.val.x); + WRFLOAT(&pkey.val.y); + WRFLOAT(&pkey.val.z); + break; + + case KEY_ROT: + WRFLOAT(&rkey.val.angle); + WRFLOAT(&rkey.val.axis.x); + WRFLOAT(&rkey.val.axis.y); + WRFLOAT(&rkey.val.axis.z); + break; + } + + } else { + // Sample the control at each key time + t = cont->GetKeyTime(i); + + // Write key time + long keytime = t/GetTicksPerFrame(); + WRLONG(&keytime); + + // Write flags + short wflags = 0; + WRSHORT(&wflags); + + // Write values + switch (type) { + case KEY_FLOAT: + cont->GetValue(t,&fval,valid); + fval*=scale; + WRFLOAT(&fval); + break; + + case KEY_SCL: + cont->GetValue(t,&sval,valid); + WRFLOAT(&sval.s.x); + WRFLOAT(&sval.s.y); + WRFLOAT(&sval.s.z); + break; + + case KEY_COLOR: + case KEY_POS: + cont->GetValue(t,&pval,valid); + WRFLOAT(&pval.x); + WRFLOAT(&pval.y); + WRFLOAT(&pval.z); + break; + + case KEY_ROT: + cont->GetValue(t,&q,valid); + rval = AngAxis(q/qLast); qLast = q; + WRFLOAT(&rval.angle); + WRFLOAT(&rval.axis.x); + WRFLOAT(&rval.axis.y); + WRFLOAT(&rval.axis.z); + break; + } + } + } + return TRUE; + } + + + +static int WriteFloatTrack(Control *c, float scale) { + Interval valid; + if (!WriteControllerChunk(c,KEY_FLOAT,scale)) { + float v; + c->GetValue(0,&v,valid); + v *= scale; + if (!WriteStd1KeyHdr()) return 0; + WRFLOAT(&v); + } + return 1; + } + +static int WriteFloatTrackOrStd1KeyHdr(Control *c, float scale) { + if (c) { + if (!WriteFloatTrack(c, scale)) return 0; + } + else { + if (!WriteStd1KeyHdr()) return 0; + WRFLOAT(&floatVal); + } + return 1; + } + +int KFWriteChunk(unsigned short tag, void *data); + +int dump_kchunk(unsigned short tag, FILE *stream, void *data) { + wstream = stream; + return(KFWriteChunk(tag,data)); + } + +// RB 4-4-96: see comment by OBJECT_NODE_TAG +static BOOL savingLiteralData = FALSE; + +int KFWriteChunk(unsigned short tag, void *data) { + long chunkptr,chunkbase,curpos,chunksize; + Interval valid; + INode *node; + SHORT version = KFVERSION; + Object *ob; + + chunkbase = ftell(wstream); +#ifdef DBGKFB + if(dbgio) { + printf("\n------>Writing chunk type: "); + kfprint_ID(tag); + printf(" Chunkbase = %lx, tag = %5x.\n",chunkbase,tag); + } +#endif + + WRSHORT(&tag); + chunkptr = ftell(wstream); + + WRLONG(&chunkptr); + + switch(tag) { + case KFDATA: + { + /* Keyframe main chunk */ + int nodeid; + if (!KFWriteChunk(KFHDR,data)) return(0); + if (!KFWriteChunk(KFSEG,data)) return(0); + if (!KFWriteChunk(KFCURTIME,data)) return(0); + + nodeid=0; + for (SceneEntry *se = theSceneEnum->head; se!=NULL; se = se->next) { + switch (se->type) { + case OBTYPE_DUMMY: + case OBTYPE_MESH: + se->id = nodeid++; + if (!KFWriteChunk(OBJECT_NODE_TAG,se)) return(0); + break; + case OBTYPE_OMNILIGHT: + se->id = nodeid++; + if (!KFWriteChunk(LIGHT_NODE_TAG,se))return(0); + break; + case OBTYPE_SPOTLIGHT: + se->id = nodeid++; + if (!KFWriteChunk(SPOTLIGHT_NODE_TAG,se)) return(0); + break; + case OBTYPE_LTARGET: + se->id = nodeid++; + if (!KFWriteChunk(L_TARGET_NODE_TAG,se)) return(0); + break; + case OBTYPE_CTARGET: + se->id = nodeid++; + if (!KFWriteChunk(TARGET_NODE_TAG,se)) return(0); + break; + case OBTYPE_CAMERA: + se->id = nodeid++; + if (!KFWriteChunk(CAMERA_NODE_TAG,se))return(0); + break; +// case TARGET_NODE: +// { +// Namedobj *ob = node->object; +// node->id = nodeid++; +// switch(ob->type) { +// case N_CAMERA: +// if (!KFWriteChunk(TARGET_NODE_TAG,node)) +// return(0); +// break; +// case N_DIRECT_LIGHT: +// if (!KFWriteChunk(L_TARGET_NODE_TAG,node)) +// return(0); +// break; +// } +// } +// break; +// case OBTYPE_SPOTLIGHT: +// node->id = nodeid++; +// if (!KFWriteChunk(LIGHT_NODE_TAG,node))return(0); +// break; +// case SPOTLIGHT_NODE: +// node->id = nodeid++; +// if (!KFWriteChunk(SPOTLIGHT_NODE_TAG,node))return(0); +// break; + } + } +// /* Do new kinds of nodes later, so 3DS2.0 doesn't get screwed up*/ +// for (i=0; itype) { +// case AMBIENT_NODE: +// node->id = -1; +// if (!KFWriteChunk(AMBIENT_NODE_TAG,node))return(0); +// break; +// } +// } +// if (KFappdata!=NULL) +// if (!KFWriteChunk(APP_DATA,KFappdata)) return(0); + } + break; + case KFHDR: { + WRSHORT(&version); + WRSTRING("MAXSCENE"); + long animLength = theSceneEnum->i->GetAnimRange().End()/GetTicksPerFrame(); + /* + char Temp[50]; + sprintf(Temp, "AnimRange: %lu", animLength); + MessageBox(NULL, Temp, "John's Message", MB_OK); + theSceneEnum->i->SetAnimRange(Interval(0,animLength)); + //SetAnimEnd(50); + */ + + WRLONG(&animLength); +#ifdef DBGKFB + if (dbgio) + printf("version = %d, mshName = %s, P.animLength = %d \n", + version, mshName, P.animLength); +#endif + } + break; + case KFSEG: { + Interval i = theSceneEnum->i->GetAnimRange(); + long s = i.Start()/GetTicksPerFrame(); + long e = i.End()/GetTicksPerFrame(); + WRLONG(&s); + WRLONG(&e); + } + break; + case KFCURTIME: { + long t = theSceneEnum->i->GetTime(); + WRLONG(&t); + } + break; + case PIVOT: { + Point3 pivot = -((SceneEntry *)data)->node->GetObjOffsetPos(); + WR3FLOAT(&pivot[0]); + } + break; + case BOUNDBOX: { + Box3 bb; + ViewExp *vpt = theSceneEnum->i->GetViewport(NULL); + SceneEntry *se = (SceneEntry *)data; + se->obj->GetLocalBoundBox(theSceneEnum->i->GetTime(), se->node, vpt, bb); + WR3FLOAT(&bb.pmin[0]); + WR3FLOAT(&bb.pmax[0]); + } + break; + case INSTANCE_NAME: { + CStr *name = (CStr *)data; + if(name->Length()>10) + name->Resize(10); + WERR(name->data(),(size_t)(name->Length()+1)); + } + break; +// case MORPH_SMOOTH: { +// ObjectNode *onode = (ObjectNode *)data; +// WRFLOAT(&onode->smooth_ang); +// } +// break; + case NODE_ID: { + SceneEntry *se = (SceneEntry *)data; +#ifdef DBGKFB + if (dbgio) + printf(" writing NODE_ID =%d \n", nd->id); +#endif + WRSHORT(&se->id); + } + break; + case NODE_HDR: { + SceneEntry *se = (SceneEntry *)data; + BOOL isInstance = FALSE; + node = se->node; + ob = se->obj; + // Write out the primary name -- It's the name of the first node using the object. + // We do this to work with 3DS's system where a primary node uses an object and + // shares its name, and all other instances use this name as a primary name with + // a dot (.) followed by the instance name. + if (se->type == OBTYPE_DUMMY) { + WRSTRING("$$$DUMMY"); + } + else if (se->type == OBTYPE_CTARGET||se->type == OBTYPE_LTARGET) { + // The object name written should be the same as that of the associated + // light or camera. + //INode *lan = se->node->GetLookatNode(); + //ObjectEntry *oe = theObjects->Contains(lan); + ObjectEntry *oe = theObjects->FindLookatNode(se->node); + assert(oe); + CStr name(oe->entry->name); + if(name.Length()>10) + name.Resize(10); + WERR(name.data(),(size_t)(name.Length()+1)); + } + else { + TSTR name; + + // for cameras, lights, which can't be multiple instanced in 3DS + // just get name from scene entry -- DS 4/6/96 + if (se->type != OBTYPE_MESH) { + name = se->name; + } + else { + // search for the object entry + ObjectEntry *oe = theObjects->Contains(ob); + assert(oe); + name = oe->entry->name; // RB + // If the name is not equal to the master name then + // it is an instance. + if (!(oe->entry->name==se->name)) + isInstance = TRUE; + } + + if(name.Length()>10) + name.Resize(10); +//DebugPrint("Making %s unique\n",CStr(name)); +// theObjNames.MakeUnique(name); +//DebugPrint("Got %s\n",CStr(name)); + CStr cname(name); // Make it char* + WERR(cname.data(),(size_t)(cname.Length()+1)); + } + short zero = 0; + short fl = (short) (isInstance ? 0 : PRIMARY_NODE); + WRSHORT(&fl); // Node flags + WRSHORT(&zero); // flags 2 + INode *parentNode = node->GetParentNode(); + SceneEntry *pse = theSceneEnum->Find(parentNode); +#ifdef DBGKFB + if (dbgio) + printf("nparent = %X \n", nparent); +#endif + if(pse) { + WRSHORT(&pse->id); + } + else{ + short none = (short)NO_PARENT; + WRSHORT(&none); + } + } + break; +// case APP_DATA: +// { +// ULONG *plong = (ULONG *)data; +// WERR(&plong[1],plong[0]); +// } +// break; + case OBJECT_NODE_TAG: { + SceneEntry *se = (SceneEntry *)data; + ob = se->obj; + if (!KFWriteChunk(NODE_ID,se)) return(0); + if (!KFWriteChunk(NODE_HDR,se)) return(0); +// if (on->appdata) if (!KFWriteChunk(APP_DATA,on->appdata)) return(0); + if (!KFWriteChunk(PIVOT,se)) return(0); + //TSTR name(se->node->GetName()); + TSTR name(se->name); // RB + // MAX doesn't have the notion of instance names, but 3DS does -- we must use the name + // of the original object as the node name, and this node's name as the instance name. + // We don't write an instance name if the instance name is the same as the master object's + // name. + ObjectEntry *oe = theObjects->Contains(ob); + assert(oe); + //TSTR mname(oe->entry->node->GetName()); // Master name + TSTR mname(oe->entry->name); // Master name + if (se->type!=OBTYPE_CTARGET&&se->type!=OBTYPE_LTARGET) { + if (se->type==OBTYPE_DUMMY || !(mname == name)) { + CStr wname(name); + if (!KFWriteChunk(INSTANCE_NAME,&wname)) return(0); + } + } + /* if (!KFWriteChunk(PRESCALE,data) return(0); */ + + + // RB 4-4-96: There was a problem when the transform controller didn't + // support GetController() for pos/rot/scale. 3DS would crash + // on load when these tracks weren't present. + // So... we'll only write out controller data if controllers + // are present otherwise we'll use the old method. + // I have to set a global variable to indicate if the data pointer + // is pointing to a controller or the actual value. + Control *cpos = se->node->GetTMController()->GetPositionController(); + Control *crot = se->node->GetTMController()->GetRotationController(); + Control *cscl = se->node->GetTMController()->GetScaleController(); + if (cpos && crot && cscl) { + // Write keyframe data if possible + savingLiteralData = FALSE; + if (!KFWriteChunk(POS_TRACK_TAG, cpos)) return(0); + if (!KFWriteChunk(ROT_TRACK_TAG, crot)) return(0); + if (!KFWriteChunk(SCL_TRACK_TAG, cscl)) return(0); + + } else { + // The old way + Matrix3 tm = se->node->GetObjectTM(theSceneEnum->i->GetTime()); + Matrix3 ptm = se->node->GetParentNode()->GetNodeTM(theSceneEnum->i->GetTime()); + tm = tm * Inverse(ptm); + Point3 pos; + Quat q; + Point3 scl; + DecomposeMatrix(tm, pos, q, scl); // Break it down into components + + savingLiteralData = TRUE; + if (!KFWriteChunk(POS_TRACK_TAG, &pos)) return(0); + if (!KFWriteChunk(ROT_TRACK_TAG, &q)) return(0); + if (!KFWriteChunk(SCL_TRACK_TAG, &scl)) return(0); + savingLiteralData = FALSE; + } + + +// if (on->mtrack.keytab) +// if (!KFWriteChunk(MORPH_TRACK_TAG, &on->mtrack)) return(0); +// if (on->htrack.keytab) +// if (!KFWriteChunk(HIDE_TRACK_TAG, &on->htrack)) return(0); + if (se->type==OBTYPE_DUMMY) { /* dummy Node */ + if (!KFWriteChunk(BOUNDBOX, data)) return(0); + } +// if (!KFWriteChunk(MORPH_SMOOTH, data)) return(0); + } + break; + case CAMERA_NODE_TAG: { + SceneEntry *se = (SceneEntry *)data; + GenCamera *ob = (GenCamera *)se->obj; + if (!KFWriteChunk(NODE_ID,se)) return(0); + if (!KFWriteChunk(NODE_HDR,se)) return(0); +// if (cn->appdata) if (!KFWriteChunk(APP_DATA,cn->appdata)) return(0); + Control *c; + + c = se->node->GetTMController()->GetPositionController(); + if (c) if (!KFWriteChunk(POS_TRACK_TAG, c)) return(0); + + floatVal = RadToDeg(ob->GetFOV(0)); + c = ob->GetFOVControl(); + if (!KFWriteChunk(FOV_TRACK_TAG, c)) return(0); + + Control* tmc = se->node->GetTMController(); + c = tmc->GetRollController(); + if (c) if (!KFWriteChunk(ROLL_TRACK_TAG, c)) return(0); + } + break; + case L_TARGET_NODE_TAG: + case TARGET_NODE_TAG:{ + SceneEntry *se = (SceneEntry *)data; + if (!KFWriteChunk(NODE_ID,se)) return(0); + if (!KFWriteChunk(NODE_HDR,se)) return(0); +// if (tn->appdata) if (!KFWriteChunk(APP_DATA,tn->appdata)) return(0); + Control *c; + c = se->node->GetTMController()->GetPositionController(); + if (c) if (!KFWriteChunk(POS_TRACK_TAG, c)) return(0); + } + break; + case LIGHT_NODE_TAG: { + SceneEntry *se = (SceneEntry *)data; + GenLight* ob = (GenLight *)se->obj; + if (!KFWriteChunk(NODE_ID,se)) return(0); + if (!KFWriteChunk(NODE_HDR,se)) return(0); +// if (ln->appdata) if (!KFWriteChunk(APP_DATA,ln->appdata)) return(0); + Control *c; + + colorVal = ob->GetRGBColor(0); + c = ob->GetColorControl(); + if (!KFWriteChunk(COL_TRACK_TAG, c)) return(0); + + c = se->node->GetTMController()->GetPositionController(); + if (c) if (!KFWriteChunk(POS_TRACK_TAG, c)) return(0); + } + break; + + case SPOTLIGHT_NODE_TAG: { + SceneEntry *se = (SceneEntry *)data; + GenLight* ob = (GenLight *)se->obj; + if (!KFWriteChunk(NODE_ID,se)) return(0); + if (!KFWriteChunk(NODE_HDR,se)) return(0); + Control *c; + c = se->node->GetTMController()->GetPositionController(); + if (c) if (!KFWriteChunk(POS_TRACK_TAG, c)) return(0); + +// if (sln->appdata) if (!KFWriteChunk(APP_DATA,sln->appdata)) return(0); + + colorVal = ob->GetRGBColor(0); + c = ob->GetColorControl(); + if (!KFWriteChunk(COL_TRACK_TAG, c)) return(0); + + floatVal = ob->GetHotspot(0); + c = ob->GetHotSpotControl(); + if (!KFWriteChunk(HOT_TRACK_TAG, c)) return(0); + + floatVal = ob->GetFallsize(0); + c = ob->GetFalloffControl(); + if (!KFWriteChunk(FALL_TRACK_TAG, c)) return(0); + + Control* tmc = se->node->GetTMController(); + c = tmc->GetRollController(); + if (!KFWriteChunk(ROLL_TRACK_TAG, c)) return(0); + } + break; +// case AMBIENT_NODE_TAG: +// AmbientNode *an = (AmbientNode *)data; +// if (!KFWriteChunk(NODE_ID,an)) return(0); +// if (!KFWriteChunk(NODE_HDR,an)) return(0); +// if (an->appdata) if (!KFWriteChunk(APP_DATA,an->appdata)) return(0); +// if (!KFWriteChunk(COL_TRACK_TAG, &an->coltrack)) return(0); +// break; + case SCL_TRACK_TAG: { + if (!savingLiteralData) { + Control *c = (Control*)data; + if (!WriteControllerChunk(c,KEY_SCL)) { + ScaleValue pos; + c->GetValue(0,&pos,valid); + if (!WriteStd1KeyHdr()) return 0; + WRFLOAT(&pos.s.x); + WRFLOAT(&pos.s.y); + WRFLOAT(&pos.s.z); + } + } else { + Point3 *p = (Point3*)data; + if (!WriteStd1KeyHdr()) return 0; + WRFLOAT(&p->x); + WRFLOAT(&p->y); + WRFLOAT(&p->z); + } + } + break; + + case POS_TRACK_TAG: { + if (!savingLiteralData) { + Control *c = (Control*)data; + if (!WriteControllerChunk(c,KEY_POS)) { + Point3 pos; + c->GetValue(0,&pos,valid); + if (!WriteStd1KeyHdr()) return 0; + WRFLOAT(&pos.x); + WRFLOAT(&pos.y); + WRFLOAT(&pos.z); + } + } else { + Point3 *p = (Point3*)data; + if (!WriteStd1KeyHdr()) return 0; + WRFLOAT(&p->x); + WRFLOAT(&p->y); + WRFLOAT(&p->z); + } + } + break; + + case ROT_TRACK_TAG: { + if (!savingLiteralData) { + Control *c = (Control*)data; + if (!WriteControllerChunk(c,KEY_ROT)) { + Quat rot; + c->GetValue(0,&rot,valid); + float angle; + Point3 axis; + AngAxisFromQ(rot,&angle,axis); + if (!WriteStd1KeyHdr()) return 0; + WRFLOAT(&angle); + WRFLOAT(&axis.x); + WRFLOAT(&axis.y); + WRFLOAT(&axis.z); + } + } else { + Quat *q = (Quat*)data; + float angle; + Point3 axis; + AngAxisFromQ(*q,&angle,axis); + if (!WriteStd1KeyHdr()) return 0; + WRFLOAT(&angle); + WRFLOAT(&axis.x); + WRFLOAT(&axis.y); + WRFLOAT(&axis.z); + } + } + break; + case FOV_TRACK_TAG: + if (!WriteFloatTrackOrStd1KeyHdr((Control *)data, RAD_TO_DEG)) + return 0; + break; + case FALL_TRACK_TAG: + case HOT_TRACK_TAG: + if (!WriteFloatTrackOrStd1KeyHdr((Control *)data,1.0f)) + return 0; + break; + case ROLL_TRACK_TAG: + if (!WriteFloatTrackOrStd1KeyHdr((Control *)data, -RAD_TO_DEG)) + return 0; + break; + case COL_TRACK_TAG: { + Control *c = (Control*)data; + if (!c||!WriteControllerChunk(c,KEY_COLOR)) { + Point3 pos; + if (c) c->GetValue(0,&pos,valid); + else pos = colorVal; + if (!WriteStd1KeyHdr()) return 0; + WRFLOAT(&pos.x); + WRFLOAT(&pos.y); + WRFLOAT(&pos.z); + } + } + break; + case HIDE_TRACK_TAG: + case MORPH_TRACK_TAG: + if (!WriteFloatTrackOrStd1KeyHdr((Control *)data, 1.0f)) + return 0; + break; + default: + assert(0); + break; + } + + /* Save file ptr */ + curpos=ftell(wstream); + + /* Point back to chunk size location */ + fseek(wstream,chunkptr,SEEK_SET); + + /* Calc & write chunk size */ + chunksize=curpos-chunkbase; +#ifdef DBGKFB + if (dbgio) { + printf("writing chunkptr = %lx, chunkSize = %ld \n",chunkptr,chunksize); + } +#endif + + WERR(&chunksize,4); + + /* Point back to file end */ + + fseek(wstream,curpos,SEEK_SET); + return(1); + } + + + +/* Main routine for writing MSH+KFB! */ +/* Recursive chunk writer -- keeps track of each chunk */ + +int dump_3dchunk(USHORT tag,FILE *stream,void *data) { + long chunkptr,chunkbase,curpos,chunksize,lval; + chunkbase=ftell(stream); + WRTERR(&tag,2); + chunkptr=ftell(stream); /* Save file ptr for chunk size */ + WRTERR(&chunkptr,4); + switch(tag) { + case M3DMAGIC: /* Mesh editor */ + if(dump_3dchunk(M3D_VERSION,stream,NULL)==0) + return(0); + if (dump_mchunk(MMAGIC,stream,NULL)==0) + return(0); + if(dump_kchunk(KFDATA,stream,NULL)==0) + return(0); + break; + case M3D_VERSION: + lval= 3; + WRTERR(&lval,4); + break; + } + /* Save file ptr */ + curpos=ftell(stream); + + /* Point back to chunk size location */ + fseek(stream,chunkptr,SEEK_SET); + + /* Calc & write chunk size */ + + chunksize=curpos-chunkbase; + WRTERR(&chunksize,4); + + /* Point back to file end */ + fseek(stream,curpos,SEEK_SET); + return(1); + } + +class NullView: public View { + public: + Point2 ViewToScreen(Point3 p) { return Point2(p.x,p.y); } + NullView() { worldToView.IdentityMatrix(); screenW=640.0f; screenH = 480.0f; } + }; + +#ifndef USE_MAX1SDK +Modifier* FindPhysiqueModifier(INode* nodePtr) +{ + // Get object from node. Abort if no object. + Object* ObjectPtr = nodePtr->GetObjectRef(); + if(ObjectPtr == NULL) + { + return NULL; + } + // Is derived object ? + if (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID) + { + // Yes -> Cast. + IDerivedObject* DerivedObjectPtr = static_cast(ObjectPtr); + // Iterate over all entries of the modifier stack. + int ModStackIndex = 0; + while (ModStackIndex < DerivedObjectPtr->NumModifiers()) + { + // Get current modifier. + Modifier* ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex); + // Is this Physique ? + if (ModifierPtr->ClassID() == Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B)) + { + // Yes -> Exit. + return ModifierPtr; + } + // Next modifier stack entry. + ModStackIndex++; + } + } + // Not found. + return NULL; +} +#endif + +short wSignificantFrame1 = 1; +short wSignificantFrame2 = 1; +short wSignificantFrame3 = 1; +int nOneOfEveryFrame = 1; +short AnimLength = 0; +short wActualAnimLength = 0; +short wAnimStart = 0; +short wAnimEnd = 0; +Point3 vGroundPointA, vGroundPointB, vGroundPointC; + +void ConstructGroundPlane(void) +{ + Point3 v; + + // Plane equation: Ax + By + Cz + D = 0 + // Calculate ground plane by setting vGroundPointA to the plane's normal + // and leaving vGroundPointC as the point on the plane. vGroundPointB.x + // holds the D coefficient. vGroundPointA holds coefficients A, B, & C. + v = vGroundPointC - vGroundPointA; + vGroundPointB -= vGroundPointA; + vGroundPointA = vGroundPointB ^ v; // cross product + vGroundPointB.x = -DotProd(vGroundPointA, vGroundPointC); +} + +float GetGroundZAtPoint(Point3 &v) +{ + float numer; + + if(vGroundPointA.z == 0.0f) + { + assert(0 && "Screwball ground plane"); + return(0.0f); + } + + numer = vGroundPointA.x * v.x + vGroundPointA.y * v.y + vGroundPointB.x; + numer /= -vGroundPointA.z; + + return(numer); +} + +BOOL CALLBACK ExportOptionsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + { + HWND hWnd; + char text[10]; + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT1); + itoa(nOneOfEveryFrame, text, 10); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT2); + itoa(wSignificantFrame1, text, 10); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT6); + itoa(wSignificantFrame2, text, 10); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT7); + itoa(wSignificantFrame3, text, 10); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT3); + itoa(AnimLength, text, 10); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT4); + itoa(wAnimStart, text, 10); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT5); + itoa(wAnimEnd, text, 10); + SetWindowText(hWnd, text); + + // vGroundPointA + hWnd = GetDlgItem(hwndDlg, IDC_EDIT8); + sprintf(text, "%f", vGroundPointA.x); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT9); + sprintf(text, "%f", vGroundPointA.y); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT10); + sprintf(text, "%f", vGroundPointA.z); + SetWindowText(hWnd, text); + + // vGroundPointB + hWnd = GetDlgItem(hwndDlg, IDC_EDIT11); + sprintf(text, "%f", vGroundPointB.x); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT12); + sprintf(text, "%f", vGroundPointB.y); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT13); + sprintf(text, "%f", vGroundPointB.z); + SetWindowText(hWnd, text); + + // vGroundPointC + hWnd = GetDlgItem(hwndDlg, IDC_EDIT14); + sprintf(text, "%f", vGroundPointC.x); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT15); + sprintf(text, "%f", vGroundPointC.y); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT16); + sprintf(text, "%f", vGroundPointC.z); + SetWindowText(hWnd, text); + + hWnd = GetDlgItem(hwndDlg, IDOK); + SetFocus(hWnd); + + return(TRUE); + } + break; + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDOK: + { + HWND hWnd; + char text[10]; + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT1); + GetWindowText(hWnd, text, 10); + nOneOfEveryFrame = atoi(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT2); + GetWindowText(hWnd, text, 10); + wSignificantFrame1 = (unsigned short)atoi(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT6); + GetWindowText(hWnd, text, 10); + wSignificantFrame2 = (unsigned short)atoi(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT7); + GetWindowText(hWnd, text, 10); + wSignificantFrame3 = (unsigned short)atoi(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT4); + GetWindowText(hWnd, text, 10); + wAnimStart = (unsigned short)atoi(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT5); + GetWindowText(hWnd, text, 10); + wAnimEnd = (unsigned short)atoi(text); + + // vGroundPointA + hWnd = GetDlgItem(hwndDlg, IDC_EDIT8); + GetWindowText(hWnd, text, 10); + vGroundPointA.x = (float)atof(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT9); + GetWindowText(hWnd, text, 10); + vGroundPointA.y = (float)atof(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT10); + GetWindowText(hWnd, text, 10); + vGroundPointA.z = (float)atof(text); + + // vGroundPointB + hWnd = GetDlgItem(hwndDlg, IDC_EDIT11); + GetWindowText(hWnd, text, 10); + vGroundPointB.x = (float)atof(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT12); + GetWindowText(hWnd, text, 10); + vGroundPointB.y = (float)atof(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT13); + GetWindowText(hWnd, text, 10); + vGroundPointB.z = (float)atof(text); + + // vGroundPointC + hWnd = GetDlgItem(hwndDlg, IDC_EDIT14); + GetWindowText(hWnd, text, 10); + vGroundPointC.x = (float)atof(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT15); + GetWindowText(hWnd, text, 10); + vGroundPointC.y = (float)atof(text); + + hWnd = GetDlgItem(hwndDlg, IDC_EDIT16); + GetWindowText(hWnd, text, 10); + vGroundPointC.z = (float)atof(text); + + EndDialog(hwndDlg, IDOK); + + return(FALSE); + } + break; + + case IDCANCEL: + + EndDialog(hwndDlg, IDCANCEL); + return(FALSE); + } + return(TRUE); + } + break; + } + return(FALSE); +} + +void WriteBoneHierarchy(FILE* f, INode* node) +{ + int NumKids, i; + + fprintf(f, "the %s bone\n", node->GetName()); + + NumKids = node->NumberOfChildren(); + + for(i=0;iGetChildNode(i); + Object* obj = child->EvalWorldState(0).obj; + if( (obj->ClassID() == Class_ID(BONE_CLASS_ID,0)) || + (obj->ClassID() == Class_ID(BIP_BONE_CLASS_ID, 0)) ) + { + fprintf(f, "the %s bone is connected to ", node->GetName()); + WriteBoneHierarchy(f, child); + } + } +} + +#define _3DSMAX_TICKS_PER_SECOND 4800 + +void Matrix3fprint(FILE* f, const Matrix3& m) +{ + Point3 p; + + p = m.GetRow(0); + fprintf(f, "%f, %f, %f,\n", p.x, p.y, p.z); + + p = m.GetRow(1); + fprintf(f, "%f, %f, %f,\n", p.x, p.y, p.z); + + p = m.GetRow(2); + fprintf(f, "%f, %f, %f,\n", p.x, p.y, p.z); + + p = m.GetRow(3); + fprintf(f, "%f, %f, %f,\n", p.x, p.y, p.z); +} + +void CalculateVertexNormal(Mesh* mesh, Matrix3& tm, DWORD dwVertex, DWORD dwGroup, Point3* pResultNormal) +{ + int NumVerts = mesh->getNumVerts(); + int NumFaces = mesh->getNumFaces(); + int j; + + //------------------------------------------------------------------- + // Calculate Vertex normals + + static Point3 ZeroPoint(0.0f, 0.0f, 0.0f); + Point3 ThisNormal; + Point3 Normal(0.0f, 0.0f, 0.0f);; + Point3 A, B, v; + + // Average the normals for all common faces in the same smoothing group + int nNumNormals = 0; + + Normal = ZeroPoint; + for(j=0;jfaces[j].getSmGroup() == dwGroup) + { + if( (mesh->faces[j].getVert(0) == (DWORD)dwVertex) || + (mesh->faces[j].getVert(1) == (DWORD)dwVertex) || + (mesh->faces[j].getVert(2) == (DWORD)dwVertex) ) + { + A = tm * mesh->verts[mesh->faces[j].getVert(2)]; + B = tm * mesh->verts[mesh->faces[j].getVert(0)]; + v = tm * mesh->verts[mesh->faces[j].getVert(1)]; + A -= v; + B -= v; + ThisNormal = A ^ B; // cross product + + Normal += ThisNormal; + nNumNormals++; + } + } + } + if(nNumNormals == 0) + { + // found an instance where there was a vertex that was not + // attached to any face. very strange. + MessageBox(NULL, "Zero Normals", "Big Hairy Problem", MB_OK); + } + else + { + Normal /= (float)nNumNormals; + Normal = Normalize(Normal); + } + + *pResultNormal = Normal; +} + +int KEYExport(const TCHAR *filename, BOOL suppressPrompts) +{ + FILE *f; + + int FramesPerSecond = GetFrameRate(); + int TicksPerFrame = GetTicksPerFrame(); + int FirstTick = theSceneEnum->i->GetAnimRange().Start(); + int LastTick = theSceneEnum->i->GetAnimRange().End(); + + Point3 v; + Matrix3 tm; + + f = fopen(filename, "wt"); + if (!f) + { + Alert(IDS_TH_CANTCREATE); + return(0); + } + + // Write signature and version + fprintf(f, "KEYEXP %s\n", ExportVersion); + + INode *node; + ObjectEntry *Current; + + //----------------------------------------------------------------------- + // Count bones and report + + int NumBones = 0; + Current = theObjects->head; + while(Current) + { + if(Current->entry->type != OBTYPE_BONE) + { + Current = Current->next; + continue; + } + + NumBones++; + + Current = Current->next; + } + + fprintf(f, "Number of Bones = %d\n", NumBones); + + //----------------------------------------------------------------------- + // Write out necessary data for motion keys + + fprintf(f, "Key Data\n"); + + TimeValue t; + Quat qq; + Point3 tp, sp; + INode* parent; + Matrix3 tmp; + + fprintf(f, "%d %d %d\n", FirstTick / TicksPerFrame, LastTick / TicksPerFrame, FramesPerSecond); + + Current = theObjects->head; + while(Current) + { + if(Current->entry->type != OBTYPE_BONE) + { + Current = Current->next; + continue; + } + + Matrix3 tm; + + node = Current->entry->node; + + fprintf(f, "Node: %s\n", node->GetName()); + + // Print notetrack info + { + int NumNT, n, i, j, NumNotes; + NoteTrack* pNT; + DefNoteTrack* pDNT; + NoteKey* pNK; + + NumNT = node->NumNoteTracks(); + + // count all of the notes on all of the notetracks + NumNotes = 0; + for(n=0;nGetNoteTrack(n); + if(pNT->ClassID() == Class_ID(NOTETRACK_CLASS_ID, 0)) + { + pDNT = (DefNoteTrack*)pNT; + j = pDNT->NumKeys(); + for(i=0;ikeys[i]; + if( (pNK->time >= FirstTick) && (pNK->time <= LastTick) ) + NumNotes++; + } + } + } + + fprintf(f, "Number of Notes = %d\n", NumNotes); + + for(n=0;nGetNoteTrack(n); + if(pNT->ClassID() == Class_ID(NOTETRACK_CLASS_ID, 0)) + { + pDNT = (DefNoteTrack*)pNT; + j = pDNT->NumKeys(); + for(i=0;ikeys[i]; + if( (pNK->time >= FirstTick) && (pNK->time <= LastTick) ) + fprintf(f, "%d: %s\n", (pNK->time - FirstTick) / TicksPerFrame, pNK->note); + } + } + } + } + + for(t=FirstTick;t<=LastTick;t+=TicksPerFrame) + { + tm = node->GetNodeTM(t); + DecomposeMatrix(tm, tp, qq, sp); + qq.MakeMatrix(tm); + tm.SetTrans(tp); + + parent = node->GetParentNode(); + if(parent) + { + tmp = parent->GetNodeTM(t); + DecomposeMatrix(tmp, tp, qq, sp); + qq.MakeMatrix(tmp); + tmp.SetTrans(tp); + tmp = Inverse(tmp); + tm *= tmp; + } + + Matrix3fprint(f, tm); + } + + Current = Current->next; + } + + fprintf(f, "Key Data Complete\n"); + + fclose (f); + + return 1; +} + +int NFOExport(const TCHAR *filename, BOOL suppressPrompts) +{ + FILE *f; + long i, j, k; + + FullNameListSize = 0; + // This is the time when all samples are taken + int FirstFrame = theSceneEnum->i->GetAnimRange().Start(); + + int NumFaces, NumTVerts, NumVerts; + Point3 v; + Matrix3 tm; + unsigned short NumNodes = 0; + + f = fopen(filename, "wt"); + if (!f) + { + Alert(IDS_TH_CANTCREATE); + return(0); + } + + // Write signature and version + fprintf(f, "NFO %s\n", ExportVersion); + + INode *node; + ObjectEntry *Current; + ObjectState os; + Mesh *mesh; + BOOL needDel; + NullView View; + + // Write out number of materials + unsigned short NumMaterials = (*theMtls).Count(); + fprintf(f, "Material List\n"); + fprintf(f, "Number of Materials = %d\n", NumMaterials); + + unsigned char r=0,g=0,b=0; + // Write out all materials + for (i=0; i< NumMaterials; i++) + { + // first char will be null if no texmap name + if((*theMtls)[i].sm->map[0]) + { + fprintf(f, "(MAP) %s: %s\n", (*theMtls)[i].sm->name, + //(*theMtls)[i].sm->map[0]->map.name); + FullNameList[i]); + free(FullNameList[i]); + } + else + { + fprintf(f, "(RGB) %s: %d %d %d\n", (*theMtls)[i].sm->name, + (int)(*theMtls)[i].sm->amb.r, + (int)(*theMtls)[i].sm->amb.g, + (int)(*theMtls)[i].sm->amb.b); + } + } + + //if (FullNameList!=NULL) + // free(FullNameList); + FullNameListSize = 0; + // Now, count all bones + int NumBones = 0; + Current = theObjects->head; + while(Current) + { + if(Current->entry->type == OBTYPE_BONE) + NumBones++; + Current = Current->next; + } + +/* + // Write out bone hierarchy + fprintf(f, "Searching for root bone\n"); + Current = theObjects->head; + while(Current) + { + if (Current->entry->type != OBTYPE_BONE) + { + Current = Current->next; + continue; + } + + if(Current->entry->node->GetParentNode()->IsRootNode() != 0) + { + // Found one! + fprintf(f, "It's the root!\n"); + break; + } + + Current = Current->next; + } + + if(Current != NULL) + { + fprintf(f, "Bone Hierarchy from the root: "); + WriteBoneHierarchy(f, Current->entry->node); + } +*/ + struct BoneID + { + char Name[300]; + int ParentID; + }; + + // Copy out names + BoneID* pBones = new BoneID[NumBones]; + Current = theObjects->head; + i = 0; + while(Current) + { + if (Current->entry->type != OBTYPE_BONE) + { + Current = Current->next; + continue; + } + + strncpy(pBones[i].Name, Current->entry->node->GetName(), 299); + pBones[i].Name[299] = 0; // safety net + + for(k=0;kentry->node->GetParentNode()->GetName()) == 0) + { + pBones[i].ParentID = k; + break; + } + } + if(k == i) + pBones[i].ParentID = -1; // BODY_NO_PARENT_BONE; (see body.h) + + Current = Current->next; + i++; + } + + fprintf(f, "Bone List\n"); + fprintf(f, "Number of Bones = %d\n", NumBones); + for(i=0;ihead; + while(Current) + { + if (Current->entry->type != OBTYPE_DUMMY) + { + Current = Current->next; + continue; + } + + node = Current->entry->node; + if (!node) + { + Current = Current->next; + continue; + } + + if(strcmp(node->GetName(), "Dummy BoundingBox") == 0) + { + // found it! + DummyObject* pDO; + Box3 box; + Point3 min, max; + Matrix3 m; + Point3 p; + + pDO = (DummyObject*)Current->entry->obj; + assert(pDO != NULL); + box = pDO->GetBox(); + min = box.Min(); + max = box.Max(); + + m = node->GetNodeTM(FirstFrame); + p *= 0.0f; // zero the point + p = m * p; // get box's position + + min += p; + max += p; + + fprintf(f, "Bounding Box\n"); + fprintf(f, "%f %f %f\n", min.x, min.y, min.z); + fprintf(f, "%f %f %f\n", max.x, max.y, max.z); + } + + Current = Current->next; + } +*/ + // count number of nodes + NumNodes = 0; + Current = theObjects->head; + while(Current) + { + node = Current->entry->node; + if (!node) + { + Current = Current->next; + continue; + } + + Current = Current->next; + NumNodes++; + } + + // write out bone matrices + fprintf(f, "Node Transform Matrix List\n"); + fprintf(f, "Number of Nodes = %d\n", NumNodes); + + int NodeN = 0; + Current = theObjects->head; + while(Current) + { + node = Current->entry->node; + if (!node) + { + Current = Current->next; + continue; + } + + fprintf(f, "Node(%d): %s\n", NodeN, node->GetName()); + + Matrix3 mp; + Point3 tp, sp; + Quat qq; + + //fprintf(f, "GetNodeTM(%d)\n", FirstFrame); + mp = node->GetNodeTM(FirstFrame); + Matrix3fprint(f, mp); + DecomposeMatrix(mp, tp, qq, sp); + fprintf(f, "Q(w,x,y,z): %f %f %f %f\n", qq.w, qq.x, qq.y, qq.z); + fprintf(f, "S(x,y,z): %f %f %f\n", sp.x, sp.y, sp.z); + fprintf(f, "T(x,y,z): %f %f %f\n", tp.x, tp.y, tp.z); + + Current = Current->next; + NodeN++; + } + + // Look for bounding box dummy nodes + Current = theObjects->head; + while(Current) + { + if (Current->entry->type != OBTYPE_DUMMY) + { + Current = Current->next; + continue; + } + + node = Current->entry->node; + if (!node) + { + Current = Current->next; + continue; + } + + if(strstr(node->GetName(), "Bone BoundingBox") != NULL) + { + // found it! + DummyObject* pDO; + Box3 box; + Point3 min, max; + Matrix3 m; + Point3 p, tp, sp; + Quat qq; + + pDO = (DummyObject*)Current->entry->obj; + assert(pDO != NULL); + box = pDO->GetBox(); + min = box.Min(); + max = box.Max(); + + m = node->GetNodeTM(FirstFrame); + p *= 0.0f; // zero the point + p = m * p; // get box's position + + min += p; + max += p; + + fprintf(f, "Bounding Box: %s\n", node->GetName()); + fprintf(f, "Parent: "); + if(node->GetParentNode() != NULL) + fprintf(f, "%s\n", node->GetParentNode()->GetName()); + else + fprintf(f, "-1\n"); + fprintf(f, "%f %f %f\n", min.x, min.y, min.z); + fprintf(f, "%f %f %f\n", max.x, max.y, max.z); + + Matrix3fprint(f, m); + DecomposeMatrix(m, tp, qq, sp); + fprintf(f, "Q(w,x,y,z): %f %f %f %f\n", qq.w, qq.x, qq.y, qq.z); + fprintf(f, "S(x,y,z): %f %f %f\n", sp.x, sp.y, sp.z); + fprintf(f, "T(x,y,z): %f %f %f\n", tp.x, tp.y, tp.z); + + } + + Current = Current->next; + } + + // count number of mesh nodes + NumNodes = 0; + Current = theObjects->head; + while(Current) + { + if (Current->entry->type != OBTYPE_MESH) + { + Current = Current->next; + continue; + } + + node = Current->entry->node; + if (!node) + { + Current = Current->next; + continue; + } + + Current = Current->next; + NumNodes++; + } + + fprintf(f, "Mesh List\n"); + fprintf(f, "Number of meshes = %d\n", NumNodes); + + Current = theObjects->head; + NodeN = 0; + while (Current) + { + if (Current->entry->type != OBTYPE_MESH) + { + Current = Current->next; + continue; + } + + node = Current->entry->node; + if (!node) + { + Current = Current->next; + continue; + } + + //sprintf(Temp, "Writing Node: %i of %i", NodeN++, NumNodes); + //MessageBox(NULL, Temp, "John's Message", MB_OK); + + fprintf(f, "Node: %s\n", node->GetName()); + + os = node->EvalWorldState(FirstFrame); + tm = node->GetObjTMAfterWSM(FirstFrame); + + mesh = ((GeomObject*)os.obj)->GetRenderMesh(0,node,View,needDel); + + if (!mesh) + { + MessageBox(NULL, "ERROR: No mesh for node!", node->GetName(), MB_OK); + return 0; + } + +#ifndef USE_MAX1SDK + IPhysiqueExport* phyExport = NULL; + IPhyContextExport* mcExport = NULL; + Modifier* phyMod = NULL; + + phyMod = FindPhysiqueModifier(node); + if(phyMod == NULL) + { +// MessageBox(NULL, "No physique modifier for node!", node->GetName(), MB_OK); + } + else + { + phyExport = (IPhysiqueExport*)phyMod->GetInterface(I_PHYINTERFACE); + if(phyExport == NULL) + { +// MessageBox(NULL, "No Physique Exporter", node->GetName(), MB_OK); + } + else + { + mcExport = (IPhyContextExport*)phyExport->GetContextInterface(node); + if(mcExport == NULL) + { +// MessageBox(NULL, "No Physique Context Exporter", node->GetName(), MB_OK); + } + } + } +#endif + + Point3 v; + UVVert uv; + NumTVerts = mesh->getNumTVerts(); + NumVerts = mesh->getNumVerts(); + char szBone[1024]; + + //------------------------------------------------------------------- + // Write the Vertex info + + fprintf(f, "Vertex List\n"); + fprintf(f, "Number of Vertices = %d\n", NumVerts); + + // Write out the vertex list + for(i=0;igetVert(i); + fprintf(f, "%f %f %f", v.x, v.y, v.z); + +#ifndef USE_MAX1SDK + if(mcExport != NULL) + { + IPhyRigidVertex* vtxExport = (IPhyRigidVertex*)mcExport->GetVertexInterface(i); + if(vtxExport != NULL) + { + INode* Bone = vtxExport->GetNode(); + if(Bone == NULL) + { + char textmsg[1000]; + sprintf(textmsg, "Vertex at %f, %f, %f is not linked", v.x, v.y, v.z); + MessageBox(NULL, textmsg, "ERROR", MB_OK); + goto NFOExportCleanup; + } + strcpy(szBone, Bone->GetName()); + v = vtxExport->GetOffsetVector(); + mcExport->ReleaseVertexInterface(vtxExport); + } + } + else +#endif + { + strcpy(szBone, "-1"); // default to BODY_NO_PARENT_BONE (see body.h) + } + fprintf(f, " %f %f %f %s\n", v.x, v.y, v.z, szBone); + } + + //------------------------------------------------------------------- + // Write the Texture Vertex info + + fprintf(f, "Texture Vertex List\n"); + fprintf(f, "Number of Texture Vertices = %d\n", NumTVerts); + + // Write out the vertex list + for(i=0;igetTVert(i); + fprintf(f, "%f %f\n", uv.x, uv.y); + } + + //------------------------------------------------------------------- + // Write the Face info + + fprintf(f, "Face List\n"); + + // Write out the number of faces + NumFaces = mesh->getNumFaces(); + fprintf(f, "Number of Faces = %d\n", NumFaces); + + //------------------------------------------------------------------- + // Find this node's material(s) + + Mtl *Mat = node->GetMtl(); + + int ix, count; + unsigned short temp, MatNum, NumMats = 0; + char Name[256]; + + NumMats = 0; + if (Mat) + { + if (IsStdMulti(Mat)) + { + multiMtl = TRUE; + // make a table that maps sub-mtl number to the proper index + // into theMtls. + k = 1; + j = Mat->NumSubMtls(); + for(ix=0;ixgetFaceMtlIndex(ix)) + j = mesh->getFaceMtlIndex(ix); + if(k > mesh->getFaceMtlIndex(ix)) + k = mesh->getFaceMtlIndex(ix); + } + j -= k; + j++; + mtlNumMap.SetCount(j); + for(i=0;iNumSubMtls(); i++) + { + Mtl *sub = Mat->GetSubMtl(i); + if (sub) + { + mtlNumMap[i] = theMtls->FindMtl(sub); + NumMats++; + } + else + mtlNumMap[i] = 0; + } + + //fprintf(f, "Number of Materials = %d\n", NumMats); + + for (i=0; iNumSubMtls(); i++) + { + Mtl *sub = Mat->GetSubMtl(i); + if (sub) + { + MatNum = mtlNumMap[i]; + + count = 0; + for (ix=0; ixnumFaces; ix++) + { + j = mesh->getFaceMtlIndex(ix); + if(j < mtlNumMap.Count()) + { + int mtlIndex = mtlNumMap[j]; + if (mtlIndex==MatNum) + count++; + } + else + { + fprintf(f,"*** ERROR *** Face assigned to a non existing material\n"); + return (0); + } + } + + memset(Name, 0, 32); + //if ((*theMtls)[MatNum].sm->map[0]) + if(MatNum >= (*theMtls).Count()) + { + fprintf(f,"*** ERROR *** Material Index is greater than number of materials\n"); + return (0); + } + strcpy(Name, (*theMtls)[MatNum].sm->name);//->map[0]->map.name); + //fprintf(f, "%s\n", Name); + + temp = (unsigned short)count; + + } + } + } + else + { + NumMats = 1; + MatNum = theMtls->FindMtl(Mat); + multiMtl = FALSE; + count = mesh->numFaces; + + //fprintf(f, "Number of Materials = %d\n", NumMats); + + memset(Name, 0, 32); + //if ((*theMtls)[MatNum].sm->map[0]) + if(MatNum >= (*theMtls).Count()) + { + fprintf(f,"*** ERROR *** Material Index is greater than number of materials\n"); + return (0); + } + strcpy(Name, (*theMtls)[MatNum].sm->name);//->map[0]->map.name); + //fprintf(f, "%s\n", Name); + + //fprintf(f, "Number of Faces with this material = %d, Face list follows\n", count); + + for(ix=0; ixnumFaces; ++ix) + { + //fprintf(f, "%d\n", ix); + } + } + } + else + { + NumMats = 0; + //fprintf(f, "Number of Materials = %d\n", NumMats); + } + + // Write out the face index info + for (i=0; i< NumFaces; i++) + { + // Each face writes out: + // facenum: + // material name + // Smoothing Group + // v1 uv1 + // v2 uv2 + // v3 uv3 + + fprintf(f, "Face %d:\n", i); + + // material name + if(Mat) + { + if(IsStdMulti(Mat)) + { + // assumes mtlNumMap was setup above + j = mesh->getFaceMtlIndex(i); + MatNum = mtlNumMap[j]; + } + else + { + MatNum = theMtls->FindMtl(Mat); + } + if(MatNum >= (*theMtls).Count()) + { + fprintf(f,"*** ERROR *** Material Index is greater than number of materials\n"); + return (0); + } + fprintf(f, " %d\n", MatNum); + } + else + { + fprintf(f, " -1\n"); + } + + // smoothing group number + fprintf(f, " %d\n", mesh->faces[i].getSmGroup()); + + // vertex info for three vertices + for(k=0;k<3;k++) + { + fprintf(f, " %d", mesh->faces[i].getVert(k)); + if(NumTVerts > 0) + fprintf(f, " %d", mesh->tvFace[i].t[k]); + else + fprintf(f, " -1"); + fprintf(f, "\n"); + } + } + +#ifndef USE_MAX1SDK + if(mcExport != NULL) + phyExport->ReleaseContextInterface(mcExport); + if(phyExport != NULL) + phyMod->ReleaseInterface(I_PHYINTERFACE, phyExport); +#endif + + Current = Current->next; + } + +NFOExportCleanup: + + delete [] pBones; + + fclose (f); + + return 1; +} + +int BVHExport(const TCHAR *filename, const TCHAR *nfofile, const TCHAR *keyfile, BOOL suppressPrompts) +{ + int RetCode = 1; + TCHAR bodyfile[MAX_PATH]; + TCHAR motionfile[MAX_PATH]; + TCHAR bodyarg[MAX_PATH * 2]; + TCHAR arg1[MAX_PATH * 2]; + TCHAR arg2[MAX_PATH * 2]; + TCHAR* pdot; + + // body name + GetTempFileName(".", GetString(IDS_NFO_EXT), 0, bodyfile); + strcpy(bodyarg, "-b"); + strcat(bodyarg, bodyfile); + // nfo name + strcpy(arg1, "-n"); + strcat(arg1, nfofile); + // make the body + if(_spawnl(_P_WAIT, "mkbody.exe", bodyarg, arg1, NULL) != 0) + RetCode = 0; + if(RetCode == 0) + goto CleanAndReturn; + + // build motion filename: keyfile.??? -> keyfile.mot + strcpy(motionfile, keyfile); + pdot = strrchr(motionfile, '.'); + if(pdot == NULL) + { + pdot = motionfile + strlen(motionfile); + } + strcpy(pdot, ".mot"); + + // bodyarg still has "-bbodyfile" + // make the motion + if(_spawnl(_P_WAIT, "mkmotion.exe", bodyarg, keyfile, NULL) != 0) + RetCode = 0; + if(RetCode == 0) + goto CleanAndReturn; + + // motion name + strcpy(arg1, "-m"); + strcat(arg1, motionfile); + // bvh name + strcpy(arg2, "-o"); + strcat(arg2, filename); + // make the bvh + if(_spawnl(_P_WAIT, "mkbvh.exe", bodyarg, arg1, arg2, NULL) != 0) + RetCode = 0; + if(RetCode == 0) + goto CleanAndReturn; + +CleanAndReturn: + + remove(bodyfile); + remove(motionfile); + + return(RetCode); +} + +int _3ds_save(const TCHAR *filename, ExpInterface *ei, Interface *gi, _3DSExport *exp, BOOL suppressPrompts) +{ + MeshMtlList myMtls; + + // Make sure there are nodes we're interested in! + // Ask the scene to enumerate all its nodes so we can determine if there are any we can use + SceneEnumProc myScene(ei->theScene, gi->GetTime(), gi, &myMtls); + + // Any useful nodes? + if(!myScene.Count()) + { + Alert(IDS_TH_NODATATOEXPORT); + return 1; + } + + // Construct unique names < 10 chars. + myScene.BuildNames(); + + ObjectList myObjects(myScene); + + theSceneEnum = &myScene; + theObjects = &myObjects; + theMtls = &myMtls; + +#ifdef NFOEXP + return(NFOExport(filename, suppressPrompts)); +#endif + +#ifdef KEYEXP + return(KEYExport(filename, suppressPrompts)); +#endif + +#ifdef BVHEXP + + int RetCode = 1; // codes are 0 (failure) or 1 (success) + TCHAR nfofile[MAX_PATH]; + TCHAR keyfile[MAX_PATH]; + + GetTempFileName(".", GetString(IDS_NFO_EXT), 0, nfofile); + GetTempFileName(".", GetString(IDS_KEY_EXT), 0, keyfile); + + RetCode = NFOExport(nfofile, suppressPrompts); + if(RetCode != 1) + goto BVHCleanAndReturn; + + RetCode = KEYExport(keyfile, suppressPrompts); + if(RetCode != 1) + goto BVHCleanAndReturn; + + RetCode = BVHExport(filename, nfofile, keyfile, suppressPrompts); + +BVHCleanAndReturn: + + remove(nfofile); + remove(keyfile); + + return (RetCode); +#endif +} + +#ifdef USE_MAX1SDK + int _3DSExport: : DoExport(const TCHAR *filename,ExpInterface *ei,Interface *gi) +#else + #if (MAX_RELEASE >= 3000) + int _3DSExport::DoExport(const TCHAR *filename,ExpInterface *ei,Interface *gi, BOOL suppressPrompts, DWORD options) + #else // (MAX_RELEASE >= 2000) + int _3DSExport::DoExport(const TCHAR *filename,ExpInterface *ei,Interface *gi, BOOL suppressPrompts) + #endif +#endif // !USE_MAX1SDK +{ + int status; +#ifdef USE_MAX1SDK + BOOL suppressPrompts = FALSE; +#endif + + status = _3ds_save(filename, ei, gi, this, suppressPrompts); + + if(status == 0) + return 1; // Dialog cancelled + if(status < 0) + return 0; // Real, honest-to-goodness error + return(status); +} + +#ifdef HOLDING + + for(ox=0; oxnode; + Object *obj = myScene[ox]->obj; + TriObject *tri = (TriObject *)obj->ConvertToType(gi->GetTime(), triObjectClassID); + Mesh &mesh = tri->mesh; + Matrix3 tm = n->GetObjectTM(gi->GetTime()); + + int verts = mesh.getNumVerts(); + int faces = mesh.getNumFaces(); + + Point3 vert; + Face face; + for(ix=0; ixDeleteThis(); + } +#endif + + + +short Get3DSTVerts(Mesh& mesh, Point2 *tv) { + int nv = mesh.getNumVerts(); + int nf = mesh.getNumFaces(); + short wrap = 0; + BitArray done(nv); + for (int j=0; j65535) continue; + if (!done[vert]) { + tv[vert] = v; + done.Set(vert,1); + } + else { + if (v.x!=tv[vert].x) { + wrap |= UWRAP; + if (v.x +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=gexp - Win32 NFO Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gexp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gexp.mak" CFG="gexp - Win32 NFO Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gexp - Win32 NFO Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 NFO Hybrid" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 KEY Hybrid" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 KEY Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 R3 KEY Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 R3 NFO Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Tools/Exporters", GUIAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gexp - Win32 NFO Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\nfoRelease" +# PROP Intermediate_Dir ".\nfoRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /G5 /MT /W3 /GX /O2 /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "NFOEXP" /FD /c +# SUBTRACT CPP /Fr /YX +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /x /i "..\..\msdev60\include" /d "NDEBUG" /d "NFOEXP" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 libcmt.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib /out:".\nforelease\nfoexp.dle" /libpath:"..\..\msdev60\lib" +# SUBTRACT LINK32 /debug + +!ELSEIF "$(CFG)" == "gexp - Win32 NFO Hybrid" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\nfoexp_0" +# PROP BASE Intermediate_Dir ".\nfoexp_0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\nfoHybrid" +# PROP Intermediate_Dir ".\nfoHybrid" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MD /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "NFOEXP" /FD /c +# SUBTRACT CPP /Fr /YX +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /x /i "..\..\msdev60\include" /d "_DEBUG" /d "NFOEXP" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"..\..\..\exe\stdplugs\nfoexp.dle" +# ADD LINK32 libcmtd.lib winmm.lib oldnames.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib /out:".\nfohybrid\nfoexp.dle" /libpath:"..\..\msdev60\lib" + +!ELSEIF "$(CFG)" == "gexp - Win32 KEY Hybrid" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gexp___1" +# PROP BASE Intermediate_Dir "gexp___1" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "keyhybrid" +# PROP Intermediate_Dir "keyhybrid" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MDd /W3 /Gm /GX /Zi /Od /I "max2sdk\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "NFOEXP" /FD /c +# SUBTRACT BASE CPP /Fr /YX +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "KEYEXP" /FD /c +# SUBTRACT CPP /Fr /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /x /i "..\..\msdev60\include" /d "_DEBUG" /d "KEYEXP" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 winmm.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\nfohybrid\nfoexp.dle" +# ADD LINK32 libcmtd.lib winmm.lib oldnames.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib /out:".\keyhybrid\keyexp.dle" /libpath:"..\..\msdev60\lib" + +!ELSEIF "$(CFG)" == "gexp - Win32 KEY Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gexp___2" +# PROP BASE Intermediate_Dir "gexp___2" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "keyrelease" +# PROP Intermediate_Dir "keyrelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MD /W3 /GX /O2 /I "max2sdk\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "NFOEXP" /FD /c +# SUBTRACT BASE CPP /Fr /YX +# ADD CPP /nologo /G5 /MT /W3 /GX /O2 /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "KEYEXP" /FD /c +# SUBTRACT CPP /Fr /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /x /i "..\..\msdev60\include" /d "NDEBUG" /d "KEYEXP" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:I386 /out:".\nforelease\nfoexp.dle" +# SUBTRACT BASE LINK32 /debug +# ADD LINK32 libcmt.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib /out:".\keyrelease\keyexp.dle" /libpath:"..\..\msdev60\lib" +# SUBTRACT LINK32 /debug + +!ELSEIF "$(CFG)" == "gexp - Win32 R3 KEY Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gexp___Win32_R3_KEY_Release" +# PROP BASE Intermediate_Dir "gexp___Win32_R3_KEY_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "R3KEYRelease" +# PROP Intermediate_Dir "R3KEYRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MT /W3 /GX /O2 /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "KEYEXP" /FD /c +# SUBTRACT BASE CPP /Fr /YX +# ADD CPP /nologo /G5 /MT /W3 /GX /O2 /X /I "..\..\msdev60\include" /I "max3sdk\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "KEYEXP" /FD /c +# SUBTRACT CPP /Fr /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /x /i "..\..\msdev60\include" /d "NDEBUG" /d "KEYEXP" +# ADD RSC /l 0x409 /x /i "..\..\msdev60\include" /d "NDEBUG" /d "KEYEXP" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 libcmt.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib /out:".\keyrelease\keyexp.dle" /libpath:"..\..\msdev60\lib" +# SUBTRACT BASE LINK32 /debug +# ADD LINK32 libcmt.lib max3sdk\lib\core.lib max3sdk\lib\maxutil.lib max3sdk\lib\geom.lib max3sdk\lib\gfx.lib max3sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib /out:".\R3keyrelease\keyexp.dle" /libpath:"..\..\msdev60\lib" +# SUBTRACT LINK32 /debug + +!ELSEIF "$(CFG)" == "gexp - Win32 R3 NFO Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gexp___Win32_R3_NFO_Release" +# PROP BASE Intermediate_Dir "gexp___Win32_R3_NFO_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "R3NFORelease" +# PROP Intermediate_Dir "R3NFORelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MT /W3 /GX /O2 /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "NFOEXP" /FD /c +# SUBTRACT BASE CPP /Fr /YX +# ADD CPP /nologo /G5 /MT /W3 /GX /O2 /X /I "..\..\msdev60\include" /I "max3sdk\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "NFOEXP" /FD /c +# SUBTRACT CPP /Fr /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /x /i "..\..\msdev60\include" /d "NDEBUG" /d "NFOEXP" +# ADD RSC /l 0x409 /x /i "..\..\msdev60\include" /d "NDEBUG" /d "NFOEXP" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 libcmt.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib /out:".\nforelease\nfoexp.dle" /libpath:"..\..\msdev60\lib" +# SUBTRACT BASE LINK32 /debug +# ADD LINK32 libcmt.lib max3sdk\lib\core.lib max3sdk\lib\maxutil.lib max3sdk\lib\geom.lib max3sdk\lib\gfx.lib max3sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib /out:".\R3nforelease\nfoexp.dle" /libpath:"..\..\msdev60\lib" +# SUBTRACT LINK32 /debug + +!ENDIF + +# Begin Target + +# Name "gexp - Win32 NFO Release" +# Name "gexp - Win32 NFO Hybrid" +# Name "gexp - Win32 KEY Hybrid" +# Name "gexp - Win32 KEY Release" +# Name "gexp - Win32 R3 KEY Release" +# Name "gexp - Win32 R3 NFO Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\3dsmtl.cpp +# End Source File +# Begin Source File + +SOURCE=.\gexp.cpp +# End Source File +# Begin Source File + +SOURCE=.\gexp.def +# End Source File +# Begin Source File + +SOURCE=.\gexp.rc +# End Source File +# Begin Source File + +SOURCE=.\Savemli.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\3dseres.h +# End Source File +# Begin Source File + +SOURCE=.\3dsimp.h +# End Source File +# Begin Source File + +SOURCE=.\3dsires.h +# End Source File +# Begin Source File + +SOURCE=.\Cfile.h +# End Source File +# Begin Source File + +SOURCE=.\gexp.h +# End Source File +# Begin Source File + +SOURCE=.\Kfio.h +# End Source File +# Begin Source File + +SOURCE=.\Mtldef.h +# End Source File +# Begin Source File + +SOURCE=.\Ofile.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=.\gexp.mak +# End Source File +# End Target +# End Project diff --git a/Exporters/gexp.h b/Exporters/gexp.h new file mode 100644 index 0000000..bf55e64 --- /dev/null +++ b/Exporters/gexp.h @@ -0,0 +1,190 @@ + +/********************************************************************** + *< + FILE: 3dsexp.h + + DESCRIPTION: .3DS file export module header file + + CREATED BY: Tom Hudson + + HISTORY: created 26 December 1994 + + *> Copyright (c) 1994, All Rights Reserved. + **********************************************************************/ + +#pragma pack(1) + +/* 3DS Shape point structure */ + +struct shppt +{ +float x; /* Control point */ +float y; +float z; +float inx; /* Incoming vector */ +float iny; +float inz; +float outx; /* Outgoing vector */ +float outy; +float outz; +unsigned short flags; +}; +typedef struct shppt Shppt; + +#include "ofile.h" // 3DS Object file header +//#include "3dsshape.h" // 3DS shape file header +#include "kfio.h" // 3DS KF header +#pragma pack() + + +// Some 3DS structures + +#pragma pack(1) +typedef struct { + unsigned short tag; + long size; + } Chunk_hdr; + +typedef struct { + float x; + float y; + float z; + unsigned short flags; + } Verts; + +typedef struct { + float u; + float v; + } Texverts; + +typedef struct { + unsigned short a; + unsigned short b; + unsigned short c; + unsigned char material; + unsigned char filler; + unsigned long sm_group; + unsigned short flags; + } Faces; +#pragma pack() + +// 3DS face edge vis flags +#define ABLINE (1<<2) +#define BCLINE (1<<1) +#define CALINE 1 + +#define VWRAP (1<<11) /* Texture coord V wraps on this face */ +#define UWRAP (1<<3) /* Texture coord U wraps on this face */ + +// Node list structure + +//struct WkObjList; +typedef struct { + TriObject *object; + TCHAR name[11]; + int used; + void *next; + } WkObjList; + +//struct WkNodeList; +typedef struct { + ImpNode *node; + short id; + TCHAR name[11]; + Mesh *mesh; + ImpNode *parent; + Matrix3 tm; + void *next; + } WkNodeList; + +// 3DS Key structures + +#pragma pack(1) + +struct fc_wrt +{ +unsigned short a; +unsigned short b; +unsigned short c; +unsigned short flags; +} Fc_wrt; + +struct color_24 +{ +uchar r; +uchar g; +uchar b; +}; +typedef struct color_24 Color_24; + +struct color_f +{ +float r; +float g; +float b; +}; +typedef struct color_f Color_f; + +// key types +#define KEY_FLOAT 0 +#define KEY_POS 1 +#define KEY_ROT 2 +#define KEY_SCL 3 +#define KEY_COLOR 4 + +#define KEYHDR \ + TimeValue time; \ + float tens,cont,bias; \ + float easeTo,easeFrom; + +typedef struct { float p,ds,dd; } PosElem; +typedef struct { + KEYHDR + PosElem e[8]; /* enough to be bigger than the biggest key, + including RotKey */ + } Key; + +typedef struct { + KEYHDR + PosElem e[1]; + } ScalarKey; + +typedef struct { + KEYHDR + PosElem e[3]; + } PosKey; + +typedef struct { + KEYHDR + float angle; /* angle of rotation in radians (always >0) */ + float axis[3]; /* axis of rotation (unit vector) */ + float q[4]; /* quaternion describing orientation */ + float b[4]; /* incoming tangent term */ + float a[4]; /* outgoing tangent term */ + } RotKey; + +#ifdef LATER +typedef struct { + KEYHDR + Namedobj *object; + } MorphKey; + +typedef struct { + KEYHDR + } HideKey; + +typedef struct { + KEYHDR + FLOAT c[3]; + } ColorKey; +#endif // LATER +#pragma pack() + +typedef struct { + union { + Key key; + PosKey pos; + RotKey rot; + } key; + void *next; + } KeyList; diff --git a/Exporters/gexp.mak b/Exporters/gexp.mak new file mode 100644 index 0000000..782ad1c --- /dev/null +++ b/Exporters/gexp.mak @@ -0,0 +1,384 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on gexp.dsp +!IF "$(CFG)" == "" +CFG=gexp - Win32 NFO Release +!MESSAGE No configuration specified. Defaulting to gexp - Win32 NFO Release. +!ENDIF + +!IF "$(CFG)" != "gexp - Win32 NFO Release" && "$(CFG)" != "gexp - Win32 NFO Hybrid" && "$(CFG)" != "gexp - Win32 KEY Hybrid" && "$(CFG)" != "gexp - Win32 KEY Release" && "$(CFG)" != "gexp - Win32 R3 KEY Release" && "$(CFG)" != "gexp - Win32 R3 NFO Release" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gexp.mak" CFG="gexp - Win32 NFO Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gexp - Win32 NFO Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 NFO Hybrid" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 KEY Hybrid" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 KEY Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 R3 KEY Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gexp - Win32 R3 NFO Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gexp - Win32 NFO Release" + +OUTDIR=.\nfoRelease +INTDIR=.\nfoRelease +# Begin Custom Macros +OutDir=.\nfoRelease +# End Custom Macros + +ALL : "$(OUTDIR)\nfoexp.dle" + + +CLEAN : + -@erase "$(INTDIR)\3dsmtl.obj" + -@erase "$(INTDIR)\gexp.obj" + -@erase "$(INTDIR)\gexp.res" + -@erase "$(INTDIR)\Savemli.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\nfoexp.dle" + -@erase "$(OUTDIR)\nfoexp.exp" + -@erase "$(OUTDIR)\nfoexp.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /G5 /MT /W3 /GX /O2 /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "NFOEXP" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\gexp.res" /i "..\..\msdev60\include" /d "NDEBUG" /d "NFOEXP" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\gexp.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libcmt.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\nfoexp.pdb" /machine:I386 /nodefaultlib /def:".\gexp.def" /out:"$(OUTDIR)\nfoexp.dle" /implib:"$(OUTDIR)\nfoexp.lib" /libpath:"..\..\msdev60\lib" +DEF_FILE= \ + ".\gexp.def" +LINK32_OBJS= \ + "$(INTDIR)\3dsmtl.obj" \ + "$(INTDIR)\gexp.obj" \ + "$(INTDIR)\Savemli.obj" \ + "$(INTDIR)\gexp.res" + +"$(OUTDIR)\nfoexp.dle" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "gexp - Win32 NFO Hybrid" + +OUTDIR=.\nfoHybrid +INTDIR=.\nfoHybrid +# Begin Custom Macros +OutDir=.\nfoHybrid +# End Custom Macros + +ALL : "$(OUTDIR)\nfoexp.dle" + + +CLEAN : + -@erase "$(INTDIR)\3dsmtl.obj" + -@erase "$(INTDIR)\gexp.obj" + -@erase "$(INTDIR)\gexp.res" + -@erase "$(INTDIR)\Savemli.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\nfoexp.dle" + -@erase "$(OUTDIR)\nfoexp.exp" + -@erase "$(OUTDIR)\nfoexp.ilk" + -@erase "$(OUTDIR)\nfoexp.lib" + -@erase "$(OUTDIR)\nfoexp.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "NFOEXP" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\gexp.res" /i "..\..\msdev60\include" /d "_DEBUG" /d "NFOEXP" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\gexp.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libcmtd.lib winmm.lib oldnames.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"$(OUTDIR)\nfoexp.pdb" /debug /machine:I386 /nodefaultlib /def:".\gexp.def" /out:"$(OUTDIR)\nfoexp.dle" /implib:"$(OUTDIR)\nfoexp.lib" /libpath:"..\..\msdev60\lib" +DEF_FILE= \ + ".\gexp.def" +LINK32_OBJS= \ + "$(INTDIR)\3dsmtl.obj" \ + "$(INTDIR)\gexp.obj" \ + "$(INTDIR)\Savemli.obj" \ + "$(INTDIR)\gexp.res" + +"$(OUTDIR)\nfoexp.dle" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "gexp - Win32 KEY Hybrid" + +OUTDIR=.\keyhybrid +INTDIR=.\keyhybrid +# Begin Custom Macros +OutDir=.\keyhybrid +# End Custom Macros + +ALL : "$(OUTDIR)\keyexp.dle" + + +CLEAN : + -@erase "$(INTDIR)\3dsmtl.obj" + -@erase "$(INTDIR)\gexp.obj" + -@erase "$(INTDIR)\gexp.res" + -@erase "$(INTDIR)\Savemli.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\keyexp.dle" + -@erase "$(OUTDIR)\keyexp.exp" + -@erase "$(OUTDIR)\keyexp.ilk" + -@erase "$(OUTDIR)\keyexp.lib" + -@erase "$(OUTDIR)\keyexp.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "KEYEXP" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\gexp.res" /i "..\..\msdev60\include" /d "_DEBUG" /d "KEYEXP" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\gexp.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libcmtd.lib winmm.lib oldnames.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"$(OUTDIR)\keyexp.pdb" /debug /machine:I386 /nodefaultlib /def:".\gexp.def" /out:"$(OUTDIR)\keyexp.dle" /implib:"$(OUTDIR)\keyexp.lib" /libpath:"..\..\msdev60\lib" +DEF_FILE= \ + ".\gexp.def" +LINK32_OBJS= \ + "$(INTDIR)\3dsmtl.obj" \ + "$(INTDIR)\gexp.obj" \ + "$(INTDIR)\Savemli.obj" \ + "$(INTDIR)\gexp.res" + +"$(OUTDIR)\keyexp.dle" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "gexp - Win32 KEY Release" + +OUTDIR=.\keyrelease +INTDIR=.\keyrelease +# Begin Custom Macros +OutDir=.\keyrelease +# End Custom Macros + +ALL : "$(OUTDIR)\keyexp.dle" + + +CLEAN : + -@erase "$(INTDIR)\3dsmtl.obj" + -@erase "$(INTDIR)\gexp.obj" + -@erase "$(INTDIR)\gexp.res" + -@erase "$(INTDIR)\Savemli.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\keyexp.dle" + -@erase "$(OUTDIR)\keyexp.exp" + -@erase "$(OUTDIR)\keyexp.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /G5 /MT /W3 /GX /O2 /X /I "max2sdk\include" /I "..\..\msdev60\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "KEYEXP" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\gexp.res" /i "..\..\msdev60\include" /d "NDEBUG" /d "KEYEXP" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\gexp.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libcmt.lib max2sdk\lib\core.lib max2sdk\lib\util.lib max2sdk\lib\geom.lib max2sdk\lib\gfx.lib max2sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\keyexp.pdb" /machine:I386 /nodefaultlib /def:".\gexp.def" /out:"$(OUTDIR)\keyexp.dle" /implib:"$(OUTDIR)\keyexp.lib" /libpath:"..\..\msdev60\lib" +DEF_FILE= \ + ".\gexp.def" +LINK32_OBJS= \ + "$(INTDIR)\3dsmtl.obj" \ + "$(INTDIR)\gexp.obj" \ + "$(INTDIR)\Savemli.obj" \ + "$(INTDIR)\gexp.res" + +"$(OUTDIR)\keyexp.dle" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "gexp - Win32 R3 KEY Release" + +OUTDIR=.\R3KEYRelease +INTDIR=.\R3KEYRelease +# Begin Custom Macros +OutDir=.\R3KEYRelease +# End Custom Macros + +ALL : "$(OUTDIR)\keyexp.dle" + + +CLEAN : + -@erase "$(INTDIR)\3dsmtl.obj" + -@erase "$(INTDIR)\gexp.obj" + -@erase "$(INTDIR)\gexp.res" + -@erase "$(INTDIR)\Savemli.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\keyexp.dle" + -@erase "$(OUTDIR)\keyexp.exp" + -@erase "$(OUTDIR)\keyexp.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /G5 /MT /W3 /GX /O2 /X /I "..\..\msdev60\include" /I "max3sdk\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "KEYEXP" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\gexp.res" /i "..\..\msdev60\include" /d "NDEBUG" /d "KEYEXP" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\gexp.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libcmt.lib max3sdk\lib\core.lib max3sdk\lib\maxutil.lib max3sdk\lib\geom.lib max3sdk\lib\gfx.lib max3sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\keyexp.pdb" /machine:I386 /nodefaultlib /def:".\gexp.def" /out:"$(OUTDIR)\keyexp.dle" /implib:"$(OUTDIR)\keyexp.lib" /libpath:"..\..\msdev60\lib" +DEF_FILE= \ + ".\gexp.def" +LINK32_OBJS= \ + "$(INTDIR)\3dsmtl.obj" \ + "$(INTDIR)\gexp.obj" \ + "$(INTDIR)\Savemli.obj" \ + "$(INTDIR)\gexp.res" + +"$(OUTDIR)\keyexp.dle" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "gexp - Win32 R3 NFO Release" + +OUTDIR=.\R3NFORelease +INTDIR=.\R3NFORelease +# Begin Custom Macros +OutDir=.\R3NFORelease +# End Custom Macros + +ALL : "$(OUTDIR)\nfoexp.dle" + + +CLEAN : + -@erase "$(INTDIR)\3dsmtl.obj" + -@erase "$(INTDIR)\gexp.obj" + -@erase "$(INTDIR)\gexp.res" + -@erase "$(INTDIR)\Savemli.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\nfoexp.dle" + -@erase "$(OUTDIR)\nfoexp.exp" + -@erase "$(OUTDIR)\nfoexp.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /G5 /MT /W3 /GX /O2 /X /I "..\..\msdev60\include" /I "max3sdk\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "NFOEXP" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\gexp.res" /i "..\..\msdev60\include" /d "NDEBUG" /d "NFOEXP" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\gexp.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libcmt.lib max3sdk\lib\core.lib max3sdk\lib\maxutil.lib max3sdk\lib\geom.lib max3sdk\lib\gfx.lib max3sdk\lib\mesh.lib version.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\nfoexp.pdb" /machine:I386 /nodefaultlib /def:".\gexp.def" /out:"$(OUTDIR)\nfoexp.dle" /implib:"$(OUTDIR)\nfoexp.lib" /libpath:"..\..\msdev60\lib" +DEF_FILE= \ + ".\gexp.def" +LINK32_OBJS= \ + "$(INTDIR)\3dsmtl.obj" \ + "$(INTDIR)\gexp.obj" \ + "$(INTDIR)\Savemli.obj" \ + "$(INTDIR)\gexp.res" + +"$(OUTDIR)\nfoexp.dle" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("gexp.dep") +!INCLUDE "gexp.dep" +!ELSE +!MESSAGE Warning: cannot find "gexp.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "gexp - Win32 NFO Release" || "$(CFG)" == "gexp - Win32 NFO Hybrid" || "$(CFG)" == "gexp - Win32 KEY Hybrid" || "$(CFG)" == "gexp - Win32 KEY Release" || "$(CFG)" == "gexp - Win32 R3 KEY Release" || "$(CFG)" == "gexp - Win32 R3 NFO Release" +SOURCE=.\3dsmtl.cpp + +"$(INTDIR)\3dsmtl.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\gexp.cpp + +"$(INTDIR)\gexp.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\gexp.rc + +"$(INTDIR)\gexp.res" : $(SOURCE) "$(INTDIR)" + $(RSC) $(RSC_PROJ) $(SOURCE) + + +SOURCE=.\Savemli.cpp + +"$(INTDIR)\Savemli.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/Exporters/gexp.rc b/Exporters/gexp.rc new file mode 100644 index 0000000..1d56463 --- /dev/null +++ b/Exporters/gexp.rc @@ -0,0 +1,246 @@ +//Microsoft Developer Studio generated resource script. +// +#include "3dseres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "3dseres.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#ifdef NFOEXP + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "WildTangent, Inc.\0" + VALUE "FileDescription", "nfoexp\0" + VALUE "FileVersion", "2.0\0" + VALUE "InternalName", "NFOexp\0" + VALUE "LegalCopyright", "Copyright © 1999 WildTangent, Inc.\0" + VALUE "OriginalFilename", "NFOexp.dle\0" + VALUE "ProductName", "NFOexp\0" + VALUE "ProductVersion", "2.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif + +#ifdef KEYEXP + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "WildTangent, Inc.\0" + VALUE "FileDescription", "keyexp\0" + VALUE "FileVersion", "2.0\0" + VALUE "InternalName", "KEYexp\0" + VALUE "LegalCopyright", "Copyright © 1999 WildTangent, Inc.\0" + VALUE "OriginalFilename", "KEYexp.dle\0" + VALUE "ProductName", "KEYexp\0" + VALUE "ProductVersion", "2.1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // KEYEXP + +#ifdef BVHEXP + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "WildTangent, Inc.\0" + VALUE "FileDescription", "bvhexp\0" + VALUE "FileVersion", "1.0\0" + VALUE "InternalName", "BVHexp\0" + VALUE "LegalCopyright", "Copyright © 1999 WildTangent, Inc.\0" + VALUE "OriginalFilename", "BVHexp.dle\0" + VALUE "ProductName", "BVHexp\0" + VALUE "ProductVersion", "1.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // BVHEXP + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN +#ifdef NFOEXP + IDS_TH_EXP "NFOEXP" +#endif +#ifdef KEYEXP + IDS_TH_EXP "KEYEXP" +#endif +#ifdef BVHEXP + IDS_TH_EXP "BVHEXP" +#endif + IDS_TH_SCENEEXPORT "Scene Export" +#ifdef NFOEXP + IDS_TH_EXPORTDLL ".NFO File Export DLL" +#endif +#ifdef KEYEXP + IDS_TH_EXPORTDLL ".KEY File Export DLL" +#endif +#ifdef BVHEXP + IDS_TH_EXPORTDLL ".BVH File Export DLL" +#endif + IDS_TH_NODATATOEXPORT "No data to export" + IDS_TH_CANTCREATE "Can't create output file" + IDS_TH_WRITEERROR "Write error on file" + IDS_OBJ_TOO_LARGE "Object %s is to large to export" + IDS_EXPORT_ERROR "Export Error" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_NFO_EXT "NFO" + IDS_KEY_EXT "KEY" + IDS_BVH_EXT "BVH" +#ifdef NFOEXP + IDS_TH_CLASS "NFO File" + IDS_TH_SCENEFILE "Eclipse iNFO file" + IDS_TH_MESH "Eclipse iNFO" +#endif +#ifdef KEYEXP + IDS_TH_CLASS "KEY File" + IDS_TH_SCENEFILE "Eclipse Motion KEY file" + IDS_TH_MESH "Eclipse KEY" +#endif +#ifdef BVHEXP + IDS_TH_CLASS "BVH File" + IDS_TH_SCENEFILE "Eclipse BVH file" + IDS_TH_MESH "Eclipse BVH" +#endif + IDS_TH_AUTHOR "Stephen Balkum" + IDS_TH_COPYRIGHT_ECLIPSE + "Copyright 1999, WildTangent, Inc.; All Rights Reserved." +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Exporters/max2sdk/readme.txt b/Exporters/max2sdk/readme.txt new file mode 100644 index 0000000..558cfe5 --- /dev/null +++ b/Exporters/max2sdk/readme.txt @@ -0,0 +1 @@ +See the file BUILD.TXT for instructions regarding this directory diff --git a/Exporters/max3sdk/readme.txt b/Exporters/max3sdk/readme.txt new file mode 100644 index 0000000..558cfe5 --- /dev/null +++ b/Exporters/max3sdk/readme.txt @@ -0,0 +1 @@ +See the file BUILD.TXT for instructions regarding this directory diff --git a/Exporters/mssccprj.scc b/Exporters/mssccprj.scc new file mode 100644 index 0000000..d1ce92e --- /dev/null +++ b/Exporters/mssccprj.scc @@ -0,0 +1,4 @@ +SCC = This is a Source Code Control file + +[gexp.mak] +SCC_Project_Name = "$/Genesis10/Tools/Exporters", MECCAAAA diff --git a/G3D/Actor/QKFrame.c b/G3D/Actor/QKFrame.c new file mode 100644 index 0000000..5ce7aa1 --- /dev/null +++ b/G3D/Actor/QKFrame.c @@ -0,0 +1,1182 @@ +/****************************************************************************************/ +/* QKFRAME.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Quaternion keyframe implementation. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +/* geQKFrame (geQuaternion - Keyframe) + This module handles interpolation for keyframes that contain a quaternion + This is intended to support Path.c + geTKArray supplies general support for a time-keyed array, and this supplements + that support to include the specific time-keyed arrays: + An array of geQuaternion interpolated linearly + An array of geQuaternion with spherical linear interpolation (SLERP) + An array of geQuaternion with spherical quadrangle + interpolation (SQUAD) as defined by: + Advanced Animation and Rendering Techniques by Alan Watt and Mark Watt + + These are phycially separated and have different base structures because + the different interpolation techniques requre different additional data. + + The two lists are created with different creation calls, + interpolated with different calls, but insertion and queries share a call. + + Quadrangle interpolation requires additional computation after changes are + made to the keyframe list. Call geQKFrame_SquadRecompute() to update the + calculations. +*/ +#include +#include +#include + +#include "vec3d.h" +#include "QKFrame.h" +#include "errorlog.h" +#include "ram.h" + +#define LINEAR_BLEND(a,b,t) ( (t)*((b)-(a)) + (a) ) + // linear blend of a and b 0a and t=1 ->b + +typedef struct +{ + geTKArray_TimeType Time; // Time for this keyframe + geQuaternion Q; // quaternion for this keyframe +} QKeyframe; + // This is the root structure that geQKFrame supports + // all keyframe types must begin with this structure. Time is first, so + // that this structure can be manipulated by geTKArray + +typedef struct +{ + QKeyframe Key; // key values for this keyframe +} geQKFrame_Linear; + // keyframe data for linear interpolation + // The structure includes no additional information. + +typedef struct +{ + QKeyframe Key; // key values for this keyframe +} geQKFrame_Slerp; + // keyframe data for spherical linear interpolation + // The structure includes no additional information. + +typedef struct +{ + QKeyframe Key; // key values for this keyframe + geQuaternion QuadrangleCorner; +} geQKFrame_Squad; + // keyframe data for spherical quadratic interpolation + + +geTKArray *GENESISCC geQKFrame_LinearCreate() + // creates a frame list for linear interpolation +{ + return geTKArray_Create(sizeof(geQKFrame_Linear) ); +} + + +geTKArray *GENESISCC geQKFrame_SlerpCreate() + // creates a frame list for spherical linear interpolation +{ + return geTKArray_Create(sizeof(geQKFrame_Slerp) ); +} + +geTKArray *GENESISCC geQKFrame_SquadCreate() + // creates a frame list for spherical linear interpolation +{ + return geTKArray_Create(sizeof(geQKFrame_Squad) ); +} + + +geBoolean GENESISCC geQKFrame_Insert( + geTKArray **KeyList, // keyframe list to insert into + geTKArray_TimeType Time, // time of new keyframe + const geQuaternion *Q, // quaternion at new keyframe + int *Index) // index of new key + // inserts a new keyframe with the given time and vector into the list. +{ + assert( KeyList != NULL ); + assert( *KeyList != NULL ); + assert( Q != NULL ); + assert( sizeof(geQKFrame_Squad) == geTKArray_ElementSize(*KeyList) + || sizeof(geQKFrame_Slerp) == geTKArray_ElementSize(*KeyList) + || sizeof(geQKFrame_Linear) == geTKArray_ElementSize(*KeyList) ); + + if (geTKArray_Insert(KeyList, Time, Index) == GE_FALSE) + { + geErrorLog_Add(ERR_QKARRAY_INSERT, NULL); + return GE_FALSE; + } + else + { + QKeyframe *KF; + KF = (QKeyframe *)geTKArray_Element(*KeyList,*Index); + KF->Q = *Q; + return GE_TRUE; + } +} + +void GENESISCC geQKFrame_Query( + const geTKArray *KeyList, // keyframe list + int Index, // index of frame to return + geTKArray_TimeType *Time, // time of the frame is returned + geQuaternion *Q) // vector from the frame is returned + // returns the vector and the time at keyframe[index] +{ + QKeyframe *KF; + assert( KeyList != NULL ); + assert( Time != NULL ); + assert( Q != NULL ); + assert( Index < geTKArray_NumElements(KeyList) ); + assert( Index >= 0 ); + assert( sizeof(geQKFrame_Squad) == geTKArray_ElementSize(KeyList) + || sizeof(geQKFrame_Slerp) == geTKArray_ElementSize(KeyList) + || sizeof(geQKFrame_Linear) == geTKArray_ElementSize(KeyList) ); + + KF = (QKeyframe *)geTKArray_Element(KeyList,Index); + *Time = KF->Time; + *Q = KF->Q; +} + +void GENESISCC geQKFrame_Modify( + geTKArray *KeyList, // keyframe list + int Index, // index of frame to change + const geQuaternion *Q) // vector for the new key +{ + QKeyframe *KF; + assert( KeyList != NULL ); + assert( Q != NULL ); + assert( Index < geTKArray_NumElements(KeyList) ); + assert( Index >= 0 ); + assert( sizeof(geQKFrame_Squad) == geTKArray_ElementSize(KeyList) + || sizeof(geQKFrame_Slerp) == geTKArray_ElementSize(KeyList) + || sizeof(geQKFrame_Linear) == geTKArray_ElementSize(KeyList) ); + + KF = (QKeyframe *)geTKArray_Element(KeyList,Index); + KF->Q = *Q; +} + + + +void GENESISCC geQKFrame_LinearInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result) // put the result in here (geQuaternion) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates linearly +{ + geQuaternion *Q1,*Q2; + geQuaternion *QNew = (geQuaternion *)Result; + + assert( Result != NULL ); + assert( KF1 != NULL ); + assert( KF2 != NULL ); + + assert( T >= (geFloat)0.0f ); + assert( T <= (geFloat)1.0f ); + + if ( KF1 == KF2 ) + { + *QNew = ((geQKFrame_Linear *)KF1)->Key.Q; + return; + } + + Q1 = &( ((geQKFrame_Linear *)KF1)->Key.Q); + Q2 = &( ((geQKFrame_Linear *)KF2)->Key.Q); + + QNew->X = LINEAR_BLEND(Q1->X,Q2->X,T); + QNew->Y = LINEAR_BLEND(Q1->Y,Q2->Y,T); + QNew->Z = LINEAR_BLEND(Q1->Z,Q2->Z,T); + QNew->W = LINEAR_BLEND(Q1->W,Q2->W,T); + if (geQuaternion_Normalize(QNew)==0.0f) + { + geQuaternion_SetNoRotation(QNew); + } + +} + + + +void GENESISCC geQKFrame_SlerpInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result) // put the result in here (geQuaternion) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates using spherical linear blending +{ + geQuaternion *Q1,*Q2; + geQuaternion *QNew = (geQuaternion *)Result; + + assert( Result != NULL ); + assert( KF1 != NULL ); + assert( KF2 != NULL ); + + assert( T >= (geFloat)0.0f ); + assert( T <= (geFloat)1.0f ); + + if ( KF1 == KF2 ) + { + *QNew = ((geQKFrame_Slerp *)KF1)->Key.Q; + return; + } + + Q1 = &( ((geQKFrame_Slerp *)KF1)->Key.Q); + Q2 = &( ((geQKFrame_Slerp *)KF2)->Key.Q); + geQuaternion_SlerpNotShortest(Q1,Q2,T,QNew); +} + + + + +void GENESISCC geQKFrame_SquadInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result) // put the result in here (geQuaternion) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates using spherical quadratic blending +{ + geQuaternion *Q1,*Q2; + geQuaternion *QNew = (geQuaternion *)Result; + + assert( Result != NULL ); + assert( KF1 != NULL ); + assert( KF2 != NULL ); + + assert( T >= (geFloat)0.0f ); + assert( T <= (geFloat)1.0f ); + + if ( KF1 == KF2 ) + { + *QNew = ((geQKFrame_Squad *)KF1)->Key.Q; + return; + } + + Q1 = &( ((geQKFrame_Squad *)KF1)->Key.Q); + Q2 = &( ((geQKFrame_Squad *)KF2)->Key.Q); + + { + geQuaternion *A1,*B2; + geQuaternion SL1,SL2; + + A1 = &( ((geQKFrame_Squad *)KF1)->QuadrangleCorner); + B2 = &( ((geQKFrame_Squad *)KF2)->QuadrangleCorner); + + geQuaternion_SlerpNotShortest(Q1, Q2, T, &SL1); + assert( geQuaternion_IsUnit(&SL1) == GE_TRUE); + geQuaternion_SlerpNotShortest(A1, B2, T, &SL2); + assert( geQuaternion_IsUnit(&SL2) == GE_TRUE); + geQuaternion_SlerpNotShortest(&SL1, &SL2, (2.0f*T*(1.0f-T)), QNew); + assert( geQuaternion_IsUnit(QNew) == GE_TRUE); + } +} + + +static void GENESISCC geQKFrame_QuadrangleCorner( + const geQuaternion *Q0, + const geQuaternion *Q1, + const geQuaternion *Q2, + geQuaternion *Corner) + // compute quadrangle corner for a keyframe containing Q1. + // Q0 and Q2 are the quaternions for the previous and next keyframes + // corner is the newly computed quaternion +{ + geQuaternion Q1Inv,LnSum; + + assert( Q0 != NULL ); + assert( Q1 != NULL ); + assert( Q2 != NULL ); + assert( Corner != NULL ); + + assert( geQuaternion_IsUnit(Q1) == GE_TRUE ); + + Q1Inv.W = Q1->W; + Q1Inv.X = -Q1->X; + Q1Inv.Y = -Q1->Y; + Q1Inv.Z = -Q1->Z; + + { + geQuaternion Q1InvQ2, Q1InvQ0; + geQuaternion Ln1,Ln2; + + geQuaternion_Multiply(&Q1Inv,Q2,&Q1InvQ2); + geQuaternion_Multiply(&Q1Inv,Q0,&Q1InvQ0); + geQuaternion_Ln(&Q1InvQ0,&Ln1); + geQuaternion_Ln(&Q1InvQ2,&Ln2); + geQuaternion_Add(&Ln1,&Ln2,&LnSum); + geQuaternion_Scale(&LnSum,-0.25f,&LnSum); + } + + geQuaternion_Exp(&LnSum,Corner); + geQuaternion_Multiply(Q1,Corner,Corner); +} + +static void GENESISCC geQKFrame_ChooseBestQuat(const geQuaternion *Q0,geQuaternion *Q1) + // adjusts the sign of Q1: to either Q1 or -Q1 + // adjusts Q1 such that Q1 is the 'closest' of the two choices to Q0. +{ + geQuaternion pLessQ,pPlusQ; + geFloat MagpLessQ,MagpPlusQ; + + assert( Q0 != NULL ); + assert( Q1 != NULL ); + + geQuaternion_Add(Q0,Q1,&pPlusQ); + geQuaternion_Subtract(Q0,Q1,&pLessQ); + + geQuaternion_Multiply(&pPlusQ,&pPlusQ,&pPlusQ); + geQuaternion_Multiply(&pLessQ,&pLessQ,&pLessQ); + + MagpLessQ= (pLessQ.W * pLessQ.W) + (pLessQ.X * pLessQ.X) + + (pLessQ.Y * pLessQ.Y) + (pLessQ.Z * pLessQ.Z); + + MagpPlusQ= (pPlusQ.W * pPlusQ.W) + (pPlusQ.X * pPlusQ.X) + + (pPlusQ.Y * pPlusQ.Y) + (pPlusQ.Z * pPlusQ.Z); + + if (MagpLessQ >= MagpPlusQ) + { + Q1->X = -Q1->X; + Q1->Y = -Q1->Y; + Q1->Z = -Q1->Z; + Q1->W = -Q1->W; + } +} + + + + +void GENESISCC geQKFrame_SquadRecompute( + int Looped, // if keylist has the first key connected to last key + geTKArray *KeyList) // list of keys to recompute hermite values for + // rebuild precomputed data for keyframe list. +{ + + // compute the extra interpolation points at each keyframe + // see Advanced Animation and Rendering Techniques + // by Alan Watt and Mark Watt, pg 366 + int i; + geQKFrame_Squad *QList=NULL; + int count; + + int Index0,Index1,Index2; + assert( KeyList != NULL ); + + count = geTKArray_NumElements(KeyList); + + if (count > 0) + { + QList = (geQKFrame_Squad *)geTKArray_Element(KeyList,0); + + for (i =0; i< count-1; i++) + { + geQKFrame_ChooseBestQuat(&(QList[i].Key.Q),&(QList[i+1].Key.Q) ); + } + } + + if (count<3) + { + Looped = 0; + // cant compute 'slopes' without enough points to loop. + // so treat path as non-looped. + } + for (i =0; i< count; i++) + { + Index0 = i-1; + Index1 = i; + Index2 = i+1; + + if (Index1 == 0) + { + if (Looped != GE_TRUE) + { + Index0 = 0; + } + else + { + Index0 = count-2; + } + } + + if (Index2 == count) + { + if (Looped != GE_TRUE) + { + Index2 = count-1; + } + else + { + Index2 = 1; + } + } + + if (( Looped != GE_TRUE) && (Index1 == 0) ) + { + geQuaternion_Copy( + &(QList[i].Key.Q), + &(QList[i].QuadrangleCorner) ); + } + else if (( Looped != GE_TRUE) && (Index1 == count-1)) + { + geQuaternion_Copy( + &(QList[i].Key.Q), + &(QList[i].QuadrangleCorner) ); + } + else + { + geQKFrame_QuadrangleCorner( + &(QList[Index0].Key.Q), + &(QList[Index1].Key.Q), + &(QList[Index2].Key.Q), + &(QList[i].QuadrangleCorner) ); + + } + } +} + + + +void GENESISCC geQKFrame_SlerpRecompute( + geTKArray *KeyList) // list of keys to recompute hermite values for + // rebuild precomputed data for keyframe list. + // also make sure that each successive key is the 'closest' quaternion choice + // to the previous one. +{ + + int i; + geQKFrame_Slerp *QList; + int count; + assert( KeyList != NULL ); + + count = geTKArray_NumElements(KeyList); + + if (count > 0) + { + QList = (geQKFrame_Slerp *)geTKArray_Element(KeyList,0); + for (i =0; i< count-1; i++) + { + geQKFrame_ChooseBestQuat(&(QList[i].Key.Q),&(QList[i+1].Key.Q) ); + } + } +} + + +#define QKFRAME_LINEAR_ASCII_FILE 0x4C464B51 // 'QKFL' +#define QKFRAME_SLERP_ASCII_FILE 0x53464B51 // 'QKFS' +#define QKFRAME_SQUAD_ASCII_FILE 0x51464B51 // 'QKFQ' +#define CHECK_FOR_WRITE(uu) if(uu <= 0) { geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); return GE_FALSE; } +#define CHECK_FOR_READ(uu, nn) if(uu != nn) { geErrorLog_Add(ERR_PATH_FILE_READ, NULL); return GE_FALSE; } + +#define QKFRAME_KEYLIST_ID "Keys" + +//------------------------------------------------------------------------ +// support for older data files + +geBoolean GENESISCC geQKFrame_LinearRead(geVFile* pFile, void* geQKFrame) +{ + uint32 u; + char QKeyString[64]; + geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geQKFrame; + + assert( pFile != NULL ); + assert( geQKFrame != NULL ); + + // Read the format/version flag + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + + if(u != QKFRAME_LINEAR_ASCII_FILE) + { + geErrorLog_Add(ERR_PATH_FILE_VERSION, NULL); + return GE_FALSE; + } + + if (geVFile_GetS(pFile, QKeyString, sizeof(QKeyString)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + + u = sscanf(QKeyString, "%f %f %f %f\n", &pLinear->Key.Q.W, + &pLinear->Key.Q.X, + &pLinear->Key.Q.Y, + &pLinear->Key.Q.Z); + CHECK_FOR_READ(u, 4); + + return GE_TRUE; +} + +geBoolean GENESISCC geQKFrame_SlerpRead(geVFile* pFile, void* geQKFrame) +{ + uint32 u; + char QKeyString[64]; + geQKFrame_Slerp* pSlerp = (geQKFrame_Slerp*)geQKFrame; + + assert( pFile != NULL ); + assert( geQKFrame != NULL ); + + // Read the format/version flag + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + + if(u != QKFRAME_SLERP_ASCII_FILE) + { + geErrorLog_Add(ERR_PATH_FILE_VERSION, NULL); + return GE_FALSE; + } + + if (geVFile_GetS(pFile, QKeyString, sizeof(QKeyString)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + + u = sscanf(QKeyString, "%f %f %f %f\n", &pSlerp->Key.Q.W, + &pSlerp->Key.Q.X, + &pSlerp->Key.Q.Y, + &pSlerp->Key.Q.Z); + CHECK_FOR_READ(u, 4); + + return GE_TRUE; +} + + +geBoolean GENESISCC geQKFrame_SquadRead(geVFile* pFile, void* geQKFrame) +{ + uint32 u; + char SQuadKeyString[128]; + geQKFrame_Squad* pSquad = (geQKFrame_Squad*)geQKFrame; + + assert( pFile != NULL ); + assert( geQKFrame != NULL ); + + // Read the format/version flag + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + + if(u != QKFRAME_SQUAD_ASCII_FILE) + { + geErrorLog_Add(ERR_PATH_FILE_VERSION, NULL); + return GE_FALSE; + } + + if (geVFile_GetS(pFile, SQuadKeyString, sizeof(SQuadKeyString)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + + u = sscanf(SQuadKeyString, "%f %f %f %f %f %f %f %f\n", &pSquad->Key.Q.W, + &pSquad->Key.Q.X, + &pSquad->Key.Q.Y, + &pSquad->Key.Q.Z, + &pSquad->QuadrangleCorner.W, + &pSquad->QuadrangleCorner.X, + &pSquad->QuadrangleCorner.Y, + &pSquad->QuadrangleCorner.Z); + CHECK_FOR_READ(u, 8); + + return GE_TRUE; +} + +//------------------------------------------------------------------------ +#define QKFRAME_HINGE_COMPRESSION 0x1 +#define QKFRAME_LINEARTIME_COMPRESSION 0x2 + + +#define HINGE_TOLERANCE (0.0001f) +#define LINEARTIME_TOLERANCE (0.0001f) + +static geBoolean GENESISCC geQKFrame_PathIsHinged(geTKArray *KeyList, geFloat Tolerance) +{ + int i,Count; + geVec3d Axis; + geVec3d NextAxis; + geFloat Angle; + geQKFrame_Linear* pLinear; + + assert( KeyList != NULL ); + + Count = geTKArray_NumElements(KeyList); + + if (Count<2) + return GE_FALSE; + pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, 0); + if (geQuaternion_GetAxisAngle(&(pLinear->Key.Q),&Axis,&Angle)==GE_FALSE) + { + return GE_FALSE; + } + + for (i=1; iKey.Q),&NextAxis,&Angle)==GE_FALSE) + { + return GE_FALSE; + } + + if (geVec3d_Compare(&Axis,&NextAxis,Tolerance) == GE_FALSE) + { + return GE_FALSE; + } + } + return GE_TRUE; +} + + +static int GENESISCC geQKFrame_DetermineCompressionType(geTKArray *KeyList) +{ + int Compression=0; + int NumElements=0; + + assert( KeyList != NULL ); + + NumElements = geTKArray_NumElements(KeyList); + + if (NumElements>2) + { + if ( geTKArray_SamplesAreTimeLinear(KeyList,LINEARTIME_TOLERANCE) != GE_FALSE ) + { + Compression |= QKFRAME_LINEARTIME_COMPRESSION; + } + } + + + if (NumElements>3) + { + if ( geQKFrame_PathIsHinged(KeyList,HINGE_TOLERANCE)!=GE_FALSE ) + { + Compression |= QKFRAME_HINGE_COMPRESSION; + } + } + + return Compression; +} + + + +geBoolean GENESISCC geQKFrame_WriteToFile(geVFile *pFile, geTKArray *KeyList, + geQKFrame_InterpolationType InterpolationType, int Looping) +{ + int NumElements,i; + geFloat Time,DeltaTime; + int Compression; + + assert( pFile != NULL ); + assert( KeyList != NULL ); + + NumElements = geTKArray_NumElements(KeyList); + + Compression = geQKFrame_DetermineCompressionType(KeyList); + + if (geVFile_Printf(pFile, + "%s %d %d %d %d\n", + QKFRAME_KEYLIST_ID, + NumElements, + InterpolationType, + Compression, + Looping) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); + return GE_FALSE; + } + + if (Compression & QKFRAME_LINEARTIME_COMPRESSION) + { + Time = geTKArray_ElementTime(KeyList, 0); + DeltaTime = geTKArray_ElementTime(KeyList, 1)- Time; + if (geVFile_Printf(pFile,"%f %f Start T,Delta T\n",Time,DeltaTime) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); + return GE_FALSE; + } + } + + switch (Compression & (~QKFRAME_LINEARTIME_COMPRESSION) ) + { + case (0): + { + for(i=0;iKey.Q.W, pLinear->Key.Q.X, + pLinear->Key.Q.Y, pLinear->Key.Q.Z) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); + return GE_FALSE; + } + } + } + break; + case (QKFRAME_HINGE_COMPRESSION): + { + geVec3d Hinge; + geFloat Angle; + + geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, 0); + geQuaternion_GetAxisAngle(&(pLinear->Key.Q),&Hinge,&Angle); + geVec3d_Normalize(&Hinge); + if (geVFile_Printf(pFile,"%f %f %f Axis\n",Hinge.X,Hinge.Y,Hinge.Z) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); + return GE_FALSE; + } + for(i=0;iKey.Q),&Hinge,&Angle); + if (geVFile_Printf(pFile,"%f\n", Angle) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); + return GE_FALSE; + } + } + } + break; + default: + assert(0); + + } + return GE_TRUE; +} + + +geTKArray *GENESISCC geQKFrame_CreateFromFile(geVFile *pFile, int *InterpolationType, int *Looping) +{ + int i,u,NumElements; + int Compression; + geFloat StartTime=0.0f; + geFloat DeltaTime=0.0f; + + #define ERROREXIT {geErrorLog_Add( ERR_PATH_FILE_READ, NULL);if (KeyList != NULL){geTKArray_Destroy(&KeyList);} return NULL;} + + #define LINE_LENGTH 256 + char line[LINE_LENGTH]; + geTKArray *KeyList=NULL; + + assert( pFile != NULL ); + assert( InterpolationType != NULL ); + + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + ERROREXIT; + if(strnicmp(line, QKFRAME_KEYLIST_ID, sizeof(QKFRAME_KEYLIST_ID)-1) != 0) + ERROREXIT; + + if(sscanf(line + sizeof(QKFRAME_KEYLIST_ID)-1, "%d %d %d %d", + &NumElements,InterpolationType,&Compression,Looping) != 4) + ERROREXIT; + + if (!( (*InterpolationType == QKFRAME_LINEAR) || (*InterpolationType == QKFRAME_SLERP) || (*InterpolationType == QKFRAME_SQUAD) )) + ERROREXIT; + + if ( Compression > 0xFF) + ERROREXIT; + + + + switch (*InterpolationType) + { + case (QKFRAME_LINEAR): + KeyList = geTKArray_CreateEmpty(sizeof(geQKFrame_Linear),NumElements); + break; + case (QKFRAME_SLERP): + KeyList = geTKArray_CreateEmpty(sizeof(geQKFrame_Slerp),NumElements); + break; + case (QKFRAME_SQUAD): + KeyList = geTKArray_CreateEmpty(sizeof(geQKFrame_Squad),NumElements); + break; + default: + ERROREXIT; + } + if (KeyList == NULL) + ERROREXIT; + + if (Compression & QKFRAME_LINEARTIME_COMPRESSION) + { + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + ERROREXIT; + if (sscanf(line,"%f %f",&StartTime,&DeltaTime) != 2) + ERROREXIT; + } + switch (Compression & (~QKFRAME_LINEARTIME_COMPRESSION) ) + { + case (0): + { + for(i=0;iKey.Time = StartTime + DeltaTime * i; + u = sscanf(line,"%f %f %f %f", &(pLinear->Key.Q.W), + &(pLinear->Key.Q.X),&(pLinear->Key.Q.Y),&(pLinear->Key.Q.Z)); + if (u==4) u = 5; + } + else + { + u = sscanf(line,"%f %f %f %f %f",&(pLinear->Key.Time), &(pLinear->Key.Q.W), + &(pLinear->Key.Q.X),&(pLinear->Key.Q.Y),&(pLinear->Key.Q.Z)); + } + if (u!=5) + ERROREXIT; + } + } + break; + case (QKFRAME_HINGE_COMPRESSION): + { + geVec3d Hinge; + geFloat Angle; + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + ERROREXIT; + u = sscanf(line,"%f %f %f",&(Hinge.X),&(Hinge.Y),&(Hinge.Z) ); + if (u != 3) + ERROREXIT; + for(i=0;iKey.Time = StartTime + DeltaTime * i; + u = sscanf(line,"%f", &(Angle)); + if (u==1) u = 2; + } + else + { + u = sscanf(line,"%f %f",&(pLinear->Key.Time), &(Angle) ); + } + if (u!=2) + ERROREXIT; + geQuaternion_SetFromAxisAngle(&(pLinear->Key.Q),&Hinge,Angle); + } + } + break; + default: + assert(0); + + } + + switch (*InterpolationType) + { + case (QKFRAME_LINEAR): + break; + case (QKFRAME_SLERP): + geQKFrame_SlerpRecompute( KeyList); + break; + case (QKFRAME_SQUAD): + geQKFrame_SquadRecompute( *Looping, KeyList); + break; + default: + assert(0); + } + return KeyList; + +} + +uint32 GENESISCC geQKFrame_ComputeBlockSize(geTKArray *KeyList, int Compression) +{ + uint32 Size=0; + int Count; + assert( KeyList != NULL ); + assert( Compression < 0xFF); + + Count = geTKArray_NumElements(KeyList); + + Size += sizeof(uint32); // flags + Size += sizeof(uint32); // count + + if (Compression & QKFRAME_LINEARTIME_COMPRESSION) + { + Size += sizeof(geFloat) * 2; + } + else + { + Size += sizeof(geFloat) * Count; + } + + switch (Compression & (~QKFRAME_LINEARTIME_COMPRESSION) ) + { + case 0: + Size += sizeof(geQuaternion) * Count; + break; + case QKFRAME_HINGE_COMPRESSION: + Size += (sizeof(geFloat) * 3) + sizeof(geFloat) * Count; + break; + default: + assert(0); + } + return Size; +} + +geTKArray *GENESISCC geQKFrame_CreateFromBinaryFile(geVFile *pFile, int *InterpolationType, int *Looping) +{ + uint32 u; + int BlockSize; + int Compression; + int Count,i; + int FieldSize; + char *Block; + geFloat *Data; + geTKArray *KeyList; + geQKFrame_Linear* pLinear0; + geQKFrame_Linear* pLinear; + + assert( pFile != NULL ); + assert( InterpolationType != NULL ); + assert( Looping != NULL ); + + if (geVFile_Read(pFile, &BlockSize, sizeof(int)) == GE_FALSE) + { + geErrorLog_AddString(-1,"Failure to read binary QKFrame header", NULL); + return NULL; + } + if (BlockSize<0) + { + geErrorLog_AddString(-1,"Bad Blocksize", NULL); + return NULL; + } + + Block = geRam_Allocate(BlockSize); + if(geVFile_Read(pFile, Block, BlockSize) == GE_FALSE) + { + geErrorLog_AddString(-1,"Failure to read binary QKFrame header", NULL); + return NULL; + } + u = *(uint32 *)Block; + *InterpolationType = (u>>16)& 0xFF; + Compression = (u>>8) & 0xFF; + *Looping = (u & 0x1); + Count = *(((uint32 *)Block)+1); + + if (Compression > 0xFF) + { + geRam_Free(Block); + geErrorLog_AddString(-1,"Bad Compression Flag", NULL); + return NULL; + } + switch (*InterpolationType) + { + case (QKFRAME_LINEAR): + FieldSize = sizeof(geQKFrame_Linear); + break; + case (QKFRAME_SLERP): + FieldSize = sizeof(geQKFrame_Slerp); + break; + case (QKFRAME_SQUAD): + FieldSize = sizeof(geQKFrame_Squad); + break; + default: + geRam_Free(Block); + geErrorLog_AddString(-1,"Bad InterpolationType", NULL); + return NULL; + } + + KeyList = geTKArray_CreateEmpty(FieldSize,Count); + if (KeyList == NULL) + { + geRam_Free(Block); + geErrorLog_AddString(-1,"Failed to allocate tkarray", NULL); + return NULL; + } + + Data = (geFloat *)(Block + sizeof(uint32)*2); + + pLinear0 = (geQKFrame_Linear*)geTKArray_Element(KeyList, 0); + + pLinear = pLinear0; + + if (Compression & QKFRAME_LINEARTIME_COMPRESSION) + { + geFloat fi; + geFloat fCount = (geFloat)Count; + geFloat Time,DeltaTime; + Time = *(Data++); + DeltaTime = *(Data++); + for(fi=0.0f;fiKey.Time = Time + fi*DeltaTime; + pLinear = (geQKFrame_Linear *) ( ((char *)pLinear) + FieldSize ); + } + } + else + { + for(i=0;iKey.Time = *(Data++); + pLinear = (geQKFrame_Linear *) ( ((char *)pLinear) + FieldSize ); + } + } + + pLinear = pLinear0; + + if (Compression & QKFRAME_HINGE_COMPRESSION) + { + geVec3d Hinge; + Hinge.X = *(Data++); + Hinge.Y = *(Data++); + Hinge.Z = *(Data++); + + for(i=0;iKey.Q),&Hinge,*(Data++)); + pLinear = (geQKFrame_Linear *) ( ((char *)pLinear) + FieldSize ); + } + } + else + { + for(i=0;iKey.Q = *(geQuaternion *)Data; + Data += 4; + pLinear = (geQKFrame_Linear *) ( ((char *)pLinear) + FieldSize ); + } + } + + switch (*InterpolationType) + { + case (QKFRAME_LINEAR): + break; + case (QKFRAME_SLERP): + geQKFrame_SlerpRecompute( KeyList); + break; + case (QKFRAME_SQUAD): + geQKFrame_SquadRecompute( *Looping, KeyList); + break; + default: + assert(0); + } + geRam_Free(Block); + return KeyList; +} + +geBoolean GENESISCC geQKFrame_WriteToBinaryFile(geVFile *pFile, geTKArray *KeyList, + geQKFrame_InterpolationType InterpolationType, int Looping) +{ + #define WBERREXIT {geErrorLog_AddString( ERR_PATH_FILE_WRITE,"Failure to write binary key data", NULL);return GE_FALSE;} + uint32 u,BlockSize; + int Compression; + int Count,i; + geFloat Time,DeltaTime; + assert( pFile != NULL ); + assert( InterpolationType < 0xFF); + assert( (Looping == 0) || (Looping == 1) ); + + + Compression = geQKFrame_DetermineCompressionType(KeyList); + u = (InterpolationType << 16) | (Compression << 8) | Looping; + + BlockSize = geQKFrame_ComputeBlockSize(KeyList,Compression); + + if (geVFile_Write(pFile, &BlockSize,sizeof(uint32)) == GE_FALSE) + WBERREXIT; + + if (geVFile_Write(pFile, &u, sizeof(uint32)) == GE_FALSE) + WBERREXIT; + + Count = geTKArray_NumElements(KeyList); + if (geVFile_Write(pFile, &Count, sizeof(uint32)) == GE_FALSE) + WBERREXIT; + + if (Compression & QKFRAME_LINEARTIME_COMPRESSION) + { + Time = geTKArray_ElementTime(KeyList, 0); + DeltaTime = geTKArray_ElementTime(KeyList, 1)- Time; + if (geVFile_Write(pFile, &Time,sizeof(geFloat)) == GE_FALSE) + WBERREXIT; + if (geVFile_Write(pFile, &DeltaTime,sizeof(geFloat)) == GE_FALSE) + WBERREXIT; + } + else + { + for(i=0;iKey.Q),&Hinge,&Angle); + geVec3d_Normalize(&Hinge); + if (geVFile_Write(pFile, &Hinge,sizeof(geVec3d)) == GE_FALSE) + WBERREXIT; + + for(i=0;iKey.Q),&Hinge,&Angle); + if (geVFile_Write(pFile, &Angle,sizeof(geFloat)) == GE_FALSE) + WBERREXIT; + } + } + else + { + for(i=0;iKey.Q),sizeof(geQuaternion)) == GE_FALSE) + WBERREXIT; + } + } + + return GE_TRUE; +} diff --git a/G3D/Actor/QKFrame.h b/G3D/Actor/QKFrame.h new file mode 100644 index 0000000..45ab0bb --- /dev/null +++ b/G3D/Actor/QKFrame.h @@ -0,0 +1,151 @@ +/****************************************************************************************/ +/* QKFRAME.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Quaternion keyframe interface. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +/* geQKFrame (geQuaternion - Keyframe) + This module handles interpolation for keyframes that contain a quaternion + This is intended to support Path.c + geTKArray supplies general support for a time-keyed array, and this supplements + that support to include the specific time-keyed arrays: + An array of geQuaternion interpolated linearly + An array of geQuaternion with spherical linear interpolation (SLERP) + An array of geQuaternion with spherical quadrangle + interpolation (SQUAD) as defined by: + Advanced Animation and Rendering Techniques by Alan Watt and Mark Watt + + These are phycially separated and have different base structures because + the different interpolation techniques requre different additional data. + + The two lists are created with different creation calls, + interpolated with different calls, but insertion and queries share a call. + + Quadrangle interpolation requires additional computation after changes are + made to the keyframe list. Call geQKFrame_SquadRecompute() to update the + calculations. +*/ +#ifndef GE_QKFRAME_H +#define GE_QKFRAME_H + + +#include "TKArray.h" +#include "Quatern.h" +#include "vfile.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + QKFRAME_LINEAR, + QKFRAME_SLERP, + QKFRAME_SQUAD +} geQKFrame_InterpolationType; + + +geTKArray *GENESISCC geQKFrame_LinearCreate(void); + // creates a frame list for linear interpolation + +geTKArray *GENESISCC geQKFrame_SlerpCreate(); + // creates a frame list for spherical linear interpolation + +geTKArray *GENESISCC geQKFrame_SquadCreate(); + // creates a frame list for spherical linear interpolation + + +geBoolean GENESISCC geQKFrame_Insert( + geTKArray **KeyList, // keyframe list to insert into + geTKArray_TimeType Time, // time of new keyframe + const geQuaternion *Q, // quaternion at new keyframe + int *Index); // index of new frame + // inserts a new keyframe with the given time and vector into the list. + +void GENESISCC geQKFrame_Query( + const geTKArray *KeyList, // keyframe list + int Index, // index of frame to return + geTKArray_TimeType *Time, // time of the frame is returned + geQuaternion *V); // vector from the frame is returned + // returns the vector and the time at keyframe[index] + +void GENESISCC geQKFrame_Modify( + geTKArray *KeyList, // keyframe list + int Index, // index of frame to change + const geQuaternion *Q); // vector for the new key + // modifies a vector at keyframe[index] + +void GENESISCC geQKFrame_LinearInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result); // put the result in here (geQuaternion) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates linearly + +void GENESISCC geQKFrame_SlerpInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result); // put the result in here (geQuaternion) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates using spherical linear blending + +void GENESISCC geQKFrame_SquadInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result); // put the result in here (geQuaternion) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates using spherical quadratic blending + +void GENESISCC geQKFrame_SquadRecompute( + int Looped, // if keylist has the first key connected to last key + geTKArray *KeyList); + // rebuild precomputed data for keyframe list. + +void GENESISCC geQKFrame_SlerpRecompute( + geTKArray *KeyList); // list of keys to recompute hermite values for + // rebuild precomputed data for keyframe list. + + +geBoolean GENESISCC geQKFrame_LinearRead(geVFile* pFile, void* geQKFrame); +geBoolean GENESISCC geQKFrame_SlerpRead(geVFile* pFile, void* geQKFrame); +geBoolean GENESISCC geQKFrame_SquadRead(geVFile* pFile, void* geQKFrame); + +geBoolean GENESISCC geQKFrame_WriteToFile(geVFile *pFile, void *geQKFrame, + geQKFrame_InterpolationType InterpolationType, int Looping); +geTKArray *GENESISCC geQKFrame_CreateFromFile(geVFile *pFile, geQKFrame_InterpolationType *InterpolationType, int *Looping); +geTKArray *GENESISCC geQKFrame_CreateFromBinaryFile(geVFile *pFile, int *InterpolationType, int *Looping); +geBoolean GENESISCC geQKFrame_WriteToBinaryFile(geVFile *pFile, geTKArray *KeyList, + geQKFrame_InterpolationType InterpolationType, int Looping); + + + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/G3D/Actor/XFArray.c b/G3D/Actor/XFArray.c new file mode 100644 index 0000000..829b608 --- /dev/null +++ b/G3D/Actor/XFArray.c @@ -0,0 +1,101 @@ +/****************************************************************************************/ +/* XFARRAY.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Array of transforms implementation. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include "XFArray.h" +#include "Ram.h" +#include "ErrorLog.h" + + +typedef struct geXFArray +{ + int TransformCount; + geXForm3d *TransformArray; +} geXFArray; + +geXFArray *GENESISCC geXFArray_Create(int Size) +{ + geXFArray *XFA; + + assert( Size > 0 ); + + XFA = GE_RAM_ALLOCATE_STRUCT( geXFArray ); + if (XFA == NULL) + { + geErrorLog_Add( ERR_XFARRAY_ENOMEM , NULL); + return NULL; + } + XFA->TransformArray = GE_RAM_ALLOCATE_ARRAY(geXForm3d,Size); + if (XFA->TransformArray == NULL) + { + geErrorLog_Add( ERR_XFARRAY_ENOMEM , NULL); + geRam_Free( XFA ); + return NULL; + } + XFA->TransformCount = Size; + { + geXForm3d X; + geXForm3d_SetIdentity(&X); + geXFArray_SetAll(XFA,&X); + } + return XFA; +} + +void GENESISCC geXFArray_Destroy( geXFArray **XFA ) +{ + assert( XFA != NULL ); + assert( *XFA != NULL ); + assert( (*XFA)->TransformCount > 0 ); + assert( (*XFA)->TransformArray != NULL ); + + (*XFA)->TransformCount = -1; + geRam_Free( (*XFA)->TransformArray); + (*XFA)->TransformArray = NULL; + geRam_Free( (*XFA) ); + (*XFA) = NULL; +} + +geXForm3d *GENESISCC geXFArray_GetElements(const geXFArray *XFA, int *Size) +{ + assert( XFA != NULL ); + assert( Size != NULL ); + assert( XFA->TransformCount > 0 ); + assert( XFA->TransformArray != NULL ); + + *Size = XFA->TransformCount; + return XFA->TransformArray; +} + +void GENESISCC geXFArray_SetAll(geXFArray *XFA, const geXForm3d *Matrix) +{ + assert( XFA != NULL ); + assert( Matrix != NULL ); + assert( XFA->TransformCount > 0 ); + assert( XFA->TransformArray != NULL ); + { + int i; + geXForm3d *X; + for (i=0,X=XFA->TransformArray; iTransformCount; i++,X++) + { + *X = *Matrix; + } + } +} diff --git a/G3D/Actor/actor.c b/G3D/Actor/actor.c new file mode 100644 index 0000000..5d128f3 --- /dev/null +++ b/G3D/Actor/actor.c @@ -0,0 +1,2001 @@ +/****************************************************************************************/ +/* ACTOR.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Actor implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +/* + + TODO: + make cued motions keyed to a 'root' bone. Register the root bone, and then + all requests are relative to that bone, rather than the current 'anchor' point. + actually, this doesn't really change much, just _AnimationCue() - and it allows + a more efficient _TestStep() + + +*/ +#include +#include //strnicmp memmove() +#include // fabs() +#include //sscanf + +#include "world.h" // to expose _Render apis in actor.h + +#include "Actor.h" +#include "Ram.h" +#include "Puppet.h" +#include "Body.h" +#include "Motion.h" +#include "ErrorLog.h" +#include "strblock.h" +#ifdef _DEBUG +#include +#endif + +/* to do: + need to utilize extbox module rather than hard coding vector corners of boxes + (BoundingBoxMinCorner,BoundingBoxMaxCorner) +*/ + +#define ACTOR_MOTIONS_MAX 0x0FFFF // really arbitrary. just for sanity checking +#define ACTOR_CUES_MAX 0x0FFFF // arbitrary. + +typedef struct geActor +{ + int32 RefCount; // this is the number of owners. + gePuppet *Puppet; + gePose *Pose; + geActor_BlendingType BlendingType; + geActor_Def *ActorDefinition; // actor definition this is an instance of + + geMotion *CueMotion; + geVec3d BoundingBoxMinCorner; + geVec3d BoundingBoxMaxCorner; + int BoundingBoxCenterBoneIndex; + int StepBoneIndex; // used for single-bone motion optimization. + void * UserData; + + geExtBox RenderHintExtBox; + int RenderHintExtBoxCenterBoneIndex; + geBoolean RenderHintExtBoxEnabled; +} geActor; + + +typedef struct geActor_Def +{ + geBody *Body; + geVFile * TextureFileContext; + + int32 MotionCount; + geMotion **MotionArray; + + int32 RefCount; // this is the number of owners. + + geActor_Def *ValidityCheck; +} geActor_Def; + + // these are useful globals to monitor resources +int geActor_Count = 0; +int geActor_RefCount = 0; +int geActor_DefCount = 0; +int geActor_DefRefCount = 0; + + // returns number of actors that are currently created. +GENESISAPI int GENESISCC geActor_GetCount(void) +{ + return geActor_Count; +} + +GENESISAPI geBoolean GENESISCC geActor_IsValid(const geActor *A) +{ + if (A==NULL) + return GE_FALSE; + if (geActor_DefIsValid(A->ActorDefinition)==GE_FALSE) + return GE_FALSE; + if (A->Pose == NULL) + return GE_FALSE; + if (A->CueMotion == NULL) + return GE_FALSE; + if (geBody_IsValid(A->ActorDefinition->Body) == GE_FALSE ) + return GE_FALSE; + + return GE_TRUE; +} + + +//MRB BEGIN +GENESISAPI void GENESISCC geActor_GetNonWorldExtBox(const geActor *A, geExtBox *ExtBox) +{ + assert( geActor_IsValid(A) != GE_FALSE); + assert( ExtBox != NULL ); + + geVec3d_Copy(&(A->BoundingBoxMinCorner), &(ExtBox->Min)); + geVec3d_Copy(&(A->BoundingBoxMaxCorner), &(ExtBox->Max)); +} +GENESISAPI void GENESISCC geActor_GetPosition(const geActor *A, geVec3d *Pos) +{ + geXForm3d Transform; + assert( geActor_IsValid(A) != GE_FALSE); + assert( Pos != NULL ); + gePose_GetJointTransform( A->Pose, + A->BoundingBoxCenterBoneIndex, + &Transform); + assert ( geXForm3d_IsOrthonormal(&Transform) != GE_FALSE ); + geVec3d_Copy(&(Transform.Translation), Pos); +} +//MRB END + +// LWM_ACTOR_RENDERING: +GENESISAPI geFloat GENESISCC geActor_GetAlpha(const geActor *A) +{ + assert( A != NULL ) ; + assert( A->Puppet != NULL ) ; + return gePuppet_GetAlpha(A->Puppet); +} + +// LWM_ACTOR_RENDERING: +GENESISAPI void GENESISCC geActor_SetAlpha(geActor *A, geFloat Alpha) +{ + assert( A != NULL ) ; + assert( A->Puppet != NULL ) ; + gePuppet_SetAlpha( A->Puppet, Alpha ) ; +} + +GENESISAPI geBoolean GENESISCC geActor_DefIsValid(const geActor_Def *A) +{ + if (A==NULL) + return GE_FALSE; + if (A->ValidityCheck != A) + return GE_FALSE; + return GE_TRUE; +} + +static geBoolean GENESISCC geActor_GetBoneIndex(const geActor *A, const char *BoneName, int *BoneIndex) +{ + geXForm3d Dummy; + int ParentBoneIndex; + assert( geActor_IsValid(A) != GE_FALSE); + assert( BoneIndex != NULL ); + + if ( BoneName != NULL ) + { + if (geBody_GetBoneByName(A->ActorDefinition->Body, + BoneName, + BoneIndex, + &Dummy, + &ParentBoneIndex) ==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone not found:", BoneName); + //geErrorLog_AppendString(BoneName); + return GE_FALSE; + } + } + else + { + *BoneIndex = GE_POSE_ROOT_JOINT; + } + return GE_TRUE; +} + + +GENESISAPI geActor_Def *GENESISCC geActor_GetActorDef(const geActor *A) +{ + assert( geActor_DefIsValid(A->ActorDefinition) != GE_FALSE ); + return A->ActorDefinition; +} + +GENESISAPI void GENESISCC geActor_DefCreateRef(geActor_Def *A) +{ + assert( geActor_DefIsValid(A) != GE_FALSE ); + A->RefCount++; + geActor_DefRefCount++; +} + +GENESISAPI geActor_Def *GENESISCC geActor_DefCreate(void) +{ + geActor_Def *Ad; + + Ad = GE_RAM_ALLOCATE_STRUCT( geActor_Def ); + if ( Ad == NULL ) + { + geErrorLog_Add( ERR_ACTOR_ENOMEM , NULL); + return NULL; + } + + Ad->Body = NULL; + Ad->MotionCount = 0; + Ad->MotionArray = NULL; + Ad->ValidityCheck = Ad; + Ad->RefCount = 0; + geActor_DefCount++; + return Ad; +} + +GENESISAPI void GENESISCC geActor_CreateRef(geActor *Actor) +{ + assert( geActor_IsValid(Actor) ); + Actor->RefCount ++; + geActor_RefCount++; +} + +GENESISAPI geActor *GENESISCC geActor_Create(geActor_Def *ActorDefinition) +{ + geActor *A; + assert( geActor_DefIsValid(ActorDefinition) != GE_FALSE ); + + if (ActorDefinition->Body == NULL) + { + geErrorLog_AddString(-1,"geActor_Def must have a body before Actors can be created", NULL); + return NULL; + } + assert( geBody_IsValid(ActorDefinition->Body) != GE_FALSE ); + + A = GE_RAM_ALLOCATE_STRUCT( geActor ); + if ( A == NULL ) + { + geErrorLog_Add( ERR_ACTOR_ENOMEM , NULL); + goto ActorCreateFailure; + } + A->Puppet = NULL; + A->Pose = NULL; + A->CueMotion = NULL; + + A->Pose = gePose_Create(); + if (A->Pose == NULL) + { + geErrorLog_Add(ERR_ACTOR_ENOMEM, NULL); + goto ActorCreateFailure; + } + + A->RefCount = 0; + A->BlendingType = GE_ACTOR_BLEND_HERMITE; + A->ActorDefinition = ActorDefinition; + A->CueMotion = geMotion_Create(GE_TRUE); + A->BoundingBoxCenterBoneIndex = GE_POSE_ROOT_JOINT; + A->RenderHintExtBoxCenterBoneIndex = GE_POSE_ROOT_JOINT; + A->RenderHintExtBoxEnabled = GE_FALSE; + A->StepBoneIndex = GE_POSE_ROOT_JOINT; + geExtBox_Set(&(A->RenderHintExtBox), 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f); + if (A->CueMotion == NULL) + { + geErrorLog_Add( ERR_ACTOR_ENOMEM , NULL); + goto ActorCreateFailure; + } + + + { + int i; + int BoneCount; + + BoneCount = geBody_GetBoneCount(A->ActorDefinition->Body); + for (i=0; iActorDefinition->Body, i, &Name,&Attachment, &ParentBone ); + if (gePose_AddJoint( A->Pose, + ParentBone,Name,&Attachment,&Index)==GE_FALSE) + { + geErrorLog_Add(ERR_ACTOR_ENOMEM, NULL); + goto ActorCreateFailure; + } + } + } + + + geVec3d_Clear(&(A->BoundingBoxMinCorner)); + geVec3d_Clear(&(A->BoundingBoxMaxCorner)); + assert( geActor_IsValid(A) != GE_FALSE ); + geActor_DefCreateRef(ActorDefinition); + geActor_Count++; + return A; + + ActorCreateFailure: + if ( A!= NULL) + { + if (A->Pose != NULL) + gePose_Destroy(&(A->Pose)); + if (A->CueMotion != NULL) + geMotion_Destroy(&(A->CueMotion)); + geRam_Free( A ); + } + return NULL; +} + +GENESISAPI geBoolean GENESISCC geActor_DefDestroy(geActor_Def **pActorDefinition) +{ + int i; + geActor_Def *Ad; + assert( pActorDefinition != NULL ); + assert( *pActorDefinition != NULL ); + assert( geActor_DefIsValid( *pActorDefinition ) != GE_FALSE ); + + Ad = *pActorDefinition; + + if (Ad->RefCount > 0) + { + Ad->RefCount--; + geActor_DefRefCount--; + return GE_FALSE; + } + + if (Ad->Body != NULL) + { + geBody_Destroy( &(Ad->Body) ); + Ad->Body = NULL; + } + if (Ad->MotionArray != NULL) + { + for (i=0; iMotionCount; i++) + { + geMotion_Destroy( &(Ad->MotionArray[i]) ); + Ad->MotionArray[i] = NULL; + } + geRam_Free( Ad->MotionArray ); + Ad->MotionArray = NULL; + } + + Ad->MotionCount = 0; + + geRam_Free(*pActorDefinition); + *pActorDefinition = NULL; + geActor_DefCount--; + return GE_TRUE; +} + + +GENESISAPI geBoolean GENESISCC geActor_Destroy(geActor **pA) +{ + geActor *A; + assert( pA != NULL ); + assert( *pA != NULL ); + assert( geActor_IsValid(*pA) != GE_FALSE ); + + A = *pA; + if (A->RefCount > 0) + { + A->RefCount --; + geActor_RefCount--; + return GE_FALSE; + } + + geActor_DefDestroy(&(A->ActorDefinition)); + if (A->Puppet != NULL) + { + gePuppet_Destroy( &(A->Puppet) ); + A->Puppet = NULL; + } + if ( A->Pose != NULL ) + { + gePose_Destroy( &( A->Pose ) ); + A->Pose = NULL; + } + if ( A->CueMotion != NULL ) + { + geMotion_Destroy(&(A->CueMotion)); + A->CueMotion = NULL; + } + geRam_Free(*pA); + geActor_Count--; + *pA = NULL; + return GE_TRUE; + +} + + +GENESISAPI geBoolean GENESISCC geActor_DestroyDirect(geActor **pA) +{ + geActor *CurrentActor=NULL; + int i=0; + + // dumb brute force deletion of actors in ActorArray + + // destroy the actor + CurrentActor = *pA; + + if(!CurrentActor) + return GE_FALSE; + + gePuppet_Destroy( &(CurrentActor->Puppet) ); + gePose_Destroy( &( CurrentActor->Pose ) ); + geMotion_Destroy(&(CurrentActor->CueMotion)); + + assert( _CrtIsValidPointer( &CurrentActor->ActorDefinition, sizeof(CurrentActor->ActorDefinition), FALSE ) ); + + if(geActor_DefIsValid(CurrentActor->ActorDefinition)==GE_TRUE ) + { + // destroy the definition + if (CurrentActor->ActorDefinition->Body != NULL) + { + geBody_Destroy( &(CurrentActor->ActorDefinition->Body) ); + CurrentActor->ActorDefinition->Body = NULL; + } + if (CurrentActor->ActorDefinition->MotionArray != NULL) + { + for (i=0; iActorDefinition->MotionCount; i++) + { + geMotion_Destroy( &(CurrentActor->ActorDefinition->MotionArray[i]) ); + CurrentActor->ActorDefinition->MotionArray[i] = NULL; + } + geRam_Free( CurrentActor->ActorDefinition->MotionArray ); + CurrentActor->ActorDefinition->MotionArray = NULL; + } + + CurrentActor->ActorDefinition->TextureFileContext=NULL; + CurrentActor->ActorDefinition->ValidityCheck = NULL; + + //free the def + geRam_Free(CurrentActor->ActorDefinition); + CurrentActor->ActorDefinition = NULL; + + } + + CurrentActor->UserData = NULL; + + // free the actor + geRam_Free(CurrentActor); + CurrentActor = NULL; + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geActor_SetBody( geActor_Def *ActorDefinition, geBody *BodyGeometry) +{ + assert( geBody_IsValid(BodyGeometry) != GE_FALSE ); + + if (ActorDefinition->RefCount > 0) + { + geErrorLog_Add(-1, NULL); // ActorDef already used by a body. cant change now + return GE_FALSE; + } + + if (ActorDefinition->Body != NULL) + { + geBody_Destroy( &(ActorDefinition->Body) ); + } + + ActorDefinition->Body = BodyGeometry; + return GE_TRUE; +} + + +#pragma message ("consider removing this and related parameters to setpose") +GENESISAPI void GENESISCC geActor_SetBlendingType( geActor *A, geActor_BlendingType BlendingType ) +{ + assert( geActor_IsValid(A) != GE_FALSE ); + + assert( (BlendingType == GE_ACTOR_BLEND_LINEAR) || + (BlendingType == GE_ACTOR_BLEND_HERMITE) ); + + if (BlendingType == GE_ACTOR_BLEND_LINEAR) + { + A->BlendingType = GE_POSE_BLEND_LINEAR; + } + else + { + A->BlendingType = GE_POSE_BLEND_HERMITE; + } +} + +GENESISAPI geVFile *geActor_DefGetFileContext(const geActor_Def *A) +{ + assert( geActor_DefIsValid(A) != GE_FALSE ); + return A->TextureFileContext; +} + + + +GENESISAPI geBoolean GENESISCC geActor_AddMotion(geActor_Def *Ad, geMotion *NewMotion, int *Index) +{ + geMotion **NewMArray; + assert( geActor_DefIsValid(Ad) != GE_FALSE ); + assert( NewMotion != NULL ); + assert( Index != NULL ); + + if (Ad->MotionCount >= ACTOR_MOTIONS_MAX) + { + geErrorLog_Add(ERR_ACTOR_TOO_MANY_MOTIONS, NULL); + return GE_FALSE; + } + NewMArray = GE_RAM_REALLOC_ARRAY( Ad->MotionArray, geMotion*, Ad->MotionCount +1 ); + if ( NewMArray == NULL ) + { + geErrorLog_Add(ERR_ACTOR_ENOMEM, NULL); + return GE_FALSE; + } + + Ad->MotionArray = NewMArray; + + Ad->MotionArray[Ad->MotionCount]= NewMotion; + Ad->MotionCount++; + *Index = Ad->MotionCount; + return GE_TRUE; +}; + +GENESISAPI void GENESISCC geActor_ClearPose(geActor *A, const geXForm3d *Transform) +{ + assert( geActor_IsValid(A) != GE_FALSE ); + assert ( (Transform==NULL) || (geXForm3d_IsOrthonormal(Transform) != GE_FALSE) ); + gePose_Clear( A->Pose ,Transform); +} + +GENESISAPI void GENESISCC geActor_SetPose(geActor *A, const geMotion *M, + geFloat Time, const geXForm3d *Transform) +{ + assert( geActor_IsValid(A) != GE_FALSE ); + assert( M != NULL ); + assert ( (Transform==NULL) || (geXForm3d_IsOrthonormal(Transform) != GE_FALSE) ); + + gePose_SetMotion( A->Pose,M,Time,Transform); +} + +GENESISAPI void GENESISCC geActor_BlendPose(geActor *A, const geMotion *M, + geFloat Time, + const geXForm3d *Transform, + geFloat BlendAmount) +{ + assert( geActor_IsValid(A) != GE_FALSE ); + assert( M != NULL ); + assert ( (Transform==NULL) || (geXForm3d_IsOrthonormal(Transform) != GE_FALSE) ); + + gePose_BlendMotion( A->Pose,M,Time,Transform, + BlendAmount,A->BlendingType); +} + + +GENESISAPI int GENESISCC geActor_GetMotionCount(const geActor_Def *Ad) +{ + assert( geActor_DefIsValid(Ad) != GE_FALSE ); + return Ad->MotionCount; +} + + +GENESISAPI geMotion *GENESISCC geActor_GetMotionByIndex(const geActor_Def *Ad, int Index ) +{ + assert( geActor_DefIsValid(Ad) != GE_FALSE ); + assert( Index >= 0 ); + assert( Index < Ad->MotionCount ); + assert( Ad->MotionArray != NULL ); + + return Ad->MotionArray[Index]; +} + +GENESISAPI geMotion *GENESISCC geActor_GetMotionByName(const geActor_Def *Ad, const char *Name ) +{ + int i; + const char *TestName; + assert( geActor_DefIsValid(Ad) != GE_FALSE ); + assert( Name != NULL ); + for (i=0; iMotionCount; i++) + { + TestName = geMotion_GetName(Ad->MotionArray[i]); + if (TestName != NULL) + { + if (strcmp(TestName,Name)==0) + return Ad->MotionArray[i]; + } + + } + return NULL; +} + +GENESISAPI const char *GENESISCC geActor_GetMotionName(const geActor_Def *Ad, int Index ) +{ + assert( geActor_DefIsValid(Ad) != GE_FALSE ); + assert( Index >= 0 ); + assert( Index < Ad->MotionCount ); + assert( Ad->MotionArray != NULL ); + return geMotion_GetName(Ad->MotionArray[Index]); +} + +GENESISAPI geBody *GENESISCC geActor_GetBody(const geActor_Def *Ad) +{ + assert( geActor_DefIsValid(Ad) != GE_FALSE ); + return Ad->Body; +} + +#pragma message ("Keep this function: geActor_DefHasBoneNamed()?") +// Returns GE_TRUE if the actor definition has a bone named 'Name' +GENESISAPI geBoolean GENESISCC geActor_DefHasBoneNamed(const geActor_Def *Ad, const char *Name ) +{ + int DummyIndex,DummyParent; + geXForm3d DummyAttachment; + + assert( geActor_DefIsValid(Ad) != GE_FALSE ); + assert( Name != NULL ); + if (geBody_GetBoneByName(geActor_GetBody(Ad),Name, + &DummyIndex, &DummyAttachment, &DummyParent ) == GE_FALSE ) + { + return GE_FALSE; + } + return GE_TRUE; +} + + +#define GE_ACTOR_BODY_NAME "Body" +#define GE_ACTOR_HEADER_NAME "Header" +#define GE_MOTION_DIRECTORY_NAME "Motions" + +#define ACTOR_FILE_TYPE 0x52544341 // 'ACTR' +#define ACTOR_FILE_VERSION 0x00F1 // Restrict version to 16 bits + + + +static geActor_Def * GENESISCC geActor_DefCreateHeader(geVFile *pFile, geBoolean *HasBody) +{ + uint32 u; + uint32 version; + geActor_Def *Ad; + + assert( pFile != NULL ); + assert( HasBody != NULL ); + + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); return NULL;} + if (u != ACTOR_FILE_TYPE) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); return NULL;} + + if(geVFile_Read(pFile, &version, sizeof(version)) == GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); return NULL;} + if ( (version != ACTOR_FILE_VERSION) ) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); return NULL;} + + Ad = geActor_DefCreate(); + if (Ad==NULL) + { geErrorLog_Add( ERR_ACTOR_ENOMEM , NULL); return NULL; } + + Ad->TextureFileContext = geVFile_GetContext(pFile); + assert(Ad->TextureFileContext); + + if(geVFile_Read(pFile, HasBody, sizeof(*HasBody)) == GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); geActor_DefDestroy(&Ad); return NULL;} + + if(geVFile_Read(pFile, &(Ad->MotionCount), sizeof(Ad->MotionCount)) == GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); geActor_DefDestroy(&Ad); return NULL;} + + return Ad; +} + + +static geBoolean GENESISCC geActor_DefWriteHeader(const geActor_Def *Ad, geVFile *pFile) +{ + uint32 u; + geBoolean Flag; + + assert( geActor_DefIsValid(Ad) != GE_FALSE ); + assert( pFile != NULL ); + + // Write the format flag + u = ACTOR_FILE_TYPE; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); return GE_FALSE; } + + + u = ACTOR_FILE_VERSION; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); return GE_FALSE;} + + if (Ad->Body != NULL) + Flag = GE_TRUE; + else + Flag = GE_FALSE; + + if(geVFile_Write(pFile, &Flag, sizeof(Flag)) == GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); return GE_FALSE;} + + if(geVFile_Write(pFile, &(Ad->MotionCount), sizeof(Ad->MotionCount)) == GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); return GE_FALSE;} + + return GE_TRUE; +} + + + +GENESISAPI geActor_Def *GENESISCC geActor_DefCreateFromFile(geVFile *pFile) +{ + int i; + geActor_Def *Ad = NULL; + geVFile *VFile = NULL; + geVFile *SubFile = NULL; + geVFile *MotionDirectory = NULL; + geBoolean HasBody = GE_FALSE; + geBody * Body = NULL; + + assert( pFile != NULL ); + + VFile = geVFile_OpenNewSystem(pFile,GE_VFILE_TYPE_VIRTUAL, NULL, + NULL, GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_READONLY); + if (VFile == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); goto CreateError;} + + SubFile = geVFile_Open(VFile,GE_ACTOR_HEADER_NAME,GE_VFILE_OPEN_READONLY); + if (SubFile == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); goto CreateError;} + + Ad = geActor_DefCreateHeader(SubFile,&HasBody); + if (Ad == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); goto CreateError;} + geVFile_Close(SubFile); + + + if (HasBody != GE_FALSE) + { + SubFile = geVFile_Open(VFile,GE_ACTOR_BODY_NAME,GE_VFILE_OPEN_READONLY); + if (SubFile == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); goto CreateError;} + + Body = geBody_CreateFromFile(SubFile); + if (Body == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); goto CreateError; } + if (geActor_SetBody(Ad,Body)==GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_ENOMEM , NULL); goto CreateError; } + geVFile_Close(SubFile); + } + + MotionDirectory = geVFile_Open(VFile,GE_MOTION_DIRECTORY_NAME, + GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_READONLY); + if (MotionDirectory == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); return NULL;} + + if (Ad->MotionCount>0) + { + Ad->MotionArray = GE_RAM_ALLOCATE_ARRAY( geMotion*, Ad->MotionCount); + for (i=0; iMotionCount; i++) + Ad->MotionArray[i] = NULL; + + for (i=0; iMotionCount; i++) + { + char FName[1000]; + sprintf(FName,"%d",i); + + SubFile = geVFile_Open(MotionDirectory,FName,GE_VFILE_OPEN_READONLY); + if (SubFile == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); goto CreateError;} + Ad->MotionArray[i] = geMotion_CreateFromFile(SubFile); + if (Ad->MotionArray[i] == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_READ , NULL); goto CreateError;} + geVFile_Close(SubFile); + } + } + else + { + Ad->MotionArray = NULL; + } + geVFile_Close(MotionDirectory); + geVFile_Close(VFile); + return Ad; + + CreateError: + if (SubFile != NULL) + geVFile_Close(SubFile); + if (MotionDirectory != NULL) + geVFile_Close(MotionDirectory); + if (VFile != NULL) + geVFile_Close(VFile); + if (Ad != NULL) + geActor_DefDestroy(&Ad); + return NULL; +} + + +GENESISAPI geBoolean GENESISCC geActor_DefWriteToFile(const geActor_Def *Ad, geVFile *pFile) +{ + int i; + geVFile *VFile; + geVFile *SubFile; + geVFile *MotionDirectory; + + assert( geActor_DefIsValid(Ad) != GE_FALSE ); + assert( pFile != NULL ); + + VFile = geVFile_OpenNewSystem(pFile,GE_VFILE_TYPE_VIRTUAL, NULL, + NULL, GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_CREATE); + if (VFile == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + + SubFile = geVFile_Open(VFile,GE_ACTOR_HEADER_NAME,GE_VFILE_OPEN_CREATE); + if (SubFile == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + + if (geActor_DefWriteHeader(Ad,SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + if (geVFile_Close(SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + + if (Ad->Body != NULL) + { + SubFile = geVFile_Open(VFile,GE_ACTOR_BODY_NAME,GE_VFILE_OPEN_CREATE); + if (SubFile == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + if (geBody_WriteToFile(Ad->Body,SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + if (geVFile_Close(SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + } + + MotionDirectory = geVFile_Open(VFile,GE_MOTION_DIRECTORY_NAME, + GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_CREATE); + if (MotionDirectory == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + + for (i=0; iMotionCount; i++) + { + char FName[1000]; + sprintf(FName,"%d",i); + + SubFile = geVFile_Open(MotionDirectory,FName,GE_VFILE_OPEN_CREATE); + if (SubFile == NULL) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + if (geMotion_WriteToBinaryFile(Ad->MotionArray[i],SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + if (geVFile_Close(SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + } + + if (geVFile_Close(MotionDirectory)==GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + if (geVFile_Close(VFile)==GE_FALSE) + { geErrorLog_Add( ERR_ACTOR_FILE_WRITE , NULL); goto WriteError;} + + return GE_TRUE; + WriteError: + return GE_FALSE; +} + +GENESISAPI geBoolean GENESISCC geActor_GetBoneTransform(const geActor *A, const char *BoneName, geXForm3d *Transform) +{ + int BoneIndex; + + assert( geActor_IsValid(A)!=GE_FALSE ); + assert( Transform!= NULL ); + + if (geActor_GetBoneIndex(A,BoneName,&BoneIndex)==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone not found", BoneName); + return GE_FALSE; + } + + gePose_GetJointTransform( A->Pose, BoneIndex, Transform); + assert ( geXForm3d_IsOrthonormal(Transform) != GE_FALSE ); + + return GE_TRUE; +} + + +GENESISAPI geBoolean GENESISCC geActor_GetBoneTransformByIndex(const geActor *A, int BoneIndex, geXForm3d *Transform) +{ + assert( geActor_IsValid(A)!=GE_FALSE ); + assert( Transform!= NULL ); + + gePose_GetJointTransform( A->Pose, BoneIndex, Transform); + assert ( geXForm3d_IsOrthonormal(Transform) != GE_FALSE ); + + return GE_TRUE; +} + +static void GENESISCC geActor_AccumulateMinMax( + geVec3d *P,geVec3d *Mins,geVec3d *Maxs) +{ + assert( geVec3d_IsValid( P ) != GE_FALSE ); + assert( geVec3d_IsValid(Mins) != GE_FALSE ); + assert( geVec3d_IsValid(Maxs) != GE_FALSE ); + + if (P->X < Mins->X) Mins->X = P->X; + if (P->Y < Mins->Y) Mins->Y = P->Y; + if (P->Z < Mins->Z) Mins->Z = P->Z; + + if (P->X > Maxs->X) Maxs->X = P->X; + if (P->Y > Maxs->Y) Maxs->Y = P->Y; + if (P->Z > Maxs->Z) Maxs->Z = P->Z; +} + + +static geBoolean GENESISCC geActor_GetBoneBoundingBoxByIndex( + const geActor *A, + int BoneIndex, + geVec3d *Corner, + geVec3d *DX, + geVec3d *DY, + geVec3d *DZ) +{ + geVec3d Min,Max; + geVec3d Orientation; + geXForm3d Transform; + + assert( geActor_IsValid(A) != GE_FALSE ); + assert( geActor_DefIsValid(A->ActorDefinition) != GE_FALSE ); + assert( A->ActorDefinition->Body != NULL ); + + assert( Corner ); + assert( DX ); + assert( DY ); + assert( DZ ); + assert( (BoneIndex < gePose_GetJointCount(A->Pose)) || (BoneIndex ==GE_POSE_ROOT_JOINT)); + assert( (BoneIndex >=0) || (BoneIndex ==GE_POSE_ROOT_JOINT)); + + if (geBody_GetBoundingBox( A->ActorDefinition->Body, BoneIndex, &Min, &Max )==GE_FALSE) + { + return GE_FALSE; + } + + // scale bounding box: + { + geVec3d Scale; + gePose_GetScale(A->Pose, &Scale); + assert( geVec3d_IsValid(&Scale) != GE_FALSE ); + + Min.X *= Scale.X; + Min.Y *= Scale.Y; + Min.Z *= Scale.Z; + + Max.X *= Scale.X; + Max.Y *= Scale.Y; + Max.Z *= Scale.Z; + } + + + gePose_GetJointTransform(A->Pose,BoneIndex,&(Transform)); + + geVec3d_Subtract(&Max,&Min,&Orientation); + + DX->X = Orientation.X; DX->Y = DX->Z = 0.0f; + DY->Y = Orientation.Y; DY->X = DY->Z = 0.0f; + DZ->Z = Orientation.Z; DZ->X = DZ->Y = 0.0f; + + // transform into world space + geXForm3d_Transform(&(Transform),&Min,&Min); + geXForm3d_Rotate(&(Transform),DX,DX); + geXForm3d_Rotate(&(Transform),DY,DY); + geXForm3d_Rotate(&(Transform),DZ,DZ); + + *Corner = Min; + return GE_TRUE; +} + + + +GENESISAPI geBoolean GENESISCC geActor_GetBoneExtBoxByIndex( + const geActor *A, + int BoneIndex, + geExtBox *ExtBox) +{ + geVec3d Min; + geVec3d DX,DY,DZ,Corner; + + assert( ExtBox ); + + if (geActor_GetBoneBoundingBoxByIndex(A,BoneIndex,&Min,&DX,&DY,&DZ)==GE_FALSE) + { + return GE_FALSE; + } + + ExtBox->Min = Min; + ExtBox->Max = Min; + Corner = Min; + // should use extent box (extbox) methods rather than this + geVec3d_Add(&Corner,&DX,&Corner); + geActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max)); + geVec3d_Add(&Corner,&DZ,&Corner); + geActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max)); + geVec3d_Subtract(&Corner,&DX,&Corner); + geActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max)); + geVec3d_Add(&Corner,&DY,&Corner); + geActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max)); + geVec3d_Add(&Corner,&DX,&Corner); + geActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max)); + geVec3d_Subtract(&Corner,&DZ,&Corner); + geActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max)); + geVec3d_Subtract(&Corner,&DX,&Corner); + geActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max)); + + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geActor_GetBoneExtBox(const geActor *A, + const char *BoneName, + geExtBox *ExtBox) +{ + int BoneIndex; + assert( geActor_IsValid(A) != GE_FALSE); + assert( ExtBox != NULL ); + + if (geActor_GetBoneIndex(A,BoneName,&BoneIndex)==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone for bounding box not found", BoneName); + return GE_FALSE; + } + return geActor_GetBoneExtBoxByIndex(A,BoneIndex,ExtBox); +} + + +GENESISAPI geBoolean GENESISCC geActor_GetBoneBoundingBox(const geActor *A, + const char *BoneName, + geVec3d *Corner, + geVec3d *DX, + geVec3d *DY, + geVec3d *DZ) +{ + int BoneIndex; + assert( geActor_IsValid(A) != GE_FALSE); + assert( Corner != NULL ); + assert( DX != NULL ); + assert( DY != NULL ); + assert( DZ != NULL ); + + if (geActor_GetBoneIndex(A,BoneName,&BoneIndex)==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone for bounding box not found", BoneName); + return GE_FALSE; + } + if (geActor_GetBoneBoundingBoxByIndex(A,BoneIndex,Corner,DX,DY,DZ)==GE_FALSE) + { + geErrorLog_AddString(-1,"Failed to get bounding box named:", BoneName); + //geErrorLog_AppendString(BoneName); + return GE_FALSE; + } + return GE_TRUE; +} + + + +GENESISAPI geBoolean GENESISCC geActor_GetExtBox(const geActor *A, geExtBox *ExtBox) +{ + geXForm3d Transform; + + assert( geActor_IsValid(A) != GE_FALSE); + assert( ExtBox != NULL ); + + gePose_GetJointTransform( A->Pose, + A->BoundingBoxCenterBoneIndex, + &Transform); + assert ( geXForm3d_IsOrthonormal(&Transform) != GE_FALSE ); + geVec3d_Add( &(Transform.Translation), &(A->BoundingBoxMinCorner), &(ExtBox->Min)); + geVec3d_Add( &(Transform.Translation), &(A->BoundingBoxMaxCorner), &(ExtBox->Max)); + return GE_TRUE; +} + + +GENESISAPI geBoolean GENESISCC geActor_SetExtBox(geActor *A, + const geExtBox *ExtBox, + const char *CenterOnThisNamedBone) +{ + + assert( geActor_IsValid(A) != GE_FALSE); + assert( geExtBox_IsValid(ExtBox) != GE_FALSE); + + A->BoundingBoxMinCorner = ExtBox->Min; + A->BoundingBoxMaxCorner = ExtBox->Max; + + if (geActor_GetBoneIndex(A,CenterOnThisNamedBone,&(A->BoundingBoxCenterBoneIndex))==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone for bounding box not found", CenterOnThisNamedBone); + return GE_FALSE; + } + + return GE_TRUE; +} + + + // Gets the rendering hint bounding box from the actor +GENESISAPI geBoolean GENESISCC geActor_GetRenderHintExtBox(const geActor *A, geExtBox *Box, geBoolean *Enabled) +{ + geXForm3d Transform; + + assert( geActor_IsValid(A) != GE_FALSE); + assert( Box != NULL ); + assert( Enabled != NULL ); + + gePose_GetJointTransform( A->Pose, + A->RenderHintExtBoxCenterBoneIndex, + &Transform); + assert ( geXForm3d_IsOrthonormal(&Transform) != GE_FALSE ); + + *Box = A->RenderHintExtBox; + geExtBox_Translate ( Box, Transform.Translation.X, + Transform.Translation.Y, + Transform.Translation.Z ); + + *Enabled = A->RenderHintExtBoxEnabled; + return GE_TRUE; +} + + // Sets a rendering hint bounding box from the actor +GENESISAPI geBoolean GENESISCC geActor_SetRenderHintExtBox(geActor *A, const geExtBox *Box, + const char *CenterOnThisNamedBone) +{ + assert( geActor_IsValid(A) != GE_FALSE); + assert( Box != NULL ); + assert( Box->Max.X >= Box->Min.X ); + assert( Box->Max.Y >= Box->Min.Y ); + assert( Box->Max.Z >= Box->Min.Z ); + + if (geActor_GetBoneIndex(A,CenterOnThisNamedBone,&(A->RenderHintExtBoxCenterBoneIndex))==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone for render hint box not found", CenterOnThisNamedBone); + return GE_FALSE; + } + + A->RenderHintExtBox = *Box; + if ( (Box->Min.X == 0.0f) && (Box->Max.X == 0.0f) + && (Box->Min.Y == 0.0f) && (Box->Max.Y == 0.0f) + && (Box->Min.Z == 0.0f) && (Box->Max.Z == 0.0f) ) + { + A->RenderHintExtBoxEnabled = GE_FALSE; + } + else + { + A->RenderHintExtBoxEnabled = GE_TRUE; + } + + return GE_TRUE; +} + + +GENESISAPI void *GENESISCC geActor_GetUserData(const geActor *A) +{ + assert( geActor_IsValid(A) != GE_FALSE); + return A->UserData; +} + +GENESISAPI void GENESISCC geActor_SetUserData(geActor *A, void *UserData) +{ + assert( geActor_IsValid(A) != GE_FALSE); + A->UserData = UserData; +} + +#define MAX(aa,bb) ( (aa)>(bb)?(aa):(bb) ) +#define MIN(aa,bb) ( (aa)<(bb)?(aa):(bb) ) + +static void GENESISCC geActor_StretchBoundingBox( geVec3d *Min, geVec3d *Max, + const geVec3d *Corner, + const geVec3d *DX, const geVec3d *DY, const geVec3d *DZ) +{ + geVec3d P; + + P = *Corner; + Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z); + Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z); + + geVec3d_Add (Corner ,DX,&P); + Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z); + Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z); + + geVec3d_Add (&P, DZ,&P); + Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z); + Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z); + + geVec3d_Subtract(&P,DX,&P); + Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z); + Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z); + + geVec3d_Add (&P,DY,&P); + Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z); + Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z); + + geVec3d_Add (&P,DX,&P); + Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z); + Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z); + + geVec3d_Subtract(&P,DZ,&P); + Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z); + Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z); + + geVec3d_Subtract(&P,DX,&P); + Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z); + Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z); +} + +// eaa3 07/27/2000 + +GENESISAPI int geActor_GetBoneCount(const geActor *A) +{ + return geBody_GetBoneCount( A->ActorDefinition->Body ); +} + +GENESISAPI geBoolean GENESISCC geActor_GetDynamicExtBox( const geActor *A, geExtBox *ExtBox) +{ +#define GE_ACTOR_REALLY_BIG_NUMBER (9e9f) + + geVec3d Corner; + geVec3d DX; + geVec3d DY; + geVec3d DZ; + int Count,i,BCount; + + assert( geActor_IsValid(A) != GE_FALSE); + assert( A->ActorDefinition->Body != NULL ); + + geVec3d_Set(&(ExtBox->Min), + GE_ACTOR_REALLY_BIG_NUMBER,GE_ACTOR_REALLY_BIG_NUMBER,GE_ACTOR_REALLY_BIG_NUMBER); + geVec3d_Set(&(ExtBox->Max), + -GE_ACTOR_REALLY_BIG_NUMBER,-GE_ACTOR_REALLY_BIG_NUMBER,-GE_ACTOR_REALLY_BIG_NUMBER); + + BCount = 0; + Count = geBody_GetBoneCount( A->ActorDefinition->Body ); + for (i=0; i< Count; i++) + { + if (geActor_GetBoneBoundingBoxByIndex(A,i,&Corner,&DX,&DY,&DZ)!=GE_FALSE) + { + geActor_StretchBoundingBox( &(ExtBox->Min), + &(ExtBox->Max),&Corner,&DX,&DY,&DZ); + BCount ++; + } + } + if (BCount>0) + { + return GE_TRUE; + } + return GE_FALSE; +} + + + +GENESISAPI geBoolean GENESISCC geActor_Attach( geActor *Slave, const char *SlaveBoneName, + const geActor *Master, const char *MasterBoneName, + const geXForm3d *Attachment) +{ + int SlaveBoneIndex,MasterBoneIndex; + + assert( geActor_IsValid(Slave) != GE_FALSE); + assert( geActor_IsValid(Master) != GE_FALSE); + assert( geXForm3d_IsOrthonormal(Attachment) != GE_FALSE ); + + assert( MasterBoneName != NULL ); // might this be possible? + + if (geActor_GetBoneIndex(Slave,SlaveBoneName,&(SlaveBoneIndex))==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone for slave not found", SlaveBoneName); + return GE_FALSE; + } + + if (geActor_GetBoneIndex(Master,MasterBoneName,&(MasterBoneIndex))==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone for master not found", MasterBoneName); + return GE_FALSE; + } + + return gePose_Attach( Slave->Pose, SlaveBoneIndex, + Master->Pose, MasterBoneIndex, + Attachment); +} + + +GENESISAPI void GENESISCC geActor_Detach(geActor *A) +{ + assert( geActor_IsValid(A) != GE_FALSE); + + gePose_Detach( A->Pose ); +} + + +GENESISAPI geBoolean GENESISCC geActor_GetBoneAttachment(const geActor *A, + const char *BoneName, + geXForm3d *Attachment) +{ + + int BoneIndex; + assert( geActor_IsValid(A) != GE_FALSE); + assert( Attachment != NULL ); + + if (geActor_GetBoneIndex(A,BoneName,&(BoneIndex))==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone not found", BoneName); + return GE_FALSE; + } + + gePose_GetJointAttachment(A->Pose,BoneIndex, Attachment); + assert ( geXForm3d_IsOrthonormal(Attachment) != GE_FALSE ); + + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geActor_SetBoneAttachment(geActor *A, + const char *BoneName, + geXForm3d *Attachment) +{ + + int BoneIndex; + + assert( geActor_IsValid(A) != GE_FALSE); + assert( geXForm3d_IsOrthonormal(Attachment) != GE_FALSE ); + + if (geActor_GetBoneIndex(A,BoneName,&(BoneIndex))==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone not found", BoneName); + return GE_FALSE; + } + + gePose_SetJointAttachment(A->Pose,BoneIndex, Attachment); + return GE_TRUE; +} + + +//------------------------------------------------------------------------------------------------- +// Actor Cuing system +//------------------------------------------------------------------------------------------------- +#define ACTOR_CUE_MINIMUM_BLEND (0.0001f) +#define ACTOR_CUE_MAXIMUM_BLEND (0.999f) + + +static geBoolean GENESISCC geActor_IsAnimationCueDead(geActor *A, int Index) +{ + geBoolean Kill= GE_FALSE; + geFloat BlendAmount; + geMotion *M; + assert( geActor_IsValid(A) != GE_FALSE); + assert( (Index>=0) && (IndexCueMotion))); + + M = A->CueMotion; + + BlendAmount = geMotion_GetBlendAmount(M,Index,0.0f); + if (BlendAmount <= ACTOR_CUE_MINIMUM_BLEND) + { + int KeyCount; + gePath *P; + geFloat KeyTime; + + P = geMotion_GetBlendPath(M,Index); + assert( P != NULL ); + KeyCount = gePath_GetKeyframeCount(P,GE_PATH_TRANSLATION_CHANNEL); + if (KeyCount>0) + { + geXForm3d Dummy; + geFloat TimeOffset = -geMotion_GetTimeOffset( M, Index); + gePath_GetKeyframe( P, KeyCount-1, GE_PATH_TRANSLATION_CHANNEL, &KeyTime, &Dummy ); + + if ( KeyTime <= TimeOffset ) + { + Kill = GE_TRUE; + } + } + else + { + Kill = GE_TRUE; + } + } + return Kill; +} + + +static void GENESISCC geActor_KillCue( geActor *A, int Index ) +{ + geMotion *M; + assert( geActor_IsValid(A) != GE_FALSE); + assert( (Index>=0) && (IndexCueMotion))); + M = geMotion_RemoveSubMotion(A->CueMotion,Index); +} + +GENESISAPI geBoolean GENESISCC geActor_AnimationNudge(geActor *A, geXForm3d *Offset) +{ + geMotion *M; + int i,Count; + assert( geActor_IsValid(A) != GE_FALSE); + assert( geXForm3d_IsOrthonormal(Offset) != GE_FALSE ); + M = A->CueMotion; + Count = geMotion_GetSubMotionCount(M); + + for (i=Count-1; i>=0; i--) + { + geXForm3d Transform; + const geXForm3d *pTransform; + pTransform = geMotion_GetBaseTransform( M, i ); + if ( pTransform != NULL ) + { + Transform = *pTransform; + + geXForm3d_Multiply(Offset,&Transform,&Transform); + geXForm3d_Orthonormalize(&Transform); + + geMotion_SetBaseTransform( M, i, &Transform); + } + } + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geActor_AnimationRemoveLastCue( geActor *A ) +{ + int Count; + assert( geActor_IsValid(A) != GE_FALSE); + Count = geMotion_GetSubMotionCount(A->CueMotion); + if (Count>0) + { + geActor_KillCue( A, Count-1 ); + return GE_TRUE; + } + return GE_FALSE; +} + +GENESISAPI geBoolean GENESISCC geActor_AnimationCue( geActor *A, + geMotion *Motion, + geFloat TimeScaleFactor, + geFloat TimeIntoMotion, + geFloat BlendTime, + geFloat BlendFromAmount, + geFloat BlendToAmount, + const geXForm3d *MotionTransform) +{ + int Index; + + assert( geActor_IsValid(A) != GE_FALSE); + + assert( (BlendFromAmount>=0.0f) && (BlendFromAmount<=1.0f)); + assert( ( BlendToAmount>=0.0f) && ( BlendToAmount<=1.0f)); + assert( (MotionTransform==NULL) || (geXForm3d_IsOrthonormal(MotionTransform)) != GE_FALSE ); + + assert( Motion != NULL ); + + assert( BlendTime >= 0.0f); + if (BlendTime==0.0f) + { + BlendFromAmount = BlendToAmount; + BlendTime = 1.0f; // anything that is > GE_TKA_TIME_TOLERANCE + } + + if (geMotion_AddSubMotion( A->CueMotion, TimeScaleFactor, -TimeIntoMotion, Motion, + TimeIntoMotion, BlendFromAmount, + TimeIntoMotion + BlendTime, BlendToAmount, + MotionTransform, &Index )==GE_FALSE) + { + return GE_FALSE; + } + + return GE_TRUE; +} + + +GENESISAPI geBoolean GENESISCC geActor_AnimationStep(geActor *A, geFloat DeltaTime ) +{ + int i,Coverage,Count; + geMotion *M; + geMotion *SubM; + + assert( geActor_IsValid(A) != GE_FALSE); + assert( DeltaTime >= 0.0f ); + + gePose_ClearCoverage(A->Pose,0); + + M = A->CueMotion; + + Count = geMotion_GetSubMotionCount(M); + + for (i=Count-1; i>=0; i--) + { + geFloat TimeOffset = geMotion_GetTimeOffset( M, i ); + TimeOffset = TimeOffset - DeltaTime; + geMotion_SetTimeOffset( M, i, TimeOffset); + + if (geActor_IsAnimationCueDead(A,i)) + { + geActor_KillCue(A,i); + } + else + { + geBoolean SetWithBlending= GE_TRUE; + geFloat BlendAmount; + + SubM = geMotion_GetSubMotion(M,i); + assert( SubM != NULL ); + + BlendAmount = geMotion_GetBlendAmount( M,i,0.0f ); + + if (BlendAmount >= ACTOR_CUE_MAXIMUM_BLEND) + { + SetWithBlending = GE_FALSE; + } + Coverage = gePose_AccumulateCoverage(A->Pose,SubM, SetWithBlending); + if ( Coverage == 0 ) + { + geActor_KillCue(A,i); + } + } + } + + gePose_SetMotion( A->Pose, M, 0.0f, NULL ); + geMotion_SetupEventIterator(M,-DeltaTime,0.0f); + + return GE_TRUE; +} + + +GENESISAPI geBoolean GENESISCC geActor_AnimationStepBoneOptimized(geActor *A, geFloat DeltaTime, const char *BoneName ) +{ + int i,Coverage,Count; + geMotion *M; + geMotion *SubM; + + assert( geActor_IsValid(A) != GE_FALSE); + assert( DeltaTime >= 0.0f ); + + if (BoneName == NULL) + { + A->StepBoneIndex = GE_POSE_ROOT_JOINT; + } + else + { + geBoolean LookupBoneName= GE_TRUE; + const char *LastBoneName; + geXForm3d Attachment; + int LastParentBoneIndex; + if (A->StepBoneIndex >= 0) + { + geBody_GetBone( A->ActorDefinition->Body,A->StepBoneIndex,&LastBoneName,&Attachment,&LastParentBoneIndex); + if ( (LastBoneName != NULL) ) + if (strcmp(LastBoneName,BoneName)==0) + LookupBoneName = GE_FALSE; + } + if (LookupBoneName != GE_FALSE) + { + if (geActor_GetBoneIndex(A,BoneName,&(A->StepBoneIndex))==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone not found", BoneName); + return GE_FALSE; + } + } + } + + + gePose_ClearCoverage(A->Pose,0); + + M = A->CueMotion; + + Count = geMotion_GetSubMotionCount(M); + + for (i=Count-1; i>=0; i--) + { + geFloat TimeOffset = geMotion_GetTimeOffset( M, i ); + TimeOffset = TimeOffset - DeltaTime; + geMotion_SetTimeOffset( M, i, TimeOffset); + + if (geActor_IsAnimationCueDead(A,i)) + { + geActor_KillCue(A,i); + } + else + { + geBoolean SetWithBlending= GE_TRUE; + geFloat BlendAmount; + + SubM = geMotion_GetSubMotion(M,i); + assert( SubM != NULL ); + + BlendAmount = geMotion_GetBlendAmount( M,i,0.0f ); + + if (BlendAmount >= ACTOR_CUE_MAXIMUM_BLEND) + { + SetWithBlending = GE_FALSE; + } + Coverage = gePose_AccumulateCoverage(A->Pose,SubM, SetWithBlending); + if ( Coverage == 0 ) + { + geActor_KillCue(A,i); + } + } + } + + gePose_SetMotionForABone( A->Pose, M, 0.0f, NULL, A->StepBoneIndex ); + geMotion_SetupEventIterator(M,-DeltaTime,0.0f); + + return GE_TRUE; +} + + + +GENESISAPI geBoolean GENESISCC geActor_AnimationTestStep(geActor *A, geFloat DeltaTime) +{ + assert( geActor_IsValid(A) != GE_FALSE); + assert( DeltaTime >= 0.0f ); + + gePose_SetMotion( A->Pose, A->CueMotion , DeltaTime, NULL ); + + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geActor_AnimationTestStepBoneOptimized(geActor *A, geFloat DeltaTime, const char *BoneName) +{ + assert( geActor_IsValid(A) != GE_FALSE); + assert( DeltaTime >= 0.0f ); + + if (BoneName == NULL) + { + A->StepBoneIndex = GE_POSE_ROOT_JOINT; + } + else + { + geBoolean LookupBoneName= GE_TRUE; + const char *LastBoneName; + geXForm3d Attachment; + int LastParentBoneIndex; + if (A->StepBoneIndex >= 0) + { + geBody_GetBone( A->ActorDefinition->Body,A->StepBoneIndex,&LastBoneName,&Attachment,&LastParentBoneIndex); + if ( (LastBoneName != NULL) ) + if (strcmp(LastBoneName,BoneName)==0) + LookupBoneName = GE_FALSE; + } + if (LookupBoneName != GE_FALSE) + { + if (geActor_GetBoneIndex(A,BoneName,&(A->StepBoneIndex))==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone not found", BoneName); + return GE_FALSE; + } + } + } + gePose_SetMotionForABone( A->Pose, A->CueMotion , DeltaTime, NULL,A->StepBoneIndex ); + + return GE_TRUE; +} + + + +GENESISAPI geBoolean GENESISCC geActor_GetAnimationEvent( + geActor *A, + const char **ppEventString) // Return data, if found + // returns the event string for the 'next' event that occured during the last + // animation step time delta. + // if the return value is GE_FALSE, there are no more events, and ppEventString will be Empty +{ + geFloat Time; + assert( geActor_IsValid(A) != GE_FALSE); + + return geMotion_GetNextEvent(A->CueMotion, &Time, ppEventString ); +} + + +#ifndef NDEBUG +static geBoolean GENESISCC geActor_TransformCompare(const geXForm3d *T1, const geXForm3d *T2) +{ + #define SINGLE_TERM_ERROR_THRESHOLD (0.0001f) + if (fabs(T1->AX - T2->AX)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->BX - T2->BX)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->CX - T2->CX)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->AY - T2->AY)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->BY - T2->BY)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->CY - T2->CY)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->AZ - T2->AZ)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->BZ - T2->BZ)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->CZ - T2->CZ)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + + if (fabs(T1->Translation.X - T2->Translation.X)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->Translation.Y - T2->Translation.Y)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + if (fabs(T1->Translation.Z - T2->Translation.Z)>SINGLE_TERM_ERROR_THRESHOLD) return GE_FALSE; + return GE_TRUE; +} +#endif + + + +GENESISAPI geBoolean GENESISCC geActor_GetLightingOptions(const geActor *Actor, + geBoolean *UseFillLight, + geVec3d *FillLightNormal, + geFloat *FillLightRed, + geFloat *FillLightGreen, + geFloat *FillLightBlue, + geFloat *AmbientLightRed, + geFloat *AmbientLightGreen, + geFloat *AmbientLightBlue, + geBoolean *UseAmbientLightFromFloor, + int *MaximumDynamicLightsToUse, + const char **LightReferenceBoneName, + geBoolean *PerBoneLighting) +{ + int BoneIndex; + assert( geActor_IsValid(Actor)!=GE_FALSE ); + + assert( UseFillLight != NULL ); + assert( FillLightNormal != NULL ); + assert( FillLightRed != NULL ); + assert( FillLightGreen != NULL ); + assert( FillLightBlue != NULL ); + assert( AmbientLightRed != NULL ); + assert( AmbientLightGreen != NULL ); + assert( AmbientLightBlue != NULL ); + assert( UseAmbientLightFromFloor != NULL ); + assert( MaximumDynamicLightsToUse != NULL ); + assert( LightReferenceBoneName != NULL ); + + if (Actor->Puppet == NULL) + { + geErrorLog_AddString(-1,"Can't set lighting options until actor is prepared for rendering", NULL); + return GE_FALSE; + } + + gePuppet_GetLightingOptions( Actor->Puppet, + UseFillLight, + FillLightNormal, + FillLightRed, + FillLightGreen, + FillLightBlue, + AmbientLightRed, + AmbientLightGreen, + AmbientLightBlue, + UseAmbientLightFromFloor, + MaximumDynamicLightsToUse, + &BoneIndex, + PerBoneLighting); + + if (BoneIndex>=0 && (BoneIndex < geBody_GetBoneCount(Actor->ActorDefinition->Body))) + { + geXForm3d DummyAttachment; + int DummyParentBoneIndex; + geBody_GetBone( Actor->ActorDefinition->Body, + BoneIndex, + LightReferenceBoneName, + &DummyAttachment, + &DummyParentBoneIndex); + } + else + { + LightReferenceBoneName = NULL; + } + + return GE_TRUE; // CB +} + +//Actor-level environmental mapping code +GENESISAPI void GENESISCC geActor_SetEnvironOptions( geActor *A, geEnvironmentOptions *opts ) +{ + assert ( geActor_IsValid(A) != GE_FALSE ); + assert ( A->Puppet != NULL ); + gePuppet_SetEnvironmentOptions( A->Puppet, opts ); +} + +GENESISAPI geEnvironmentOptions GENESISCC geActor_GetEnvironOptions( geActor *A ) +{ + assert ( geActor_IsValid(A) != GE_FALSE ); + assert ( A->Puppet != NULL ); + return gePuppet_GetEnvironmentOptions( A->Puppet ); +} + +GENESISAPI geBoolean GENESISCC geActor_SetLightingOptions(geActor *A, + geBoolean UseFillLight, + const geVec3d *FillLightNormal, + geFloat FillLightRed, // 0 .. 255 + geFloat FillLightGreen, // 0 .. 255 + geFloat FillLightBlue, // 0 .. 255 + geFloat AmbientLightRed, // 0 .. 255 + geFloat AmbientLightGreen, // 0 .. 255 + geFloat AmbientLightBlue, // 0 .. 255 + geBoolean AmbientLightFromFloor, + int MaximumDynamicLightsToUse, // 0 for none + const char *LightReferenceBoneName, + geBoolean PerBoneLighting ) +{ + int BoneIndex; + + assert( geActor_IsValid(A)!=GE_FALSE ); + assert( FillLightNormal != NULL ); + + if (A->Puppet == NULL) + { + geErrorLog_AddString(-1,"Can't set lighting options until actor is prepared for rendering", NULL); + return GE_FALSE; + } + if (geActor_GetBoneIndex(A,LightReferenceBoneName,&BoneIndex)==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone for light reference not found", LightReferenceBoneName); + return GE_FALSE; + } + + gePuppet_SetLightingOptions( A->Puppet, + UseFillLight, + FillLightNormal, + FillLightRed, + FillLightGreen, + FillLightBlue, + AmbientLightRed, + AmbientLightGreen, + AmbientLightBlue, + AmbientLightFromFloor, + MaximumDynamicLightsToUse, + BoneIndex, + PerBoneLighting); + return GE_TRUE; +} + +GENESISAPI void GENESISCC geActor_SetScale(geActor *A, geFloat ScaleX,geFloat ScaleY,geFloat ScaleZ) +{ + geVec3d S; + assert( A != NULL ); + + geVec3d_Set(&S,ScaleX,ScaleY,ScaleZ); + gePose_SetScale(A->Pose,&S); +} + + + +GENESISAPI geBoolean GENESISCC geActor_SetShadow(geActor *A, + geBoolean DoShadow, + geFloat Radius, + const geBitmap *ShadowMap, + const char *BoneName) +{ + int BoneIndex; + + assert( geActor_IsValid(A)!=GE_FALSE ); + assert( (DoShadow==GE_FALSE) || (DoShadow==GE_TRUE)); + assert( Radius >= 0.0f); + + if (A->Puppet == GE_FALSE) + { + geErrorLog_AddString(-1,"Can't set shadow options until actor is prepared for rendering", NULL); + return GE_FALSE; + } + + if (geActor_GetBoneIndex(A,BoneName,&BoneIndex)==GE_FALSE) + { + geErrorLog_AddString(-1,"Named bone for shadow not found", BoneName); + return GE_FALSE; + } + + gePuppet_SetShadow(A->Puppet,DoShadow,Radius,ShadowMap,BoneIndex); + + return GE_TRUE; +} + + +geBoolean GENESISCC geActor_RenderPrep( geActor *A, geWorld *World) +{ + assert( geActor_IsValid(A) != GE_FALSE ); + #pragma message ("need to make a world method that does this. so World doesn't get passed in") + assert( geActor_DefIsValid(A->ActorDefinition) != GE_FALSE ); + assert( geBody_IsValid(A->ActorDefinition->Body) != GE_FALSE ); + + if (A->Puppet!=NULL) + { + gePuppet_Destroy(&(A->Puppet)); + A->Puppet =NULL; + } + + A->Puppet = gePuppet_Create(A->ActorDefinition->TextureFileContext, A->ActorDefinition->Body,World); + if ( A->Puppet == NULL ) + { + geErrorLog_Add( ERR_ACTOR_RENDER_PREP , NULL); + return GE_FALSE; + } + { + geExtBox EB; + //initialize body bounding box + geActor_GetDynamicExtBox(A, &EB); + geBody_SetBoundingBox(A->ActorDefinition->Body, GE_BODY_ROOT, &EB.Min, &EB.Max); + if (geActor_GetBoneExtBoxByIndex(A,GE_POSE_ROOT_JOINT,&EB) == GE_FALSE) + { + geErrorLog_AddString(-1,"Failure to get Root Bounding box from puppet", NULL); + return GE_FALSE; + } + + A->BoundingBoxMinCorner = EB.Min; + A->BoundingBoxMaxCorner = EB.Max; + } + + return GE_TRUE; +} + +geBoolean GENESISCC geActor_RenderThroughFrustum(const geActor *A, geEngine *Engine, geWorld *World,geCamera *Camera, Frustum_Info *FInfo) +{ + geExtBox Box; + + assert( geActor_IsValid(A) != GE_FALSE ); + assert( A->Puppet != NULL ); + + if (!geActor_GetDynamicExtBox( A, &Box)) + { + geErrorLog_AddString(-1, "geActor_RenderThroughFrustum: geActor_GetDynamicAABoundingBox failed.", NULL); + return GE_FALSE; + } + + if (gePuppet_RenderThroughFrustum( A->Puppet, A->Pose, &Box, Engine, World, Camera, FInfo)==GE_FALSE) + { + geErrorLog_Add( ERR_ACTOR_RENDER_FAILED , NULL); + return GE_FALSE; + } + return GE_TRUE; +} + +geBoolean GENESISCC geActor_Render(const geActor *A, geEngine *Engine, geWorld *World,geCamera *Camera) +{ + assert( geActor_IsValid(A) != GE_FALSE ); + assert( A->Puppet != NULL ); + + if (A->RenderHintExtBoxEnabled) + { + geBoolean Enabled; + geExtBox Box; + if (geActor_GetRenderHintExtBox(A, &Box, &Enabled)==GE_FALSE) + { + geErrorLog_Add( -1 , NULL); //? + return GE_FALSE; + } + if (gePuppet_Render( A->Puppet, A->Pose, Engine,World, Camera, &Box )==GE_FALSE) + { + geErrorLog_Add( ERR_ACTOR_RENDER_FAILED , NULL); + return GE_FALSE; + } + } + else + { + if (gePuppet_Render( A->Puppet, A->Pose, Engine,World, Camera, NULL )==GE_FALSE) + { + geErrorLog_Add( ERR_ACTOR_RENDER_FAILED , NULL); + return GE_FALSE; + } + } + return GE_TRUE; +} + +GENESISAPI int GENESISCC geActor_GetMaterialCount(const geActor *A) +{ + assert( geActor_IsValid(A) != GE_FALSE ); + assert( A->Puppet != NULL ); + + return gePuppet_GetMaterialCount( A->Puppet ); +} + +GENESISAPI geBoolean GENESISCC geActor_GetMaterial(const geActor *A, int MaterialIndex, + geBitmap **Bitmap, geFloat *Red, geFloat *Green, geFloat *Blue) +{ + assert( geActor_IsValid(A) != GE_FALSE ); + assert( A->Puppet != NULL ); + + return gePuppet_GetMaterial(A->Puppet, MaterialIndex, Bitmap, Red, Green, Blue ); +} + + +GENESISAPI geBoolean GENESISCC geActor_SetMaterial(geActor *A, int MaterialIndex, + geBitmap *Bitmap, geFloat Red, geFloat Green, geFloat Blue) +{ + assert( geActor_IsValid(A) != GE_FALSE ); + assert( A->Puppet != NULL ); + + return gePuppet_SetMaterial(A->Puppet,MaterialIndex, Bitmap, Red, Green, Blue ); +} + +GENESISAPI geBoolean GENESISCC geActor_SetStaticLightingOptions(geActor *A, geBoolean AmbientLightFromStaticLights, geBoolean TestRayCollision, int MaxStaticLightsToUse ) +{ assert( geActor_IsValid(A)!=GE_FALSE ); + if (A->Puppet == NULL) + { + geErrorLog_AddString(-1,"Can't set lighting options until actor is prepared for rendering", NULL); + return GE_FALSE; + } + gePuppet_SetStaticLightingOptions( A->Puppet, + AmbientLightFromStaticLights, + MaxStaticLightsToUse, + TestRayCollision + ); + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geActor_GetStaticLightingOptions( const geActor *Actor, geBoolean *UseAmbientLightFromStaticLights, geBoolean *TestRayCollision, int *MaxStaticLightsToUse ) +{ assert( geActor_IsValid(Actor)!=GE_FALSE ); + assert( UseAmbientLightFromStaticLights != NULL ); + assert( TestRayCollision != NULL ); + if (Actor->Puppet == NULL) + { + geErrorLog_AddString(-1,"Can't set lighting options until actor is prepared for rendering", NULL); + return GE_FALSE; + } + + gePuppet_GetStaticLightingOptions( Actor->Puppet, + UseAmbientLightFromStaticLights, + TestRayCollision, + MaxStaticLightsToUse + ); + return GE_TRUE; +} diff --git a/G3D/Actor/actor.h b/G3D/Actor/actor.h new file mode 100644 index 0000000..82cf213 --- /dev/null +++ b/G3D/Actor/actor.h @@ -0,0 +1,478 @@ +/****************************************************************************************/ +/* ACTOR.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Actor interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +/* Actor + + This object is designed to support character animation. + There are two basic objects to deal with. + + Actor Definition (geActor_Def) + A geActor_Def embodies the geometry (polygon, and bone information), + and a library of motions that can be applied to that geometry. + + Actor + A geActor is an instance of an actor definition. The definition is used for + the geometry, but all additional settings, such as the bone pose, lighting information, + and cuing information is unique for a geActor. +// GENESIS_PRIVATE_API + An Actor Definition is created either from an existing Actor Definition file, or from scratch by + first creating a geBody and geMotions and selecting these into an Actor. If the Actor Definition + is constructed from scratch, the objects selected into it (via SetBody and AddMotion) are + then 'owned' by the actor and will be destroyed along with the Actor when it is destroyed. + Of course, when the Actor is loaded from a file, the Body and Motion it creates as it is + loaded are cleaned up when the Actor is destroyed. + + Once an Actor is created, prepare it for rendering and animating by calling + Actor_RenderPrep(). This must be called (and it must succeed) before any render or + pose setting functions can be called. +// GENESIS_PUBLIC_API + + There are two ways to use an Actor. + Direct Control + One method is to directly control the skeleton configuration. Use _SetPose() to set its + skeleton using a geMotion animation. The pose is positioned in world space relative to the + transform given in SetPose(). Whenever a new skeleton pose is required, call _SetPose() + to reposition the skeleton for a new point in time. + + More complex positioning can be achieved by blending more than one animation. Use + _BlendPose() after a _SetPose() to blend the second geMotion into the first. Additional + blends can be applied by additional _BlendPose() calls. Each blend is performed on the + the existing skeleton (the results of any previous blends). + Cuing + Another method is to 'cue' up motions that are applied with parameterized blending over time. + A cued motion takes effect 'now' in time. The Actor advances in time and repositions itself + according to its currently cued motions with a call to _AnimationStep(). AnimationStep() + redefines what the actor thinks 'now' is. This causes historical cues to be forgotten, and + motions that are no longer valid are cleaned up. AnimationTestStep() can be used to position + the actor for potential queries with its currently cued motions at some arbitrary future time + - relative to the last AnimationTestStep() call. AnimationNudge() applies a given transform + 'instantly' to the current actor's cue list. This is usefull for moving the actor as a + result of a collision with another object. + + If a motion contains joint information that does not exactly match the Actor's skeleton + joints, only the joints that match by name are applied. So a geMotion can be applied to + a portion of the Actor, or a geMotion that has more joint information than the skeleton can + be applied and the extra joint information is ignored. + + Examples of this: If the Actor is a biped and has no tail, but the motion is for a + biped with a tail, the geMotion can be applied, but the tail information will be ignored. + Also if there is a geMotion for only a left arm, it can be applied and it will only affect + the left arm of the Actor, and consequently its left hand and fingers, but no other + bones that are not children of the affected bones will be changed. + + +*/ +#ifndef GE_ACTOR_H +#define GE_ACTOR_H + +#include "genesis.h" +#include "basetype.h" +#include "extbox.h" +#include "bitmap.h" + +#include "Motion.h" + +#ifdef GE_WORLD_H +#include "camera.h" +#include "Frustum.h" +#endif + +#include "Body.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// GENESIS_PUBLIC_APIS + +#ifndef GE_ACTOR_ENUMS +#define GE_ACTOR_ENUMS +typedef enum +{ + GE_ACTOR_BLEND_LINEAR, // Treats the blending amount as a linear value + GE_ACTOR_BLEND_HERMITE // Applies a parametric smoothing curve to the blending amount + // so that a linear change in BlendAmount parameters will + // result in a smooth (non-linear) change in blending. +} geActor_BlendingType; + +#endif + +typedef struct geActor geActor; // an instance of an actor +typedef struct geActor_Def geActor_Def; // the deinition of an actor's geometry/bone structure + + +// GENESIS_PRIVATE_APIS + +//--------------------------------------------------------------------------------- +// Creation/Destruction functions +//--------------------------------------------------------------------------------- + // Create an 'empty' Actor Definition. +GENESISAPI geActor_Def *GENESISCC geActor_DefCreate(void); + + // Create an Actor Definition from a file image. +GENESISAPI geActor_Def *GENESISCC geActor_DefCreateFromFile(geVFile *pFile); + + // Create an additional reference (owner) for the Actor_Definition +GENESISAPI void GENESISCC geActor_DefCreateRef(geActor_Def *pActorDefinition); + + // Destroy a geActor_Def (its geBody and its geMotions) Actors that rely on this definition become invalid. + // can fail if there are actors still referencing this definition. +GENESISAPI geBoolean GENESISCC geActor_DefDestroy(geActor_Def **pActorDefinition); + + // Create an Actor instance associated with the given Actor Definition +GENESISAPI geActor *GENESISCC geActor_Create(geActor_Def *ActorDefinition); + + // Create an additional reference (owner) for the Actor +GENESISAPI void GENESISCC geActor_CreateRef(geActor *Actor); + + // Give the Actor Definition a Body. geActor becomes responsible for its destruction. + // sets up default materials as referenced by the Body. +GENESISAPI geBoolean GENESISCC geActor_SetBody( geActor_Def *ActorDefinition, geBody *geBodyGeometry); + + // Adds a geMotion to the Actor Definition's library. The ActorDefinition becomes responsible for its destruction. + // returns the library index to the new geMotion. +GENESISAPI geBoolean GENESISCC geActor_AddMotion(geActor_Def *ActorDefinition, geMotion *M, int *Index); + + // Destroy an Actor. +GENESISAPI geBoolean GENESISCC geActor_Destroy(geActor **pA); + +GENESISAPI geBoolean GENESISCC geActor_DestroyDirect(geActor **pA); + +GENESISAPI geBoolean GENESISCC geActor_DefIsValid(const geActor_Def *A); +GENESISAPI geBoolean GENESISCC geActor_IsValid(const geActor *A); + +// GENESIS_PUBLIC_APIS +//--------------------------------------------------------------------------------- +// Queries +//--------------------------------------------------------------------------------- +// GENESIS_PRIVATE_APIS + + // In general: Objects retuned from Get functions should not not be destroyed. + // if ownership is desired, call the objects _CreateRef() function to create another owner. + // (An 'owner' has access to the object regardless of the number of other owners, and + // an owner must call the object's _Destroy() function to relinquish ownership ) + + // Returns the Actor Definition associated with Actor A +GENESISAPI geActor_Def *GENESISCC geActor_GetActorDef(const geActor *A); + + // Writes an existing geActor to a file image. Returns GE_TRUE on success, GE_FALSE on failure. +GENESISAPI geBoolean GENESISCC geActor_DefWriteToFile(const geActor_Def *A, geVFile *pFile); + + // Returns a geBody pointer from the geActor +GENESISAPI geBody *GENESISCC geActor_GetBody(const geActor_Def *ActorDefinition); + + // Returns GE_TRUE if the actor definition has a bone named 'Name' +GENESISAPI geBoolean GENESISCC geActor_DefHasBoneNamed(const geActor_Def *Ad, const char *Name ); + + // Selects a blending type. BlendingType only affects the meaning of the + // BlendAmount parameter for the blend functions. Can be changed anytime. +GENESISAPI void GENESISCC geActor_SetBlendingType( geActor *A, geActor_BlendingType BlendingType ); + +// GENESIS_PUBLIC_APIS + + // Returns the number of geMotions in the geActors geMotion library. +GENESISAPI int GENESISCC geActor_GetMotionCount(const geActor_Def *ActorDefinition); + + // Returns a geMotion pointer from the geActors geMotion library + // This is an aliased pointer - Not a copy. Changes to this motion will be reflected + // in the actor. Destroying this return motion will confuse the actor. + // Index must be in range [0..geActor_GetMotionCount-1] +GENESISAPI geMotion *GENESISCC geActor_GetMotionByIndex(const geActor_Def *ActorDefinition, int Index ); + + // Returns a geMotion pointer from the geActors geMotion library + // This is an aliased pointer - Not a copy. Changes to this motion will be reflected + // in the actor. Destroying this return motion will confuse the actor. + // if there is no motion that matches the given name, the return value will be NULL +GENESISAPI geMotion *GENESISCC geActor_GetMotionByName(const geActor_Def *ActorDefinition, const char *Name ); + + // Returns a motion name given an ActorDef and a motion index. +GENESISAPI const char *GENESISCC geActor_GetMotionName(const geActor_Def *ActorDefinition, int Index ); + + // Returns the number of materials for an instance of an actor. +GENESISAPI int GENESISCC geActor_GetMaterialCount(const geActor *A); + + // Returns the current material for an instance of an actor +GENESISAPI geBoolean GENESISCC geActor_GetMaterial(const geActor *Actor, int MaterialIndex, + geBitmap **Bitmap, geFloat *Red, geFloat *Green, geFloat *Blue); + + // Allows a material to be overriden in an actor instance +GENESISAPI geBoolean GENESISCC geActor_SetMaterial(geActor *Actor, int MaterialIndex, + geBitmap *Bitmap, geFloat Red, geFloat Green, geFloat Blue); + + + + // Gets the current transform for a single bone in A. (actor space->world space transform) + // with a NULL BoneName, this returns the current 'root' transform +GENESISAPI geBoolean GENESISCC geActor_GetBoneTransform(const geActor *A, const char *BoneName, geXForm3d *Transform); + + // Gets the extent box (axial-aligned bounding box) for a given bone (for the current pose) + // if BoneName is NULL, gets the a general bounding box from the body of the actor if it has been set. +GENESISAPI geBoolean GENESISCC geActor_GetBoneExtBox(const geActor *A, + const char *BoneName,geExtBox *ExtBox); + + // Gets the non-axial-aligned bounding box for a given bone (for the current pose) + // The box is specified by a corner, and + // a non-normalized orientation transform. Add DX,DY,DZ components + // of the orientation to get other corners of the box + // if BoneName is NULL, gets the a general bounding box from the body of the actor if it has been set. +GENESISAPI geBoolean GENESISCC geActor_GetBoneBoundingBox(const geActor *A, + const char *BoneName, + geVec3d *Corner, + geVec3d *DX, + geVec3d *DY, + geVec3d *DZ); + + // Gets the current axial-aligned bounding box for an actor's bone configuration + // takes all bones into account +GENESISAPI geBoolean GENESISCC geActor_GetDynamicExtBox( const geActor *A, geExtBox *ExtBox); + + // Gets an assigned general non changing bounding box from the actor +GENESISAPI geBoolean GENESISCC geActor_GetExtBox(const geActor *A, geExtBox *ExtBox); + + // Sets an assigned general non changing bounding box from the actor +GENESISAPI geBoolean GENESISCC geActor_SetExtBox(geActor *A, const geExtBox *ExtBox, + const char *CenterBoxOnThisNamedBone); // NULL uses root position of actor + + // Gets the rendering hint bounding box from the actor + // if the RenderHintExtBox is disabled, Enabled is GE_FALSE, and the box returned has zero dimensions, + // centered at the root position of the actor. If the RenderHintExtBox is enabled, Enabled is + // GE_TRUE, and the box returned is the one set with _SetRenderHintExtBox, offset by the + // bone position of the bone named in _SetRenderHintExtBox(). +GENESISAPI geBoolean GENESISCC geActor_GetRenderHintExtBox(const geActor *A, geExtBox *Box, geBoolean *Enabled); + + // Sets a rendering hint bounding box from the actor. Increases performance by + // enabling the rendering of the actor to occur only if the box is visible. + // If the box is not visible, a detailed analysis of the actor's current geometry is avoided. + // This does allow errors to occur: + // If the actor has a bit of geometry that extends outside this box for some + // animation, that extended geometry may not be drawn, if the box if off-screen. + // If the render hint box is not set, the engine will make no conservative assumptions + // about the visibility of an actor - it will always be drawn if any portion of it is + // visible. + // To attach the box to the 'root' bone, pass NULL for CenterBoxOnThisNamedBone + // For disabling the hint box: (disabled is default) pass Box with zero mins and maxs +GENESISAPI geBoolean GENESISCC geActor_SetRenderHintExtBox(geActor *A, const geExtBox *Box, + const char *CenterBoxOnThisNamedBone ); + + + // Returns the pointer which was set with geActor_SetUserData. NULL if not set. +GENESISAPI void *GENESISCC geActor_GetUserData(const geActor *A); + + // Sets the actors user data pointer to the given value. For clients only. +GENESISAPI void GENESISCC geActor_SetUserData(geActor *A, void *UserData); + + +//-------------------------------------------------------------------------------- +// Posing and Rendering +//-------------------------------------------------------------------------------- + +// GENESIS_PRIVATE_APIS + +#ifdef GE_WORLD_H + // Prepares the geActor for rendering and posing. Call Once once the actor is fully created. + // Must be called prior to render/pose/setworldtransform +geBoolean GENESISCC geActor_RenderPrep( geActor *A, geWorld *World); + + // Draws the geActor. (RenderPrep must be called first) +geBoolean GENESISCC geActor_RenderThroughFrustum(const geActor *A, geEngine *Engine, geWorld *World, geCamera *Camera, Frustum_Info *FInfo); +geBoolean GENESISCC geActor_Render(const geActor *A, geEngine *Engine, geWorld *World, geCamera *Camera); +#endif + +// GENESIS_PUBLIC_APIS + + // Poses the actor in its default pose + // Transform is where to position the root for this pose. + // if Transform is NULL, the root for the pose is assumed to be the root of the actor. +GENESISAPI void GENESISCC geActor_ClearPose(geActor *A, const geXForm3d *Transform); + + // Poses the actor using given motion M at a time offset of Time + // Transform is where to position the root for this pose. + // if Transform is NULL, the root for the pose is assumed to be the root of the actor. +GENESISAPI void GENESISCC geActor_SetPose(geActor *A, const geMotion *Motion, geFloat Time, const geXForm3d *Transform); + + // Blends the current pose of the geActor with + // a new pose using motion M at a time offset of Time + // A BlendAmount of 0 will result in the existing pose, A BlendAmount of 1 will + // result in the new pose from M. The BlendingType set by _SetBlendingType() determines + // the blending function between 0 and 1 + // Transform is where to position the root for this pose. + // if Transform is NULL, the root for the pose is assumed to be the root of the actor. +GENESISAPI void GENESISCC geActor_BlendPose(geActor *A, const geMotion *Motion, geFloat Time, + const geXForm3d *Transform, geFloat BlendAmount); + + +GENESISAPI geBoolean GENESISCC geActor_GetBoneAttachment(const geActor *A, const char *BoneName, geXForm3d *Transform); +GENESISAPI geBoolean GENESISCC geActor_SetBoneAttachment(geActor *A, const char *BoneName, geXForm3d *Transform); + +// GENESIS_PRIVATE_APIS + +GENESISAPI geBoolean GENESISCC geActor_Attach( geActor *Slave, const char *SlaveBoneName, + const geActor *Master, const char *MasterBoneName, + const geXForm3d *Attachment); + +GENESISAPI void GENESISCC geActor_Detach(geActor *Slave); + +//Environmental mapping... +GENESISAPI void GENESISCC geActor_SetEnvironOptions( geActor *A, geEnvironmentOptions *opts ); + +GENESISAPI geEnvironmentOptions GENESISCC geActor_GetEnvironOptions( geActor *A ); + +// GENESIS_PUBLIC_APIS +GENESISAPI geBoolean GENESISCC geActor_SetLightingOptions(geActor *A, + geBoolean UseFillLight, // GE_TRUE or GE_FALSE + const geVec3d *FillLightNormal, // normalized vector + geFloat FillLightRed, // 0 .. 255 + geFloat FillLightGreen, // 0 .. 255 + geFloat FillLightBlue, // 0 .. 255 + geFloat AmbientLightRed, // 0 .. 255 + geFloat AmbientLightGreen, // 0 .. 255 + geFloat AmbientLightBlue, // 0 .. 255 + geBoolean AmbientLightFromFloor, // GE_TRUE or GE_FALSE + int MaximumDynamicLightsToUse, // 0 for none + const char *LightReferenceBoneName, //NULL for root + geBoolean PerBoneLighting); + // if GE_TRUE, then dynamic lighting attenuation and direction is computed + // for each bone. if GE_FALSE, then the computations are relative to the + // single bone named by the LightReferenceBoneName + +GENESISAPI geBoolean GENESISCC geActor_GetLightingOptions(const geActor *A, + geBoolean *UseFillLight, // GE_TRUE or GE_FALSE + geVec3d *FillLightNormal, // normalized vector + geFloat *FillLightRed, // 0 .. 255 + geFloat *FillLightGreen, // 0 .. 255 + geFloat *FillLightBlue, // 0 .. 255 + geFloat *AmbientLightRed, // 0 .. 255 + geFloat *AmbientLightGreen, // 0 .. 255 + geFloat *AmbientLightBlue, // 0 .. 255 + geBoolean *UseAmbientLightFromFloor,// GE_TRUE or GE_FALSE + int *MaximumDynamicLightsToUse, + const char **LightReferenceBoneName, + geBoolean *PerBoneLighting); // NULL for root + + +GENESISAPI void GENESISCC geActor_SetScale(geActor *A, geFloat ScaleX,geFloat ScaleY,geFloat ScaleZ); + +// LWM_ACTOR_RENDERING: +GENESISAPI geFloat GENESISCC geActor_GetAlpha(const geActor *A) ; +// LWM_ACTOR_RENDERING: +GENESISAPI void GENESISCC geActor_SetAlpha(geActor *A, geFloat Alpha) ; + +GENESISAPI geBoolean GENESISCC geActor_GetStaticLightingOptions(const geActor *Actor, geBoolean *UseAmbientLightFromStaticLights, geBoolean *TestRayCollision, int *MaxStaticLightsToUse ); +GENESISAPI geBoolean GENESISCC geActor_SetStaticLightingOptions(geActor *A, + geBoolean AmbientLightFromStaticLights, + geBoolean TestRayCollision, + int MaxStaticLightsToUse + ); + +GENESISAPI geBoolean GENESISCC geActor_SetShadow(geActor *A, + geBoolean DoShadow, + geFloat Radius, + const geBitmap *ShadowMap, + const char * BoneName); + +// Animation Cuing API: +// high level Actor animation: The principle is that motions can be applied to an actor +// and the actor will keep track of which motions are currently appropriate. Call +// _AnimationStep() to compute a new pose for an elapsed time interval. The new pose +// will take into account all motions that are 'currently' cued up to be set or blended. + + + // cue up a new motion. The motion begins at the current time. The motion can be + // blended in or out over time and time scaled. If the return value is GE_FALSE, the + // animation was not cued up (failure implies Actor is incompletely initialized). +GENESISAPI geBoolean GENESISCC geActor_AnimationCue( + geActor *A, // actor to apply animation to + geMotion *Motion, // motion to Cue + geFloat TimeScaleFactor, // time scale to apply to cued motion + geFloat TimeIntoMotion, // time offset to begin motion with (Not TimeScaled) + geFloat BlendTime, // time to apply a blend. + geFloat BlendFromAmount, // blend value at current time + geFloat BlendToAmount, // blend value after BlendTime time has elapsed + const geXForm3d *MotionTransform); // local transform to adjust motion by (NULL implies NO transform) + + // removes the last animation cue that was cued up. Can be called repeatedly to successively + // remove older and older cues. Returns GE_TRUE when a cue was removed, GE_FALSE if there + // are no cues to remove. +GENESISAPI geBoolean GENESISCC geActor_AnimationRemoveLastCue( geActor *A ); + + // applies a time step to actor A. re-poses the actor according to all currently applicable + // Animation Cues. (failure implies Actor is incompletely initialized) +GENESISAPI geBoolean GENESISCC geActor_AnimationStep(geActor *A, geFloat DeltaTime ); + + // applies a 'temporary' time step to actor A. re-poses the actor according to all + // currently appliciable cues. (failure implies Actor is incompletely initialized) + // DeltaTime is always relative to the the last AnimationStep() +GENESISAPI geBoolean GENESISCC geActor_AnimationTestStep(geActor *A, geFloat DeltaTime); + + // optimized version of geActor_AnimationStep. Limits calculations to the bone named BoneName, and it's + // parents. BoneName will be correctly computed, but the other bones will be wrong. This is usefull for + // moving and animating an actor that is not actually visible. Rendering and queries will be 'optimized' + // until the actor is given any pose or animation that doesn't go through geActor_AnimationStepBoneOptimized() or + // geActor_AnimationTestStepBoneOptimized(). BoneName can be NULL to compute only 'root' bone. +GENESISAPI geBoolean GENESISCC geActor_AnimationStepBoneOptimized(geActor *A, geFloat DeltaTime, const char *BoneName ); + + // optimized version of geActor_AnimationTestStep. Limits calculations to the bone named BoneName, and it's + // parents. BoneName will be correctly computed, but the other bones will be wrong. This is usefull for + // moving and animating an actor that is not actually visible. Rendering and queries will be 'optimized' + // until the actor is given any pose or animation that doesn't go through geActor_AnimationStepBoneOptimized() or + // geActor_AnimationTestStepBoneOptimized(). BoneName can be NULL to compute only 'root' bone. +GENESISAPI geBoolean GENESISCC geActor_AnimationTestStepBoneOptimized(geActor *A, geFloat DeltaTime, const char *BoneName); + + + // applies an 'immediate' offset to the animated actor +GENESISAPI geBoolean GENESISCC geActor_AnimationNudge(geActor *A, geXForm3d *Offset); + + +GENESISAPI geBoolean GENESISCC geActor_GetAnimationEvent(geActor *A, + const char **ppEventString); // Return data, if return value is GE_TRUE + + // returns number of actors that are currently created. +GENESISAPI int GENESISCC geActor_GetCount(void); + +// eaa3 07/21/2000 Mods for detailed collision detection + +GENESISAPI geBoolean GENESISCC geActor_GetBoneExtBoxByIndex( + const geActor *A, + int BoneIndex, + geExtBox *ExtBox); + +GENESISAPI geBoolean GENESISCC geActor_GetBoneTransformByIndex(const geActor *A, int BoneIndex, geXForm3d *Transform); + +GENESISAPI int geActor_GetBoneCount(const geActor *A); + +//MRB BEGIN +// Unlike geActor_GetExtBox, this gets the bounding box in non-world coordinates. +// Whatever you put in with geActor_SetExtBox, you get out with this function. +GENESISAPI void GENESISCC geActor_GetNonWorldExtBox(const geActor *A, geExtBox *ExtBox); +GENESISAPI void GENESISCC geActor_GetPosition(const geActor *A, geVec3d *Pos); +//MRB END + +// GENESIS_PRIVATE_APIS + // call setscale and setshadow after preparing the actor for rendering (renderprep) + + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/G3D/Actor/body._h b/G3D/Actor/body._h new file mode 100644 index 0000000..06f7db2 --- /dev/null +++ b/G3D/Actor/body._h @@ -0,0 +1,124 @@ +/****************************************************************************************/ +/* BODY._H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Exports private BODY data structures for "friends". */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_BODY__H +#define GE_BODY__H + +#include "basetype.h" +#include "xform3d.h" +#include "body.h" +#include "strblock.h" +#include "bitmap.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#define GE_BODY_INDEX_MAX (0xEFFF) + +#define GE_BODY_REALLY_BIG_NUMBER (9e9f) // bigger than any skin point + +#define GE_BODY_HIGHEST_LOD_MASK ( 1 << GE_BODY_HIGHEST_LOD ) +#define GE_BODY_BBOX_LOD_MASK ( 1 << GE_BODY_NUMBER_OF_LOD ) // bounding box mask + + +typedef int16 geBody_Index; + +typedef struct geBody_XSkinVertex +{ + geVec3d XPoint; + geFloat XU,XV; + int8 LevelOfDetailMask; + geBody_Index BoneIndex; +} geBody_XSkinVertex; + +typedef struct geBody_Normal +{ + geVec3d Normal; + int8 LevelOfDetailMask; + geBody_Index BoneIndex; +} geBody_Normal; + +typedef struct geBody_Bone +{ + geVec3d BoundingBoxMin; + geVec3d BoundingBoxMax; + geXForm3d AttachmentMatrix; + geBody_Index ParentBoneIndex; +} geBody_Bone; + +typedef struct geBody_Triangle +{ + geBody_Index VtxIndex[3]; + geBody_Index NormalIndex[3]; + geBody_Index MaterialIndex; + //geBody_Index FaceNormal; +} geBody_Triangle; + +typedef struct geBody_TriangleList +{ + geBody_Index FaceCount; + geBody_Triangle *FaceArray; // Sorted by MaterialIndex +} geBody_TriangleList; + +typedef struct geBody_Material +{ + geBitmap *Bitmap; + geFloat Red,Green,Blue; +} geBody_Material; + +typedef struct geBody +{ + geVec3d BoundingBoxMin; + geVec3d BoundingBoxMax; + + geBody_Index XSkinVertexCount; + geBody_XSkinVertex *XSkinVertexArray; // Sorted by BoneIndex + + geBody_Index SkinNormalCount; + geBody_Normal *SkinNormalArray; + + geBody_Index BoneCount; + geBody_Bone *BoneArray; + geStrBlock *BoneNames; + + geBody_Index MaterialCount; + geBody_Material *MaterialArray; + geStrBlock *MaterialNames; + + int LevelsOfDetail; + geBody_TriangleList SkinFaces[GE_BODY_NUMBER_OF_LOD]; + + geBody *IsValid; +} geBody; + +#if defined(DEBUG) || !defined(NDEBUG) +geBoolean GENESISCC geBody_SanityCheck(const geBody *B); +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Actor/body.c b/G3D/Actor/body.c new file mode 100644 index 0000000..a002942 --- /dev/null +++ b/G3D/Actor/body.c @@ -0,0 +1,1283 @@ +/****************************************************************************************/ +/* BODY.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Actor body implementation. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include //assert() +#include //strlen(), strcpy() +#include //fabs() +#include //sscanf + +#include "body.h" +#include "body._h" +#include "ram.h" +#include "errorlog.h" + + +#define MAX(aa,bb) ( (aa)>(bb)?(aa):(bb) ) +#define MIN(aa,bb) ( (aa)<(bb)?(aa):(bb) ) + + + + +#if defined(DEBUG) || !defined(NDEBUG) +static geBoolean GENESISCC geBody_SanityCheck(const geBody *B) +{ + int i,j,k; + int Lod,FaceCount,VertexCount,NormalCount,BoneCount; + geBody_XSkinVertex *SV; + geBody_Bone *Bone; + geBody_Normal *N; + + Lod = B->LevelsOfDetail; + VertexCount = B->XSkinVertexCount; + NormalCount = B->SkinNormalCount; + BoneCount = B->BoneCount; + + if (B->MaterialNames == NULL ) + return GE_FALSE; + if (B->MaterialCount != geStrBlock_GetCount(B->MaterialNames)) + return GE_FALSE; + + if (B->BoneNames == NULL) + return GE_FALSE; + if (B->BoneCount != geStrBlock_GetCount(B->BoneNames)) + return GE_FALSE; + + if ((B->XSkinVertexArray == NULL) && (B->XSkinVertexCount>0)) + return GE_FALSE; + if ((B->SkinNormalArray == NULL) && (B->SkinNormalCount>0)) + return GE_FALSE; + if ((B->BoneArray == NULL) && (B->BoneCount>0)) + return GE_FALSE; + if ((B->MaterialArray == NULL) && (B->MaterialCount>0)) + return GE_FALSE; + + + for (i=0; iSkinFaces[i].FaceCount; + for (j=0,F=B->SkinFaces[i].FaceArray; jVtxIndex[k] < 0) || (F->VtxIndex[k] >= VertexCount )) + return GE_FALSE; + if ((F->NormalIndex[k] < 0) || (F->NormalIndex[k] >= NormalCount )) + return GE_FALSE; + if ((F->MaterialIndex < 0) || (F->MaterialIndex >= B->MaterialCount)) + return GE_FALSE; + } + } + } + for (i=0,SV = B->XSkinVertexArray; iBoneIndex < 0) || (SV->BoneIndex >= BoneCount)) + return GE_FALSE; + } + + for (i=0,N = B->SkinNormalArray; iBoneIndex < 0) || (N->BoneIndex >= BoneCount)) + return GE_FALSE; + } + + for (i=0,Bone = B->BoneArray; iParentBoneIndex != GE_BODY_NO_PARENT_BONE) + { + if ((Bone->ParentBoneIndex < 0) || (Bone->ParentBoneIndex > i)) + return GE_FALSE; + } + } + + return GE_TRUE; + +} +#endif + + +geBoolean GENESISCC geBody_IsValid(const geBody *B) +{ + if ( B == NULL ) + return GE_FALSE; + if ( B -> IsValid != B ) + return GE_FALSE; + assert( geBody_SanityCheck(B) != GE_FALSE) ; + return GE_TRUE; +} + + +static geBody *GENESISCC geBody_CreateNull(void) +{ + geBody *B; + int i; + + B = GE_RAM_ALLOCATE_STRUCT(geBody); + if ( B == NULL) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return NULL; + } + B->IsValid = NULL; + B->XSkinVertexCount = 0; + B->XSkinVertexArray = NULL; + + B->SkinNormalCount = 0; + B->SkinNormalArray = NULL; + + B->BoneCount = 0; + B->BoneArray = NULL; + B->BoneNames = NULL; + + B->MaterialCount = 0; + B->MaterialArray = NULL; + B->MaterialNames = NULL; + for (i=0; iSkinFaces[i].FaceCount = 0; + B->SkinFaces[i].FaceArray = NULL; + } + B->LevelsOfDetail = 1; + B->IsValid = B; + + geVec3d_Set(&(B->BoundingBoxMin),0.0f,0.0f,0.0f); + geVec3d_Set(&(B->BoundingBoxMax),0.0f,0.0f,0.0f); + return B; +} + +static void GENESISCC geBody_DestroyPossiblyIncompleteBody( geBody **PB ) +{ + geBody *B; + int i; + + B = *PB; + B->IsValid = NULL; + if (B->XSkinVertexArray != NULL) + { + geRam_Free( B->XSkinVertexArray ); + B->XSkinVertexArray = NULL; + } + if (B->SkinNormalArray != NULL) + { + geRam_Free( B->SkinNormalArray ); + B->SkinNormalArray = NULL; + } + if (B->BoneNames != NULL) + { + geStrBlock_Destroy(&(B->BoneNames)); + B->BoneNames = NULL; + } + if (B->BoneArray != NULL) + { + geRam_Free(B->BoneArray); + B->BoneArray = NULL; + } + if (B->MaterialArray != NULL) + { + for (i=0; iMaterialCount; i++) + { + // <> CB ; see note above + // this doesn't seem to prevent us from crashing here + // when an actor has an error during _Create + if ( (uint32)(B->MaterialArray[i].Bitmap) > 1 ) + geBitmap_Destroy(&(B->MaterialArray[i].Bitmap)); + B->MaterialArray[i].Bitmap = NULL; + } + geRam_Free( B->MaterialArray ); + B->MaterialArray = NULL; + } + if (B->MaterialNames != NULL) + { + geStrBlock_Destroy(&(B->MaterialNames)); + B->MaterialNames = NULL; + } + + for (i=0; iSkinFaces[i].FaceArray != NULL) + { + geRam_Free(B->SkinFaces[i].FaceArray); + B->SkinFaces[i].FaceArray = NULL; + } + } + geRam_Free(*PB); + *PB = NULL; +} + +geBody *GENESISCC geBody_Create(void) +{ + geBody *B; + + B = geBody_CreateNull(); + if ( B == NULL) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return NULL; + } + + B->BoneNames = geStrBlock_Create(); + if (B->BoneNames == NULL) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + geBody_DestroyPossiblyIncompleteBody(&B); + return NULL; + } + B->MaterialNames = geStrBlock_Create(); + + if (B->MaterialNames == NULL) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + geBody_DestroyPossiblyIncompleteBody(&B); + return NULL; + } + + assert( geBody_SanityCheck(B) != GE_FALSE ); + return B; +} + +void GENESISCC geBody_Destroy(geBody **PB) +{ + assert( PB != NULL ); + assert( *PB != NULL ); + assert( geBody_IsValid(*PB) != GE_FALSE ); + geBody_DestroyPossiblyIncompleteBody( PB ); +} + + +geBoolean GENESISCC geBody_GetGeometryStats(const geBody *B, int lod, int *Vertices, int *Faces, int *Normals) +{ + assert( geBody_IsValid(B) == GE_TRUE ); + assert( ( lod >=0 ) && ( lod < GE_BODY_NUMBER_OF_LOD ) ); + *Vertices = B->XSkinVertexCount; + *Faces = B->SkinFaces[lod].FaceCount; + *Normals = B->SkinNormalCount; + return GE_TRUE; +} + + + +int GENESISCC geBody_GetBoneCount(const geBody *B) +{ + assert( B != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + return B->BoneCount; +} + +void GENESISCC geBody_GetBone(const geBody *B, + int BoneIndex, + const char **BoneName, + geXForm3d *Attachment, + int *ParentBoneIndex) +{ + assert( B != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + assert( Attachment != NULL ); + assert( ParentBoneIndex != NULL ); + assert( BoneName != NULL ); + + assert( BoneIndex >=0 ); + assert( BoneIndex < B->BoneCount ); + *Attachment = B->BoneArray[BoneIndex].AttachmentMatrix; + *ParentBoneIndex = B->BoneArray[BoneIndex].ParentBoneIndex; + *BoneName = geStrBlock_GetString(B->BoneNames,BoneIndex); +} + +int32 GENESISCC geBody_GetBoneNameChecksum(const geBody *B) +{ + assert( geBody_IsValid(B) != GE_FALSE ); + + if (B->BoneNames != NULL) + { + return geStrBlock_GetChecksum( B->BoneNames ); + } + else + return 0; +} + + +geBoolean GENESISCC geBody_GetBoundingBox( const geBody *B, + int BoneIndex, + geVec3d *MinimumBoxCorner, + geVec3d *MaximumBoxCorner) +{ + assert( B != NULL); + assert( MinimumBoxCorner != NULL ); + assert( MaximumBoxCorner != NULL ); + assert( (BoneIndex >=0) || (BoneIndex == GE_BODY_ROOT)); + assert( (BoneIndex < B->BoneCount) || (BoneIndex == GE_BODY_ROOT)); + if (BoneIndex == GE_BODY_ROOT) + { + #pragma message ("discontinue this?") + *MinimumBoxCorner = B->BoundingBoxMin; + *MaximumBoxCorner = B->BoundingBoxMax; + } + else + { + geBody_Bone *Bone = &(B->BoneArray[BoneIndex]); + + if (Bone->BoundingBoxMin.X > Bone->BoundingBoxMax.X) + { + return GE_FALSE; + } + *MinimumBoxCorner = Bone->BoundingBoxMin; + *MaximumBoxCorner = Bone->BoundingBoxMax; + } + return GE_TRUE; +} + +void GENESISCC geBody_SetBoundingBox( geBody *B, + int BoneIndex, + const geVec3d *MinimumBoxCorner, + const geVec3d *MaximumBoxCorner) +{ + assert( B != NULL); + assert( MinimumBoxCorner != NULL ); + assert( MaximumBoxCorner != NULL ); + assert( (BoneIndex >=0) || (BoneIndex == GE_BODY_ROOT)); + assert( (BoneIndex < B->BoneCount) || (BoneIndex == GE_BODY_ROOT)); + if (BoneIndex == GE_BODY_ROOT) + { + B->BoundingBoxMin = *MinimumBoxCorner; + B->BoundingBoxMax = *MaximumBoxCorner; + } + else + { + B->BoneArray[BoneIndex].BoundingBoxMin = *MinimumBoxCorner; + B->BoneArray[BoneIndex].BoundingBoxMax = *MaximumBoxCorner; + } +} + + + + +geBoolean GENESISCC geBody_GetBoneByName(const geBody* B, + const char* BoneName, + int* pBoneIndex, + geXForm3d* Attachment, + int* pParentBoneIndex) +{ + assert( B != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + assert( Attachment != NULL ); + assert( pParentBoneIndex != NULL ); + assert( pBoneIndex != NULL ); + assert( BoneName != NULL ); + + if(geStrBlock_FindString(B->BoneNames, BoneName, pBoneIndex) == GE_TRUE) + { + *Attachment = B->BoneArray[*pBoneIndex].AttachmentMatrix; + *pParentBoneIndex = B->BoneArray[*pBoneIndex].ParentBoneIndex; + + return GE_TRUE; + } + + return GE_FALSE; +} + +int GENESISCC geBody_GetMaterialCount(const geBody *B) +{ + assert( B != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + return B->MaterialCount; +} + +#define GE_BODY_TOLERANCE (0.001f) + +static geBoolean GENESISCC geBody_XSkinVertexCompare( + const geBody_XSkinVertex *SV1, + const geBody_XSkinVertex *SV2) +{ + assert( SV1 != NULL ); + assert( SV2 != NULL ); + if (geVec3d_Compare( &(SV1->XPoint), &(SV2->XPoint), + GE_BODY_TOLERANCE) == GE_FALSE) + { + return GE_FALSE; + } + if (geVec3d_Compare( &(SV1->XPoint), &(SV2->XPoint), + GE_BODY_TOLERANCE) == GE_FALSE) + { + return GE_FALSE; + } + if (fabs(SV1->XU - SV2->XU) > GE_BODY_TOLERANCE) + { + return GE_FALSE; + } + if (fabs(SV1->XV - SV2->XV) > GE_BODY_TOLERANCE) + { + return GE_FALSE; + } + return GE_TRUE; +} + + +static void GENESISCC geBody_SwapVertexIndices( geBody *B, geBody_Index Index1, geBody_Index Index2) + // zips through all triangles, and swaps index1 and index2. +{ + int i,j,lod; + geBody_Index Count; + geBody_Triangle *T; + + assert( B!=NULL ); + for (lod = 0; lod< GE_BODY_NUMBER_OF_LOD; lod++) + { + Count = B->SkinFaces[lod].FaceCount; + for (i=0,T=B->SkinFaces[lod].FaceArray; + iVtxIndex[j] == Index1) + { + T->VtxIndex[j] = Index2; + } + else + { + if (T->VtxIndex[j] == Index2) + { + T->VtxIndex[j] = Index1; + } + } + } + } + } +} + +static void GENESISCC geBody_ChangeVertexIndex( geBody *B, geBody_Index Index1, geBody_Index Index2) + // zips through all triangles, and changes index1 to index2. +{ + int i,j,lod; + geBody_Index Count; + geBody_Triangle *T; + + assert( B!=NULL ); + for (lod = 0; lod< GE_BODY_NUMBER_OF_LOD; lod++) + { + Count = B->SkinFaces[lod].FaceCount; + for (i=0,T=B->SkinFaces[lod].FaceArray; + iVtxIndex[j] == Index1) + { + T->VtxIndex[j] = Index2; + } + } + } + } +} + +static void GENESISCC geBody_SortSkinVertices( geBody *B ) +{ + int i,j; + int Count; + geBoolean AnyChanges = GE_FALSE; + assert( B != NULL ); + + Count = B->XSkinVertexCount; + for (i=0; iXSkinVertexArray[j].BoneIndex > B->XSkinVertexArray[j+1].BoneIndex) + { + geBody_XSkinVertex Swap; + + Swap= B->XSkinVertexArray[j]; + B->XSkinVertexArray[j] = B->XSkinVertexArray[j+1]; + B->XSkinVertexArray[j+1] = Swap; + geBody_SwapVertexIndices(B,(geBody_Index)j,(geBody_Index)(j+1)); + AnyChanges = GE_TRUE; + } + } + if (AnyChanges != GE_TRUE) + { + break; + } + AnyChanges = GE_FALSE; + } +} + + +static geBoolean GENESISCC geBody_AddSkinVertex( geBody *B, + const geVec3d *Vertex, + geFloat U, geFloat V, + geBody_Index BoneIndex, + geBody_Index *Index) +{ + geBody_Bone *Bone; + geBody_XSkinVertex *SV; + geBody_XSkinVertex NewSV; + int i; + assert( B != NULL ); + assert( Vertex != NULL ); + assert( Index != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + + assert( B->XSkinVertexCount+1 > 0 ); + + NewSV.XPoint = *Vertex; + NewSV.XU = U; + NewSV.XV = V; + NewSV.LevelOfDetailMask = GE_BODY_HIGHEST_LOD_MASK; + NewSV.BoneIndex = BoneIndex; + + assert( B->BoneCount > BoneIndex ); + Bone = &(B->BoneArray[BoneIndex]); + + + // see if new Vertex is alreay in XSkinVertexArray + for (i=0; iXSkinVertexCount; i++) + { + SV = &(B->XSkinVertexArray[i]); + if (SV->BoneIndex == BoneIndex) + { + if (geBody_XSkinVertexCompare(SV,&NewSV) == GE_TRUE ) + { + *Index = (geBody_Index)i; + return GE_TRUE; + } + } + } + // new Vertex needs to be added to XSkinVertexArray + SV = GE_RAM_REALLOC_ARRAY( B->XSkinVertexArray , + geBody_XSkinVertex, (B->XSkinVertexCount + 1) ); + if ( SV == NULL ) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return GE_FALSE; + } + B->XSkinVertexArray = SV; + + B->XSkinVertexArray[B->XSkinVertexCount] = NewSV; + *Index = B->XSkinVertexCount; + + Bone->BoundingBoxMin.X = MIN(Bone->BoundingBoxMin.X,NewSV.XPoint.X); + Bone->BoundingBoxMin.Y = MIN(Bone->BoundingBoxMin.Y,NewSV.XPoint.Y); + Bone->BoundingBoxMin.Z = MIN(Bone->BoundingBoxMin.Z,NewSV.XPoint.Z); + Bone->BoundingBoxMax.X = MAX(Bone->BoundingBoxMax.X,NewSV.XPoint.X); + Bone->BoundingBoxMax.Y = MAX(Bone->BoundingBoxMax.Y,NewSV.XPoint.Y); + Bone->BoundingBoxMax.Z = MAX(Bone->BoundingBoxMax.Z,NewSV.XPoint.Z); + + B->XSkinVertexCount ++ ; + return GE_TRUE; +} + +static geBoolean GENESISCC geBody_AddNormal( geBody *B, + const geVec3d *Normal, + geBody_Index BoneIndex, + geBody_Index *Index ) +{ + geBody_Normal *NewNormalArray; + geBody_Normal *N; + geVec3d NNorm; + int i; + + assert( B != NULL ); + assert( Normal != NULL ); + assert( Index != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + + assert( B->SkinNormalCount+1 > 0 ); + NNorm = *Normal; + geVec3d_Normalize(&NNorm); + // see if new normal is alreay in SkinNormalArray + for (i=0, N = B->SkinNormalArray; iSkinNormalCount; i++,N++) + { + if (N->BoneIndex == BoneIndex) + { + if ( geVec3d_Compare( &(N->Normal),&NNorm,GE_BODY_TOLERANCE ) == GE_TRUE ) + { + *Index = (geBody_Index)i; + return GE_TRUE; + } + } + } + + // new normal needs to be added to SkinNormalArray + NewNormalArray = GE_RAM_REALLOC_ARRAY( B->SkinNormalArray, + geBody_Normal,(B->SkinNormalCount+1)); + if (NewNormalArray == NULL) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return GE_FALSE; + } + B->SkinNormalArray = NewNormalArray; + B->SkinNormalArray[ B->SkinNormalCount ].Normal = NNorm; + B->SkinNormalArray[ B->SkinNormalCount ].BoneIndex = BoneIndex; + B->SkinNormalArray[ B->SkinNormalCount ].LevelOfDetailMask = GE_BODY_HIGHEST_LOD_MASK; + *Index = B->SkinNormalCount; + B->SkinNormalCount ++ ; + return GE_TRUE; +} + +static geBoolean GENESISCC geBody_AddToFaces( geBody *B, geBody_Triangle *F, int DetailLevel ) +{ + geBody_Triangle *NewFaceArray; + geBody_TriangleList *FL; + + assert( B != NULL ); + assert( F != NULL ); + assert( DetailLevel >= 0); + assert( DetailLevel < GE_BODY_NUMBER_OF_LOD ); + assert( geBody_IsValid(B) != GE_FALSE ); + + FL = &( B->SkinFaces[DetailLevel] ); + + assert( F->MaterialIndex >= 0 ); + assert( F->MaterialIndex < B->MaterialCount ); + + NewFaceArray = GE_RAM_REALLOC_ARRAY( FL->FaceArray, + geBody_Triangle,(FL->FaceCount+1) ); + if ( NewFaceArray == NULL ) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return GE_FALSE; + } + + FL->FaceArray = NewFaceArray; + + { + int i; + // insertion sort new face into FaceArray keyed on MaterialIndex + geBody_Index MaterialIndex = F->MaterialIndex; + for (i=FL->FaceCount; i>=1; i--) + { + if (FL->FaceArray[i-1].MaterialIndex <= MaterialIndex) + break; + FL->FaceArray[i] = FL->FaceArray[i-1]; + } + + FL->FaceArray[i] = *F; + } + FL->FaceCount ++; + + return GE_TRUE; +} + + + +geBoolean GENESISCC geBody_AddFace( geBody *B, + const geVec3d *Vertex1, const geVec3d *Normal1, + geFloat U1, geFloat V1, int BoneIndex1, + const geVec3d *Vertex2, const geVec3d *Normal2, + geFloat U2, geFloat V2, int BoneIndex2, + const geVec3d *Vertex3, const geVec3d *Normal3, + geFloat U3, geFloat V3, int BoneIndex3, + int MaterialIndex) +{ + geBody_Triangle F; + + assert( B != NULL ); + assert( Vertex1 != NULL ); + assert( Normal1 != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + + assert( BoneIndex1 >= 0 ); + assert( BoneIndex1 < B->BoneCount ); + + assert( Vertex2 != NULL ); + assert( Normal2 != NULL ); + assert( BoneIndex2 >= 0 ); + assert( BoneIndex2 < B->BoneCount ); + + assert( Vertex3 != NULL ); + assert( Normal3 != NULL ); + assert( BoneIndex3 >= 0 ); + assert( BoneIndex3 < B->BoneCount ); + + assert( MaterialIndex >= 0 ); + assert( MaterialIndex < B->MaterialCount ); + + if (geBody_AddSkinVertex(B,Vertex1,U1,V1,(geBody_Index)BoneIndex1,&(F.VtxIndex[0]))==GE_FALSE) + { // error already recorded + return GE_FALSE; + } + if (geBody_AddSkinVertex(B,Vertex2,U2,V2,(geBody_Index)BoneIndex2,&(F.VtxIndex[1]))==GE_FALSE) + { // error already recorded + return GE_FALSE; + } + if (geBody_AddSkinVertex(B,Vertex3,U3,V3,(geBody_Index)BoneIndex3,&(F.VtxIndex[2]))==GE_FALSE) + { // error already recorded + return GE_FALSE; + } + + if (geBody_AddNormal( B, Normal1, (geBody_Index)BoneIndex1, &(F.NormalIndex[0]) ) == GE_FALSE) + { // error already recorded + return GE_FALSE; + } + if (geBody_AddNormal( B, Normal2, (geBody_Index)BoneIndex2, &(F.NormalIndex[1]) ) == GE_FALSE) + { // error already recorded + return GE_FALSE; + } + if (geBody_AddNormal( B, Normal3, (geBody_Index)BoneIndex3, &(F.NormalIndex[2]) ) == GE_FALSE) + { // error already recorded + return GE_FALSE; + } + + F.MaterialIndex = (geBody_Index)MaterialIndex; + if (geBody_AddToFaces( B, &F, GE_BODY_HIGHEST_LOD ) == GE_FALSE) + { // error already recorded + return GE_FALSE; + } + + geBody_SortSkinVertices(B); + + return GE_TRUE; + +} + + +geBoolean GENESISCC geBody_AddMaterial( geBody *B, + const char *MaterialName, + geBitmap *Bitmap, + geFloat Red, geFloat Green, geFloat Blue, + int *MaterialIndex) +{ + int FoundIndex; + geBody_Material *NewMaterial; + assert( B != NULL ); + assert( MaterialIndex != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + assert( B->MaterialCount >= 0 ); + + if (MaterialName == NULL) + { + geErrorLog_AddString(-1,"Can't add material - name can not be NULL", NULL); + return GE_FALSE; + } + if (MaterialName[0] == 0) + { + geErrorLog_AddString(-1,"Can't add material - name must have > 0 length", NULL); + return GE_FALSE; + } + if (geStrBlock_FindString(B->MaterialNames, MaterialName, &FoundIndex) == GE_TRUE) + { + geErrorLog_AddString(-1,"Can't add material - name already used", NULL); + return GE_FALSE; + } + + + NewMaterial = GE_RAM_REALLOC_ARRAY( B->MaterialArray, + geBody_Material,(B->MaterialCount+1) ); + if ( NewMaterial == NULL ) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return GE_FALSE; + } + + + B->MaterialArray = NewMaterial; + if (geStrBlock_Append(&(B->MaterialNames),MaterialName) == GE_FALSE) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return GE_FALSE; + } + + { + geBody_Material *M = &(B->MaterialArray[B->MaterialCount]); + M->Bitmap = Bitmap; + if (Bitmap != NULL) + geBitmap_CreateRef(Bitmap); + M->Red = Red; + M->Green = Green; + M->Blue = Blue; + + } + *MaterialIndex = B->MaterialCount; + B->MaterialCount ++; + return GE_TRUE; +} + +geBoolean GENESISCC geBody_GetMaterial(const geBody *B, int MaterialIndex, + const char **MaterialName, + geBitmap **Bitmap, geFloat *Red, geFloat *Green, geFloat *Blue) +{ + assert( B != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + assert( Red != NULL ); + assert( Green != NULL ); + assert( Blue != NULL ); + assert( Bitmap != NULL ); + assert( MaterialIndex >= 0 ); + assert( MaterialIndex < B->MaterialCount ); + assert( MaterialName != NULL ); + *MaterialName = geStrBlock_GetString(B->MaterialNames,MaterialIndex); + + { + geBody_Material *M = &(B->MaterialArray[MaterialIndex]); + *Bitmap = M->Bitmap; + *Red = M->Red; + *Green = M->Green; + *Blue = M->Blue; + } + return GE_TRUE; +} + +geBoolean GENESISCC geBody_SetMaterial(geBody *B, int MaterialIndex, + geBitmap *Bitmap, geFloat Red, geFloat Green, geFloat Blue) +{ + assert( geBody_IsValid(B) != GE_FALSE ); + assert( MaterialIndex >= 0 ); + assert( MaterialIndex < B->MaterialCount ); + { + geBody_Material *M = &(B->MaterialArray[MaterialIndex]); + M->Bitmap = Bitmap; + if (Bitmap != NULL) + geBitmap_CreateRef(Bitmap); + M->Red = Red; + M->Green = Green; + M->Blue = Blue; + } + return GE_TRUE; +} + + + + +geBoolean GENESISCC geBody_AddBone( geBody *B, + int ParentBoneIndex, + const char *BoneName, + const geXForm3d *AttachmentMatrix, + int *BoneIndex) +{ + geBody_Bone *NewBones; + assert( B != NULL ); + assert( BoneName != NULL ); + assert( BoneIndex != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + + assert( ParentBoneIndex < B->BoneCount ); + assert( ( ParentBoneIndex >= 0) || (ParentBoneIndex == GE_BODY_NO_PARENT_BONE)); + assert( B->BoneCount >= 0 ); + + NewBones = GE_RAM_REALLOC_ARRAY( B->BoneArray, + geBody_Bone, (B->BoneCount+1) ); + if ( NewBones == NULL ) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return GE_FALSE; + } + + B->BoneArray = NewBones; + if (geStrBlock_Append(&(B->BoneNames),BoneName) == GE_FALSE) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return GE_FALSE; + } + + { + geBody_Bone *Bone = &(B->BoneArray[B->BoneCount]); + geVec3d_Set(&(Bone->BoundingBoxMin), + GE_BODY_REALLY_BIG_NUMBER,GE_BODY_REALLY_BIG_NUMBER,GE_BODY_REALLY_BIG_NUMBER); + geVec3d_Set(&(Bone->BoundingBoxMax), + -GE_BODY_REALLY_BIG_NUMBER,-GE_BODY_REALLY_BIG_NUMBER,-GE_BODY_REALLY_BIG_NUMBER); + Bone->AttachmentMatrix = *AttachmentMatrix; + Bone->ParentBoneIndex = (geBody_Index)ParentBoneIndex; + } + *BoneIndex = B->BoneCount; + B->BoneCount++; + return GE_TRUE; +} + + + +geBoolean GENESISCC geBody_ComputeLevelsOfDetail( geBody *B ,int Levels) +{ + assert( B != NULL); + assert( Levels >= 0 ); + assert( Levels < GE_BODY_NUMBER_OF_LOD ); + assert( geBody_IsValid(B) != GE_FALSE ); + #pragma message ("LOD code goes here:") + B->LevelsOfDetail = GE_BODY_HIGHEST_LOD_MASK; // Levels + Levels; + return GE_TRUE; +} + + + + + +#define GE_BODY_GEOMETRY_NAME "Geometry" +#define GE_BODY_BITMAP_DIRECTORY_NAME "Bitmaps" + +#define GE_BODY_FILE_TYPE 0x5E444F42 // 'BODY' +#define GE_BODY_FILE_VERSION 0x00F1 // Restrict version to 16 bits + + + + +static geBoolean GENESISCC geBody_ReadGeometry(geBody *B, geVFile *pFile) +{ + uint32 u; + int i; + + assert( B != NULL ); + assert( pFile != NULL ); + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + if (u!=GE_BODY_FILE_TYPE) + { geErrorLog_Add( ERR_BODY_FILE_PARSE , NULL); return GE_FALSE; } + + + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + if (u!=GE_BODY_FILE_VERSION) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + + if(geVFile_Read(pFile, &(B->BoundingBoxMin), sizeof(B->BoundingBoxMin)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + if(geVFile_Read(pFile, &(B->BoundingBoxMax), sizeof(B->BoundingBoxMax)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + if(geVFile_Read(pFile, &(B->XSkinVertexCount), sizeof(B->XSkinVertexCount)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + if (B->XSkinVertexCount>0) + { + u = sizeof(geBody_XSkinVertex) * B->XSkinVertexCount; + B->XSkinVertexArray = geRam_Allocate(u); + if (B->XSkinVertexArray == NULL) + { geErrorLog_Add( ERR_BODY_ENOMEM , NULL); return GE_FALSE; } + if(geVFile_Read(pFile, B->XSkinVertexArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + } + + if(geVFile_Read(pFile, &(B->SkinNormalCount), sizeof(B->SkinNormalCount)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + if (B->SkinNormalCount>0) + { + u = sizeof(geBody_Normal) * B->SkinNormalCount; + B->SkinNormalArray = geRam_Allocate(u); + if (B->SkinNormalArray == NULL) + { geErrorLog_Add( ERR_BODY_ENOMEM , NULL); return GE_FALSE; } + if(geVFile_Read(pFile, B->SkinNormalArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + } + + if(geVFile_Read(pFile, &(B->BoneCount), sizeof(B->BoneCount)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + if (B->BoneCount>0) + { + u = sizeof(geBody_Bone) * B->BoneCount; + B->BoneArray = geRam_Allocate(u); + if (B->BoneArray == NULL) + { geErrorLog_Add( ERR_BODY_ENOMEM , NULL); return GE_FALSE; } + if(geVFile_Read(pFile, B->BoneArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + } + + B->BoneNames = geStrBlock_CreateFromFile(pFile); + if (B->BoneNames==NULL) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + if(geVFile_Read(pFile, &(B->MaterialCount), sizeof(B->MaterialCount)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + if (B->MaterialCount>0) + { + u = sizeof(geBody_Material) * B->MaterialCount; + B->MaterialArray = geRam_Allocate(u); + if (B->MaterialArray == NULL) + { geErrorLog_Add( ERR_BODY_ENOMEM , NULL); return GE_FALSE; } + if(geVFile_Read(pFile, B->MaterialArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + // CB added this nastiness because it seems the Bitmap pointer is + // read in with the Material array, and is later used as a boolean + // for "should this material have a texture" + for(u=0;u<(uint32)B->MaterialCount;u++) + { + if ( B->MaterialArray[u].Bitmap ) + B->MaterialArray[u].Bitmap = (geBitmap *)1; + } + } + + B->MaterialNames = geStrBlock_CreateFromFile(pFile); + if ( B->MaterialNames == NULL ) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + if(geVFile_Read(pFile, &(B->LevelsOfDetail), sizeof(B->LevelsOfDetail)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + if (B->LevelsOfDetail > GE_BODY_NUMBER_OF_LOD) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + + for (i=0; iLevelsOfDetail; i++) + { + if(geVFile_Read(pFile, &(u), sizeof(u)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + B->SkinFaces[i].FaceCount = (geBody_Index)u; + + if (u>0) + { + u = sizeof(geBody_Triangle) * u; + B->SkinFaces[i].FaceArray = geRam_Allocate(u); + if (B->SkinFaces[i].FaceArray == NULL) + { geErrorLog_Add( ERR_BODY_ENOMEM , NULL); return GE_FALSE; } + if(geVFile_Read(pFile, B->SkinFaces[i].FaceArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); return GE_FALSE; } + } + } + + assert( geBody_IsValid(B) != GE_FALSE ); + return GE_TRUE; +} + +geBody *GENESISCC geBody_CreateFromFile(geVFile *pFile) +{ + geBody *B; + int i; + + geVFile *VFile; + geVFile *SubFile=NULL; + geVFile *BitmapDirectory=NULL; + + assert( pFile != NULL ); + + VFile = geVFile_OpenNewSystem(pFile,GE_VFILE_TYPE_VIRTUAL, NULL, + NULL, GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_READONLY); + if (VFile == NULL) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); goto CreateError;} + + SubFile = geVFile_Open(VFile,GE_BODY_GEOMETRY_NAME,GE_VFILE_OPEN_READONLY); + if (SubFile == NULL) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); goto CreateError;} + + B = geBody_CreateNull(); + if (B==NULL) + { geErrorLog_Add( ERR_BODY_ENOMEM , NULL); goto CreateError; } + + if (geBody_ReadGeometry(B,SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); goto CreateError;} + geVFile_Close(SubFile); + + BitmapDirectory = geVFile_Open(VFile,GE_BODY_BITMAP_DIRECTORY_NAME, + GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_READONLY); + if (BitmapDirectory == NULL) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); goto CreateError;} + + for (i=0; iMaterialCount; i++) + { + geBody_Material *M; + M = &(B->MaterialArray[i]); + + if (M->Bitmap != NULL) + { + char FName[1000]; + sprintf(FName,"%d",i); + + SubFile = geVFile_Open(BitmapDirectory,FName,GE_VFILE_OPEN_READONLY); + if (SubFile == NULL) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); goto CreateError;} + + M->Bitmap = geBitmap_CreateFromFile(SubFile); + + if (M->Bitmap == NULL) + { geErrorLog_Add( ERR_BODY_FILE_READ , NULL); goto CreateError;} + + #if 1 + // Set the number of mips to 4 + if (!geBitmap_SetMipCount(M->Bitmap, 4)) + { + geErrorLog_Add( ERR_BODY_FILE_READ , NULL); + goto CreateError; + } + #endif + + geVFile_Close(SubFile); + } + } + geVFile_Close(BitmapDirectory); + geVFile_Close(VFile); + return B; + + CreateError: + geBody_DestroyPossiblyIncompleteBody(&B); + if (SubFile != NULL) + geVFile_Close(SubFile); + if (BitmapDirectory != NULL) + geVFile_Close(BitmapDirectory); + if (VFile != NULL) + geVFile_Close(VFile); + return NULL; +} + + + +geBoolean GENESISCC geBody_WriteGeometry(const geBody *B,geVFile *pFile) +{ + uint32 u; + int i; + + assert( B != NULL ); + assert( pFile != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + + // Write the format flag + u = GE_BODY_FILE_TYPE; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + // Write the version + u = GE_BODY_FILE_VERSION; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + if(geVFile_Write(pFile, &(B->BoundingBoxMin), sizeof(B->BoundingBoxMin)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + if(geVFile_Write(pFile, &(B->BoundingBoxMax), sizeof(B->BoundingBoxMax)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + if(geVFile_Write(pFile, &(B->XSkinVertexCount), sizeof(B->XSkinVertexCount)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + assert( (B->XSkinVertexCount==0) || (B->XSkinVertexArray!=NULL)); + + if (B->XSkinVertexCount>0) + { + u = sizeof(geBody_XSkinVertex) * B->XSkinVertexCount; + if(geVFile_Write(pFile, B->XSkinVertexArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + } + + if(geVFile_Write(pFile, &(B->SkinNormalCount), sizeof(B->SkinNormalCount)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + if (B->SkinNormalCount>0) + { + u = sizeof(geBody_Normal) * B->SkinNormalCount; + if(geVFile_Write(pFile, B->SkinNormalArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + } + + if(geVFile_Write(pFile, &(B->BoneCount), sizeof(B->BoneCount)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + if (B->BoneCount>0) + { + u = sizeof(geBody_Bone) * B->BoneCount; + if(geVFile_Write(pFile, B->BoneArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + } + + if (geStrBlock_WriteToBinaryFile(B->BoneNames,pFile)==GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + if(geVFile_Write(pFile, &(B->MaterialCount), sizeof(B->MaterialCount)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + if (B->MaterialCount>0) + { + u = sizeof(geBody_Material) * B->MaterialCount; + if(geVFile_Write(pFile, B->MaterialArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + } + + if (geStrBlock_WriteToBinaryFile(B->MaterialNames,pFile)==GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + if(geVFile_Write(pFile, &(B->LevelsOfDetail), sizeof(B->LevelsOfDetail)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + + for (i=0; iLevelsOfDetail; i++) + { + u = B->SkinFaces[i].FaceCount; + if(geVFile_Write(pFile, &(u), sizeof(u)) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + if (u>0) + { + u = sizeof(geBody_Triangle) * u; + if(geVFile_Write(pFile, B->SkinFaces[i].FaceArray, u) == GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); return GE_FALSE; } + } + } + return GE_TRUE; +} + + +geBoolean GENESISCC geBody_WriteToFile(const geBody *B, geVFile *pFile) +{ + int i; + geVFile *VFile; + geVFile *SubFile; + geVFile *BitmapDirectory; + + assert( geBody_IsValid(B) != GE_FALSE ); + assert( pFile != NULL ); + + VFile = geVFile_OpenNewSystem(pFile,GE_VFILE_TYPE_VIRTUAL, NULL, + NULL, GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_CREATE); + if (VFile == NULL) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + + SubFile = geVFile_Open(VFile,GE_BODY_GEOMETRY_NAME,GE_VFILE_OPEN_CREATE); + if (SubFile == NULL) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + + if (geBody_WriteGeometry(B,SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + if (geVFile_Close(SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + + BitmapDirectory = geVFile_Open(VFile,GE_BODY_BITMAP_DIRECTORY_NAME, + GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_CREATE); + if (BitmapDirectory == NULL) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + + for (i=0; iMaterialCount; i++) + { + geBody_Material *M; + M = &(B->MaterialArray[i]); + + if (M->Bitmap != NULL) + { + char FName[1000]; + sprintf(FName,"%d",i); + + SubFile = geVFile_Open(BitmapDirectory,FName,GE_VFILE_OPEN_CREATE); + if (SubFile == NULL) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + + if (geBitmap_WriteToFile(M->Bitmap,SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + + if (geVFile_Close(SubFile)==GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + } + } + if (geVFile_Close(BitmapDirectory)==GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + if (geVFile_Close(VFile)==GE_FALSE) + { geErrorLog_Add( ERR_BODY_FILE_WRITE , NULL); goto WriteError;} + + return GE_TRUE; + WriteError: + return GE_FALSE; +} diff --git a/G3D/Actor/body.h b/G3D/Actor/body.h new file mode 100644 index 0000000..186e3fc --- /dev/null +++ b/G3D/Actor/body.h @@ -0,0 +1,136 @@ +/****************************************************************************************/ +/* BODY.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Actor body interface. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_BODY_H +#define GE_BODY_H + +/* This object is for managing the data associated with a skeletal-based mesh, + a 'body'. + This object holds the geometry for the body and the list of materials needed. +*/ + +#include "basetype.h" +#include "xform3d.h" +#include "vfile.h" +#include "bitmap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GE_BODY_NUMBER_OF_LOD (4) // 0 is highest detail +#define GE_BODY_NO_PARENT_BONE (-1) +#define GE_BODY_HIGHEST_LOD (0) + +#define GE_BODY_ROOT (-1) // for specifying 'root' bounding box. + +typedef struct geBody geBody; + + + +geBody *GENESISCC geBody_Create(void); + +void GENESISCC geBody_Destroy(geBody **B); + +geBoolean GENESISCC geBody_IsValid(const geBody *B); + + +geBoolean GENESISCC geBody_GetGeometryStats(const geBody *B, int lod, int *Vertices, int *Faces, int *Normals); + +geBoolean GENESISCC geBody_AddFace( geBody *B, + const geVec3d *Vertex1, const geVec3d *Normal1, + geFloat U1, geFloat V1, int BoneIndex1, + const geVec3d *Vertex2, const geVec3d *Normal2, + geFloat U2, geFloat V2, int BoneIndex2, + const geVec3d *Vertex3, const geVec3d *Normal3, + geFloat U3, geFloat V3, int BoneIndex3, + int MaterialIndex); + + // Bitmap is added to body. It's reference count is increased. Caller still owns a pointer + // to the bitmap, and is responsible for destroying it. +geBoolean GENESISCC geBody_AddMaterial( geBody *B, + const char *MaterialName, + geBitmap *Bitmap, + geFloat Red, + geFloat Green, + geFloat Blue, + int *MaterialIndex); + + // returned bitmap is a pointer to the bitmap in the body's list. It may not be destroyed. + // if caller would like to 'own' a copy of that bitmap pointer, it should call geBitmap_CreateRef() +geBoolean GENESISCC geBody_GetMaterial(const geBody *Body, int MaterialIndex, + const char **MaterialName, + geBitmap **Bitmap, geFloat *Red, geFloat *Green, geFloat *Blue); + + // Bitmap is set into the body. It's reference count is increased. Caller still owns a pointer + // to the bitmap, and is responsible for destroying it. +geBoolean GENESISCC geBody_SetMaterial(geBody *Body, int MaterialIndex, + geBitmap *Bitmap, geFloat Red, geFloat Green, geFloat Blue); + +int GENESISCC geBody_GetMaterialCount(const geBody *B); + +geBoolean GENESISCC geBody_AddBone( geBody *B, + int ParentBoneIndex, + const char *BoneName, + const geXForm3d *AttachmentMatrix, + int *BoneIndex); + +geBoolean GENESISCC geBody_ComputeLevelsOfDetail( geBody *B ,int Levels); + +int GENESISCC geBody_GetBoneCount(const geBody *B); + +void GENESISCC geBody_GetBone( const geBody *B, + int BoneIndex, + const char **BoneName, + geXForm3d *Attachment, + int *ParentBoneIndex); + +int32 GENESISCC geBody_GetBoneNameChecksum(const geBody *B); + +void GENESISCC geBody_SetBoundingBox( geBody *B, + int BoneIndex, // GE_BODY_ROOT for specifing 'root' bounding box. + const geVec3d *MinimumBoxCorner, + const geVec3d *MaximumBoxCorner); + + +geBoolean GENESISCC geBody_GetBoundingBox( const geBody *B, + int BoneIndex, // GE_BODY_ROOT for specifing 'root' bounding box. + geVec3d *MinimumBoxCorner, + geVec3d *MaximumBoxCorner); + +geBoolean GENESISCC geBody_GetBoneByName(const geBody* B, + const char* BoneName, + int* pBoneIndex, + geXForm3d* Attachment, + int* pParentBoneIndex); + +geBoolean GENESISCC geBody_WriteToFile(const geBody *B, geVFile *pFile); +geBody *GENESISCC geBody_CreateFromFile(geVFile *pFile); + + + + +#ifdef __cplusplus +} +#endif + +#endif + \ No newline at end of file diff --git a/G3D/Actor/bodyinst.c b/G3D/Actor/bodyinst.c new file mode 100644 index 0000000..48bf919 --- /dev/null +++ b/G3D/Actor/bodyinst.c @@ -0,0 +1,369 @@ +/****************************************************************************************/ +/* BODYINST.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Actor body instance implementation. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include //assert() + +#include "body._h" +#include "bodyinst.h" +#include "ram.h" +#include "errorlog.h" +#include "strblock.h" + + + +typedef struct geBodyInst +{ + const geBody *BodyTemplate; + geBodyInst_Geometry ExportGeometry; + int LastLevelOfDetail; + geBodyInst_Index FaceCount; +} geBodyInst; + + + +void GENESISCC geBodyInst_PostScale(const geXForm3d *M,const geVec3d *S,geXForm3d *Scaled) +{ + Scaled->AX = M->AX * S->X; + Scaled->BX = M->BX * S->X; + Scaled->CX = M->CX * S->X; + + Scaled->AY = M->AY * S->Y; + Scaled->BY = M->BY * S->Y; + Scaled->CY = M->CY * S->Y; + + Scaled->AZ = M->AZ * S->Z; + Scaled->BZ = M->BZ * S->Z; + Scaled->CZ = M->CZ * S->Z; + Scaled->Translation = M->Translation; +} + + +geBodyInst *GENESISCC geBodyInst_Create(const geBody *B) +{ + geBodyInst *BI; + assert( B != NULL ); + assert( geBody_IsValid(B) != GE_FALSE ); + + BI = GE_RAM_ALLOCATE_STRUCT(geBodyInst); + if (BI == NULL) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + return NULL; + } + BI->BodyTemplate = B; + { + geBodyInst_Geometry *G = &(BI->ExportGeometry); + G->SkinVertexCount =0; + G->SkinVertexArray = NULL; + + G->NormalCount = 0; + G->NormalArray = NULL; + + G->FaceCount = (geBody_Index) 0; + G->FaceListSize = 0; + G->FaceList = NULL; + } + + BI->LastLevelOfDetail = -1; + BI->FaceCount = 0; + + return BI; +} + + +void GENESISCC geBodyInst_Destroy( geBodyInst **BI) +{ + geBodyInst_Geometry *G; + assert( BI != NULL ); + assert( *BI != NULL ); + G = &( (*BI)->ExportGeometry ); + if (G->SkinVertexArray != NULL ) + { + geRam_Free( G->SkinVertexArray ); + G->SkinVertexArray = NULL; + } + if (G->NormalArray != NULL ) + { + geRam_Free( G->NormalArray ); + G->NormalArray = NULL; + } + if (G->FaceList != NULL ) + { + geRam_Free( G->FaceList ); + G->FaceList = NULL; + } + geRam_Free( *BI ); + *BI = NULL; +} + + + +#define GE_BODYINST_FACELIST_SIZE_FOR_TRIANGLE (8) + +static geBodyInst_Geometry *GENESISCC geBodyInst_GetGeometryPrep( + geBodyInst *BI, + int LevelOfDetail) +{ + const geBody *B; + geBodyInst_Geometry *G; + + assert( BI != NULL ); + assert( geBody_IsValid(BI->BodyTemplate) != GE_FALSE ); + B = BI->BodyTemplate; + + G = &(BI->ExportGeometry); + assert( G != NULL ); + + if (G->SkinVertexCount != B->XSkinVertexCount) + { + if (G->SkinVertexArray!=NULL) + { + geRam_Free(G->SkinVertexArray); + } + G->SkinVertexArray = GE_RAM_ALLOCATE_ARRAY(geBodyInst_SkinVertex,B->XSkinVertexCount); + if ( G->SkinVertexArray == NULL ) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + G->SkinVertexCount = 0; + return NULL; + } + G->SkinVertexCount = B->XSkinVertexCount; + } + + if (G->NormalCount != B->SkinNormalCount) + { + if (G->NormalArray!=NULL) + { + geRam_Free(G->NormalArray); + } + G->NormalArray = GE_RAM_ALLOCATE_ARRAY( geVec3d,B->SkinNormalCount); + if ( G->NormalArray == NULL ) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + G->NormalCount = 0; + return NULL; + } + G->NormalCount = B->SkinNormalCount; + } + + if (BI->FaceCount != B->SkinFaces[GE_BODY_HIGHEST_LOD].FaceCount) + { + if (G->FaceList!=NULL) + { + geRam_Free(G->FaceList); + } + G->FaceListSize = sizeof(geBody_Index) * + B->SkinFaces[GE_BODY_HIGHEST_LOD].FaceCount * + GE_BODYINST_FACELIST_SIZE_FOR_TRIANGLE; + G->FaceList = GE_RAM_ALLOCATE_ARRAY(geBody_Index, + B->SkinFaces[GE_BODY_HIGHEST_LOD].FaceCount * + GE_BODYINST_FACELIST_SIZE_FOR_TRIANGLE); + if ( G->FaceList == NULL ) + { + geErrorLog_Add(ERR_BODY_ENOMEM, NULL); + BI->FaceCount = 0; + return NULL; + } + BI->FaceCount = B->SkinFaces[GE_BODY_HIGHEST_LOD].FaceCount; + } + return G; +} + +const geBodyInst_Geometry *GENESISCC geBodyInst_GetGeometry( + const geBodyInst *BI, + const geVec3d *ScaleVector, + const geXFArray *BoneTransformArray, + int LevelOfDetail, + const geCamera *Camera) +{ + geBodyInst_Geometry *G; + const geBody *B; + geXForm3d *BoneXFArray; + int BoneXFCount; + geBody_Index BoneIndex; + + geBoolean GottaUpdateFaces = GE_FALSE; + assert( BI != NULL ); + assert( BoneTransformArray != NULL ); + assert( geBody_IsValid(BI->BodyTemplate) != GE_FALSE ); + + G = geBodyInst_GetGeometryPrep((geBodyInst *)BI,LevelOfDetail); + if (G == NULL) + { + return NULL; + } + + + B = BI->BodyTemplate; + + BoneXFArray = geXFArray_GetElements(BoneTransformArray,&BoneXFCount); + if ( BoneXFArray == NULL) + { + geErrorLog_Add(ERR_BODY_BONEXFARRAY, NULL); + return NULL; + } + if (BoneXFCount != B->BoneCount) + { + geErrorLog_Add(ERR_BODY_BONEXFARRAY, NULL); + return NULL; + } + + + { + int i,LevelOfDetailBit; + + if (Camera != NULL) + { + // transform and project all appropriate points + geBody_XSkinVertex *S; + geBodyInst_SkinVertex *D; + LevelOfDetailBit = 1 << LevelOfDetail; + BoneIndex = -1; // S->BoneIndex won't ever be this. + geVec3d_Set(&(G->Maxs), -GE_BODY_REALLY_BIG_NUMBER, -GE_BODY_REALLY_BIG_NUMBER, -GE_BODY_REALLY_BIG_NUMBER ); + geVec3d_Set(&(G->Mins), GE_BODY_REALLY_BIG_NUMBER, GE_BODY_REALLY_BIG_NUMBER, GE_BODY_REALLY_BIG_NUMBER ); + for (i=B->XSkinVertexCount,S=B->XSkinVertexArray,D=G->SkinVertexArray; + i>0; + i--,S++,D++) + { + geXForm3d ObjectToCamera; + if (S->BoneIndex!=BoneIndex) + { //Keep XSkinVertexArray sorted by BoneIndex for best performance + BoneIndex = S->BoneIndex; + geXForm3d_Multiply( geCamera_GetCameraSpaceXForm(Camera), + &(BoneXFArray[BoneIndex]), + &ObjectToCamera); + geBodyInst_PostScale(&ObjectToCamera,ScaleVector,&ObjectToCamera); + } + if ( S->LevelOfDetailMask && LevelOfDetailBit ) + { + geVec3d *VecDestPtr = &(D->SVPoint); + geXForm3d_Transform( &(ObjectToCamera), + &(S->XPoint),VecDestPtr); + #ifdef ONE_OVER_Z_PIPELINE + geCamera_ProjectZ( Camera, VecDestPtr, VecDestPtr); + #else + geCamera_Project( Camera, VecDestPtr, VecDestPtr); + #endif + D->SVU = S->XU; + D->SVV = S->XV; + if (VecDestPtr->X > G->Maxs.X ) G->Maxs.X = VecDestPtr->X; + if (VecDestPtr->X < G->Mins.X ) G->Mins.X = VecDestPtr->X; + if (VecDestPtr->Y > G->Maxs.Y ) G->Maxs.Y = VecDestPtr->Y; + if (VecDestPtr->Y < G->Mins.Y ) G->Mins.Y = VecDestPtr->Y; + if (VecDestPtr->Z > G->Maxs.Z ) G->Maxs.Z = VecDestPtr->Z; + if (VecDestPtr->Z < G->Mins.Z ) G->Mins.Z = VecDestPtr->Z; + D->ReferenceBoneIndex=BoneIndex; + } + } + } + else + { + // transform all appropriate points + geBody_XSkinVertex *S; + geBodyInst_SkinVertex *D; + LevelOfDetailBit = 1 << LevelOfDetail; + BoneIndex = -1; // S->BoneIndex won't ever be this. + geVec3d_Set(&(G->Maxs), -GE_BODY_REALLY_BIG_NUMBER, -GE_BODY_REALLY_BIG_NUMBER, -GE_BODY_REALLY_BIG_NUMBER ); + geVec3d_Set(&(G->Mins), GE_BODY_REALLY_BIG_NUMBER, GE_BODY_REALLY_BIG_NUMBER, GE_BODY_REALLY_BIG_NUMBER ); + + for (i=B->XSkinVertexCount,S=B->XSkinVertexArray,D=G->SkinVertexArray; + i>0; + i--,S++,D++) + { + geXForm3d ObjectToWorld; + if (S->BoneIndex!=BoneIndex) + { //Keep XSkinVertexArray sorted by BoneIndex for best performance + BoneIndex = S->BoneIndex; + geBodyInst_PostScale(&BoneXFArray[BoneIndex],ScaleVector,&ObjectToWorld); + + } + if ( S->LevelOfDetailMask && LevelOfDetailBit ) + { + geVec3d *VecDestPtr = &(D->SVPoint); + geXForm3d_Transform( &(ObjectToWorld), + &(S->XPoint),VecDestPtr); + D->SVU = S->XU; + D->SVV = S->XV; + if (VecDestPtr->X > G->Maxs.X ) G->Maxs.X = VecDestPtr->X; + if (VecDestPtr->X < G->Mins.X ) G->Mins.X = VecDestPtr->X; + if (VecDestPtr->Y > G->Maxs.Y ) G->Maxs.Y = VecDestPtr->Y; + if (VecDestPtr->Y < G->Mins.Y ) G->Mins.Y = VecDestPtr->Y; + if (VecDestPtr->Z > G->Maxs.Z ) G->Maxs.Z = VecDestPtr->Z; + if (VecDestPtr->Z < G->Mins.Z ) G->Mins.Z = VecDestPtr->Z; + D->ReferenceBoneIndex=BoneIndex; + } + } + } + + { + geBody_Normal *S; + geVec3d *D; + // rotate all appropriate normals + for (i=B->SkinNormalCount,S=B->SkinNormalArray,D=G->NormalArray; + i>0; + i--,S++,D++) + { + if ( S->LevelOfDetailMask && LevelOfDetailBit ) + { + geXForm3d_Rotate(&(BoneXFArray[S->BoneIndex]), + &(S->Normal),D); + } + } + } + + } + + + if (LevelOfDetail != BI->LastLevelOfDetail) + { + // build face list to export + int i,j; + geBody_Index Count; + const geBody_Triangle *T; + geBody_Index *D; + Count = B->SkinFaces[LevelOfDetail].FaceCount; + + for (i=0,T=B->SkinFaces[LevelOfDetail].FaceArray,D=G->FaceList; + iMaterialIndex; + D++; + for (j=0; j<3; j++) + { + *D = T->VtxIndex[j]; + D++; + *D = T->NormalIndex[j]; + D++; + } + } + assert( ((uint32)D) - ((uint32)G->FaceList) == (uint32)(G->FaceListSize) ); + G->FaceCount = Count; + ((geBodyInst *)BI)->LastLevelOfDetail = LevelOfDetail; + } + + + + return G; +} + diff --git a/G3D/Actor/bodyinst.h b/G3D/Actor/bodyinst.h new file mode 100644 index 0000000..f079679 --- /dev/null +++ b/G3D/Actor/bodyinst.h @@ -0,0 +1,128 @@ +/****************************************************************************************/ +/* BODYINST.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Actor body instance interface. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_BODYINST_H +#define GE_BODYINST_H + +/* This object is for accessing and retrieving an 'instance' of the geometry + for a body. + + The retrieval is a list of drawing commands in world space or + in camera space. + + An array of transforms that corresponds to the bones in the body is needed. + */ + + +#include "basetype.h" +#include "xform3d.h" +#include "body.h" +#include "XFArray.h" +#include "camera.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct geBodyInst geBodyInst; + +typedef int16 geBodyInst_Index; + +typedef enum +{ + GE_BODYINST_FACE_TRIANGLE, + GE_BODYINST_FACE_TRISTRIP, + GE_BODYINST_FACE_TRIFAN +} geBodyInst_FaceType; + + +typedef struct geBodyInst_SkinVertex +{ + geVec3d SVPoint; + geFloat SVU,SVV; + int ReferenceBoneIndex; +} geBodyInst_SkinVertex; + +typedef struct geBodyInst_Geometry +{ + geBodyInst_Index SkinVertexCount; + geBodyInst_SkinVertex *SkinVertexArray; + + geBodyInst_Index NormalCount; + geVec3d *NormalArray; + + geBodyInst_Index FaceCount; + int32 FaceListSize; + geBodyInst_Index *FaceList; + + geVec3d Maxs, Mins; +} geBodyInst_Geometry; + +/* format for geBodyInst_Geometry.FaceList: + primitive type (GE_BODY_FACE_TRIANGLE, GE_BODY_FACE_TRISTRIP, GE_BODY_FACE_TRIFAN ) + followed by material index + followed by... + case primitive + GE_BODY_FACE_TRIANGLE: + vertex index 1, normal index 1 + vertex index 2, normal index 2 + vertex index 3, normal index 3 + (next primitive) + GE_BODY_FACE_TRISTRIP: + triangle count + vertex index 1, normal index 1 + vertex index 2, normal index 2 + vertex index 3, normal index 3 + vertex index 4, normal index 4 + ... # vertices is triangle count+2 + (next primitive) + GE_BODY_FACE_TRIFAN: + triangle count + vertex index 1, normal index 1 + vertex index 2, normal index 2 + vertex index 3, normal index 3 + vertex index 4, normal index 4 + ... # vertices is triangle count+2 + (next primitive) +*/ + + + + +geBodyInst *GENESISCC geBodyInst_Create( const geBody *B ); +void GENESISCC geBodyInst_Destroy(geBodyInst **BI); + +const geBodyInst_Geometry *GENESISCC geBodyInst_GetGeometry( + const geBodyInst *BI, + const geVec3d *Scale, + const geXFArray *BoneXformArray, + int LevelOfDetail, + const geCamera *Camera); + + +#ifdef __cplusplus +} +#endif + +#endif + \ No newline at end of file diff --git a/G3D/Actor/motion.c b/G3D/Actor/motion.c new file mode 100644 index 0000000..db825c8 --- /dev/null +++ b/G3D/Actor/motion.c @@ -0,0 +1,2190 @@ +/****************************************************************************************/ +/* MOTION.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Motion implementation. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +/* motion.c + + This object is a list of (named) gePath objects, + and an associated event list + +*/ + +#include +#include // strcmp, strnicmp + +#include "basetype.h" +#include "ram.h" +#include "errorlog.h" +#include "motion.h" +#include "tkevents.h" +#include "StrBlock.h" + +#pragma warning(disable : 4201) // we're using nameless structures + +#define gePath_TimeType geFloat + +#define MIN(aa,bb) (( (aa)>(bb) ) ? (bb) : (aa) ) +#define MAX(aa,bb) (( (aa)>(bb) ) ? (aa) : (bb) ) + +typedef enum { MOTION_NODE_UNDECIDED, MOTION_NODE_BRANCH, MOTION_NODE_LEAF } geMotion_NodeType; + +#define MOTION_BLEND_PART_OF_TRANSFORM(TForm) ((TForm).Translation.X) +#define MOTION_BLEND_PART_OF_VECTOR(Vec) ((Vec).X) + + +typedef struct geMotion_Leaf +{ + int PathCount; + int32 NameChecksum; // checksum based on names and list order + geTKEvents *Events; + geStrBlock *NameArray; + gePath **PathArray; +} geMotion_Leaf; + + +typedef struct geMotion_Mixer +{ + geFloat TimeScale; // multipler for time + geFloat TimeOffset; // already scaled. + gePath *Blend; // path used to interpolate blending amounts. + geXForm3d Transform; // base transform for this motion (if TransformUsed==GE_TRUE) + geBoolean TransformUsed; // GE_FALSE if there is no base transform. + geMotion *Motion; +} geMotion_Mixer; + +typedef struct geMotion_Branch +{ + int MixerCount; + int CurrentEventIterator; + geMotion_Mixer *MixerArray; +} geMotion_Branch; + + +typedef struct geMotion +{ + char *Name; + int CloneCount; + geBoolean MaintainNames; + geMotion_NodeType NodeType; + union + { + geMotion_Leaf Leaf; + geMotion_Branch Branch; + }; + geMotion *SanityCheck; +} geMotion; + + +GENESISAPI geBoolean GENESISCC geMotion_IsValid(const geMotion *M) +{ + if (M == NULL) + return GE_FALSE; + if (M->SanityCheck!=M) + return GE_FALSE; + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geMotion_SetName(geMotion *M, const char *Name) +{ + char *NewName; + + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + NewName = geRam_Allocate( strlen(Name)+1 ); + if (NewName == NULL ) + { + geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL); + return GE_FALSE; + } + if (M->Name!=NULL) + { + geRam_Free(M->Name); + } + M->Name = NewName; + strcpy(M->Name, Name); + return GE_TRUE; +} + +GENESISAPI const char * GENESISCC geMotion_GetName(const geMotion *M) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + return M->Name; +} + +static geBoolean GENESISCC geMotion_InitNodeAsLeaf(geMotion *M,geBoolean SetupStringBlock) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + assert( M->NodeType == MOTION_NODE_UNDECIDED ); + + M->NodeType = MOTION_NODE_LEAF; + + M->Leaf.PathCount = 0; + M->Leaf.Events = NULL; + M->Leaf.PathArray = NULL; + M->Leaf.NameChecksum = 0; + if ((M->MaintainNames != GE_FALSE) && (SetupStringBlock!=GE_FALSE)) + { + M->Leaf.NameArray = geStrBlock_Create(); + if (M->Leaf.NameArray == NULL) + { + geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL); + return GE_FALSE; + } + } + else + { + M->Leaf.NameArray = NULL; + } + return GE_TRUE; +} + +static geBoolean GENESISCC geMotion_InitNodeAsBranch(geMotion *M) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + assert( M->NodeType == MOTION_NODE_UNDECIDED ); + + M->NodeType = MOTION_NODE_BRANCH; + + M->Branch.MixerCount = 0; + M->Branch.CurrentEventIterator = 0; + M->Branch.MixerArray = NULL; + return GE_TRUE; +} + + +GENESISAPI geMotion * GENESISCC geMotion_Create(geBoolean WithNames) +{ + geMotion *M; + assert( (WithNames==GE_TRUE) || (WithNames==GE_FALSE) ); + + M = GE_RAM_ALLOCATE_STRUCT(geMotion); + + if ( M == NULL ) + { + geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL); + return NULL; + } + + M->Name = NULL; + M->CloneCount = 0; + M->MaintainNames = WithNames; + M->NodeType = MOTION_NODE_UNDECIDED; + M->SanityCheck = M; + return M; +} + + +GENESISAPI geBoolean GENESISCC geMotion_RemoveNames(geMotion *M) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->CloneCount > 0) + { + geErrorLog_AddString(-1,"Can't remove names from a cloned motion.", NULL); + return GE_FALSE; + } + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + break; + case (MOTION_NODE_BRANCH): + geErrorLog_AddString(-1,"Can't remove names from a compound motion.", NULL); + return GE_FALSE; + break; + case (MOTION_NODE_LEAF): + assert( M->Leaf.PathCount >= 0 ); + + if ( M->Leaf.NameArray != NULL ) + { + geStrBlock_Destroy(&(M->Leaf.NameArray)); + } + M->Leaf.NameArray = NULL; + break; + default: + assert(0); + } + + M->MaintainNames = GE_FALSE; + return GE_TRUE; +} + + + +GENESISAPI void GENESISCC geMotion_Destroy(geMotion **PM) +{ + int i; + geMotion *M; + + assert(PM != NULL ); + assert(*PM != NULL ); + M = *PM; + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->CloneCount > 0 ) + { + M->CloneCount--; + return; + } + + if (M->Name != NULL) + { + geRam_Free(M->Name); + M->Name = NULL; + } + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + break; + case (MOTION_NODE_BRANCH): + for (i=0; iBranch.MixerCount; i++) + { + assert( M->Branch.MixerArray[i].Motion != NULL ); + geMotion_Destroy( &(M->Branch.MixerArray[i].Motion)); + M->Branch.MixerArray[i].Motion = NULL; + + if (M->Branch.MixerArray[i].Blend != NULL ) + { + gePath_Destroy( &(M->Branch.MixerArray[i].Blend)); + M->Branch.MixerArray[i].Blend = NULL; + } + + } + if (M->Branch.MixerArray != NULL) + { + geRam_Free(M->Branch.MixerArray); + M->Branch.MixerArray = NULL; + } + M->Branch.MixerCount = 0; + M->Branch.CurrentEventIterator = 0; + break; + case (MOTION_NODE_LEAF): + if (M->MaintainNames == GE_TRUE) + { + geBoolean Test= geMotion_RemoveNames(M); + assert( Test != GE_FALSE ); + Test; + } + for (i=0; i< M->Leaf.PathCount; i++) + { + assert( M->Leaf.PathArray[i] ); + gePath_Destroy( &( M->Leaf.PathArray[i] ) ); + M->Leaf.PathArray[i] = NULL; + } + if (M->Leaf.PathArray!=NULL) + { + geRam_Free(M->Leaf.PathArray); + M->Leaf.PathArray = NULL; + } + M->Leaf.PathCount = 0; + if ( M->Leaf.Events != NULL ) + { + geTKEvents_Destroy( &(M->Leaf.Events) ); + } + break; + default: + assert(0); + } + M->NodeType = MOTION_NODE_UNDECIDED; + geRam_Free( *PM ); + *PM = NULL; +} + +GENESISAPI geBoolean GENESISCC geMotion_AddPath(geMotion *M, + gePath *P,const char *Name,int *PathIndex) +{ + int PathCount; + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + if (geMotion_InitNodeAsLeaf(M,GE_TRUE)==GE_FALSE) + { + geErrorLog_Add(-1, NULL); + return GE_FALSE; + } + break; + case (MOTION_NODE_BRANCH): + geErrorLog_Add(ERR_MOTION_ADDPATH_ENOMEM, NULL); //FIXME! + return GE_FALSE; + case (MOTION_NODE_LEAF): + break; + default: + assert(0); + } + + assert( M->Leaf.PathCount >= 0 ); + + if (Name!=NULL) + { + if (geMotion_GetPathNamed( M, Name) != NULL ) + { + geErrorLog_Add(ERR_MOTION_ADDPATH_BAD_NAME, NULL); + return GE_FALSE; + } + } + + PathCount = M->Leaf.PathCount; + + { + gePath **NewPathArray; + + NewPathArray = geRam_Realloc(M->Leaf.PathArray, (1+PathCount) * sizeof(gePath*) ); + + if ( NewPathArray == NULL ) + { + geErrorLog_Add(ERR_MOTION_ADDPATH_ENOMEM, NULL); + return GE_FALSE; + } + M->Leaf.PathArray = NewPathArray; + } + + M->Leaf.PathArray[PathCount] = P; + + if ( M->MaintainNames == GE_TRUE ) + { + + assert (M->Leaf.NameArray != NULL); + if (geStrBlock_Append(&(M->Leaf.NameArray),Name)==GE_FALSE) + { + geErrorLog_Add(ERR_MOTION_ADDPATH_ENOMEM, NULL); + assert(M->Leaf.PathArray[PathCount]); + gePath_Destroy(&(M->Leaf.PathArray[PathCount])); + return GE_FALSE; + } + M->Leaf.NameChecksum = geStrBlock_GetChecksum(M->Leaf.NameArray); + } + + M->Leaf.PathCount = PathCount+1; + *PathIndex = PathCount; + gePath_CreateRef(P); + return GE_TRUE; +} + + +// returns 0 if there is no name information... or if children don't all share the same checksum. +GENESISAPI int32 GENESISCC geMotion_GetNameChecksum(const geMotion *M) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + return 0; + case (MOTION_NODE_BRANCH): + { + int i; + int32 Checksum,FirstChecksum; + if (M->Branch.MixerCount<1) + return 0; + assert( M->Branch.MixerArray[0].Motion ); + FirstChecksum = geMotion_GetNameChecksum( M->Branch.MixerArray[0].Motion ); + + for (i=1; iBranch.MixerCount; i++) + { + assert( M->Branch.MixerArray[i].Motion ); + Checksum = geMotion_GetNameChecksum( M->Branch.MixerArray[i].Motion ); + if (Checksum != FirstChecksum) + return 0; + } + return FirstChecksum; + } + case (MOTION_NODE_LEAF): + return M->Leaf.NameChecksum; + default: + assert(0); + } + return 0; +} + +GENESISAPI geBoolean GENESISCC geMotion_HasNames(const geMotion *M) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + assert( (M->MaintainNames == GE_TRUE) || (M->MaintainNames == GE_FALSE) ); + // if M has names, all children of M have names. + return M->MaintainNames; +} + +GENESISAPI gePath * GENESISCC geMotion_GetPathNamed(const geMotion *M,const char *Name) +{ + int i; + + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->NodeType != MOTION_NODE_LEAF) + { // not an error condition. + return NULL; + } + + assert( M->Leaf.PathCount >=0 ); + + if (Name != NULL) + { + if ( M->MaintainNames == GE_TRUE ) + { + for (i=0; iLeaf.PathCount; i++) + { + if ( strcmp(Name,geStrBlock_GetString(M->Leaf.NameArray,i))==0 ) + { + return M->Leaf.PathArray[i]; + } + } + } + } + return NULL; +} + + +#define LINEAR_BLEND(a,b,t) ( (t)*((b)-(a)) + (a) ) + // linear blend of a and b 0a and t=1 ->b + + + +GENESISAPI void GENESISCC geMotion_Sample(const geMotion *M, int PathIndex, gePath_TimeType Time, geXForm3d *Transform) +{ + geQuaternion Rotation; + geVec3d Translation; + assert( M != NULL); + assert( geMotion_IsValid(M) != GE_FALSE ); + assert( Transform != NULL ); + + geMotion_SampleChannels(M,PathIndex,Time,&Rotation,&Translation); + geQuaternion_ToMatrix(&Rotation,Transform); + Transform->Translation = Translation; +} + + +GENESISAPI void GENESISCC geMotion_SampleChannels(const geMotion *M, int PathIndex, gePath_TimeType Time, geQuaternion *Rotation, geVec3d *Translation) +{ + assert( M != NULL); + assert( Rotation != NULL ); + assert( Translation != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + assert(0); + break; + case (MOTION_NODE_BRANCH): + { + geQuaternion R; + geVec3d T; + geMotion_Mixer *Mixer; + int i; + + if ( M->Branch.MixerCount == 0 ) + { + geVec3d_Clear(Translation); + geQuaternion_SetNoRotation(Rotation); + return; + } + + assert( M->Branch.MixerCount > 0); + Mixer = &(M->Branch.MixerArray[0]); + + assert(Mixer->Motion != NULL ); + geMotion_SampleChannels(Mixer->Motion,PathIndex, + (Time - Mixer->TimeOffset) * Mixer->TimeScale, + Rotation,Translation); + + for (i=1; iBranch.MixerCount; i++) + { + geFloat BlendAmount; + geFloat MixTime; + + Mixer = &(M->Branch.MixerArray[i]); + + assert( Mixer->Motion != NULL ); + assert( Mixer->Blend != NULL ); + + MixTime = (Time - Mixer->TimeOffset) * Mixer->TimeScale; + + geMotion_SampleChannels(Mixer->Motion,PathIndex,MixTime,&R,&T); + { + geVec3d BlendVector; + geQuaternion Dummy; + gePath_SampleChannels(Mixer->Blend,MixTime,&Dummy,&BlendVector); + BlendAmount = MOTION_BLEND_PART_OF_VECTOR(BlendVector); + } + geQuaternion_Slerp(Rotation,&R,BlendAmount,Rotation); + Translation->X = LINEAR_BLEND(Translation->X,T.X,BlendAmount); + Translation->Y = LINEAR_BLEND(Translation->Y,T.Y,BlendAmount); + Translation->Z = LINEAR_BLEND(Translation->Z,T.Z,BlendAmount); + } + } + break; + case (MOTION_NODE_LEAF): + { + gePath *P; + assert( ( PathIndex >=0 ) && ( PathIndex < M->Leaf.PathCount ) ); + P= M->Leaf.PathArray[PathIndex]; + assert( P != NULL ); + gePath_SampleChannels(P,Time,Rotation,Translation); + } + break; + default: + assert(0); + } +} + +GENESISAPI geBoolean GENESISCC geMotion_SampleNamed(const geMotion *M, const char *PathName, gePath_TimeType Time, geXForm3d *Transform) +{ + geQuaternion Rotation; + geVec3d Translation; + assert( M != NULL); + assert( geMotion_IsValid(M) != GE_FALSE ); + assert( Transform != NULL ); + + if (geMotion_SampleChannelsNamed(M,PathName,Time,&Rotation,&Translation)==GE_FALSE) + { + return GE_FALSE; + } + + geQuaternion_ToMatrix(&Rotation,Transform); + Transform->Translation = Translation; + return GE_TRUE; +} + + + +GENESISAPI geBoolean GENESISCC geMotion_SampleChannelsNamed(const geMotion *M, const char *PathName, gePath_TimeType Time, geQuaternion *Rotation, geVec3d *Translation) +{ + geBoolean AnyChannels=GE_FALSE; + assert( M != NULL); + assert( Rotation != NULL ); + assert( Translation != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + return GE_FALSE; + break; + case (MOTION_NODE_BRANCH): + { + int i; + geQuaternion R; + geVec3d T; + geMotion_Mixer *Mixer; + + if ( M->Branch.MixerCount == 0 ) + { + geVec3d_Clear(Translation); + geQuaternion_SetNoRotation(Rotation); + return GE_TRUE; + } + + assert( M->Branch.MixerCount > 0 ); + + for (i=0; iBranch.MixerCount; i++) + { + geFloat BlendAmount; + geFloat MixTime; + + Mixer = &(M->Branch.MixerArray[i]); + + assert( Mixer->Motion != NULL ); + assert( Mixer->Blend != NULL ); + + MixTime = (Time - Mixer->TimeOffset) * Mixer->TimeScale; + + // hmm. is BlendAmount still good if there is no path? + if ( geMotion_SampleChannelsNamed(Mixer->Motion,PathName,MixTime,&R,&T) + != GE_FALSE ) + { + if (AnyChannels != GE_FALSE) + { + { + geVec3d BlendVector; + geQuaternion Dummy; + gePath_SampleChannels(Mixer->Blend,MixTime,&Dummy,&BlendVector); + BlendAmount = MOTION_BLEND_PART_OF_VECTOR(BlendVector); + } + geQuaternion_Slerp(Rotation,&R,BlendAmount,Rotation); + Translation->X = LINEAR_BLEND(Translation->X,T.X,BlendAmount); + Translation->Y = LINEAR_BLEND(Translation->Y,T.Y,BlendAmount); + Translation->Z = LINEAR_BLEND(Translation->Z,T.Z,BlendAmount); + } + else + { + *Rotation = R; + *Translation = T; + AnyChannels = GE_TRUE; + } + } + } + } + break; + case (MOTION_NODE_LEAF): + { + gePath *P; + P = geMotion_GetPathNamed(M, PathName); + if (P == NULL) + { + return GE_FALSE; + } + gePath_SampleChannels(P,Time,Rotation,Translation); + AnyChannels = GE_TRUE; + } + break; + default: + assert(0); + } + return AnyChannels; +} + + +GENESISAPI gePath * GENESISCC geMotion_GetPath(const geMotion *M,int Index) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->NodeType != MOTION_NODE_LEAF) + { // not an error condition. + return NULL; + } + + assert( M->Leaf.PathCount >=0 ); + assert( Index <= M->Leaf.PathCount ); + assert( Index >= 0 ); + + return M->Leaf.PathArray[Index]; +} + +GENESISAPI const char * GENESISCC geMotion_GetNameOfPath(const geMotion *M, int Index) +{ + gePath *P; + assert( M != NULL ); + + if (M->NodeType!=MOTION_NODE_LEAF) + { + return NULL; + } + if (geMotion_HasNames(M)==GE_FALSE) + { + return NULL; + } + + P = geMotion_GetPath(M,Index); + if (P==NULL) + { + return NULL; + } + assert( M->Leaf.NameArray!=NULL ); + + return geStrBlock_GetString(M->Leaf.NameArray,Index); + +} + + + +GENESISAPI int GENESISCC geMotion_GetPathCount(const geMotion *M) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->NodeType != MOTION_NODE_LEAF) + { // not an error condition. + return 0; + } + assert( M->Leaf.PathCount >=0 ); + return M->Leaf.PathCount; +} + + +GENESISAPI geBoolean GENESISCC geMotion_GetTimeExtents(const geMotion *M,gePath_TimeType *StartTime,gePath_TimeType *EndTime) +{ + int i,found; + gePath_TimeType Start,End; + assert( M != NULL ); + assert( StartTime != NULL ); + assert( EndTime != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + found = 0; + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + break; + case (MOTION_NODE_BRANCH): + for (i=0; iBranch.MixerCount; i++) + { + if (geMotion_GetTimeExtents(M->Branch.MixerArray[i].Motion,&Start,&End)!=GE_FALSE) + { + found++; + + // Assertions in AddSubMotion and SetTimeScale prevent TimeScale from being 0. + End = M->Branch.MixerArray[i].TimeOffset + ((End - Start) / M->Branch.MixerArray[i].TimeScale); + Start += M->Branch.MixerArray[i].TimeOffset; + + // If time scale is negative, then End will be < Start, which violates + // the entire idea of extents. So we'll swap them. + if (End < Start) + { + geFloat Temp = Start; + Start = End; + End = Temp; + } + if (found==1) + { + *StartTime = Start; + *EndTime = End; + } + else + { //found>1 + *StartTime = MIN(*StartTime,Start); + *EndTime = MAX(*EndTime,End); + } + } + } + break; + case (MOTION_NODE_LEAF): + found = 0; + for (i=0; iLeaf.PathCount; i++) + { + if (gePath_GetTimeExtents(M->Leaf.PathArray[i],&Start,&End)!=GE_FALSE) + { + found++; + if (found==1) + { + *StartTime = Start; + *EndTime = End; + } + else + { //found>1 + *StartTime = MIN(*StartTime,Start); + *EndTime = MAX(*EndTime,End); + } + } + } + break; + default: + assert(0); + } + if (found>0) + { + return GE_TRUE; + } + return GE_FALSE; +} + + +GENESISAPI int GENESISCC geMotion_GetSubMotionCount(const geMotion *M) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + if (M->NodeType == MOTION_NODE_BRANCH) + { + return M->Branch.MixerCount; + } + return 0; +} + + +#pragma message ("do we want to copy these before returning them?") +GENESISAPI geMotion * GENESISCC geMotion_GetSubMotion(const geMotion *M,int SubMotionIndex) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + if (M->NodeType != MOTION_NODE_BRANCH ) + { + return NULL; + } + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + assert( M->Branch.MixerArray != NULL ); + + return M->Branch.MixerArray[SubMotionIndex].Motion; +} + +GENESISAPI geMotion * GENESISCC geMotion_GetSubMotionNamed(const geMotion *M,const char *Name) +{ + int i; + assert( M != NULL); + assert( Name != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->NodeType != MOTION_NODE_BRANCH) + { + return NULL; + } + assert( M->Branch.MixerArray != NULL ); + for (i=0; iBranch.MixerCount; i++) + { + geMotion *MI = M->Branch.MixerArray[i].Motion; + assert( MI != NULL ); + if (MI->Name!=NULL) + { + if (strcmp(MI->Name,Name)==0) + { + return MI; + } + } + } + return NULL; +} + +static geBoolean GENESISCC geMotion_SearchForSubMotion(const geMotion *Parent, const geMotion*Child) +{ + int i; + assert( Parent != NULL ); + assert( Child != NULL ); + assert( geMotion_IsValid(Parent) != GE_FALSE ); + assert( geMotion_IsValid(Child) != GE_FALSE ); + + if (Parent == Child) + return GE_TRUE; + + if (Parent->NodeType != MOTION_NODE_BRANCH) + return GE_FALSE; + + assert( Parent->Branch.MixerArray != NULL ); + + for (i=0; iBranch.MixerCount; i++) + { + assert( Parent->Branch.MixerArray[i].Motion != NULL ); + if (geMotion_SearchForSubMotion(Parent->Branch.MixerArray[i].Motion,Child)==GE_TRUE) + return GE_TRUE; + } + return GE_FALSE; +} + +GENESISAPI geBoolean GENESISCC geMotion_AddSubMotion(geMotion *ParentMotion, + geFloat TimeScale, + geFloat TimeOffset, + geMotion *SubMotion, + geFloat StartTime, geFloat StartMagnitude, + geFloat EndTime, geFloat EndMagnitude, + const geXForm3d *Transform, + int *Index) + +{ + + int Count; + geMotion_Mixer *NewMixerArray; + assert( ParentMotion != NULL ); + assert( TimeScale != 0.0f ); + assert( SubMotion != NULL ); + assert( Index != NULL ); + //assert( Transform != NULL ); + assert( ( StartMagnitude >= 0.0f) && ( StartMagnitude <=1.0f )); + assert( ( EndMagnitude >= 0.0f) && ( EndMagnitude <=1.0f )); + assert( geMotion_IsValid(ParentMotion) != GE_FALSE ); + assert( geMotion_IsValid(SubMotion) != GE_FALSE ); + + switch (ParentMotion->NodeType) + { + case (MOTION_NODE_UNDECIDED): + if (geMotion_InitNodeAsBranch(ParentMotion)==GE_FALSE) + { + geErrorLog_Add(-1, NULL); + return GE_FALSE; + } + break; + case (MOTION_NODE_LEAF): + { + geErrorLog_Add(-1, NULL); + return GE_FALSE; + } + case (MOTION_NODE_BRANCH): + break; + default: + assert(0); + } + + if (ParentMotion->MaintainNames != SubMotion->MaintainNames) + { + geErrorLog_Add(-1, NULL); //? + return GE_FALSE; + } + + if (geMotion_SearchForSubMotion(SubMotion,ParentMotion)!=GE_FALSE) + { + geErrorLog_Add(-1, NULL); + return GE_FALSE; + } + + Count = ParentMotion->Branch.MixerCount; + NewMixerArray = geRam_Realloc(ParentMotion->Branch.MixerArray, (1+Count) * sizeof(geMotion_Mixer) ); + if ( NewMixerArray == NULL ) + { + geErrorLog_Add(-1, NULL); + return GE_FALSE; + } + + ParentMotion->Branch.MixerArray = NewMixerArray; + { + geMotion_Mixer *Mixer; + geXForm3d BlendKeyTransform; + Mixer = &(ParentMotion->Branch.MixerArray[Count]); + + Mixer->Motion = SubMotion; + Mixer->TimeScale = TimeScale; + Mixer->TimeOffset = TimeOffset; + + Mixer->Blend = gePath_Create(GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV,GE_PATH_INTERPOLATE_SLERP,GE_FALSE); + if (Mixer->Blend==NULL) + { + geErrorLog_Add(-1, NULL); + return GE_FALSE; + } + MOTION_BLEND_PART_OF_TRANSFORM(BlendKeyTransform) = StartMagnitude; + if (gePath_InsertKeyframe(Mixer->Blend, + GE_PATH_TRANSLATION_CHANNEL,StartTime,&BlendKeyTransform)==GE_FALSE) + { + geErrorLog_Add(-1, NULL); + gePath_Destroy(&(Mixer->Blend)); + return GE_FALSE; + } + + MOTION_BLEND_PART_OF_TRANSFORM(BlendKeyTransform) = EndMagnitude; + if (gePath_InsertKeyframe(Mixer->Blend, + GE_PATH_TRANSLATION_CHANNEL,EndTime,&BlendKeyTransform)==GE_FALSE) + { + geErrorLog_Add(-1, NULL); + gePath_Destroy(&(Mixer->Blend)); + return GE_FALSE; + } + if (Transform == NULL) + { + Mixer->TransformUsed = GE_FALSE; + } + else + { + Mixer->TransformUsed = GE_TRUE; + Mixer->Transform = *Transform; + } + } + + *Index = Count; + SubMotion->CloneCount++; + ParentMotion->Branch.MixerCount++; + + return GE_TRUE; +} + +GENESISAPI geMotion * GENESISCC geMotion_RemoveSubMotion(geMotion *ParentMotion, int SubMotionIndex) +{ + int Count; + geMotion *M; + assert( ParentMotion != NULL ); + assert( geMotion_IsValid(ParentMotion) != GE_FALSE ); + + if (ParentMotion->NodeType != MOTION_NODE_BRANCH) + { + return NULL; + } + + Count = ParentMotion->Branch.MixerCount; + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerArray[SubMotionIndex].Motion; + assert( ParentMotion->Branch.MixerArray[SubMotionIndex].Blend != NULL ); + gePath_Destroy( &(ParentMotion->Branch.MixerArray[SubMotionIndex].Blend) ); + + if (Count>1) + { + memcpy( &(ParentMotion->Branch.MixerArray[SubMotionIndex]), + &(ParentMotion->Branch.MixerArray[SubMotionIndex+1]), + sizeof(geMotion_Mixer) * (Count-(SubMotionIndex+1))); + } + ParentMotion->Branch.MixerCount--; + + { + geMotion_Mixer *NewMixerArray; + if (ParentMotion->Branch.MixerCount == 0) + { + geRam_Free(ParentMotion->Branch.MixerArray); + ParentMotion->Branch.MixerArray = NULL; + } + else + { + NewMixerArray = geRam_Realloc(ParentMotion->Branch.MixerArray, + (ParentMotion->Branch.MixerCount) * sizeof(geMotion_Mixer) ); + if ( NewMixerArray != NULL ) + { + ParentMotion->Branch.MixerArray = NewMixerArray; + } + } + } + geMotion_Destroy( &M ); + return M; +} + + + +GENESISAPI geFloat GENESISCC geMotion_GetTimeOffset( const geMotion *M,int SubMotionIndex ) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + // wrong node type is neither error nor invalid. return value is just 0 + + if (M->NodeType == MOTION_NODE_BRANCH) + { + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + return M->Branch.MixerArray[SubMotionIndex].TimeOffset; + } + return 0.0f; +} + +GENESISAPI geBoolean GENESISCC geMotion_SetTimeOffset( geMotion *M,int SubMotionIndex,geFloat TimeOffset ) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->NodeType == MOTION_NODE_BRANCH) + { + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + M->Branch.MixerArray[SubMotionIndex].TimeOffset = TimeOffset; + return GE_TRUE; + } + return GE_FALSE; +} + +GENESISAPI geFloat GENESISCC geMotion_GetTimeScale( const geMotion *M,int SubMotionIndex ) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + // wrong node type is neither error nor invalid. return value is just 1 + + if (M->NodeType == MOTION_NODE_BRANCH) + { + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + return M->Branch.MixerArray[SubMotionIndex].TimeScale; + } + return 1.0f; +} + +GENESISAPI geBoolean GENESISCC geMotion_SetTimeScale( geMotion *M,int SubMotionIndex,geFloat TimeScale ) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + assert( TimeScale != 0.0f); + + if (M->NodeType == MOTION_NODE_BRANCH) + { + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + M->Branch.MixerArray[SubMotionIndex].TimeScale = TimeScale; + return GE_TRUE; + } + return GE_FALSE; +} + +GENESISAPI geFloat GENESISCC geMotion_GetBlendAmount( const geMotion *M, int SubMotionIndex, geFloat Time) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + // wrong node type is neither error nor invalid. return value is just 0 + + if (M->NodeType == MOTION_NODE_BRANCH) + { + geQuaternion Dummy; + geVec3d BlendVector; + geFloat BlendAmount; + + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + assert( M->Branch.MixerArray[SubMotionIndex].Blend != NULL ); + gePath_SampleChannels(M->Branch.MixerArray[SubMotionIndex].Blend, + ( Time - M->Branch.MixerArray[SubMotionIndex].TimeOffset ) + * M->Branch.MixerArray[SubMotionIndex].TimeScale, + &Dummy,&BlendVector); + BlendAmount = MOTION_BLEND_PART_OF_VECTOR(BlendVector); + return BlendAmount; + } + return 0.0f; +} + +GENESISAPI gePath * GENESISCC geMotion_GetBlendPath( const geMotion *M,int SubMotionIndex ) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + // wrong node type is neither error nor invalid. return value is just NULL + + if (M->NodeType == MOTION_NODE_BRANCH) + { + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + return M->Branch.MixerArray[SubMotionIndex].Blend; + } + return NULL; +} + +GENESISAPI geBoolean GENESISCC geMotion_SetBlendPath( geMotion *M,int SubMotionIndex, gePath *Blend ) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + if (M->NodeType == MOTION_NODE_BRANCH) + { + gePath *P; + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + assert( Blend != NULL ); + P = M->Branch.MixerArray[SubMotionIndex].Blend; + gePath_Destroy(&P); + P = gePath_CreateCopy(Blend); + if ( P == NULL ) + { + geErrorLog_Add(-1, NULL); + return GE_FALSE; + } + M->Branch.MixerArray[SubMotionIndex].Blend = P; + return GE_TRUE; + } + return GE_FALSE; +} + + +GENESISAPI const geXForm3d * GENESISCC geMotion_GetBaseTransform( const geMotion *M,int SubMotionIndex ) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + // wrong node type is neither error nor invalid. return value is just NULL + + if (M->NodeType == MOTION_NODE_BRANCH) + { + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + if (M->Branch.MixerArray[SubMotionIndex].TransformUsed != GE_FALSE) + { + return &(M->Branch.MixerArray[SubMotionIndex].Transform); + } + else + { + return NULL; + } + } + return NULL; +} + +GENESISAPI geBoolean GENESISCC geMotion_SetBaseTransform( geMotion *M,int SubMotionIndex, geXForm3d *BaseTransform ) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->NodeType == MOTION_NODE_BRANCH) + { + assert( (SubMotionIndex>=0) && (SubMotionIndexBranch.MixerCount)); + assert( BaseTransform != NULL ); + if (BaseTransform!=NULL) + { + M->Branch.MixerArray[SubMotionIndex].Transform = *BaseTransform; + M->Branch.MixerArray[SubMotionIndex].TransformUsed = GE_TRUE; + } + else + { + M->Branch.MixerArray[SubMotionIndex].TransformUsed = GE_FALSE; + } + + return GE_TRUE; + } + return GE_FALSE; +} + + +#pragma warning( disable : 4701) // don't want to set Translation until we are ready +GENESISAPI geBoolean GENESISCC geMotion_GetTransform( const geMotion *M, geFloat Time, geXForm3d *Transform) +{ + assert( M != NULL); + assert( geMotion_IsValid(M) != GE_FALSE ); + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + { + return GE_FALSE; + } + break; + case (MOTION_NODE_BRANCH): + { + geQuaternion R,Rotation; + geVec3d T,Translation; + geMotion_Mixer *Mixer; + geFloat MixTime; + int i; + int MixCount=0; + + if ( M->Branch.MixerCount == 0 ) + { + return GE_FALSE; + } + assert( M->Branch.MixerCount > 0 ); + + for (i=0; iBranch.MixerCount; i++) + { + geFloat BlendAmount; + geBoolean DoMix=GE_FALSE; + + Mixer = &(M->Branch.MixerArray[i]); + + assert( Mixer->Motion != NULL ); + assert( Mixer->Blend != NULL ); + + MixTime = (Time - Mixer->TimeOffset) * Mixer->TimeScale; + if (geMotion_GetTransform(Mixer->Motion,MixTime,Transform)!=GE_FALSE) + { + DoMix=GE_TRUE; + if (Mixer->TransformUsed!=GE_FALSE) + { + geXForm3d_Multiply(&(Mixer->Transform),Transform,Transform); + } + } + else + { + if (Mixer->TransformUsed!=GE_FALSE) + { + DoMix = GE_TRUE; + *Transform = Mixer->Transform; + } + } + if (DoMix!=GE_FALSE) + { + if (MixCount==0) + { + geQuaternion_FromMatrix(Transform,&Rotation); + Translation = Transform->Translation; + } + else + { + geQuaternion_FromMatrix(Transform,&R); + T = Transform->Translation; + { + geVec3d BlendVector; + geQuaternion Dummy; + gePath_SampleChannels(Mixer->Blend,MixTime,&Dummy,&BlendVector); + BlendAmount = MOTION_BLEND_PART_OF_VECTOR(BlendVector); + } + geQuaternion_Slerp(&Rotation,&R,BlendAmount,&Rotation); + Translation.X = LINEAR_BLEND(Translation.X,T.X,BlendAmount); + Translation.Y = LINEAR_BLEND(Translation.Y,T.Y,BlendAmount); + Translation.Z = LINEAR_BLEND(Translation.Z,T.Z,BlendAmount); + } + + MixCount++; + } + } + if (MixCount>0) + { + geQuaternion_ToMatrix(&Rotation,Transform); + Transform->Translation = Translation; + return GE_TRUE; + } + return GE_FALSE; + } + break; + case (MOTION_NODE_LEAF): + { + return GE_FALSE; + } + break; + default: + assert(0); + } + return GE_FALSE; +} +#pragma warning( default : 4701) + + +//-------------------------------------------------------------------------------------------- +// Event Support + +GENESISAPI geBoolean GENESISCC geMotion_GetEventExtents(const geMotion *M,geFloat *FirstEventTime,geFloat *LastEventTime) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + assert( FirstEventTime != NULL ); + assert( LastEventTime != NULL ); + + return geTKEvents_GetExtents(M->Leaf.Events,FirstEventTime,LastEventTime); +} + + + // Inserts the new event and corresponding string. +GENESISAPI geBoolean GENESISCC geMotion_InsertEvent(geMotion *M, gePath_TimeType tKey, const char* String) +{ + assert( M != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + assert( String != NULL ); + + if (M->NodeType != MOTION_NODE_LEAF ) + { + geErrorLog_Add(ERR_MOTION_INSERT_EVENT, NULL); + return GE_FALSE; + } + + if (M->Leaf.Events == NULL) + { + M->Leaf.Events = geTKEvents_Create(); + if ( M->Leaf.Events == NULL ) + { + geErrorLog_Add(ERR_MOTION_INSERT_EVENT, NULL); + return GE_FALSE; + } + } + if (geTKEvents_Insert(M->Leaf.Events, tKey,String)==GE_FALSE) + { + geErrorLog_Add(ERR_MOTION_INSERT_EVENT, NULL); + return GE_FALSE; + }; + return GE_TRUE; +} + + + + // Deletes the event +GENESISAPI geBoolean GENESISCC geMotion_DeleteEvent(geMotion *M, gePath_TimeType tKey) +{ + assert( M != NULL); + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->NodeType != MOTION_NODE_LEAF ) + { + geErrorLog_Add(ERR_MOTION_INSERT_EVENT, NULL); + return GE_FALSE; + } + if ( M->Leaf.Events == NULL ) + { + geErrorLog_Add(ERR_MOTION_DELETE_EVENT, NULL); + return GE_FALSE; + } + if (geTKEvents_Delete(M->Leaf.Events,tKey)==GE_FALSE) + { + geErrorLog_Add(ERR_MOTION_DELETE_EVENT, NULL); + return GE_FALSE; + } + return GE_TRUE; +} + +GENESISAPI void GENESISCC geMotion_SetupEventIterator( + geMotion *M, + gePath_TimeType StartTime, // Inclusive search start + gePath_TimeType EndTime) // Non-inclusive search stop + // For searching or querying the array for events between two times + // times are compaired [StartTime,EndTime), '[' is inclusive, ')' is + // non-inclusive. This prepares the geMotion_GetNextEvent() function. +{ + int i; + assert( M != NULL); + assert( geMotion_IsValid(M) != GE_FALSE ); + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + break; + case (MOTION_NODE_LEAF): + if ( M->Leaf.Events != NULL ) + { + geTKEvents_SetupIterator(M->Leaf.Events,StartTime,EndTime); + } + break; + case (MOTION_NODE_BRANCH): + for (i=0; iBranch.MixerCount; i++) + { + geMotion_Mixer *Mixer; + + Mixer = &(M->Branch.MixerArray[i]); + + geMotion_SetupEventIterator(Mixer->Motion, + (StartTime - Mixer->TimeOffset) * Mixer->TimeScale, + (EndTime - Mixer->TimeOffset) * Mixer->TimeScale); + } + M->Branch.CurrentEventIterator =0; + break; + default: + assert(0); + } +} + + +GENESISAPI geBoolean GENESISCC geMotion_GetNextEvent( + geMotion *M, // Event list to iterate + gePath_TimeType *pTime, // Return time, if found + const char **ppEventString) // Return data, if found + // Iterates from StartTime to EndTime as setup in geMotion_SetupEventIterator() + // and for each event between these times [StartTime,EndTime) + // this function will return Time and EventString returned for that event + // and the iterator will be positioned for the next search. When there + // are no more events in the range, this function will return GE_FALSE (Time + // will be 0 and ppEventString will be empty). +{ + assert( M != NULL); + assert( geMotion_IsValid(M) != GE_FALSE ); + + assert( pTime != NULL ); + assert( ppEventString != NULL ); + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + { + return GE_FALSE; + } + break; + case (MOTION_NODE_LEAF): + if ( M->Leaf.Events != NULL ) + { + return geTKEvents_GetNextEvent(M->Leaf.Events,pTime,ppEventString); + } + break; + case (MOTION_NODE_BRANCH): + while (M->Branch.CurrentEventIterator < M->Branch.MixerCount) + { + if (geMotion_GetNextEvent( + M->Branch.MixerArray[M->Branch.CurrentEventIterator].Motion, + pTime,ppEventString) !=GE_FALSE) + return GE_TRUE; + M->Branch.CurrentEventIterator++; + } + break; + default: + assert(0); + } + + return GE_FALSE; +} + +//------------------------------------------------------------------------------------------------------ +// Read/Write support + + +#define CHECK_FOR_WRITE(uu) if(uu <= 0) { geErrorLog_Add( ERR_MOTION_FILE_WRITE, NULL ); return GE_FALSE; } + +#define MOTION_ASCII_FILE_TYPE 0x4E544F4D // 'MOTN' +#define MOTION_BIN_FILE_TYPE 0x424E544D // 'MTNB' +#define MOTION_FILE_VERSION 0x00F0 // Restrict version to 16 bits + + +#define MOTION_NAME_ID "NameID" +#define MOTION_MAINTAINNAMES_ID "MaintainNames" + +#define MOTION_NUM_ASCII_IDS 6 // Keep this up to date + +#define MOTION_PATHCOUNT_ID "PathCount" +#define MOTION_NAMECHECKSUM_ID "NameChecksum" +#define MOTION_EVENTS_ID "Events" +#define MOTION_NAMEARRAY_ID "NameArray" +#define MOTION_PATHARRAY_ID "PathArray" +#define LEAF_NUM_ASCII_IDS 5 // keep this up to date + +#define MOTION_MixerCount_ID "MixerCount" +#define MOTION_MOTION_ARRAY "MotionArray" +#define MOTION_BLEND_ARRAY "BlendArray" +#define BRANCH_NUM_ASCII_IDS 3 // keep this up to date + +static geMotion *GENESISCC geMotion_CreateFromBinaryFile(geVFile *pFile); + + +GENESISAPI geMotion* GENESISCC geMotion_CreateFromFile(geVFile* pFile) +{ + uint32 u, v; + geMotion* M; + + assert( pFile != NULL ); + + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return NULL; + } + + if(u == MOTION_ASCII_FILE_TYPE) + { + int NumItemsNeeded=0; + int NumItemsRead = 0; + #define LINE_LENGTH 256 + char line[LINE_LENGTH]; + + M = geMotion_Create(GE_FALSE); + if( M == NULL ) + { + geErrorLog_Add(-1, NULL); + return NULL; // error logged already in geMotion_Create + } + + // Read and build the version. Then determine the number of items to read. + if (geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return NULL; + } + if (sscanf(line, "%X.%X\n", &u, &v) != 2) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return NULL; + } + v |= (u << 8); + if(v >= MOTION_FILE_VERSION) + { + NumItemsNeeded = MOTION_NUM_ASCII_IDS; + } + + // remove this when leaf/branch split happens. + if (geMotion_InitNodeAsLeaf(M,GE_FALSE)==GE_FALSE) + { + geErrorLog_Add(-1, NULL); + return GE_FALSE; + } + + + while(NumItemsRead < NumItemsNeeded) + { + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; // got to read something + } + else if(strnicmp(line, MOTION_NAME_ID, sizeof(MOTION_NAME_ID)-1) == 0) + { + //line[strlen(line)-1]=0; // zap off cr + if ( line[0] != 0 ) + line[strlen(line)-1] = 0; // remove trailing /n (textmode) + if ( line[0] != 0 ) + { + int len = strlen(line)-1; + if (line[len] == 13) // remove trailing /r (binary file mode) + { + line[len] = 0; + } + } + if (strlen(line) > sizeof(MOTION_NAME_ID)) + { + if (geMotion_SetName(M,line+sizeof(MOTION_NAME_ID))==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; + } + } + //NumItemsRead++; + } + + else if(strnicmp(line, MOTION_MAINTAINNAMES_ID, sizeof(MOTION_MAINTAINNAMES_ID)-1) == 0) + { + if(sscanf(line + sizeof(MOTION_MAINTAINNAMES_ID)-1, "%d", &M->MaintainNames) != 1) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; + } + NumItemsRead++; + } + else if(strnicmp(line, MOTION_PATHCOUNT_ID, sizeof(MOTION_PATHCOUNT_ID)-1) == 0) + { + if(sscanf(line + sizeof(MOTION_PATHCOUNT_ID)-1, "%d", &M->Leaf.PathCount) != 1) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; + } + NumItemsRead++; + } + else if(strnicmp(line, MOTION_NAMECHECKSUM_ID, sizeof(MOTION_NAMECHECKSUM_ID)-1) == 0) + { + if(sscanf(line + sizeof(MOTION_NAMECHECKSUM_ID)-1, "%d", &M->Leaf.NameChecksum) != 1) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; + } + NumItemsRead++; + } + else if(strnicmp(line, MOTION_EVENTS_ID, sizeof(MOTION_EVENTS_ID)-1) == 0) + { + int flag; + if(sscanf(line + sizeof(MOTION_EVENTS_ID)-1, "%d", &flag) != 1) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; + } + if (flag!=GE_FALSE) + { + M->Leaf.Events = geTKEvents_CreateFromFile(pFile); + if (M->Leaf.Events == NULL) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; + } + } + NumItemsRead++; + } + else if(strnicmp(line, MOTION_NAMEARRAY_ID, sizeof(MOTION_NAMEARRAY_ID)-1) == 0) + { + int flag; + if(sscanf(line + sizeof(MOTION_NAMEARRAY_ID)-1, "%d", &flag) != 1) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; + } + if (flag!=GE_FALSE) + { + M->Leaf.NameArray = geStrBlock_CreateFromFile(pFile); + if (M->Leaf.NameArray == NULL) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; + } + } + NumItemsRead++; + } + else if(strnicmp(line, MOTION_PATHARRAY_ID, sizeof(MOTION_PATHARRAY_ID)-1) == 0) + { + int i,count; + if(sscanf(line + sizeof(MOTION_PATHARRAY_ID)-1, "%d", &count) != 1) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + break; + } + + M->Leaf.PathArray = geRam_Allocate( count * sizeof(gePath*) ); + + if ( M->Leaf.PathArray == NULL ) + { + geErrorLog_Add(ERR_MOTION_ADDPATH_ENOMEM, NULL); + break; + } + + for (i=0; iLeaf.PathArray[i] = gePath_CreateFromFile(pFile); + if (M->Leaf.PathArray[i] == NULL ) + { + geErrorLog_Add(ERR_MOTION_FILE_READ, NULL); + break; + } + + } + NumItemsRead++; + } + + + } + + if(NumItemsNeeded == NumItemsRead) + { + return M; + } + else + { + geErrorLog_Add( ERR_MOTION_FILE_PARSE , NULL); + geMotion_Destroy(&M); // try to destroy it + return NULL; + } + } + else + { + if (u==MOTION_BIN_FILE_TYPE) + { + return geMotion_CreateFromBinaryFile(pFile); + } + } + + geErrorLog_Add( ERR_MOTION_FILE_PARSE , NULL); + return NULL; +} + +static geBoolean GENESISCC geMotion_WriteLeaf(const geMotion *M, geVFile *pFile) +{ + int i; + int flag; + + assert( M != NULL ); + assert( pFile != NULL ); + assert( M->NodeType == MOTION_NODE_LEAF); + assert( geMotion_IsValid(M) != GE_FALSE ); + + if (M->Leaf.Events == NULL) + flag = GE_FALSE; + else + flag = GE_TRUE; + + if (geVFile_Printf(pFile, "%s %d\n", MOTION_PATHCOUNT_ID,M->Leaf.PathCount) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + if (geVFile_Printf(pFile, "%s %d\n", MOTION_NAMECHECKSUM_ID,M->Leaf.NameChecksum) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + + if (geVFile_Printf(pFile, "%s %d\n", MOTION_EVENTS_ID, flag) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + + if (flag != GE_FALSE) + { + if (geTKEvents_WriteToFile(M->Leaf.Events,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + } + + if (M->Leaf.NameArray == NULL) + flag = GE_FALSE; + else + flag = GE_TRUE; + if (geVFile_Printf(pFile, "%s %d\n", MOTION_NAMEARRAY_ID, flag) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + if (flag != GE_FALSE) + { + if (geStrBlock_WriteToFile(M->Leaf.NameArray,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + } + + if (geVFile_Printf(pFile, "%s %d\n", MOTION_PATHARRAY_ID, M->Leaf.PathCount) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + for (i=0; iLeaf.PathCount; i++) + { + if (gePath_WriteToFile(M->Leaf.PathArray[i],pFile) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + } + return GE_TRUE; +} + +static geBoolean GENESISCC geMotion_WriteBranch(const geMotion *M, geVFile *pFile) +{ + assert( M != NULL ); + assert( pFile != NULL ); + assert( M->NodeType == MOTION_NODE_BRANCH); + assert( geMotion_IsValid(M) != GE_FALSE ); + #pragma message("finish this") + return GE_FALSE; +} + + +GENESISAPI geBoolean GENESISCC geMotion_WriteToFile(const geMotion *M, geVFile *pFile) +{ + uint32 u; + + assert( M != NULL ); + assert( pFile != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + + // Write the format flag + u = MOTION_ASCII_FILE_TYPE; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + + + // Write the version + if (geVFile_Printf(pFile, " %X.%.2X\n", (MOTION_FILE_VERSION & 0xFF00) >> 8, + MOTION_FILE_VERSION & 0x00FF) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + + if (geVFile_Printf(pFile, "%s %s\n", MOTION_NAME_ID,(M->Name==NULL)?(""):(M->Name)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + + if (geVFile_Printf(pFile, "%s %d\n", MOTION_MAINTAINNAMES_ID,M->MaintainNames) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + break; + case (MOTION_NODE_BRANCH): + if (geMotion_WriteBranch(M,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + break; + case (MOTION_NODE_LEAF): + if (geMotion_WriteLeaf(M,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + break; + default: + assert(0); + break; + } + return GE_TRUE; +} + + + +typedef struct +{ + int PathCount; + int32 NameChecksum; + uint32 Flags; +} geMotion_BinaryFileLeafHeader; + +static geBoolean GENESISCC geMotion_ReadBinaryBranch(geMotion *M, geVFile *pFile) +{ + assert( M != NULL ); + assert( pFile != NULL ); + if (geMotion_InitNodeAsBranch(M)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return GE_FALSE; + } + + #pragma message("finish this") + return GE_FALSE; +} + +static geBoolean GENESISCC geMotion_ReadBinaryLeaf(geMotion *M, geVFile *pFile) +{ + int i; + geMotion_BinaryFileLeafHeader Header; + assert( M != NULL ); + assert( pFile != NULL ); + if (geMotion_InitNodeAsLeaf(M,GE_FALSE)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return GE_FALSE; + } + + if (geVFile_Read(pFile, &Header, sizeof(geMotion_BinaryFileLeafHeader)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return GE_FALSE; + } + M->Leaf.NameChecksum = Header.NameChecksum; + + if (Header.Flags & 0x1) + { + M->Leaf.Events = geTKEvents_CreateFromFile(pFile); + if (M->Leaf.Events == NULL ) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return GE_FALSE; + } + } + else + { + M->Leaf.Events = NULL; + } + + if (Header.Flags & 0x2) + { + M->Leaf.NameArray = geStrBlock_CreateFromFile(pFile); + if (M->Leaf.NameArray == NULL) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return GE_FALSE; + } + } + else + { + M->Leaf.NameArray = NULL; + } + + M->Leaf.PathCount = 0; + M->Leaf.PathArray = geRam_Allocate( Header.PathCount * sizeof(gePath*) ); + + if ( M->Leaf.PathArray == NULL ) + { + geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL); + return GE_TRUE; + } + + for (i=0; iLeaf.PathArray[i] = gePath_CreateFromFile(pFile); + if (M->Leaf.PathArray[i] == NULL ) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return GE_FALSE; + } + M->Leaf.PathCount++; + } + return GE_TRUE; +} + +static geMotion *GENESISCC geMotion_CreateFromBinaryFile(geVFile *pFile) +{ + uint32 u; + geBoolean MaintainNames; + int NodeType; + int NameLength; + geMotion *M; + + assert( pFile != NULL ); + + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return NULL; + } + if (u!=MOTION_FILE_VERSION) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return NULL; + } + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + return NULL; + } + + if (u & (1<<16)) + { + MaintainNames = GE_TRUE; + } + else + { + MaintainNames = GE_FALSE; + } + + NameLength = (u & 0xFFFF); + NodeType = (u >> 24); + M = geMotion_Create(MaintainNames); + if ( M == NULL ) + { + geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL); + return NULL; + } + if (NameLength>0) + { + M->Name = geRam_Allocate(NameLength); + if ( M->Name == NULL ) + { + geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL); + geMotion_Destroy(&M); + return NULL; + } + if ( geVFile_Read (pFile, M->Name, NameLength ) == GE_FALSE ) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + geMotion_Destroy(&M); + return NULL; + } + } + else + { + M->Name = NULL; + } + switch (NodeType) + { + case (MOTION_NODE_UNDECIDED): + break; + case (MOTION_NODE_BRANCH): + if (geMotion_ReadBinaryBranch(M,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + geMotion_Destroy(&M); + return NULL; + } + break; + case (MOTION_NODE_LEAF): + if (geMotion_ReadBinaryLeaf(M,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); + geMotion_Destroy(&M); + return NULL; + } + break; + default: + assert(0); + break; + } + return M; +} + + +static geBoolean GENESISCC geMotion_WriteBinaryLeaf(const geMotion *M, geVFile *pFile) +{ + int i; + geMotion_BinaryFileLeafHeader Header; + + #define MOTION_LEAF_EVENTS_FLAG (1) + #define MOTION_LEAF_NAMEARRAY_FLAG (2) + + assert( M != NULL ); + assert( pFile != NULL ); + assert( M->NodeType == MOTION_NODE_LEAF); + assert( geMotion_IsValid(M) != GE_FALSE ); + + Header.PathCount = M->Leaf.PathCount; + Header.NameChecksum = M->Leaf.NameChecksum; + Header.Flags = 0; + + if (M->Leaf.Events != NULL) + { + Header.Flags |= MOTION_LEAF_EVENTS_FLAG; + } + + if (M->Leaf.NameArray != NULL) + { + Header.Flags |= MOTION_LEAF_NAMEARRAY_FLAG; + } + + + if (geVFile_Write(pFile, &Header, sizeof(geMotion_BinaryFileLeafHeader)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + + + if (Header.Flags & MOTION_LEAF_EVENTS_FLAG) + { + if (geTKEvents_WriteToBinaryFile(M->Leaf.Events,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + } + + + if (Header.Flags & MOTION_LEAF_NAMEARRAY_FLAG) + { + if (geStrBlock_WriteToBinaryFile(M->Leaf.NameArray,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + } + + for (i=0; iLeaf.PathCount; i++) + { + if (gePath_WriteToBinaryFile(M->Leaf.PathArray[i],pFile) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + } + return GE_TRUE; +} + +static geBoolean GENESISCC geMotion_WriteBinaryBranch(const geMotion *M, geVFile *pFile) +{ + assert( M != NULL ); + assert( pFile != NULL ); + assert( M->NodeType == MOTION_NODE_BRANCH); + assert( geMotion_IsValid(M) != GE_FALSE ); + #pragma message("finish this") + return GE_FALSE; +} + + +GENESISAPI geBoolean GENESISCC geMotion_WriteToBinaryFile(const geMotion *M,geVFile *pFile) +{ + uint32 u; + + assert( M != NULL ); + assert( pFile != NULL ); + assert( geMotion_IsValid(M) != GE_FALSE ); + + + // Write the format flag + u = MOTION_BIN_FILE_TYPE; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + + u = MOTION_FILE_VERSION; + if (geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + if ( M->Name != NULL ) + { + u = strlen(M->Name)+1; + } + else + { + u = 0; + } + assert( u < 0xFFFF ); + + if (M->MaintainNames != GE_FALSE) + { + u |= (1<<16); + } + assert( M->NodeType < 0xFF ); + u |= (M->NodeType << 24); + if (geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + if ((u&0xFFFF) > 0) + { + if (geVFile_Write(pFile, M->Name, (u&0xFFFF)) == GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + } + + switch (M->NodeType) + { + case (MOTION_NODE_UNDECIDED): + break; + case (MOTION_NODE_BRANCH): + if (geMotion_WriteBinaryBranch(M,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + break; + case (MOTION_NODE_LEAF): + if (geMotion_WriteBinaryLeaf(M,pFile)==GE_FALSE) + { + geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); + return GE_FALSE; + } + break; + default: + assert(0); + break; + } + return GE_TRUE; +} diff --git a/G3D/Actor/motion.h b/G3D/Actor/motion.h new file mode 100644 index 0000000..de4fbea --- /dev/null +++ b/G3D/Actor/motion.h @@ -0,0 +1,180 @@ +/****************************************************************************************/ +/* MOTION.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Motion interface. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_MOTION_H +#define GE_MOTION_H + +/* motion + + This object is a list of named Path objects + +*/ + +#include +#include "basetype.h" +#include "path.h" +#include "vfile.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// GENESIS_PUBLIC_APIS +typedef struct geMotion geMotion; + +GENESISAPI geMotion *GENESISCC geMotion_Create(geBoolean ManageNames); + +GENESISAPI void GENESISCC geMotion_Destroy(geMotion **PM); + +// GENESIS_PRIVATE_APIS + +GENESISAPI geBoolean GENESISCC geMotion_IsValid(const geMotion *M); + + // AddPath adds a reference of P to the motion M. Ownership is shared - The caller must destroy P. +GENESISAPI geBoolean GENESISCC geMotion_AddPath(geMotion *M, gePath *P,const char *Name,int *Index); + +GENESISAPI geBoolean GENESISCC geMotion_HasNames(const geMotion *M); +GENESISAPI int32 GENESISCC geMotion_GetNameChecksum(const geMotion *M); + +GENESISAPI geBoolean GENESISCC geMotion_RemoveNames(geMotion *M); + +GENESISAPI void GENESISCC geMotion_SampleChannels(const geMotion *M, int PathIndex, geFloat Time, geQuaternion *Rotation, geVec3d *Translation); +GENESISAPI geBoolean GENESISCC geMotion_SampleChannelsNamed(const geMotion *M, const char *PathName, geFloat Time, geQuaternion *Rotation, geVec3d *Translation); + +GENESISAPI void GENESISCC geMotion_Sample(const geMotion *M, int PathIndex, geFloat Time, geXForm3d *Transform); +GENESISAPI geBoolean GENESISCC geMotion_SampleNamed(const geMotion *M, const char *PathName, geFloat Time, geXForm3d *Transform); + + // the returned Paths from _Get functions should not be destroyed. + // if ownership is desired, call gePath_CreateRef() to create another owner. + // an 'owner' has access to the object regardless of the number of other owners, and + // an owner must call the object's destroy method to relinquish ownership +GENESISAPI gePath *GENESISCC geMotion_GetPathNamed(const geMotion *M,const char *Name); +GENESISAPI const char *GENESISCC geMotion_GetNameOfPath(const geMotion *M, int Index); + +// GENESIS_PUBLIC_APIS +GENESISAPI gePath *GENESISCC geMotion_GetPath(const geMotion *M,int Index); +GENESISAPI int GENESISCC geMotion_GetPathCount(const geMotion *M); + + +GENESISAPI geBoolean GENESISCC geMotion_SetName(geMotion *M, const char * Name); +GENESISAPI const char *GENESISCC geMotion_GetName(const geMotion *M); + +// GENESIS_PRIVATE_APIS + + // support for compound motions. A motion can either have sub-motions, or be single motion. + // these functions support motions that have sub-motions. +GENESISAPI int GENESISCC geMotion_GetSubMotionCount(const geMotion*M); + + // the returned motions from these _Get functions should not be destroyed. + // if ownership is desired, call geMotion_CreateRef() to create another owner. + // an 'owner' has access to the object regardless of the number of other owners, and + // an owner must call the object's destroy method to relinquish ownership +GENESISAPI geMotion *GENESISCC geMotion_GetSubMotion(const geMotion *M,int Index); +GENESISAPI geMotion *GENESISCC geMotion_GetSubMotionNamed(const geMotion *M,const char *Name); +GENESISAPI geBoolean GENESISCC geMotion_AddSubMotion( + geMotion *ParentMotion, + geFloat TimeScale, // Scale factor for this submotion + geFloat TimeOffset, // Time in parent motion when submotion should start + geMotion *SubMotion, + geFloat StartTime, // Blend start time (relative to submotion) + geFloat StartMagnitude, // Blend start magnitude (0..1) + geFloat EndTime, // Blend ending time (relative to submotion) + geFloat EndMagnitude, // Blend ending magnitude (0..1) + const geXForm3d *Transform, // Base transform to apply to this submotion + int *Index); // returned motion index + +GENESISAPI geMotion *GENESISCC geMotion_RemoveSubMotion(geMotion *ParentMotion, int SubMotionIndex); + +// Get/Set submotion time offset. The time offset is the offset into the +// compound (parent) motion at which the submotion should start. +GENESISAPI geFloat GENESISCC geMotion_GetTimeOffset( const geMotion *M,int SubMotionIndex ); +GENESISAPI geBoolean GENESISCC geMotion_SetTimeOffset( geMotion *M,int SubMotionIndex,geFloat TimeOffset ); + +// Get/Set submotion time scale. Time scaling is applied to the submotion after the TimeOffset +// is applied. The formula is: (CurrentTime - TimeOffset) * TimeScale +GENESISAPI geFloat GENESISCC geMotion_GetTimeScale( const geMotion *M,int SubMotionIndex ); +GENESISAPI geBoolean GENESISCC geMotion_SetTimeScale( geMotion *M,int SubMotionIndex,geFloat TimeScale ); + +// Get blending amount for a particular submotion. The Time parameter is parent-relative. +GENESISAPI geFloat GENESISCC geMotion_GetBlendAmount( const geMotion *M, int SubMotionIndex, geFloat Time); + +// Get/Set blending path. The keyframe times in the blend path are relative to the submotion. +GENESISAPI gePath *GENESISCC geMotion_GetBlendPath( const geMotion *M,int SubMotionIndex ); +GENESISAPI geBoolean GENESISCC geMotion_SetBlendPath( geMotion *M,int SubMotionIndex, gePath *Blend ); + +GENESISAPI const geXForm3d *GENESISCC geMotion_GetBaseTransform( const geMotion *M,int SubMotionIndex ); +GENESISAPI geBoolean GENESISCC geMotion_SetBaseTransform( geMotion *M,int SubMotionIndex, geXForm3d *BaseTransform ); +GENESISAPI geBoolean GENESISCC geMotion_GetTransform(const geMotion *M, geFloat Time, geXForm3d *Transform); +// GENESIS_PUBLIC_APIS + + // gets time of first key and time of last key (as if motion did not loop) + // if there are no paths in the motion: returns GE_FALSE and times are not set + // otherwise returns GE_TRUE + // + // For a compound motion, GetTimeExtents will return the extents of the scaled submotions. + // For a single motion, no scaling is applied. +GENESISAPI geBoolean GENESISCC geMotion_GetTimeExtents(const geMotion *M,geFloat *StartTime,geFloat *EndTime); + +// Only one event is allowed per time key. + +GENESISAPI geBoolean GENESISCC geMotion_InsertEvent(geMotion *M, geFloat tKey, const char* String); + // Inserts the new event and corresponding string. + +GENESISAPI geBoolean GENESISCC geMotion_DeleteEvent(geMotion *M, geFloat tKey); + // Deletes the event + +GENESISAPI void GENESISCC geMotion_SetupEventIterator( + geMotion *M, + geFloat StartTime, // Inclusive search start + geFloat EndTime); // Non-inclusive search stop + // For searching or querying the array for events between two times + // times are compaired [StartTime,EndTime), '[' is inclusive, ')' is + // non-inclusive. This prepares the geMotion_GetNextEvent() function. + +GENESISAPI geBoolean GENESISCC geMotion_GetNextEvent( + geMotion *M, // Event list to iterate + geFloat *pTime, // Return time, if found + const char **ppEventString); // Return data, if found + // Iterates from StartTime to EndTime as setup in geMotion_SetupEventIterator() + // and for each event between these times [StartTime,EndTime) + // this function will return Time and EventString returned for that event + // and the iterator will be positioned for the next search. When there + // are no more events in the range, this function will return GE_FALSE (Time + // will be 0 and ppEventString will be empty). + +GENESISAPI geBoolean GENESISCC geMotion_GetEventExtents(const geMotion *M, + geFloat *FirstEventTime, + geFloat *LastEventTime); + // returns the time associated with the first and last events + // returns GE_FALSE if there are no events (and Times are not set) + + +// GENESIS_PRIVATE_APIS +GENESISAPI geMotion *GENESISCC geMotion_CreateFromFile(geVFile *f); +GENESISAPI geBoolean GENESISCC geMotion_WriteToFile(const geMotion *M, geVFile *f); +GENESISAPI geBoolean GENESISCC geMotion_WriteToBinaryFile(const geMotion *M,geVFile *pFile); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/G3D/Actor/path.c b/G3D/Actor/path.c new file mode 100644 index 0000000..2cf105e --- /dev/null +++ b/G3D/Actor/path.c @@ -0,0 +1,1657 @@ +/****************************************************************************************/ +/* PATH.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Time-indexed keyframe creation, maintenance, and sampling. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include //fmod() +#include +#include //sscanf + +#include "path.h" +#include "Quatern.h" +#include "errorlog.h" +#include "ram.h" +#include "tkarray.h" +#include "VKFrame.h" +#include "QKFrame.h" +#include "vec3d.h" + +#define min(aa,bb) (( (aa)>(bb) ) ? (bb) : (aa) ) +#define max(aa,bb) (( (aa)>(bb) ) ? (aa) : (bb) ) + + +#define gePath_TimeType geFloat + +typedef int8 Bool8; + +typedef void (GENESISCC *InterpolationFunction)( + const void *KF1, + const void *KF2, + gePath_TimeType T, + void *Result); + + +#define FLAG_DIRTY (0x01) +#define FLAG_LOOPED (0x01) +#define FLAG_OTHER (0x696C6345) +#define FLAG_EMPTY (0x21657370) + +typedef struct +{ + geTKArray *KeyList; + int InterpolationType; // type of interpolation for channel + + gePath_TimeType StartTime; // First time in channel's path + gePath_TimeType EndTime; // Last time in channel's path + + // --remember keys used for last sample-- + int32 LastKey1; // smaller key + int32 LastKey2; // larger key (keys may be equal) + gePath_TimeType LastKey1Time; // Time at LastKey1 + gePath_TimeType LastKey2Time; // Time at LastKey2 + // if last key is not valid: LastKey1Time > LastKey2Time +} gePath_Channel; + + +typedef struct _gePath +{ + gePath_Channel Rotation; + gePath_Channel Translation; + unsigned int Dirty : 1; + unsigned int Looped : 1; + unsigned int RefCount:30; +} gePath; + +typedef enum +{ + GE_PATH_VK_LINEAR, + GE_PATH_VK_HERMITE, + GE_PATH_VK_HERMITE_ZERO_DERIV, + GE_PATH_QK_LINEAR, + GE_PATH_QK_SLERP, + GE_PATH_QK_SQUAD, + GE_PATH_MANY_INTERPOLATORS +} gePath_InterpolationType; + +typedef struct +{ + InterpolationFunction InterpolationTable[GE_PATH_MANY_INTERPOLATORS]; + int32 Flags[2]; +} gePath_StaticType; + +gePath_StaticType gePath_Statics = +{ + { geVKFrame_LinearInterpolation, + geVKFrame_HermiteInterpolation, + geVKFrame_HermiteInterpolation, + geQKFrame_LinearInterpolation, + geQKFrame_SlerpInterpolation, + geQKFrame_SquadInterpolation + }, + {FLAG_OTHER,FLAG_EMPTY} +}; + + +static geVKFrame_InterpolationType GENESISCC gePath_PathToVKInterpolation(gePath_InterpolationType I) +{ + switch (I) + { + case (GE_PATH_VK_LINEAR): return VKFRAME_LINEAR; + case (GE_PATH_VK_HERMITE): return VKFRAME_HERMITE; + case (GE_PATH_VK_HERMITE_ZERO_DERIV): return VKFRAME_HERMITE_ZERO_DERIV; + default: assert(0); + } + return VKFRAME_LINEAR; // this is just for warning removal +} + +static gePath_InterpolationType GENESISCC gePath_VKToPathInterpolation(geVKFrame_InterpolationType I) +{ + switch (I) + { + case (VKFRAME_LINEAR): return GE_PATH_VK_LINEAR; + case (VKFRAME_HERMITE): return GE_PATH_VK_HERMITE; + case (VKFRAME_HERMITE_ZERO_DERIV): return GE_PATH_VK_HERMITE_ZERO_DERIV; + default: assert(0); + } + return GE_PATH_VK_LINEAR; // this is just for warning removal +} + +static geQKFrame_InterpolationType GENESISCC gePath_PathToQKInterpolation(gePath_InterpolationType I) +{ + switch (I) + { + case (GE_PATH_QK_LINEAR): return QKFRAME_LINEAR; + case (GE_PATH_QK_SLERP): return QKFRAME_SLERP; + case (GE_PATH_QK_SQUAD): return QKFRAME_SQUAD; + default: assert(0); + } + return QKFRAME_LINEAR; // this is just for warning removal +} + +static gePath_InterpolationType GENESISCC gePath_QKToPathInterpolation(geQKFrame_InterpolationType I) +{ + switch (I) + { + case (QKFRAME_LINEAR): return GE_PATH_QK_LINEAR; + case (QKFRAME_SLERP): return GE_PATH_QK_SLERP; + case (QKFRAME_SQUAD): return GE_PATH_QK_SQUAD; + default: assert(0); + } + return GE_PATH_QK_LINEAR; // this is just for warning removal +} + + +GENESISAPI void GENESISCC gePath_CreateRef( gePath *P ) +{ + assert( P != NULL ); + P->RefCount++; +} + +GENESISAPI gePath *GENESISCC gePath_Create( + gePath_Interpolator TranslationInterpolation, // type of interpolation for translation channel + gePath_Interpolator RotationInterpolation, // type of interpolation for rotation channel + geBoolean Looped) // GE_TRUE if end of path is connected to head + +{ + gePath *P; + + P = geRam_Allocate(sizeof(gePath)); + + if ( P == NULL ) + { + geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL); + return NULL; + } + + P->Rotation.KeyList = NULL; + P->Translation.KeyList = NULL; + + P->RefCount = 0; + P->Dirty = FLAG_DIRTY; + + if (Looped==GE_TRUE) + P->Looped = FLAG_LOOPED; + else + P->Looped = 0; + + + switch (RotationInterpolation) + { + case (GE_PATH_INTERPOLATE_LINEAR): + P->Rotation.InterpolationType = GE_PATH_QK_LINEAR; + break; + case (GE_PATH_INTERPOLATE_SLERP): + P->Rotation.InterpolationType = GE_PATH_QK_SLERP; + break; + case (GE_PATH_INTERPOLATE_SQUAD): + P->Rotation.InterpolationType = GE_PATH_QK_SQUAD; + break; + default: + assert(0); + } + + P->Rotation.KeyList = NULL; + + switch (TranslationInterpolation) + { + case (GE_PATH_INTERPOLATE_LINEAR): + P->Translation.InterpolationType = GE_PATH_VK_LINEAR; + break; + case (GE_PATH_INTERPOLATE_HERMITE): + P->Translation.InterpolationType = GE_PATH_VK_HERMITE; + break; + case (GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV): + P->Translation.InterpolationType = GE_PATH_VK_HERMITE_ZERO_DERIV; + break; + default: + assert(0); + } + + P->Translation.KeyList = NULL; + + return P; +} + +static geBoolean GENESISCC gePath_SetupRotationKeyList(gePath *P) +{ + assert( P != NULL ); + switch (P->Rotation.InterpolationType) + { + case (GE_PATH_QK_LINEAR): + P->Rotation.KeyList = geQKFrame_LinearCreate(); + break; + case (GE_PATH_QK_SLERP): + P->Rotation.KeyList = geQKFrame_SlerpCreate(); + break; + case (GE_PATH_QK_SQUAD): + P->Rotation.KeyList = geQKFrame_SquadCreate(); + break; + default: + assert(0); + } + if (P->Rotation.KeyList == NULL) + { + return GE_FALSE; + } + return GE_TRUE; +} + +static geBoolean GENESISCC gePath_SetupTranslationKeyList(gePath *P) +{ + assert( P != NULL ); + switch (P->Translation.InterpolationType) + { + case (GE_PATH_VK_LINEAR): + P->Translation.KeyList = geVKFrame_LinearCreate(); + break; + case (GE_PATH_VK_HERMITE): + P->Translation.KeyList = geVKFrame_HermiteCreate(); + break; + case (GE_PATH_VK_HERMITE_ZERO_DERIV): + P->Translation.KeyList = geVKFrame_HermiteCreate(); + break; + default: + assert(0); + } + if (P->Translation.KeyList == NULL) + { + return GE_FALSE; + } + return GE_TRUE; +} + +GENESISAPI gePath *GENESISCC gePath_CreateCopy(const gePath *Src) +{ + gePath *P; + gePath_TimeType Time; + geBoolean Looped; + + int i,Count; + int RInterp=0; + int TInterp=0; + + assert ( Src != NULL ); + + switch (Src->Rotation.InterpolationType) + { + case (GE_PATH_QK_LINEAR): + RInterp = GE_PATH_INTERPOLATE_LINEAR; + break; + case (GE_PATH_QK_SLERP): + RInterp = GE_PATH_INTERPOLATE_SLERP; + break; + case (GE_PATH_QK_SQUAD): + RInterp = GE_PATH_INTERPOLATE_SQUAD; + break; + default: + assert(0); + } + + switch (Src->Translation.InterpolationType) + { + case (GE_PATH_VK_LINEAR): + TInterp = GE_PATH_INTERPOLATE_LINEAR; + break; + case (GE_PATH_VK_HERMITE): + TInterp = GE_PATH_INTERPOLATE_HERMITE; + break; + case (GE_PATH_VK_HERMITE_ZERO_DERIV): + TInterp = GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV; + break; + default: + assert(0); + } + + if (Src->Looped) + Looped = GE_TRUE; + else + Looped = GE_FALSE; + + P = gePath_Create(TInterp, RInterp, Looped); + if (P == NULL) + { + geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL); + return NULL; + } + + { + geVec3d V; + Count = 0; + if (Src->Translation.KeyList != NULL) + { + Count = geTKArray_NumElements(Src->Translation.KeyList); + } + if (Count>0) + { + if (gePath_SetupTranslationKeyList(P)==GE_FALSE) + { + geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL); + gePath_Destroy(&P); + return NULL; + } + + for (i=0; iTranslation.KeyList, i, &Time, &V); + if (geVKFrame_Insert(&(P->Translation.KeyList), Time, &V,&Index) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL); + gePath_Destroy(&P); + return NULL; + } + } + } + } + + { + geQuaternion Q; + Count = 0; + if (Src->Rotation.KeyList != NULL) + { + Count = geTKArray_NumElements(Src->Rotation.KeyList); + } + if (Count>0) + { + if (gePath_SetupRotationKeyList(P)==GE_FALSE) + { + geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL); + gePath_Destroy(&P); + return NULL; + } + + for (i=0; iRotation.KeyList, i, &Time, &Q); + if (geQKFrame_Insert(&(P->Rotation.KeyList), Time, &Q, &Index) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL); + gePath_Destroy(&P); + return NULL; + } + } + } + } + return P; +} + + + +GENESISAPI void GENESISCC gePath_Destroy(gePath **PP) +{ + gePath *P; + + assert( PP != NULL ); + assert( *PP != NULL ); + + P = *PP; + + if ( P->RefCount > 0) + { + P->RefCount -- ; + return; + } + if ( P->Rotation.KeyList != NULL) + { + geTKArray_Destroy(&(P->Rotation.KeyList)); + P->Rotation.KeyList = NULL; + } + + if ( P->Translation.KeyList != NULL) + { + geTKArray_Destroy(&(P->Translation.KeyList)); + P->Translation.KeyList = NULL; + } + + geRam_Free(*PP); + + *PP = NULL; +} + + +static void GENESISCC gePath_Recompute(gePath *P) + // Recompute any pre-computed constants for the current path. +{ + geBoolean Looped; + assert(P); + + P->Dirty = 0; + + P->Translation.LastKey1Time = 0.0f; + P->Translation.LastKey2Time = -1.0f; + if (P->Looped) + Looped = GE_TRUE; + else + Looped = GE_FALSE; + + if (P->Translation.KeyList != NULL) + { + if (geTKArray_NumElements(P->Translation.KeyList) > 0 ) + { + P->Translation.StartTime = geTKArray_ElementTime(P->Translation.KeyList,0); + P->Translation.EndTime = geTKArray_ElementTime(P->Translation.KeyList, + geTKArray_NumElements(P->Translation.KeyList) - 1); + } + if(P->Translation.InterpolationType == GE_PATH_VK_HERMITE) + geVKFrame_HermiteRecompute(Looped, GE_FALSE, P->Translation.KeyList); + else if (P->Translation.InterpolationType == GE_PATH_VK_HERMITE_ZERO_DERIV) + geVKFrame_HermiteRecompute(Looped, GE_TRUE, P->Translation.KeyList); + } + + P->Rotation.LastKey1Time = 0.0f; + P->Rotation.LastKey2Time = -1.0f; + + if (P->Rotation.KeyList != NULL) + { + if (geTKArray_NumElements(P->Rotation.KeyList) > 0 ) + { + P->Rotation.StartTime = geTKArray_ElementTime(P->Rotation.KeyList,0); + P->Rotation.EndTime = geTKArray_ElementTime(P->Rotation.KeyList, + geTKArray_NumElements(P->Rotation.KeyList) - 1); + } + if (P->Rotation.InterpolationType == GE_PATH_QK_SQUAD) + geQKFrame_SquadRecompute(Looped, P->Rotation.KeyList); + else if (P->Rotation.InterpolationType == GE_PATH_QK_SLERP) + geQKFrame_SlerpRecompute(P->Rotation.KeyList); + } +} + +//------------------ time based keyframe operations +GENESISAPI geBoolean GENESISCC gePath_InsertKeyframe( + gePath *P, + int ChannelMask, + gePath_TimeType Time, + const geXForm3d *Matrix) +{ + int VIndex; + int QIndex=0; + assert( P != NULL ); + assert( Matrix != NULL ); + assert( ( ChannelMask & GE_PATH_ROTATION_CHANNEL ) || + ( ChannelMask & GE_PATH_TRANSLATION_CHANNEL ) ); + + if (ChannelMask & GE_PATH_ROTATION_CHANNEL) + { + geQuaternion Q; + geQuaternion_FromMatrix(Matrix, &Q); + geQuaternion_Normalize(&Q); + if (P->Rotation.KeyList==NULL) + { + if (gePath_SetupRotationKeyList(P)==GE_FALSE) + { + geErrorLog_Add(ERR_PATH_INSERT_R_KEYFRAME, NULL); + return GE_FALSE; + } + } + if (geQKFrame_Insert(&(P->Rotation.KeyList), Time, &Q, &QIndex) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_INSERT_R_KEYFRAME, NULL); + return GE_FALSE; + } + } + + + if (ChannelMask & GE_PATH_TRANSLATION_CHANNEL) + { + geBoolean ErrorOccured = GE_FALSE; + if (P->Translation.KeyList == NULL) + { + if (gePath_SetupTranslationKeyList(P)==GE_FALSE) + { + geErrorLog_Add(ERR_PATH_INSERT_R_KEYFRAME, NULL); + ErrorOccured = GE_TRUE; + } + } + if (ErrorOccured == GE_FALSE) + { + if (geVKFrame_Insert( &(P->Translation.KeyList), Time, &(Matrix->Translation), &VIndex) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_INSERT_T_KEYFRAME, NULL); + ErrorOccured = GE_TRUE; + } + } + if (ErrorOccured != GE_FALSE) + { + if (ChannelMask & GE_PATH_ROTATION_CHANNEL) + { // clean up previously inserted rotation + if (geTKArray_DeleteElement(&(P->Rotation.KeyList),QIndex)==GE_FALSE) + { + geErrorLog_Add(ERR_PATH_DELETE_T_KEYFRAME, NULL); + } + } + P->Dirty = FLAG_DIRTY; + return GE_FALSE; + } + } + + P->Dirty = FLAG_DIRTY; + + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC gePath_DeleteKeyframe( + gePath *P, + int Index, + int ChannelMask) +{ + int ErrorOccured= 0; + + assert( P != NULL ); + assert( ( ChannelMask & GE_PATH_ROTATION_CHANNEL ) || + ( ChannelMask & GE_PATH_TRANSLATION_CHANNEL ) ); + + if (ChannelMask & GE_PATH_ROTATION_CHANNEL) + { + if (geTKArray_DeleteElement( &(P->Rotation.KeyList), Index) == GE_FALSE) + { + ErrorOccured = 1; + geErrorLog_Add(ERR_PATH_DELETE_R_KEYFRAME, NULL); + } + } + + if (ChannelMask & GE_PATH_TRANSLATION_CHANNEL) + { + if (geTKArray_DeleteElement( &(P->Translation.KeyList), Index) == GE_FALSE) + { + ErrorOccured = 1; + geErrorLog_Add(ERR_PATH_DELETE_T_KEYFRAME, NULL); + } + } + + P->Dirty = FLAG_DIRTY; + + + if (ErrorOccured) + { + return GE_FALSE; + } + + return GE_TRUE; +} + + +GENESISAPI void GENESISCC gePath_GetKeyframe( + const gePath *P, + int Index, // gets keyframe[index] + int Channel, // for this channel + gePath_TimeType *Time, // returns the time of the keyframe + geXForm3d *Matrix) // returns the matrix of the keyframe +{ + assert( P != NULL ); + assert( Index >= 0 ); + assert( Time != NULL ); + assert( Matrix != NULL ); + + geXForm3d_SetIdentity(Matrix); + + switch (Channel) + { + case (GE_PATH_ROTATION_CHANNEL): + { + geQuaternion Q; + assert( Index < geTKArray_NumElements(P->Rotation.KeyList) ); + geQKFrame_Query(P->Rotation.KeyList, Index, Time, &Q); + geQuaternion_ToMatrix(&Q, Matrix); + } + break; + + case (GE_PATH_TRANSLATION_CHANNEL): + { + assert( Index < geTKArray_NumElements(P->Translation.KeyList) ); + geVKFrame_Query(P->Translation.KeyList, Index, Time, &(Matrix->Translation)); + } + break; + + default: + assert(0); + } +} + +GENESISAPI geBoolean GENESISCC gePath_ModifyKeyframe( + gePath *P, + int Index, // keyframe[index] + int ChannelMask, // for this channel + const geXForm3d *Matrix) // new matrix for the keyframe +{ + assert( P != NULL ); + assert( Index >= 0 ); + assert( Matrix != NULL ); + assert( ( ChannelMask & GE_PATH_ROTATION_CHANNEL ) || + ( ChannelMask & GE_PATH_TRANSLATION_CHANNEL ) ); + + + if (ChannelMask & GE_PATH_ROTATION_CHANNEL) + { + geQuaternion Q; + assert( Index < geTKArray_NumElements(P->Rotation.KeyList) ); + geQuaternion_FromMatrix(Matrix, &Q); + geQuaternion_Normalize(&Q); + geQKFrame_Modify(P->Rotation.KeyList, Index, &Q); + } + + if (ChannelMask & GE_PATH_TRANSLATION_CHANNEL) + { + assert( Index < geTKArray_NumElements(P->Translation.KeyList) ); + geVKFrame_Modify(P->Translation.KeyList, Index, &(Matrix->Translation)); + } + + P->Dirty = FLAG_DIRTY; + return GE_TRUE; +} + + +GENESISAPI int GENESISCC gePath_GetKeyframeCount(const gePath *P, int Channel) +{ + assert( P != NULL ); + + switch (Channel) + { + case (GE_PATH_ROTATION_CHANNEL): + if (P->Rotation.KeyList!=NULL) + { + return geTKArray_NumElements(P->Rotation.KeyList); + } + else + { + return 0; + } + break; + + case (GE_PATH_TRANSLATION_CHANNEL): + if (P->Translation.KeyList!=NULL) + { + return geTKArray_NumElements(P->Translation.KeyList); + } + else + { + return 0; + } + break; + + default: + assert(0); + } + return 0; // this is just for warning removal +} + +GENESISAPI int GENESISCC gePath_GetKeyframeIndex(const gePath *P, int Channel, geFloat Time) + // retrieves the index of the keyframe at a specific time for a specific channel +{ + int KeyIndex; + geTKArray *Array = NULL; + + assert ((Channel == GE_PATH_TRANSLATION_CHANNEL) || + (Channel == GE_PATH_ROTATION_CHANNEL)); + + switch (Channel) + { + case GE_PATH_ROTATION_CHANNEL : + Array = P->Rotation.KeyList; + break; + + case GE_PATH_TRANSLATION_CHANNEL : + Array = P->Translation.KeyList; + break; + } + + // find the time in the channel's array + KeyIndex = geTKArray_BSearch (Array, Time); + if (KeyIndex != -1) + { + // since geTKArray_BSearch will return the "closest" key, + // I need to make sure that it's exact... + if (fabs (Time - geTKArray_ElementTime (Array, KeyIndex)) > GE_TKA_TIME_TOLERANCE) + { + KeyIndex = -1; + } + } + + return KeyIndex; +} + + +static gePath_TimeType GENESISCC gePath_AdjustTimeForLooping( + geBoolean Looped, + gePath_TimeType Time, + gePath_TimeType TStart, + gePath_TimeType TEnd) +{ + if (Looped!=GE_FALSE) + { + if (Time < TStart) + { + return (gePath_TimeType)fmod(Time - TStart, TEnd - TStart) + TStart + TEnd; + } + else + { + if (Time >= TEnd) + { + if(TStart + GE_TKA_TIME_TOLERANCE > TEnd) + return TStart; + + return (gePath_TimeType)fmod(Time - TStart, TEnd - TStart) + TStart; + } + else + { + return Time; + } + } + } + else + { + return Time; + } +} + + +static geBoolean GENESISCC gePath_SampleChannel( + const gePath_Channel *Channel, // channel to sample + geBoolean Looped, + gePath_TimeType Time, + void *Result) + // return GE_TRUE if sample was made, + // return GE_FALSE if no sample was made (no keyframes) +{ + int Index1,Index2; // index of keyframe just before and after Time + gePath_TimeType Time1, Time2; // Times in those keyframes + gePath_TimeType T; // 0..1 blending factor + gePath_TimeType AdjTime; // parameter Time adjusted for looping. + int Length; + + assert( Channel != NULL ); + assert( Result != NULL ); + + if (Channel->KeyList == NULL) + return GE_FALSE; + + Length = geTKArray_NumElements( Channel->KeyList ); + + if ( Length == 0 ) + { + //Interpolate(Channel,NULL,NULL,Time,Result); + return GE_FALSE; + } + + AdjTime = gePath_AdjustTimeForLooping(Looped,Time, + Channel->StartTime,Channel->EndTime); + + if ( ( Channel->LastKey1Time <= AdjTime ) && + ( AdjTime < Channel->LastKey2Time ) ) + { + Index1 = Channel->LastKey1; + Index2 = Channel->LastKey2; + Time1 = Channel->LastKey1Time; + Time2 = Channel->LastKey2Time; + } + else + { + Index1 = geTKArray_BSearch( Channel->KeyList, + AdjTime); + Index2 = Index1 + 1; + + // edge conditions: if Time is off end of path's time, use end point twice + if ( Index1 < 0 ) + { + if (Looped!=GE_FALSE) + { + Index1 = Length -1; + } + else + { + Index1 = 0; + } + } + if ( Index2 >= Length ) + { + if (Looped!=GE_FALSE) + { + Index2 = 0; + } + else + { + Index2 = Length - 1; + } + } + ((gePath_Channel *)Channel)->LastKey1 = Index1; + ((gePath_Channel *)Channel)->LastKey2 = Index2; + Time1 = ((gePath_Channel *)Channel)->LastKey1Time = geTKArray_ElementTime(Channel->KeyList, Index1); + Time2 = ((gePath_Channel *)Channel)->LastKey2Time = geTKArray_ElementTime(Channel->KeyList, Index2); + } + + if (Index1 == Index2) + T=0.0f; // Time2 == Time1 ! + else + T = (AdjTime-Time1) / (Time2 - Time1); + + gePath_Statics.InterpolationTable[Channel->InterpolationType]( + geTKArray_Element(Channel->KeyList,Index1), + geTKArray_Element(Channel->KeyList,Index2), + T,Result); + + return GE_TRUE; +} + + +GENESISAPI void GENESISCC gePath_Sample(const gePath *P, gePath_TimeType Time, geXForm3d *Matrix) +{ + geQuaternion Rotation; + geVec3d Translation; + geBoolean Looped; + + assert( P != NULL ); + assert( Matrix != NULL ); + + + if (P->Dirty) + { + gePath_Recompute((gePath *)P); + } + if (P->Looped) + Looped = GE_TRUE; + else + Looped = GE_FALSE; + + if(gePath_SampleChannel(&(P->Rotation), Looped, Time, (void*)&Rotation) == GE_TRUE) + { + geQuaternion_ToMatrix(&Rotation, Matrix); + } + else + { + geXForm3d_SetIdentity(Matrix); + } + + if(gePath_SampleChannel(&(P->Translation), Looped, Time, (void*)&Translation) == GE_TRUE) + { + Matrix->Translation = Translation; + } + else + { + Matrix->Translation.X = Matrix->Translation.Y = Matrix->Translation.Z = 0.0f; + } + +} + +void GENESISCC gePath_SampleChannels(const gePath *P, gePath_TimeType Time, geQuaternion *Rotation, geVec3d *Translation) +{ + geBoolean Looped; + assert( P != NULL ); + assert( Rotation != NULL ); + assert( Translation != NULL ); + + if (P->Dirty) + { + gePath_Recompute((gePath *)P); + } + + if (P->Looped) + Looped = GE_TRUE; + else + Looped = GE_FALSE; + + if(gePath_SampleChannel(&(P->Rotation), Looped, Time, (void*)Rotation) == GE_FALSE) + { + geQuaternion_SetNoRotation(Rotation); + } + + if(gePath_SampleChannel(&(P->Translation), Looped, Time, (void*)Translation) == GE_FALSE) + { + Translation->X = Translation->Y = Translation->Z = 0.0f; + } +} + + +GENESISAPI geBoolean GENESISCC gePath_GetTimeExtents(const gePath *P, gePath_TimeType *StartTime, gePath_TimeType *EndTime) + // returns false and times are unchanged if there is no extent (no keys) +{ + gePath_TimeType TransStart,TransEnd,RotStart,RotEnd; + + int RCount,TCount; + assert( P != NULL ); + assert( StartTime != NULL ); + assert( EndTime != NULL ); + // this is a pain because each channel may have 0,1, or more keys + + if (P->Rotation.KeyList!=NULL) + RCount = geTKArray_NumElements( P->Rotation.KeyList ); + else + RCount = 0; + + if (P->Translation.KeyList!=NULL) + TCount = geTKArray_NumElements( P->Translation.KeyList ); + else + TCount = 0; + + if (RCount>0) + { + RotStart = geTKArray_ElementTime(P->Rotation.KeyList, 0); + if (RCount>1) + { + RotEnd = geTKArray_ElementTime(P->Rotation.KeyList, RCount-1); + } + else + { + RotEnd = RotStart; + } + if (TCount>0) + { // Rotation and Translation keys + TransStart = geTKArray_ElementTime(P->Translation.KeyList, 0); + if (TCount>1) + { + TransEnd = geTKArray_ElementTime(P->Translation.KeyList,TCount-1); + } + else + { + TransEnd = TransStart; + } + + *StartTime = min(TransStart,RotStart); + *EndTime = max(TransEnd,RotEnd); + } + else + { // No Translation Keys + *StartTime = RotStart; + *EndTime = RotEnd; + } + } + else + { // No Rotation Keys + if (TCount>0) + { + *StartTime = geTKArray_ElementTime(P->Translation.KeyList, 0); + if (TCount>1) + { + *EndTime = geTKArray_ElementTime(P->Translation.KeyList,TCount-1); + } + else + { + *EndTime = *StartTime; + } + } + else + { // No Rotation or Translation keys + return GE_FALSE; + } + } + return GE_TRUE; +} + +// First uint32 of ASCII and Binary formats flags the file type. If the value +// matches the token, it's ASCII. Binary files use this uint32 for versions +// and flags. + +#define GE_PATH_BINARY_FILE_VERSION 0x1001 +static gePath *GENESISCC gePath_CreateFromBinaryFile(geVFile *F,uint32 Header); + + +#define CHECK_FOR_WRITE(uu) if(uu <= 0) { geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL); return GE_FALSE; } + +#define GE_PATH_CHANNEL_ASCII_FILE_TYPE 0x4C4E4843 // 'CHNL' +#define GE_PATH_CHANNEL_FILE_VERSION 0x00F0 // Restrict version to 16 bits + +#define GE_PATH_CHANNEL_INTERPOLATE_ID "InterpolationType" +#define GE_PATH_CHANNEL_STARTTIME_ID "StartTime" +#define GE_PATH_CHANNEL_ENDTIME_ID "EndTime" +#define GE_PATH_CHANNEL_KEYLIST_ID "KeyList" +#define GE_PATH_CHANNEL_NUM_ASCII_IDS 4 // Keep this up to date + +geBoolean GENESISCC gePath_ReadChannel_F0_(int ChannelMask, gePath_Channel *C, geVFile* pFile) +{ + uint32 u, v; + int NumItemsNeeded=0; + int NumItemsRead = 0; + #define LINE_LENGTH 256 + char line[LINE_LENGTH]; + geBoolean (GENESISCC *FrameRead)(geVFile*, void*); + gePath_TimeType Time; + int Interp=0; + void* pElement; + char VersionString[32]; + + assert( C != NULL ); + assert( pFile != NULL ); + + // Read the format/version flag + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + return GE_FALSE; + } + + if(u != GE_PATH_CHANNEL_ASCII_FILE_TYPE) + { + geErrorLog_Add( ERR_PATH_FILE_VERSION , NULL); + return GE_FALSE; + } + + // Read and build the version. Then determine the number of items to read. + if (geVFile_GetS(pFile, VersionString, sizeof(VersionString)) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + return GE_FALSE; + } + + if (sscanf(VersionString, "%X.%X\n", &u, &v) != 2) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + return GE_FALSE; + } + v |= (u << 8); + if(v >= GE_PATH_CHANNEL_FILE_VERSION) + { + NumItemsNeeded = GE_PATH_CHANNEL_NUM_ASCII_IDS; + } + + // Set InterpolationType to something less than valid so the KeyList will + // be assured of reading properly. + C->InterpolationType = -1; + + // reset sample optimization bracket + C->LastKey1Time = 0.0f; + C->LastKey2Time = -1.0f; + + while(NumItemsRead < NumItemsNeeded) + { + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + break; // got to read something + } + + if(strnicmp(line, GE_PATH_CHANNEL_INTERPOLATE_ID, sizeof(GE_PATH_CHANNEL_INTERPOLATE_ID)-1) == 0) + { + if(sscanf(line + sizeof(GE_PATH_CHANNEL_INTERPOLATE_ID)-1, "%d", &Interp) != 1) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + break; + } + NumItemsRead++; + } + else if(strnicmp(line, GE_PATH_CHANNEL_STARTTIME_ID, sizeof(GE_PATH_CHANNEL_STARTTIME_ID)-1) == 0) + { + if(sscanf(line + sizeof(GE_PATH_CHANNEL_STARTTIME_ID)-1, "%f", &C->StartTime) != 1) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + break; + } + NumItemsRead++; + } + else if(strnicmp(line, GE_PATH_CHANNEL_ENDTIME_ID, sizeof(GE_PATH_CHANNEL_ENDTIME_ID)-1) == 0) + { + if(sscanf(line + sizeof(GE_PATH_CHANNEL_ENDTIME_ID)-1, "%f", &C->EndTime) != 1) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + break; + } + NumItemsRead++; + } + else if(strnicmp(line, GE_PATH_CHANNEL_KEYLIST_ID, sizeof(GE_PATH_CHANNEL_KEYLIST_ID)-1) == 0) + { + assert(C->KeyList == NULL); + + // v = number of elements + if(sscanf(line + sizeof(GE_PATH_CHANNEL_KEYLIST_ID)-1, "%d", &v) != 1) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + break; + } + + if(ChannelMask == GE_PATH_ROTATION_CHANNEL) + { + switch(Interp) + { + case GE_PATH_INTERPOLATE_LINEAR: + C->KeyList = geQKFrame_LinearCreate(); + C->InterpolationType = GE_PATH_QK_LINEAR; + FrameRead = geQKFrame_LinearRead; + break; + + case GE_PATH_INTERPOLATE_SLERP: + C->KeyList = geQKFrame_SlerpCreate(); + C->InterpolationType = GE_PATH_QK_SLERP; + FrameRead = geQKFrame_SlerpRead; + break; + + case GE_PATH_INTERPOLATE_SQUAD: + C->KeyList = geQKFrame_SquadCreate(); + C->InterpolationType = GE_PATH_QK_SQUAD; + FrameRead = geQKFrame_SquadRead; + break; + + default: + geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL); + return GE_FALSE; + } + } + else + { + assert(ChannelMask == GE_PATH_TRANSLATION_CHANNEL); + + switch(Interp) + { + case GE_PATH_INTERPOLATE_LINEAR: + C->KeyList = geVKFrame_LinearCreate(); + C->InterpolationType = GE_PATH_VK_LINEAR; + FrameRead = geVKFrame_LinearRead; + break; + + case GE_PATH_INTERPOLATE_HERMITE: + C->KeyList = geVKFrame_HermiteCreate(); + C->InterpolationType = GE_PATH_VK_HERMITE; + FrameRead = geVKFrame_HermiteRead; + break; + + case GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV: + C->KeyList = geVKFrame_HermiteCreate(); + C->InterpolationType = GE_PATH_VK_HERMITE_ZERO_DERIV; + FrameRead = geVKFrame_HermiteRead; + break; + + default: + geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL); + return GE_FALSE; + } + } + + while( v > 0 ) + { + char TimeString[32]; + v--; + + if(geVFile_GetS(pFile, TimeString, sizeof(TimeString)) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + break; + } + if(sscanf(TimeString, "%f ", &Time) != 1) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + break; + } + + { + int NewlyAddedElement; // u = newly added element + if(geTKArray_Insert(&C->KeyList, Time, &NewlyAddedElement) == GE_FALSE) + break; + pElement = geTKArray_Element(C->KeyList, NewlyAddedElement); + } + if(FrameRead(pFile, pElement) == GE_FALSE) + break; + } + + if( v > 0 ) + { + // must have aborted early + geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL); + break; + } + + NumItemsRead++; + } + else + { + // Bad news, unknown line, kill the loop + geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL); + break; + } + } + if (NumItemsNeeded == NumItemsRead) + { + return GE_TRUE; + } + else + { + geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL); + return GE_FALSE; + } +} + + +#define GE_PATH_ASCII_FILE_TYPE 0x48544150 // 'PATH' +#define GE_PATH_FILE_VERSION0 0x00F0 // Restrict version to 16 bits +#define GE_PATH_FILE_VERSION1 0x00F1 // Restrict version to 16 bits +#define GE_PATH_FILE_VERSION 0x00F2 // Restrict version to 16 bits + +#define GE_PATH_ROTATION_ID "Rotation" +#define GE_PATH_TRANSLATION_ID "Translation" +#define GE_PATH_LOOPED_ID "Looped" +#define GE_PATH_NUM_ASCII_IDS 2 // Keep this up to date + +#define EXIT_ERROR { gePath_Destroy(&P); geErrorLog_Add( ERR_PATH_FILE_READ , NULL); return NULL; } + +gePath* GENESISCC gePath_CreateFromFile_F0_(geVFile* pFile) +{ + gePath* P; + int flag; + + #define LINE_LENGTH 256 + char line[LINE_LENGTH]; + + assert( pFile != NULL ); + + P = gePath_Create(0, 0, GE_FALSE); + if( P == NULL ) + { + return NULL; // error logged already in gePath_Create + } + + P->Translation.InterpolationType = 0; + P->Rotation.InterpolationType = 0; + + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + EXIT_ERROR + if(strnicmp(line, GE_PATH_LOOPED_ID, sizeof(GE_PATH_LOOPED_ID)-1) != 0) + EXIT_ERROR + + if(sscanf(line + sizeof(GE_PATH_LOOPED_ID)-1, "%d", &flag) != 1) + EXIT_ERROR + + if (flag == GE_TRUE) + { + P->Looped = FLAG_LOOPED; + } + + if(!geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + EXIT_ERROR + if(strnicmp(line, GE_PATH_ROTATION_ID, sizeof(GE_PATH_ROTATION_ID)-1) != 0) + EXIT_ERROR + + if(sscanf(line + sizeof(GE_PATH_ROTATION_ID)-1, "%d", &flag) != 1) + EXIT_ERROR + if (flag!=GE_FALSE) + { + if(!gePath_ReadChannel_F0_(GE_PATH_ROTATION_CHANNEL, &P->Rotation, pFile)) + EXIT_ERROR + } + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + EXIT_ERROR + if(strnicmp(line, GE_PATH_TRANSLATION_ID, sizeof(GE_PATH_TRANSLATION_ID)-1) != 0) + EXIT_ERROR + if(sscanf(line + sizeof(GE_PATH_TRANSLATION_ID)-1, "%d", &flag) != 1) + EXIT_ERROR + + if (flag!=GE_FALSE) + if(!gePath_ReadChannel_F0_(GE_PATH_TRANSLATION_CHANNEL, &P->Translation, pFile)) + EXIT_ERROR + + P->Dirty = FLAG_DIRTY; + return P; +} + +GENESISAPI gePath* GENESISCC gePath_CreateFromFile(geVFile* pFile) +{ + uint32 u, v, flag; + int Interp,Loop; + gePath* P; + #define LINE_LENGTH 256 + char line[LINE_LENGTH]; + + assert( pFile != NULL ); + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + return NULL; + } + + if ( (u>>16) == GE_PATH_BINARY_FILE_VERSION) + return gePath_CreateFromBinaryFile(pFile,u); + + + if(u != GE_PATH_ASCII_FILE_TYPE) + { + geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL); + return NULL; + } + + // Read the version. + if (geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_READ , NULL); + return NULL; + } + if (sscanf(line, "%X.%X\n", &u, &v) != 2) + { + geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL); + return NULL; + } + v |= (u << 8); + if(v == GE_PATH_FILE_VERSION0) + return gePath_CreateFromFile_F0_(pFile); + if (! ((v == GE_PATH_FILE_VERSION1) || (v== GE_PATH_FILE_VERSION)) ) + { + geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL); + return NULL; + } + + P = gePath_Create(0, 0, GE_FALSE); + if( P == NULL ) + { + return NULL; // error logged already in gePath_Create + } + + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + EXIT_ERROR + if(strnicmp(line, GE_PATH_ROTATION_ID, sizeof(GE_PATH_ROTATION_ID)-1) != 0) + EXIT_ERROR + if (v==GE_PATH_FILE_VERSION1) + { + P->Rotation.InterpolationType = 0; + if(sscanf(line + sizeof(GE_PATH_ROTATION_ID)-1, "%d", &flag) != 1) + EXIT_ERROR + } + else + { + if (v==GE_PATH_FILE_VERSION) + { + if(sscanf(line + sizeof(GE_PATH_ROTATION_ID)-1, "%d %d", &flag, &(P->Rotation.InterpolationType)) != 2) + EXIT_ERROR + } + else + EXIT_ERROR + } + if (flag!=GE_FALSE) + { + P->Rotation.KeyList = geQKFrame_CreateFromFile(pFile,&Interp,&Loop); + if (P->Rotation.KeyList == NULL) + EXIT_ERROR + P->Rotation.InterpolationType = gePath_QKToPathInterpolation(Interp); + if (Loop) + P->Looped = FLAG_LOOPED; + } + + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + EXIT_ERROR + if(strnicmp(line, GE_PATH_TRANSLATION_ID, sizeof(GE_PATH_TRANSLATION_ID)-1) != 0) + EXIT_ERROR + if (v==GE_PATH_FILE_VERSION1) + { + P->Translation.InterpolationType = 0; + if(sscanf(line + sizeof(GE_PATH_TRANSLATION_ID)-1, "%d", &flag) != 1) + EXIT_ERROR + } + else + { + if (v==GE_PATH_FILE_VERSION) + { + if(sscanf(line + sizeof(GE_PATH_TRANSLATION_ID)-1, "%d %d", &flag, &(P->Translation.InterpolationType)) != 2) + EXIT_ERROR + } + else + EXIT_ERROR + } + + if (flag!=GE_FALSE) + { + P->Translation.KeyList = geVKFrame_CreateFromFile(pFile,&Interp,&Loop); + if (P->Translation.KeyList == NULL) + EXIT_ERROR + P->Translation.InterpolationType = gePath_VKToPathInterpolation(Interp); + if (Loop) + P->Looped = FLAG_LOOPED; + } + + P->Dirty = FLAG_DIRTY; + return P; +} + +GENESISAPI geBoolean GENESISCC gePath_WriteToFile(const gePath *P,geVFile *pFile) +{ + uint32 u; + int Looped=0; + + assert( P != NULL ); + assert( pFile != NULL ); + + if (P->Dirty) + gePath_Recompute((gePath *)P); + + // Write the format flag + u = GE_PATH_ASCII_FILE_TYPE; + if(geVFile_Write(pFile, &u,sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL); + return GE_FALSE; + } + + // Write the version + if (geVFile_Printf(pFile, " %X.%.2X\n", (GE_PATH_FILE_VERSION & 0xFF00) >> 8, + GE_PATH_FILE_VERSION & 0x00FF) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL); + return GE_FALSE; + } + + { + int flag; + flag = GE_FALSE; + + if (P->Rotation.KeyList != NULL) + { + if (geTKArray_NumElements(P->Rotation.KeyList)>0) + { + flag = GE_TRUE; + } + } + if (geVFile_Printf(pFile, + "%s %d %d\n", + GE_PATH_ROTATION_ID, + flag, + P->Rotation.InterpolationType) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL); + return GE_FALSE; + } + + if (P->Looped) + Looped = 1; + + if (flag!=GE_FALSE) + if (geQKFrame_WriteToFile( pFile, P->Rotation.KeyList, + gePath_PathToQKInterpolation(P->Rotation.InterpolationType), + Looped)==GE_FALSE) + { + return GE_FALSE; + } + + flag = GE_FALSE; + if (P->Translation.KeyList != NULL) + { + if (geTKArray_NumElements(P->Translation.KeyList)>0) + { + flag = GE_TRUE; + } + } + if (geVFile_Printf(pFile, + "%s %d %d\n", + GE_PATH_TRANSLATION_ID, + flag, + P->Translation.InterpolationType) == GE_FALSE) + { + geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL); + return GE_FALSE; + } + + if (flag!=GE_FALSE) + if (geVKFrame_WriteToFile( pFile, P->Translation.KeyList, + gePath_PathToVKInterpolation(P->Translation.InterpolationType), + Looped)==GE_FALSE) + { + return GE_FALSE; + } + } + + + return GE_TRUE; +} + +/* + Binary file header: + 13 bit version id, 8 bit Rotation InterpolationType, + 8 bit Translation InterpolationType, 1 bits for looped flag, + 1 bit for translation keys exist, 1 bit for rotation keys exist +*/ +#define GE_PATH_MAX_INT_TYPE_COUNT (127) // 7 bits +#define GE_PATH_TRANS_SHIFT_INTO_HEADER (9) // 7 bits shifted into bits 9..15 +#define GE_PATH_ROT_SHIFT_INTO_HEADER (2) // 7 bits shifted into bits 2..8 + +GENESISAPI geBoolean GENESISCC gePath_WriteToBinaryFile(const gePath *P, geVFile *F) +{ + uint32 Header; + int R,T,Looped; + + assert( F != NULL ); + assert( P != NULL ); + assert( GE_PATH_BINARY_FILE_VERSION < 0xFFFF ); + + R=T=0; + + if (P->Rotation.KeyList != NULL) + { + if (geTKArray_NumElements(P->Rotation.KeyList)>0) + { + R = GE_TRUE; + } + } + + if (P->Translation.KeyList != NULL) + { + if (geTKArray_NumElements(P->Translation.KeyList)>0) + { + T = GE_TRUE; + } + } + + if (P->Looped) + Looped = 1; + else + Looped = 0; + assert( P->Translation.InterpolationType <= GE_PATH_MAX_INT_TYPE_COUNT); + assert( P->Rotation.InterpolationType <= GE_PATH_MAX_INT_TYPE_COUNT); + + Header = + (GE_PATH_BINARY_FILE_VERSION << 16) | + (T<<1) | + (R) | + (P->Translation.InterpolationType << GE_PATH_TRANS_SHIFT_INTO_HEADER) | + (P->Rotation.InterpolationType << GE_PATH_ROT_SHIFT_INTO_HEADER ); + + if (geVFile_Write(F, &Header,sizeof(uint32)) == GE_FALSE) + { + geErrorLog_AddString( -1 ,"Failure to write Path Binary File Header", NULL); + return GE_FALSE; + } + + if (T==1) + { + if (geVKFrame_WriteToBinaryFile( F, P->Translation.KeyList, + gePath_PathToVKInterpolation(P->Translation.InterpolationType), + Looped)==GE_FALSE) + { + geErrorLog_AddString( -1 ,"Failure to write Path data", NULL); + return GE_FALSE; + } + } + if (R==1) + { + if (geQKFrame_WriteToBinaryFile( F, P->Rotation.KeyList, + gePath_PathToQKInterpolation(P->Rotation.InterpolationType), + Looped)==GE_FALSE) + { + geErrorLog_AddString( -1 ,"Failure to write Path data", NULL); + return GE_FALSE; + } + } + + return GE_TRUE; +} + + + +static gePath * GENESISCC gePath_CreateFromBinaryFile(geVFile *F,uint32 Header) +{ + gePath *P; + int Interp,Looping; + + assert( F != NULL ); + + if ((Header>>16) != GE_PATH_BINARY_FILE_VERSION) + { + geErrorLog_AddString( -1, "Bad path binary file version" , NULL); + return NULL; + } + + P = geRam_Allocate(sizeof(gePath)); + P->Translation.KeyList = NULL; + P->Rotation.KeyList = NULL; + if (P == NULL) + { + geErrorLog_AddString( -1, "Failure to allocate memory for path" , NULL); + return NULL; + } + + P->Translation.InterpolationType = (Header >> GE_PATH_TRANS_SHIFT_INTO_HEADER) & GE_PATH_MAX_INT_TYPE_COUNT; + P->Rotation.InterpolationType = (Header >> GE_PATH_ROT_SHIFT_INTO_HEADER) & GE_PATH_MAX_INT_TYPE_COUNT; + // this will be replaced by the path reader (if the path has keys) + + P->Translation.LastKey1Time = 0.0f; + P->Translation.LastKey2Time = -1.0f; + + P->Rotation.LastKey1Time = 0.0f; + P->Rotation.LastKey2Time = -1.0f; + P-> Dirty = 0; + P-> Looped = 0; + P-> RefCount = 0; + + if ((Header >> 1) & 0x1) + { + P->Translation.KeyList = geVKFrame_CreateFromBinaryFile(F,&Interp,&Looping); + if (P->Translation.KeyList == NULL) + { + geErrorLog_AddString( -1, "Failure to read translation keys" , NULL); + geRam_Free(P); + return NULL; + } + P->Translation.InterpolationType = gePath_VKToPathInterpolation(Interp); + if( Looping != 0 ) + P->Looped = FLAG_LOOPED; + } + + if (Header & 0x1) + { + P->Rotation.KeyList = geQKFrame_CreateFromBinaryFile(F,&Interp,&Looping); + if (P->Rotation.KeyList == NULL) + { + geErrorLog_AddString( -1, "Failure to read rotation keys" , NULL); + if (P->Translation.KeyList != NULL) + { + geTKArray_Destroy(&P->Translation.KeyList); + } + geRam_Free(P); + return NULL; + } + P->Rotation.InterpolationType = gePath_QKToPathInterpolation(Interp); + if( Looping != 0 ) + P->Looped = FLAG_LOOPED; + + } + P->Dirty = FLAG_DIRTY; + return P; +} + \ No newline at end of file diff --git a/G3D/Actor/path.h b/G3D/Actor/path.h new file mode 100644 index 0000000..6052947 --- /dev/null +++ b/G3D/Actor/path.h @@ -0,0 +1,153 @@ +/****************************************************************************************/ +/* PATH.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Time-indexed keyframe creation, maintenance, and sampling. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_PATH_H +#define GE_PATH_H + +#include "basetype.h" +#include "xform3d.h" +#include "quatern.h" +#include "vfile.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +// GENESIS_PUBLIC_APIS +typedef struct _gePath gePath; + +#define GE_PATH_ROTATION_CHANNEL 1 +#define GE_PATH_TRANSLATION_CHANNEL 2 + +#define GE_PATH_ALL_CHANNELS (GE_PATH_ROTATION_CHANNEL | GE_PATH_TRANSLATION_CHANNEL) + +#ifndef GE_PATH_ENUMS + #define GE_PATH_ENUMS + typedef enum + { + GE_PATH_INTERPOLATE_LINEAR = 0, // linear blend for translation or rotation channel + GE_PATH_INTERPOLATE_HERMITE, // hermite cubic spline for translation channel + GE_PATH_INTERPOLATE_SLERP, // spherical-linear blend for rotation channel + GE_PATH_INTERPOLATE_SQUAD, // higher order blend for rotation channel 'G1' continuity + //GE_PATH_INTEROPLATE_TRIPOD, // not supported yet. + GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV = 7 // hermite cubic with zero derivative at keyframes ('easing' curve) + }gePath_Interpolator; +#endif + +GENESISAPI void GENESISCC gePath_CreateRef( gePath *P ); + +GENESISAPI gePath *GENESISCC gePath_Create( + gePath_Interpolator TranslationInterpolation, // type of interpolation for translation channel + gePath_Interpolator RotationInterpolation, // type of interpolation for rotation channel + geBoolean Looped); // True if end of path is connected to head + // creates new gePath + // A looping path should have the same first & last point. The path + // generator will choose arbitrarily between these points for a + // sample exactly at the end of the loop. + +GENESISAPI gePath *GENESISCC gePath_CreateCopy( const gePath *P ); + +GENESISAPI void GENESISCC gePath_Destroy(gePath **PP); + // destroys path *PP + +//------------------ time based keyframe operations +GENESISAPI geBoolean GENESISCC gePath_InsertKeyframe( + gePath *P, + int ChannelMask, + geFloat Time, + const geXForm3d *Matrix); + // inserts a keyframe at a specific time. + +GENESISAPI geBoolean GENESISCC gePath_DeleteKeyframe( + gePath *P, + int Index, + int ChannelMask); + // deletes the nth keyframe + +GENESISAPI geBoolean GENESISCC gePath_GetTimeExtents( + const gePath *P, + geFloat *StartTime, + geFloat *EndTime); + // gets the time for the first and last keys in the path (ignoring looping) + // if there are no keys, return GE_FALSE and times are not set. + // returns GE_TRUE if there are keys. + +//----------------- index based keyframe operations +GENESISAPI void GENESISCC gePath_GetKeyframe( + const gePath *P, + int Index, // gets keyframe[index] + int Channel, // for this channel + geFloat *Time, // returns the time of the keyframe + geXForm3d *Matrix); // returns the matrix of the keyframe + // retrieves keyframe[index], and it's time + +GENESISAPI int GENESISCC gePath_GetKeyframeCount(const gePath *P,int Channel); + // retrieves count of keyframes for a specific channel + +GENESISAPI int GENESISCC gePath_GetKeyframeIndex(const gePath *P, int Channel, geFloat Time); + // retrieves the index of the keyframe at a specific time for a specific channel + +//----------------- sampling a path (time based) +GENESISAPI void GENESISCC gePath_Sample(const gePath *P, geFloat Time,geXForm3d *Matrix); + // returns a transform matrix sampled at 'Time'. + // p is not const because information is cached in p for next sample + +// GENESIS_PRIVATE_APIS +void GENESISCC gePath_SampleChannels( + const gePath *P, + geFloat Time, + geQuaternion *Rotation, + geVec3d *Translation); + // returns a rotation and a translation for the path at 'Time' + // p is not const because information is cached in p for next sample + +GENESISAPI geBoolean GENESISCC gePath_OffsetTimes(gePath *P, + int StartingIndex, int ChannelMask, geFloat TimeOffset ); + // slides all samples in path starting with StartingIndex down by TimeOffset + +GENESISAPI geBoolean GENESISCC gePath_ModifyKeyframe( + gePath *P, + int Index, + int ChannelMask, + const geXForm3d *Matrix); + + +// GENESIS_PUBLIC_APIS + +//------------------ saving/loading a path +GENESISAPI gePath* GENESISCC gePath_CreateFromFile(geVFile *F); + // loads a file (binary or ascii) + +GENESISAPI geBoolean GENESISCC gePath_WriteToFile(const gePath *P, geVFile *F); + // dumps formatted ascii to the file. + +GENESISAPI geBoolean GENESISCC gePath_WriteToBinaryFile(const gePath *P, geVFile *F); + // dumps a minimal binary image for fastest reading + + + +#ifdef __cplusplus + } +#endif + + +#endif diff --git a/G3D/Actor/pose.c b/G3D/Actor/pose.c new file mode 100644 index 0000000..d7a1d1b --- /dev/null +++ b/G3D/Actor/pose.c @@ -0,0 +1,1120 @@ +/****************************************************************************************/ +/* POSE.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Bone hierarchy implementation. . */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#pragma message ("could optimize a name binded setPose by caching the mapping from motionpath[i] to joint[j]") + +#include +#include + +#include "ram.h" +#include "errorlog.h" +#include "Pose.h" +#include "StrBlock.h" + +#define GE_POSE_STARTING_JOINT_COUNT (1) + + +/* this object maintains a hierarchy of joints. + the hierarchy is stored as an array of joints, with each joint having an number + that is it's parent's index in the array. + This code assumes: + **The parent's index is always smaller than the child** +*/ + +typedef struct gePose_Joint +{ + int ParentJoint; // parent of path + geXForm3d *Transform; // matrix for path (pointer into TransformArray) + geQuaternion Rotation; // quaternion representation for orientation of above Transform + + geVec3d UnscaledAttachmentTranslation; + // point of Attachment to parent (in parent frame of ref) **Unscaled + geQuaternion AttachmentRotation;// rotation of attachement to parent (in parent frame of ref) + geXForm3d AttachmentTransform; //------------ + + geVec3d LocalTranslation; // translation relative to attachment + geQuaternion LocalRotation; // rotation relative to attachment + + geBoolean Touched; // if this joint has been touched and needs recomputation + geBoolean NoAttachmentRotation; // GE_TRUE if there is no attachment rotation. + int Covered; // if joint has been 100% set (no blending) +} gePose_Joint; // structure to bind a name and a path for a joint + +typedef struct gePose +{ + int JointCount; // number of joints in the motion + int32 NameChecksum; // checksum based on joint names and list order + geBoolean Touched; // if any joint has been touched & needs recomputation + geStrBlock *JointNames; + geVec3d Scale; // current scaling. Used for scaling motion samples + + geBoolean Slave; // if pose is 'slaved' to parent -vs- attached. + int SlaveJointIndex; // index of 'slaved' joint + gePose *Parent; + gePose_Joint RootJoint; + geXForm3d ParentsLastTransform; // Compared to parent's transform to see if it changed: recompute is needed + geXForm3d RootTransform; + geXFArray *TransformArray; + gePose_Joint *JointArray; + int OnlyThisJoint; // update only this joint (and it's parents) if this is >0 +} gePose; + + + +static void gePose_ReattachTransforms(gePose *P) +{ + int XFormCount; + int JointCount; + geXForm3d *XForms; + int i; + + assert( P != NULL ); + + JointCount = P->JointCount; + if (JointCount > 0) + { + assert( P->TransformArray != NULL ); + + XForms = geXFArray_GetElements(P->TransformArray,&XFormCount); + + assert( XForms != NULL ); + assert( XFormCount == JointCount ); + + for (i=0; iJointArray[i].Transform=&(XForms[i]); + } + } + P->RootJoint.Transform = &(P->RootTransform); +} + + +static const gePose_Joint *gePose_JointByIndex(const gePose *P, int Index) +{ + assert( P != NULL ); + assert( (Index >=0) || (Index==(GE_POSE_ROOT_JOINT))); + assert( (Index < P->JointCount) || (Index==(GE_POSE_ROOT_JOINT))); + + if (Index == GE_POSE_ROOT_JOINT) + { + return &(P->RootJoint); + } + else + { + return &(P->JointArray[Index]); + } +} + +static void GENESISCC gePose_SetAttachmentRotationFlag( gePose_Joint *Joint) +{ + geQuaternion Q = Joint->AttachmentRotation; +#define GE_POSE_ROTATION_THRESHOLD (0.0001) // if the rotation is closer than this to zero for + // quaterion elements X,Y,Z -> no rotation computed + if ( ( (Q.X-GE_POSE_ROTATION_THRESHOLD) ) + && ( (Q.Y-GE_POSE_ROTATION_THRESHOLD) ) + && ( (Q.Z-GE_POSE_ROTATION_THRESHOLD) ) ) + { + Joint->NoAttachmentRotation = GE_TRUE; + } + else + { + Joint->NoAttachmentRotation = GE_FALSE; + } +} + +static void GENESISCC gePose_InitializeJoint(gePose_Joint *Joint, int ParentJointIndex, const geXForm3d *Attachment) +{ + assert( Joint != NULL ); + + Joint->ParentJoint = ParentJointIndex; + if (Attachment != NULL) + { + geQuaternion_FromMatrix(Attachment,&(Joint->AttachmentRotation)); + Joint->AttachmentTransform = *Attachment; + Joint->UnscaledAttachmentTranslation = Joint->AttachmentTransform.Translation; + } + else + { + geQuaternion_SetNoRotation(&(Joint->AttachmentRotation)); + geXForm3d_SetIdentity(&(Joint->AttachmentTransform)); + Joint->UnscaledAttachmentTranslation = Joint->AttachmentTransform.Translation; + } + + geQuaternion_SetNoRotation(&(Joint->LocalRotation)); + + geXForm3d_SetIdentity(Joint->Transform); + geQuaternion_SetNoRotation(&(Joint->Rotation)); + + geVec3d_Set( (&Joint->LocalTranslation),0.0f,0.0f,0.0f); + geQuaternion_SetNoRotation(&(Joint->LocalRotation)); + Joint->Touched = GE_TRUE; + gePose_SetAttachmentRotationFlag(Joint); +} + + + +gePose *GENESISCC gePose_Create(void) +{ + gePose *P; + + P = GE_RAM_ALLOCATE_STRUCT(gePose); + + if ( P == NULL ) + { + geErrorLog_Add(ERR_POSE_CREATE_ENOMEM, NULL); + goto PoseCreateFailure; + } + P->JointCount = 0; + P->OnlyThisJoint = GE_POSE_ROOT_JOINT-1; + P->JointNames = geStrBlock_Create(); + P->Touched = GE_FALSE; + if ( P->JointNames == NULL ) + { + geErrorLog_Add(ERR_POSE_CREATE_ENOMEM, NULL); + goto PoseCreateFailure; + } + P->JointArray = GE_RAM_ALLOCATE_STRUCT( gePose_Joint ); + if (P->JointArray == NULL) + { + geErrorLog_Add(ERR_POSE_CREATE_ENOMEM, NULL); + goto PoseCreateFailure; + } + P->TransformArray=NULL; + + P->Slave = GE_FALSE; + P->Parent = NULL; + gePose_ReattachTransforms(P); + gePose_InitializeJoint(&(P->RootJoint),GE_POSE_ROOT_JOINT,NULL); + + P->Scale.X = P->Scale.Y = P->Scale.Z = 1.0f; + return P; + PoseCreateFailure: + if (P!=NULL) + { + if (P->JointNames != NULL) + geStrBlock_Destroy(&(P->JointNames)); + if (P->JointArray != NULL) + geRam_Free(P->JointArray); + geRam_Free(P); + } + return NULL; +} + +void GENESISCC gePose_Destroy(gePose **PP) +{ + assert(PP != NULL ); + assert(*PP != NULL ); + + assert( (*PP)->JointNames != NULL ); + assert( geStrBlock_GetCount((*PP)->JointNames) == (*PP)->JointCount ); + geStrBlock_Destroy( &( (*PP)->JointNames ) ); + if ((*PP)->TransformArray!=NULL) + { + geXFArray_Destroy(&( (*PP)->TransformArray) ); + } + if ((*PP)->JointArray != NULL) + geRam_Free((*PP)->JointArray); + geRam_Free( *PP ); + + *PP = NULL; +} + +// uses J->LocalRotation and J->LocalTranslation to compute +// J->Rotation,J->Translation and J->Transform +static void GENESISCC gePose_JointRelativeToParent( + const gePose_Joint *Parent, + gePose_Joint *J) +{ + + #if 0 + // the math in clearer (but slower) matrix form. + // W = PAK + geXForm3d X; + geXForm3d K; + + geQuaternion_ToMatrix(&(J->LocalRotation),&K); + K.Translation = J->LocalTranslation; + + geXForm3d_Multiply((Parent->Transform),&(J->AttachmentTransform),&X); + geXForm3d_Multiply(&X,&(K),J->Transform); + + J->LocalTranslation = K.Translation; + geQuaternion_FromMatrix(J->Transform,&(J->LocalRotation)); + + #endif + + + geVec3d *Translation = &(J->Transform->Translation); + if (J->NoAttachmentRotation != GE_FALSE) + { + // ( no attachment rotation ) + //ROTATION: + // concatenate local rotation to parent rotation for complete rotation + geQuaternion_Multiply(&(Parent->Rotation), &(J->LocalRotation), &(J->Rotation)); + + geQuaternion_ToMatrix(&(J->Rotation), (J->Transform)); + //TRANSLATION: + geVec3d_Add(&(J->LocalTranslation),&(J->AttachmentTransform.Translation),Translation); + geXForm3d_Transform((Parent->Transform),Translation,Translation); + } + else + { + // (there is an attachment rotation) + + geQuaternion BaseRotation; // attachement transform applied to the parent transform: + //ROTATION: + // concatenate attachment rotation to parent rotation for base rotation + geQuaternion_Multiply(&(Parent->Rotation),&(J->AttachmentRotation),&BaseRotation); + // concatenate base rotation with local rotation for complete rotation + geQuaternion_Multiply(&BaseRotation, &(J->LocalRotation), &(J->Rotation)); + + geQuaternion_ToMatrix(&(J->Rotation), (J->Transform)); + + //TRANSLATION: + geXForm3d_Transform(&(J->AttachmentTransform),&(J->LocalTranslation),Translation); + geXForm3d_Transform((Parent->Transform),Translation,Translation); + } +} + + +geBoolean GENESISCC gePose_Attach(gePose *Slave, int SlaveBoneIndex, + gePose *Master, int MasterBoneIndex, + const geXForm3d *Attachment) +{ + gePose *P; + P = Master; + + assert( Slave != NULL ); + assert( Master != NULL ); + assert( MasterBoneIndex >= 0); + assert( MasterBoneIndex < Master->JointCount); + assert( Attachment != NULL ); + assert( Master != Slave ); + + + assert( (SlaveBoneIndex >=0) || (SlaveBoneIndex==(GE_POSE_ROOT_JOINT))); + assert( (SlaveBoneIndex < Slave->JointCount) || (SlaveBoneIndex==(GE_POSE_ROOT_JOINT))); + + while (P!=NULL) + { + if (P==Slave) + { + geErrorLog_Add(-1, NULL);//FIXME + return GE_FALSE; + } + P=P->Parent; + } + + Slave->SlaveJointIndex = SlaveBoneIndex; + Slave->Parent = Master; + if (SlaveBoneIndex == GE_POSE_ROOT_JOINT) + { + Slave->Slave = GE_FALSE; + } + else + { + Slave->Slave = GE_TRUE; + } + + gePose_InitializeJoint(&(Slave->RootJoint),MasterBoneIndex,Attachment); + Slave->Touched = GE_TRUE; + Slave->ParentsLastTransform = *(Master->RootJoint.Transform); + + return GE_TRUE; +} + + +void GENESISCC gePose_Detach(gePose *P) +{ + P->Parent = NULL; + P->Slave = GE_FALSE; + gePose_InitializeJoint(&(P->RootJoint),GE_POSE_ROOT_JOINT,NULL); +} + + +static geBoolean GENESISCC gePose_TransformCompare(const geXForm3d *T1, const geXForm3d *T2) +{ + if (T1->AX != T2->AX) return GE_FALSE; + if (T1->BX != T2->BX) return GE_FALSE; + if (T1->CX != T2->CX) return GE_FALSE; + if (T1->AY != T2->AY) return GE_FALSE; + if (T1->BY != T2->BY) return GE_FALSE; + if (T1->CY != T2->CY) return GE_FALSE; + if (T1->AZ != T2->AZ) return GE_FALSE; + if (T1->BZ != T2->BZ) return GE_FALSE; + if (T1->CZ != T2->CZ) return GE_FALSE; + + if (T1->Translation.X != T2->Translation.X) return GE_FALSE; + if (T1->Translation.Y != T2->Translation.Y) return GE_FALSE; + if (T1->Translation.Z != T2->Translation.Z) return GE_FALSE; + return GE_TRUE; +} + + +static void GENESISCC gePose_UpdateRecursively(gePose *P,int Joint) +{ + gePose_Joint *J; + assert( P != NULL ); + assert( Joint >= GE_POSE_ROOT_JOINT ); + + J=&(P->JointArray[Joint]); + + assert( J->ParentJoint < Joint); + + if (J->ParentJoint != GE_POSE_ROOT_JOINT) + gePose_UpdateRecursively(P,J->ParentJoint); + + gePose_JointRelativeToParent(gePose_JointByIndex(P, J->ParentJoint) ,J); +} + +// updates a node if node->touched or if any of it's parents have been touched. +// returns GE_TRUE if any updates were made. +static void GENESISCC gePose_UpdateRelativeToParent(gePose *P) +{ + int i; + gePose_Joint *J; + const gePose_Joint *Parent; + assert( P != NULL ); + + if ( P->Parent != NULL ) + { + gePose_UpdateRelativeToParent(P->Parent); +// Wismerhill Attach Fix RF064 + if (gePose_TransformCompare( + (P->Parent->RootJoint.Transform),&(P->ParentsLastTransform)) == GE_FALSE) + { + P->Touched = GE_TRUE; + P->RootJoint.Touched = GE_TRUE; // bubble touched down entire hierarchy + P->ParentsLastTransform = *(P->Parent->RootJoint.Transform); + } + + if (P->Slave == GE_FALSE) + { + Parent = gePose_JointByIndex(P->Parent, P->RootJoint.ParentJoint); + gePose_JointRelativeToParent(Parent,&(P->RootJoint)); + } + else + { + geXForm3d_SetIdentity(P->RootJoint.Transform); + geQuaternion_SetNoRotation(&(P->RootJoint.Rotation)); + } + } + else + { + // No parent. RootJoint is relative to nothing. + J = &(P->RootJoint); + if (J->Touched) + { + geQuaternion_Multiply(&(J->AttachmentRotation),&(J->LocalRotation),&(J->Rotation)); + geQuaternion_ToMatrix(&(J->Rotation), (J->Transform)); + geXForm3d_Transform(&(J->AttachmentTransform),&(J->LocalTranslation),&(J->Transform->Translation)); + } + } + + + if (P->Touched == GE_FALSE) + { + return; + } + + + if (P->OnlyThisJoint>=GE_POSE_ROOT_JOINT) + { + gePose_UpdateRecursively(P,P->OnlyThisJoint); + } + else + { + for (i=0, J=&(P->JointArray[0]); iJointCount; i++,J++) + { + assert( J->ParentJoint < i); + + Parent = gePose_JointByIndex(P, J->ParentJoint); + if (J->Touched == GE_TRUE) + { + gePose_JointRelativeToParent(Parent ,J); + } + else + { + if (Parent->Touched) + { + J->Touched = GE_TRUE; + gePose_JointRelativeToParent(Parent,J); + } + } + } + // touched flags don't mean anything when recursing backwards. + P->RootJoint.Touched = GE_FALSE; + for (i=0, J=&(P->JointArray[0]); iJointCount; i++,J++) + { + J->Touched = GE_FALSE; + } + } + + if (P->Slave != GE_FALSE) + { + geXForm3d SlavedJointInverse; + geXForm3d FullSlaveTransform; + geXForm3d *MasterTransform; + geXForm3d MasterAttachment; + + MasterTransform = (P->Parent->JointArray[P->RootJoint.ParentJoint].Transform); + geXForm3d_GetTranspose((P->JointArray[P->SlaveJointIndex].Transform), &SlavedJointInverse); + + geQuaternion_ToMatrix(&(P->RootJoint.AttachmentRotation), &MasterAttachment); + //MasterAttachment.Translation = P->RootJoint.AttachmentTranslation; + MasterAttachment.Translation = P->RootJoint.AttachmentTransform.Translation; + + geXForm3d_Multiply(MasterTransform,&MasterAttachment,&FullSlaveTransform); + + *(P->RootJoint.Transform) = FullSlaveTransform; + + geXForm3d_Multiply(&FullSlaveTransform,&SlavedJointInverse,&FullSlaveTransform); + + for (i=0, J=&(P->JointArray[0]); iJointCount; i++,J++) + { + geXForm3d_Multiply(&FullSlaveTransform, + (P->JointArray[i].Transform), + (P->JointArray[i].Transform)); + } + + } + P->Touched = GE_FALSE; +} + + +geBoolean GENESISCC gePose_FindNamedJointIndex(const gePose *P, const char *JointName, int *Index) +{ + int i; + + assert( P != NULL ); + assert( Index!= NULL ); + if (JointName == NULL ) + return GE_FALSE; + + for (i=0; iJointCount; i++) + { + const char *NthName = geStrBlock_GetString(P->JointNames,i); + assert( NthName!= NULL ); + if ( strcmp(JointName,NthName)==0 ) + { + *Index = i; + return GE_TRUE; + } + } + return GE_FALSE; +} + + +geBoolean GENESISCC gePose_AddJoint( + gePose *P, + int ParentJointIndex, + const char *JointName, + const geXForm3d *Attachment, + int *JointIndex) +{ + int JointCount; + gePose_Joint *Joint; + + assert( P != NULL ); + assert( JointIndex != NULL ); + assert( P->JointCount >= 0 ); + assert( (ParentJointIndex == GE_POSE_ROOT_JOINT) || + ((ParentJointIndex >=0) && (ParentJointIndex JointCount) ) ); + + // Duplicate names ARE allowed + + JointCount = P->JointCount; + { + gePose_Joint *NewJoints; + NewJoints = GE_RAM_REALLOC_ARRAY(P->JointArray,gePose_Joint,JointCount+1); + if (NewJoints == NULL) + { + geErrorLog_Add(ERR_POSE_ADDJOINT_ENOMEM, NULL); + return GE_FALSE; + } + P->JointArray = NewJoints; + } + + assert( P->JointNames != NULL ); + assert( geStrBlock_GetCount(P->JointNames) == P->JointCount ); + + if (geStrBlock_Append( &(P->JointNames), (JointName==NULL)?"":JointName )==GE_FALSE) + { + geErrorLog_Add(ERR_POSE_ADDJOINT_ENOMEM, NULL); + return GE_FALSE; + } + + + { + geXFArray *NewXFA; + NewXFA = geXFArray_Create(JointCount+1); + if (NewXFA == NULL) + { + geErrorLog_Add(ERR_POSE_ADDJOINT_ENOMEM, NULL); + return GE_FALSE; + } + if (P->TransformArray != NULL) + { + geXFArray_Destroy(&(P->TransformArray)); + } + P->TransformArray = NewXFA; + } + + P->JointCount = JointCount+1; + gePose_ReattachTransforms(P); + + Joint = &( P->JointArray[JointCount] ); + gePose_InitializeJoint(Joint,ParentJointIndex, Attachment); + P->Touched = GE_TRUE; + + *JointIndex = JointCount; + + P->NameChecksum = geStrBlock_GetChecksum( P->JointNames ); + return GE_TRUE; +} + +void GENESISCC gePose_GetJointAttachment(const gePose *P,int JointIndex, geXForm3d *AttachmentTransform) +{ + assert( P != NULL ); + assert( AttachmentTransform != NULL ); + { + const gePose_Joint *J; + J = gePose_JointByIndex(P, JointIndex); + *AttachmentTransform = J->AttachmentTransform; + } +} + +void GENESISCC gePose_SetJointAttachment(gePose *P, + int JointIndex, + const geXForm3d *AttachmentTransform) +{ + assert( P != NULL ); + assert( AttachmentTransform != NULL ); + { + gePose_Joint *J; + J = (gePose_Joint *)gePose_JointByIndex(P, JointIndex); + geQuaternion_FromMatrix(AttachmentTransform,&(J->AttachmentRotation)); + J->Touched = GE_TRUE; + J->AttachmentTransform = *AttachmentTransform; + J->UnscaledAttachmentTranslation = J->AttachmentTransform.Translation; + gePose_SetAttachmentRotationFlag(J); + } + P->Touched = GE_TRUE; +} + +void GENESISCC gePose_GetJointTransform(const gePose *P, int JointIndex,geXForm3d *Transform) +{ + assert( P != NULL ); + assert( Transform != NULL ); + + gePose_UpdateRelativeToParent((gePose *)P); + + { + const gePose_Joint *J; + J = gePose_JointByIndex(P, JointIndex); + *Transform = *(J->Transform); + } +} + +void GENESISCC gePose_GetJointLocalTransform(const gePose *P, int JointIndex,geXForm3d *Transform) +{ + assert( P != NULL ); + assert( Transform != NULL ); + { + const gePose_Joint *J; + J = gePose_JointByIndex(P, JointIndex); + geQuaternion_ToMatrix(&(J->LocalRotation), Transform); + Transform->Translation = J->LocalTranslation; + } +} + +void GENESISCC gePose_SetJointLocalTransform(gePose *P, int JointIndex,const geXForm3d *Transform) +{ + assert( P != NULL ); + assert( Transform != NULL ); + { + gePose_Joint *J; + J = (gePose_Joint *)gePose_JointByIndex(P, JointIndex); + geQuaternion_FromMatrix(Transform,&(J->LocalRotation)); + J->LocalTranslation = Transform->Translation; + J->Touched = GE_TRUE; + } + P->Touched = GE_TRUE; +} + +int GENESISCC gePose_GetJointCount(const gePose *P) +{ + assert( P != NULL ); + assert( P->JointCount >= 0 ); + + return P->JointCount; +} + +geBoolean GENESISCC gePose_MatchesMotionExactly(const gePose *P, const geMotion *M) +{ + if (geMotion_HasNames(M) != GE_FALSE) + { + if (geMotion_GetNameChecksum(M) == P->NameChecksum) + return GE_TRUE; + else + return GE_FALSE; + } + return GE_FALSE; +} + +// sets pose to it's base position: applies no modifier to the joints: only +// it's attachment positioning is used. +void GENESISCC gePose_Clear(gePose *P,const geXForm3d *Transform) +{ + int i; + gePose_Joint *J; + + assert( P != NULL ); + assert( P->JointCount >= 0 ); + P->OnlyThisJoint = GE_POSE_ROOT_JOINT-1; // calling this function disables one-joint optimizations + if (P->Parent==NULL) + { + if (Transform!=NULL) + { + geQuaternion_FromMatrix(Transform,&(P->RootJoint.LocalRotation)); + P->RootJoint.LocalTranslation = Transform->Translation; + } + P->RootJoint.Touched = GE_TRUE; + } + + for (i=0, J=&(P->JointArray[0]); iJointCount; i++,J++) + { + geVec3d_Set( (&J->LocalTranslation),0.0f,0.0f,0.0f); + geQuaternion_SetNoRotation(&(J->LocalRotation)); + assert( J->ParentJoint < i); + P->Touched = GE_TRUE; + } + P->Touched = GE_TRUE; +} + +void GENESISCC gePose_SetMotion(gePose *P, const geMotion *M, geFloat Time, + const geXForm3d *Transform) +{ + geBoolean NameBinding; + int i; + gePose_Joint *J; + geXForm3d RootTransform; + + assert( P != NULL ); + + P->OnlyThisJoint = GE_POSE_ROOT_JOINT-1; // calling this function disables one-joint optimizations + + if (P->Parent==NULL) + { + geBoolean SetRoot = GE_FALSE; + if (geMotion_GetTransform(M,Time,&RootTransform)!=GE_FALSE) + { + SetRoot = GE_TRUE; + + if ( Transform != NULL ) + { + geXForm3d_Multiply(Transform,&RootTransform,&RootTransform); + } + } + else + { + if ( Transform != NULL ) + { + SetRoot = GE_TRUE; + RootTransform = *Transform; + } + } + + if (SetRoot != GE_FALSE) + { + geQuaternion_FromMatrix(&RootTransform,&(P->RootJoint.LocalRotation)); + P->RootJoint.LocalTranslation = RootTransform.Translation; + P->RootJoint.Touched = GE_TRUE; + } + } + + if (M==NULL) + { + return; + } + + if (gePose_MatchesMotionExactly(P,M)==GE_TRUE) + NameBinding = GE_FALSE; + else + NameBinding = GE_TRUE; + + P->Touched = GE_TRUE; + #pragma message("could optimize this by looping two ways (min(jointcount,pathcount))") + for (i=0, J=&(P->JointArray[0]); iJointCount; i++,J++) + { + //gePath *JointPath; + if (NameBinding == GE_FALSE) + { + geMotion_SampleChannels(M,i,Time,&(J->LocalRotation),&(J->LocalTranslation)); + + //JointPath = geMotion_GetPath(M,i); + //assert( JointPath != NULL ); + } + else + { + if (geMotion_SampleChannelsNamed(M, + geStrBlock_GetString(P->JointNames,i), + Time,&(J->LocalRotation),&(J->LocalTranslation))==GE_FALSE) + continue; + + } + J->Touched = GE_TRUE; + J->LocalTranslation.X *= P->Scale.X; + J->LocalTranslation.Y *= P->Scale.Y; + J->LocalTranslation.Z *= P->Scale.Z; + } +} + +static void GENESISCC gePose_SetMotionForABoneRecursion(gePose *P, const geMotion *M, geFloat Time, + int BoneIndex,geBoolean NameBinding) +{ + gePose_Joint *J; + geBoolean Touched = GE_FALSE; + assert(P!=NULL); + assert(M!=NULL); + assert( BoneIndex >= 0); + + J=&(P->JointArray[BoneIndex]); + + if (NameBinding == GE_FALSE) + { + geMotion_SampleChannels(M,BoneIndex,Time,&(J->LocalRotation),&(J->LocalTranslation)); + Touched = GE_TRUE; + } + else + { + if (geMotion_SampleChannelsNamed(M, + geStrBlock_GetString(P->JointNames,BoneIndex), + Time,&(J->LocalRotation),&(J->LocalTranslation))!=GE_FALSE) + Touched = GE_TRUE; + } + if (Touched != GE_FALSE) + { + J->Touched = GE_TRUE; + J->LocalTranslation.X *= P->Scale.X; + J->LocalTranslation.Y *= P->Scale.Y; + J->LocalTranslation.Z *= P->Scale.Z; + } + if (J->ParentJoint != GE_POSE_ROOT_JOINT) + gePose_SetMotionForABoneRecursion(P,M,Time,J->ParentJoint,NameBinding); + +} + +void GENESISCC gePose_SetMotionForABone(gePose *P, const geMotion *M, geFloat Time, + const geXForm3d *Transform,int BoneIndex) +{ + geBoolean NameBinding; + geXForm3d RootTransform; + + assert( P != NULL ); + //assert( M != NULL ); + P->OnlyThisJoint = BoneIndex; // calling this function enables single-joint optimizations + + if (P->Parent==NULL) + { + geBoolean SetRoot = GE_FALSE; + if (geMotion_GetTransform(M,Time,&RootTransform)!=GE_FALSE) + { + SetRoot = GE_TRUE; + + if ( Transform != NULL ) + { + geXForm3d_Multiply(Transform,&RootTransform,&RootTransform); + } + } + else + { + if ( Transform != NULL ) + { + SetRoot = GE_TRUE; + RootTransform = *Transform; + } + } + + if (SetRoot != GE_FALSE) + { + geQuaternion_FromMatrix(&RootTransform,&(P->RootJoint.LocalRotation)); + P->RootJoint.LocalTranslation = RootTransform.Translation; + P->RootJoint.Touched = GE_TRUE; + } + } + + if (M==NULL) + { + return; + } + if (BoneIndex == GE_POSE_ROOT_JOINT) + { + return; + } + + if (gePose_MatchesMotionExactly(P,M)==GE_TRUE) + NameBinding = GE_FALSE; + else + NameBinding = GE_TRUE; + + P->Touched = GE_TRUE; + + gePose_SetMotionForABoneRecursion(P, M, Time, BoneIndex, NameBinding); +} + + + + +#define LINEAR_BLEND(a,b,t) ( (t)*((b)-(a)) + (a) ) + // linear blend of a and b 0a and t=1 ->b + + + +void GENESISCC gePose_BlendMotion( + gePose *P, const geMotion *M, geFloat Time, + const geXForm3d *Transform, + geFloat BlendAmount, gePose_BlendingType BlendingType) +{ + int i; + geBoolean NameBinding; + gePose_Joint *J; + geQuaternion R1; + geVec3d T1; + geXForm3d RootTransform; + + assert( P != NULL ); + //assert( M != NULL ); // M can be NULL + assert( BlendingType == GE_POSE_BLEND_HERMITE || BlendingType == GE_POSE_BLEND_LINEAR); + assert( BlendAmount >= 0.0f ); + assert( BlendAmount <= 1.0f ); + + P->OnlyThisJoint = GE_POSE_ROOT_JOINT-1; // calling this function disables one-joint optimizations + if (BlendingType == GE_POSE_BLEND_HERMITE) + { + geFloat t2,t3; + t2 = BlendAmount * BlendAmount; + t3 = t2 * BlendAmount; + BlendAmount = t2*3.0f -t3-t3; + } + + if (P->Parent==NULL) + { + geBoolean SetRoot = GE_FALSE; + if (geMotion_GetTransform(M,Time,&RootTransform)!=GE_FALSE) + { + SetRoot = GE_TRUE; + + if ( Transform != NULL ) + { + geXForm3d_Multiply(Transform,&RootTransform,&RootTransform); + } + } + else + { + if ( Transform != NULL ) + { + SetRoot = GE_TRUE; + RootTransform = *Transform; + } + } + + if (SetRoot != GE_FALSE) + { + geQuaternion_FromMatrix(&RootTransform,&R1); + T1 = RootTransform.Translation; + J = &(P->RootJoint); + geQuaternion_Slerp(&(J->LocalRotation),&(R1),BlendAmount,&(J->LocalRotation)); + { + geVec3d *LT = &(J->LocalTranslation); + LT->X = LINEAR_BLEND(LT->X,T1.X,BlendAmount); + LT->Y = LINEAR_BLEND(LT->Y,T1.Y,BlendAmount); + LT->Z = LINEAR_BLEND(LT->Z,T1.Z,BlendAmount); + } + J->Touched = GE_TRUE; + } + } + + if (M==NULL) + { + return; + } + + + if (gePose_MatchesMotionExactly(P,M)==GE_TRUE) + NameBinding = GE_FALSE; + else + NameBinding = GE_TRUE; + + P->Touched = GE_TRUE; + + for (i=0, J=&(P->JointArray[0]); iJointCount; i++,J++) + { + //gePath *JointPath; + + if (NameBinding == GE_FALSE) + { + geMotion_SampleChannels(M,i,Time,&R1,&T1); + //JointPath = geMotion_GetPath(M,i); + //assert( JointPath != NULL ); + } + else + { + //JointPath = geMotion_GetPathNamed(M, geStrBlock_GetString(P->JointNames,i)); + //if (JointPath == NULL) + // continue; + if (geMotion_SampleChannelsNamed(M, + geStrBlock_GetString(P->JointNames,i), + Time,&R1,&T1)==GE_FALSE) + continue; + + } + J->Touched = GE_TRUE; + + //gePath_SampleChannels(JointPath,Time,&(R1),&(T1)); + + T1.X *= P->Scale.X; + T1.Y *= P->Scale.Y; + T1.Z *= P->Scale.Z; + + geQuaternion_Slerp(&(J->LocalRotation),&(R1),BlendAmount,&(J->LocalRotation)); + + { + geVec3d *LT = &(J->LocalTranslation); + LT->X = LINEAR_BLEND(LT->X,T1.X,BlendAmount); + LT->Y = LINEAR_BLEND(LT->Y,T1.Y,BlendAmount); + LT->Z = LINEAR_BLEND(LT->Z,T1.Z,BlendAmount); + } + } +} + +const char* GENESISCC gePose_GetJointName(const gePose* P, int JointIndex) +{ + return geStrBlock_GetString(P->JointNames, JointIndex); +} + +const geXFArray * GENESISCC gePose_GetAllJointTransforms(const gePose *P) +{ + assert( P != NULL ); + + gePose_UpdateRelativeToParent((gePose *)P); + return P->TransformArray; +} + +void GENESISCC gePose_GetScale(const gePose *P, geVec3d *Scale) +{ + assert( P != NULL ); + assert( Scale != NULL ); + *Scale = P->Scale; +} + + +void GENESISCC gePose_SetScale(gePose *P, const geVec3d *Scale ) +{ + assert( P != NULL ); + assert( geVec3d_IsValid(Scale) != GE_FALSE ); + + { + int i; + gePose_Joint *J; + + P->Scale = *Scale; + //geVec3d_Set(&(P->Scale),ScaleX,ScaleY,ScaleZ); + + for (i=0, J=&(P->JointArray[0]); iJointCount; i++,J++) + { + J->AttachmentTransform.Translation.X = J->UnscaledAttachmentTranslation.X * Scale->X; + J->AttachmentTransform.Translation.Y = J->UnscaledAttachmentTranslation.Y * Scale->Y; + J->AttachmentTransform.Translation.Z = J->UnscaledAttachmentTranslation.Z * Scale->Z; + //J->AttachmentTransform.Translation = J->AttachmentTranslation; + J->Touched = GE_TRUE; + } + P->Touched = GE_TRUE; + } +} + +void GENESISCC gePose_ClearCoverage(gePose *P, int ClearTo) +{ + int i; + gePose_Joint *J; + + assert( P != NULL ); + assert( (ClearTo == GE_FALSE) || (ClearTo == GE_TRUE) ); + + for (i=0, J=&(P->JointArray[0]); iJointCount; i++,J++) + { + J->Covered = ClearTo; + } +} + +int GENESISCC gePose_AccumulateCoverage(gePose *P, const geMotion *M, geBoolean QueryOnly) +{ + int i,SubMotions; + geBoolean NameBinding; + int Covers=0; + gePose_Joint *J; + + assert( P != NULL ); + if (M==NULL) + { + return P->JointCount; + } + + SubMotions = geMotion_GetSubMotionCount(M); + if (SubMotions>0) + { + for (i=0; i Covers) + { + Covers = c; + } + } + return Covers; + } + + if (gePose_MatchesMotionExactly(P,M)==GE_TRUE) + NameBinding = GE_FALSE; + else + NameBinding = GE_TRUE; + + for (i=0, J=&(P->JointArray[0]); iJointCount; i++,J++) + { + gePath *JointPath; + if (J->Covered == GE_FALSE) + { + if (NameBinding == GE_TRUE) + { + JointPath = geMotion_GetPathNamed(M, geStrBlock_GetString(P->JointNames,i)); + if (JointPath == NULL) + continue; + } + if (QueryOnly == GE_FALSE) + { + J->Covered = GE_TRUE; + } + Covers ++; + } + } + return Covers; +} + diff --git a/G3D/Actor/pose.h b/G3D/Actor/pose.h new file mode 100644 index 0000000..262068a --- /dev/null +++ b/G3D/Actor/pose.h @@ -0,0 +1,169 @@ +/****************************************************************************************/ +/* POSE.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Bone hierarchy interface. . */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_POSE_H +#define GE_POSE_H + +/* gePose + + This object is a hierarchical set of attached joints. The joints can have names. + A 'gePose' keeps track of which children joints move in the hierarchy when a parent + joint moves. A gePose also remembers the position transform matrices for each joint. + + The gePose is set by applying a motion at a specific time. This queries the motion + to determine each joint's change and applies them to the hierarchy. Each joint can + then be queried for it's world transform (for drawing, etc.) + + Additional motions can modify or be blended into the pose. A motion that describes + only a few joint changes can be applied to only those joints, or a motion can be + blended with the current pose. + + Something to watch for: since setting the pose by applying a motion is powerful + enough to resolve intentionally mismatched motion-pose sets, this can lead to + problems if the motion UNintentionally does not match the pose. Use + gePose_MatchesgeMotionExactly() to test for an exact name-based match. + + +*/ + +#include +#include "Motion.h" +#include "XFArray.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define GE_POSE_ROOT_JOINT (-1) + +typedef enum +{ + GE_POSE_BLEND_LINEAR, + GE_POSE_BLEND_HERMITE +} gePose_BlendingType; + +typedef struct gePose gePose; + + // Creates a new pose with no joints. +gePose *GENESISCC gePose_Create(void); + + // Destroys an existing pose. +void GENESISCC gePose_Destroy(gePose **PM); + + // Adds a new joint to a pose. +geBoolean GENESISCC gePose_AddJoint( + gePose *P, + int ParentJointIndex, + const char *JointName, + const geXForm3d *Attachment, + int *JointIndex); + + +void GENESISCC gePose_GetScale(const gePose *P, geVec3d *Scale); + // Retrieves current joint attachment scaling factors + +void GENESISCC gePose_SetScale(gePose *P, const geVec3d *Scale); + // Scales all joint attachments by component scaling factors in Scale + + // Returns the index of a joint named JointName. Returns GE_TRUE if it is + // located, and Index is set. Returns GE_FALSE if not, and Index is not changed. +geBoolean GENESISCC gePose_FindNamedJointIndex(const gePose *P, const char *JointName, int *Index); + + // returns the number of joints in the pose +int GENESISCC gePose_GetJointCount(const gePose *P); + +geBoolean GENESISCC gePose_MatchesMotionExactly(const gePose *P, const geMotion *M); + +void GENESISCC gePose_Clear(gePose *P, const geXForm3d *Transform); + + // set the pose according to a motion. Use the motion at time 'Time'. + // if the motion does not describe motion for all joints, name-based resolution + // will be used to decide which motion to attach to which joints. + // joints that are unaffected are unchanged. + // if Transform is non-NULL, it is applied to the Motion +void GENESISCC gePose_SetMotion(gePose *P, const geMotion *M,geFloat Time,const geXForm3d *Transform); + + // optimization: if this is called, then all pose computations are limited to the BoneIndex'th bone, and + // it's parents (including the root bone). This is true for all queries until an entire motion is set or blended + // into the pose. +void GENESISCC gePose_SetMotionForABone(gePose *P, const geMotion *M, geFloat Time, + const geXForm3d *Transform,int BoneIndex); + + + // blend in the pose according to a motion. Use the motion at time 'Time'. + // the blending is between the 'current' pose and the pose described by the motion. + // a BlendAmount of 0 will result in the 'current' pose, and a BlendAmount of 1.0 + // will result in the pose according to the new motion. + // if the motion does not describe motion for all joints, name-based resolution + // will be used to decide which motion to attach to which joints. + // joints that are unaffected are unchanged. + // if Transform is non-NULL, it is applied to the Motion prior to blending +void GENESISCC gePose_BlendMotion(gePose *P, const geMotion *M, geFloat Time, + const geXForm3d *Transform, + geFloat BlendAmount, gePose_BlendingType BlendingType); + + // get a joint's current transform (relative to world space) +void GENESISCC gePose_GetJointTransform(const gePose *P, int JointIndex,geXForm3d *Transform); + + // get the transforms for the entire pose. *TransformArray must not be changed. +const geXFArray *GENESISCC gePose_GetAllJointTransforms(const gePose *P); + + // query a joint's current transform relative to it's attachment to it's parent. +void GENESISCC gePose_GetJointLocalTransform(const gePose *P, int JointIndex,geXForm3d *Transform); + + // adjust a joint's current transform relative to it's attachment to it's parent. + // this is like setting a mini-motion into this joint only: this will only affect + // the current pose +void GENESISCC gePose_SetJointLocalTransform(gePose *P, int JointIndex,const geXForm3d *Transform); + + // query how a joint is attached to it's parent. (it's base attachment) +void GENESISCC gePose_GetJointAttachment(const gePose *P,int JointIndex,geXForm3d *AttachmentTransform); + + // adjust how a joint is attached to it's parent. These changes are permanent: all + // future pose motions will incorporate this joint's new relation to it's parent */ +void GENESISCC gePose_SetJointAttachment(gePose *P,int JointIndex,const geXForm3d *AttachmentTransform); + +const char* GENESISCC gePose_GetJointName(const gePose* P, int JointIndex); + +geBoolean GENESISCC gePose_Attach(gePose *Slave, int SlaveBoneIndex, + gePose *Master, int MasterBoneIndex, + const geXForm3d *Attachment); + +void GENESISCC gePose_Detach(gePose *P); + + // a pose can also maintain a record of which joints are touched by a given motion. + // these funtions set,clear and query the record. + // ClearCoverage clears the coverage flag for all joints +void GENESISCC gePose_ClearCoverage(gePose *P, int ClearTo); + // AccumulateCoverage returns the number of joints that are not already 'covered' + // that will be affected by a motion M, + // if QueryOnly is GE_FALSE, affected joints are tagged as 'covered', otherwise no changes + // are made to the joint coverage flags. +int GENESISCC gePose_AccumulateCoverage(gePose *P, const geMotion *M, geBoolean QueryOnly); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/G3D/Actor/puppet.c b/G3D/Actor/puppet.c new file mode 100644 index 0000000..25d3f8e --- /dev/null +++ b/G3D/Actor/puppet.c @@ -0,0 +1,1901 @@ +/****************************************************************************************/ +/* PUPPET.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Puppet implementation. . */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +//#define CIRCULAR_SHADOW +#define SHADOW_MAP +//#define PROJECTED_SHADOW + +#include //fabs() +#include + +#include "light.h" +#include "world.h" +#include "trace.h" //Trace_WorldCollisionExact2() +#include "surface.h" // Surf_InSurfBoundingBox() + +#include "xfarray.h" +#include "puppet.h" +#include "pose.h" +#include "ErrorLog.h" +#include "ram.h" +#include "tclip.h" + +#include "Frustum.h" +#include "ExtBox.h" +#include "bodyinst.h" + +#ifdef PROFILE +#include "rdtsc.h" +#endif + +#include "bitmap.h" +#include "bitmap._h" + +#define PUPPET_DEFAULT_MAX_DYNAMIC_LIGHTS 3 + +typedef struct gePuppet_Color +{ + geFloat Red,Green,Blue; +} gePuppet_Color; + +typedef struct gePuppet_Material +{ + gePuppet_Color Color; + geBoolean UseTexture; + geBitmap *Bitmap; + const char *TextureName; + const char *MaterialName; + const char *AlphaName; +} gePuppet_Material; + +typedef struct gePuppet +{ + geVFile * TextureFileContext; + geBodyInst *BodyInstance; + int MaterialCount; + gePuppet_Material *MaterialArray; + int MaxDynamicLightsToUse; + int LightReferenceBoneIndex; + + geVec3d FillLightNormal; + gePuppet_Color FillLightColor; // 0..255 + geBoolean UseFillLight; // use fill light normal + //Environment mapping... + geEnvironmentOptions internal_env; + gePuppet_Color AmbientLightIntensity; // 0..1 + geBoolean AmbientLightFromFloor; // use local lighting from floor + + geBoolean PerBoneLighting; + + geBoolean DoShadow; + geFloat ShadowScale; + const geBitmap *ShadowMap; + int ShadowBoneIndex; + + // LWM_ACTOR_RENDERING: + geFloat OverallAlpha ; + + #pragma message ("this goes away!: World") + geWorld *World; + geBoolean AmbientLightFromStaticLights; // use static lights from map + geBoolean DoTestRayCollision; //test static light in shadow + int MaxStaticLightsToUse; //max number of light to use +} gePuppet; + +typedef struct +{ + geVec3d Normal; + gePuppet_Color Color; + geFloat Distance; + geFloat Radius; +} gePuppet_Light; + +typedef struct +{ + geBoolean UseFillLight; + geVec3d FillLightNormal; + gePuppet_Color MaterialColor; + gePuppet_Color FillLightColor; + gePuppet_Color Ambient; + geVec3d SurfaceNormal; + gePuppet_Light StaticLights[MAX_DYNAMIC_LIGHTS]; + int StaticLightCount; + gePuppet_Light Lights[MAX_DYNAMIC_LIGHTS]; + int LightCount; + geBoolean PerBoneLighting; +} gePuppet_LightParamGroup; + +typedef struct +{ + gePuppet_Light Lights[MAX_DYNAMIC_LIGHTS]; + int LightCount; +} gePuppet_BoneLight; + +// Local info stored across multiple puppets to avoid resource waste. +gePuppet_LightParamGroup gePuppet_StaticLightGrp; +gePuppet_BoneLight *gePuppet_StaticBoneLightArray=NULL; +int gePuppet_StaticBoneLightArraySize=0; +int gePuppet_StaticPuppetCount=0; +int gePuppet_StaticFlags[2]={1768710981,560296816}; + +static geBoolean GENESISCC gePuppet_FetchTextures(gePuppet *P, const geBody *B) +{ + int i; + assert( P ); + + P->MaterialCount = geBody_GetMaterialCount(B); + if (P->MaterialCount <= 0) + { + return GE_TRUE; + } + + P->MaterialArray = GE_RAM_ALLOCATE_ARRAY(gePuppet_Material, P->MaterialCount); + if (P->MaterialArray == NULL) + { + geErrorLog_Add(ERR_PUPPET_ENOMEM, NULL); + return GE_FALSE; + } + + for (i=0; iMaterialCount; i++) + { + const char *Name; + geBitmap *Bitmap; + gePuppet_Material *M = &(P->MaterialArray[i]); + geBody_GetMaterial( B, i, &(Name), &(Bitmap), + &(M->Color.Red),&(M->Color.Green),&(M->Color.Blue)); + + if (Bitmap == NULL ) + { + M->Bitmap = NULL; + M->UseTexture = GE_FALSE; + } + else + { + M->UseTexture = GE_TRUE; + assert( P->World ); + + M->Bitmap = Bitmap; + geBitmap_CreateRef(Bitmap); + + if ( ! geWorld_AddBitmap(P->World,Bitmap) ) + { + geErrorLog_AddString(-1,"Puppet_FetchTextures : World_AddBitmap", NULL); + geRam_Free(P->MaterialArray); + P->MaterialArray = NULL; + P->MaterialCount = 0; + return GE_FALSE; + } + } + M->MaterialName = Name; + } + + return GE_TRUE; +} + +int GENESISCC gePuppet_GetMaterialCount( gePuppet *P ) +{ + assert( P ); + return P->MaterialCount; +} + +geBoolean GENESISCC gePuppet_GetMaterial( gePuppet *P, int MaterialIndex, + geBitmap **Bitmap, + geFloat *Red, geFloat *Green, geFloat *Blue) +{ + assert( P ); + assert( Red ); + assert( Green ); + assert( Blue ); + assert( Bitmap ); + assert( MaterialIndex >= 0 ); + assert( MaterialIndex < P->MaterialCount ); + + { + gePuppet_Material *M = &(P->MaterialArray[MaterialIndex]); + *Bitmap = M->Bitmap; + *Red = M->Color.Red; + *Green = M->Color.Green; + *Blue = M->Color.Blue; + } + return GE_TRUE; +} + + +geBoolean GENESISCC gePuppet_SetMaterial(gePuppet *P, int MaterialIndex, geBitmap *Bitmap, + geFloat Red, geFloat Green, geFloat Blue) +{ + assert( P ); + assert( MaterialIndex >= 0 ); + assert( MaterialIndex < P->MaterialCount ); + + { + geBitmap * OldBitmap; + gePuppet_Material *M = P->MaterialArray + MaterialIndex; + + OldBitmap = M->Bitmap; + + M->Bitmap = Bitmap; + M->Color.Red = Red; + M->Color.Green = Green; + M->Color.Blue = Blue; + + if ( OldBitmap != Bitmap ) + { + if ( OldBitmap ) + { + assert( M->UseTexture ); + geWorld_RemoveBitmap( P->World, OldBitmap ); + geBitmap_Destroy( &(OldBitmap) ); + } + + M->UseTexture = GE_FALSE; + + if ( Bitmap ) + { + geBitmap_CreateRef(Bitmap); + + M->UseTexture = GE_TRUE; + + if ( ! geWorld_AddBitmap(P->World,Bitmap) ) + { + geErrorLog_AddString(-1,"Puppet_SetMaterial : World_AddBitmap", NULL); + return GE_FALSE; + } + } + } + } + + return GE_TRUE; +} + + +gePuppet *GENESISCC gePuppet_Create(geVFile *TextureFS, const geBody *B, geWorld *World) +{ + gePuppet *P; + + assert( geBody_IsValid(B)!=GE_FALSE ); + #pragma message ("Need geWorld_IsValid()") + + P = GE_RAM_ALLOCATE_STRUCT(gePuppet); + if (P==NULL) + { + geErrorLog_Add(ERR_PUPPET_ENOMEM, NULL); + return NULL; + } + + memset(P,0,sizeof(*P)); + + P->BodyInstance = NULL; + P->MaxDynamicLightsToUse = PUPPET_DEFAULT_MAX_DYNAMIC_LIGHTS; + P->LightReferenceBoneIndex = GE_POSE_ROOT_JOINT; + + P->FillLightNormal.X = -0.2f; + P->FillLightNormal.Y = 1.0f; + P->FillLightNormal.Z = 0.4f; + geVec3d_Normalize(&(P->FillLightNormal)); + P->FillLightColor.Red = 0.25f; + P->FillLightColor.Green = 0.25f; + P->FillLightColor.Blue = 0.25f; + P->UseFillLight = GE_TRUE; + // LWM_ACTOR_RENDERING: + P->OverallAlpha = 255.0f ; + + P->AmbientLightIntensity.Red = 0.1f; + P->AmbientLightIntensity.Green = 0.1f; + P->AmbientLightIntensity.Blue = 0.1f; + P->AmbientLightFromFloor = GE_TRUE; + + P->DoShadow = GE_FALSE; + P->ShadowScale = 0.0f; + P->ShadowBoneIndex = GE_POSE_ROOT_JOINT; + P->TextureFileContext = TextureFS; + + P->World = World; + + P->AmbientLightFromStaticLights = GE_FALSE; //BY DEFAULT DO NOTHING + P->DoTestRayCollision = GE_FALSE; + P->MaxStaticLightsToUse = PUPPET_DEFAULT_MAX_DYNAMIC_LIGHTS; + + //Set default environment options + P->internal_env.PercentEnvironment = 0.0f; + P->internal_env.PercentPuppet = 1.0f; + P->internal_env.PercentMaterial = 1.0f; + P->internal_env.UseEnvironmentMapping = GE_FALSE; + P->internal_env.Supercede = GE_TRUE; + + if (gePuppet_FetchTextures(P,B)==GE_FALSE) + { + geRam_Free(P); + return NULL; + } + + P->BodyInstance = geBodyInst_Create(B); + if (P->BodyInstance == NULL) + { + geErrorLog_Add(ERR_PUPPET_ENOMEM, NULL); + gePuppet_Destroy( &P ); + return NULL; + } + gePuppet_StaticPuppetCount++; + return P; +} + + +void GENESISCC gePuppet_Destroy(gePuppet **P) +{ + assert( P ); + assert( *P ); + if ( (*P)->BodyInstance ) + { + geBodyInst_Destroy( &((*P)->BodyInstance) ); + (*P)->BodyInstance = NULL; + } + if ( (*P)->MaterialArray ) + { + gePuppet_Material *M; + int i; + + for (i=0; i<(*P)->MaterialCount; i++) + { + M = &((*P)->MaterialArray[i]); + if (M->UseTexture ) + { + assert( M->Bitmap ); + geWorld_RemoveBitmap( (*P)->World, M->Bitmap ); + geBitmap_Destroy( &(M->Bitmap) ); + M->UseTexture = GE_FALSE; + } + } + + + geRam_Free( (*P)->MaterialArray ); + (*P)->BodyInstance = NULL; + } + if ( (*P)->ShadowMap ) + { + geBitmap_Destroy((geBitmap **)&((*P)->ShadowMap)); + (*P)->ShadowMap = NULL; + } + + geRam_Free( (*P) ); + *P = NULL; + + // clean up any shared resources. + gePuppet_StaticPuppetCount--; + if (gePuppet_StaticPuppetCount==0) + { + if (gePuppet_StaticBoneLightArray!=NULL) + geRam_Free(gePuppet_StaticBoneLightArray); + gePuppet_StaticBoneLightArray=NULL; + gePuppet_StaticBoneLightArraySize = 0; + } +} + +void GENESISCC gePuppet_GetStaticLightingOptions(const gePuppet *P, geBoolean *UseAmbientLightFromStaticLights, geBoolean *TestRayCollision, int *MaxStaticLightsToUse ) +{ assert( P != NULL); + assert( UseAmbientLightFromStaticLights ); + assert( MaxStaticLightsToUse ); + *UseAmbientLightFromStaticLights = P->AmbientLightFromStaticLights; + *TestRayCollision = P->DoTestRayCollision; + *MaxStaticLightsToUse = P->MaxStaticLightsToUse; +} + +void GENESISCC gePuppet_SetStaticLightingOptions(gePuppet *P, geBoolean UseAmbientLightFromStaticLights, geBoolean TestRayCollision, int MaxStaticLightsToUse ) +{ assert( P!= NULL); + P->AmbientLightFromStaticLights = UseAmbientLightFromStaticLights; + P->DoTestRayCollision = TestRayCollision; + P->MaxStaticLightsToUse = MaxStaticLightsToUse; +} + +void GENESISCC gePuppet_GetLightingOptions(const gePuppet *P, + geBoolean *UseFillLight, + geVec3d *FillLightNormal, + geFloat *FillLightRed, + geFloat *FillLightGreen, + geFloat *FillLightBlue, + geFloat *AmbientLightRed, + geFloat *AmbientLightGreen, + geFloat *AmbientLightBlue, + geBoolean *UseAmbientLightFromFloor, + int *MaximumDynamicLightsToUse, + int *LightReferenceBoneIndex, + geBoolean *PerBoneLighting + ) +{ + geFloat Scaler; + assert( P != NULL); + assert( UseFillLight ); + assert( FillLightNormal ); + assert( FillLightRed ); + assert( FillLightGreen ); + assert( FillLightBlue ); + assert( AmbientLightRed ); + assert( AmbientLightGreen ); + assert( AmbientLightBlue ); + assert( UseAmbientLightFromFloor ); + assert( MaximumDynamicLightsToUse ); + assert( LightReferenceBoneIndex ); + + *UseFillLight = P->UseFillLight; + + *FillLightNormal = P->FillLightNormal; + + Scaler = 255.0f; + *FillLightRed = P->FillLightColor.Red * Scaler; + *FillLightGreen = P->FillLightColor.Green * Scaler; + *FillLightBlue = P->FillLightColor.Blue * Scaler; + + *AmbientLightRed = P->AmbientLightIntensity.Red * Scaler; + *AmbientLightGreen = P->AmbientLightIntensity.Green * Scaler; + *AmbientLightBlue = P->AmbientLightIntensity.Blue * Scaler; + + *UseAmbientLightFromFloor = P->AmbientLightFromFloor; + *MaximumDynamicLightsToUse = P->MaxDynamicLightsToUse; + *LightReferenceBoneIndex = P->LightReferenceBoneIndex; + *PerBoneLighting = P->PerBoneLighting; +} + +void GENESISCC gePuppet_SetLightingOptions(gePuppet *P, + geBoolean UseFillLight, + const geVec3d *FillLightNormal, + geFloat FillLightRed, // 0 .. 255 + geFloat FillLightGreen, // 0 .. 255 + geFloat FillLightBlue, // 0 .. 255 + geFloat AmbientLightRed, // 0 .. 255 + geFloat AmbientLightGreen, // 0 .. 255 + geFloat AmbientLightBlue, // 0 .. 255 + geBoolean UseAmbientLightFromFloor, + int MaximumDynamicLightsToUse, // 0 for none + int LightReferenceBoneIndex, + geBoolean PerBoneLighting + ) +{ + geFloat Scaler; + assert( P!= NULL); + assert( FillLightNormal ); + assert( geVec3d_IsNormalized(FillLightNormal) ); + assert( MaximumDynamicLightsToUse >= 0 ); + assert( (LightReferenceBoneIndex >=0) || (LightReferenceBoneIndex==GE_POSE_ROOT_JOINT)); + + P->UseFillLight = UseFillLight; + + P->FillLightNormal = *FillLightNormal; + + Scaler = 1.0f/255.0f; + + P->FillLightColor.Red = FillLightRed * Scaler; + P->FillLightColor.Green = FillLightGreen * Scaler; + P->FillLightColor.Blue = FillLightBlue * Scaler; + + P->AmbientLightIntensity.Red = AmbientLightRed * Scaler; + P->AmbientLightIntensity.Green = AmbientLightGreen * Scaler; + P->AmbientLightIntensity.Blue = AmbientLightBlue * Scaler; + + P->AmbientLightFromFloor =UseAmbientLightFromFloor; + P->MaxDynamicLightsToUse = MaximumDynamicLightsToUse; + P->LightReferenceBoneIndex = LightReferenceBoneIndex; + P->PerBoneLighting = PerBoneLighting; +} + + +static int GENESISCC gePuppet_PrepLights(const gePuppet *P, + geWorld *World, + gePuppet_Light *LP, + const geVec3d *ReferencePoint) +{ + int i,j,cnt; + + Light_LightInfo *L; + assert( P ); + assert( LP ); + + L = (World->LightInfo); + for (i=0,cnt=0; iDynamicLights[i].Active) + { + geVec3d *Position = &(L->DynamicLights[i].Pos); + geVec3d Normal; + + geVec3d_Subtract(Position,ReferencePoint,&Normal); + + LP[cnt].Distance = Normal.X * Normal.X + + Normal.Y * Normal.Y + + Normal.Z * Normal.Z; + if (LP[cnt].Distance < L->DynamicLights[i].Radius*L->DynamicLights[i].Radius) + { + LP[cnt].Color.Red = L->DynamicLights[i].Color.r; + LP[cnt].Color.Green = L->DynamicLights[i].Color.g; + LP[cnt].Color.Blue = L->DynamicLights[i].Color.b; + LP[cnt].Radius = L->DynamicLights[i].Radius; + LP[cnt].Normal = Normal; + cnt++; + } + } + } + + // sort dynamic lights by distance (squared) + for(i=0; iMaxDynamicLightsToUse && i LP[j].Distance) + { + gePuppet_Light Swap = LP[j]; + LP[j] = LP[i]; + LP[i] = Swap; + } + } + + // go back and finish setting up closest lights + for (i=0; iAmbientLightFromFloor != GE_FALSE) + { +#define GE_PUPPET_MAX_AMBIENT (0.3f) + int32 Node, Plane, i; + geVec3d Pos1, Pos2, Impact; + GFX_Node *GFXNodes; + Surf_SurfInfo *Surf; + GE_RGBA RGBA; + //geBoolean Col1, Col2; + + GFXNodes = World->CurrentBSP->BSPData.GFXNodes; + + Pos1 = *ReferencePoint; + + Pos2 = Pos1; + + Pos2.Y -= 30000.0f; + + if(!Trace_WorldCollisionExact2((geWorld*)World, &Pos1, &Pos1, &Impact, &Node, &Plane, NULL)) //just save one test //xing studios + { + // Now find the color of the mesh by getting the lightmap point he is standing on... + if (Trace_WorldCollisionExact2((geWorld*)World, &Pos1, &Pos2, &Impact, &Node, &Plane, NULL)) + { + Surf = &(World)->CurrentBSP->SurfInfo[GFXNodes[Node].FirstFace]; + if (Surf->LInfo.Face<0) + { // FIXME? surface has no light... + Ambient->Red = Ambient->Green = Ambient->Blue = 0.0f; + } + else + { + for (i=0; i< GFXNodes[Node].NumFaces; i++) + { + if (Surf_InSurfBoundingBox(Surf, &Impact, 20.0f)) + { + Light_SetupLightmap(&Surf->LInfo, NULL); + + if (Light_GetLightmapRGB(Surf, &Impact, &RGBA)) + { + geFloat Scale = 1.0f / 255.0f; + Ambient->Red = RGBA.r * Scale; + Ambient->Green = RGBA.g * Scale; + Ambient->Blue = RGBA.b * Scale; + if (Ambient->Red > GE_PUPPET_MAX_AMBIENT) + { + Ambient->Red = GE_PUPPET_MAX_AMBIENT; + } + if (Ambient->Green > GE_PUPPET_MAX_AMBIENT) + { + Ambient->Green = GE_PUPPET_MAX_AMBIENT; + } + if (Ambient->Blue > GE_PUPPET_MAX_AMBIENT) + { + Ambient->Blue = GE_PUPPET_MAX_AMBIENT; + } + break; + } + } + Surf++; + } + } + } + } + } + + if(P->AmbientLightFromStaticLights != GE_FALSE) + { + int i,j,cnt; + geEntity_EntitySet * entitySet = NULL; + geEntity * entity = NULL; + light * aLight; + entitySet = geWorld_GetEntitySet(World, "light"); + if (entitySet != NULL) + entity = geEntity_EntitySetGetNextEntity(entitySet, entity); + + //loop through all static lights and select the ones that touch the actor, with a max limit of MAX_DYNAMIC_LIGHTS + for (i=0,cnt=0; entity != NULL && cntorigin); + geVec3d_Subtract(Position,ReferencePoint,&Normal); + LP[cnt].Distance = Normal.X * Normal.X + + Normal.Y * Normal.Y + + Normal.Z * Normal.Z; + if (LP[cnt].Distance < aLight->light * aLight->light) + { + if (P->DoTestRayCollision == GE_TRUE) + { + if (!Trace_WorldCollisionExact2((geWorld*)World, ReferencePoint, Position, NULL, NULL, NULL, NULL)) + { + LP[cnt].Color.Red = aLight->color.r; + LP[cnt].Color.Green = aLight->color.g; + LP[cnt].Color.Blue = aLight->color.b; + LP[cnt].Radius = (float)aLight->light; + LP[cnt].Normal = Normal; + cnt++; + } + } + else + { + LP[cnt].Color.Red = aLight->color.r; + LP[cnt].Color.Green = aLight->color.g; + LP[cnt].Color.Blue = aLight->color.b; + LP[cnt].Radius = (float)aLight->light; + LP[cnt].Normal = Normal; + cnt++; + } + } + entity = geEntity_EntitySetGetNextEntity(entitySet, entity); + } + // sort static lights by distance (squared) + // for(i=0; iMaxDynamicLightsToUse && i LP[j].Distance) + { + gePuppet_Light Swap = LP[j]; + LP[j] = LP[i]; + LP[i] = Swap; + } + } + // go back and finish setting up closest lights + for (i=0; iAmbientLightFromFloor == GE_FALSE && P->AmbientLightFromStaticLights == GE_FALSE) + { + *Ambient = P->AmbientLightIntensity; + } + return 0; +} + +static void GENESISCC gePuppet_SetVertexColor( + GE_LVertex *v,int BoneIndex) +{ + geFloat RedIntensity,GreenIntensity,BlueIntensity; + geFloat Color; + int l; + + assert( v ); + + RedIntensity = gePuppet_StaticLightGrp.Ambient.Red; + GreenIntensity = gePuppet_StaticLightGrp.Ambient.Green; + BlueIntensity = gePuppet_StaticLightGrp.Ambient.Blue; + + if (gePuppet_StaticLightGrp.UseFillLight) + { + geFloat Intensity; + Intensity = gePuppet_StaticLightGrp.FillLightNormal.X * gePuppet_StaticLightGrp.SurfaceNormal.X + + gePuppet_StaticLightGrp.FillLightNormal.Y * gePuppet_StaticLightGrp.SurfaceNormal.Y + + gePuppet_StaticLightGrp.FillLightNormal.Z * gePuppet_StaticLightGrp.SurfaceNormal.Z; + if (Intensity > 0.0) + { + RedIntensity += Intensity * gePuppet_StaticLightGrp.FillLightColor.Red; + GreenIntensity += Intensity * gePuppet_StaticLightGrp.FillLightColor.Green; + BlueIntensity += Intensity * gePuppet_StaticLightGrp.FillLightColor.Blue; + } + } + + if (gePuppet_StaticLightGrp.PerBoneLighting) + { + gePuppet_BoneLight *L; + L=&(gePuppet_StaticBoneLightArray[BoneIndex]); + + for (l=0; lLightCount; l++) + { + geVec3d *LightNormal; + geFloat Intensity; + + LightNormal = &(L->Lights[l].Normal); + + Intensity= LightNormal->X * gePuppet_StaticLightGrp.SurfaceNormal.X + + LightNormal->Y * gePuppet_StaticLightGrp.SurfaceNormal.Y + + LightNormal->Z * gePuppet_StaticLightGrp.SurfaceNormal.Z; + if (Intensity > 0.0f) + { + RedIntensity += Intensity * L->Lights[l].Color.Red; + GreenIntensity += Intensity * L->Lights[l].Color.Green; + BlueIntensity += Intensity * L->Lights[l].Color.Blue; + } + } + } + else + { + for (l=0; lX * gePuppet_StaticLightGrp.SurfaceNormal.X + + LightNormal->Y * gePuppet_StaticLightGrp.SurfaceNormal.Y + + LightNormal->Z * gePuppet_StaticLightGrp.SurfaceNormal.Z; + if (Intensity > 0.0f) + { + RedIntensity += Intensity * gePuppet_StaticLightGrp.Lights[l].Color.Red; + GreenIntensity += Intensity * gePuppet_StaticLightGrp.Lights[l].Color.Green; + BlueIntensity += Intensity * gePuppet_StaticLightGrp.Lights[l].Color.Blue; + } + } + } + for (l=0; lX * gePuppet_StaticLightGrp.SurfaceNormal.X + + LightNormal->Y * gePuppet_StaticLightGrp.SurfaceNormal.Y + + LightNormal->Z * gePuppet_StaticLightGrp.SurfaceNormal.Z; + if (Intensity > 0.0f) + { + RedIntensity += Intensity * gePuppet_StaticLightGrp.StaticLights[l].Color.Red; + GreenIntensity += Intensity * gePuppet_StaticLightGrp.StaticLights[l].Color.Green; + BlueIntensity += Intensity * gePuppet_StaticLightGrp.StaticLights[l].Color.Blue; + } + } + + Color = gePuppet_StaticLightGrp.MaterialColor.Red * RedIntensity; + if (Color > 255.0f) + Color = 255.0f; + if (Color < 0.0f) + Color = 0.0f; + v->r = Color; + + Color = gePuppet_StaticLightGrp.MaterialColor.Green * GreenIntensity; + if (Color > 255.0f) + Color = 255.0f; + if (Color < 0.0f) + Color = 0.0f; + v->g = Color; + + Color = gePuppet_StaticLightGrp.MaterialColor.Blue * BlueIntensity; + if (Color > 255.0f) + Color = 255.0f; + if (Color < 0.0f) + Color = 0.0f; + v->b = Color; + +} + + +static void GENESISCC gePuppet_DrawShadow(const gePuppet *P, + const gePose *Joints, + geEngine *Engine, + geWorld *World, + const geCamera *Camera) +{ + GE_LVertex v[3]; + + geVec3d Impact; + geBoolean GoodImpact; + GFX_Plane Plane; + geXForm3d RootTransform; + + assert( P ); + assert( World ); + assert( Camera ); + assert( Joints ); + + assert( (P->ShadowBoneIndex < gePose_GetJointCount(Joints)) || (P->ShadowBoneIndex ==GE_POSE_ROOT_JOINT)); + assert( (P->ShadowBoneIndex >=0) || (P->ShadowBoneIndex ==GE_POSE_ROOT_JOINT)); + + gePose_GetJointTransform(Joints,P->ShadowBoneIndex,&RootTransform); + + { + geVec3d Pos1, Pos2; + GE_Collision Collision; + + Pos1 = RootTransform.Translation; + + Pos2 = Pos1; + + Pos2.Y -= 30000.0f; + + // Get shadow hit plane impact point + GoodImpact = Trace_GEWorldCollision(World, + NULL, + NULL, + &Pos1, + &Pos2, + GE_CONTENTS_SOLID_CLIP, + GE_COLLIDE_MODELS, + 0, + NULL, + NULL, + &Collision); + + //if(GoodImpact) + Impact = Collision.Impact; + //else + //return; + } + + Impact.Y += 1.0f; + + v[0].r = v[0].b = v[0].g = 0.0f; + v[1].r = v[1].b = v[1].g = 0.0f; + v[2].r = v[2].b = v[2].g = 0.0f; + +#ifdef SHADOW_MAP + { + int i; + GE_LVertex s[4]; + geVec3d ws[4]; + geVec3d In,Left; + geVec3d Up; + geVec3d Zero = {0.0f,0.0f,0.0f}; + + geVec3d_Subtract(&Impact,&(RootTransform.Translation),&Up); + geVec3d_Normalize(&Up); + geVec3d_CrossProduct(&(Plane.Normal),&Up,&Left); + if (geVec3d_Compare(&Left,&Zero,0.001f)!=GE_FALSE) + { + geXForm3d_GetLeft(&(RootTransform),&Left); + } + geVec3d_CrossProduct(&Left,&(Plane.Normal),&In); + + geVec3d_Normalize(&Left); + geVec3d_Normalize(&In); + + s[0].r = s[0].b = s[0].g = 0.0f; + s[1].r = s[1].b = s[1].g = 0.0f; + s[2].r = s[2].b = s[2].g = 0.0f; + s[3].r = s[3].b = s[3].g = 0.0f; + + geVec3d_Scale(&In ,P->ShadowScale,&In); + geVec3d_Scale(&Left,P->ShadowScale,&Left); + + s[0].a = s[1].a = s[2].a = s[3].a = 160.0f; + + s[0].u = 0.0f; s[0].v = 0.0f; + s[1].u = 1.0f; s[1].v = 0.0f; + s[2].u = 1.0f; s[2].v = 1.0f; + s[3].u = 0.0f; s[3].v = 1.0f; + ws[0].Y = ws[1].Y = ws[2].Y = ws[3].Y = Impact.Y; + + ws[0].X = RootTransform.Translation.X + Left.X - In.X; + ws[0].Z = RootTransform.Translation.Z + Left.Z - In.Z; + + ws[1].X = RootTransform.Translation.X - Left.X - In.X; + ws[1].Z = RootTransform.Translation.Z - Left.Z - In.Z; + + ws[2].X = RootTransform.Translation.X - Left.X + In.X; + ws[2].Z = RootTransform.Translation.Z - Left.Z + In.Z; + + ws[3].X = RootTransform.Translation.X + Left.X + In.X; + ws[3].Z = RootTransform.Translation.Z + Left.Z + In.Z; + + for (i=0; i<4; i++) + { + geCamera_Transform(Camera,&ws[i],&ws[i]); + geCamera_Project(Camera,&ws[i],&ws[i]); + } + + + s[0].X = ws[0].X; s[0].Y = ws[0].Y; s[0].Z = ws[0].Z; + s[1].X = ws[1].X; s[1].Y = ws[1].Y; s[1].Z = ws[1].Z; + s[2].X = ws[2].X; s[2].Y = ws[2].Y; s[2].Z = ws[2].Z; + s[3].X = ws[3].X; s[3].Y = ws[3].Y; s[3].Z = ws[3].Z; + + geTClip_SetTexture(P->ShadowMap); + + geTClip_Triangle(s); + s[1] = s[2]; + s[2] = s[3]; + + geTClip_Triangle(s); + } +#endif + +#ifdef CIRCULAR_SHADOW + v[0].a = v[1].a = v[2].a = 160.0f; + v[0].u = v[1].u = v[2].u = 0.5f; + v[0].v = v[1].v = v[2].v = 0.5f; + + v[0].X = Impact.X; + v[0].Y = v[1].Y = v[2].Y = Impact.Y; + v[0].Z = Impact.Z; + + { + int steps = 30; + int i; + geVec3d V; + geFloat Angle = 0.0f; + geFloat DAngleDStep = -(2.0f * 3.14159f / (geFloat)steps); + geFloat Radius = P->ShadowScale/2.0f; + + V = Impact; + geCamera_Transform(Camera,&V,&V); + geCamera_Project(Camera,&V,&V); + v[0].X = V.X; + v[0].Y = V.Y; + v[0].Z = V.Z; + + //geTClip_SetTexture(NULL); + geTClip_SetTexture(P->ShadowMap); + + V = Impact; + V.Z += Radius; + geCamera_Transform(Camera,&V,&V); + geCamera_Project(Camera,&V,&V); + v[1].X = V.X; + v[1].Y = V.Y; + v[1].Z = V.Z; + for (i=0; iShadowMap, 0 ); + //geTClip_Triangle(v); + } + } +#endif + +#ifdef PROJECTED_SHADOW + { + int i,j,Count; + geBodyInst_Index *List; + geBodyInst_Index Command; + geBody_SkinVertex *SV; + + G = geBodyInst_GetShadowGeometry(P->BodyInstance, + gePose_GetAllJointTransforms(Joints),0,Camera,&Impact); + + if ( G == NULL ) + { + geErrorLog_Add(ERR_PUPPET_RENDER, NULL); + return GE_FALSE; + } + + geTClip_SetTexture(NULL); + + Count = G->FaceCount; + List = G->FaceList; + + for (i=0; iSkinVertexArray[ *List2 ]); + AX = SV->SVPoint.X; + AY = SV->SVPoint.Y; + List2++; + List2++; + + SV = &(G->SkinVertexArray[ *List2 ]); + BXMinusAX = SV->SVPoint.X - AX; + BYMinusAY = SV->SVPoint.Y - AY; + List2++; + List2++; + + SV = &(G->SkinVertexArray[ *List2 ]); + CXMinusAX = SV->SVPoint.X - AX; + CYMinusAY = SV->SVPoint.Y - AY; + List2++; + List2++; + + // ZCROSS is z the component of a 2d vector cross product of ABxAC + //#define ZCROSS(Ax,Ay,Bx,By,Cx,Cy) ((((Bx)-(Ax))*((Cy)-(Ay))) - (((By)-(Ay))*((Cx)-(Ax)))) + + // 2d cross product of AB cross AC (A is vtx[0], B is vtx[1], C is vtx[2] + if ( ((BXMinusAX * CYMinusAY) - (BYMinusAY * CXMinusAX)) > 0.0f ) + { + List = List2; + continue; + } + } + + #define SOME_SCALE ( 255.0f / 40.0f ) + for (j=0; j<3; j++) + { + SV = &(G->SkinVertexArray[ *List ]); + List++; + + v[j].X = SV->SVPoint.X; + v[j].Y = SV->SVPoint.Y; + + v[j].Z = SV->SVPoint.Z; + //Environment mapping code + if( P->internal_env.UseEnvironmentMapping ) + { + v[j].u = ( SV->SVU * P->internal_env.PercentPuppet ); + v[j].v = ( SV->SVV * P->internal_env.PercentPuppet ); + + if( P->internal_env.Supercede && PM->MaterialName[0] == 'g' ) + { + v[j].u += ( (G->NormalArray[ *List ]).X * P->internal_env.PercentMaterial); + v[j].v += ( (G->NormalArray[ *List ]).Y * P->internal_env.PercentMaterial); + } + else + { + v[j].u += ( (G->NormalArray[ *List ]).X * P->internal_env.PercentEnvironment); + v[j].v += ( (G->NormalArray[ *List ]).Y * P->internal_env.PercentEnvironment); + } + } + else + { + v[j].u = SV->SVU; + v[j].v = SV->SVV; + + if( P->internal_env.Supercede && PM->MaterialName[0] == 'g' ) + { + v[j].u += ( (G->NormalArray[ *List ]).X * P->internal_env.PercentMaterial); + v[j].v += ( (G->NormalArray[ *List ]).Y * P->internal_env.PercentMaterial); + } + } + + List++; + v[j].a = (255.0f- (SV->SVU * SOME_SCALE)); + } + + if ((v[0].a > 0) && (v[1].a > 0) && (v[2].a > 0)) + { + geTClip_Triangle(v); + } + } + assert( ((uint32)List) - ((uint32)G->FaceList) == (uint32)(G->FaceListSize) ); + } +#endif +} + +//Environment mapping code... +void GENESISCC gePuppet_SetEnvironmentOptions( gePuppet *P, geEnvironmentOptions *envop ) +{ + assert ( P ); + assert ( (envop->UseEnvironmentMapping == GE_TRUE) || (envop->UseEnvironmentMapping == GE_FALSE ) ); + assert ( (envop->Supercede == GE_TRUE) || (envop->Supercede == GE_FALSE) ); + assert ( (envop->PercentEnvironment >= 0.0f) && (envop->PercentEnvironment <= 1.0f) ); + assert ( (envop->PercentMaterial >= 0.0f) && (envop->PercentMaterial <= 1.0f) ); + assert ( (envop->PercentPuppet >= 0.0f) && (envop->PercentPuppet <= 1.0f) ); + + P->internal_env.UseEnvironmentMapping = envop->UseEnvironmentMapping; + P->internal_env.Supercede = envop->Supercede; + P->internal_env.PercentEnvironment = envop->PercentEnvironment; + P->internal_env.PercentMaterial = envop->PercentEnvironment; + P->internal_env.PercentPuppet = envop->PercentPuppet; +} + +geEnvironmentOptions GENESISCC gePuppet_GetEnvironmentOptions( gePuppet *P ) +{ + assert ( P ); + return P->internal_env; +} + +int32 NumClips; + +// LWM_ACTOR_RENDERING +geFloat GENESISCC gePuppet_GetAlpha( const gePuppet *P ) +{ + assert( P ) ; + return P->OverallAlpha ; +} + +// LWM_ACTOR_RENDERING +void GENESISCC gePuppet_SetAlpha( gePuppet *P, geFloat Alpha ) +{ + assert( P ) ; + P->OverallAlpha = Alpha ; +} + +// LWM_ACTOR_RENDERING +geBoolean GENESISCC gePuppet_RenderThroughFrustum(const gePuppet *P, + const gePose *Joints, + const geExtBox *Box, + geEngine *Engine, + geWorld *World, + const geCamera *Camera, + Frustum_Info *FInfo) +{ + int32 ClipFlags; + geVec3d Scale; + const geXFArray *JointTransforms; + + const geBodyInst_Geometry *G; + assert( P ); + assert( Engine ); + assert( World ); + assert( Camera ); + assert( Joints ); + + JointTransforms = gePose_GetAllJointTransforms(Joints); + + #pragma message ("Level of detail hacked:") + + gePose_GetScale(Joints,&Scale); + G = geBodyInst_GetGeometry(P->BodyInstance, &Scale, JointTransforms, 0, NULL); + + // Setup clip flags... + ClipFlags = 0xffff; + + { + geExtBox MinMaxs; + //geVec3d d1, d2, d3; + GFX_Plane *Planes; + int32 k; + geVec3d Expand = {150.0f, 150.f, 150.0f}; + int32 OriginalClips; + + OriginalClips = NumClips; + + MinMaxs = *Box; + + Planes = FInfo->Planes; + + for (k=0; k< FInfo->NumPlanes; k++, Planes++) + { + int32 Side; + + Planes->Type = PLANE_ANY; + + Side = Trace_BoxOnPlaneSide(&MinMaxs.Min, &MinMaxs.Max, Planes); + + if (Side == PSIDE_BACK) + { + NumClips = OriginalClips; + return GE_TRUE; + } + + if (Side == PSIDE_FRONT) + { + ClipFlags &= ~(1<UseFillLight; + gePuppet_StaticLightGrp.FillLightNormal = P->FillLightNormal; + gePuppet_StaticLightGrp.FillLightColor.Red = P->FillLightColor.Red; + gePuppet_StaticLightGrp.FillLightColor.Green = P->FillLightColor.Green; + gePuppet_StaticLightGrp.FillLightColor.Blue = P->FillLightColor.Blue; + gePuppet_StaticLightGrp.PerBoneLighting = P->PerBoneLighting; + + gePose_GetJointTransform(Joints,P->LightReferenceBoneIndex,&(RootTransform)); + + // LWM_OPTIMIZATION: It seems that if you know that there are + // no dynamic lights anywhere you could skip this test easily + if (P->MaxDynamicLightsToUse > 0) + { + if (P->PerBoneLighting) + { + int BoneCount; + const geXForm3d *XFA = geXFArray_GetElements(JointTransforms, &BoneCount); + if (BoneCount>0) + { + if (gePuppet_StaticBoneLightArraySize < BoneCount) + { + gePuppet_BoneLight *LG; + + LG = geRam_Realloc(gePuppet_StaticBoneLightArray, sizeof(gePuppet_BoneLight) * BoneCount); + if (LG==NULL) + { + geErrorLog_Add(ERR_PUPPET_RENDER,"Failed to allocate space for bone lighting info cache"); + return GE_FALSE; + } + gePuppet_StaticBoneLightArray = LG; + gePuppet_StaticBoneLightArraySize = BoneCount; + } + for (i=0; iFaceCount; + List = G->FaceList; + + // For each face, clip it to the view frustum supplied... + for (i=0; i=0 ); + assert( MaterialMaterialCount); + + PM = &(P->MaterialArray[Material]); + gePuppet_StaticLightGrp.MaterialColor = PM->Color; + + Length1 = 3; //FIXME: I'm assuming numverts == 3 + + pVerts = Verts; + pTexVerts = TexVerts; + + // AHHH!! Copy over till I get a better way... + for (v=0; v< Length1; v++, pVerts++, pTexVerts++) + { + geBodyInst_SkinVertex *SVert; + GE_LVertex lvert; + + SVert = &G->SkinVertexArray[*List]; + List++; + + *pVerts = SVert->SVPoint; + + assert( ((geFloat)fabs(1.0-geVec3d_Length( &(G->NormalArray[ *List ] ))))< 0.001f ); + + gePuppet_StaticLightGrp.SurfaceNormal = (G->NormalArray[ *List ]); + + List++; + + //gePuppet_SetVertexColor2(P,PM,&Ambient,SurfaceNormal, Lights,LightCount, pTexVerts); + gePuppet_SetVertexColor(&lvert,SVert->ReferenceBoneIndex); + pTexVerts->r = lvert.r; + pTexVerts->g = lvert.g; + pTexVerts->b = lvert.b; + //Environment mapping code... + if( P->internal_env.UseEnvironmentMapping ) + { + pTexVerts->u = ( SVert->SVU * P->internal_env.PercentPuppet ); + pTexVerts->v = ( SVert->SVV * P->internal_env.PercentPuppet ); + + if( P->internal_env.Supercede && PM->MaterialName[0] == 'g' ) + { + pTexVerts->u += ( (G->NormalArray[ *List ]).X * P->internal_env.PercentMaterial); + pTexVerts->v += ( (G->NormalArray[ *List ]).Y * P->internal_env.PercentMaterial); + } + else + { + pTexVerts->u += ( (G->NormalArray[ *List ]).X * P->internal_env.PercentEnvironment); + pTexVerts->v += ( (G->NormalArray[ *List ]).Y * P->internal_env.PercentEnvironment); + } + } + else + { + pTexVerts->u = SVert->SVU; + pTexVerts->v = SVert->SVV; + + if( P->internal_env.Supercede && PM->MaterialName[0] == 'g' ) + { + pTexVerts->u += ( (G->NormalArray[ *List ]).X * P->internal_env.PercentMaterial); + pTexVerts->v += ( (G->NormalArray[ *List ]).Y * P->internal_env.PercentMaterial); + } + } + } + + geVec3d_Subtract(&Verts[2], &Verts[1], &v1); + geVec3d_Subtract(&Verts[0], &Verts[1], &v2); + geVec3d_CrossProduct(&v1, &v2, &v3); + geVec3d_Normalize(&v3); + + Dist = geVec3d_DotProduct(&v3, &Verts[0]); + + Dist = geVec3d_DotProduct(&v3, geCamera_GetPov(Camera)) - Dist; + + if (Dist <= 0) + continue; + + pDest1 = Verts; + pDest2 = Dest2; + pTex1 = TexVerts; + pTex2 = Tex2; + + FPlanes = FInfo->Planes; + + for (p=0; p< FInfo->NumPlanes; p++, FPlanes++) + { + if (!(ClipFlags & (1<NumPlanes) + continue; // Can't possibly be visible + + if (Length1 < 3) + continue; // Can't possibly be visible + + // Transform to world space... + for (v=0; vOverallAlpha ; + #else + ScreenPts[0].a = 255.0f; + #endif + + geEngine_RenderPoly(Engine, (GE_TLVertex*)ScreenPts, Length1, PM->Bitmap, 0 ); + } + } + + #pragma message ("BUG: Shadow caused crash in mirrors (oops). Need to write a RenderShadowThroughFrustum...") + /* + if (P->DoShadow) + { + gePuppet_DrawShadow(P,Engine,World,Camera); + } + */ + return GE_TRUE; +} + +#ifdef PROFILE +#define PUPPET_AVERAGE_ACROSS 60 +double Puppet_AverageCount[PUPPET_AVERAGE_ACROSS]={ + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; +int Puppet_AverageIndex = 0; +#endif + + +geBoolean GENESISCC gePuppet_Render( const gePuppet *P, + const gePose *Joints, + geEngine *Engine, + geWorld *World, + const geCamera *Camera, + geExtBox *TestBox) +{ + const geXFArray *JointTransforms; + geVec3d Scale; + #ifdef PROFILE + rdtsc_timer_type RDTSCStart,RDTSCEnd; + #endif + geRect ClippingRect; + geBoolean Clipping = GE_TRUE; + + char name[128]; + int i, j; + geBoolean flag; + + #define BACK_EDGE (1.0f) + + const geBodyInst_Geometry *G; + assert( P ); + assert( Engine ); + assert( World ); + assert( Camera ); + + #ifdef PROFILE + rdtsc_read(&RDTSCStart); + rdtsc_zero(&RDTSCEnd); + #endif + + flag = GE_FALSE; + j = Engine->DriverInfo.NumSubDrivers; + for(i=0;iDriverInfo.SubDrivers[i].Name); + if(name[0]=='G') + { + flag = GE_TRUE; + break; + } + } + + + geCamera_GetClippingRect(Camera,&ClippingRect); + + if (TestBox != NULL) + { + // see if the test box is visible on the screen. If not: don't draw actor. + // (transform and project it to the screen, then check extents of that projection + // against the clipping rect) + geVec3d BoxCorners[8]; + const geXForm3d *ObjectToCamera; + geVec3d Maxs,Mins; + #define BIG_NUMBER (99e9f) + int i; + geBoolean ZFarEnable; + geFloat ZFar; + + BoxCorners[0] = TestBox->Min; + BoxCorners[1] = BoxCorners[0]; BoxCorners[1].X = TestBox->Max.X; + BoxCorners[2] = BoxCorners[0]; BoxCorners[2].Y = TestBox->Max.Y; + BoxCorners[3] = BoxCorners[0]; BoxCorners[3].Z = TestBox->Max.Z; + BoxCorners[4] = TestBox->Max; + BoxCorners[5] = BoxCorners[4]; BoxCorners[5].X = TestBox->Min.X; + BoxCorners[6] = BoxCorners[4]; BoxCorners[6].Y = TestBox->Min.Y; + BoxCorners[7] = BoxCorners[4]; BoxCorners[7].Z = TestBox->Min.Z; + + ObjectToCamera = geCamera_GetCameraSpaceXForm(Camera); + assert( ObjectToCamera ); + + geVec3d_Set(&Maxs,-BIG_NUMBER,-BIG_NUMBER,-BIG_NUMBER); + geVec3d_Set(&Mins, BIG_NUMBER, BIG_NUMBER, BIG_NUMBER); + for (i=0; i<8; i++) + { + geVec3d V; + geXForm3d_Transform( ObjectToCamera,&(BoxCorners[i]),&(BoxCorners[i])); + geCamera_Project( Camera,&(BoxCorners[i]),&V); + if (V.X > Maxs.X ) Maxs.X = V.X; + if (V.X < Mins.X ) Mins.X = V.X; + if (V.Y > Maxs.Y ) Maxs.Y = V.Y; + if (V.Y < Mins.Y ) Mins.Y = V.Y; + if (V.Z > Maxs.Z ) Maxs.Z = V.Z; + if (V.Z < Mins.Z ) Mins.Z = V.Z; + } + + // Reject against ZFar clipplane if enabled... + geCamera_GetFarClipPlane(Camera, &ZFarEnable, &ZFar); + if (ZFarEnable) + { + if ( (Maxs.X < ClippingRect.Left) + || (Mins.X > ClippingRect.Right) + || (Maxs.Z < BACK_EDGE) //Test X and Z first, and Y + || (Mins.Z > ZFar) + || (Maxs.Y < ClippingRect.Top) + || (Mins.Y > ClippingRect.Bottom)) + { + // not gonna draw: box is not visible. + return GE_TRUE; + } + + } else + { + if ( (Maxs.X < ClippingRect.Left) + || (Mins.X > ClippingRect.Right) + || (Maxs.Y < ClippingRect.Top) + || (Mins.Y > ClippingRect.Bottom) + || (Maxs.Z < BACK_EDGE)) + { + // not gonna draw: box is not visible. + return GE_TRUE; + } + } + + } + + Engine->DebugInfo.NumActors++; + + geTClip_SetupEdges(Engine, + (geFloat)ClippingRect.Left, + (geFloat)ClippingRect.Right, + (geFloat)ClippingRect.Top, + (geFloat)ClippingRect.Bottom, + BACK_EDGE); + + JointTransforms = gePose_GetAllJointTransforms(Joints); + + #pragma message ("Level of detail hacked:") + gePose_GetScale(Joints,&Scale); + G = geBodyInst_GetGeometry(P->BodyInstance, &Scale, JointTransforms, 0,Camera); + + if ( G == NULL ) + { + geErrorLog_Add(ERR_PUPPET_RENDER, NULL); + return GE_FALSE; + } + +#ifdef ONE_OVER_Z_PIPELINE +#define TEST_Z_OUT(zzz, edge) ((zzz) > (edge)) +#define TEST_Z_IN(zzz, edge) ((zzz) < (edge)) +#pragma message ("test this! this is untested") +#else +#define TEST_Z_OUT(zzz, edge) ((zzz) < (edge)) +#define TEST_Z_IN(zzz, edge) ((zzz) > (edge)) +#endif + + + // check for trivial rejection: + { + if ( (G->Maxs.X < ClippingRect.Left) + || (G->Mins.X > ClippingRect.Right) + || ( TEST_Z_OUT( G->Maxs.Z, BACK_EDGE) ) //test Y last + || (G->Maxs.Y < ClippingRect.Top) + || (G->Mins.Y > ClippingRect.Bottom) ) + { + // not gonna draw + return GE_TRUE; + } + + if ( (G->Maxs.X < ClippingRect.Right) + && (G->Mins.X > ClippingRect.Left) + && (G->Maxs.Y < ClippingRect.Bottom) + && (G->Mins.Y > ClippingRect.Top) + && ( TEST_Z_IN( G->Mins.Z, BACK_EDGE) ) ) + { + // not gonna clip + Clipping = GE_FALSE; + } + else + { + Clipping = GE_TRUE; + } + } + + { + GE_LVertex v[3]; + int i,j,Count; + geBodyInst_Index *List; + geBodyInst_Index Command; + geBodyInst_SkinVertex *SV; + geXForm3d RootTransform; + gePuppet_Material *PM; + geBodyInst_Index Material,LastMaterial; + + gePuppet_StaticLightGrp.UseFillLight = P->UseFillLight; + gePuppet_StaticLightGrp.FillLightNormal = P->FillLightNormal; + gePuppet_StaticLightGrp.FillLightColor.Red = P->FillLightColor.Red; + gePuppet_StaticLightGrp.FillLightColor.Green = P->FillLightColor.Green; + gePuppet_StaticLightGrp.FillLightColor.Blue = P->FillLightColor.Blue; + gePuppet_StaticLightGrp.PerBoneLighting = P->PerBoneLighting; + + gePose_GetJointTransform(Joints,P->LightReferenceBoneIndex,&(RootTransform)); + + if (P->MaxDynamicLightsToUse > 0) + { + if (P->PerBoneLighting) + { + int BoneCount; + const geXForm3d *XFA = geXFArray_GetElements(JointTransforms, &BoneCount); + if (BoneCount>0) + { + if (gePuppet_StaticBoneLightArraySize < BoneCount) + { + gePuppet_BoneLight *LG; + + LG = geRam_Realloc(gePuppet_StaticBoneLightArray, sizeof(gePuppet_BoneLight) * BoneCount); + if (LG==NULL) + { + geErrorLog_Add(ERR_PUPPET_RENDER,"Failed to allocate space for bone lighting info cache"); + return GE_FALSE; + } + gePuppet_StaticBoneLightArray = LG; + gePuppet_StaticBoneLightArraySize = BoneCount; + } + for (i=0; iFaceCount; + List = G->FaceList; + #if 1 + v[0].a = v[1].a= v[2].a = P->OverallAlpha ; + #else + v[0].a = v[1].a= v[2].a = 255.0f; + #endif + + LastMaterial = -1; + + for (i=0; i=0 ); + assert( MaterialMaterialCount); + + { + geFloat AX,AY,BXMinusAX,BYMinusAY,CYMinusAY,CXMinusAX; + geBodyInst_Index *List2; + + List2 = List; + SV = &(G->SkinVertexArray[ *List2 ]); + AX = SV->SVPoint.X; + AY = SV->SVPoint.Y; + List2++; + List2++; + + SV = &(G->SkinVertexArray[ *List2 ]); + BXMinusAX = SV->SVPoint.X - AX; + BYMinusAY = SV->SVPoint.Y - AY; + List2++; + List2++; + + SV = &(G->SkinVertexArray[ *List2 ]); + CXMinusAX = SV->SVPoint.X - AX; + CYMinusAY = SV->SVPoint.Y - AY; + List2++; + List2++; + + // ZCROSS is z the component of a 2d vector cross product of ABxAC + //#define ZCROSS(Ax,Ay,Bx,By,Cx,Cy) ((((Bx)-(Ax))*((Cy)-(Ay))) - (((By)-(Ay))*((Cx)-(Ax)))) + + // 2d cross product of AB cross AC (A is vtx[0], B is vtx[1], C is vtx[2] + if ( ((BXMinusAX * CYMinusAY) - (BYMinusAY * CXMinusAX)) > 0.0f ) + { + List = List2; + continue; + } + } + + if ( Material != LastMaterial ) + { + PM = &(P->MaterialArray[Material]); + geTClip_SetTexture(PM->Bitmap); + gePuppet_StaticLightGrp.MaterialColor = PM->Color; + } + + for (j=0; j<3; j++) + { + SV = &(G->SkinVertexArray[ *List ]); + List++; + + v[j].X = SV->SVPoint.X; + v[j].Y = SV->SVPoint.Y; + + v[j].Z = SV->SVPoint.Z; + v[j].u = SV->SVU; + v[j].v = SV->SVV; + +// assert( ((geFloat)fabs(1.0-geVec3d_Length( &(G->NormalArray[ *List ] ))))< 0.001f ); + + gePuppet_StaticLightGrp.SurfaceNormal = (G->NormalArray[ *List ]); + List++; + + gePuppet_SetVertexColor(&(v[j]),SV->ReferenceBoneIndex); + } + + if(flag==GE_FALSE) + Clipping = GE_FALSE; + + if (Clipping) + { + geTClip_Triangle(v); + } + else + { + geEngine_RenderPoly(Engine, (GE_TLVertex *)v, 3, PM->Bitmap, 0 ); + } + + } + assert( ((uint32)List) - ((uint32)G->FaceList) == (uint32)(G->FaceListSize) ); + } + + + if (P->DoShadow) + { + gePuppet_DrawShadow(P,Joints,Engine,World,Camera); + } + + + #ifdef PROFILE + { + double Count=0.0; + int i; + + rdtsc_read(&RDTSCEnd); + rdtsc_delta(&RDTSCStart,&RDTSCEnd,&RDTSCEnd); + geEngine_Printf(Engine, 320,10,"Puppet Render Time=%f",(double)(rdtsc_cycles(&RDTSCEnd)/200000000.0)); + geEngine_Printf(Engine, 320,30,"Puppet Render Cycles=%f",(double)(rdtsc_cycles(&RDTSCEnd))); + #if 1 + Puppet_AverageCount[(Puppet_AverageIndex++)%PUPPET_AVERAGE_ACROSS] = rdtsc_cycles(&RDTSCEnd); + for (i=0; iShadowMap ) + geBitmap_Destroy((geBitmap **)&(P->ShadowMap)); + + P->DoShadow = DoShadow; + P->ShadowScale = Scale; + P->ShadowMap = ShadowMap; + P->ShadowBoneIndex = BoneIndex; + + if ( P->ShadowMap ) + geBitmap_CreateRef((geBitmap *)P->ShadowMap); +} + diff --git a/G3D/Actor/puppet.h b/G3D/Actor/puppet.h new file mode 100644 index 0000000..37531ef --- /dev/null +++ b/G3D/Actor/puppet.h @@ -0,0 +1,118 @@ +/****************************************************************************************/ +/* PUPPET.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Puppet interface. . */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_PUPPET_H +#define GE_PUPPET_H + +#include "Motion.h" +#include "Camera.h" +#include "Body.h" +#include "Pose.h" +#include "ExtBox.h" // geExtBox for gePuppet_RenderThroughFrustum + +#include "Frustum.h" +#include "vfile.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct gePuppet gePuppet; + +gePuppet *GENESISCC gePuppet_Create(geVFile *TextureFS, const geBody *B, geWorld *World); + +void GENESISCC gePuppet_Destroy(gePuppet **P); + +geBoolean GENESISCC gePuppet_RenderThroughFrustum(const gePuppet *P, + const gePose *Joints, + const geExtBox *Box, + geEngine *Engine, + geWorld *World, + const geCamera *Camera, + Frustum_Info *FInfo); + +geBoolean GENESISCC gePuppet_Render(const gePuppet *P, + const gePose *Joints, + geEngine *Engine, + geWorld *World, + const geCamera *Camera, + geExtBox *Box); + +int GENESISCC gePuppet_GetMaterialCount( gePuppet *P ); +geBoolean GENESISCC gePuppet_GetMaterial( gePuppet *P, int MaterialIndex, + geBitmap **Bitmap, + geFloat *Red, geFloat *Green, geFloat *Blue); +geBoolean GENESISCC gePuppet_SetMaterial(gePuppet *P, int MaterialIndex, geBitmap *Bitmap, + geFloat Red, geFloat Green, geFloat Blue); + +void GENESISCC gePuppet_SetShadow(gePuppet *P, geBoolean DoShadow, geFloat Scale, + const geBitmap *ShadowMap,int BoneIndex); + +// LWM_ACTOR_RENDERING +geFloat GENESISCC gePuppet_GetAlpha( const gePuppet *P ) ; +// LWM_ACTOR_RENDERING +void GENESISCC gePuppet_SetAlpha( gePuppet *P, geFloat Alpha ) ; +//Environment mapping code... +void GENESISCC gePuppet_SetEnvironmentOptions( gePuppet *P, geEnvironmentOptions *envop ); + +geEnvironmentOptions GENESISCC gePuppet_GetEnvironmentOptions( gePuppet *P ); + +void GENESISCC gePuppet_GetStaticLightingOptions(const gePuppet *P, geBoolean *AmbientLightFromStaticLights, geBoolean *TestRayCollision, int *MaxStaticLightsToUse ); +void GENESISCC gePuppet_SetStaticLightingOptions(gePuppet *P, geBoolean AmbientLightFromStaticLights, geBoolean TestRayCollision, int MaxStaticLightsToUse ); + +void GENESISCC gePuppet_GetLightingOptions(const gePuppet *P, + geBoolean *UseFillLight, + geVec3d *FillLightNormal, + geFloat *FillLightRed, + geFloat *FillLightGreen, + geFloat *FillLightBlue, + geFloat *AmbientLightRed, + geFloat *AmbientLightGreen, + geFloat *AmbientLightBlue, + geBoolean *UseAmbientLightFromFloor, + int *MaximumDynamicLightsToUse, + int *LightReferenceBoneIndex, + geBoolean *PerBoneLighting + ); + +void GENESISCC gePuppet_SetLightingOptions(gePuppet *P, + geBoolean UseFillLight, + const geVec3d *FillLightNormal, + geFloat FillLightRed, // 0 .. 255 + geFloat FillLightGreen, // 0 .. 255 + geFloat FillLightBlue, // 0 .. 255 + geFloat AmbientLightRed, // 0 .. 255 + geFloat AmbientLightGreen, // 0 .. 255 + geFloat AmbientLightBlue, // 0 .. 255 + geBoolean AmbientLightFromFloor, + int MaximumDynamicLightsToUse, // 0 for none + int LightReferenceBoneIndex, + int PerBoneLighting); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/G3D/Actor/strblock.c b/G3D/Actor/strblock.c new file mode 100644 index 0000000..392b90e --- /dev/null +++ b/G3D/Actor/strblock.c @@ -0,0 +1,622 @@ +/****************************************************************************************/ +/* STRBLOCK.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: String block implementation. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +// strblock.c +// a list of strings implemented as a single block of memory for fast +// loading. The 'Data' Field is interpreted as an array of integer +// offsets relative to the beginning of the data field. After the int list +// is the packed string data. Since no additional allocations are needed +// this object can be file loaded as one block. +#include +#include +#include + +#include "strblock.h" +#include "ram.h" +#include "errorlog.h" + +#define STRBLOCK_MAX_STRINGLEN 255 + +typedef struct geStrBlock +{ + int Count; + geStrBlock *SanityCheck; + union + { + int IntArray[1]; // char offset into CharArray for string[n] + char CharArray[1]; + } Data; + +} geStrBlock; + + +int GENESISCC geStrBlock_GetChecksum(const geStrBlock *SB) +{ + int Count; + int Len; + int i,j; + const char *Str; + int Checksum=0; + assert( SB != NULL ); + + Count = geStrBlock_GetCount(SB); + for (i=0; iCount=0; + SB->SanityCheck = SB; + return SB; +} + + +void GENESISCC geStrBlock_Destroy(geStrBlock **SB) +{ + assert( (*SB)->SanityCheck == (*SB) ); + assert( SB != NULL ); + assert( *SB != NULL ); + geRam_Free( *SB ); + *SB = NULL; +} + + +static int GENESISCC geStrBlock_BlockSize(const geStrBlock *B) +{ + int Offset; + const char *LastStr; + assert( B != NULL ); + assert( B->SanityCheck == B ); + + if ( B->Count == 0 ) + return 0; + Offset = B->Data.IntArray[B->Count-1]; + LastStr = &(B->Data.CharArray[Offset]); + + return strlen(LastStr) + 1 + Offset; +} + + +void GENESISCC geStrBlock_Delete(geStrBlock **ppSB,int Nth) +{ + int BlockSize; + int StringLen; + int CloseSize; + const char *String; + assert( ppSB != NULL ); + assert( *ppSB != NULL ); + assert( Nth >=0 ); + assert( Nth < (*ppSB)->Count ); + assert( (*ppSB)->SanityCheck == (*ppSB) ); + + String = geStrBlock_GetString(*ppSB,Nth); + assert( String != NULL ); + StringLen = strlen(String) + 1; + + BlockSize = geStrBlock_BlockSize(*ppSB); + + { + geStrBlock *B = *ppSB; + char *ToBeReplaced; + char *Replacement=NULL; + int i; + ToBeReplaced = &((*ppSB)->Data.CharArray[(*ppSB)->Data.IntArray[Nth]]); + if (Nth< (*ppSB)->Count-1) + Replacement = &((*ppSB)->Data.CharArray[(*ppSB)->Data.IntArray[Nth+1]]); + for (i=Nth+1,CloseSize = 0; i<(*ppSB)->Count ; i++) + { + CloseSize += strlen(&((*ppSB)->Data.CharArray[(*ppSB)->Data.IntArray[i]])) +1; + B->Data.IntArray[i] -= StringLen; + } + for (i=0; i<(*ppSB)->Count ; i++) + { + B->Data.IntArray[i] -= sizeof(int); + } + // crunch out Nth string + if (Nth< (*ppSB)->Count-1) + memmove(ToBeReplaced,Replacement,CloseSize); + // crunch out Nth index + memmove(&(B->Data.IntArray[Nth]), + &(B->Data.IntArray[Nth+1]), + BlockSize - ( sizeof(int) * (Nth+1) ) ); + + } + + { + geStrBlock * NewgeStrBlock; + + NewgeStrBlock = geRam_Realloc( *ppSB, + BlockSize // size of data block + + sizeof(geStrBlock) // size of strblock structure + - StringLen // size of dying string + - sizeof(int) ); // size of new index to string + if ( NewgeStrBlock != NULL ) + { + *ppSB = NewgeStrBlock; + (*ppSB)->SanityCheck = NewgeStrBlock; + } + } + + (*ppSB)->Count--; +} + + +#if 0 + // as of yet un needed. and this is untested +geBoolean GENESISCC geStrBlock_SetString(geStrBlock **ppSB, int Index, const char *String) +{ + assert( ppSB != NULL ); + assert( *ppSB != NULL ); + assert( Index >=0 ); + assert( Index < (*ppSB)->Count ); + assert( String != NULL ); + + if (geStrBlock_Insert(ppSB,Index,String) == GE_FALSE) + { + geErrorLog_Add(ERR_STRBLOCK_ENOMEM, NULL); + return GE_FALSE; + } + + geStrBlock_Delete(ppSB,Index); + return GE_TRUE; +} +#endif + +#if 0 + // as of yet un needed. and this is untested +geBoolean GENESISCC geStrBlock_Insert(geStrBlock **ppSB,int InsertAfterIndex,const char *String) +{ + int BlockSize; + int StringLen; + int MoveSize; + + assert( ppSB != NULL ); + assert( *ppSB != NULL ); + assert( InsertAfterIndex >=-1); + assert( InsertAfterIndex < (*ppSB)->Count ); + assert( (*ppSB)->SanityCheck == (*ppSB) ); + assert( String != NULL ); + + if (InsertAfterIndex == (*ppSB)->Count - 1) + { + if (geStrBlock_Append(ppSB,String)==GE_FALSE) + { + geErrorLog_Add(-1, NULL); + return GE_FALSE; + } + return GE_TRUE; + } + + StringLen = strlen(String) + 1; + + BlockSize = geStrBlock_BlockSize(*ppSB); + + { + geStrBlock * NewgeStrBlock; + + NewgeStrBlock = geRam_Realloc( *ppSB, + BlockSize // size of data block + + sizeof(geStrBlock) // size of strblock structure + + StringLen // size of new string + + sizeof(int) ); // size of new index to string + if ( NewgeStrBlock != NULL ) + { + *ppSB = NewgeStrBlock; + (*ppSB)->SanityCheck = NewgeStrBlock; + } + } + + + + { + geStrBlock *B = *ppSB; + char *Chars = B->Data.CharArray; + int *Table = B->Data.IntArray; + char *MoveFrom; + char *MoveTo=NULL; + int i; + + MoveFrom = &(Chars[Table[InsertAfterIndex+1]]); + + MoveTo = MoveFrom + StringLen; + + for (i=InsertAfterIndex+1,MoveSize = 0; iCount ; i++) + { + MoveSize += strlen(&(Chars[Table[i]])) +1; + Table[i] += StringLen; + } + for (i=0; i<(*ppSB)->Count ; i++) + { + Table[i] += sizeof(int); + } + // make room for string + memmove(MoveFrom,MoveTo,MoveSize); + // make room for new index + memmove(&(Table[InsertAfterIndex+1]), + &(Table[InsertAfterIndex+2]), + BlockSize - ( sizeof(int) * (InsertAfterIndex+2) ) ); + Table[InsertAfterIndex+1] = Table[InsertAfterIndex] + + strlen(&(Chars[Table[InsertAfterIndex]])) +1; + + } + + + (*ppSB)->Count++; + return GE_TRUE; + + +} +#endif + +geBoolean GENESISCC geStrBlock_FindString(const geStrBlock* pSB, const char* String, int* pIndex) +{ + int i; + int Count; + const char *Str; + + assert(pSB != NULL); + assert(String != NULL); + assert(pIndex != NULL); + assert( pSB->SanityCheck == pSB ); + + Count = geStrBlock_GetCount(pSB); + for (i=0; iSanityCheck == (*ppSB) ); + + if (strlen(String)>=STRBLOCK_MAX_STRINGLEN) + { + geErrorLog_Add(ERR_STRBLOCK_STRLEN, NULL); + return GE_FALSE; + } + + BlockSize = geStrBlock_BlockSize(*ppSB); + + { + geStrBlock * NewgeStrBlock; + + NewgeStrBlock = geRam_Realloc( *ppSB, + BlockSize // size of data block + + sizeof(geStrBlock) // size of strblock structure + + strlen(String) + 1 // size of new string + + sizeof(int) ); // size of new index to string + if ( NewgeStrBlock == NULL ) + { + geErrorLog_Add(ERR_STRBLOCK_ENOMEM, NULL); + return GE_FALSE; + } + *ppSB = NewgeStrBlock; + (*ppSB)->SanityCheck = NewgeStrBlock; + } + + { + geStrBlock *B = *ppSB; + int i; + for (i=0; iCount; i++) + { + B->Data.IntArray[i] += sizeof(int); + } + if (B->Count > 0) + { + memmove(&(B->Data.IntArray[B->Count+1]), + &(B->Data.IntArray[B->Count]), + BlockSize - sizeof(int) * B->Count); + } + B->Data.IntArray[B->Count] = BlockSize + sizeof(int); + strcpy(&(B->Data.CharArray[B->Data.IntArray[B->Count]]),String); + } + (*ppSB)->Count++; + return GE_TRUE; +} + + +const char *GENESISCC geStrBlock_GetString(const geStrBlock *SB, int Index) +{ + assert( SB != NULL ); + assert( Index >= 0 ); + assert( Index < SB->Count ); + assert( SB->SanityCheck == SB ); + return &(SB->Data.CharArray[SB->Data.IntArray[Index]]); +} + +int GENESISCC geStrBlock_GetCount(const geStrBlock *SB) +{ + assert( SB != NULL); + assert( SB->SanityCheck == SB ); + return SB->Count; +} + + +#define CHECK_FOR_WRITE(uu) if(uu <= 0) { geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE, NULL ); return GE_FALSE; } + +#define STRBLOCK_ASCII_FILE_TYPE 0x4B4C4253 // 'SBLK' +#define STRBLOCK_BIN_FILE_TYPE 0x424B4253 // 'SBKB' +#define STRBLOCK_FILE_VERSION 0x00F0 // Restrict version to 16 bits + +#define STRBLOCK_STRINGARRAY_ID "Strings" +#define STRBLOCK_NUM_ASCII_IDS 1 // Keep this up to date + +static geStrBlock *GENESISCC geStrBlock_CreateFromBinaryFile(geVFile *pFile); + +geStrBlock* GENESISCC geStrBlock_CreateFromFile(geVFile* pFile) +{ + uint32 u, v; + geStrBlock* SB; + char VersionString[32]; + + assert( pFile != NULL ); + + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL); + return NULL; + } + + if(u == STRBLOCK_ASCII_FILE_TYPE) + { + int NumItemsNeeded=0; + int NumItemsRead = 0; + char line[STRBLOCK_MAX_STRINGLEN]; + + SB = geStrBlock_Create(); + if( SB == NULL ) + { + geErrorLog_Add(ERR_STRBLOCK_ENOMEM, NULL); + return NULL; + } + + // Read and build the version. Then determine the number of items to read. + if (geVFile_GetS(pFile, VersionString, sizeof(VersionString)) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL); + return NULL; + } + if (sscanf(VersionString, "%X.%X\n", &u, &v) != 2) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL); + return NULL; + } + v |= (u << 8); + if(v >= STRBLOCK_FILE_VERSION) + { + NumItemsNeeded = STRBLOCK_NUM_ASCII_IDS; + } + + while(NumItemsRead < NumItemsNeeded) + { + if(geVFile_GetS(pFile, line, STRBLOCK_MAX_STRINGLEN) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL); + break; // got to read something + } + else if(strnicmp(line, STRBLOCK_STRINGARRAY_ID, sizeof(STRBLOCK_STRINGARRAY_ID)-1) == 0) + { + int i,Count; + if(sscanf(line + sizeof(STRBLOCK_STRINGARRAY_ID)-1, "%d", &Count) != 1) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL); + break; + } + for (i=0; iSanityCheck == SB ); + + + // Write the format flag + u = STRBLOCK_ASCII_FILE_TYPE; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL); + return GE_FALSE; + } + + // Write the version + if (geVFile_Printf(pFile, " %X.%.2X\n", (STRBLOCK_FILE_VERSION & 0xFF00) >> 8, + STRBLOCK_FILE_VERSION & 0x00FF) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL); + return GE_FALSE; + } + + count = geStrBlock_GetCount(SB); + if (geVFile_Printf(pFile, "%s %d\n", STRBLOCK_STRINGARRAY_ID,count) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL); + return GE_FALSE; + } + for (i=0; iSanityCheck = SB; + SB->Count = Header.Count; + + if (geVFile_Read(pFile, &(SB->Data),Header.Size) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL); + return NULL; + } + return SB; +} + + +geBoolean GENESISCC geStrBlock_WriteToBinaryFile(const geStrBlock *SB,geVFile *pFile) +{ + uint32 u; + geStrBlock_BinaryFileHeader Header; + + assert( SB != NULL ); + assert( pFile != NULL ); + assert( SB->SanityCheck == SB ); + + // Write the format flag + u = STRBLOCK_BIN_FILE_TYPE; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL); + return GE_FALSE; + } + + Header.Size = geStrBlock_BlockSize(SB); + Header.Count = SB->Count; + + if(geVFile_Write(pFile, &Header, sizeof(geStrBlock_BinaryFileHeader)) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL); + return GE_FALSE; + } + + if (geVFile_Write(pFile, &(SB->Data),Header.Size) == GE_FALSE) + { + geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL); + return GE_FALSE; + } + + return GE_TRUE; +} diff --git a/G3D/Actor/strblock.h b/G3D/Actor/strblock.h new file mode 100644 index 0000000..50c02bd --- /dev/null +++ b/G3D/Actor/strblock.h @@ -0,0 +1,61 @@ +/****************************************************************************************/ +/* STRBLOCK.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: String block interface. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +// geStrBlock +#ifndef GE_STRBLOCK_H +#define GE_STRBLOCK_H + +#include "basetype.h" // geBoolean +#include "vfile.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct geStrBlock geStrBlock; + +geStrBlock *GENESISCC geStrBlock_Create(void); +void GENESISCC geStrBlock_Destroy(geStrBlock **SB); + +geBoolean GENESISCC geStrBlock_Append(geStrBlock **ppSB,const char *String); + +void GENESISCC geStrBlock_Delete(geStrBlock **ppSB,int Nth); + +const char *GENESISCC geStrBlock_GetString(const geStrBlock *SB, int Index); + +// untested... +//geBoolean GENESISCC geStrBlock_SetString(geStrBlock **ppSB, int Index, const char *String); +//geBoolean GENESISCC geStrBlock_Insert(geStrBlock **ppSB,int InsertAfterIndex,const char *String); + +geBoolean GENESISCC geStrBlock_FindString(const geStrBlock* pSB, const char* String, int* pIndex); + +int GENESISCC geStrBlock_GetCount(const geStrBlock *SB); +int GENESISCC geStrBlock_GetChecksum(const geStrBlock *SB); + +geStrBlock* GENESISCC geStrBlock_CreateFromFile(geVFile* pFile); +geBoolean GENESISCC geStrBlock_WriteToFile(const geStrBlock *SB, geVFile *pFile); +geBoolean GENESISCC geStrBlock_WriteToBinaryFile(const geStrBlock *SB,geVFile *pFile); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Actor/tkarray.c b/G3D/Actor/tkarray.c new file mode 100644 index 0000000..4c4cd7a --- /dev/null +++ b/G3D/Actor/tkarray.c @@ -0,0 +1,411 @@ +/****************************************************************************************/ +/* TKARRAY.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Time-keyed array implementation. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +/*TKArray + (Time-Keyed-Array) + This module is designed primarily to support path.c + + The idea is that there are these packed arrays of elements, + sorted by a geTKArray_TimeType key. The key is assumed to be the + first field in each element. + + the geTKArray functions operate on this very specific array type. + + Error conditions are reported to errorlog +*/ +#include +#include +#include + +#include "TKArray.h" +#include "ErrorLog.h" +#include "ram.h" + +typedef struct geTKArray +{ + int32 NumElements; // number of elements in use + int32 ElementSize; // size of each element + char Elements[1]; // array elements. This list will be expanded by changing + // the allocated size of the entire geTKArray object +} geTKArray; + +typedef struct +{ + int32 NumElements; // number of elements in use + int32 ElementSize; // size of each element +} geTKArray_BinaryFileHeader; + + +#define TK_MAX_ARRAY_LENGTH (0x7FFFFFFF) // NumElements is (signed) 32 bit int + + +#define TK_ARRAYSIZE (offsetof(geTKArray, Elements)) // gets rid of the extra element char in the def. + +// General validity test. +// Use TK_ASSERT_VALID to test array for reasonable data. +#ifdef _DEBUG + +#define TK_ASSERT_VALID(A) geTKArray_Asserts(A) + +// Do not call this function directly. Use TK_ASSERT_VALID +static void GENESISCC geTKArray_Asserts(const geTKArray* A) +{ + assert( (A) != NULL ); + assert( ((A)->NumElements == 0) || + (((A)->NumElements > 0) && ((A)->Elements != NULL)) ); + assert( (A)->NumElements >= 0 ); + assert( (A)->NumElements <= TK_MAX_ARRAY_LENGTH ); + assert( (A)->ElementSize > 0 ); +} + +#else // !_DEBUG + +#define TK_ASSERT_VALID(A) ((void)0) + +#endif // _DEBUG + + +geTKArray *GENESISCC geTKArray_Create( + int ElementSize) // element size + // Creates new array with given attributes. The first field of the element + // is assumed to be the geTKArray_TimeType key. +{ + geTKArray *A; + + // first item in each element must be the time key + assert( ElementSize >= sizeof(geTKArray_TimeType) ); + + A = geRam_Allocate(TK_ARRAYSIZE); + if ( A == NULL) + { + geErrorLog_Add(ERR_TKARRAY_CREATE, NULL); + return NULL; + } + + A->ElementSize = ElementSize; + A->NumElements = 0; + + TK_ASSERT_VALID(A); + + return A; +} + +geTKArray *GENESISCC geTKArray_CreateEmpty( + int ElementSize,int ElementCount) // element size + // Creates new array with given size and count. The first field of the element + // is assumed to be the geTKArray_TimeType key. +{ + geTKArray *A; + int32 size = TK_ARRAYSIZE + ElementCount * ElementSize; + A = (geTKArray*)geRam_Allocate(size); + if( A == NULL ) + { + geErrorLog_AddString(-1,"Failure to allocate empty TKArray", NULL); + return NULL; + } + A->ElementSize = ElementSize; + A->NumElements = ElementCount; + + TK_ASSERT_VALID(A); + + return A; +} + +geTKArray* GENESISCC geTKArray_CreateFromBinaryFile( + geVFile* pFile) // stream positioned at array data + // Creates a new array from the given stream. +{ + int32 size; + geTKArray* A; + geTKArray_BinaryFileHeader Header; + + if (geVFile_Read(pFile, &Header, sizeof(geTKArray_BinaryFileHeader)) == GE_FALSE) + { + geErrorLog_AddString(-1,"Failure to binary read TKArray header", NULL); + return NULL; + } + + size = TK_ARRAYSIZE + Header.NumElements * Header.ElementSize; + A = (geTKArray*)geRam_Allocate(size); + if( A == NULL ) + { + geErrorLog_AddString(-1,"Failure to allocate TKArray during binary read", NULL); + return NULL; + } + + + if(geVFile_Read(pFile, A->Elements, size - sizeof(geTKArray_BinaryFileHeader)) == GE_FALSE) + { + geRam_Free(A); + geErrorLog_AddString(-1,"Failure to binary read TKArray body", NULL); + return NULL; + } + + A->NumElements = Header.NumElements; + A->ElementSize = Header.ElementSize; + + return A; +} + + +geBoolean GENESISCC geTKArray_SamplesAreTimeLinear(const geTKArray *Array,geFloat Tolerance) +{ + int i; + + geTKArray_TimeType Delta,Nth,LastNth,NthDelta; + + if (Array->NumElements < 2) + return GE_TRUE; + + LastNth = geTKArray_ElementTime(Array, 0); + Nth = geTKArray_ElementTime(Array, 1); + Delta = Nth - LastNth; + LastNth = Nth; + + for (i=2; i< Array->NumElements; i++) + { + Nth = geTKArray_ElementTime(Array, i); + NthDelta = (Nth-LastNth)-Delta; + if (NthDelta<0.0f) NthDelta = -NthDelta; + if (NthDelta>Tolerance) + { + return GE_FALSE; + } + LastNth = Nth; + } + return GE_TRUE; +} + +geBoolean GENESISCC geTKArray_WriteToBinaryFile( + const geTKArray* Array, // sorted array to write + geVFile* pFile) // stream positioned for writing + // Writes the array to the given stream. +{ + int size; + + size = TK_ARRAYSIZE + Array->NumElements * Array->ElementSize; + if(geVFile_Write(pFile, Array, size) == GE_FALSE) + { + geErrorLog_AddString(-1,"Failure to write binary TKArray data", NULL); + return GE_FALSE; + } + return GE_TRUE; +} + +void GENESISCC geTKArray_Destroy(geTKArray **PA) + // destroys array +{ + assert( PA != NULL ); + TK_ASSERT_VALID(*PA); + + geRam_Free(*PA); + *PA = NULL; +} + + +int GENESISCC geTKArray_BSearch( + const geTKArray *A, // sorted array to search + geTKArray_TimeType Key) // searching for this key + // Searches for key in the Array. A is assumed to be sorted + // if key is found (within +-tolarance), the index to that element is returned. + // if key is not found, the index to the key just smaller than the + // given key is returned. (-1 if the key is smaller than the first element) +{ + int low,hi,mid; + int ElementSize; + const char *Array; + geTKArray_TimeType test; + + TK_ASSERT_VALID(A); + + low = 0; + hi = A->NumElements - 1; + Array = A->Elements; + ElementSize = A->ElementSize; + + while ( low<=hi ) + { + mid = (low+hi)/2; + test = *(geTKArray_TimeType *)(Array + mid*ElementSize); + if ( Key > test ) + { + low = mid+1; + } + else + { + if ( Key < test ) + { + hi = mid-1; + } + else + { + return mid; + } + } + } + return hi; +} + + +geBoolean GENESISCC geTKArray_Insert( + geTKArray **PtrA, // sorted array to insert into + geTKArray_TimeType Key, // key to insert + int *Index) // new element index + // inserts a new element into Array. + // sets only the key for the new element - the rest is junk + // returns GE_TRUE if the insertion was successful. + // returns GE_FALSE if the insertion failed. + // if Array is empty (no elements, NULL pointer) it is allocated and filled + // with the one Key element + // Index is the index of the new element +{ + int n; + geTKArray *ChangedA; + geTKArray *A; + geTKArray_TimeType Found; + + assert( PtrA ); + A = *PtrA; + TK_ASSERT_VALID(A); + + n = geTKArray_BSearch(A,Key); + // n is the element just prior to the location of the new element + + if(Index) + *Index = n+1; + + if (n >= 0) + { + Found = *(geTKArray_TimeType *)(A->Elements + (n * (A->ElementSize)) ); + // Found <= Key (within +-GE_TKA_TIME_TOLERANCE) + if (Found > Key - GE_TKA_TIME_TOLERANCE) + { // if Found==Key, bail. Can't have two identical keys. + geErrorLog_Add(ERR_TKARRAY_INSERT_IDENTICAL, NULL); + return GE_FALSE; + } + } + + if (A->NumElements >= TK_MAX_ARRAY_LENGTH) + { + geErrorLog_Add(ERR_TKARRAY_TOO_BIG, NULL); + return GE_FALSE; + } + + ChangedA = (geTKArray *)geRam_Realloc(A, + TK_ARRAYSIZE + (A->NumElements + 1) * A->ElementSize); + + if ( ChangedA == NULL ) + { + geErrorLog_Add(ERR_TKARRAY_INSERT_ENOMEM, NULL); + return GE_FALSE; + } + A = ChangedA; + + // advance n to new element's position + n++; + + // move elements as necessary + if(n < A->NumElements) + { + memmove( A->Elements + (n + 1) * A->ElementSize, // dest + A->Elements + n * A->ElementSize, // src + (A->NumElements - n) * A->ElementSize); // count + } + + *(geTKArray_TimeType *)((A->Elements) + ((n) * (A->ElementSize)) ) = Key; + A->NumElements++; + *PtrA = A; + + return GE_TRUE; +} + + +geBoolean GENESISCC geTKArray_DeleteElement( + geTKArray **PtrA, // sorted array to delete from + int N) // element to delete + // deletes an element from Array. + // returns GE_TRUE if the deletion was successful. + // returns GE_FALSE if the deletion failed. (key not found or realloc failed) +{ + geTKArray *A; + geTKArray *ChangedA; + + assert( PtrA != NULL); + A = *PtrA; + TK_ASSERT_VALID(A); + assert(N >= 0); + assert(N < A->NumElements); + + memmove( (A->Elements) + (N) * (A->ElementSize), //dest + (A->Elements) + (N+1) * (A->ElementSize), //src + ((A->NumElements) - (N+1))* (A->ElementSize) ); + + A->NumElements--; + ChangedA = (geTKArray *)geRam_Realloc(A, + TK_ARRAYSIZE + A->NumElements * A->ElementSize); + if ( ChangedA != NULL ) + { + // if realloc fails to shrink block. no real error. + A = ChangedA; + } + + *PtrA = A; + + return GE_TRUE; +} + + +void *GENESISCC geTKArray_Element(const geTKArray *A, int N) + // returns the Nth element +{ + TK_ASSERT_VALID(A); + assert(N >= 0); + assert(N < A->NumElements); + + return (void *)( (A->Elements) + (N * (A->ElementSize)) ); +} + + +geTKArray_TimeType GENESISCC geTKArray_ElementTime(const geTKArray *A, int N) + // returns the time key for the Nth element +{ + TK_ASSERT_VALID(A); + assert(N >= 0); + assert(N < A->NumElements); + + return *(geTKArray_TimeType *)((A->Elements) + (N * (A->ElementSize)) ); +} + + +int GENESISCC geTKArray_NumElements(const geTKArray *A) + // returns the number of elements in the array +{ + TK_ASSERT_VALID(A); + return A->NumElements; +} + + +int GENESISCC geTKArray_ElementSize(const geTKArray *A) + // returns the size of each element in the array +{ + TK_ASSERT_VALID(A); + return A->ElementSize; +} diff --git a/G3D/Actor/tkarray.h b/G3D/Actor/tkarray.h new file mode 100644 index 0000000..7155441 --- /dev/null +++ b/G3D/Actor/tkarray.h @@ -0,0 +1,126 @@ +/****************************************************************************************/ +/* TKARRAY.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Time-keyed array interface. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_TKARRAY_H +#define GE_TKARRAY_H +/* TKArray + (Time-Keyed-Array) + This module is designed primarily to support path.c + + The idea is that there are these packed arrays of elements, + sorted by a geTKArray_TimeType key. The key is assumed to be the + first field in each element. + + the TKArray functions operate on this very specific array type. + + Error conditions are reported to errorlog +*/ + +#include "basetype.h" +#include "vfile.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef geFloat geTKArray_TimeType; + +#define GE_TKA_TIME_TOLERANCE (0.00001f) + +typedef struct geTKArray geTKArray; + +geTKArray *GENESISCC geTKArray_Create(int ElementSize); + // creates new array with given attributes + +geTKArray *GENESISCC geTKArray_CreateEmpty(int ElementSize,int ElementCount); + // creates new array with given element size and given count of uninitialized members + +geTKArray* GENESISCC geTKArray_CreateFromBinaryFile( + geVFile* pFile); // stream positioned at array data + // Creates a new array from the given stream. + +geBoolean GENESISCC geTKArray_WriteToBinaryFile( + const geTKArray* Array, // sorted array to write + geVFile* pFile); // stream positioned for writing + // Writes the array to the given stream. + + +int GENESISCC geTKArray_BSearch( + const geTKArray *Array, // sorted array to search + geTKArray_TimeType Key); // searching for this time + // Searches for key in the Array. (assumes array is sorted) + // if key is found (within +-tolerance), the index to that element is returned. + // if key is not found, the index to the key just smaller than the + // given key is returned. (-1 if the key is smaller than the first element) + // search is only accurate to 2*TKA_TIME_TOLERANCE. + // if multiple keys exist within 2*TKA_TIME_TOLERANCE, this will find an arbitrary one of them. + +geBoolean GENESISCC geTKArray_Insert( + geTKArray **Array, + geTKArray_TimeType Key, // time to insert + int *Index); // new element index + // inserts a new element into Array. + // sets only the key for the new element - the rest is junk + // returns TRUE if the insertion was successful. + // returns FALSE if the insertion failed. + // if Array is empty (no elements, NULL pointer) it is allocated and filled + // with the one Key element + // Index is the index of the new element + +geBoolean GENESISCC geTKArray_DeleteElement( + geTKArray **Array, + int N); // element to delete + // deletes an element from Array. + // returns TRUE if the deletion was successful. + // returns FALSE if the deletion failed. (key not found or realloc failed) + +void GENESISCC geTKArray_Destroy( + geTKArray **Array); + // destroys array + +void *GENESISCC geTKArray_Element( + const geTKArray *Array, + int N); + // returns a pointer to the Nth element of the array. + +int GENESISCC geTKArray_NumElements( + const geTKArray *Array); + // returns the number of elements in the array + +geTKArray_TimeType GENESISCC geTKArray_ElementTime( + const geTKArray *Array, + int N); + // returns the Time associated with the Nth element of the array + +int GENESISCC geTKArray_ElementSize( + const geTKArray *A); + // returns the size of each element in the array + +geBoolean GENESISCC geTKArray_SamplesAreTimeLinear(const geTKArray *Array,geFloat Tolerance); + // returns true if the samples are linear in time within a tolerance + +#ifdef __cplusplus +} +#endif + + + +#endif diff --git a/G3D/Actor/tkevents.c b/G3D/Actor/tkevents.c new file mode 100644 index 0000000..04d1a1a --- /dev/null +++ b/G3D/Actor/tkevents.c @@ -0,0 +1,688 @@ +/****************************************************************************************/ +/* TKARRAY.C */ +/* */ +/* Author: Stephen Balkum */ +/* Description: Time-keyed events implementation. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +/* geTKEvents + (Time-Keyed-Events) + + geTKEvents is a sorted array of times with an identifying descriptor. + The descriptors are stored as strings in a separate, packed buffer. + + Error conditions are reported to errorlog +*/ +#include +#include + +#include "TKEvents.h" +#include "TKArray.h" +#include "ErrorLog.h" +#include "ram.h" +#include "string.h" + +typedef struct +{ + geTKEvents_TimeType EventTime; + uint32 DataOffset; +} EventType; + +typedef struct geTKEventsIterator +{ + geTKEvents_TimeType EndTime; + int CurrentIndex; +} geTKEventsIterator; + +typedef struct geTKEvents +{ + geTKArray* pTimeKeys; + uint32 DataSize; + char* pEventData; + + geTKEventsIterator Iterator; +} geTKEvents; + + + +// General validity test. +// Use TKE_ASSERT_VALID to test array for reasonable data. +#ifdef _DEBUG + +#define TKE_ASSERT_VALID(E) geTKEvents_Asserts(E) + +// Do not call this function directly. Use TKE_ASSERT_VALID +static void GENESISCC geTKEvents_Asserts(const geTKEvents* E) +{ + assert( (E) != NULL ); + assert( (E)->pTimeKeys != NULL ); + if(geTKArray_NumElements((E)->pTimeKeys) == 0) + { + assert( (E)->pEventData == NULL ); + } + else + { + assert( (E)->pEventData != NULL ); + } +} + +#else // !_DEBUG + +#define TKE_ASSERT_VALID(E) ((void)0) + +#endif // _DEBUG + +geTKEvents* GENESISCC geTKEvents_Create(void) + // Creates a new event array. +{ + geTKEvents* pEvents; + + pEvents = GE_RAM_ALLOCATE_STRUCT(geTKEvents); + if(!pEvents) + { + geErrorLog_Add(ERR_TKEVENTS_CREATE_ENOMEM, NULL); + return NULL; + } + + pEvents->pTimeKeys = geTKArray_Create(sizeof(EventType)); + if(!pEvents->pTimeKeys) + { + geErrorLog_Add(ERR_TKEVENTS_CREATE_ENOMEM, NULL); + geRam_Free(pEvents); + return NULL; + } + + pEvents->DataSize = 0; + pEvents->pEventData = NULL; + + pEvents->Iterator.CurrentIndex = 0; + pEvents->Iterator.EndTime = -99e33f; // you could sample here I suppose... + + return pEvents; +} + + +void GENESISCC geTKEvents_Destroy(geTKEvents** ppEvents) + // Destroys array. +{ + geTKEvents* pE; + + assert(ppEvents); + pE = *ppEvents; + assert(pE); + + if( pE->pEventData != NULL ) + { + geRam_Free(pE->pEventData); + } + + if (pE->pTimeKeys != NULL) + { + geTKArray_Destroy(&pE->pTimeKeys); + } + geRam_Free(*ppEvents); + *ppEvents = NULL; +} + + +geBoolean GENESISCC geTKEvents_Insert(geTKEvents* pEvents, geTKEvents_TimeType tKey, const char* pEventData) +{ + int nIndex; + uint32 DataLength; + uint32 InitialOffset; + int nNumElements; + EventType* pKeyInfo; + char* pNewData; + + TKE_ASSERT_VALID(pEvents); + + if( geTKArray_Insert(&pEvents->pTimeKeys, tKey, &nIndex) != GE_TRUE ) + { + geErrorLog_Add(ERR_TKEVENTS_INSERT, NULL); + return GE_FALSE; + } + pKeyInfo = geTKArray_Element(pEvents->pTimeKeys, nIndex); + assert( pKeyInfo != NULL ); // I just successfully added it; it better be there. + + DataLength = strlen(pEventData) + 1; + + // Resize data to add new stuff + pNewData = geRam_Realloc(pEvents->pEventData, pEvents->DataSize + DataLength); + if(!pNewData) + { + geErrorLog_Add(ERR_TKEVENTS_INSERT_ENOMEM, NULL); + if( geTKArray_DeleteElement(&pEvents->pTimeKeys, nIndex) == GE_FALSE) + { + // This object is now in an unstable state. + assert(0); + } + // invalidate the iterator + pEvents->Iterator.EndTime = -99e33f; // you could sample here I suppose... + return GE_FALSE; + } + pEvents->pEventData = pNewData; + + // Find where new data will go + nNumElements = geTKArray_NumElements(pEvents->pTimeKeys); + assert(nIndex < nNumElements); // sanity check + if(nIndex == nNumElements - 1) + { + // We were added to the end + InitialOffset = pEvents->DataSize; + } + else + { + EventType* pNextKeyInfo = geTKArray_Element(pEvents->pTimeKeys, nIndex + 1); + assert( pNextKeyInfo != NULL ); + + InitialOffset = pNextKeyInfo->DataOffset; + } + pKeyInfo->DataOffset = InitialOffset; + + // Add new data, moving only if necessary + if(InitialOffset < pEvents->DataSize) + { + memmove(pEvents->pEventData + InitialOffset + DataLength, // dest + pEvents->pEventData + InitialOffset, // src + pEvents->DataSize - InitialOffset); // count + } + memcpy( pEvents->pEventData + InitialOffset, // dest + pEventData, // src + DataLength); // count + + pEvents->DataSize += DataLength; + + // Bump all remaining offsets up + nIndex++; + while(nIndex < nNumElements) + { + pKeyInfo = geTKArray_Element(pEvents->pTimeKeys, nIndex); + assert( pKeyInfo != NULL ); + pKeyInfo->DataOffset += DataLength; + + nIndex++; + } + + // invalidate the iterator + pEvents->Iterator.EndTime = -99e33f; // you could sample here I suppose... + + return GE_TRUE; +} + + +geBoolean GENESISCC geTKEvents_Delete(geTKEvents* pEvents, geTKEvents_TimeType tKey) +{ + int nIndex, Count; + geTKEvents_TimeType tFound; + EventType* pKeyInfo; + int DataOffset, DataSize; + char *pNewData; + + TKE_ASSERT_VALID(pEvents); + + nIndex = geTKArray_BSearch(pEvents->pTimeKeys, tKey); + + if( nIndex < 0 ) + { // no key wasn't found + geErrorLog_Add(ERR_TKEVENTS_DELETE_NOT_FOUND, NULL); + return GE_FALSE; + } + + tFound = geTKArray_ElementTime(pEvents->pTimeKeys, nIndex); + if(tFound < tKey - GE_TKA_TIME_TOLERANCE) + { + // key not found + geErrorLog_Add(ERR_TKEVENTS_DELETE_NOT_FOUND, NULL); + return GE_FALSE; + } + + pKeyInfo = geTKArray_Element(pEvents->pTimeKeys, nIndex); + DataOffset = pKeyInfo->DataOffset; + if(nIndex < geTKArray_NumElements(pEvents->pTimeKeys) - 1) + { + // not the last element + pKeyInfo = geTKArray_Element(pEvents->pTimeKeys, nIndex + 1); + DataSize = pKeyInfo->DataOffset - DataOffset; + + memmove(pEvents->pEventData + DataOffset, // dest + pEvents->pEventData + DataOffset + DataSize, // src + pEvents->DataSize - DataOffset - DataSize); // count + } + else + { + // It's the last element and no memory needs to be moved + DataSize = pEvents->DataSize - DataOffset; + } + + // Adjust data + pEvents->DataSize -= DataSize; + if (pEvents->DataSize == 0) + { + geRam_Free (pEvents->pEventData); + pEvents->pEventData = NULL; + } + else + { + pNewData = geRam_Realloc(pEvents->pEventData, pEvents->DataSize); + // If the reallocation failed, it doesn't really hurt. However, it is a + // sign of problems ahead. + if(pNewData) + { + pEvents->pEventData = pNewData; + } + } + + // Finally, remove this element + geTKArray_DeleteElement(&pEvents->pTimeKeys, nIndex); + + // Adjust the offsets + Count = geTKArray_NumElements(pEvents->pTimeKeys); + while(nIndex < Count) + { + pKeyInfo = geTKArray_Element(pEvents->pTimeKeys, nIndex); + assert( pKeyInfo != NULL ); + pKeyInfo->DataOffset -= DataSize; + nIndex++; + } + + // invalidate the iterator + pEvents->Iterator.EndTime = -99e33f; // you could sample here I suppose... + + return GE_TRUE; +} + + +#define TKEVENTS_ASCII_FILE_TYPE 0x56454B54 // 'TKEV' +#define TKEVENTS_FILE_VERSION 0x00F0 // Restrict to 16 bits + +#define TKEVENTS_BIN_FILE_TYPE 0x42454B54 // 'TKEB' +#define TKEVENTS_TIMEKEYS_ID "TimeKeys" +#define TKEVENTS_DATASIZE_ID "DataSize" + + +geTKEvents* GENESISCC geTKEvents_CreateFromFile( + geVFile* pFile) // stream positioned at array data + // Creates a new array from the given stream. +{ + uint32 u; + geTKEvents* pEvents; + + assert( pFile != NULL ); + + // Read the format/version flag + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_READ, NULL); + return NULL; + } + + pEvents = GE_RAM_ALLOCATE_STRUCT(geTKEvents); + if(!pEvents) + { + geErrorLog_Add(ERR_TKEVENTS_CREATE_ENOMEM, NULL); + return NULL; + } + pEvents->pEventData = NULL; + pEvents->pTimeKeys = NULL; + + if(u == TKEVENTS_ASCII_FILE_TYPE) + { + int i; + uint32 v; + char VersionString[32]; +#define LINE_LENGTH 256 + char line[LINE_LENGTH]; + char* pTextLine = NULL; + EventType* pEInfo; + geTKEvents_TimeType Time; + +#define ABORT_READ_AND_FREE { geErrorLog_Add(ERR_TKEVENTS_FILE_READ, NULL); geTKEvents_Destroy(&pEvents); return NULL; } +#define ABORT_READ_AND_FREE_ALL \ +{ \ + geErrorLog_Add(ERR_TKEVENTS_FILE_READ, NULL); \ + geTKEvents_Destroy(&pEvents); \ + if(pTextLine != NULL) \ + geRam_Free(pTextLine); \ + return NULL; \ +} + + // Read and build the version. + if (geVFile_GetS(pFile, VersionString, sizeof(VersionString)) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_READ, NULL); + return NULL; + } + sscanf(VersionString, "%X.%X\n", &u, &v); + v |= (u << 8); + // Should this structure change, then actually code multiversion support. + if(v != TKEVENTS_FILE_VERSION) + ABORT_READ_AND_FREE; + + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + ABORT_READ_AND_FREE; + + if(strnicmp(line, TKEVENTS_DATASIZE_ID, sizeof(TKEVENTS_DATASIZE_ID)-1) != 0) + ABORT_READ_AND_FREE; + + if(sscanf(line + sizeof(TKEVENTS_DATASIZE_ID)-1, "%d", &pEvents->DataSize) != 1) + ABORT_READ_AND_FREE; + if (pEvents->DataSize +1> LINE_LENGTH) + ABORT_READ_AND_FREE; + + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + ABORT_READ_AND_FREE; + + if(strnicmp(line, TKEVENTS_TIMEKEYS_ID, sizeof(TKEVENTS_TIMEKEYS_ID)-1) != 0) + ABORT_READ_AND_FREE; + + if(sscanf(line + sizeof(TKEVENTS_TIMEKEYS_ID)-1, "%d", &i) != 1) + ABORT_READ_AND_FREE; + + pEvents->pTimeKeys = geTKArray_Create(sizeof(EventType)); + if(!pEvents->pTimeKeys) + ABORT_READ_AND_FREE; + + pEvents->pEventData = geRam_Allocate(pEvents->DataSize); + if(!pEvents->pEventData) + ABORT_READ_AND_FREE_ALL; + + // The strings are read in with a CR. The max line length will then be + // the datasize + 1. + pTextLine = geRam_Allocate(pEvents->DataSize + 1); + if(pTextLine == NULL) + ABORT_READ_AND_FREE_ALL; + + while(i > 0) + { + char TimeString[64]; + if (geVFile_GetS(pFile, TimeString, sizeof(TimeString)) == GE_FALSE) + ABORT_READ_AND_FREE_ALL; + if(sscanf(TimeString, "%f %d\n", &Time, &v) != 2) + ABORT_READ_AND_FREE_ALL; + if(!geTKArray_Insert(&pEvents->pTimeKeys, Time, (int*)&u)) + ABORT_READ_AND_FREE_ALL; + pEInfo = geTKArray_Element(pEvents->pTimeKeys, u); + pEInfo->DataOffset = v; + //if(!fgets(pEvents->pEventData + v, pEvents->DataSize - v, pFile)) + if(geVFile_GetS(pFile, pTextLine, pEvents->DataSize + 1) == GE_FALSE) + ABORT_READ_AND_FREE_ALL; + // strip the CR + pTextLine[strlen(pTextLine) - 1] = 0; + { // maybe strip the rest of the CR + int len = strlen(pTextLine)-1; + if (pTextLine[len] == 13) // remove trailing /r (binary file mode) + { + pTextLine[len] = 0; + } + } + strcpy(pEvents->pEventData + v, pTextLine); + + i--; + } + + if(pTextLine != NULL) + geRam_Free(pTextLine); + } + else + { + if(u == TKEVENTS_BIN_FILE_TYPE) + { + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_READ, NULL); + geTKEvents_Destroy(&pEvents); + return GE_FALSE; + } + if (u != TKEVENTS_FILE_VERSION) + { + geErrorLog_AddString(-1,"Failure to recognize TKEvents file version", NULL); + geTKEvents_Destroy(&pEvents); + return GE_FALSE; + } + + if(geVFile_Read(pFile, &(pEvents->DataSize), sizeof(pEvents->DataSize)) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_READ, NULL); + geTKEvents_Destroy(&pEvents); + return NULL; + } + + pEvents->pEventData = geRam_Allocate(pEvents->DataSize); + if(!pEvents->pEventData) + { + geErrorLog_Add(ERR_TKEVENTS_CREATE_ENOMEM, NULL); + geTKEvents_Destroy(&pEvents); + return NULL; + } + + if(geVFile_Read(pFile, pEvents->pEventData, pEvents->DataSize) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_READ, NULL); + geTKEvents_Destroy(&pEvents); + return NULL; + } + pEvents->pTimeKeys = geTKArray_CreateFromBinaryFile(pFile); + if(!pEvents->pTimeKeys) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_READ, NULL); + geTKEvents_Destroy(&pEvents); + return NULL; + } + } + } + + return pEvents; +} + + +#define CHECK_FOR_WRITE(uu) if(uu <= 0) { geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); return GE_FALSE; } + +geBoolean GENESISCC geTKEvents_WriteToFile( + const geTKEvents* pEvents, // sorted array to write + geVFile* pFile) // stream positioned for writing + // Writes the array to the given stream. +{ + uint32 u; + int NumElements; + int i; + EventType* pEInfo; + + assert( pEvents != NULL ); + assert( pFile != NULL ); + + u = TKEVENTS_ASCII_FILE_TYPE; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + + // Write the version + if (geVFile_Printf(pFile, + " %X.%.2X\n", + (TKEVENTS_FILE_VERSION & 0xFF00) >> 8, + TKEVENTS_FILE_VERSION & 0x00FF) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + + // Write the data size first and then combine the time array and string + // data into one loop of human readable output. + if (geVFile_Printf(pFile, "%s %d\n", TKEVENTS_DATASIZE_ID, pEvents->DataSize) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + + // Write the TimeKeys array and string data. + NumElements = geTKArray_NumElements(pEvents->pTimeKeys); + if (geVFile_Printf(pFile, "%s %d\n", TKEVENTS_TIMEKEYS_ID, NumElements) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + + for(i=0;ipTimeKeys, i); + if (geVFile_Printf(pFile, "%f %d\n", pEInfo->EventTime, pEInfo->DataOffset) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + if (geVFile_Printf(pFile, "%s\n", pEvents->pEventData + pEInfo->DataOffset) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + } + return GE_TRUE; +} + + + +geBoolean GENESISCC geTKEvents_WriteToBinaryFile( + const geTKEvents* pEvents, // sorted array to write + geVFile* pFile) // stream positioned for writing + // Writes the array to the given stream. +{ + uint32 u; + assert( pEvents != NULL ); + assert( pFile != NULL ); + + u = TKEVENTS_BIN_FILE_TYPE; + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + u = TKEVENTS_FILE_VERSION; + // Write the version + if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + + if(geVFile_Write(pFile, &pEvents->DataSize, sizeof(pEvents->DataSize)) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + + if(geVFile_Write(pFile, pEvents->pEventData, pEvents->DataSize) == GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + + if (geTKArray_WriteToBinaryFile(pEvents->pTimeKeys, pFile)==GE_FALSE) + { + geErrorLog_Add(ERR_TKEVENTS_FILE_WRITE, NULL); + return GE_FALSE; + } + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geTKEvents_GetExtents(geTKEvents *Events, + geTKEvents_TimeType *FirstEventTime, + geTKEvents_TimeType *LastEventTime) +{ + int Count; + assert( Events != NULL ); + + Count = geTKArray_NumElements(Events->pTimeKeys); + if (Count<0) + { + return GE_FALSE; + } + + *FirstEventTime = geTKArray_ElementTime(Events->pTimeKeys, 0); + *LastEventTime = geTKArray_ElementTime(Events->pTimeKeys, Count-1); + return GE_TRUE; +} + +void GENESISCC geTKEvents_SetupIterator( + geTKEvents* pEvents, // Event list to iterate + geTKEvents_TimeType StartTime, // Inclusive search start + geTKEvents_TimeType EndTime) // Non-inclusive search stop + // For searching or querying the array for events between two times + // times are compaired [StartTime,EndTime), '[' is inclusive, ')' is + // non-inclusive. This prepares the PathGetNextEvent() function. +{ + geTKEventsIterator* pTKEI; + + assert( pEvents != NULL ); + + pTKEI = &pEvents->Iterator; + + pTKEI->EndTime = EndTime; + + // Initialize search with first index before StartTime + pTKEI->CurrentIndex = geTKArray_BSearch(pEvents->pTimeKeys, StartTime - GE_TKA_TIME_TOLERANCE); + while( (pTKEI->CurrentIndex > -1) && + (geTKArray_ElementTime(pEvents->pTimeKeys, pTKEI->CurrentIndex) >= StartTime - GE_TKA_TIME_TOLERANCE) ) + { + pTKEI->CurrentIndex--; + } +} + + +geBoolean GENESISCC geTKEvents_GetNextEvent( + geTKEvents* pEvents, // Event list to iterate + geTKEvents_TimeType *pTime, // Return time, if found + const char **ppEventString) // Return data, if found + // Iterates from StartTime to EndTime as setup in geTKEvents_CreateIterator() + // and for each event between these times [StartTime,EndTime) + // this function will return Time and EventString returned for that event + // and the iterator will be positioned for the next search. When there + // are no more events in the range, this function will return NULL (Time + // will be 0 and ppEventString will be empty). +{ + geTKEventsIterator* pTKEI; + geTKArray* pTimeKeys; + EventType* pKeyInfo; + int Index; + + assert(pEvents); + assert(pTime); + assert(ppEventString); + + pTKEI = &pEvents->Iterator; + + pTimeKeys = pEvents->pTimeKeys; + + pTKEI->CurrentIndex++; + Index = pTKEI->CurrentIndex; + if(Index < geTKArray_NumElements(pTimeKeys)) + { + *pTime = geTKArray_ElementTime(pTimeKeys, Index); + if(*pTime + GE_TKA_TIME_TOLERANCE < pTKEI->EndTime) + { + // Looks good. Get the string and return. + pKeyInfo = geTKArray_Element(pTimeKeys, Index); + *ppEventString = pEvents->pEventData + pKeyInfo->DataOffset; + return GE_TRUE; + } + } + + // None found, clean up + *pTime = 0.0f; + *ppEventString = NULL; + return GE_FALSE; +} diff --git a/G3D/Actor/tkevents.h b/G3D/Actor/tkevents.h new file mode 100644 index 0000000..15b8b0a --- /dev/null +++ b/G3D/Actor/tkevents.h @@ -0,0 +1,102 @@ +/****************************************************************************************/ +/* TKARRAY.H */ +/* */ +/* Author: Stephen Balkum */ +/* Description: Time-keyed events interface. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_TKEVENTS_H +#define GE_TKEVENTS_H +/* TKEvents + (Time-Keyed-Events) + This module is designed primarily to support motion.c + + geTKEvents is a sorted array of times with an identifying descriptor. + The descriptors are stored as strings in a separate, packed buffer. + + Error conditions are reported to errorlog +*/ + +#include "basetype.h" +#include "vfile.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct geTKEvents geTKEvents; +typedef geFloat geTKEvents_TimeType; + +geTKEvents* GENESISCC geTKEvents_Create(void); + // Creates a new event array. + +void GENESISCC geTKEvents_Destroy(geTKEvents** pEvents); + // Destroys array. + +geBoolean GENESISCC geTKEvents_Insert(geTKEvents* pEvents, geTKEvents_TimeType tKey, const char* pEventData); + // Inserts the new key and corresponding data. + +geBoolean GENESISCC geTKEvents_Delete(geTKEvents* pEvents, geTKEvents_TimeType tKey); + // Deletes the key + +geTKEvents* GENESISCC geTKEvents_CreateFromFile( + geVFile* pFile); // stream positioned at array data + // Creates a new array from the given stream. + +geBoolean GENESISCC geTKEvents_WriteToFile( + const geTKEvents* pEvents, // sorted array to write + geVFile* pFile); // stream positioned for writing + // Writes the array to the given stream. + +geBoolean GENESISCC geTKEvents_WriteToBinaryFile( + const geTKEvents* pEvents, // sorted array to write (in binary format) + geVFile* pFile); // stream positioned for writing + // Writes the array to the given stream. +//--------------------------------------------------------------------------- +// Event Iteration + +void GENESISCC geTKEvents_SetupIterator( + geTKEvents* pEvents, // Event list to iterate + geTKEvents_TimeType StartTime, // Inclusive search start + geTKEvents_TimeType EndTime); // Non-inclusive search stop + // For searching or querying the array for events between two times + // times are compaired [StartTime,EndTime), '[' is inclusive, ')' is + // non-inclusive. This prepares the PathGetNextEvent() function. + +geBoolean GENESISCC geTKEvents_GetNextEvent( + geTKEvents* pEvents, // Event list to iterate + geTKEvents_TimeType *pTime, // Return time, if found + const char **ppEventString); // Return data, if found + // Iterates from StartTime to EndTime as setup in geTKEvents_CreateIterator() + // and for each event between these times [StartTime,EndTime) + // this function will return Time and EventString returned for that event + // and the iterator will be positioned for the next search. When there + // are no more events in the range, this function will return GE_FALSE (Time + // will be 0 and ppEventString will be empty). + +GENESISAPI geBoolean GENESISCC geTKEvents_GetExtents( + geTKEvents *Events, + geTKEvents_TimeType *FirstEventTime, // time of first event + geTKEvents_TimeType *LastEventTime); // time of last event + +#ifdef __cplusplus +} +#endif + + + +#endif // __TKEVENTS_H__ \ No newline at end of file diff --git a/G3D/Actor/vkframe.c b/G3D/Actor/vkframe.c new file mode 100644 index 0000000..8f24c8c --- /dev/null +++ b/G3D/Actor/vkframe.c @@ -0,0 +1,845 @@ +/****************************************************************************************/ +/* VKFRAME.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Vector keyframe implementation. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +/* geVKFrame (Vector-Keyframe) + This module handles interpolation for keyframes that contain a vector (a geVec3d) + This is intended to support Path.c + geTKArray supplies general support for a time-keyed array, and this supplements + that support to include the two specific time-keyed arrays: + An array of geVec3d interpolated linearly + An array of geVec3d interpolated with hermite blending + These are phycially separated and have different base structures because: + linear blending requires less data. + future blending might require more data. + The two types of lists are created with different creation calls, + interpolated with different calls, but insertion and queries share a call. + + Hermite interpolation requires additional computation after changes are + made to the keyframe list. Call geVKFrame_HermiteRecompute() to update the + calculations. +*/ +#include +#include +#include + +#include "vec3d.h" +#include "vkframe.h" +#include "errorlog.h" +#include "ram.h" + +#define LINEAR_BLEND(a,b,t) ( (t)*((b)-(a)) + (a) ) + // linear blend of a and b 0a and t=1 ->b + +typedef struct +{ + geTKArray_TimeType Time; // Time for this keyframe + geVec3d V; // vector for this keyframe +} geVKFrame; + // This is the root structure that geVKFrame supports + // all keyframe types must begin with this structure. Time is first, so + // that this structure can be manipulated by geTKArray + +typedef struct +{ + geVKFrame Key; // key values for this keyframe + geVec3d SDerivative; // Hermite Derivative (Incoming) + geVec3d DDerivative; // Hermite Derivative (Outgoing) +} geVKFrame_Hermite; + // keyframe data for hermite blending + // The structure includes computed derivative information. + +typedef struct +{ + geVKFrame Key; // key values for this keyframe +} geVKFrame_Linear; + // keyframe data for linear interpolation + // The structure includes no additional information. + +geTKArray *GENESISCC geVKFrame_LinearCreate(void) + // creates a frame list for linear interpolation +{ + return geTKArray_Create(sizeof(geVKFrame_Linear) ); +} + + +geTKArray *GENESISCC geVKFrame_HermiteCreate(void) + // creates a frame list for hermite interpolation +{ + return geTKArray_Create(sizeof(geVKFrame_Hermite) ); +} + + +geBoolean GENESISCC geVKFrame_Insert( + geTKArray **KeyList, // keyframe list to insert into + geTKArray_TimeType Time, // time of new keyframe + const geVec3d *V, // vector at new keyframe + int *Index) // index of new key + // inserts a new keyframe with the given time and vector into the list. +{ + assert( KeyList != NULL ); + assert( *KeyList != NULL ); + assert( V != NULL ); + assert( sizeof(geVKFrame_Hermite) == geTKArray_ElementSize(*KeyList) + || sizeof(geVKFrame_Linear) == geTKArray_ElementSize(*KeyList) ); + + if (geTKArray_Insert(KeyList, Time, Index) == GE_FALSE) + { + geErrorLog_Add(ERR_VKARRAY_INSERT, NULL); + return GE_FALSE; + } + else + { + geVKFrame *KF; + KF = (geVKFrame *)geTKArray_Element(*KeyList,*Index); + KF->V = *V; + return GE_TRUE; + } +} + +void GENESISCC geVKFrame_Query( + const geTKArray *KeyList, // keyframe list + int Index, // index of frame to return + geTKArray_TimeType *Time, // time of the frame is returned + geVec3d *V) // vector from the frame is returned + // returns the vector and the time at keyframe[index] +{ + geVKFrame *KF; + assert( KeyList != NULL ); + assert( Time != NULL ); + assert( V != NULL ); + assert( Index < geTKArray_NumElements(KeyList) ); + assert( Index >= 0 ); + assert( sizeof(geVKFrame_Hermite) == geTKArray_ElementSize(KeyList) + || sizeof(geVKFrame_Linear) == geTKArray_ElementSize(KeyList) ); + + KF = (geVKFrame *)geTKArray_Element(KeyList,Index); + *Time = KF->Time; + *V = KF->V; +} + + +void GENESISCC geVKFrame_Modify( + geTKArray *KeyList, // keyframe list + int Index, // index of frame to change + const geVec3d *V) // vector for the key + // chganes the vector at keyframe[index] +{ + geVKFrame *KF; + assert( KeyList != NULL ); + assert( V != NULL ); + assert( Index < geTKArray_NumElements(KeyList) ); + assert( Index >= 0 ); + assert( sizeof(geVKFrame_Hermite) == geTKArray_ElementSize(KeyList) + || sizeof(geVKFrame_Linear) == geTKArray_ElementSize(KeyList) ); + + KF = (geVKFrame *)geTKArray_Element(KeyList,Index); + KF->V = *V; +} + + +void GENESISCC geVKFrame_LinearInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result) // put the result in here (geVec3d) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates linearly +{ + geVec3d *Vec1,*Vec2; + geVec3d *VNew = (geVec3d *)Result; + + assert( Result != NULL ); + assert( KF1 != NULL ); + assert( KF2 != NULL ); + + assert( T >= (geFloat)0.0f ); + assert( T <= (geFloat)1.0f ); + + if ( KF1 == KF2 ) + { + *VNew = ((geVKFrame_Linear *)KF1)->Key.V; + return; + } + + Vec1 = &( ((geVKFrame_Linear *)KF1)->Key.V); + Vec2 = &( ((geVKFrame_Linear *)KF2)->Key.V); + + VNew->X = LINEAR_BLEND(Vec1->X,Vec2->X,T); + VNew->Y = LINEAR_BLEND(Vec1->Y,Vec2->Y,T); + VNew->Z = LINEAR_BLEND(Vec1->Z,Vec2->Z,T); +} + + + +void GENESISCC geVKFrame_HermiteInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result) // put the result in here (geVec3d) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates using 'hermite' blending +{ + geVec3d *Vec1,*Vec2; + geVec3d *VNew = (geVec3d *)Result; + + assert( Result != NULL ); + assert( KF1 != NULL ); + assert( KF2 != NULL ); + + assert( T >= (geFloat)0.0f ); + assert( T <= (geFloat)1.0f ); + + if ( KF1 == KF2 ) + { + *VNew = ((geVKFrame_Hermite *)KF1)->Key.V; + return; + } + + Vec1 = &( ((geVKFrame_Hermite *)KF1)->Key.V); + Vec2 = &( ((geVKFrame_Hermite *)KF2)->Key.V); + + { + geFloat t2; // T sqaured + geFloat t3; // T cubed + geFloat H1,H2,H3,H4; // hermite basis function coefficients + + t2 = T * T; + t3 = t2 * T; + + H2 = -(t3 + t3) + t2*3.0f; + H1 = 1.0f - H2; + H4 = t3 - t2; + H3 = H4 - t2 + T; //t3 - 2.0f * t2 + t; + + geVec3d_Scale(Vec1,H1,VNew); + geVec3d_AddScaled(VNew,Vec2,H2,VNew); + geVec3d_AddScaled(VNew,&( ((geVKFrame_Hermite *)KF1)->DDerivative),H3,VNew); + geVec3d_AddScaled(VNew,&( ((geVKFrame_Hermite *)KF2)->SDerivative),H4,VNew); + } +} + + +void GENESISCC geVKFrame_HermiteRecompute( + int Looped, // if keylist has the first key connected to last key + geBoolean ZeroDerivative,// if each key should have a zero derivatives (good for 2 point S curves) + geTKArray *KeyList) // list of keys to recompute hermite values for + // rebuild precomputed data for keyframe list. +{ + // compute the incoming and outgoing derivatives at each keyframe + int i; + geVec3d V0,V1,V2; + geFloat Time0, Time1, Time2, N0, N1, N0N1; + geVKFrame_Hermite *TK; + geVKFrame_Hermite *Vector= NULL; + int count; + int Index0,Index1,Index2; + + assert( KeyList != NULL ); + assert( sizeof(geVKFrame_Hermite) == geTKArray_ElementSize(KeyList) ); + + + // Compute derivatives at the keyframe points: + // The derivative is the average of the source chord p[i]-p[i-1] + // and the destination chord p[i+1]-p[i] + // (where i is Index1 in this function) + // D = 1/2 * ( p[i+1]-p[i-1] ) = 1/2 *( (p[i+1]-p[i]) + (p[i]-p[i-1]) ) + // The very first and last chords are simply the + // destination and source derivative. + // These 'averaged' D's are adjusted for variences in the time scale + // between the Keyframes. To do this, the derivative at each keyframe + // is split into two parts, an incoming ('source' DS) + // and an outgoing ('destination' DD) derivative. + // DD[i] = DD[i] * 2 * N[i] / ( N[i-1] + N[i] ) + // DS[i] = DS[i] * 2 * N[i-1]/ ( N[i-1] + N[i] ) + // where N[i] is time between keyframes i and i+1 + // Since the chord dealt with on a given chord between key[i] and key[i+1], only + // one of the derivates are needed for each keyframe. For key[i] the outgoing + // derivative at is needed (DD[i]). For key[i+1], the incoming derivative + // is needed (DS[i+1]) ( note that (1/2) * 2 = 1 ) + count = geTKArray_NumElements(KeyList); + if (count > 0) + { + Vector = (geVKFrame_Hermite *)geTKArray_Element(KeyList,0); + } + + if (ZeroDerivative!=GE_FALSE) + { // in this case, just bang all derivatives to zero. + for (i =0; i< count; i++) + { + TK = &(Vector[i]); + geVec3d_Clear(&(TK->DDerivative)); + geVec3d_Clear(&(TK->SDerivative)); + } + return; + } + + if (count < 3) + { + Looped = GE_FALSE; + // cant compute slopes without a closed loop: + // so compute slopes as if it is not closed. + } + for (i =0; i< count; i++) + { + TK = &(Vector[i]); + Index0 = i-1; + Index1 = i; + Index2 = i+1; + + Time1 = Vector[Index1].Key.Time; + if (Index1 == 0) + { + if (Looped != GE_TRUE) + { + Index0 = 0; + Time0 = Vector[Index0].Key.Time; + } + else + { + Index0 = count-2; + Time0 = Time1 - (Vector[count-1].Key.Time - Vector[count-2].Key.Time); + } + } + else + { + Time0 = Vector[Index0].Key.Time; + } + + + if (Index2 == count) + { + if (Looped != GE_TRUE) + { + Index2 = count-1; + Time2 = Vector[Index2].Key.Time; + } + else + { + Index2 = 1; + Time2 = Time1 + (Vector[1].Key.Time - Vector[0].Key.Time); + } + } + else + { + Time2 = Vector[Index2].Key.Time; + } + + V0 = Vector[Index0].Key.V; + V1 = Vector[Index1].Key.V; + V2 = Vector[Index2].Key.V; + + N0 = (Time1 - Time0); + N1 = (Time2 - Time1); + N0N1 = N0 + N1; + + if (( Looped != GE_TRUE) && (Index1 == 0) ) + { + geVec3d_Subtract(&V2,&V1,&(TK->SDerivative)); + geVec3d_Copy( &(TK->SDerivative), &(TK->DDerivative)); + } + else if (( Looped != GE_TRUE) && (Index1 == count-1)) + { + geVec3d_Subtract(&V1,&V0,&(TK->SDerivative)); + geVec3d_Copy( &(TK->SDerivative), &(TK->DDerivative)); + } + else + { + geVec3d Slope; + geVec3d_Subtract(&V2,&V0,&Slope); + geVec3d_Scale(&Slope, (N1 / N0N1), &(TK->DDerivative)); + geVec3d_Scale(&Slope, (N0 / N0N1), &(TK->SDerivative)); + } + } +} + + +#define VKFRAME_LINEAR_ASCII_FILE 0x4C464B56 // 'VKFL' +#define VKFRAME_HERMITE_ASCII_FILE 0x48464B56 // 'VKFH' +#define CHECK_FOR_READ(uu, nn) if(uu != nn) { geErrorLog_Add(ERR_PATH_FILE_READ, NULL); return GE_FALSE; } +#define CHECK_FOR_WRITE(uu) if (uu <= 0) { geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); return GE_FALSE; } + +#define VKFRAME_KEYLIST_ID "Keys" + + +//----------------------------------- +// Support for 'old' 1.0 ascii data format + +geBoolean GENESISCC geVKFrame_LinearRead(geVFile* pFile, void* geVKFrame) +{ + uint32 u; + char KeyString[64]; + geVKFrame_Linear* pLinear = (geVKFrame_Linear*)geVKFrame; + + assert( pFile != NULL ); + assert( geVKFrame != NULL ); + + // Read the format/version flag + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + + if(u != VKFRAME_LINEAR_ASCII_FILE) + { + geErrorLog_Add(ERR_PATH_FILE_VERSION, NULL); + return GE_FALSE; + } + + if (geVFile_GetS(pFile, KeyString, sizeof(KeyString)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + + u = sscanf(KeyString, "%f %f %f\n", &pLinear->Key.V.X, + &pLinear->Key.V.Y, + &pLinear->Key.V.Z); + CHECK_FOR_READ(u, 3); + + return GE_TRUE; +} + + +geBoolean GENESISCC geVKFrame_HermiteRead(geVFile* pFile, void* geVKFrame) +{ + uint32 u; + char HermiteString[128]; + geVKFrame_Hermite* pHermite = (geVKFrame_Hermite*)geVKFrame; + + assert( pFile != NULL ); + assert( geVKFrame != NULL ); + + // Read the format/version flag + if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + + if(u != VKFRAME_HERMITE_ASCII_FILE) + { + geErrorLog_Add(ERR_PATH_FILE_VERSION, NULL); + return GE_FALSE; + } + + if (geVFile_GetS(pFile, HermiteString, sizeof(HermiteString)) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_READ, NULL); + return GE_FALSE; + } + u = sscanf(HermiteString, "%f %f %f %f %f %f %f %f %f\n", &pHermite->Key.V.X, + &pHermite->Key.V.Y, + &pHermite->Key.V.Z, + &pHermite->SDerivative.X, + &pHermite->SDerivative.Y, + &pHermite->SDerivative.Z, + &pHermite->DDerivative.X, + &pHermite->DDerivative.Y, + &pHermite->DDerivative.Z); + CHECK_FOR_READ(u, 9); + + return GE_TRUE; +} + + + // (above)Support for 'old' 1.0 ascii data format +//----------------------------------- +#define LINEARTIME_TOLERANCE (0.0001f) +#define VKFRAME_LINEARTIME_COMPRESSION 0x2 + + + +geBoolean GENESISCC geVKFrame_WriteToFile(geVFile *pFile, geTKArray *KeyList, + geVKFrame_InterpolationType InterpolationType, int Looping) +{ + int NumElements,i; + geFloat Time,DeltaTime; + int Compression=0; + + assert( pFile != NULL ); + assert( KeyList != NULL ); + + NumElements = geTKArray_NumElements(KeyList); + + if (NumElements>2) + { + if ( geTKArray_SamplesAreTimeLinear(KeyList,LINEARTIME_TOLERANCE) != GE_FALSE ) + { + Compression |= VKFRAME_LINEARTIME_COMPRESSION; + } + } + + + if (geVFile_Printf(pFile, + "%s %d %d %d %d\n", + VKFRAME_KEYLIST_ID, + NumElements, + InterpolationType, + Compression, + Looping) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); + return GE_FALSE; + } + + if (Compression & VKFRAME_LINEARTIME_COMPRESSION) + { + Time = geTKArray_ElementTime(KeyList, 0); + DeltaTime = geTKArray_ElementTime(KeyList, 1)- Time; + if(geVFile_Printf(pFile,"%f %f Start T,Delta T\n",Time,DeltaTime) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); + return GE_FALSE; + } + } + + for(i=0;iKey.V.X, + pLinear->Key.V.Y, + pLinear->Key.V.Z) == GE_FALSE) + { + geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); + return GE_FALSE; + } + } + return GE_TRUE; +} + + +geTKArray *GENESISCC geVKFrame_CreateFromFile(geVFile *pFile, int *InterpolationType, int *Looping) +{ + #define ERROREXIT {geErrorLog_Add( ERR_PATH_FILE_READ , NULL);if (KeyList != NULL){geTKArray_Destroy(&KeyList);} return NULL;} + int i,u,NumElements; + int Compression; + #define LINE_LENGTH 256 + char line[LINE_LENGTH]; + geTKArray *KeyList= NULL; + geFloat StartTime=0.0f; + geFloat DeltaTime=0.0f; + + + assert( pFile != NULL ); + assert( InterpolationType != NULL ); + + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + ERROREXIT; + + if(strnicmp(line, VKFRAME_KEYLIST_ID, sizeof(VKFRAME_KEYLIST_ID)-1) != 0) + ERROREXIT; + + if(sscanf(line + sizeof(VKFRAME_KEYLIST_ID)-1, "%d %d %d %d", + &NumElements,InterpolationType,&Compression,Looping) != 4) + ERROREXIT; + + switch (*InterpolationType) + { + case (VKFRAME_LINEAR): + KeyList = geTKArray_CreateEmpty(sizeof(geVKFrame_Linear),NumElements); + break; + case (VKFRAME_HERMITE): + case (VKFRAME_HERMITE_ZERO_DERIV): + KeyList = geTKArray_CreateEmpty(sizeof(geVKFrame_Hermite),NumElements); + break; + default: + ERROREXIT; + } + if (KeyList == NULL) + ERROREXIT; + + if (Compression & VKFRAME_LINEARTIME_COMPRESSION) + { + if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE) + ERROREXIT; + if (sscanf(line,"%f %f",&StartTime,&DeltaTime) != 2) + ERROREXIT; + } + + for(i=0;iKey.Time = StartTime + DeltaTime * i; + u = sscanf(line,"%f %f %f", &(pLinear->Key.V.X), + &(pLinear->Key.V.Y),&(pLinear->Key.V.Z)); + if (u!=3) + ERROREXIT; + } + else + { + u = sscanf(line,"%f %f %f %f",&(pLinear->Key.Time), &(pLinear->Key.V.X), + &(pLinear->Key.V.Y),&(pLinear->Key.V.Z)); + if (u!=4) + ERROREXIT; + } + } + + switch (*InterpolationType) + { + case (VKFRAME_LINEAR): + break; + case (VKFRAME_HERMITE): + geVKFrame_HermiteRecompute( *Looping, GE_FALSE, KeyList); + break; + case (VKFRAME_HERMITE_ZERO_DERIV): + geVKFrame_HermiteRecompute( *Looping, GE_TRUE, KeyList); + break; + default: + assert(0); + } + + return KeyList; +} + +uint32 GENESISCC geVKFrame_ComputeBlockSize(geTKArray *KeyList, int Compression) +{ + uint32 Size=0; + int Count; + + assert( KeyList != NULL ); + assert( Compression < 0xFF); + + Count = geTKArray_NumElements(KeyList); + + Size += sizeof(uint32); // flags + Size += sizeof(uint32); // count + + if (Compression & VKFRAME_LINEARTIME_COMPRESSION) + { + Size += sizeof(geFloat) * 2; + } + else + { + Size += sizeof(geFloat) * Count; + } + + Size += sizeof(geVec3d) * Count; + return Size; +} + + +geTKArray *GENESISCC geVKFrame_CreateFromBinaryFile(geVFile *pFile, int *InterpolationType, int *Looping) +{ + uint32 u; + int BlockSize; + int Compression; + int Count,i; + int FieldSize; + char *Block; + geFloat *Data; + geTKArray *KeyList; + geVKFrame_Linear* pLinear0; + geVKFrame_Linear* pLinear; + + assert( pFile != NULL ); + assert( InterpolationType != NULL ); + assert( Looping != NULL ); + + if (geVFile_Read(pFile, &BlockSize, sizeof(int)) == GE_FALSE) + { + geErrorLog_AddString(-1,"Failure to read binary VKFrame header", NULL); + return NULL; + } + if (BlockSize<0) + { + geErrorLog_AddString(-1,"Bad Blocksize", NULL); + return NULL; + } + + Block = geRam_Allocate(BlockSize); + if(geVFile_Read(pFile, Block, BlockSize) == GE_FALSE) + { + geErrorLog_AddString(-1,"Failure to read binary VKFrame header", NULL); + return NULL; + } + u = *(uint32 *)Block; + *InterpolationType = (u>>16)& 0xFF; + Compression = (u>>8) & 0xFF; + *Looping = (u & 0x1); + Count = *(((uint32 *)Block)+1); + + if (Compression > 0xFF) + { + geRam_Free(Block); + geErrorLog_AddString(-1,"Bad Compression Flag", NULL); + return NULL; + } + switch (*InterpolationType) + { + case (VKFRAME_LINEAR): + FieldSize = sizeof(geVKFrame_Linear); + break; + case (VKFRAME_HERMITE): + case (VKFRAME_HERMITE_ZERO_DERIV): + FieldSize = sizeof(geVKFrame_Hermite); + break; + default: + geRam_Free(Block); + geErrorLog_AddString(-1,"Bad InterpolationType", NULL); + return NULL; + } + + KeyList = geTKArray_CreateEmpty(FieldSize,Count); + if (KeyList == NULL) + { + geRam_Free(Block); + geErrorLog_AddString(-1,"Failed to allocate tkarray", NULL); + return NULL; + } + + Data = (geFloat *)(Block + sizeof(uint32)*2); + + pLinear0 = (geVKFrame_Linear*)geTKArray_Element(KeyList, 0); + + pLinear = pLinear0; + + if (Compression & VKFRAME_LINEARTIME_COMPRESSION) + { + geFloat fi; + geFloat fCount = (geFloat)Count; + geFloat Time,DeltaTime; + Time = *(Data++); + DeltaTime = *(Data++); + for(fi=0.0f;fiKey.Time = Time + fi*DeltaTime; + pLinear = (geVKFrame_Linear *) ( ((char *)pLinear) + FieldSize ); + } + } + else + { + for(i=0;iKey.Time = *(Data++); + pLinear = (geVKFrame_Linear *) ( ((char *)pLinear) + FieldSize ); + } + } + + pLinear = pLinear0; + for(i=0;iKey.V = *(geVec3d *)Data; + Data += 3; + pLinear = (geVKFrame_Linear *) ( ((char *)pLinear) + FieldSize ); + } + + switch (*InterpolationType) + { + case (VKFRAME_LINEAR): + break; + case (VKFRAME_HERMITE): + geVKFrame_HermiteRecompute( *Looping, GE_FALSE, KeyList); + break; + case (VKFRAME_HERMITE_ZERO_DERIV): + geVKFrame_HermiteRecompute( *Looping, GE_TRUE, KeyList); + break; + default: + assert(0); + } + geRam_Free(Block); + return KeyList; + +} + +geBoolean GENESISCC geVKFrame_WriteToBinaryFile(geVFile *pFile, geTKArray *KeyList, + geVKFrame_InterpolationType InterpolationType, int Looping) +{ + #define WBERREXIT {geErrorLog_AddString( ERR_PATH_FILE_WRITE,"Failure to write binary key data", NULL);return GE_FALSE;} + uint32 u,BlockSize; + int Compression=0; + int Count,i; + geFloat Time,DeltaTime; + + assert( pFile != NULL ); + assert( InterpolationType < 0xFF); + assert( (Looping == 0) || (Looping == 1) ); + + if (geTKArray_NumElements(KeyList)>2) + { + if ( geTKArray_SamplesAreTimeLinear(KeyList,LINEARTIME_TOLERANCE) != GE_FALSE ) + { + Compression |= VKFRAME_LINEARTIME_COMPRESSION; + } + } + + u = (InterpolationType << 16) | (Compression << 8) | Looping; + + BlockSize = geVKFrame_ComputeBlockSize(KeyList,Compression); + + if (geVFile_Write(pFile, &BlockSize,sizeof(uint32)) == GE_FALSE) + WBERREXIT; + + if (geVFile_Write(pFile, &u, sizeof(uint32)) == GE_FALSE) + WBERREXIT; + + Count = geTKArray_NumElements(KeyList); + if (geVFile_Write(pFile, &Count, sizeof(uint32)) == GE_FALSE) + WBERREXIT; + + if (Compression & VKFRAME_LINEARTIME_COMPRESSION) + { + Time = geTKArray_ElementTime(KeyList, 0); + DeltaTime = geTKArray_ElementTime(KeyList, 1)- Time; + if (geVFile_Write(pFile, &Time,sizeof(geFloat)) == GE_FALSE) + WBERREXIT; + if (geVFile_Write(pFile, &DeltaTime,sizeof(geFloat)) == GE_FALSE) + WBERREXIT; + } + else + { + for(i=0;iKey.V),sizeof(geVec3d)) == GE_FALSE) + WBERREXIT; + } + + return GE_TRUE; +} diff --git a/G3D/Actor/vkframe.h b/G3D/Actor/vkframe.h new file mode 100644 index 0000000..ab637a6 --- /dev/null +++ b/G3D/Actor/vkframe.h @@ -0,0 +1,126 @@ +/****************************************************************************************/ +/* VKFRAME.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Vector keyframe interface. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +/* VKFrame (Vector-Keyframe) + This module handles interpolation for keyframes that contain a vector (a geVec3d) + This is intended to support Path.c + geTKArray supplies general support for a time-keyed array, and this supplements + that support to include the two specific time-keyed arrays: + An array of geVec3d interpolated linearly + An array of geVec3d interpolated with hermite blending + These are phycially separated and have different base structures because: + linear blending requires less data. + future blending might require more data. + The two types of lists are created with different creation calls, + interpolated with different calls, but insertion and queries share a call. + + Hermite interpolation requires additional computation after changes are + made to the keyframe list. Call geVKFrame_HermiteRecompute() to update the + calculations. +*/ +#ifndef GE_VKFRAME_H +#define GE_VKFRAME_H + +#include "TKArray.h" +#include "vfile.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + VKFRAME_LINEAR, + VKFRAME_HERMITE, + VKFRAME_HERMITE_ZERO_DERIV, +} geVKFrame_InterpolationType; + + +geTKArray *GENESISCC geVKFrame_LinearCreate(void); + // creates a frame list for linear interpolation + +geTKArray *GENESISCC geVKFrame_HermiteCreate(void); + // creates a frame list for hermite interpolation + + +geBoolean GENESISCC geVKFrame_Insert( + geTKArray **KeyList, // keyframe list to insert into + geTKArray_TimeType Time, // time of new keyframe + const geVec3d *V, // vector at new keyframe + int *Index); // indx of new key + // inserts a new keyframe with the given time and vector into the list. + +void GENESISCC geVKFrame_Query( + const geTKArray *KeyList, // keyframe list + int Index, // index of frame to return + geTKArray_TimeType *Time, // time of the frame is returned + geVec3d *V); // vector from the frame is returned + // returns the vector and the time at keyframe[index] + +void GENESISCC geVKFrame_Modify( + geTKArray *KeyList, // keyframe list + int Index, // index of frame to change + const geVec3d *V); // vector for the key + // chganes the vector at keyframe[index] + +void GENESISCC geVKFrame_LinearInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result); // put the result in here (geVec3d) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates linearly + +void GENESISCC geVKFrame_HermiteInterpolation( + const void *KF1, // pointer to first keyframe + const void *KF2, // pointer to second keyframe + geFloat T, // 0 <= T <= 1 blending parameter + void *Result); // put the result in here (geVec3d) + // interpolates to get a vector between the two vectors at the two + // keyframes where T==0 returns the vector for KF1 + // and T==1 returns the vector for KF2 + // interpolates using 'hermite' blending + + +void GENESISCC geVKFrame_HermiteRecompute( + int Looped, // if keylist has the first key connected to last key + geBoolean ZeroDerivative, // if each key should have a zero derivatives (good for 2 point S curves) + geTKArray *KeyList); // list of keys to recompute hermite values for + // rebuild precomputed data for keyframe list. + + +geBoolean GENESISCC geVKFrame_LinearRead(geVFile* pFile, void* geVKFrame); +geBoolean GENESISCC geVKFrame_HermiteRead(geVFile* pFile, void* geVKFrame); + +geBoolean GENESISCC geVKFrame_WriteToFile(geVFile *pFile, void *geVKFrame, + geVKFrame_InterpolationType InterpolationType,int Looping); +geTKArray *GENESISCC geVKFrame_CreateFromFile(geVFile *pFile, geVKFrame_InterpolationType *InterpolationType, int *Looping); +geBoolean GENESISCC geVKFrame_WriteToBinaryFile(geVFile *pFile, void *geVKFrame, + geVKFrame_InterpolationType InterpolationType, int Looping); +geTKArray *GENESISCC geVKFrame_CreateFromBinaryFile(geVFile *pFile, geVKFrame_InterpolationType *InterpolationType, int *Looping); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Actor/xfarray.h b/G3D/Actor/xfarray.h new file mode 100644 index 0000000..21c0db5 --- /dev/null +++ b/G3D/Actor/xfarray.h @@ -0,0 +1,64 @@ +/****************************************************************************************/ +/* XFARRAY.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Array of transforms interface. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_XFARRAY_H +#define GE_XFARRAY_H + +/* This is a simple object to formalize an array of transforms (geXForm3d) + + Unfortunately, it's not a very safe object. + + This object exports data (allows external access to one of it's data members) + This is dangerous - no checking can be done on the use of that data, and no + checking can be done on array boundry conditions. This is on purpose. + + ...In the name of optimal access to the array. +*/ + +#include "xform3d.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct geXFArray geXFArray; + + // Create the object. Creates an array of Size elements. + // All elements are initialized to the identity transform +geXFArray *GENESISCC geXFArray_Create(int Size); + + // Destroy the object. Don't use the pointer returned by _GetElements + // after destroying the ojbect! +void GENESISCC geXFArray_Destroy( geXFArray **XFA ); + + // Get a pointer to the array. For external iteration. The size of the + // array is returned in Size. Valid array indicies are (0..Size-1) +geXForm3d *GENESISCC geXFArray_GetElements(const geXFArray *XFA, int *Size); + + // Sets every transform in the array to the given transform. +void GENESISCC geXFArray_SetAll(geXFArray *XFA, const geXForm3d *Matrix); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/G3D/Afxres.h b/G3D/Afxres.h new file mode 100644 index 0000000..d98da48 --- /dev/null +++ b/G3D/Afxres.h @@ -0,0 +1,774 @@ +// This is a part of the Microsoft Foundation Classes C++ library. +// Copyright (C) 1992-1998 Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Microsoft Foundation Classes Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Microsoft Foundation Classes product. + +#ifndef __AFXRES_H__ +#define __AFXRES_H__ + +#ifdef RC_INVOKED +#ifndef _INC_WINDOWS +#define _INC_WINDOWS +#include // extract from windows header +#endif +#endif + +#ifdef _AFX_MINREBUILD +#pragma component(minrebuild, off) +#endif + +#ifdef APSTUDIO_INVOKED +#define APSTUDIO_HIDDEN_SYMBOLS +#endif + +///////////////////////////////////////////////////////////////////////////// +// MFC resource types (see Technical note TN024 for implementation details) + +#ifndef RC_INVOKED +#define RT_DLGINIT MAKEINTRESOURCE(240) +#define RT_TOOLBAR MAKEINTRESOURCE(241) +#endif + +///////////////////////////////////////////////////////////////////////////// + +#ifdef APSTUDIO_INVOKED +#undef APSTUDIO_HIDDEN_SYMBOLS +#endif + +///////////////////////////////////////////////////////////////////////////// +// General style bits etc + +// ControlBar styles +#define CBRS_ALIGN_LEFT 0x1000L +#define CBRS_ALIGN_TOP 0x2000L +#define CBRS_ALIGN_RIGHT 0x4000L +#define CBRS_ALIGN_BOTTOM 0x8000L +#define CBRS_ALIGN_ANY 0xF000L + +#define CBRS_BORDER_LEFT 0x0100L +#define CBRS_BORDER_TOP 0x0200L +#define CBRS_BORDER_RIGHT 0x0400L +#define CBRS_BORDER_BOTTOM 0x0800L +#define CBRS_BORDER_ANY 0x0F00L + +#define CBRS_TOOLTIPS 0x0010L +#define CBRS_FLYBY 0x0020L +#define CBRS_FLOAT_MULTI 0x0040L +#define CBRS_BORDER_3D 0x0080L +#define CBRS_HIDE_INPLACE 0x0008L +#define CBRS_SIZE_DYNAMIC 0x0004L +#define CBRS_SIZE_FIXED 0x0002L +#define CBRS_FLOATING 0x0001L + +#define CBRS_GRIPPER 0x00400000L + +#define CBRS_ORIENT_HORZ (CBRS_ALIGN_TOP|CBRS_ALIGN_BOTTOM) +#define CBRS_ORIENT_VERT (CBRS_ALIGN_LEFT|CBRS_ALIGN_RIGHT) +#define CBRS_ORIENT_ANY (CBRS_ORIENT_HORZ|CBRS_ORIENT_VERT) + +#define CBRS_ALL 0x0040FFFFL + +// the CBRS_ style is made up of an alignment style and a draw border style +// the alignment styles are mutually exclusive +// the draw border styles may be combined +#define CBRS_NOALIGN 0x00000000L +#define CBRS_LEFT (CBRS_ALIGN_LEFT|CBRS_BORDER_RIGHT) +#define CBRS_TOP (CBRS_ALIGN_TOP|CBRS_BORDER_BOTTOM) +#define CBRS_RIGHT (CBRS_ALIGN_RIGHT|CBRS_BORDER_LEFT) +#define CBRS_BOTTOM (CBRS_ALIGN_BOTTOM|CBRS_BORDER_TOP) + +///////////////////////////////////////////////////////////////////////////// +// Standard window components + +// Mode indicators in status bar - these are routed like commands +#define ID_INDICATOR_EXT 0xE700 // extended selection indicator +#define ID_INDICATOR_CAPS 0xE701 // cap lock indicator +#define ID_INDICATOR_NUM 0xE702 // num lock indicator +#define ID_INDICATOR_SCRL 0xE703 // scroll lock indicator +#define ID_INDICATOR_OVR 0xE704 // overtype mode indicator +#define ID_INDICATOR_REC 0xE705 // record mode indicator +#define ID_INDICATOR_KANA 0xE706 // kana lock indicator + +#define ID_SEPARATOR 0 // special separator value + +#ifndef RC_INVOKED // code only +// Standard control bars (IDW = window ID) +#define AFX_IDW_CONTROLBAR_FIRST 0xE800 +#define AFX_IDW_CONTROLBAR_LAST 0xE8FF + +#define AFX_IDW_TOOLBAR 0xE800 // main Toolbar for window +#define AFX_IDW_STATUS_BAR 0xE801 // Status bar window +#define AFX_IDW_PREVIEW_BAR 0xE802 // PrintPreview Dialog Bar +#define AFX_IDW_RESIZE_BAR 0xE803 // OLE in-place resize bar +#define AFX_IDW_REBAR 0xE804 // COMCTL32 "rebar" Bar +#define AFX_IDW_DIALOGBAR 0xE805 // CDialogBar + +// Note: If your application supports docking toolbars, you should +// not use the following IDs for your own toolbars. The IDs chosen +// are at the top of the first 32 such that the bars will be hidden +// while in print preview mode, and are not likely to conflict with +// IDs your application may have used succesfully in the past. + +#define AFX_IDW_DOCKBAR_TOP 0xE81B +#define AFX_IDW_DOCKBAR_LEFT 0xE81C +#define AFX_IDW_DOCKBAR_RIGHT 0xE81D +#define AFX_IDW_DOCKBAR_BOTTOM 0xE81E +#define AFX_IDW_DOCKBAR_FLOAT 0xE81F + +// Macro for mapping standard control bars to bitmask (limit of 32) +#define AFX_CONTROLBAR_MASK(nIDC) (1L << (nIDC - AFX_IDW_CONTROLBAR_FIRST)) + +// parts of Main Frame +#define AFX_IDW_PANE_FIRST 0xE900 // first pane (256 max) +#define AFX_IDW_PANE_LAST 0xE9ff +#define AFX_IDW_HSCROLL_FIRST 0xEA00 // first Horz scrollbar (16 max) +#define AFX_IDW_VSCROLL_FIRST 0xEA10 // first Vert scrollbar (16 max) + +#define AFX_IDW_SIZE_BOX 0xEA20 // size box for splitters +#define AFX_IDW_PANE_SAVE 0xEA21 // to shift AFX_IDW_PANE_FIRST +#endif //!RC_INVOKED + +#ifndef APSTUDIO_INVOKED + +// common style for form views +#define AFX_WS_DEFAULT_VIEW (WS_CHILD | WS_VISIBLE | WS_BORDER) + +#endif //!APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// Standard app configurable strings + +// for application title (defaults to EXE name or name in constructor) +#define AFX_IDS_APP_TITLE 0xE000 +// idle message bar line +#define AFX_IDS_IDLEMESSAGE 0xE001 +// message bar line when in shift-F1 help mode +#define AFX_IDS_HELPMODEMESSAGE 0xE002 +// document title when editing OLE embedding +#define AFX_IDS_APP_TITLE_EMBEDDING 0xE003 +// company name +#define AFX_IDS_COMPANY_NAME 0xE004 +// object name when server is inplace +#define AFX_IDS_OBJ_TITLE_INPLACE 0xE005 + +///////////////////////////////////////////////////////////////////////////// +// Standard Commands + +// File commands +#define ID_FILE_NEW 0xE100 +#define ID_FILE_OPEN 0xE101 +#define ID_FILE_CLOSE 0xE102 +#define ID_FILE_SAVE 0xE103 +#define ID_FILE_SAVE_AS 0xE104 +#define ID_FILE_PAGE_SETUP 0xE105 +#define ID_FILE_PRINT_SETUP 0xE106 +#define ID_FILE_PRINT 0xE107 +#define ID_FILE_PRINT_DIRECT 0xE108 +#define ID_FILE_PRINT_PREVIEW 0xE109 +#define ID_FILE_UPDATE 0xE10A +#define ID_FILE_SAVE_COPY_AS 0xE10B +#define ID_FILE_SEND_MAIL 0xE10C + +#define ID_FILE_MRU_FIRST 0xE110 +#define ID_FILE_MRU_FILE1 0xE110 // range - 16 max +#define ID_FILE_MRU_FILE2 0xE111 +#define ID_FILE_MRU_FILE3 0xE112 +#define ID_FILE_MRU_FILE4 0xE113 +#define ID_FILE_MRU_FILE5 0xE114 +#define ID_FILE_MRU_FILE6 0xE115 +#define ID_FILE_MRU_FILE7 0xE116 +#define ID_FILE_MRU_FILE8 0xE117 +#define ID_FILE_MRU_FILE9 0xE118 +#define ID_FILE_MRU_FILE10 0xE119 +#define ID_FILE_MRU_FILE11 0xE11A +#define ID_FILE_MRU_FILE12 0xE11B +#define ID_FILE_MRU_FILE13 0xE11C +#define ID_FILE_MRU_FILE14 0xE11D +#define ID_FILE_MRU_FILE15 0xE11E +#define ID_FILE_MRU_FILE16 0xE11F +#define ID_FILE_MRU_LAST 0xE11F + +// Edit commands +#define ID_EDIT_CLEAR 0xE120 +#define ID_EDIT_CLEAR_ALL 0xE121 +#define ID_EDIT_COPY 0xE122 +#define ID_EDIT_CUT 0xE123 +#define ID_EDIT_FIND 0xE124 +#define ID_EDIT_PASTE 0xE125 +#define ID_EDIT_PASTE_LINK 0xE126 +#define ID_EDIT_PASTE_SPECIAL 0xE127 +#define ID_EDIT_REPEAT 0xE128 +#define ID_EDIT_REPLACE 0xE129 +#define ID_EDIT_SELECT_ALL 0xE12A +#define ID_EDIT_UNDO 0xE12B +#define ID_EDIT_REDO 0xE12C + +// Window commands +#define ID_WINDOW_NEW 0xE130 +#define ID_WINDOW_ARRANGE 0xE131 +#define ID_WINDOW_CASCADE 0xE132 +#define ID_WINDOW_TILE_HORZ 0xE133 +#define ID_WINDOW_TILE_VERT 0xE134 +#define ID_WINDOW_SPLIT 0xE135 +#ifndef RC_INVOKED // code only +#define AFX_IDM_WINDOW_FIRST 0xE130 +#define AFX_IDM_WINDOW_LAST 0xE13F +#define AFX_IDM_FIRST_MDICHILD 0xFF00 // window list starts here +#endif //!RC_INVOKED + +// Help and App commands +#define ID_APP_ABOUT 0xE140 +#define ID_APP_EXIT 0xE141 +#define ID_HELP_INDEX 0xE142 +#define ID_HELP_FINDER 0xE143 +#define ID_HELP_USING 0xE144 +#define ID_CONTEXT_HELP 0xE145 // shift-F1 +// special commands for processing help +#define ID_HELP 0xE146 // first attempt for F1 +#define ID_DEFAULT_HELP 0xE147 // last attempt + +// Misc +#define ID_NEXT_PANE 0xE150 +#define ID_PREV_PANE 0xE151 + +// Format +#define ID_FORMAT_FONT 0xE160 + +// OLE commands +#define ID_OLE_INSERT_NEW 0xE200 +#define ID_OLE_EDIT_LINKS 0xE201 +#define ID_OLE_EDIT_CONVERT 0xE202 +#define ID_OLE_EDIT_CHANGE_ICON 0xE203 +#define ID_OLE_EDIT_PROPERTIES 0xE204 +#define ID_OLE_VERB_FIRST 0xE210 // range - 16 max +#ifndef RC_INVOKED // code only +#define ID_OLE_VERB_LAST 0xE21F +#endif //!RC_INVOKED + +// for print preview dialog bar +#define AFX_ID_PREVIEW_CLOSE 0xE300 +#define AFX_ID_PREVIEW_NUMPAGE 0xE301 // One/Two Page button +#define AFX_ID_PREVIEW_NEXT 0xE302 +#define AFX_ID_PREVIEW_PREV 0xE303 +#define AFX_ID_PREVIEW_PRINT 0xE304 +#define AFX_ID_PREVIEW_ZOOMIN 0xE305 +#define AFX_ID_PREVIEW_ZOOMOUT 0xE306 + +// View commands (same number used as IDW used for control bar) +#define ID_VIEW_TOOLBAR 0xE800 +#define ID_VIEW_STATUS_BAR 0xE801 +#define ID_VIEW_REBAR 0xE804 +#define ID_VIEW_AUTOARRANGE 0xE805 + // E810 -> E81F must be kept in order for RANGE macros +#define ID_VIEW_SMALLICON 0xE810 +#define ID_VIEW_LARGEICON 0xE811 +#define ID_VIEW_LIST 0xE812 +#define ID_VIEW_DETAILS 0xE813 +#define ID_VIEW_LINEUP 0xE814 +#define ID_VIEW_BYNAME 0xE815 +#define AFX_ID_VIEW_MINIMUM ID_VIEW_SMALLICON +#define AFX_ID_VIEW_MAXIMUM ID_VIEW_BYNAME + // E800 -> E8FF reserved for other control bar commands + +// RecordForm commands +#define ID_RECORD_FIRST 0xE900 +#define ID_RECORD_LAST 0xE901 +#define ID_RECORD_NEXT 0xE902 +#define ID_RECORD_PREV 0xE903 + +///////////////////////////////////////////////////////////////////////////// +// Standard control IDs + +#ifdef IDC_STATIC +#undef IDC_STATIC +#endif +#define IDC_STATIC (-1) // all static controls + +///////////////////////////////////////////////////////////////////////////// +// Standard string error/warnings + +#ifndef RC_INVOKED // code only +#define AFX_IDS_SCFIRST 0xEF00 +#endif //!RC_INVOKED + +#define AFX_IDS_SCSIZE 0xEF00 +#define AFX_IDS_SCMOVE 0xEF01 +#define AFX_IDS_SCMINIMIZE 0xEF02 +#define AFX_IDS_SCMAXIMIZE 0xEF03 +#define AFX_IDS_SCNEXTWINDOW 0xEF04 +#define AFX_IDS_SCPREVWINDOW 0xEF05 +#define AFX_IDS_SCCLOSE 0xEF06 +#define AFX_IDS_SCRESTORE 0xEF12 +#define AFX_IDS_SCTASKLIST 0xEF13 + +#define AFX_IDS_MDICHILD 0xEF1F + +#define AFX_IDS_DESKACCESSORY 0xEFDA + +// General strings +#define AFX_IDS_OPENFILE 0xF000 +#define AFX_IDS_SAVEFILE 0xF001 +#define AFX_IDS_ALLFILTER 0xF002 +#define AFX_IDS_UNTITLED 0xF003 +#define AFX_IDS_SAVEFILECOPY 0xF004 +#define AFX_IDS_PREVIEW_CLOSE 0xF005 +#define AFX_IDS_UNNAMED_FILE 0xF006 +#define AFX_IDS_HIDE 0xF011 + +// MFC Standard Exception Error messages +#define AFX_IDP_NO_ERROR_AVAILABLE 0xF020 +#define AFX_IDS_NOT_SUPPORTED_EXCEPTION 0xF021 +#define AFX_IDS_RESOURCE_EXCEPTION 0xF022 +#define AFX_IDS_MEMORY_EXCEPTION 0xF023 +#define AFX_IDS_USER_EXCEPTION 0xF024 + +// Printing and print preview strings +#define AFX_IDS_PRINTONPORT 0xF040 +#define AFX_IDS_ONEPAGE 0xF041 +#define AFX_IDS_TWOPAGE 0xF042 +#define AFX_IDS_PRINTPAGENUM 0xF043 +#define AFX_IDS_PREVIEWPAGEDESC 0xF044 +#define AFX_IDS_PRINTDEFAULTEXT 0xF045 +#define AFX_IDS_PRINTDEFAULT 0xF046 +#define AFX_IDS_PRINTFILTER 0xF047 +#define AFX_IDS_PRINTCAPTION 0xF048 +#define AFX_IDS_PRINTTOFILE 0xF049 + + +// OLE strings +#define AFX_IDS_OBJECT_MENUITEM 0xF080 +#define AFX_IDS_EDIT_VERB 0xF081 +#define AFX_IDS_ACTIVATE_VERB 0xF082 +#define AFX_IDS_CHANGE_LINK 0xF083 +#define AFX_IDS_AUTO 0xF084 +#define AFX_IDS_MANUAL 0xF085 +#define AFX_IDS_FROZEN 0xF086 +#define AFX_IDS_ALL_FILES 0xF087 +// dynamically changing menu items +#define AFX_IDS_SAVE_MENU 0xF088 +#define AFX_IDS_UPDATE_MENU 0xF089 +#define AFX_IDS_SAVE_AS_MENU 0xF08A +#define AFX_IDS_SAVE_COPY_AS_MENU 0xF08B +#define AFX_IDS_EXIT_MENU 0xF08C +#define AFX_IDS_UPDATING_ITEMS 0xF08D +// COlePasteSpecialDialog defines +#define AFX_IDS_METAFILE_FORMAT 0xF08E +#define AFX_IDS_DIB_FORMAT 0xF08F +#define AFX_IDS_BITMAP_FORMAT 0xF090 +#define AFX_IDS_LINKSOURCE_FORMAT 0xF091 +#define AFX_IDS_EMBED_FORMAT 0xF092 +// other OLE utility strings +#define AFX_IDS_PASTELINKEDTYPE 0xF094 +#define AFX_IDS_UNKNOWNTYPE 0xF095 +#define AFX_IDS_RTF_FORMAT 0xF096 +#define AFX_IDS_TEXT_FORMAT 0xF097 +// OLE datatype format error strings +#define AFX_IDS_INVALID_CURRENCY 0xF098 +#define AFX_IDS_INVALID_DATETIME 0xF099 +#define AFX_IDS_INVALID_DATETIMESPAN 0xF09A + +// General error / prompt strings +#define AFX_IDP_INVALID_FILENAME 0xF100 +#define AFX_IDP_FAILED_TO_OPEN_DOC 0xF101 +#define AFX_IDP_FAILED_TO_SAVE_DOC 0xF102 +#define AFX_IDP_ASK_TO_SAVE 0xF103 +#define AFX_IDP_FAILED_TO_CREATE_DOC 0xF104 +#define AFX_IDP_FILE_TOO_LARGE 0xF105 +#define AFX_IDP_FAILED_TO_START_PRINT 0xF106 +#define AFX_IDP_FAILED_TO_LAUNCH_HELP 0xF107 +#define AFX_IDP_INTERNAL_FAILURE 0xF108 // general failure +#define AFX_IDP_COMMAND_FAILURE 0xF109 // command failure +#define AFX_IDP_FAILED_MEMORY_ALLOC 0xF10A +#define AFX_IDP_UNREG_DONE 0xF10B +#define AFX_IDP_UNREG_FAILURE 0xF10C +#define AFX_IDP_DLL_LOAD_FAILED 0xF10D +#define AFX_IDP_DLL_BAD_VERSION 0xF10E + +// DDV parse errors +#define AFX_IDP_PARSE_INT 0xF110 +#define AFX_IDP_PARSE_REAL 0xF111 +#define AFX_IDP_PARSE_INT_RANGE 0xF112 +#define AFX_IDP_PARSE_REAL_RANGE 0xF113 +#define AFX_IDP_PARSE_STRING_SIZE 0xF114 +#define AFX_IDP_PARSE_RADIO_BUTTON 0xF115 +#define AFX_IDP_PARSE_BYTE 0xF116 +#define AFX_IDP_PARSE_UINT 0xF117 +#define AFX_IDP_PARSE_DATETIME 0xF118 +#define AFX_IDP_PARSE_CURRENCY 0xF119 + +// CFile/CArchive error strings for user failure +#define AFX_IDP_FAILED_INVALID_FORMAT 0xF120 +#define AFX_IDP_FAILED_INVALID_PATH 0xF121 +#define AFX_IDP_FAILED_DISK_FULL 0xF122 +#define AFX_IDP_FAILED_ACCESS_READ 0xF123 +#define AFX_IDP_FAILED_ACCESS_WRITE 0xF124 +#define AFX_IDP_FAILED_IO_ERROR_READ 0xF125 +#define AFX_IDP_FAILED_IO_ERROR_WRITE 0xF126 + +// OLE errors / prompt strings +#define AFX_IDP_STATIC_OBJECT 0xF180 +#define AFX_IDP_FAILED_TO_CONNECT 0xF181 +#define AFX_IDP_SERVER_BUSY 0xF182 +#define AFX_IDP_BAD_VERB 0xF183 +#define AFX_IDS_NOT_DOCOBJECT 0xF184 +#define AFX_IDP_FAILED_TO_NOTIFY 0xF185 +#define AFX_IDP_FAILED_TO_LAUNCH 0xF186 +#define AFX_IDP_ASK_TO_UPDATE 0xF187 +#define AFX_IDP_FAILED_TO_UPDATE 0xF188 +#define AFX_IDP_FAILED_TO_REGISTER 0xF189 +#define AFX_IDP_FAILED_TO_AUTO_REGISTER 0xF18A +#define AFX_IDP_FAILED_TO_CONVERT 0xF18B +#define AFX_IDP_GET_NOT_SUPPORTED 0xF18C +#define AFX_IDP_SET_NOT_SUPPORTED 0xF18D +#define AFX_IDP_ASK_TO_DISCARD 0xF18E +#define AFX_IDP_FAILED_TO_CREATE 0xF18F + +// MAPI errors / prompt strings +#define AFX_IDP_FAILED_MAPI_LOAD 0xF190 +#define AFX_IDP_INVALID_MAPI_DLL 0xF191 +#define AFX_IDP_FAILED_MAPI_SEND 0xF192 + +#define AFX_IDP_FILE_NONE 0xF1A0 +#define AFX_IDP_FILE_GENERIC 0xF1A1 +#define AFX_IDP_FILE_NOT_FOUND 0xF1A2 +#define AFX_IDP_FILE_BAD_PATH 0xF1A3 +#define AFX_IDP_FILE_TOO_MANY_OPEN 0xF1A4 +#define AFX_IDP_FILE_ACCESS_DENIED 0xF1A5 +#define AFX_IDP_FILE_INVALID_FILE 0xF1A6 +#define AFX_IDP_FILE_REMOVE_CURRENT 0xF1A7 +#define AFX_IDP_FILE_DIR_FULL 0xF1A8 +#define AFX_IDP_FILE_BAD_SEEK 0xF1A9 +#define AFX_IDP_FILE_HARD_IO 0xF1AA +#define AFX_IDP_FILE_SHARING 0xF1AB +#define AFX_IDP_FILE_LOCKING 0xF1AC +#define AFX_IDP_FILE_DISKFULL 0xF1AD +#define AFX_IDP_FILE_EOF 0xF1AE + +#define AFX_IDP_ARCH_NONE 0xF1B0 +#define AFX_IDP_ARCH_GENERIC 0xF1B1 +#define AFX_IDP_ARCH_READONLY 0xF1B2 +#define AFX_IDP_ARCH_ENDOFFILE 0xF1B3 +#define AFX_IDP_ARCH_WRITEONLY 0xF1B4 +#define AFX_IDP_ARCH_BADINDEX 0xF1B5 +#define AFX_IDP_ARCH_BADCLASS 0xF1B6 +#define AFX_IDP_ARCH_BADSCHEMA 0xF1B7 + +#define AFX_IDS_OCC_SCALEUNITS_PIXELS 0xF1C0 + +// 0xf200-0xf20f reserved + +// font names and point sizes +#define AFX_IDS_STATUS_FONT 0xF230 +#define AFX_IDS_TOOLTIP_FONT 0xF231 +#define AFX_IDS_UNICODE_FONT 0xF232 +#define AFX_IDS_MINI_FONT 0xF233 + +// ODBC Database errors / prompt strings +#ifndef RC_INVOKED // code only +#define AFX_IDP_SQL_FIRST 0xF280 +#endif //!RC_INVOKED +#define AFX_IDP_SQL_CONNECT_FAIL 0xF281 +#define AFX_IDP_SQL_RECORDSET_FORWARD_ONLY 0xF282 +#define AFX_IDP_SQL_EMPTY_COLUMN_LIST 0xF283 +#define AFX_IDP_SQL_FIELD_SCHEMA_MISMATCH 0xF284 +#define AFX_IDP_SQL_ILLEGAL_MODE 0xF285 +#define AFX_IDP_SQL_MULTIPLE_ROWS_AFFECTED 0xF286 +#define AFX_IDP_SQL_NO_CURRENT_RECORD 0xF287 +#define AFX_IDP_SQL_NO_ROWS_AFFECTED 0xF288 +#define AFX_IDP_SQL_RECORDSET_READONLY 0xF289 +#define AFX_IDP_SQL_SQL_NO_TOTAL 0xF28A +#define AFX_IDP_SQL_ODBC_LOAD_FAILED 0xF28B +#define AFX_IDP_SQL_DYNASET_NOT_SUPPORTED 0xF28C +#define AFX_IDP_SQL_SNAPSHOT_NOT_SUPPORTED 0xF28D +#define AFX_IDP_SQL_API_CONFORMANCE 0xF28E +#define AFX_IDP_SQL_SQL_CONFORMANCE 0xF28F +#define AFX_IDP_SQL_NO_DATA_FOUND 0xF290 +#define AFX_IDP_SQL_ROW_UPDATE_NOT_SUPPORTED 0xF291 +#define AFX_IDP_SQL_ODBC_V2_REQUIRED 0xF292 +#define AFX_IDP_SQL_NO_POSITIONED_UPDATES 0xF293 +#define AFX_IDP_SQL_LOCK_MODE_NOT_SUPPORTED 0xF294 +#define AFX_IDP_SQL_DATA_TRUNCATED 0xF295 +#define AFX_IDP_SQL_ROW_FETCH 0xF296 +#define AFX_IDP_SQL_INCORRECT_ODBC 0xF297 +#define AFX_IDP_SQL_UPDATE_DELETE_FAILED 0xF298 +#define AFX_IDP_SQL_DYNAMIC_CURSOR_NOT_SUPPORTED 0xF299 +#define AFX_IDP_SQL_FIELD_NOT_FOUND 0xF29A +#define AFX_IDP_SQL_BOOKMARKS_NOT_SUPPORTED 0xF29B +#define AFX_IDP_SQL_BOOKMARKS_NOT_ENABLED 0xF29C + +// ODBC Database strings +#define AFX_IDS_DELETED 0xF29D + +// DAO Database errors / prompt strings +#ifndef RC_INVOKED // code only +#define AFX_IDP_DAO_FIRST 0xF2B0 +#endif //!RC_INVOKED +#define AFX_IDP_DAO_ENGINE_INITIALIZATION 0xF2B0 +#define AFX_IDP_DAO_DFX_BIND 0xF2B1 +#define AFX_IDP_DAO_OBJECT_NOT_OPEN 0xF2B2 + +// ICDAORecordset::GetRows Errors +// These are not placed in DAO Errors collection +// and must be handled directly by MFC. +#define AFX_IDP_DAO_ROWTOOSHORT 0xF2B3 +#define AFX_IDP_DAO_BADBINDINFO 0xF2B4 +#define AFX_IDP_DAO_COLUMNUNAVAILABLE 0xF2B5 + +///////////////////////////////////////////////////////////////////////////// +// Strings for ISAPI support + +#define AFX_IDS_HTTP_TITLE 0xF2D1 +#define AFX_IDS_HTTP_NO_TEXT 0xF2D2 +#define AFX_IDS_HTTP_BAD_REQUEST 0xF2D3 +#define AFX_IDS_HTTP_AUTH_REQUIRED 0xF2D4 +#define AFX_IDS_HTTP_FORBIDDEN 0xF2D5 +#define AFX_IDS_HTTP_NOT_FOUND 0xF2D6 +#define AFX_IDS_HTTP_SERVER_ERROR 0xF2D7 +#define AFX_IDS_HTTP_NOT_IMPLEMENTED 0xF2D8 + +///////////////////////////////////////////////////////////////////////////// +// AFX implementation - control IDs (AFX_IDC) + +// Parts of dialogs +#define AFX_IDC_LISTBOX 100 +#define AFX_IDC_CHANGE 101 + +// for print dialog +#define AFX_IDC_PRINT_DOCNAME 201 +#define AFX_IDC_PRINT_PRINTERNAME 202 +#define AFX_IDC_PRINT_PORTNAME 203 +#define AFX_IDC_PRINT_PAGENUM 204 + +// Property Sheet control id's (determined with Spy++) +#define ID_APPLY_NOW 0x3021 +#define ID_WIZBACK 0x3023 +#define ID_WIZNEXT 0x3024 +#define ID_WIZFINISH 0x3025 +#define AFX_IDC_TAB_CONTROL 0x3020 + +///////////////////////////////////////////////////////////////////////////// +// IDRs for standard components + +#ifndef RC_INVOKED // code only +// These are really COMMDLG dialogs, so there usually isn't a resource +// for them, but these IDs are used as help IDs. +#define AFX_IDD_FILEOPEN 28676 +#define AFX_IDD_FILESAVE 28677 +#define AFX_IDD_FONT 28678 +#define AFX_IDD_COLOR 28679 +#define AFX_IDD_PRINT 28680 +#define AFX_IDD_PRINTSETUP 28681 +#define AFX_IDD_FIND 28682 +#define AFX_IDD_REPLACE 28683 +#endif //!RC_INVOKED + +// Standard dialogs app should leave alone (0x7801->) +#define AFX_IDD_NEWTYPEDLG 30721 +#define AFX_IDD_PRINTDLG 30722 +#define AFX_IDD_PREVIEW_TOOLBAR 30723 + +// Dialogs defined for OLE2UI library +#define AFX_IDD_INSERTOBJECT 30724 +#define AFX_IDD_CHANGEICON 30725 +#define AFX_IDD_CONVERT 30726 +#define AFX_IDD_PASTESPECIAL 30727 +#define AFX_IDD_EDITLINKS 30728 +#define AFX_IDD_FILEBROWSE 30729 +#define AFX_IDD_BUSY 30730 + +#define AFX_IDD_OBJECTPROPERTIES 30732 +#define AFX_IDD_CHANGESOURCE 30733 + +// Standard cursors (0x7901->) + // AFX_IDC = Cursor resources +#define AFX_IDC_CONTEXTHELP 30977 // context sensitive help +#define AFX_IDC_MAGNIFY 30978 // print preview zoom +#define AFX_IDC_SMALLARROWS 30979 // splitter +#define AFX_IDC_HSPLITBAR 30980 // splitter +#define AFX_IDC_VSPLITBAR 30981 // splitter +#define AFX_IDC_NODROPCRSR 30982 // No Drop Cursor +#define AFX_IDC_TRACKNWSE 30983 // tracker +#define AFX_IDC_TRACKNESW 30984 // tracker +#define AFX_IDC_TRACKNS 30985 // tracker +#define AFX_IDC_TRACKWE 30986 // tracker +#define AFX_IDC_TRACK4WAY 30987 // tracker +#define AFX_IDC_MOVE4WAY 30988 // resize bar (server only) + +// Mini frame window bitmap ID +#define AFX_IDB_MINIFRAME_MENU 30994 + +// CheckListBox checks bitmap ID +#define AFX_IDB_CHECKLISTBOX_NT 30995 +#define AFX_IDB_CHECKLISTBOX_95 30996 + +// AFX standard accelerator resources +#define AFX_IDR_PREVIEW_ACCEL 30997 + +// AFX standard ICON IDs (for MFC V1 apps) (0x7A01->) +#define AFX_IDI_STD_MDIFRAME 31233 +#define AFX_IDI_STD_FRAME 31234 + +///////////////////////////////////////////////////////////////////////////// +// AFX OLE control implementation - control IDs (AFX_IDC) + +// Font property page +#define AFX_IDC_FONTPROP 1000 +#define AFX_IDC_FONTNAMES 1001 +#define AFX_IDC_FONTSTYLES 1002 +#define AFX_IDC_FONTSIZES 1003 +#define AFX_IDC_STRIKEOUT 1004 +#define AFX_IDC_UNDERLINE 1005 +#define AFX_IDC_SAMPLEBOX 1006 + +// Color property page +#define AFX_IDC_COLOR_BLACK 1100 +#define AFX_IDC_COLOR_WHITE 1101 +#define AFX_IDC_COLOR_RED 1102 +#define AFX_IDC_COLOR_GREEN 1103 +#define AFX_IDC_COLOR_BLUE 1104 +#define AFX_IDC_COLOR_YELLOW 1105 +#define AFX_IDC_COLOR_MAGENTA 1106 +#define AFX_IDC_COLOR_CYAN 1107 +#define AFX_IDC_COLOR_GRAY 1108 +#define AFX_IDC_COLOR_LIGHTGRAY 1109 +#define AFX_IDC_COLOR_DARKRED 1110 +#define AFX_IDC_COLOR_DARKGREEN 1111 +#define AFX_IDC_COLOR_DARKBLUE 1112 +#define AFX_IDC_COLOR_LIGHTBROWN 1113 +#define AFX_IDC_COLOR_DARKMAGENTA 1114 +#define AFX_IDC_COLOR_DARKCYAN 1115 +#define AFX_IDC_COLORPROP 1116 +#define AFX_IDC_SYSTEMCOLORS 1117 + +// Picture porperty page +#define AFX_IDC_PROPNAME 1201 +#define AFX_IDC_PICTURE 1202 +#define AFX_IDC_BROWSE 1203 +#define AFX_IDC_CLEAR 1204 + +///////////////////////////////////////////////////////////////////////////// +// IDRs for OLE control standard components + +// Standard propery page dialogs app should leave alone (0x7E01->) +#define AFX_IDD_PROPPAGE_COLOR 32257 +#define AFX_IDD_PROPPAGE_FONT 32258 +#define AFX_IDD_PROPPAGE_PICTURE 32259 + +#define AFX_IDB_TRUETYPE 32384 + +///////////////////////////////////////////////////////////////////////////// +// Standard OLE control strings + +// OLE Control page strings +#define AFX_IDS_PROPPAGE_UNKNOWN 0xFE01 +#define AFX_IDS_COLOR_DESKTOP 0xFE04 +#define AFX_IDS_COLOR_APPWORKSPACE 0xFE05 +#define AFX_IDS_COLOR_WNDBACKGND 0xFE06 +#define AFX_IDS_COLOR_WNDTEXT 0xFE07 +#define AFX_IDS_COLOR_MENUBAR 0xFE08 +#define AFX_IDS_COLOR_MENUTEXT 0xFE09 +#define AFX_IDS_COLOR_ACTIVEBAR 0xFE0A +#define AFX_IDS_COLOR_INACTIVEBAR 0xFE0B +#define AFX_IDS_COLOR_ACTIVETEXT 0xFE0C +#define AFX_IDS_COLOR_INACTIVETEXT 0xFE0D +#define AFX_IDS_COLOR_ACTIVEBORDER 0xFE0E +#define AFX_IDS_COLOR_INACTIVEBORDER 0xFE0F +#define AFX_IDS_COLOR_WNDFRAME 0xFE10 +#define AFX_IDS_COLOR_SCROLLBARS 0xFE11 +#define AFX_IDS_COLOR_BTNFACE 0xFE12 +#define AFX_IDS_COLOR_BTNSHADOW 0xFE13 +#define AFX_IDS_COLOR_BTNTEXT 0xFE14 +#define AFX_IDS_COLOR_BTNHIGHLIGHT 0xFE15 +#define AFX_IDS_COLOR_DISABLEDTEXT 0xFE16 +#define AFX_IDS_COLOR_HIGHLIGHT 0xFE17 +#define AFX_IDS_COLOR_HIGHLIGHTTEXT 0xFE18 +#define AFX_IDS_REGULAR 0xFE19 +#define AFX_IDS_BOLD 0xFE1A +#define AFX_IDS_ITALIC 0xFE1B +#define AFX_IDS_BOLDITALIC 0xFE1C +#define AFX_IDS_SAMPLETEXT 0xFE1D +#define AFX_IDS_DISPLAYSTRING_FONT 0xFE1E +#define AFX_IDS_DISPLAYSTRING_COLOR 0xFE1F +#define AFX_IDS_DISPLAYSTRING_PICTURE 0xFE20 +#define AFX_IDS_PICTUREFILTER 0xFE21 +#define AFX_IDS_PICTYPE_UNKNOWN 0xFE22 +#define AFX_IDS_PICTYPE_NONE 0xFE23 +#define AFX_IDS_PICTYPE_BITMAP 0xFE24 +#define AFX_IDS_PICTYPE_METAFILE 0xFE25 +#define AFX_IDS_PICTYPE_ICON 0xFE26 +#define AFX_IDS_COLOR_PPG 0xFE28 +#define AFX_IDS_COLOR_PPG_CAPTION 0xFE29 +#define AFX_IDS_FONT_PPG 0xFE2A +#define AFX_IDS_FONT_PPG_CAPTION 0xFE2B +#define AFX_IDS_PICTURE_PPG 0xFE2C +#define AFX_IDS_PICTURE_PPG_CAPTION 0xFE2D +#define AFX_IDS_PICTUREBROWSETITLE 0xFE30 +#define AFX_IDS_BORDERSTYLE_0 0xFE31 +#define AFX_IDS_BORDERSTYLE_1 0xFE32 + +// OLE Control verb names +#define AFX_IDS_VERB_EDIT 0xFE40 +#define AFX_IDS_VERB_PROPERTIES 0xFE41 + +// OLE Control internal error messages +#define AFX_IDP_PICTURECANTOPEN 0xFE83 +#define AFX_IDP_PICTURECANTLOAD 0xFE84 +#define AFX_IDP_PICTURETOOLARGE 0xFE85 +#define AFX_IDP_PICTUREREADFAILED 0xFE86 + +// Standard OLE Control error strings +#define AFX_IDP_E_ILLEGALFUNCTIONCALL 0xFEA0 +#define AFX_IDP_E_OVERFLOW 0xFEA1 +#define AFX_IDP_E_OUTOFMEMORY 0xFEA2 +#define AFX_IDP_E_DIVISIONBYZERO 0xFEA3 +#define AFX_IDP_E_OUTOFSTRINGSPACE 0xFEA4 +#define AFX_IDP_E_OUTOFSTACKSPACE 0xFEA5 +#define AFX_IDP_E_BADFILENAMEORNUMBER 0xFEA6 +#define AFX_IDP_E_FILENOTFOUND 0xFEA7 +#define AFX_IDP_E_BADFILEMODE 0xFEA8 +#define AFX_IDP_E_FILEALREADYOPEN 0xFEA9 +#define AFX_IDP_E_DEVICEIOERROR 0xFEAA +#define AFX_IDP_E_FILEALREADYEXISTS 0xFEAB +#define AFX_IDP_E_BADRECORDLENGTH 0xFEAC +#define AFX_IDP_E_DISKFULL 0xFEAD +#define AFX_IDP_E_BADRECORDNUMBER 0xFEAE +#define AFX_IDP_E_BADFILENAME 0xFEAF +#define AFX_IDP_E_TOOMANYFILES 0xFEB0 +#define AFX_IDP_E_DEVICEUNAVAILABLE 0xFEB1 +#define AFX_IDP_E_PERMISSIONDENIED 0xFEB2 +#define AFX_IDP_E_DISKNOTREADY 0xFEB3 +#define AFX_IDP_E_PATHFILEACCESSERROR 0xFEB4 +#define AFX_IDP_E_PATHNOTFOUND 0xFEB5 +#define AFX_IDP_E_INVALIDPATTERNSTRING 0xFEB6 +#define AFX_IDP_E_INVALIDUSEOFNULL 0xFEB7 +#define AFX_IDP_E_INVALIDFILEFORMAT 0xFEB8 +#define AFX_IDP_E_INVALIDPROPERTYVALUE 0xFEB9 +#define AFX_IDP_E_INVALIDPROPERTYARRAYINDEX 0xFEBA +#define AFX_IDP_E_SETNOTSUPPORTEDATRUNTIME 0xFEBB +#define AFX_IDP_E_SETNOTSUPPORTED 0xFEBC +#define AFX_IDP_E_NEEDPROPERTYARRAYINDEX 0xFEBD +#define AFX_IDP_E_SETNOTPERMITTED 0xFEBE +#define AFX_IDP_E_GETNOTSUPPORTEDATRUNTIME 0xFEBF +#define AFX_IDP_E_GETNOTSUPPORTED 0xFEC0 +#define AFX_IDP_E_PROPERTYNOTFOUND 0xFEC1 +#define AFX_IDP_E_INVALIDCLIPBOARDFORMAT 0xFEC2 +#define AFX_IDP_E_INVALIDPICTURE 0xFEC3 +#define AFX_IDP_E_PRINTERERROR 0xFEC4 +#define AFX_IDP_E_CANTSAVEFILETOTEMP 0xFEC5 +#define AFX_IDP_E_SEARCHTEXTNOTFOUND 0xFEC6 +#define AFX_IDP_E_REPLACEMENTSTOOLONG 0xFEC7 + +///////////////////////////////////////////////////////////////////////////// + +#ifdef _AFX_MINREBUILD +#pragma component(minrebuild, on) +#endif + +#endif //__AFXRES_H__ + +///////////////////////////////////////////////////////////////////////////// diff --git a/G3D/Basetype.h b/G3D/Basetype.h new file mode 100644 index 0000000..d219f53 --- /dev/null +++ b/G3D/Basetype.h @@ -0,0 +1,85 @@ +/****************************************************************************************/ +/* BASETYPE.H */ +/* */ +/* Author: */ +/* Description: Basic type definitions and calling convention defines */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_BASETYPE_H +#define GE_BASETYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/******** The Genesis Calling Conventions ***********/ + +#define GENESISCC _fastcall + +#if defined(BUILDGENESIS) && defined(GENESISDLLVERSION) + #define GENESISAPI _declspec(dllexport) +#else + #if defined(GENESISDLLVERSION) + #define GENESISAPI _declspec(dllimport) + #else + #define GENESISAPI + #endif +#endif + +/******** The Basic Types ****************************/ + +typedef signed int geBoolean; +#define GE_FALSE (0) +#define GE_TRUE (1) + +typedef float geFloat; +typedef double geDouble; + +#ifndef NULL +/* #define NULL ((void *)0) */ +#define NULL 0 +#endif + +typedef signed long int32; +typedef signed short int16; +typedef signed char int8 ; +typedef unsigned long uint32; +typedef unsigned short uint16; +typedef unsigned char uint8 ; + +/******** Macros on Genesis basic types *************/ + +#define GE_ABS(x) ( (x) < 0 ? (-(x)) : (x) ) +#define GE_CLAMP(x,lo,hi) ( (x) < (lo) ? (lo) : ( (x) > (hi) ? (hi) : (x) ) ) +#define GE_CLAMP8(x) GE_CLAMP(x,0,255) +#define GE_CLAMP16(x) GE_CLAMP(x,0,65536) +#define GE_BOOLSAME(x,y) ( ( (x) && (y) ) || ( !(x) && !(y) ) ) + +#define GE_EPSILON ((geFloat)0.000797f) +#define GE_FLOATS_EQUAL(x,y) ( GE_ABS((x) - (y)) < GE_EPSILON ) +#define GE_FLOAT_ISZERO(x) GE_FLOATS_EQUAL(x,0.0f) + +#define GE_PI ((geFloat)3.14159265358979323846f) + +/****************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Bitmap/Compression/palcreate.c b/G3D/Bitmap/Compression/palcreate.c new file mode 100644 index 0000000..f86a0f2 --- /dev/null +++ b/G3D/Bitmap/Compression/palcreate.c @@ -0,0 +1,899 @@ +/*}{*************************************************/ + +/****************************************************************************************/ +/* PalCreate */ +/* */ +/* Author: Charles Bloom */ +/* Description: Palette Creation code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +/********** + +createPalGood goes in about 0.8 seconds +with about 0.5 of those in the "CreatePalOctTree" function + +// <> could use Optimize + +--------------- + +createPaletteFast : + trivial kludge: + gather colors in an octree + sorts colors on popularity + adds them to the palette, trying to avoiding adding extremely similar colors + has some speed-ups (like croppping low-count leaves) + +createPaletteGood : + this is the "optimal" octree color quantizer. (see below, note on non-optimality) + it is *VERY FAST* ! + gather all colors in an octree + prune isolated strands so all nodes have > 1 kids + the primary action is a "collapse" move: + a leaf is cut, so that its color will be mapped to a sibling + if it has no siblings, the color gets mapped to its parent + each leaf keeps track of the "cost" (= increase in MSE) of cutting it + each node has color which is the weighted average of its children + the "cost" of a node, is the cost of all its children, plus the cost to + move its new centroid. This is exact, it's kind of subtle. see later + we keep removing the node which has the lowest cost to cut + (we use a radix sort to sort on cutCost ; this gives us the speed win) + +my fast (incremental) way to compute the GE_TRUE node cost : + GE_TRUE_cost = Sum[kids] kid_count * (kid_color - new_color)^2 + my_cost = Sum[kids] kid_count * (kid_color - node_color)^2 + + node_count * (node_color - new_color)^2 + + GE_TRUE_cost = Sum[kids] kid_count * (kid_color - new_color)^2 + = Sum[kids] kid_count * ((kid_color - node_color) + (node_color - new_color))^2 + = Sum[kids] kid_count * ((kid_color - node_color)^2 + (node_color - new_color)^2 + + 2 * (kid_color - node_color) * (node_color - new_color)) + = approx_cost + 2 * (node_color - new_color) * { Sum[kids] kid_count * (kid_color - node_color) } + + the correction here is exactly zero! why : + Sum[kids] kid_count * (kid_color - node_color) = (Sum[kids] kid_count * kid_color) - node_count * node_color = 0 ! + since that's the definition of node_color ! + +why this isn't exactly optimal: + because octree children without the same parent are never grouped. + the classic example is in the binary tree, values 128 and 127 should have a cost of 1 to be + merged together, but 128 will be merged with all values > 128 first. + that is, the square boundaries of the tree are unnatural cuts in color space. + this means that the "cutCost" is not accurate; there could be an actual lower MSE cost + than our cutCost. + furthermore, cutCost should be relative to all other leaves, not to their parent nodes, + so that when I cut one leaf it changes the cutCosts of all other leaves. + +***********/ +/*}{*************************************************/ + +#include "palcreate.h" +#include "tsc.h" +#include "paloptimize.h" +#include "ram.h" +#include "yuv.h" +#include "mempool.h" +#include "utility.h" // delete macro +#include +#include + +/*******/ + +#define allocate(ptr) ptr = geRam_AllocateClear(sizeof(*ptr)) +#define clear(ptr) memset(ptr,0,sizeof(*ptr)) + +/*}{*************************************************/ + +geBitmap_Palette * createPaletteGood(const geBitmap_Info * Info,const void * Bits); +geBitmap_Palette * createPaletteFast(const geBitmap_Info * Info,const void * Bits); + +paletteCreater myPaletteCreater = createPaletteGood; + +void setCreatePaletteFunc(paletteCreater func) +{ + assert( func == createPaletteGood || func == createPaletteFast ); + myPaletteCreater = func; +} + +geBitmap_Palette * createPalette(const geBitmap_Info * Info,const void * Bits) +{ + assert(Info && Bits); + switch(Info->Format) + { + case GE_PIXELFORMAT_8BIT_PAL : + return Info->Palette; + case GE_PIXELFORMAT_8BIT_GRAY : + { + geBitmap_Palette * Pal; + uint8 GrayPal[256]; + int i; + Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_8BIT_GRAY,256); + if ( ! Pal ) return NULL; + for(i=0;i<256;i++) GrayPal[i] = i; + geBitmap_Palette_SetData(Pal,GrayPal,GE_PIXELFORMAT_8BIT_GRAY,256); + return Pal; + } + default: + return myPaletteCreater(Info,Bits); + } +} + +geBitmap_Palette * createPaletteFromBitmap(const geBitmap * Bitmap,geBoolean Optimize) +{ +geBitmap * Lock; +geBitmap_Info Info; +const void * Bits; +geBitmap_Palette * Pal; + + if ( ! geBitmap_GetInfo(Bitmap,&Info,NULL) ) + return NULL; + + if ( ! geBitmap_LockForRead((geBitmap *)Bitmap,&Lock,0,0,GE_PIXELFORMAT_24BIT_RGB,GE_FALSE,0) ) + return NULL; + + if ( ! geBitmap_GetInfo(Lock,&Info,NULL) ) + return NULL; + + Bits = (const void *) geBitmap_GetBits(Lock); + + Pal = createPalette(&Info,Bits); + + if ( Pal && Optimize ) + { + uint8 paldata[768]; + + if ( ! geBitmap_Palette_GetData(Pal,paldata,GE_PIXELFORMAT_24BIT_RGB,256) ) + assert(0); + + paletteOptimize(&Info,Bits,paldata,256,0); + + if ( ! geBitmap_Palette_SetData(Pal,paldata,GE_PIXELFORMAT_24BIT_RGB,256) ) + assert(0); + } + + geBitmap_UnLock(Lock); + +return Pal; +} + +/*}{*************************************************/ + +typedef struct octNode octNode; +struct octNode +{ + octNode * kids[8]; + octNode * parent; + int count,nKids; + int R,G,B; + + // for the pruner: + uint32 cutCost; // this could overflow in the upper root nodes + octNode *prev,*next; // sorted linked list of leaves +}; + +#define square(x) ((x)*(x)) + +#define RGBbits(R,G,B,bits) (((((R)>>(bits))&1)<<2) + ((((G)>>(bits))&1)<<1) + (((B)>>((bits)))&1)) + +#define RADIX_SIZE 1024 + +int createOctTree(octNode * root,const geBitmap_Info * Info,const void * Bits,geBoolean doYUV); +geBitmap_Palette * createPaletteGoodSub(const geBitmap_Info * Info,const void * Bits); +void addOctNode(octNode *root,int R,int G,int B,int *nLeavesPtr); +void gatherLeaves(octNode *node,octNode *** leavesPtrPtr,int minCount); +void gatherLeavesCutting(octNode *node,octNode *** leavesPtrPtr); +int leafCompareCount(const void *a,const void *b); +int leafCompareCost(const void *a,const void *b); +int findClosest(int R,int G,int B,uint8 *palette,int palEntries,int *foundPalPtr); +void computeOctRGBs(octNode *node); +void computeCutCosts(octNode *node); +void readLeavesToPal(octNode **leaves,int gotLeaves,uint8 *palette,int palEntries); +void insertRadix(octNode * radix,octNode *leaf); + +/*}{*************************************************/ + +static MemPool * octNodePool = NULL; +static int PoolRefs = 0; + +void PalCreate_Start(void) +{ + if ( PoolRefs == 0 ) + { + int num; + // we do addOctNode, one for each unique color + // make the poolhunks 64k + num = (1<<16) / sizeof(octNode); + octNodePool = MemPool_Create(sizeof(octNode),num,num); + assert(octNodePool); + } + PoolRefs ++; +} + +void PalCreate_Stop(void) +{ + PoolRefs --; + if ( PoolRefs == 0 ) + { + MemPool_Destroy(&octNodePool); + } +} + +/*}{*************************************************/ + +geBitmap_Palette * createPaletteFast(const geBitmap_Info * Info,const void * Bits) +{ +octNode * root; +int nLeaves,minCount,gotLeaves; +octNode ** leaves,**leavesPtr; +uint8 palette[768]; +int palEntries = 256; +geBitmap_Palette * Pal; + + pushTSC(); + + // read the whole image into an octree + // this is the only pass over the input plane + + MemPool_Reset(octNodePool); + root = MemPool_GetHunk(octNodePool); + assert(root); + nLeaves = createOctTree(root,Info,Bits,GE_FALSE); + + leaves = geRam_AllocateClear(sizeof(octNode *)*nLeaves); + assert(leaves); + + // gather leaves into a linear array + // for speed we ignore leaves with a count lower than [x] + + gotLeaves = 0; + for( minCount = 3; minCount >= 0 && gotLeaves < palEntries ; minCount-- ) + { + leavesPtr = leaves; + gatherLeaves(root,&leavesPtr,minCount); + gotLeaves = ((uint32)leavesPtr - (uint32)leaves)/sizeof(octNode *); + } + + // sort the leaves by count + + qsort(leaves,gotLeaves,sizeof(octNode *),leafCompareCount); + + // read the sorted leaves in by count; we try to only read in leaves + // that are farther than 'minDistance' from nodes already in the palette + + readLeavesToPal(leaves,gotLeaves,palette,palEntries); + + destroy(leaves); + + showPopTSC("createPalFast"); + + Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_24BIT_RGB,palEntries); + if ( ! Pal ) + return NULL; + if ( ! geBitmap_Palette_SetData(Pal,palette,GE_PIXELFORMAT_24BIT_RGB,palEntries) ) + assert(0); +return Pal; +} + +/*}{*************************************************/ + +geBitmap_Palette * createPaletteGood(const geBitmap_Info * Info,const void * Bits) +{ + return createPaletteGoodSub(Info,Bits); +} + +geBitmap_Palette * createPaletteGoodSub(const geBitmap_Info * Info,const void * Bits) +{ +octNode * root; +int nLeaves,i,gotLeaves,radixN; +octNode ** leaves,**leavesPtr; +octNode *leaf,*node; +octNode *radix; +uint8 palette[768],*palPtr; +int palEntries = 256; +geBitmap_Palette * Pal; + + pushTSC(); + + // read the whole image into an octree + // this is the only pass over the input plane + + MemPool_Reset(octNodePool); + root = MemPool_GetHunk(octNodePool); + assert(root); + + nLeaves = createOctTree(root,Info,Bits,GE_TRUE); + + leaves = geRam_AllocateClear(sizeof(octNode *)*nLeaves); + assert(leaves); + + computeOctRGBs(root); + root->parent = root; + computeCutCosts(root); + root->parent = NULL; + + // gather leaves into a linear array + // for speed we ignore leaves with a count lower than [x] + + leavesPtr = leaves; + gatherLeavesCutting(root,&leavesPtr); + gotLeaves = ((uint32)leavesPtr - (uint32)leaves)/sizeof(octNode *); + + // if gotLeaves < palEntries, just exit asap + if ( gotLeaves < palEntries ) + { + readLeavesToPal(leaves,gotLeaves,palette,palEntries); + goto done; + } + + // sort the leaves by cutCost + // radix sort instead of qsort + + radix = geRam_AllocateClear(sizeof(octNode)*RADIX_SIZE); + assert(radix); + + for(i=0;i palEntries) + { + while( (leaf = radix[radixN].next) == &(radix[radixN]) ) + { + radixN++; + assert( radixN < RADIX_SIZE ); + } + // cut it + leaf->prev->next = leaf->next; + leaf->next->prev = leaf->prev; + + node = leaf->parent; + assert(node); + node->nKids --; + + // might turn its parent into a leaf; + // if so, add it to the list + // nKids no longer corresponds to the actual number of active kids + + if ( node->nKids == 0 ) + insertRadix(radix,node); + else + gotLeaves--; + } + + // read the sorted leaves in by count; we try to only read in leaves + // that are farther than 'minDistance' from nodes already in the palette + + palPtr = palette; + radixN = RADIX_SIZE-1; + leaf = radix[radixN].prev; + for(i=0;i0;i++) + { + *palPtr++ = leaf->R; + *palPtr++ = leaf->G; + *palPtr++ = leaf->B; + leaf = leaf->prev; + while ( leaf == &(radix[radixN]) ) + { + radixN --; + if ( ! radixN ) + break; + leaf = radix[radixN].prev; + } + } + + destroy(radix); + +done: + + destroy(leaves); + + showPopTSC("createPalGood"); + + YUVb_to_RGBb_line(palette,palette,palEntries); + + Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_24BIT_RGB,palEntries); + if ( ! Pal ) + return NULL; + + if ( ! geBitmap_Palette_SetData(Pal,palette,GE_PIXELFORMAT_24BIT_RGB,palEntries) ) + assert(0); + +return Pal; +} + +/*}{*************************************************/ + +void insertRadix(octNode * radix,octNode *leaf) +{ +octNode *insertAt; + + if ( leaf->cutCost >= RADIX_SIZE ) + { + octNode * head; + insertAt = head = & radix[RADIX_SIZE-1]; + while(insertAt->cutCost < leaf->cutCost && insertAt->next != head ) + insertAt = insertAt->next; + } + else + insertAt = & radix[leaf->cutCost]; + + leaf->next = insertAt->next; + leaf->next->prev = leaf; + insertAt->next = leaf; + insertAt->next->prev = insertAt; +} + +int findClosest(int R,int G,int B,uint8 *palette,int palEntries,int *foundPalPtr) +{ +int i,d,bestD,bestP; + bestD = 99999999; bestP = -1; + for(i=palEntries;i--;) + { + d = square(R - palette[0]) + square(G - palette[1]) + square(B - palette[2]); + palette += 3; + if ( d < bestD ) + { + bestD = d; + bestP = i; + } + } + if ( foundPalPtr ) *foundPalPtr = bestP; +return bestD; +} + +static void addOctNode(octNode *root,int R,int G,int B,int *nLeavesPtr) +{ +int idx; +int bits; +octNode *node; + + node = root; + for(bits=7;bits>=0;bits--) + { + idx = RGBbits(R,G,B,bits); + if ( ! node->kids[idx] ) + { + node->nKids ++; + node->kids[idx] = MemPool_GetHunk(octNodePool); + node->kids[idx]->parent = node; + } + node->count ++; + node = node->kids[idx]; + } + if ( node->count == 0 ) (*nLeavesPtr)++; + node->count ++; + node->R = R; + node->G = G; + node->B = B; +} + +static void gatherLeaves(octNode *node,octNode *** leavesPtrPtr,int minCount) +{ + if ( node->count <= minCount ) return; + if ( node->nKids == 0 ) + { + *(*leavesPtrPtr)++ = node; + } + else + { + int i; + for(i=0;i<8;i++) + { + if ( node->kids[i] ) gatherLeaves(node->kids[i],leavesPtrPtr,minCount); + } + } +} + +static void gatherLeavesCutting(octNode *node,octNode *** leavesPtrPtr) +{ + if ( node->nKids > 0 ) + { + int i; + for(i=0;i<8;i++) + { + if ( node->kids[i] ) + { + if ( node->kids[i]->count <= 1 || node->kids[i]->cutCost <= 1 ) + { + //freeOctNodes(node->kids[i]); + node->kids[i] = NULL; + node->nKids--; + } + else + { + gatherLeavesCutting(node->kids[i],leavesPtrPtr); + + if ( node->kids[i]->nKids == 1 ) + { + octNode *kid; + int j; + kid = node->kids[i]; + for(j=0;j<8;j++) + if ( kid->kids[j] ) + node->kids[i] = kid->kids[j]; + assert( node->kids[i] != kid ); + node->kids[i]->cutCost = kid->cutCost; + //destroy(kid); + node->kids[i]->parent = node; + } + } + } + } + } + + if ( node->nKids == 0 ) + { + *(*leavesPtrPtr)++ = node; + } +} + +static int leafCompareCount(const void *a,const void *b) +{ +octNode *na,*nb; + na = *((octNode **)a); + nb = *((octNode **)b); +return (nb->count) - (na->count); +} +static int leafCompareCost(const void *a,const void *b) +{ +octNode *na,*nb; + na = *((octNode **)a); + nb = *((octNode **)b); +return (nb->cutCost) - (na->cutCost); +} + +void computeCutCosts(octNode *node) +{ + assert(node->parent); + node->cutCost = square(node->R - node->parent->R) + + square(node->G - node->parent->G) + + square(node->B - node->parent->B); + node->cutCost *= node->count; + + if ( node->nKids > 0 ) + { + int i; + for(i=0;i<8;i++) + if ( node->kids[i] ) + { + computeCutCosts(node->kids[i]); + node->cutCost += node->kids[i]->cutCost; + } + } +} + +void computeOctRGBs(octNode *node) +{ + if ( node->nKids > 0 ) + { + int R,G,B; + int i; + octNode *kid; + R = G = B = 0; + for(i=0;i<8;i++) + if ( node->kids[i] ) + computeOctRGBs(node->kids[i]); + for(i=0;i<8;i++) + { + if ( kid = node->kids[i] ) + { + R += kid->count * kid->R; + G += kid->count * kid->G; + B += kid->count * kid->B; + } + } + node->R = R / (node->count); + node->G = G / (node->count); + node->B = B / (node->count); + } +} + +void readLeavesToPal(octNode **leaves,int gotLeaves,uint8 *palette,int palEntries) +{ +octNode **leavesPtr; +uint8 *palPtr; +int R,G,B; +int i,palGot; +int distance,minDistance; + + palPtr = palette; palGot = 0; + for(minDistance=256;minDistance>=0 && palGot < palEntries;minDistance>>=1) + { + leavesPtr = leaves; + for(i=0;iR; + G = (*leavesPtr)->G; + B = (*leavesPtr)->B; + leavesPtr++; + distance = findClosest(R,G,B,palette,palGot,NULL); + if ( distance >= minDistance ) + { + *palPtr++ = R; + *palPtr++ = G; + *palPtr++ = B; + palGot ++; + if ( palGot == palEntries ) + break; + } + } + } +} + +/*}{*************************************************/ + +int createOctTree(octNode * root,const geBitmap_Info * Info,const void * Bits,geBoolean doYUV) +{ +int nLeaves; +int w,h,xtra,bpp,x,y; +gePixelFormat Format; +const gePixelFormat_Operations * ops; +int R,G,B,A; +gePixelFormat_Decomposer Decompose; + + assert(Bits); + + nLeaves = 0; + + Format = Info->Format; + w = Info->Width; + h = Info->Height; + xtra = Info->Stride - Info->Width; + bpp = gePixelFormat_BytesPerPel(Format); + + ops = gePixelFormat_GetOperations(Format); + assert(ops); + Decompose = ops->DecomposePixel; + assert(Decompose); + +// pushTSC(); + + if ( doYUV ) + { + switch(bpp) + { + default: + case 0: + return GE_FALSE; + case 1: + { + const uint8 *ptr; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + Decompose(*ptr++,&R,&G,&B,&A); + RGBi_to_YUVi(R,G,B,&R,&G,&B); + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + } + case 2: + { + const uint16 *ptr; + uint32 R,G,B,A; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + Decompose(*ptr++,&R,&G,&B,&A); + RGBi_to_YUVi(R,G,B,&R,&G,&B); + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + } + + case 3: + { + const uint8 *ptr; + uint32 R,G,B,A,Pixel; + + ptr = Bits; + xtra *= 3; + + switch(Format) + { + case GE_PIXELFORMAT_24BIT_RGB : + for(y=h;y--;) + { + for(x=w;x--;) + { + RGBb_to_YUVi(ptr,&R,&G,&B); + ptr += 3; + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + case GE_PIXELFORMAT_24BIT_BGR : + for(y=h;y--;) + { + for(x=w;x--;) + { + B = *ptr++; + G = *ptr++; + R = *ptr++; + RGBi_to_YUVi(R,G,B,&R,&G,&B); + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + default: + // can't get here now + for(y=h;y--;) + { + for(x=w;x--;) + { + Pixel = (ptr[0]<<16) + (ptr[1]<<8) + ptr[2]; ptr += 3; + Decompose(Pixel,&R,&G,&B,&A); + RGBi_to_YUVi(R,G,B,&R,&G,&B); + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + } + break; // Thanks Bobtree + } + + case 4: + { + const uint32 *ptr; + uint32 R,G,B,A; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + Decompose(*ptr++,&R,&G,&B,&A); + RGBi_to_YUVi(R,G,B,&R,&G,&B); + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + } + } + } + else + { + switch(bpp) + { + default: + case 0: + return GE_FALSE; + case 1: + { + const uint8 *ptr; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + Decompose(*ptr++,&R,&G,&B,&A); + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + } + case 2: + { + const uint16 *ptr; + uint32 R,G,B,A; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + Decompose(*ptr++,&R,&G,&B,&A); + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + } + + case 3: + { + const uint8 *ptr; + uint32 R,G,B,A,Pixel; + + ptr = Bits; + xtra *= 3; + + switch(Format) + { + case GE_PIXELFORMAT_24BIT_RGB : + for(y=h;y--;) + { + for(x=w;x--;) + { + R = *ptr++; + G = *ptr++; + B = *ptr++; + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + case GE_PIXELFORMAT_24BIT_BGR : + for(y=h;y--;) + { + for(x=w;x--;) + { + B = *ptr++; + G = *ptr++; + R = *ptr++; + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + default: + // can't get here now + for(y=h;y--;) + { + for(x=w;x--;) + { + Pixel = (ptr[0]<<16) + (ptr[1]<<8) + ptr[2]; ptr += 3; + Decompose(Pixel,&R,&G,&B,&A); + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + } + break; // Thanks Bobtree + } + + case 4: + { + const uint32 *ptr; + uint32 R,G,B,A; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + Decompose(*ptr++,&R,&G,&B,&A); + addOctNode(root,R,G,B,&nLeaves); + } + ptr += xtra; + } + break; + } + } + } + +// showPopTSC("create Pal OctTree"); + +return nLeaves; +} + +/*}{*************************************************/ diff --git a/G3D/Bitmap/Compression/palcreate.h b/G3D/Bitmap/Compression/palcreate.h new file mode 100644 index 0000000..3591a63 --- /dev/null +++ b/G3D/Bitmap/Compression/palcreate.h @@ -0,0 +1,50 @@ +#ifndef GE_BRANDO_PALCREATE_H +#define GE_BRANDO_PALCREATE_H + +#include "basetype.h" +#include "bitmap.h" + +/****************************************************************************************/ +/* PalCreate */ +/* */ +/* Author: Charles Bloom */ +/* Description: Palette Creation code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +extern geBitmap_Palette * createPaletteGood(const geBitmap_Info * Info,const void * Bits); +extern geBitmap_Palette * createPaletteFast(const geBitmap_Info * Info,const void * Bits); + +typedef geBitmap_Palette * (*paletteCreater) (const geBitmap_Info * Info,const void * Bits); +extern void setCreatePaletteFunc(paletteCreater func); + +extern geBitmap_Palette * createPalette(const geBitmap_Info * Info,const void * Bits); + +extern geBitmap_Palette * createPaletteFromBitmap(const geBitmap * Bitmap,geBoolean Optimize); + +extern void PalCreate_Start(void); +extern void PalCreate_Stop(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Bitmap/Compression/palettize.c b/G3D/Bitmap/Compression/palettize.c new file mode 100644 index 0000000..269393e --- /dev/null +++ b/G3D/Bitmap/Compression/palettize.c @@ -0,0 +1,563 @@ +/****************************************************************************************/ +/* Palettize */ +/* */ +/* Author: Charles Bloom */ +/* Description: Palettize-ing code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +/********* + +our colors are referred to as "RGB" triples, but are actually typically YUV + +------ + +can palettize a 256x256 bitmap in less than 0.1 seconds + +------ + +we palettize ("inverse colormap") using an octree lookup system + +<> do we need to be able to palettize to RGBA ?? + +**********/ + +#include "palettize.h" +#include +#include +#include "ram.h" +#include "mempool.h" + +#ifdef _TSC +#pragma message("palettize using TSC") +#include "tsc.h" +#endif + +/*******/ + +#define new(type) geRam_AllocateClear(sizeof(type)) +#define allocate(ptr) ptr = geRam_AllocateClear(sizeof(*ptr)) +#define clear(ptr) memset(ptr,0,sizeof(*ptr)) +#define destroy(ptr) if ( ptr ) { geRam_Free(ptr); (ptr) = NULL; } else + +/*******/ + +typedef struct palInfo palInfo; + +int __inline closestPalInlineRGB(int R,int G,int B,palInfo *pi); +int closestPal(int R,int G,int B,palInfo *pi); +palInfo * closestPalInit(uint8 * palette); +void closestPalFree(palInfo *info); + +/******/ + +geBoolean palettizePlane(const geBitmap_Info * SrcInfo,const void * SrcBits, + geBitmap_Info * DstInfo, void * DstBits, + int SizeX,int SizeY) +{ +palInfo *palInfo; +int x,y,xtra,bpp; +gePixelFormat Format; +int R,G,B,A; +uint8 palette[768],*pSrc,*pDst; + + assert( SrcInfo && SrcBits ); + assert( DstInfo && DstBits ); + + assert( DstInfo->Format == GE_PIXELFORMAT_8BIT_PAL ); + assert( gePixelFormat_IsRaw(SrcInfo->Format) ); + + if ( ! DstInfo->Palette ) + return GE_FALSE; + + if ( ! geBitmap_Palette_GetData(DstInfo->Palette,palette,GE_PIXELFORMAT_24BIT_RGB,256) ) + return GE_FALSE; + +#ifdef _TSC + pushTSC(); +#endif + + // rgbPlane is (planeLen*3) bytes + // palette is 768 bytes + + palInfo = closestPalInit(palette); + if ( ! palInfo ) return GE_FALSE; + + Format = SrcInfo->Format; + bpp = gePixelFormat_BytesPerPel(Format); + xtra = (SrcInfo->Stride - SizeX) * bpp; + pSrc = (uint8 *)SrcBits; + pDst = DstBits; + + if ( DstInfo->HasColorKey ) + { + int DstCK; + const gePixelFormat_Operations * ops; + ops = gePixelFormat_GetOperations(Format); + assert(ops); + DstCK = DstInfo->ColorKey; + + if ( gePixelFormat_HasAlpha(Format) ) + { + gePixelFormat_ColorGetter GetColor; + GetColor = ops->GetColor; + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + GetColor(&pSrc,&R,&G,&B,&A); + if ( A < 128 ) + { + *pDst++ = DstCK; + } + else + { + *pDst = closestPalInlineRGB(R,G,B,palInfo); + if ( *pDst == DstCK ) // {} this is really poor color-key avoidance! + *pDst ^= 1; + pDst++; + } + } + pSrc += xtra; + pDst += DstInfo->Stride - SizeX; + } + } + else if ( SrcInfo->HasColorKey ) + { + uint32 SrcCK,Pixel; + gePixelFormat_PixelGetter GetPixel; + gePixelFormat_Decomposer DecomposePixel; + DecomposePixel = ops->DecomposePixel; + GetPixel = ops->GetPixel; + + SrcCK = SrcInfo->ColorKey; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = GetPixel(&pSrc); + if ( Pixel == SrcCK ) + { + *pDst++ = DstCK; + } + else + { + DecomposePixel(Pixel,&R,&G,&B,&A); + *pDst = closestPalInlineRGB(R,G,B,palInfo); + if ( *pDst == DstCK ) // {} this is really poor color-key avoidance! + *pDst ^= 1; + pDst++; + } + } + pSrc += xtra; + pDst += DstInfo->Stride - SizeX; + } + } + else + { + gePixelFormat_ColorGetter GetColor; + GetColor = ops->GetColor; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + GetColor(&pSrc,&R,&G,&B,&A); + *pDst = closestPalInlineRGB(R,G,B,palInfo); + if ( *pDst == DstCK ) // {} this is really poor color-key avoidance! + *pDst ^= 1; + pDst++; + } + pSrc += xtra; + pDst += DstInfo->Stride - SizeX; + } + } + } + else + { + // dst does not have CK, and can't have alpha in this universe, so ignore src colorkey + #if 0 // these special cases just avoid a functional-call overhead + if ( Format == GE_PIXELFORMAT_24BIT_RGB ) + { + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + R = *pSrc++; G = *pSrc++; B = *pSrc++; + *pDst++ = closestPalInlineRGB(R,G,B,palInfo); + } + pSrc += xtra; + pDst += DstInfo->Stride - SizeX; + } + } + else if ( Format == GE_PIXELFORMAT_24BIT_BGR ) + { + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + B = *pSrc++; G = *pSrc++; R = *pSrc++; + *pDst++ = closestPalInlineRGB(R,G,B,palInfo); + } + pSrc += xtra; + pDst += DstInfo->Stride - SizeX; + } + } + else + #endif + { + const gePixelFormat_Operations * ops; + gePixelFormat_ColorGetter GetColor; + ops = gePixelFormat_GetOperations(Format); + assert(ops); + GetColor = ops->GetColor; + assert(GetColor); + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + GetColor(&pSrc,&R,&G,&B,&A); + *pDst++ = closestPalInlineRGB(R,G,B,palInfo); + } + pSrc += xtra; + pDst += DstInfo->Stride - SizeX; + } + } + } + +#ifdef _TSC + showPopTSC("palettize"); +#endif + + closestPalFree(palInfo); + +return GE_TRUE; +} + +/*************** +** +* + +Build an OctTree containing all the palette entries; the RGB value +is the index into the tree, the value at the leaf is a palette index. All null children are then set +to point to their closest neighbor. It has a maximum depth of 8. + +To find a palette entry, you take your RGB and just keep stepping in; in fact, it's quite trivial. +on an image of B bytes and a palette of P entries, this method is O(B+P) + +Find the right neighbor for null children is a very difficult algorithm. I punt and +leave them null; when we find a null in descent, we do a hash-assisted search to find +the right pal entry, then add this color & pal entry to the octree for future use. + +we store palette entries in the octree as (palVal+1) so that we can use 0 to mean "not assigned" + +per-pixel time : 5e-7 (found in octree lookup) +per-color time : 7e-6 (not in octree time) + +total_seconds = (5e-7)*(num_pels + palettize_size) + + (3e-8)*(num_actual_colors - palettize_size)*(palettize_size) + + (coder=bitplane,transform=L97) + +stop-rate 4 , PSNR on : +brute-force + pal1 ; 33.29 + pal2 : 37.69 + pal3 : 33.69 + pal4 : 44.69 +OctTree without "expandNulls" ("fast") + pal1 ; 25.73 + pal2 : 32.50 + pal3 : 27.84 + pal4 : 28.07 +OctTree with brute-force "expandNulls" + pal1 ; 32.53 + pal2 : 37.09 + pal3 : 33.27 + pal4 : 33.50 +OctTree with brute-force on null + pal1 ; 33.15 + pal2 : 37.71 + pal3 : 33.65 + pal4 : 35.05 +* +** + *****************/ + +#define QUANT_BITS (4) +#define QUANT_SHIFT (8-QUANT_BITS) +#define QUANT_ROUND (1<<(QUANT_SHIFT-1)) +#define HASH_BITS (QUANT_BITS*3) +#define HASH_SIZE (1<>QUANT_SHIFT)<<(QUANT_BITS+QUANT_BITS)) + (((G)>>QUANT_SHIFT)<<(QUANT_BITS)) + (((B)>>QUANT_SHIFT))) +#define HASHROUNDED(R,G,B) ( (((R+QUANT_ROUND)>>QUANT_SHIFT)<<(QUANT_BITS+QUANT_BITS)) + (((G+QUANT_ROUND)>>QUANT_SHIFT)<<(QUANT_BITS)) + (((B+QUANT_ROUND)>>QUANT_SHIFT))) + +typedef struct octNode octNode; +struct octNode +{ + octNode * kids[8]; + octNode * parent; +}; + +typedef struct hashNode +{ + struct hashNode *next; + int R,G,B,pal; +} hashNode; + +struct palInfo +{ + uint8 *palette; + octNode *root; + hashNode * hash[HASH_SIZE+1]; +}; + +// internal protos: + +int colorDistance(uint8 *ca,uint8 *cb); +int findClosestPalBrute(int R,int G,int B,palInfo *pi); +void addOctNode(octNode *root,int R,int G,int B,int palVal); +void addHash(palInfo *pi,int R,int G,int B,int palVal,int hash); + +#define RGBbits(R,G,B,bits) (((((R)>>(bits))&1)<<2) + ((((G)>>(bits))&1)<<1) + (((B)>>((bits)))&1)) + +static MemPool * octNodePool = NULL; +static MemPool * hashNodePool = NULL; +static int PoolRefs = 0; + +void Palettize_Start(void) +{ + if ( PoolRefs == 0 ) + { + // we init with 256 octnodes, then add one for each unique color + octNodePool = MemPool_Create(sizeof(octNode),1024,1024); + assert(octNodePool); + hashNodePool = MemPool_Create(sizeof(hashNode),1024,1024); + assert(hashNodePool); + } + PoolRefs ++; +} + +void Palettize_Stop(void) +{ + PoolRefs --; + if ( PoolRefs == 0 ) + { + MemPool_Destroy(&octNodePool); + MemPool_Destroy(&hashNodePool); + } +} + +/********************/ + +palInfo * closestPalInit(uint8 * palette) +{ +palInfo *pi; +int i; + + i = HASH_SIZE; + + if ( (pi = new(palInfo)) == NULL ) + return NULL; + + pi->palette = palette; + + pi->root = MemPool_GetHunk(octNodePool); + assert(pi->root); + + for(i=0;i<256;i++) + { + int R,G,B; + R = palette[3*i]; G = palette[3*i+1]; B = palette[3*i+2]; + addOctNode(pi->root,R,G,B,i); + addHash(pi,R,G,B,i,HASH(R,G,B)); + } + +return pi; +} + +int findClosestPal(int R,int G,int B,palInfo *pi) +{ +hashNode *node; +int hash,d,bestD,bestP; + + hash = HASHROUNDED(R,G,B); + if ( hash > HASH_SIZE ) hash = HASH_SIZE; + + node = pi->hash[ hash ]; + if ( ! node ) + { + bestP = findClosestPalBrute(R,G,B,pi); +#if 1 + // helps speed a little; depends on how common individual RGB values are + // (makes it so that if we see this exact RGB again we return bestP right away) + addOctNode(pi->root,R,G,B,bestP); +#endif +#if 0 + //this could help speed, but actually makes this method approximate + node = MemPool_GetHunk(hashNodePool); + assert(node); + node->next = pi->hash[hash]; + pi->hash[hash] = node; + node->R = R; + node->G = G; + node->B = B; + node->pal = bestP; +#endif + return bestP; + } + + bestD = 99999999; bestP = node->pal; + while(node) + { + d = (R - node->R)*(R - node->R) + (G - node->G)*(G - node->G) + (B - node->B)*(B - node->B); + if ( d < bestD ) + { + bestD = d; + bestP = node->pal; + } + node = node->next; + } + +#if 1 + // <> ? + // helps speed a little; depends on how common individual RGB values are + // (makes it so that if we see this exact RGB again we return bestP right away) + addOctNode(pi->root,R,G,B,bestP); +#endif + + return bestP; +} + +#define doStep(bits) do { kid = (node)->kids[ RGBbits(R,G,B,bits) ]; \ + if ( kid ) node = kid; else return findClosestPal(R,G,B,pi); } while(0) + +#define doSteps() do { node = pi->root; doStep(7); doStep(6); doStep(5); doStep(4); doStep(3); doStep(2); doStep(1); doStep(0); } while(0) + +int __inline closestPalInlineRGB(int R,int G,int B,palInfo *pi) +{ +octNode *node,*kid; + + doSteps(); + +return ((int)node)-1; +} + +int closestPal(int R,int G,int B,palInfo *pi) +{ +octNode *node,*kid; + + doSteps(); + + assert( ((int)node) <= 256 && ((int)node) > 0 ); + +return ((int)node)-1; +} + +void closestPalFree(palInfo *pi) +{ + + assert(pi); + + MemPool_Reset(octNodePool); + MemPool_Reset(hashNodePool); + + destroy(pi); +} + + +int findClosestPalBrute(int R,int G,int B,palInfo *pi) +{ +int d,p; +int bestD,bestP; +uint8 * pal; +uint8 color[3]; + + // now do a brute-force best-pal search to find the best pal entry + + color[0] = R; color[1] = G; color[2] = B; + pal = pi->palette; + bestD = colorDistance(color,pal); + bestP = 0; + for(p=1;p<256;p++) + { + pal += 3; + d = colorDistance(color,pal); + if ( d < bestD ) + { + bestD = d; + bestP = p; + } + } +return bestP; +} + +int colorDistance(uint8 *ca,uint8 *cb) +{ +int d,x; + d = 0; + x = ca[0] - cb[0]; + d += x*x; + x = ca[1] - cb[1]; + d += x*x; + x = ca[2] - cb[2]; + d += x*x; +return d; +} + +void addOctNode(octNode *root,int R,int G,int B,int palVal) +{ +int idx; +int bits; +octNode *node = root; + + for(bits=7;bits>0;bits--) + { + idx = RGBbits(R,G,B,bits); + if ( ! node->kids[idx] ) + { + node->kids[idx] = MemPool_GetHunk(octNodePool); + node->kids[idx]->parent = node; + } + node = node->kids[idx]; + } + idx = RGBbits(R,G,B,0); + node->kids[idx] = (octNode *)(palVal+1); +} + +void addHash(palInfo *pi,int R,int G,int B,int palVal,int hash) +{ +hashNode *node; +int i,h; + + for(i=0;i<8;i++) + { + h = hash + (i&1) + (((i>>1)&1)<>2)<<(QUANT_BITS+QUANT_BITS)); + if ( h <= HASH_SIZE ) + { + node = MemPool_GetHunk(hashNodePool); + assert(node); + node->next = pi->hash[h]; + pi->hash[h] = node; + node->R = R; + node->G = G; + node->B = B; + node->pal = palVal; + } + } +} diff --git a/G3D/Bitmap/Compression/palettize.h b/G3D/Bitmap/Compression/palettize.h new file mode 100644 index 0000000..ab3152b --- /dev/null +++ b/G3D/Bitmap/Compression/palettize.h @@ -0,0 +1,54 @@ +#ifndef GE_BRANDO_PALETTIZE_H +#define GE_BRANDO_PALETTIZE_H + +/****************************************************************************************/ +/* Palettize */ +/* */ +/* Author: Charles Bloom */ +/* Description: Palettize-ing code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "basetype.h" +#include "bitmap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +geBoolean palettizePlane(const geBitmap_Info * SrcInfo,const void * SrcBits, + geBitmap_Info * DstInfo, void * DstBits, + int SizeX,int SizeY); + +// you can create a palette with routines in "palcreate.h" + +/******* if you want to do your own palettizing : ******/ + +typedef struct palInfo palInfo; + +extern palInfo * closestPalInit(uint8 * palette); +extern void closestPalFree(palInfo *info); +extern int closestPal(int R,int G,int B,palInfo *pi); + +extern void Palettize_Start(void); +extern void Palettize_Stop(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Bitmap/Compression/paloptimize.c b/G3D/Bitmap/Compression/paloptimize.c new file mode 100644 index 0000000..47f765c --- /dev/null +++ b/G3D/Bitmap/Compression/paloptimize.c @@ -0,0 +1,247 @@ + +/****************************************************************************************/ +/* PalOptimize */ +/* */ +/* Author: Charles Bloom */ +/* Description: Palette Perfecting code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +/********* + +our colors are referred to as "uint8" triples, but are actually typically YUV + +-------- + +The basics : + + find the average color to which each palette entry is mapped. + set the palette entry to that color. + repeat. + +The problems : + + 1. this does NOT converge ; there's some wierd histerysis; + it also does NOT monotonically improve MSE ! + we simply stop when MSE hits a local min. + + <*> I think this is because our "ClosestPal" algorithm is imperfect + since it works within an oct-tree structure + + 2. we can fall into "unstable local minimum" traps, like : + (this is a plot in color space) + + X + + + + X + X + + here X indicates a blob of colors used, and + indicates a palette color; + this configuration is stable under our algorithm, though of + course the optimal is + + * + + * * + + (where * = X and +) + (note that these configurations cannot occur in 1d finite graphs; the + 1d infinite graph for an unstable minimum is ...X+X+X+X+X+... ) + + this could be solved with like a Monte-Carlo walk, + adding some rare random component. + it doesn't work to just add a random wiggle whenever we stall out; + perhaps a random componenet in the direction of the deltas, like + + diffR = Guassian_Rand( center = diffR , variance = abs(diffR) /2 ); + + tried it: + seems to help sometimes, but isn't a clear win + +**********/ + +#include "yuv.h" +#include "palettize.h" +#include "utility.h" +#include "tsc.h" +#include "log.h" + +#include "bitmap.h" +#include "pixelformat.h" + +/*******/ + +typedef struct +{ + int totR,totG,totB,count; +} palOptInfo; + +int stepTable[] = { 1009 , 757, 499, 401, 307, 239, 197, 157, 131, 103, 67, 41, 29, 17, 13, 7, 4, 1 }; + +void paletteOptimize(const geBitmap_Info * BmInfo,const void * Bits,uint8 *palette,int palEntries,int maxSamples) +{ +palInfo *palInfo; +int pal,R,G,B,A; +uint32 mse,last_mse; +uint8 *palPtr; +uint8 savePalette[768]; +int extraStepIndex,extraStepSize,extraStepSizeBytes=0,samples,totSamples; +gePixelFormat_ColorGetter GetColor; +const gePixelFormat_Operations * PixelOps; +uint8 *ptr,*ptrEnd; +int d; +palOptInfo optInfo[256]; + + assert(palEntries <= 256); + + pushTSC(); + + // palette is 768 bytes + + R = palette[(palEntries-1)*3 + 0]; + G = palette[(palEntries-1)*3 + 1]; + B = palette[(palEntries-1)*3 + 2]; + for(pal=palEntries;pal<256;pal++) + { + palette[pal*3 + 0] = R; + palette[pal*3 + 1] = G; + palette[pal*3 + 2] = B; + } + + PixelOps = gePixelFormat_GetOperations(BmInfo->Format); + GetColor = PixelOps->GetColor; + ptrEnd = (uint8 *)Bits + BmInfo->Stride * BmInfo->Height * PixelOps->BytesPerPel; + + mse = ~(uint32)0; + extraStepIndex = 0; + extraStepSize = -1; + totSamples = 0; + if ( maxSamples <= 0 ) maxSamples = 0x0FFFFFFF; + for(;;) + { + if ( extraStepSize != 0 ) + { + extraStepSize = ( stepTable[ extraStepIndex ] - 1 ); + extraStepSizeBytes = extraStepSize * PixelOps->BytesPerPel; + extraStepIndex++; + } + + last_mse = mse; + + // <> this 'closestPal' is not great for this application + // it's approximate & has a large initialization overhead + // we should use the methods from the "Local K-Means" paper + + palInfo = closestPalInit(palette); + if ( ! palInfo ) return; + + memclear(optInfo,sizeof(palOptInfo)*palEntries); + + mse = 0; + samples =0; + ptr = (uint8 *)Bits; + while( ptr < ptrEnd ) + { + GetColor(&ptr,&R,&G,&B,&A); + + pal = closestPal(R,G,B,palInfo); + + if ( pal >= palEntries ) pal = palEntries-1; + + palPtr = palette + pal*3; + d = R - (*palPtr++); mse += d*d; + d = G - (*palPtr++); mse += d*d; + d = B - (*palPtr ); mse += d*d; + + optInfo[pal].totR += R; + optInfo[pal].totG += G; + optInfo[pal].totB += B; + optInfo[pal].count ++; + + ptr += extraStepSizeBytes; + samples ++; + } + + closestPalFree(palInfo); + + if ( samples == 0 ) continue; + mse = (int)(((double)mse*256.0)/samples); + totSamples += samples; + + if ( mse >= last_mse && extraStepSize == 0 ) + { + memcpy(palette,savePalette,768); + mse = last_mse; + break; + } + else if ( mse > last_mse ) + { +#if 0 + // seems to slow convergence (!?) + memcpy(palette,savePalette,768); + mse = last_mse; +#endif + } + else + { + memcpy(savePalette,palette,768); + } + + Log_Printf("mse*256 = %7d , extrastep = %4d, samples = %7d\n",mse,extraStepSize,samples); + + if ( totSamples >= maxSamples ) + break; + + for(pal=0,palPtr = palette; pal>1); else if ( diff > 0 ) diff = ((diff + 1)>>1) + DIV(diffR); + DIV(diffG); + DIV(diffB); +#endif + +#if 0 + // this helps sometimes, hurts sometimes + diffR = GaussianRand(diffR,abs(diffR)); + diffG = GaussianRand(diffG,abs(diffG)); + diffB = GaussianRand(diffB,abs(diffB)); +#endif + + palPtr[0] = minmax( palPtr[0]+diffR , 0,255); + palPtr[1] = minmax( palPtr[1]+diffG , 0,255); + palPtr[2] = minmax( palPtr[2]+diffB , 0,255); + } + + if ( abs(mse - last_mse) < 50 && extraStepSize == 0 ) + { + break; + } + } + + showPopTSC("palOptimize"); +} diff --git a/G3D/Bitmap/Compression/paloptimize.h b/G3D/Bitmap/Compression/paloptimize.h new file mode 100644 index 0000000..deed9e1 --- /dev/null +++ b/G3D/Bitmap/Compression/paloptimize.h @@ -0,0 +1,42 @@ +#ifndef GE_PALOPTIMIZE_H +#define GE_PALOPTIMIZE_H + +/****************************************************************************************/ +/* PalOptimize */ +/* */ +/* Author: Charles Bloom */ +/* Description: Palette Perfecting code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "basetype.h" +#include "bitmap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void paletteOptimize(const geBitmap_Info * Info,const void * Bits, + uint8 *palette,int palEntries,int maxSamples); + + // use maxIterations == 0 or -1 for infinity + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Bitmap/Compression/utility.h b/G3D/Bitmap/Compression/utility.h new file mode 100644 index 0000000..e3872c9 --- /dev/null +++ b/G3D/Bitmap/Compression/utility.h @@ -0,0 +1,109 @@ +#ifndef __COMPUTIL_UTILITY_H +#define __COMPUTIL_UTILITY_H + +/****************************************************************************************/ +/* Utility.h */ +/* */ +/* Author: Charles Bloom */ +/* Description: Macros */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "basetype.h" +#include "ram.h" +#include "errorlog.h" +#include +#include +#include // for memcpy,memset + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int uint; + +/****************************************/ + +#define BrandoError(str) geErrorLog_AddString(-1,str,NULL) + +#ifndef NULL +#define NULL (0) +#endif + +#define sizeofpointer sizeof(void *) + +#define PaddedSize(a) (((a)+3) & (~3)) + +#define IsOdd(a) ( ((uint32)a)&1 ) +#define SignOf(a) (((a) < 0) ? -1 : 1) + +#ifndef max +#define max(a,b) ((a)>(b)?(a):(b)) +#endif + +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif + +#define minmax(x,lo,hi) ( (x)<(lo)?(lo):( (x)>(hi)?(hi):(x)) ) +#define putminmax(x,lo,hi) x = minmax(x,lo,hi) +#define putmin(x,lo) x = min(x,lo) +#define putmax(x,hi) x = max(x,hi) +#define max3(a,b,c) max(max(a,b),c) +#define max4(a,b,c,d) max(a,max3(b,c,d)) +#define min3(a,b,c) min(min(a,b),c) +#define min4(a,b,c,d) min(a,min3(b,c,d)) + +#ifndef mabs +#define mabs(i) ((i) < 0 ? -(i) : (i)) +#endif + +#define isinrange(x,lo,hi) ( (x) >= (lo) && (x) <= (hi) ) + +#define getuint32(bptr) ( ((((uint8 *)(bptr))[0])<<24) + (((uint8 *)(bptr))[1]<<16) + (((uint8 *)(bptr))[2]<<8) + (((uint8 *)(bptr))[3]) ) +#define getuint16(bptr) ( (((uint8 *)(bptr))[0]<<8) + (((uint8 *)(bptr))[1]) ) + +/****************************************/ + +#ifndef strofval +#define strofval(x) (#x) +#endif + +#ifndef new +#define new(type) geRam_AllocateClear(sizeof(type)) +#endif + +#ifndef destroy +#define destroy(mem) do { if ( mem ) { geRam_Free(mem); (mem) = NULL; } } while(0) +#endif + +#ifndef newarray +#define newarray(type,num) geRam_AllocateClear((num)*sizeof(type)) +#endif + +#ifndef memclear +#define memclear(mem,size) memset(mem,0,size); +#endif + +/****************************************/ + +#ifdef __cplusplus +} +#endif + +#endif // __COMPUTIL_UTILITY_H + diff --git a/G3D/Bitmap/Compression/yuv.c b/G3D/Bitmap/Compression/yuv.c new file mode 100644 index 0000000..91e0256 --- /dev/null +++ b/G3D/Bitmap/Compression/yuv.c @@ -0,0 +1,219 @@ +#include "yuv.h" +#include "utility.h" +#include + +/****************************************************************************************/ +/* Yuv */ +/* */ +/* Author: Charles Bloom */ +/* Description: YUV <-> RGB code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#pragma warning(disable : 4244) + +/**************** the YUV routines : ******************/ + +void RGBb_to_YUVb(const uint8 *RGB,uint8 *YUV) +{ +int R = RGB[0], G = RGB[1], B = RGB[2]; + + YUV[0] = Y_RGB(R,G,B); + YUV[1] = U_RGB(R,G,B) + 127; + YUV[2] = V_RGB(R,G,B) + 127; +} + +void YUVb_to_RGBb(const uint8 *YUV,uint8 *RGB) +{ +int y,u,v,r,g,b; + + y = YUV[0]; + u = YUV[1] - 127; + v = YUV[2] - 127; + + r = R_YUV(y,u,v); + g = G_YUV(y,u,v); + b = B_YUV(y,u,v); + + RGB[0] = minmax(r,0,255); // we could get negative ones and whatnot + RGB[1] = minmax(g,0,255); // because the y,u,v are not really 24 bits; + RGB[2] = minmax(b,0,255); // there are regions of YUV space that will never be reached by RGBb_to_YUVb +} + + +void RGBb_to_YUVb_line(const uint8 *RGB,uint8 *YUV,int len) +{ +int R,G,B; + + while(len--) + { + R = *RGB++; + G = *RGB++; + B = *RGB++; + *YUV++ = Y_RGB(R,G,B); + *YUV++ = U_RGB(R,G,B) + 127; + *YUV++ = V_RGB(R,G,B) + 127; + } +} + +void YUVb_to_RGBb_line(const uint8 *YUV,uint8 *RGB,int len) +{ +int y,u,v,r,g,b; + + while(len--) + { + y = (*YUV++); + u = (*YUV++) - 127; + v = (*YUV++) - 127; + + r = R_YUV(y,u,v); + g = G_YUV(y,u,v); + b = B_YUV(y,u,v); + + *RGB++ = minmax(r,0,255); // we could get negative ones and whatnot + *RGB++ = minmax(g,0,255); // because the y,u,v are not really 24 bits; + *RGB++ = minmax(b,0,255); // there are regions of YUV space that will never be reached by RGBb_to_YUVb + } +} + + +void RGBb_to_YUVi(const uint8 *RGB,int *Y,int *U,int *V) +{ +int R = RGB[0], G = RGB[1], B = RGB[2]; + + *Y = Y_RGB(R,G,B); + *U = U_RGB(R,G,B) + 127; + *V = V_RGB(R,G,B) + 127; + + assert( isinrange(*Y,0,255) ); + assert( isinrange(*U,0,255) ); + assert( isinrange(*V,0,255) ); +} + +void YUVi_to_RGBb(int y,int u,int v,uint8 *RGB) +{ +int r,g,b; + +// yuv can be kicked out of 0,255 by the wavelet +// assert( isinrange(y,0,255) ); +// assert( isinrange(u,0,255) ); +// assert( isinrange(v,0,255) ); + + u -= 127; + v -= 127; + r = R_YUV(y,u,v); // this is just like a matrix multiply + g = G_YUV(y,u,v); + b = B_YUV(y,u,v); + RGB[0] = minmax(r,0,255); // we could get negative ones and whatnot + RGB[1] = minmax(g,0,255); // because the y,u,v are not really 24 bits; + RGB[2] = minmax(b,0,255); // there are regions of YUV space that will never be reached by RGBb_to_YUVb +} + +void RGBi_to_YUVi(int R,int G,int B,int *Y,int *U,int *V) +{ + assert( isinrange(R,0,255) ); + assert( isinrange(G,0,255) ); + assert( isinrange(B,0,255) ); + + *Y = Y_RGB(R,G,B); + *U = U_RGB(R,G,B) + 127; + *V = V_RGB(R,G,B) + 127; + + assert( isinrange(*Y,0,255) ); + assert( isinrange(*U,0,255) ); + assert( isinrange(*V,0,255) ); +} + +void YUVi_to_RGBi(int y,int u,int v,int *R,int *G,int *B) +{ +int r,g,b; + +// yuv can be kicked out of 0,255 by the wavelet +// assert( isinrange(y,0,255) ); +// assert( isinrange(u,0,255) ); +// assert( isinrange(v,0,255) ); + + u -= 127; + v -= 127; + r = R_YUV(y,u,v); // this is just like a matrix multiply + g = G_YUV(y,u,v); + b = B_YUV(y,u,v); + + *R = minmax(r,0,255); // we could get negative ones and whatnot + *G = minmax(g,0,255); // because the y,u,v are not really 24 bits; + *B = minmax(b,0,255); // there are regions of YUV space that will never be reached by RGBb_to_YUVb + // <> MMX does this floor to 0-255 for us in one bang! +} + +void YUVi_to_RGBi_line(int *line1,int *line2,int *line3,int len) +{ +int y,u,v,r,g,b; + + // <> use MMX + + while(len--) + { + y = *line1; + u = *line2 - 127; + v = *line3 - 127; + + r = R_YUV(y,u,v); + g = G_YUV(y,u,v); + b = B_YUV(y,u,v); + + r = minmax(r,0,255); + g = minmax(g,0,255); + b = minmax(b,0,255); + + *line1++ = r; + *line2++ = g; + *line3++ = b; + } +} + +void YUVi_to_BGRb_line(int *iline1,int *iline2,int *iline3,uint8 * ibline,int ilen) +{ +int y,u,v,r,g,b,len; +int *line1,*line2,*line3; +uint8 * bline; + + line1 = iline1; + line2 = iline2; + line3 = iline3; + bline = ibline; + len = ilen; + + while(len--) + { + y = (*line1++); + u = (*line2++) - 127; + v = (*line3++) - 127; + + r = R_YUV(y,u,v); + g = G_YUV(y,u,v); + b = B_YUV(y,u,v); + + r = minmax(r,0,255); + g = minmax(g,0,255); + b = minmax(b,0,255); + + bline[0] = b; + bline[1] = g; + bline[2] = r; + bline+=3; + } +} diff --git a/G3D/Bitmap/Compression/yuv.h b/G3D/Bitmap/Compression/yuv.h new file mode 100644 index 0000000..275755a --- /dev/null +++ b/G3D/Bitmap/Compression/yuv.h @@ -0,0 +1,89 @@ +#ifndef GE_BRANDO_YUV_H +#define GE_BRANDO_YUV_H + +/****************************************************************************************/ +/* Yuv */ +/* */ +/* Author: Charles Bloom */ +/* Description: YUV <-> RGB code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void RGBb_to_YUVb(const uint8 *RGB,uint8 *YUV); +extern void YUVb_to_RGBb(const uint8 *YUV,uint8 *RGB); +extern void RGBb_to_YUVb_line(const uint8 *RGB,uint8 *YUV,int array); +extern void YUVb_to_RGBb_line(const uint8 *YUV,uint8 *RGB,int array); + +extern void RGBb_to_YUVi(const uint8 *RGB,int *Y,int *U,int *V); +extern void YUVi_to_RGBb(int y,int u,int v,uint8 *RGB); +extern void RGBi_to_YUVi(int R,int G,int B,int *Y,int *U,int *V); +extern void YUVi_to_RGBi(int y,int u,int v,int *R,int *G,int *B); + +extern void YUVi_to_RGBi_line(int *line1,int *line2,int *line3,int len); +extern void YUVi_to_BGRb_line(int *line1,int *line2,int *line3,uint8 * bline,int len); + +/**************************************************************/ + +#define YUV_SHIFT 14 +#define YUV_HALF (1<<(YUV_SHIFT-1)) +#define YUV_ONE (1<> YUV_SHIFT) +#define U_RGB(R,G,B) (( U_R * (R) + U_G * (G) + U_B * (B) + YUV_HALF ) >> YUV_SHIFT) +#define V_RGB(R,G,B) (( V_R * (R) + V_G * (G) + V_B * (B) + YUV_HALF ) >> YUV_SHIFT) +#define R_YUV(Y,U,V) (( R_Y * (Y) + R_U * (U) + R_V * (V) + YUV_HALF ) >> YUV_SHIFT) +#define G_YUV(Y,U,V) (( G_Y * (Y) + G_U * (U) + G_V * (V) + YUV_HALF ) >> YUV_SHIFT) +#define B_YUV(Y,U,V) (( B_Y * (Y) + B_U * (U) + B_V * (V) + YUV_HALF ) >> YUV_SHIFT) + +#define RGB_to_YUV_macro(R,G,B,Y,U,V) \\ +do { Y = Y_RGB(R,G,B); U = U_RGB(R,G,B) + 127; V = V_RGB(R,G,B) + 127; } while(0) + +#define YUV_to_RGB_macro(Y,U,V,R,G,B) \\ +do { R = R_YUV(Y,(U)-127,(V)-127); G = G_YUV(Y,(U)-127,(V)-127); B = B_YUV(Y,(U)-127,(V)-127); \\ + R = minmax(R,0,255); G = minmax(G,0,255); B = minmax(B,0,255); } while(0) + +/**************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Bitmap/bitmap.__h b/G3D/Bitmap/bitmap.__h new file mode 100644 index 0000000..8d754ef --- /dev/null +++ b/G3D/Bitmap/bitmap.__h @@ -0,0 +1,141 @@ +#ifndef GE_BITMAP____H +#define GE_BITMAP____H + +/****************************************************************************************/ +/* Bitmap.__h */ +/* */ +/* Author: Charles Bloom */ +/* Description: Bitmap*.c Internal Header (contains the Bitmap Struct) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "bitmap.h" +#include "bitmap._h" + +// Hey ! +// this is bitmap.__h : for inclusion by bitmap friends ONLY! +// included by bitmap.c , bitmap_blitdata.c + +/*}{ *********** the bitmap type *******************/ + +// the Version Major indicates an incompatibility + +#define GEBM_VERSION_MAJOR (0x0004) +#define GEBM_VERSION_MINOR (0x0000) + +#define MAXMIPLEVELS (8) + +#define PALETTE_FORMAT_DEFAULT (GE_PIXELFORMAT_24BIT_RGB) + +#define ALPHA_TO_TRANSPARENCY_THRESHOLD (80) + +struct geBitmap_Palette +{ + int LockCount,RefCount; + gePixelFormat Format; + int Size; + geBoolean HasColorKey; + uint32 ColorKey; // the color which is the colorkey + int ColorKeyIndex; // the palette index which is the color; + // Bitmap->CK == Bitmap->Pal->CK_Index + + // we have EITHER Data or DriverHandle + void *Data; //Size * BytesPerPixel(Format) + DRV_Driver *Driver; + geRDriver_THandle*DriverHandle; + void *DriverBits; //only non-null inside a Lock/UnLock +}; + +struct geBitmap +{ + int RefCount; + geBitmap_Info Info; + void * Data[MAXMIPLEVELS]; + geBoolean Modified[MAXMIPLEVELS]; + // modified tells whether a mip != a scaledown of mip 0 + // modified[0] is ignored + geBitmap * Alpha; + + int LockCount; // -Nmips for 'write' , > 0 for 'read's + geBitmap * LockOwner; // this points to our owner and doubles as boolean 'islocked' + geBitmap * DataOwner; // if this is set, then my Data is not mine to free + + gePixelFormat PreferredFormat; // user's favorite + int SeekMipCount; // when we attach to driver, ask for this many mips + + // must support any number of locks for read + // a lock for read can be a pointer to my raw bits, or a whole different bitmap + + geBitmap_Info DriverInfo; // all the driver mess.. + uint32 DriverFlags; + DRV_Driver * Driver; + geRDriver_THandle * DriverHandle; + int DriverMipLock; // which mip to lock on GetBits + geBoolean DriverBitsLocked; + geBoolean DriverDataChanged; // relative to system copy + geFloat DriverGamma; + geFloat DriverGammaLast; + geBoolean DriverGammaSet; +}; + + +/*}{ ************* internal protos *****************/ + +//geBitmap * geBitmap_CreateXerox(geBitmap *BmpSrc); + +geBoolean geBitmap_IsValid(const geBitmap *Bmp); +geBoolean geBitmap_Info_IsValid(const geBitmap_Info *Info); +geBoolean geBitmap_Palette_IsValid(const geBitmap_Palette *Pal); + +geBoolean geBitmap_BlitMipRect(const geBitmap * Src, int SrcMip, int SrcX,int SrcY, + geBitmap * Dst, int DstMip, int DstX,int DstY, + int SizeX,int SizeY); + +geBitmap * geBitmap_CreateLock_CopyInfo(geBitmap *BmpSrc,int LockCnt,int mip); +geBitmap * geBitmap_CreateLockFromMip(geBitmap *Src,int mip, + gePixelFormat Format,geBoolean HasColorKey,uint32 ColorKey,int LockCnt); +geBitmap * geBitmap_CreateLockFromMipSystem(geBitmap *Src,int mip,int LockCnt); +geBitmap * geBitmap_CreateLockFromMipOnDriver(geBitmap *Src,int mip,int LockCnt); + +geBoolean geBitmap_UnLock_NoChange(geBitmap *Bmp); +geBoolean geBitmap_UnLockArray_NoChange(geBitmap **Locks,int Size); + +geBoolean geBitmap_Update_SystemToDriver(geBitmap *Bmp); +geBoolean geBitmap_Update_DriverToSystem(geBitmap *Bmp); + +geBoolean geBitmap_MakeSystemMips(geBitmap *Bmp,int low,int high); +geBoolean geBitmap_UpdateMips_Data( geBitmap_Info * FmInfo,void * FmBits, + geBitmap_Info * ToInfo,void * ToBits); +geBoolean geBitmap_UpdateMips_System(geBitmap *Bmp,int fm,int to); + +geBoolean geBitmap_UsesColorKey(const geBitmap * Bmp); + +void geBitmap_MakeMipInfo( geBitmap_Info *Src,int mip,geBitmap_Info *Into); +geBoolean geBitmap_MakeDriverLockInfo(geBitmap *Bmp,int mip,geBitmap_Info *Into); + // MakeDriverLockInfo also doesn't full out the full info, so it must be a valid info first! + // Bmp also gets some crap written into him. + +geBoolean geBitmap_AllocSystemMip(geBitmap *Bmp,int mip); +geBoolean geBitmap_AllocPalette(geBitmap *Bmp,gePixelFormat Format,DRV_Driver * Driver); + +geBoolean geBitmap_ReadInfo( geBitmap *Bmp,geVFile * F); +geBoolean geBitmap_WriteInfo(const geBitmap *Bmp,geVFile * F); + +geBoolean geBitmap_FixDriverFlags(uint32 *pFlags); + +/*}{ ************* end *****************/ + +#endif diff --git a/G3D/Bitmap/bitmap._h b/G3D/Bitmap/bitmap._h new file mode 100644 index 0000000..f1f5625 --- /dev/null +++ b/G3D/Bitmap/bitmap._h @@ -0,0 +1,71 @@ +#ifndef BITMAP_PRIVATE_H +#define BITMAP_PRIVATE_H + +/****************************************************************************************/ +/* Bitmap._h */ +/* */ +/* Author: Charles Bloom */ +/* Description: Engine-Internal Bitmap Functions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + + +#include "bitmap.h" +#include "dcommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*** +** +* +* These functions are intended for internal Genesis use only. +* +* This can become public once Driver is exposed/formalized. !@@! +* +* Only engine.c , and maybe world & bitmaplist should include this ! +* +* You MUST DetachDriver from a bitmap, before you change the Driver +* +** + **/ + +#define BITMAP_GENESIS_INTERNAL GENESISCC + +geBoolean GENESISCC geBitmap_AttachToDriver(geBitmap *Bmp, DRV_Driver * Driver, uint32 DriverFlags); + // use Driverflags == 0 to use the flags from _SetDriverFlags + +geBoolean GENESISCC geBitmap_DetachDriver(geBitmap *Bmp, geBoolean DoUpdate); + // You MUST Detach the Driver while it is identical to the way it was when attached! + +geBitmap_Palette * GENESISCC geBitmap_Palette_CreateFromDriver(DRV_Driver * Driver,gePixelFormat Format,int Size); /*<>*/ + +geRDriver_THandle * GENESISCC geBitmap_GetTHandle(const geBitmap *Bmp); + +geBoolean GENESISCC geBitmap_SetDriverFlags(geBitmap *Bmp,uint32 flags); + +geBoolean GENESISCC geBitmap_SetGammaCorrection_DontChange(geBitmap *Bmp,geFloat Gamma); + +#ifdef __cplusplus +} +#endif + + +#endif // BITMAP_PRIVATE_H + + diff --git a/G3D/Bitmap/bitmap.c b/G3D/Bitmap/bitmap.c new file mode 100644 index 0000000..9fc6cd0 --- /dev/null +++ b/G3D/Bitmap/bitmap.c @@ -0,0 +1,5681 @@ +//bitmap.z +/****************************************************************************************/ +/* Bitmap.c */ +/* */ +/* Author: Charles Bloom */ +/* Description: Abstract Bitmap system */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +/*}{ *************** head *******************/ + +/********** +*** +* + +see @@ for urgent todos ! +see <> for todos +see {} for notes/long-term-todos + +------- + +{} when palettizing lots of mips, blit them together, so we only make + one closestPal palInfo for all the blits (big speedup). + (for UpdateMips too) + perhaps the only way is to keep a cache of the last palInfo made and + check the palette to see if its reusable. Check on memory cost of the palInfo. + +{} when we blit from one set of mips to another, we could copy the palette (or build the palette!) + many times. We must do this in general, because the mips could all have different palettes. + The answer is to keep track of "palette was just copied from X" + (actually, setting different palettes on two locked mips will cause bad data!!) + +{} make a _BlitOnto which merges with alpha? + +* +*** + ********/ +#include +#include +#include +#include +#include +#include + +#include "basetype.h" +#include "getypes.h" +#include "ram.h" + +#include "vfile.h" +#include "ErrorLog.h" +#include "Log.h" +#include "mempool.h" + +#include "bitmap.h" +#include "bitmap._h" +#include "bitmap.__h" +#include "bitmap_blitdata.h" +#include "bitmap_gamma.h" + +#include "palcreate.h" +#include "palettize.h" + +#ifdef DO_TIMER +#include "timer.h" +#endif + +#define allocate(ptr) ptr = geRam_Allocate(sizeof(*ptr)) +#define clear(ptr) memset(ptr,0,sizeof(*ptr)) + +#define SHIFT_R_ROUNDUP(val,shift) (((val)+(1<<(shift)) - 1)>>(shift)) + +/*}{ ************* statics *****************/ + +//#define DO_TIMER + +//#define DONT_USE_ASM + +#ifdef _DEBUG +#define Debug(x) x +static int _Bitmap_Debug_ActiveCount = 0; +static int _Bitmap_Debug_ActiveRefs = 0; +#else +#define Debug(x) +#endif + +static int BitmapInit_RefCount = 0; +static MemPool * BitmapPool = NULL; + +void geBitmap_Start(void) +{ + if ( BitmapInit_RefCount == 0 ) + { + BitmapPool = MemPool_Create(sizeof(geBitmap),100,100); + assert(BitmapPool); + Palettize_Start(); + PalCreate_Start(); + } + BitmapInit_RefCount ++; +} + +void geBitmap_Stop(void) +{ + assert(BitmapInit_RefCount > 0 ); + BitmapInit_RefCount --; + if ( BitmapInit_RefCount == 0 ) + { + assert(BitmapPool); + MemPool_Destroy(&BitmapPool); + Palettize_Stop(); + PalCreate_Stop(); + } +} + +/*}{ ******** Creator Functions **********************/ + +geBitmap * geBitmap_Create_Base(void) +{ +geBitmap * Bmp; + + geBitmap_Start(); + + Bmp = MemPool_GetHunk(BitmapPool); + + Bmp->RefCount = 1; + + Bmp->DriverGamma = Bmp->DriverGammaLast = 1.0f; + + Debug(_Bitmap_Debug_ActiveRefs ++); + Debug(_Bitmap_Debug_ActiveCount ++); + +return Bmp; +} + +void geBitmap_Destroy_Base(geBitmap *Bmp) +{ + assert(Bmp); + assert(Bmp->RefCount == 0); + Debug(_Bitmap_Debug_ActiveCount --); + + MemPool_FreeHunk(BitmapPool,Bmp); + + geBitmap_Stop(); +} + +GENESISAPI void GENESISCC geBitmap_CreateRef(geBitmap *Bmp) +{ + assert(Bmp); + Bmp->RefCount ++; + Debug(_Bitmap_Debug_ActiveRefs ++); +} + +GENESISAPI geBitmap * GENESISCC geBitmap_Create( + int Width, + int Height, + int MipCount, + gePixelFormat Format) +{ +geBitmap * Bmp; + + Bmp = geBitmap_Create_Base(); + if ( ! Bmp ) + return NULL; + + assert( Width > 0 ); + assert( Height > 0 ); + if ( MipCount == 0 ) + MipCount = 1; + assert( MipCount > 0 ); + + Bmp->Info.Width = Width; + Bmp->Info.Stride = Width; + Bmp->Info.Height = Height; + Bmp->Info.Format = Format; + + Bmp->Info.MinimumMip = 0; + Bmp->Info.MaximumMip = 0; + Bmp->Info.HasColorKey = GE_FALSE; + + Bmp->SeekMipCount = MipCount; + + if ( Format == GE_PIXELFORMAT_WAVELET ) + { + geErrorLog_AddString(-1,"Genesis3D 1.0 does not support Wavelet Images",NULL); + return NULL; + } + +return Bmp; +} + +GENESISAPI geBitmap * GENESISCC geBitmap_CreateFromInfo(const geBitmap_Info * pInfo) +{ +geBitmap * Bmp; + + assert(pInfo); + assert(geBitmap_Info_IsValid(pInfo)); + + Bmp = geBitmap_Create_Base(); + if ( ! Bmp ) + return NULL; + + Bmp->Info = *pInfo; + + if ( Bmp->Info.Stride < Bmp->Info.Width ) + Bmp->Info.Stride = Bmp->Info.Width; + + if ( Bmp->Info.Palette ) + geBitmap_Palette_CreateRef(Bmp->Info.Palette); + + if ( Bmp->Info.Format == GE_PIXELFORMAT_WAVELET ) + { + geErrorLog_AddString(-1,"Genesis3D 1.0 does not support Wavelet Images",NULL); + return NULL; + } + +return Bmp; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Destroy(geBitmap **Bmp) +{ +int i; +geBitmap * Bitmap; + + assert(Bmp); + + Bitmap = *Bmp; + + if ( Bitmap ) + { + if ( Bitmap->LockOwner ) + { + return geBitmap_UnLock(Bitmap); + } + + if ( Bitmap->RefCount <= 1 ) + { + if ( Bitmap->DataOwner ) + { + geBitmap_Destroy(&(Bitmap->DataOwner)); + Bitmap->DataOwner = NULL; + } + else + { + if ( Bitmap->Driver ) + { + geBitmap_DetachDriver(Bitmap,GE_FALSE); + } + + for (i = Bitmap->Info.MinimumMip; i <= Bitmap->Info.MaximumMip; i++) + { + if (Bitmap->Data[i]) + geRam_Free(Bitmap->Data[i]); + } + } + } + + Debug(assert(_Bitmap_Debug_ActiveRefs > 0)); + Debug(_Bitmap_Debug_ActiveRefs --); + + Bitmap->RefCount --; + + if ( Bitmap->RefCount <= 0 ) + { + if (Bitmap->Alpha) + { + geBitmap_Destroy(&Bitmap->Alpha); + } + + if (Bitmap->Info.Palette) + { + geBitmap_Palette_Destroy(&(Bitmap->Info.Palette)); + } + + if (Bitmap->DriverInfo.Palette) + { + geBitmap_Palette_Destroy(&(Bitmap->DriverInfo.Palette)); + } + + geBitmap_Destroy_Base(Bitmap); + + *Bmp = NULL; + + return GE_TRUE; + } + } + +return GE_FALSE; +} + +geBoolean geBitmap_AllocSystemMip(geBitmap *Bmp,int mip) +{ + if ( ! Bmp ) + { + return GE_FALSE; + } + + if ( Bmp->LockOwner && mip != 0 ) return GE_FALSE; + + if ( ! Bmp->Data[mip] ) + { + int bytes; + bytes = geBitmap_MipBytes(Bmp,mip); + if ( bytes == 0 ) + { + Bmp->Data[mip] = NULL; + return GE_TRUE; + } + Bmp->Data[mip] = geRam_Allocate( bytes ); + } + +return (Bmp->Data[mip]) ? GE_TRUE : GE_FALSE; +} + +geBoolean geBitmap_AllocPalette(geBitmap *Bmp,gePixelFormat Format,DRV_Driver * Driver) +{ +geBitmap_Info * BmpInfo; + assert(Bmp); + + if ( Driver ) + BmpInfo = &(Bmp->DriverInfo); + else + BmpInfo = &(Bmp->Info); + + if ( ! gePixelFormat_IsRaw(Format) ) + Format = GE_PIXELFORMAT_32BIT_XRGB; + + if ( ! BmpInfo->Palette ) + { + assert( BmpInfo->Format == GE_PIXELFORMAT_8BIT_PAL ); + + if ( Driver ) + { + geBoolean BmpHasAlpha; + + BmpHasAlpha = GE_FALSE; + if ( gePixelFormat_HasGoodAlpha(Bmp->Info.Format) ) + BmpHasAlpha = GE_TRUE; + else if ( Bmp->Info.Palette && gePixelFormat_HasGoodAlpha(Bmp->Info.Palette->Format) ) + BmpHasAlpha = GE_TRUE; + + if ( BmpHasAlpha || (Bmp->Info.HasColorKey && ! Bmp->DriverInfo.HasColorKey ) ) + Format = GE_PIXELFORMAT_32BIT_ARGB; + + BmpInfo->Palette = geBitmap_Palette_CreateFromDriver(Driver,Format,256); + } + else + { + BmpInfo->Palette = geBitmap_Palette_Create(Format,256); + } + } + + if ( ! BmpInfo->Palette ) + return GE_FALSE; + + if ( BmpInfo->HasColorKey ) + { + if ( ! BmpInfo->Palette->HasColorKey ) + { + BmpInfo->Palette->HasColorKey = GE_TRUE; + BmpInfo->Palette->ColorKey = 1; // <> + } + BmpInfo->Palette->ColorKeyIndex = BmpInfo->ColorKey; + } + + if ( Driver ) + { + assert( Bmp->DriverHandle ); + assert( BmpInfo->Palette->DriverHandle ); + if ( ! Driver->THandle_SetPalette(Bmp->DriverHandle,BmpInfo->Palette->DriverHandle) ) + { + geErrorLog_AddString(-1,"AllocPal : THandle_SetPalette", NULL); + return GE_FALSE; + } + } + + if ( ! Bmp->Info.Palette ) + { + Bmp->Info.Palette = geBitmap_Palette_CreateCopy(BmpInfo->Palette); + } + +return GE_TRUE; +} + +/*}{ *************** Locks *******************/ + +GENESISAPI geBoolean GENESISCC geBitmap_LockForWrite( + geBitmap * Bmp, + geBitmap ** Target, + int MinimumMip, + int MaximumMip) +{ +int mip; + + assert( geBitmap_IsValid(Bmp) ); + assert( Target); + assert(MaximumMip >= MinimumMip); + assert( &Bmp != Target ); + + if ( Bmp->LockCount || Bmp->LockOwner ) + { + geErrorLog_AddString(-1,"LockForWrite : already locked", NULL); + return GE_FALSE; + } + + if ( Bmp->DriverHandle ) + { + if ( (MinimumMip < Bmp->DriverInfo.MinimumMip) || + (MaximumMip > Bmp->DriverInfo.MaximumMip) ) + { + geErrorLog_AddString(-1,"LockForWrite : Driver : invalid mip", NULL); + return GE_FALSE; + } + } + else + { + if ( (MinimumMip < Bmp->Info.MinimumMip) || + (MaximumMip >= MAXMIPLEVELS) ) + { + geErrorLog_AddString(-1,"LockForWrite : System : invalid mip", NULL); + return GE_FALSE; + } + + if ( MaximumMip > Bmp->Info.MaximumMip ) + { + if ( ! geBitmap_MakeSystemMips(Bmp,Bmp->Info.MaximumMip,MaximumMip) ) + return GE_FALSE; + Bmp->Info.MaximumMip = MaximumMip; + } + } + + for(mip=MinimumMip;mip <= MaximumMip;mip ++) + { + if ( Bmp->DriverHandle ) + { + Target[ mip - MinimumMip ] = geBitmap_CreateLockFromMipOnDriver(Bmp,mip,-1); + } + else + { + Target[ mip - MinimumMip ] = geBitmap_CreateLockFromMipSystem(Bmp,mip,-1); + } + if ( ! Target[ mip - MinimumMip ] ) + { + geErrorLog_AddString(-1,"LockForWrite : CreateLockFromMip failed", NULL); + mip--; + while(mip >= MinimumMip ) + { + geBitmap_Destroy( & Target[ mip - MinimumMip ] ); + mip--; + } + return GE_FALSE; + } + } + + assert( Bmp->LockCount == - (MaximumMip - MinimumMip + 1) ); + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_LockForWriteFormat( + geBitmap * Bmp, + geBitmap ** Target, + int MinimumMip, + int MaximumMip, + gePixelFormat Format) +{ +int mip; + + assert( geBitmap_IsValid(Bmp) ); + assert( Target); + assert(MaximumMip >= MinimumMip); + assert( &Bmp != Target ); + + if ( Bmp->LockCount || Bmp->LockOwner ) + { + geErrorLog_AddString(-1,"LockForWrite : already locked", NULL); + return GE_FALSE; + } + + if ( Format != Bmp->Info.Format && Format != Bmp->DriverInfo.Format ) + { + geErrorLog_AddString(-1,"LockForWriteFormat : must be System or Driver Format !", NULL); + return GE_FALSE; + } + + if ( Format == Bmp->DriverInfo.Format ) + { + if ( MinimumMip < Bmp->DriverInfo.MinimumMip || MaximumMip > Bmp->DriverInfo.MaximumMip ) + { + geErrorLog_AddString(-1,"LockForWrite : invalid Driver mip", NULL); + return GE_FALSE; + } + } + else + { + assert( Format == Bmp->Info.Format ); + + if ( Bmp->DriverHandle ) + { + if ( ! geBitmap_Update_DriverToSystem(Bmp) ) + { + geErrorLog_AddString(-1,"LockForWrite : Update_DriverToSystem", NULL); + return GE_FALSE; + } + } + + // create mips? + + if ( MinimumMip < Bmp->Info.MinimumMip || MaximumMip >= MAXMIPLEVELS ) + { + geErrorLog_AddString(-1,"LockForWrite : invalid System mip", NULL); + return GE_FALSE; + } + + if ( ! geBitmap_MakeSystemMips(Bmp,Bmp->Info.MaximumMip,MaximumMip) ) + return GE_FALSE; + Bmp->Info.MaximumMip = MaximumMip; + } + + for(mip=MinimumMip;mip <= MaximumMip;mip ++) + { + if ( Bmp->DriverHandle && Format == Bmp->DriverInfo.Format ) + { + Target[ mip - MinimumMip ] = geBitmap_CreateLockFromMipOnDriver(Bmp,mip,-1); + } + else + { + Target[ mip - MinimumMip ] = geBitmap_CreateLockFromMipSystem(Bmp,mip,-1); + } + + if ( ! Target[ mip - MinimumMip ] ) + { + geErrorLog_AddString(-1,"LockForWrite : CreateLockFromMip failed", NULL); + mip--; + while(mip >= MinimumMip ) + { + geBitmap_Destroy( & Target[ mip - MinimumMip ] ); + mip--; + } + return GE_FALSE; + } + } + + assert( Bmp->LockCount == - (MaximumMip - MinimumMip + 1) ); + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_LockForReadNative( + const geBitmap * iBmp, + geBitmap ** Target, + int MinimumMip, + int MaximumMip) +{ +int mip; +geBitmap * Bmp = (geBitmap *)iBmp; + + assert( geBitmap_IsValid(Bmp) ); + assert( Target); + assert(MaximumMip >= MinimumMip); + assert( &Bmp != Target ); + + if ( (MinimumMip < Bmp->Info.MinimumMip && MinimumMip < Bmp->DriverInfo.MinimumMip) || + (MaximumMip >= MAXMIPLEVELS) ) + { + geErrorLog_AddString(-1,"LockForRead : invalid mip", NULL); + return GE_FALSE; + } + + if ( Bmp->LockCount < 0 || Bmp->LockOwner ) + { + geErrorLog_AddString(-1,"LockForRead : already locked", NULL); + return GE_FALSE; + } + + for(mip=MinimumMip;mip <= MaximumMip;mip ++) + { + // err on the side of *not* choosing the driver data to read from ! + if ( Bmp->DriverHandle && Bmp->DriverDataChanged + && mip <= Bmp->DriverInfo.MaximumMip && mip >= Bmp->DriverInfo.MinimumMip) + { + Target[ mip - MinimumMip ] = geBitmap_CreateLockFromMipOnDriver(Bmp,mip,1); + } + else + { + Target[ mip - MinimumMip ] = geBitmap_CreateLockFromMipSystem(Bmp,mip,1); + } + if ( ! Target[ mip - MinimumMip ] ) + { + geErrorLog_AddString(-1,"LockForRead : CreateLockFromMip failed", NULL); + mip--; + while(mip >= MinimumMip ) + { + geBitmap_Destroy( & Target[ mip - MinimumMip ] ); + mip--; + } + return GE_FALSE; + } + } + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_LockForRead( + const geBitmap * iBmp, + geBitmap ** Target, + int MinimumMip, + int MaximumMip, + gePixelFormat Format, + geBoolean HasColorKey, + uint32 ColorKey) +{ +int mip; +geBitmap * Bmp = (geBitmap *)iBmp; + + assert( geBitmap_IsValid(Bmp) ); + assert( Target); + assert(MaximumMip >= MinimumMip); + assert( &Bmp != Target ); + + if ( MinimumMip < Bmp->Info.MinimumMip || +// MaximumMip > Bmp->Info.MaximumMip + MaximumMip >= MAXMIPLEVELS ) + { + geErrorLog_AddString(-1,"LockForRead : invalid mip", NULL); + return GE_FALSE; + } + + if ( Bmp->LockCount < 0 || Bmp->LockOwner ) + { + geErrorLog_AddString(-1,"LockForRead : already locked", NULL); + return GE_FALSE; + } + + for(mip=MinimumMip;mip <= MaximumMip;mip ++) + { + Target[ mip - MinimumMip ] = geBitmap_CreateLockFromMip(Bmp,mip, Format,HasColorKey,ColorKey,1); + if ( ! Target[ mip - MinimumMip ] ) + { + geErrorLog_AddString(-1,"LockForRead : CreateLockFromMip failed", NULL); + mip--; + while(mip >= MinimumMip ) + { + geBitmap_Destroy( & Target[ mip - MinimumMip ] ); + mip--; + } + return GE_FALSE; + } + } + +return GE_TRUE; +} + +geBoolean geBitmap_UnLockArray_NoChange(geBitmap **Locks,int Size) +{ +int i; +geBoolean Ret = GE_TRUE; + assert(Locks); + for(i=0;iLockCount == 0 ); + + if ( Bmp->LockOwner ) + { + int DoUpdate = 0; + + assert(Bmp->LockOwner->LockCount != 0); + if ( Bmp->LockOwner->LockCount > 0 ) + { + Bmp->LockOwner->LockCount --; + } + else if ( Bmp->LockOwner->LockCount < 0 ) + { + Bmp->LockOwner->LockCount ++; + + if ( Apply ) + { + geBitmap_Palette * Pal; + + Bmp->LockOwner->Modified[Bmp->Info.MinimumMip] = GE_TRUE; + + Pal = Bmp->DriverInfo.Palette ? Bmp->DriverInfo.Palette : Bmp->Info.Palette; + if ( Pal ) + geBitmap_SetPalette(Bmp->LockOwner,Pal); + + // this palette will be destroyed later on + } + + if ( Bmp->LockOwner->LockCount == 0 && Apply ) + { + // last unlock for write + // if Bmp is on hardware, flag the Data[] as needing update + if ( Bmp->DriverBitsLocked ) + { + assert( Bmp->DriverHandle ); + Bmp->LockOwner->DriverDataChanged = GE_TRUE; + DoUpdate = 1; + } + else + { + DoUpdate = -1; + } + } + } + + if ( Bmp->DriverHandle && Bmp->DriverBitsLocked ) + { + assert(Bmp->Driver); + if ( ! Bmp->Driver->THandle_UnLock(Bmp->DriverHandle, Bmp->DriverMipLock) ) + { + geErrorLog_AddString(-1,"UnLock : thandle_unlock", NULL); + Ret = GE_FALSE; + } + Bmp->DriverBitsLocked = GE_FALSE; + Bmp->DriverMipLock = 0; + } + + if ( Bmp->Alpha ) + { + if ( ! geBitmap_UnLock(Bmp->Alpha) ) + Ret = GE_FALSE; + + Bmp->Alpha = NULL; + } + + if ( DoUpdate ) + { + assert(Bmp->LockOwner->LockCount == 0 ); + // we just finished unlocking a lock-for-write + if ( DoUpdate > 0 ) + { + // don't update from driver -> system, leaved the changed data on the driver + // we've got DriverDataChanged + // if ( ! geBitmap_Update_DriverToSystem(Bmp) ) + // Ret = GE_FALSE; + } + else + { + if ( Bmp->LockOwner->DriverHandle ) + if ( ! geBitmap_Update_SystemToDriver(Bmp->LockOwner) ) + Ret = GE_FALSE; + } + } + + // we did a CreateRef on the lockowner + geBitmap_Destroy(&(Bmp->LockOwner)); + Bmp->LockOwner = NULL; + + } + // else fail ? + + assert(Bmp->RefCount == 1); + + geBitmap_Destroy(&Bmp); + + assert(Bmp == NULL); + +return Ret; +} + +GENESISAPI geBoolean GENESISCC geBitmap_UnLock(geBitmap *Bmp) +{ +return geBitmap_UnLock_Internal(Bmp,GE_TRUE); +} + +geBoolean geBitmap_UnLock_NoChange(geBitmap *Bmp) +{ +return geBitmap_UnLock_Internal(Bmp,GE_FALSE); +} + +GENESISAPI void * GENESISCC geBitmap_GetBits(geBitmap *Bmp) +{ +void * bits; + + assert( geBitmap_IsValid(Bmp) ); + + if ( ! Bmp ) + { + geErrorLog_AddString(-1,"GetBits : bad bmp", NULL); + return NULL; + } + + if ( ! Bmp->LockOwner ) // must be a lock! + { + geErrorLog_AddString(-1,"GetBits : not a lock", NULL); + return NULL; + } + + if ( Bmp->DriverHandle ) + { + assert(Bmp->Driver); + if ( ! Bmp->Driver->THandle_Lock(Bmp->DriverHandle,Bmp->DriverMipLock,&bits) ) + { + geErrorLog_AddString(-1,"GetBits : THandle_Lock", NULL); + return NULL; + } + + Bmp->DriverBitsLocked = GE_TRUE; + } + else + { + bits = Bmp->Data[0]; + } + +return bits; +} + +/*}{ ************* _CreateLock_#? *********************/ + +geBitmap * geBitmap_CreateLock_CopyInfo(geBitmap *BmpSrc,int LockCnt,int mip) +{ +geBitmap * Bmp; + + assert( geBitmap_IsValid(BmpSrc) ); + + // all _CreateLocks go through here + + Bmp = geBitmap_Create_Base(); + if ( ! Bmp ) + return NULL; + + geBitmap_MakeMipInfo(&(BmpSrc->Info),mip,&(Bmp->Info)); + geBitmap_MakeMipInfo(&(BmpSrc->DriverInfo),mip,&(Bmp->DriverInfo)); + Bmp->DriverFlags = BmpSrc->DriverFlags; + Bmp->DriverGamma = BmpSrc->DriverGamma; + Bmp->DriverGammaLast = BmpSrc->DriverGammaLast; + + Bmp->Info.Palette = NULL; + Bmp->DriverInfo.Palette = NULL; + + Bmp->Driver = BmpSrc->Driver; + Bmp->PreferredFormat= BmpSrc->PreferredFormat; + + Bmp->LockOwner = BmpSrc; + geBitmap_CreateRef(BmpSrc); // we do a _Destroy() in UnLock() + + BmpSrc->LockCount += LockCnt; + +return Bmp; +} + +void geBitmap_MakeMipInfo(geBitmap_Info *Src,int mip,geBitmap_Info * Target) +{ + assert( Src && Target ); + assert( mip >= 0 && mip < MAXMIPLEVELS ); + *Target = *Src; + + Target->Width = SHIFT_R_ROUNDUP(Target->Width,mip); + Target->Height = SHIFT_R_ROUNDUP(Target->Height,mip); + Target->Stride = SHIFT_R_ROUNDUP(Target->Stride,mip); + Target->MinimumMip = Target->MaximumMip = mip; +} + +geBitmap * geBitmap_CreateLockFromMip(geBitmap *Src,int mip, + gePixelFormat Format, + geBoolean HasColorKey, + uint32 ColorKey, + int LockCnt) +{ +geBitmap * Ret; + + assert( geBitmap_IsValid(Src) ); + if ( mip < 0 || mip >= MAXMIPLEVELS ) + return NULL; + + // LockForRead always goes through here + + if ( gePixelFormat_BytesPerPel(Format) < 1 ) + return NULL; + + if ( Src->DriverInfo.Format == Format && + GE_BOOLSAME(Src->DriverInfo.HasColorKey,HasColorKey) && + (!HasColorKey || Src->DriverInfo.ColorKey == ColorKey) && + mip >= Src->DriverInfo.MinimumMip && mip <= Src->DriverInfo.MaximumMip ) + { + return geBitmap_CreateLockFromMipOnDriver(Src,mip,LockCnt); + } + + if ( Src->DriverHandle ) + { + if ( ! geBitmap_Update_DriverToSystem(Src) ) + { + return NULL; + } + } + + if ( ! Src->Data[mip] ) + { + if ( ! geBitmap_MakeSystemMips(Src,mip,mip) ) + return NULL; + } + + if ( Src->Info.Format == Format && + GE_BOOLSAME(Src->Info.HasColorKey,HasColorKey) && + (!HasColorKey || Src->Info.ColorKey == ColorKey) ) + { + return geBitmap_CreateLockFromMipSystem(Src,mip,LockCnt); + } + + Ret = geBitmap_CreateLock_CopyInfo(Src,LockCnt,mip); + + if ( ! Ret ) + return NULL; + + Ret->Info.Stride = Ret->Info.Width; // {} ? + + Ret->Info.Format = Format; + Ret->Info.ColorKey = ColorKey; + Ret->Info.HasColorKey = HasColorKey; + + if ( gePixelFormat_HasPalette(Format) && Src->Info.Palette ) + { + Ret->Info.Palette = Src->Info.Palette; + geBitmap_Palette_CreateRef(Ret->Info.Palette); + } + + assert( Ret->Alpha == NULL ); + if ( ! gePixelFormat_HasGoodAlpha(Format) && Src->Alpha ) + { + if ( ! geBitmap_LockForRead(Src->Alpha,&(Ret->Alpha),mip,mip,GE_PIXELFORMAT_8BIT_GRAY,0,0) ) + { + geErrorLog_AddString(-1,"CreateLockFromMip : LockForRead failed", NULL); + geBitmap_Destroy(&Ret); + return NULL; + } + assert( Ret->Alpha ); + } + + assert( geBitmap_IsValid(Ret) ); + + if ( ! geBitmap_AllocSystemMip(Ret,0) ) + { + geBitmap_Destroy(&Ret); + return NULL; + } + + if ( ! geBitmap_BlitMip( Src, mip, Ret, 0 ) ) + { + geErrorLog_AddString(-1,"CreateLockFromMip : BlitMip failed", NULL); + geBitmap_Destroy(&Ret); + return NULL; + } + +return Ret; +} + +geBitmap * geBitmap_CreateLockFromMipSystem(geBitmap *Src,int mip,int LockCnt) +{ +geBitmap * Ret; + + assert( geBitmap_IsValid(Src) ); + if ( mip < Src->Info.MinimumMip || mip >= MAXMIPLEVELS ) + return NULL; + + if ( gePixelFormat_BytesPerPel(Src->Info.Format) < 1 ) + return NULL; + + if ( ! Src->Data[mip] ) + { + if ( ! geBitmap_MakeSystemMips(Src,mip,mip) ) + return NULL; + } + + Ret = geBitmap_CreateLock_CopyInfo(Src,LockCnt,mip); + + if ( ! Ret ) return NULL; + + Ret->Data[0] = Src->Data[mip]; + + Ret->Info.Palette = Src->Info.Palette; + if ( Ret->Info.Palette ) + geBitmap_Palette_CreateRef(Ret->Info.Palette); + + Ret->DataOwner = Src; + geBitmap_CreateRef(Src); + + assert( Ret->Alpha == NULL ); + if ( ! gePixelFormat_HasGoodAlpha(Src->Info.Format) && Src->Alpha ) + { + if ( ! geBitmap_LockForRead(Src->Alpha,&(Ret->Alpha),mip,mip,GE_PIXELFORMAT_8BIT_GRAY,0,0) ) + { + geErrorLog_AddString(-1,"CreateLockFromMipSystem : LockForRead failed", NULL); + geBitmap_Destroy(&Ret); + return NULL; + } + assert( Ret->Alpha ); + } + + assert( geBitmap_IsValid(Ret) ); + +return Ret; +} + +geBitmap * geBitmap_CreateLockFromMipOnDriver(geBitmap *Src,int mip,int LockCnt) +{ +geBitmap * Ret; + + assert( geBitmap_IsValid(Src) ); + if ( ! Src->DriverHandle || ! Src->Driver || Src->DriverMipLock || mip < Src->DriverInfo.MinimumMip || mip > Src->DriverInfo.MaximumMip ) + return NULL; + + // the driver can never have Wavelet data + // {} it could have S3TC data, though.. + assert( gePixelFormat_BytesPerPel(Src->DriverInfo.Format) > 0); + + Ret = geBitmap_CreateLock_CopyInfo(Src,LockCnt,mip); + + if ( ! Ret ) return NULL; + + Ret->DriverMipLock = mip; + Ret->DriverHandle = Src->DriverHandle; + + Ret->DataOwner = Src; + geBitmap_CreateRef(Src); + + Ret->DriverInfo.Palette = Src->DriverInfo.Palette; + + if ( ! geBitmap_MakeDriverLockInfo(Ret,mip,&(Ret->DriverInfo)) ) + { + geErrorLog_AddString(-1,"CreateLockFromMipOnDriver : UpdateInfo failed", NULL); + geBitmap_Destroy(&Ret); + return NULL; + } + + assert(Ret->DriverInfo.Palette == Src->DriverInfo.Palette); + + Ret->Info = Ret->DriverInfo; //{} shouldn't be necessary + + if ( Ret->DriverInfo.Palette ) + geBitmap_Palette_CreateRef(Ret->DriverInfo.Palette); + if ( Ret->Info.Palette ) + geBitmap_Palette_CreateRef(Ret->Info.Palette); + + assert( geBitmap_IsValid(Ret) ); + +return Ret; +} + +/*}{ ************* Driver Attachment *********************/ + +#define MAX_DRIVER_FORMATS (100) + +static geBoolean EnumPFCB(geRDriver_PixelFormat *pFormat,void *Context) +{ +geRDriver_PixelFormat **pDriverFormatsPtr; + pDriverFormatsPtr = Context; + **pDriverFormatsPtr = *pFormat; + (*pDriverFormatsPtr) += 1; +return GE_TRUE; +} + +static int NumBitsOn(uint32 val) +{ +uint32 count = 0; + while(val) + { + count += val&1; + val >>= 1; + } +return count; +} + +static geBoolean IsInArray(uint32 Val,uint32 *Array,int Len) +{ + while(Len--) + { + if ( Val == *Array ) + return GE_TRUE; + Array--; + } +return GE_FALSE; +} + +geBoolean geBitmap_ChooseDriverFormat( + gePixelFormat SeekFormat1, + gePixelFormat SeekFormat2, + geBoolean SeekCK, + geBoolean SeekAlpha, + geBoolean SeekSeparates, + uint32 SeekFlags, + geRDriver_PixelFormat *DriverFormatsArray,int ArrayLen, + geRDriver_PixelFormat *pTarget) +{ +int i,rating; +int FormatRating[MAX_DRIVER_FORMATS]; +geRDriver_PixelFormat * DriverPalFormat; +geRDriver_PixelFormat * pf; +geBoolean FoundAlpha; +uint32 SeekMajor,SeekMinor; +const gePixelFormat_Operations *seekops,*pfops; + + assert(pTarget && DriverFormatsArray && ArrayLen > 0); + + if ( SeekAlpha ) + SeekCK = GE_FALSE; // you can't have both + + if ( SeekFlags & RDRIVER_PF_ALPHA ) + SeekFlags = RDRIVER_PF_ALPHA; + else if ( SeekFlags & RDRIVER_PF_PALETTE ) + SeekFlags = RDRIVER_PF_PALETTE; + + SeekMajor = SeekFlags & RDRIVER_PF_MAJOR_MASK; + SeekMinor = SeekFlags - SeekMajor; + + pf = DriverFormatsArray; + DriverPalFormat = NULL; + for(i=0;iFlags & RDRIVER_PF_PALETTE ) + { + if ( ! DriverPalFormat || gePixelFormat_HasGoodAlpha(pf->PixelFormat) ) + DriverPalFormat = pf; + } + pf++; + } + + seekops = gePixelFormat_GetOperations(SeekFormat1); + + for(i=0;iFlags & RDRIVER_PF_MAJOR_MASK) == SeekMajor ) + { + rating += 1<<23; + } + else if ( (pf->Flags & SeekMajor) != SeekMajor ) + { + FormatRating[i] = 0; + continue; + } + else + { + // advantage to as few different major flags as possible + // higher priority than similarity of pixelformats + rating += (32 - NumBitsOn( (pf->Flags ^ SeekFlags) & RDRIVER_PF_MAJOR_MASK ))<<6; + } + + pfops = gePixelFormat_GetOperations(pf->PixelFormat); + + if ( pf->PixelFormat == SeekFormat1 ) + { + rating += 1<<16; + } + else if ( pf->PixelFormat == SeekFormat2 ) + { + rating += 1<<15; + } + else if ( gePixelFormat_IsRaw(SeekFormat1) && gePixelFormat_IsRaw(pf->PixelFormat) ) + { + int R,G,B,A; + // measure similarity + R = (seekops->RMask >> seekops->RShift) ^ (pfops->RMask >> pfops->RShift); + G = (seekops->GMask >> seekops->GShift) ^ (pfops->GMask >> pfops->GShift); + B = (seekops->BMask >> seekops->BShift) ^ (pfops->BMask >> pfops->BShift); + A = (seekops->AMask >> seekops->AShift) ^ (pfops->AMask >> pfops->AShift); + R = 8 - NumBitsOn(R); + G = 8 - NumBitsOn(G); + B = 8 - NumBitsOn(B); + A = 4*(8 - NumBitsOn(A)); // right number of A bits is molto importante + rating += (R + G + B + A); + } + else + { + // one of the formats is not raw + // palettized ? compressed ? + rating += 16; + } + + FoundAlpha = GE_FALSE; + + if ( NumBitsOn(pfops->AMask) > 2 ) + FoundAlpha = GE_TRUE; + + if ( gePixelFormat_HasPalette(pf->PixelFormat) ) + { + // if Pixelformat is 8BIT_PAL , look at the palette's format to see if it + // had alpha! + assert(DriverPalFormat); + if ( gePixelFormat_HasGoodAlpha(DriverPalFormat->PixelFormat) ) + FoundAlpha = GE_TRUE; + } + + if ( SeekAlpha && FoundAlpha ) + rating += 1<<24; // HIGHEST ! (except separates) + else if ( (!SeekAlpha) && (!FoundAlpha) ) + rating += 1<<10; // LOWEST + else if ( SeekAlpha ) + { + if ( NumBitsOn(pfops->AMask) || pf->Flags & RDRIVER_PF_CAN_DO_COLORKEY ) + { + // sought Alpha, found CK + rating += 1<<19; + } + } + + if ( (pf->Flags & RDRIVER_PF_HAS_ALPHA) && SeekSeparates ) + { + // separates doesn't count as alpha unless we asked for it ! + rating += 1<<25; // VERY HIGHEST ! + } + + if ( SeekCK ) + { + if ( pf->PixelFormat == GE_PIXELFORMAT_16BIT_1555_ARGB ) + { + rating += 1<<23; // just lower than alpha + } + else if ( FoundAlpha ) //better than nothing! + { + rating += 1<<18; // higher than !FoundAlpha + } + } + + if ( GE_BOOLSAME((pf->Flags & RDRIVER_PF_CAN_DO_COLORKEY),SeekCK) ) + { + rating += 1<<17; + } + + FormatRating[i] = rating; + } + + rating = 0; + + for(i=0;i rating ) + { + rating = FormatRating[i]; + *pTarget = DriverFormatsArray[i]; + } + } + + if ( rating == 0) + { + geErrorLog_AddString(-1,"ChooseDriverFormat : no valid formats found!", NULL); + return GE_FALSE; + } + + return GE_TRUE; +} +#if 0 +geBoolean geBitmap_ChooseDriverFormat( + gePixelFormat SeekFormat1, + gePixelFormat SeekFormat2, + geBoolean SeekCK, + geBoolean SeekAlpha, + geBoolean SeekSeparates, + uint32 SeekFlags, + geRDriver_PixelFormat *DriverFormatsArray,int ArrayLen, + geRDriver_PixelFormat *pTarget) +{ +int i,rating; +int FormatRating[MAX_DRIVER_FORMATS]; +geRDriver_PixelFormat * DriverPalFormat; +geRDriver_PixelFormat * pf; +geBoolean FoundAlpha; +uint32 SeekMajor,SeekMinor; +const gePixelFormat_Operations *seekops,*pfops; + + assert(pTarget && DriverFormatsArray && ArrayLen > 0); + +#if 0 // @@ + if ( SeekAlpha ) + SeekCK = GE_FALSE; // you can't have both, you bastard! +#endif + + if ( SeekFlags & RDRIVER_PF_ALPHA ) + SeekFlags = RDRIVER_PF_ALPHA; + else if ( SeekFlags & RDRIVER_PF_PALETTE ) + SeekFlags = RDRIVER_PF_PALETTE; + + if ( ! SeekFormat1 ) + SeekFormat1 = SeekFormat2; + + SeekMajor = SeekFlags & RDRIVER_PF_MAJOR_MASK; + SeekMinor = SeekFlags - SeekMajor; + + pf = DriverFormatsArray; + DriverPalFormat = NULL; + for(i=0;iFlags & RDRIVER_PF_PALETTE ) + { + assert( gePixelFormat_IsRaw(pf->PixelFormat) ); + if ( ! DriverPalFormat || gePixelFormat_HasGoodAlpha(pf->PixelFormat) ) + DriverPalFormat = pf; + } + pf++; + } + + seekops = gePixelFormat_GetOperations(SeekFormat1); + + for(i=0;iFlags & RDRIVER_PF_MAJOR_MASK) == SeekMajor ) + { + rating += 1<<23; + } + else if ( (pf->Flags & SeekMajor) != SeekMajor ) + { + FormatRating[i] = 0; + continue; + } + else + { + // advantage to as few different major flags as possible + // higher priority than similarity of pixelformats + rating += (32 - NumBitsOn( (pf->Flags ^ SeekFlags) & RDRIVER_PF_MAJOR_MASK )) <<6; + } + + pfops = gePixelFormat_GetOperations(pf->PixelFormat); + + if ( pf->PixelFormat == SeekFormat1 ) + { + rating += 1<<22; + } + else if ( pf->PixelFormat == SeekFormat2 ) + { + rating += 1<<21; + } + else if ( gePixelFormat_IsRaw(SeekFormat1) && gePixelFormat_IsRaw(pf->PixelFormat) ) + { + int R,G,B,A; + // measure similarity + R = (seekops->RMask >> seekops->RShift) ^ (pfops->RMask >> pfops->RShift); + G = (seekops->GMask >> seekops->GShift) ^ (pfops->GMask >> pfops->GShift); + B = (seekops->BMask >> seekops->BShift) ^ (pfops->BMask >> pfops->BShift); + A = (seekops->AMask >> seekops->AShift) ^ (pfops->AMask >> pfops->AShift); + R = 8 - NumBitsOn(R); + G = 8 - NumBitsOn(G); + B = 8 - NumBitsOn(B); + A = 4*(8 - NumBitsOn(A)); // right number of A bits is molto importante + rating += R + G + B + A; + } + + FoundAlpha = GE_FALSE; + + if ( NumBitsOn(pfops->AMask) > 2 ) + FoundAlpha = GE_TRUE; + + if ( gePixelFormat_HasPalette(pf->PixelFormat) ) + { + // if Pixelformat is 8BIT_PAL , look at the palette's format to see if it + // had alpha! + assert(DriverPalFormat); + if ( gePixelFormat_HasGoodAlpha(DriverPalFormat->PixelFormat) ) + FoundAlpha = GE_TRUE; + } + + if ( SeekAlpha && FoundAlpha ) + rating += 1<<24; // HIGHEST ! (except separates) + else if ( (!SeekAlpha) && (!FoundAlpha) ) + rating += 1<<16; // LOWEST + + if ( (pf->Flags & RDRIVER_PF_HAS_ALPHA) && SeekSeparates ) + { + // separates doesn't count as alpha unless we asked for it ! + rating += 1<<25; // VERY HIGHEST ! + } + + if ( (pf->PixelFormat == GE_PIXELFORMAT_16BIT_1555_ARGB) && SeekCK ) + { + rating += 1<<23; // just lower than alpha + } + else if ( GE_BOOLSAME((pf->Flags & RDRIVER_PF_CAN_DO_COLORKEY),SeekCK) ) + { + rating += 1<<20; + } + + if ( SeekCK && FoundAlpha ) //better than nothing! + { + rating += 1<<17; // higher than !FoundAlpha + } + + FormatRating[i] = rating; + } + + rating = 0; + + for(i=0;i rating ) + { + rating = FormatRating[i]; + *pTarget = DriverFormatsArray[i]; + } + } + + if ( rating == 0) + { + geErrorLog_AddString(-1,"ChooseDriverFormat : no valid formats found!", NULL); + return GE_FALSE; + } + + return GE_TRUE; +} +#endif + +geRDriver_THandle * geBitmap_CreateTHandle(DRV_Driver *Driver,int Width,int Height,int NumMipLevels, + gePixelFormat SeekFormat1,gePixelFormat SeekFormat2,geBoolean SeekCK,geBoolean SeekAlpha,geBoolean SeekSeparates,uint32 DriverFlags) +{ +geRDriver_PixelFormat DriverFormats[MAX_DRIVER_FORMATS]; +geRDriver_PixelFormat *DriverFormatsPtr; +int DriverFormatsCount; +geRDriver_PixelFormat DriverFormat; +geRDriver_THandle * Ret; + + DriverFormatsPtr = DriverFormats; + Driver->EnumPixelFormats(EnumPFCB,&DriverFormatsPtr); + DriverFormatsCount = ((uint32)DriverFormatsPtr - (uint32)DriverFormats)/sizeof(*DriverFormatsPtr); + assert(DriverFormatsCount < MAX_DRIVER_FORMATS && DriverFormatsCount >= 0); + + if ( DriverFormatsCount == 0 ) + { + geErrorLog_AddString(-1,"Bitmap_CreateTHandle : no formats found!", NULL); + return NULL; + } + + if ( ! SeekFormat1 ) + SeekFormat1 = SeekFormat2; + else if ( ! SeekFormat2 ) + SeekFormat2 = SeekFormat1; + + assert( gePixelFormat_IsValid(SeekFormat1) ); + assert( gePixelFormat_IsValid(SeekFormat2) ); + + // now choose DriverFormat + if ( ! geBitmap_ChooseDriverFormat(SeekFormat1,SeekFormat2,SeekCK,SeekAlpha,SeekSeparates,DriverFlags, + DriverFormats,DriverFormatsCount,&DriverFormat) ) + return NULL; + + assert( gePixelFormat_IsValid(DriverFormat.PixelFormat) ); + +#if 1 //{ + Log_Printf("Bitmap : Chose %s for %s", + gePixelFormat_Description(DriverFormat.PixelFormat), + gePixelFormat_Description(SeekFormat1)); + + if ( SeekFormat1 != SeekFormat2 ) + Log_Printf(" (%s)",gePixelFormat_Description(SeekFormat2)); + if ( SeekCK ) + Log_Printf(" (sought CK)"); + if ( SeekAlpha ) + Log_Printf(" (sought Alpha)"); + if ( DriverFormat.Flags & RDRIVER_PF_2D ) + Log_Printf(" (2D)"); + if ( DriverFormat.Flags & RDRIVER_PF_3D ) + Log_Printf(" (3D)"); + if ( DriverFormat.Flags & RDRIVER_PF_CAN_DO_COLORKEY ) + Log_Printf(" (can CK)"); + if ( DriverFormat.Flags & RDRIVER_PF_PALETTE ) + Log_Printf(" (Palette)"); + if ( DriverFormat.Flags & RDRIVER_PF_ALPHA ) + Log_Printf(" (Alpha)"); + if ( DriverFormat.Flags & RDRIVER_PF_LIGHTMAP ) + Log_Printf(" (Lightmap)"); + + Log_Printf("\n"); +#endif //} + + Ret = Driver->THandle_Create( + Width,Height, + NumMipLevels, + &DriverFormat); + + if ( ! Ret ) + { + geErrorLog_AddString(-1, Driver->LastErrorStr, NULL); + geErrorLog_AddString(-1,"Bitmap_CreateTHandle : Driver->THandle_Create failed", NULL); + } + +return Ret; +} + +GENESISAPI geBoolean GENESISCC geBitmap_HasAlpha(const geBitmap * Bmp) +{ + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->Alpha ) + return GE_TRUE; + + if ( gePixelFormat_HasGoodAlpha(Bmp->Info.Format) ) + return GE_TRUE; + + if ( gePixelFormat_HasPalette(Bmp->Info.Format) && Bmp->Info.Palette ) + { + if ( gePixelFormat_HasGoodAlpha(Bmp->Info.Palette->Format) ) + return GE_TRUE; + } + +return GE_FALSE; +} + +geBoolean BITMAP_GENESIS_INTERNAL geBitmap_AttachToDriver(geBitmap *Bmp, + DRV_Driver * Driver, uint32 DriverFlags) +{ + + /************** + * When you want to change the Driver, + * I still need a copy of the old one to get the bits out + * of the old THandles. That is: + * + * AttachDriver(Bmp,Driver) + * + * Change Driver Entries + * AttachDriver(Bmp,Driver) + * + * is forbidden! The two different options are : + * + * 1. + * + * AttachDriver(Bmp,Driver) + * + * DetachDriver(Bmp) + * Change Driver Entries + * AttachDriver(Bmp,Driver) + * + * 2. + * + * AttachDriver(Bmp,Driver1) + * + * Driver2 = copy of Driver1 + * Change Driver2 Entries + * AttachDriver(Bmp,Driver2) + * Free Driver1 + * + * This isn't so critical when just changing modes, + * but is critical when changing drivers. + * + ****************/ + + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner || Bmp->DataOwner || Bmp->LockCount ) + { + geErrorLog_AddString(-1,"AttachToDriver : not an isolated bitmap", NULL); + return GE_FALSE; + } + + if ( Bmp->DriverHandle && Bmp->Driver == Driver ) + { + assert( DriverFlags == 0 || DriverFlags == Bmp->DriverFlags ); + return GE_TRUE; + } + + if ( ! geBitmap_DetachDriver(Bmp,GE_TRUE) ) + { + geErrorLog_AddString(-1,"AttachToDriver : detach failed", NULL); + return GE_FALSE; + } + + if ( DriverFlags == 0 ) + { + DriverFlags = Bmp->DriverFlags; + if ( ! DriverFlags ) + { + // return GE_FALSE; + // ? {} + DriverFlags = RDRIVER_PF_3D; + } + } + + if ( Driver ) + { + int NumMipLevels; + int Width,Height; + geBoolean WantAlpha; + geRDriver_THandle * DriverHandle; + +// if ( Bmp->DriverFlags & RDRIVER_PF_COMBINE_LIGHTMAP ) +// Bmp->SeekMipCount = max(Bmp->SeekMipCount,4); + + NumMipLevels = max(Bmp->SeekMipCount,(Bmp->Info.MaximumMip + 1)); + if ( NumMipLevels > 4 ) NumMipLevels = 4; // {} kind of a hack, our drivers ignore mips > 4 + + // make sizes power-of-two and square + // {} note : must let drivers do this to correctly scale UV's + Width = Bmp->Info.Width; + Height = Bmp->Info.Height; + + WantAlpha = geBitmap_HasAlpha(Bmp); + if ( gePixelFormat_HasGoodAlpha(Bmp->PreferredFormat) ) + WantAlpha = GE_TRUE; + + assert( geBitmap_IsValid(Bmp) ); + + DriverHandle = geBitmap_CreateTHandle(Driver,Width,Height,NumMipLevels, + Bmp->PreferredFormat,Bmp->Info.Format,Bmp->Info.HasColorKey, + WantAlpha, (Bmp->Alpha) ? GE_TRUE : GE_FALSE, + DriverFlags); + + assert( geBitmap_IsValid(Bmp) ); + + if ( ! DriverHandle ) + return GE_FALSE; + + Bmp->DriverHandle = DriverHandle; + Bmp->Driver = Driver; + Bmp->DriverFlags = DriverFlags; + +#ifdef _DEBUG + Bmp->DriverInfo = Bmp->Info; + assert( geBitmap_IsValid(Bmp) ); +#endif + clear(&(Bmp->DriverInfo)); + + if ( ! geBitmap_MakeDriverLockInfo(Bmp,0,&(Bmp->DriverInfo)) ) + { + geErrorLog_AddString(-1,"AttachToDriver : updateinfo", NULL); + return GE_FALSE; + } + + Bmp->DriverInfo.MinimumMip = 0; + Bmp->DriverInfo.MaximumMip = NumMipLevels - 1; + + assert( geBitmap_IsValid(Bmp) ); + + assert( geBitmap_IsValid(Bmp) ); + + if ( ! geBitmap_Update_SystemToDriver(Bmp) ) + { + geErrorLog_AddString(-1,"AttachToDriver : Update_SystemToDriver", NULL); + Driver->THandle_Destroy(Bmp->DriverHandle); + Bmp->DriverHandle = NULL; + return GE_FALSE; + } + + // {} Palette : Update_System calls Blit_Data, which should build it for us + // if Driver is pal & System isn't + } + +return GE_TRUE; +} + +geBoolean geBitmap_FixDriverFlags(uint32 *pFlags) +{ +uint32 DriverFlags; + assert(pFlags); + DriverFlags = *pFlags; + + if ( DriverFlags & RDRIVER_PF_COMBINE_LIGHTMAP ) + DriverFlags |= RDRIVER_PF_3D; + if ( DriverFlags & RDRIVER_PF_CAN_DO_COLORKEY ) + { + // <> someone is doing this! + // bad! + DriverFlags ^= RDRIVER_PF_CAN_DO_COLORKEY; + // return GE_FALSE; + } + if ( (DriverFlags & RDRIVER_PF_COMBINE_LIGHTMAP) && + (DriverFlags & (RDRIVER_PF_LIGHTMAP | RDRIVER_PF_PALETTE) ) ) + return GE_FALSE; + if ( NumBitsOn(DriverFlags & RDRIVER_PF_MAJOR_MASK) == 0 ) + return GE_FALSE; + *pFlags = DriverFlags; +return GE_TRUE; +} + +geBoolean BITMAP_GENESIS_INTERNAL geBitmap_SetDriverFlags(geBitmap *Bmp,uint32 Flags) +{ + assert( geBitmap_IsValid(Bmp) ); + assert(Flags); + if ( ! geBitmap_FixDriverFlags(&Flags) ) + { + Bmp->DriverFlags = 0; + return GE_FALSE; + } + Bmp->DriverFlags = Flags; +return GE_TRUE; +} + +geBoolean BITMAP_GENESIS_INTERNAL geBitmap_DetachDriver(geBitmap *Bmp,geBoolean DoUpdate) +{ +geBoolean Ret = GE_TRUE; + + assert(geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner || Bmp->DataOwner || Bmp->LockCount ) + { + geErrorLog_AddString(-1,"DetachDriver : not an isolated bitmap!", NULL); + return GE_FALSE; + } + + if ( Bmp->RefCount > 1 ) + DoUpdate = GE_TRUE; + + if ( Bmp->Driver && Bmp->DriverHandle ) + { + if ( DoUpdate ) + { + if ( ! geBitmap_Update_DriverToSystem(Bmp) ) + { + geErrorLog_AddString(-1,"DetachDriver : Update_DriverToSystem", NULL); + Ret = GE_FALSE; + } + assert(Bmp->DriverDataChanged == GE_FALSE); + } + Bmp->Driver->THandle_Destroy(Bmp->DriverHandle); + Bmp->DriverHandle = NULL; + } + + if ( Bmp->DriverInfo.Palette ) + { + // save it for later in case we re-attach + if ( ! Bmp->Info.Palette ) + { + geBitmap_Palette * NewPal; + gePixelFormat Format; + Format = Bmp->DriverInfo.Palette->Format; + NewPal = geBitmap_Palette_Create(Format,256); + if ( NewPal ) + { + if ( geBitmap_Palette_Copy(Bmp->DriverInfo.Palette,NewPal) ) + { + Bmp->Info.Palette = NewPal; + } + else + { + geBitmap_Palette_Destroy(&NewPal); + } + } + } + + geBitmap_Palette_Destroy(&(Bmp->DriverInfo.Palette)); + } + + if ( Bmp->Alpha ) + { + if ( ! geBitmap_DetachDriver(Bmp->Alpha,DoUpdate) ) + { + geErrorLog_AddString(-1,"DetachDriver : detach alpha", NULL); + Ret = GE_FALSE; + } + } + + Bmp->DriverInfo.Width = Bmp->DriverInfo.Height = Bmp->DriverInfo.Stride = 0; + Bmp->DriverInfo.MinimumMip = Bmp->DriverInfo.MaximumMip = 0; + Bmp->DriverInfo.ColorKey = Bmp->DriverInfo.HasColorKey = Bmp->DriverInfo.Format = 0; + Bmp->DriverInfo.Palette = NULL; + Bmp->DriverMipLock = 0; + Bmp->DriverBitsLocked = GE_FALSE; + Bmp->DriverDataChanged = GE_FALSE; + Bmp->DriverHandle = NULL; + Bmp->Driver = NULL; + + //Bmp->DriverFlags left intentionally ! + +return Ret; +} + +geBoolean GENESISCC geBitmap_SetGammaCorrection_DontChange(geBitmap *Bmp,geFloat Gamma) +{ + assert(geBitmap_IsValid(Bmp)); + assert( Gamma > 0.0f ); + + if ( ! Bmp->DriverGammaSet ) + { + Bmp->DriverGammaLast = Bmp->DriverGamma; + Bmp->DriverGamma = Gamma; + } + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_SetGammaCorrection(geBitmap *Bmp,geFloat Gamma,geBoolean Apply) +{ + assert(geBitmap_IsValid(Bmp)); + assert( Gamma > 0.0f ); + + /*** + + there are actually some anomalies involved in exposing this to the user: + if the driver's gamma correction is turned on, then this Gamma will be applied *in addition* to the driver gamma. + There's no easy way to avoid that problem. + + we like to expose this to the user so that they can disable software gamma correction on some bitmaps + (eg. procedurals) + perhaps provide a Bitmap_DisableGamma(Bmp) instead of SetGamma ? + + **/ + + if ( Apply && Bmp->DriverHandle ) + { + if ( fabs(Bmp->DriverGamma - Gamma) > 0.1f ) + { + if ( gePixelFormat_BytesPerPel(Bmp->Info.Format) == 0 && Bmp->DriverHandle ) + { + // system format is compressed, and Bmp is on the card + + if ( (Bmp->DriverGammaLast >= Bmp->DriverGamma && Bmp->DriverGamma >= Gamma) || + (Bmp->DriverGammaLast <= Bmp->DriverGamma && Bmp->DriverGamma <= Gamma) ) + { + // moving in the same direction + + // invert the old + if ( ! geBitmap_Gamma_Apply(Bmp,GE_TRUE) ) + return GE_FALSE; + + Bmp->DriverGammaLast = Bmp->DriverGamma; + Bmp->DriverGamma = Gamma; + + // apply the new + if ( ! geBitmap_Gamma_Apply(Bmp,GE_FALSE) ) + return GE_FALSE; + } + else + { + // changed direction so must do an update + + if ( ! geBitmap_Update_DriverToSystem(Bmp) ) + return GE_FALSE; + + Bmp->DriverGammaLast = Bmp->DriverGamma = Gamma; + + if ( ! geBitmap_Update_SystemToDriver(Bmp) ) + return GE_FALSE; + } + } + else + { + if ( ! geBitmap_Update_DriverToSystem(Bmp) ) + return GE_FALSE; + + Bmp->DriverGammaLast = Bmp->DriverGamma = Gamma; + + if ( ! geBitmap_Update_SystemToDriver(Bmp) ) + return GE_FALSE; + } + } + } + else + { + Bmp->DriverGamma = Gamma; + } + Bmp->DriverGammaSet = GE_TRUE; + +return GE_TRUE; +} + +geRDriver_THandle * BITMAP_GENESIS_INTERNAL geBitmap_GetTHandle(const geBitmap *Bmp) +{ +// assert( geBitmap_IsValid(Bmp) ); + + return Bmp->DriverHandle; +} + +geBoolean geBitmap_Update_SystemToDriver(geBitmap *Bmp) +{ +geBitmap * SrcLocks[MAXMIPLEVELS]; +geBoolean Ret,MipsChanged; +int mip,mipMin,mipMax; +geRDriver_THandle * SaveDriverHandle; +geBitmap * SaveAlpha; +int SaveMaxMip; + + assert( geBitmap_IsValid(Bmp) ); + + /** + + this function is totally hacked out, because what we really need to do + is lock Bmp for Read (system) & Write (driver) , but that's illegal! + + **/ + + if ( Bmp->LockOwner ) + Bmp = Bmp->LockOwner; + + if ( Bmp->LockCount > 0 || Bmp->DataOwner ) + { + geErrorLog_AddString(-1,"Update_SystemToDriver : not an original bitmap", NULL); + return GE_FALSE; + } + + if ( ! Bmp->DriverHandle ) + { + geErrorLog_AddString(-1,"Update_SystemToDriver : no driver data", NULL); + return GE_FALSE; + } + + MipsChanged = GE_FALSE; + for(mip=Bmp->DriverInfo.MinimumMip;mip<=Bmp->DriverInfo.MaximumMip;mip++) + { + if ( Bmp->Modified[mip] && mip != Bmp->Info.MinimumMip ) + { + assert(Bmp->Data[mip]); + MipsChanged = GE_TRUE; + } + } + + //make mips after driver blit + +#if 0 + MipsChanged = GE_TRUE; +#endif + + mipMin = Bmp->DriverInfo.MinimumMip; + + if ( MipsChanged ) + mipMax = Bmp->DriverInfo.MaximumMip; + else + mipMax = mipMin; + + + SaveDriverHandle = Bmp->DriverHandle; + Bmp->DriverHandle = NULL; // so Lock() won't use the driver data + + SaveAlpha = Bmp->Alpha; + + if ( Bmp->Alpha && ! gePixelFormat_HasGoodAlpha(Bmp->DriverInfo.Format) && + (Bmp->DriverFlags & RDRIVER_PF_HAS_ALPHA) ) + { + // hide the alpha so that it won't be used to make a colorkey in the target + // we'll blit it independently later + Bmp->Alpha = NULL; + } + + if ( ! geBitmap_LockForReadNative(Bmp,SrcLocks,mipMin,mipMax) ) + { + geErrorLog_AddString(-1,"Update_SystemToDriver : LockForReadNative", NULL); + return GE_FALSE; + } + + Ret = GE_TRUE; + Bmp->DriverHandle = SaveDriverHandle; + Bmp->Alpha = NULL; + + // we should have always updated the driver to system before fiddling the system + assert( ! Bmp->DriverDataChanged ); + + /** + + Bmp is a driver BMP + + the SrcLocks are locks of the system bits. + + **/ + + for(mip=mipMin;mip <=mipMax;mip++) + { + geBitmap *SrcMip; + void * SrcBits,*DstBits; + geBitmap_Info DstInfo; + + SrcMip = SrcLocks[mip - mipMin]; + SrcBits = geBitmap_GetBits(SrcMip); + + DstInfo = Bmp->DriverInfo; + + if ( ! geBitmap_MakeDriverLockInfo(Bmp,mip,&DstInfo) ) + { + geErrorLog_AddString(-1,"Update_SystemToDriver : MakeInfo", NULL); + Ret = GE_FALSE; + continue; + } + + // Zooma! THandle_Lock might lock the Win16 Lock ! + // this is really bad when _BlitData is a wavelet decompress ! + // {} try this : decompress to a buffer in memory (on a thread) + // then THandle_Lock and just do a (prefetching) memcpy + //#pragma message("Bitmap : minimize time spent in a THandle_Lock!") + + if ( ! Bmp->Driver->THandle_Lock(SaveDriverHandle,mip,&DstBits) ) + { + geErrorLog_AddString(-1,"Update_SystemToDriver : THandle_Lock", NULL); + Ret = GE_FALSE; + continue; + } + + if ( ! SrcBits || ! DstBits ) + { + geErrorLog_AddString(-1,"Update_SystemToDriver : No Bits", NULL); + Ret = GE_FALSE; + continue; + } + + assert( DstInfo.Palette == Bmp->DriverInfo.Palette ); + + if ( ! geBitmap_BlitData( &(SrcMip->Info),SrcBits,SrcMip, + &DstInfo, DstBits,Bmp, + SrcMip->Info.Width,SrcMip->Info.Height) ) + { + geErrorLog_AddString(-1,"Update_SystemToDriver : BlitData", NULL); + //assert(0); + Ret = GE_FALSE; + continue; + } + + if ( ! Bmp->Driver->THandle_UnLock(SaveDriverHandle,mip) ) + { + geErrorLog_AddString(-1,"Update_SystemToDriver : THandle_UnLock", NULL); + Ret = GE_FALSE; + continue; + } + + // normally this would be done by the Bitmap_UnLock , + // but since we don't lock .. + if ( DstInfo.Palette != Bmp->DriverInfo.Palette ) + { + //assert( OldDstPal == NULL ); + geBitmap_SetPalette(Bmp,DstInfo.Palette); + geBitmap_Palette_Destroy(&(DstInfo.Palette)); + // must destroy here, since DstInfo is on the stack! + } + } + + Bmp->Alpha = SaveAlpha; + Bmp->DriverBitsLocked = GE_FALSE; + Bmp->DriverMipLock = 0; + Bmp->DriverDataChanged = GE_FALSE; + + geBitmap_UnLockArray(SrcLocks, mipMax - mipMin + 1 ); + + if ( ! Ret ) + { + geErrorLog_AddString(-1,"Update_SystemToDriver : Locking and Blitting error", NULL); + } + + if ( Bmp->Alpha && ! gePixelFormat_HasGoodAlpha(Bmp->DriverInfo.Format) && + (Bmp->DriverFlags & RDRIVER_PF_HAS_ALPHA) ) + { + geRDriver_THandle * AlphaTH; + + // blit the alpha surface to the separate alpha + + AlphaTH = Bmp->Driver->THandle_GetAlpha(Bmp->DriverHandle); + if ( !AlphaTH || AlphaTH != Bmp->Alpha->DriverHandle) + { + if ( ! geBitmap_AttachToDriver(Bmp->Alpha,Bmp->Driver,Bmp->Alpha->DriverFlags | RDRIVER_PF_ALPHA) ) + { + geErrorLog_AddString(-1,"AttachToDriver : attach Alpha", NULL); + return GE_FALSE; + } + + assert(Bmp->Alpha->DriverHandle); + if ( ! Bmp->Driver->THandle_SetAlpha(Bmp->DriverHandle,Bmp->Alpha->DriverHandle) ) + { + geErrorLog_AddString(-1,"AttachToDriver : THandle_SetAlpha", NULL); + geBitmap_DetachDriver(Bmp->Alpha,GE_FALSE); + geBitmap_DetachDriver(Bmp,GE_FALSE); + return GE_FALSE; + } + + AlphaTH = Bmp->Driver->THandle_GetAlpha(Bmp->DriverHandle); + assert(AlphaTH == Bmp->Alpha->DriverHandle); + } + } + + // now bits are on driver , gamma correct them + + //for gamma : just Gamma up to mipMax then make mips from it + // seems to work + + SaveMaxMip = Bmp->DriverInfo.MaximumMip; + Bmp->DriverInfo.MaximumMip = mipMax; + if ( ! geBitmap_Gamma_Apply(Bmp,GE_FALSE) ) + { + geErrorLog_AddString(-1,"AttachToDriver : Gamma_Apply failed!", NULL); + Ret = GE_FALSE; + } + Bmp->DriverInfo.MaximumMip = SaveMaxMip; + + if ( ! MipsChanged && mipMax < Bmp->DriverInfo.MaximumMip ) + { + for(mip=mipMax+1;mip<= Bmp->DriverInfo.MaximumMip; mip++) + { + if ( ! geBitmap_UpdateMips(Bmp,mip-1,mip) ) + { + geErrorLog_AddString(-1,"AttachToDriver : UpdateMips on driver failed!", NULL); + return GE_FALSE; + } + } + } + + Bmp->DriverDataChanged = GE_FALSE; // in case _SetPal freaks us out + +return Ret; +} + +geBoolean geBitmap_Update_DriverToSystem(geBitmap *Bmp) +{ +geBitmap *DriverLocks[MAXMIPLEVELS]; +geBoolean Ret; +int mip; + + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner ) + Bmp = Bmp->LockOwner; + + if ( Bmp->LockCount > 0 || Bmp->DataOwner ) + { + geErrorLog_AddString(-1,"Update_DriverToSystem : not an original bitmap", NULL); + return GE_FALSE; + } + + if ( ! Bmp->DriverHandle ) + { + geErrorLog_AddString(-1,"Update_DriverToSystem : no driver data", NULL); + return GE_FALSE; + } + + if ( ! Bmp->DriverDataChanged ) + return GE_TRUE; + + // bits are on driver; undo the gamma to copy them home + + Log_Puts("Bitmap : Doing Update_DriverToSystem"); + + if ( ! geBitmap_Gamma_Apply(Bmp,GE_TRUE) ) // undo the gamma! + return GE_FALSE; + + if ( Bmp->Info.Palette && Bmp->DriverInfo.Palette ) + { + if ( ! geBitmap_Palette_Copy(Bmp->DriverInfo.Palette,Bmp->Info.Palette) ) + { + geErrorLog_AddString(-1,"Update_DriverToSystem : Palette_Copy", NULL); + } + } + + if ( geBitmap_LockForReadNative(Bmp,DriverLocks, + Bmp->DriverInfo.MinimumMip,Bmp->DriverInfo.MaximumMip) ) + { + Ret = GE_TRUE; + + for(mip=Bmp->DriverInfo.MinimumMip;mip <=Bmp->DriverInfo.MaximumMip;mip++) + { + geBitmap *MipBmp; + geBitmap_Info SystemInfo; + + MipBmp = DriverLocks[mip]; + + if ( Bmp->Modified[mip] ) + { + void *DriverBits,*SystemBits; + DriverBits = geBitmap_GetBits(MipBmp); + assert( MipBmp->DriverBitsLocked ); + + if ( ! geBitmap_AllocSystemMip(Bmp,mip) ) + Ret = GE_FALSE; + + SystemBits = Bmp->Data[mip]; + + geBitmap_MakeMipInfo(&(Bmp->Info),mip,&SystemInfo); + + if ( DriverBits && SystemBits ) + { + // _Update_DriverToSystem + // {} palette (not) made in AttachToDriver; must be made in here-> + if ( ! geBitmap_BlitData( &(MipBmp->Info), DriverBits, MipBmp, + &SystemInfo, SystemBits, Bmp, + SystemInfo.Width,SystemInfo.Height) ) + Ret = GE_FALSE; + } + else + { + Ret = GE_FALSE; + } + } + + geBitmap_UnLock(DriverLocks[mip]); + } + + Bmp->DriverDataChanged = GE_FALSE; + } + else + { + Ret = GE_FALSE; + } + + if ( ! Ret ) + { + geErrorLog_AddString(-1,"Update_DriverToSystem : Locking and Blitting error", NULL); + } + + if ( ! geBitmap_Gamma_Apply(Bmp,GE_FALSE) ) // redo the gamma! + return GE_FALSE; + +return Ret; +} + +/*}{ ************* Mip Control *****************/ + +// Note : all the Mip control + +GENESISAPI geBoolean GENESISCC geBitmap_RefreshMips(geBitmap *Bmp) +{ +int mip; + + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner || Bmp->LockCount || Bmp->DataOwner ) + return GE_FALSE; + + for(mip = (Bmp->Info.MinimumMip + 1);mip <= Bmp->Info.MaximumMip;mip++) + { + if ( Bmp->Data[mip] && !(Bmp->Modified[mip]) ) + { + int src; + src = mip-1; + while( ! Bmp->Data[src] ) + { + src--; + if ( src < Bmp->Info.MinimumMip ) + return GE_FALSE; + } + if ( ! geBitmap_UpdateMips(Bmp,src,mip) ) + return GE_FALSE; + } + } + +#if 0 // never turn off a modified flag + for(mip=0;mipModified[mip] = GE_FALSE; +#endif + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_UpdateMips(geBitmap *Bmp,int fm,int to) +{ +geBitmap * Locks[MAXMIPLEVELS]; +void *FmBits,*ToBits; +geBitmap_Info FmInfo,ToInfo; +geBoolean Ret = GE_FALSE; + + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner || Bmp->LockCount > 0 || Bmp->DataOwner ) + return GE_FALSE; + + if ( fm >= to ) + return GE_FALSE; + + if ( Bmp->DriverHandle ) + { + //{} this version does *NOT* make new mips if to > Bmp->DriverInfo.MaximumMip + + if ( ! geBitmap_LockForWrite(Bmp,Locks,fm,to) ) + return GE_FALSE; + + if ( geBitmap_GetInfo(Locks[0],&FmInfo,NULL) && geBitmap_GetInfo(Locks[to - fm],&ToInfo,NULL) ) + { + FmBits = geBitmap_GetBits(Locks[0]); + ToBits = geBitmap_GetBits(Locks[to - fm]); + + if ( FmBits && ToBits ) + { + Ret = geBitmap_UpdateMips_Data( &FmInfo, FmBits, + &ToInfo, ToBits ); + } + } + + geBitmap_UnLockArray_NoChange(Locks,to - fm + 1); + } + else + { + Ret = geBitmap_UpdateMips_System(Bmp,fm,to); + } + +return Ret; +} + +geBoolean geBitmap_UpdateMips_System(geBitmap *Bmp,int fm,int to) +{ +geBitmap_Info FmInfo,ToInfo; +geBoolean Ret; + + assert( geBitmap_IsValid(Bmp) ); + + // this is called to create new mips in LockFor* -> CreateLockFrom* (through MakeSystemMips) + + if ( Bmp->LockOwner ) + Bmp = Bmp->LockOwner; +// if ( Bmp->LockCount > 0 ) +// return GE_FALSE; + if ( Bmp->DataOwner ) + return GE_FALSE; + + // {} for compressed data, just don't make mips and say we did! + if ( gePixelFormat_BytesPerPel(Bmp->Info.Format) < 1 ) + return GE_TRUE; + + while(Bmp->Data[fm] == NULL || fm == to ) + { + fm--; + if ( fm < 0 ) + return GE_FALSE; + } + + if ( fm < Bmp->Info.MinimumMip || fm > Bmp->Info.MaximumMip || + to < fm || to >= MAXMIPLEVELS ) + return GE_FALSE; + + if ( ! Bmp->Data[to] ) + { + if ( ! geBitmap_AllocSystemMip(Bmp,to) ) + return GE_FALSE; + } + + assert( to > fm && fm >= 0 ); + + FmInfo = ToInfo = Bmp->Info; + + FmInfo.Width = SHIFT_R_ROUNDUP(Bmp->Info.Width ,fm); + FmInfo.Height= SHIFT_R_ROUNDUP(Bmp->Info.Height,fm); + FmInfo.Stride= SHIFT_R_ROUNDUP(Bmp->Info.Stride,fm); + ToInfo.Width = SHIFT_R_ROUNDUP(Bmp->Info.Width ,to); + ToInfo.Height= SHIFT_R_ROUNDUP(Bmp->Info.Height,to); + ToInfo.Stride= SHIFT_R_ROUNDUP(Bmp->Info.Stride,to); + + Ret = geBitmap_UpdateMips_Data( &FmInfo, Bmp->Data[fm], + &ToInfo, Bmp->Data[to]); + + Bmp->Info.MaximumMip = max(Bmp->Info.MaximumMip,to); + +return Ret; +} + +geBoolean geBitmap_UpdateMips_Data( geBitmap_Info * FmInfo,void * FmBits, + geBitmap_Info * ToInfo,void * ToBits) +{ +int fmxtra,tow,toh,toxtra,fmw,fmh,fmstep,x,y,bpp; + + assert( FmInfo && ToInfo && FmBits && ToBits ); + assert( FmInfo->Format == ToInfo->Format && FmInfo->HasColorKey == ToInfo->HasColorKey ); + + tow = ToInfo->Width; + toh = ToInfo->Height; + toxtra = ToInfo->Stride - ToInfo->Width; + + x = ToInfo->Width; + fmstep = 1; + while( x < FmInfo->Width ) + { + fmstep += fmstep; + x += x; + } + + fmw = FmInfo->Width; + fmh = FmInfo->Height; + fmxtra = (FmInfo->Stride - tow) * fmstep; // amazingly simple and correct! think about it! + + // fmh == 15 + // toh == 8 + // fmstep == 2 + // 7*2 <= 14 -> Ok + if ( (toh-1)*fmstep > (fmh - 1) ) + { + geErrorLog_AddString(-1,"UpdateMips_Data : Vertical mip scaling doesn't match horizontal!", NULL); + return GE_FALSE; + } + + // {} todo : average for some special cases (16rgb,24rgb,32rgb) + + bpp = gePixelFormat_BytesPerPel(FmInfo->Format); + + if ( fmstep == 2 && bpp > 1 ) + { + int R1,G1,B1,A1,R2,G2,B2,A2,R3,G3,B3,A3,R4,G4,B4,A4; + gePixelFormat_ColorGetter GetColor; + gePixelFormat_ColorPutter PutColor; + const gePixelFormat_Operations *ops; + uint8 *fmp,*fmp2,*top; + + fmp = FmBits; + top = ToBits; + + ops = gePixelFormat_GetOperations(FmInfo->Format); + GetColor = ops->GetColor; + PutColor = ops->PutColor; + + fmxtra *= bpp; + toxtra *= bpp; + + if ( FmInfo->HasColorKey ) + { + uint32 ck,p1,p2,p3,p4; + gePixelFormat_PixelGetter GetPixel; + gePixelFormat_PixelPutter PutPixel; + gePixelFormat_Decomposer DecomposePixel; + int32 PixelComposeRTable[]={0x696C6345,0x21657370}; + + assert( FmInfo->ColorKey == ToInfo->ColorKey ); + ck = FmInfo->ColorKey; + GetPixel = ops->GetPixel; + PutPixel = ops->PutPixel; + DecomposePixel = ops->DecomposePixel; + + // {} the colorkey mip-subsampler + // slow; yet another reason to not use CK ! + + for(y=toh;y--;) + { + //y = 7, fmh = 15; y*2+1 == fmh : last line is not a double line + if ( (y+y + 1) == fmh ) fmp2 = fmp; + else fmp2 = fmp + (FmInfo->Stride*bpp); + for(x=tow;x--;) + { + p1 = GetPixel(&fmp); + p2 = GetPixel(&fmp); + p3 = GetPixel(&fmp2); + p4 = GetPixel(&fmp2); + if ( p1 == ck || p4 == ck ) + { + PutPixel(&top,ck); + } + else + { + // p1 and p4 are not ck; + if ( p2 == ck ) p2 = p1; + if ( p3 == ck ) p3 = p4; + DecomposePixel(p1,&R1,&G1,&B1,&A1); + DecomposePixel(p2,&R2,&G2,&B2,&A2); + DecomposePixel(p3,&R3,&G3,&B3,&A3); + DecomposePixel(p4,&R4,&G4,&B4,&A4); + PutColor(&top,(R1+R2+R3+R4+2)>>2,(G1+G2+G3+G4+2)>>2,(B1+B2+B3+B4+2)>>2,(A1+A2+A3+A4+2)>>2); + } + } + fmp += fmxtra; + top += toxtra; + } + } + else + { + for(y=toh;y--;) + { + //y = 7, fmh = 15; y*2+1 == fmh : last line is not a double line + if ( (y+y + 1) == fmh ) fmp2 = fmp; + else fmp2 = fmp + (FmInfo->Stride*bpp); + for(x=tow;x--;) + { + GetColor(&fmp ,&R1,&G1,&B1,&A1); + GetColor(&fmp ,&R2,&G2,&B2,&A2); + GetColor(&fmp2,&R3,&G3,&B3,&A3); + GetColor(&fmp2,&R4,&G4,&B4,&A4); + PutColor(&top,(R1+R2+R3+R4+2)>>2,(G1+G2+G3+G4+2)>>2,(B1+B2+B3+B4+2)>>2,(A1+A2+A3+A4+2)>>2); + } + fmp += fmxtra; + top += toxtra; + } + } + + assert( top == (((uint8 *)ToBits) + ToInfo->Stride * ToInfo->Height * bpp ) ); + assert( fmp == (((uint8 *)FmBits) + FmInfo->Stride * ToInfo->Height * 2 * bpp ) ); + } + else if ( fmstep == 2 && gePixelFormat_HasPalette(FmInfo->Format) ) + { + int R,G,B; + uint8 *fmp,*fmp2,*top; + uint8 paldata[768],*palptr; + int p; + palInfo * PalInfo; + + assert(bpp == 1); + assert(FmInfo->Palette); + + if ( ! geBitmap_Palette_GetData(FmInfo->Palette,paldata,GE_PIXELFORMAT_24BIT_RGB,256) ) + return GE_FALSE; + + if ( ! (PalInfo = closestPalInit(paldata)) ) + return GE_FALSE; + + fmp = FmBits; + top = ToBits; + + // @@ colorkey? + + for(y=toh;y--;) + { + //y = 7, fmh = 15; y*2+1 == fmh : last line is not a double line + if ( (y*2 + 1) == fmh ) fmp2 = fmp; + else fmp2 = fmp + (FmInfo->Stride*bpp); + + for(x=tow;x--;) + { + p = *fmp++; + palptr = paldata + p*3; + R = palptr[0]; G = palptr[1]; B = palptr[2]; + p = *fmp++; + palptr = paldata + p*3; + R += palptr[0]; G += palptr[1]; B += palptr[2]; + p = *fmp2++; + palptr = paldata + p*3; + R += palptr[0]; G += palptr[1]; B += palptr[2]; + p = *fmp2++; + palptr = paldata + p*3; + R += palptr[0]; G += palptr[1]; B += palptr[2]; + + R = (R+2)>>2; + G = (G+2)>>2; + B = (B+2)>>2; + + p = closestPal(R,G,B,PalInfo); + *top++ = p; + } + fmp += fmxtra; + top += toxtra; + } + + closestPalFree(PalInfo); + + assert( top == (((uint8 *)ToBits) + ToInfo->Stride * ToInfo->Height * bpp ) ); + assert( fmp == (((uint8 *)FmBits) + FmInfo->Stride * ToInfo->Height * 2 * bpp ) ); + } + else + { + // we just sub-sample to make mips, so we don't have to + // know anything about pixelformat. + // (btw this spoils the whole point of mips, so we might as well kill the mip!) + + //{} Blend correctly !? + + switch( bpp ) + { + default: + { + return GE_FALSE; + } + case 1: + { + uint8 *fmp,*top; + fmp = FmBits; + top = ToBits; + for(y=toh;y--;) + { + for(x=tow;x--;) + { + *top++ = *fmp; + fmp += fmstep; + } + fmp += fmxtra; + top += toxtra; + } + break; + } + case 2: + { + uint16 *fmp,*top; + fmp = FmBits; + top = ToBits; + for(y=toh;y--;) + { + for(x=tow;x--;) + { + *top++ = *fmp; + fmp += fmstep; + } + fmp += fmxtra; + top += toxtra; + } + break; + } + case 4: + { + uint32 *fmp,*top; + fmp = FmBits; + top = ToBits; + for(y=toh;y--;) + { + for(x=tow;x--;) + { + *top++ = *fmp; + fmp += fmstep; + } + fmp += fmxtra; + top += toxtra; + } + break; + } + case 3: + { + uint8 *fmp,*top; + fmp = FmBits; + top = ToBits; + fmstep = (fmstep - 1) * 3; + fmxtra *= 3; + toxtra *= 3; + for(y=toh;y--;) + { + for(x=tow;x--;) + { + *top++ = *fmp++; + *top++ = *fmp++; + *top++ = *fmp++; + fmp += fmstep; + } + fmp += fmxtra; + top += toxtra; + } + break; + } + } + } + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_ClearMips(geBitmap *Bmp) +{ +int mip; +DRV_Driver * Driver; + + // WARNING ! This destroys any mips! + + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner || Bmp->LockCount || Bmp->DataOwner ) + return GE_FALSE; + + if ( Bmp->SeekMipCount == 0 && Bmp->Info.MaximumMip == 0 ) + return GE_TRUE; + + Driver = Bmp->Driver; + if ( Driver ) + { + if ( ! geBitmap_DetachDriver(Bmp,GE_TRUE) ) + return GE_FALSE; + } + assert(Bmp->Driver == NULL); + + mip = Bmp->Info.MinimumMip; + if ( mip == 0 ) + mip++; + + Bmp->SeekMipCount = mip; + + for( ; mip <= Bmp->Info.MaximumMip ; mip++) + { + if ( Bmp->Data[mip] ) + { + geRam_Free( Bmp->Data[mip] ); + Bmp->Data[mip] = NULL; + } + } + + Bmp->Info.MaximumMip = Bmp->Info.MinimumMip; + + if ( Driver ) + { + if ( ! geBitmap_AttachToDriver(Bmp,Driver,0) ) + return GE_FALSE; + } + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_SetMipCount(geBitmap *Bmp,int Count) +{ +DRV_Driver * Driver; + + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner || Bmp->LockCount || Bmp->DataOwner ) + return GE_FALSE; + + if ( Bmp->SeekMipCount == Count ) + { + Driver = NULL; + } + else + { + Driver = Bmp->Driver; + if ( Driver ) + { + if ( ! geBitmap_DetachDriver(Bmp,GE_TRUE) ) + return GE_FALSE; + } + assert(Bmp->Driver == NULL); + } + + Bmp->SeekMipCount = Count; + +// @@ don't do this ? +// if ( Bmp->Info.MaximumMip < (Count-1) ) +// geBitmap_MakeSystemMips(Bmp,0,Count-1); +// + + if ( Driver ) + { + if ( ! geBitmap_AttachToDriver(Bmp,Driver,0) ) + return GE_FALSE; + } + +return GE_TRUE; +} + +geBoolean geBitmap_MakeSystemMips(geBitmap *Bmp,int low,int high) +{ +int mip; + + assert( geBitmap_IsValid(Bmp) ); + + // this is that CreateLockFromMip uses to make its new data + + if ( Bmp->LockOwner ) + Bmp = Bmp->LockOwner; +// if ( Bmp->LockCount > 0 ) +// return GE_FALSE; + if ( Bmp->DataOwner ) + return GE_FALSE; + + // {} for compressed data, just don't make mips and say we did! + if ( gePixelFormat_BytesPerPel(Bmp->Info.Format) < 1 ) + return GE_TRUE; + + if ( low < 0 || high >= MAXMIPLEVELS || low > high ) + return GE_FALSE; + + for( mip = low; mip <= high; mip++) + { + if ( ! Bmp->Data[mip] ) + { + if ( ! geBitmap_AllocSystemMip(Bmp,mip) ) + return GE_FALSE; + + if ( mip != 0 ) + { + if ( ! geBitmap_UpdateMips_System(Bmp,mip-1,mip) ) + return GE_FALSE; + } + } + } + + Bmp->Info.MinimumMip = min(Bmp->Info.MinimumMip,low); + Bmp->Info.MaximumMip = max(Bmp->Info.MaximumMip,high); + +return GE_TRUE; +} + +/*}{ ******* Miscellany ***********/ + +GENESISAPI uint32 GENESISCC geBitmap_MipBytes(const geBitmap *Bmp,int mip) +{ +uint32 bytes; + if ( ! Bmp ) + return 0; + bytes = gePixelFormat_BytesPerPel(Bmp->Info.Format) * + SHIFT_R_ROUNDUP(Bmp->Info.Stride,mip) * + SHIFT_R_ROUNDUP(Bmp->Info.Height,mip); +return bytes; +} + +GENESISAPI geBoolean GENESISCC geBitmap_GetInfo(const geBitmap *Bmp, geBitmap_Info *Info, geBitmap_Info *SecondaryInfo) +{ + assert( geBitmap_IsValid(Bmp) ); + + assert(Info); + + if ( Bmp->DriverHandle ) + { + *Info = Bmp->DriverInfo; + } + else + { + *Info = Bmp->Info; + } + + if ( SecondaryInfo ) + *SecondaryInfo = Bmp->Info; + + return GE_TRUE; +} + +geBoolean geBitmap_MakeDriverLockInfo(geBitmap *Bmp,int mip,geBitmap_Info *Into) +{ +geRDriver_THandleInfo TInfo; + + // MakeDriverLockInfo also doesn't full out the full info, so it must be a valid info first! + // Bmp also gets some stuff written into him. + + assert(Bmp && Into); // not necessarily valid + + if ( ! Bmp->DriverHandle || ! Bmp->Driver || mip < Bmp->DriverInfo.MinimumMip || mip > Bmp->DriverInfo.MaximumMip ) + return GE_FALSE; + + if ( ! Bmp->Driver->THandle_GetInfo(Bmp->DriverHandle,mip,&TInfo) ) + { + geErrorLog_AddString(-1,"MakeDriverLockInfo : THandle_GetInfo", NULL); + return GE_FALSE; + } + + Bmp->DriverMipLock = mip; + Bmp->DriverFlags = TInfo.PixelFormat.Flags; + + Into->Width = TInfo.Width; + Into->Height = TInfo.Height; + Into->Stride = TInfo.Stride; + Into->Format = TInfo.PixelFormat.PixelFormat; + Into->ColorKey = TInfo.ColorKey; + + if ( TInfo.Flags & RDRIVER_THANDLE_HAS_COLORKEY ) + Into->HasColorKey = GE_TRUE; + else + Into->HasColorKey = GE_FALSE; + + Into->MinimumMip = Into->MaximumMip = mip; + + if ( gePixelFormat_HasPalette(Into->Format) && Into->Palette && Into->Palette->HasColorKey ) + { + Into->HasColorKey = GE_TRUE; + Into->ColorKey = Into->Palette->ColorKeyIndex; + } + +return GE_TRUE; +} + +GENESISAPI int GENESISCC geBitmap_Width(const geBitmap *Bmp) +{ + assert(Bmp); +return(Bmp->Info.Width); +} + +GENESISAPI int GENESISCC geBitmap_Height(const geBitmap *Bmp) +{ + assert(Bmp); +return(Bmp->Info.Height); +} + +GENESISAPI geBoolean GENESISCC geBitmap_Blit(const geBitmap *Src, int SrcPositionX, int SrcPositionY, + geBitmap *Dst, int DstPositionX, int DstPositionY, + int SizeX, int SizeY ) +{ + assert( geBitmap_IsValid(Src) ); + assert( geBitmap_IsValid(Dst) ); + return geBitmap_BlitMipRect(Src,0,SrcPositionX,SrcPositionY, + Dst,0,DstPositionX,DstPositionY, + SizeX,SizeY); +} + +GENESISAPI geBoolean GENESISCC geBitmap_BlitBitmap(const geBitmap * Src, geBitmap * Dst ) +{ + assert( geBitmap_IsValid(Src) ); + assert( geBitmap_IsValid(Dst) ); + assert( Src != Dst ); + return geBitmap_BlitMipRect(Src,0,0,0,Dst,0,0,0,-1,-1); +} + +GENESISAPI geBoolean GENESISCC geBitmap_BlitBestMip(const geBitmap * Src, geBitmap * Dst ) +{ +int Width,Mip; + assert( geBitmap_IsValid(Src) ); + assert( geBitmap_IsValid(Dst) ); + assert( Src != Dst ); + for(Mip=0; (Width = SHIFT_R_ROUNDUP(Src->Info.Width,Mip)) > Dst->Info.Width ; Mip++) ; + return geBitmap_BlitMipRect(Src,Mip,0,0,Dst,0,0,0,-1,-1); +} + +GENESISAPI geBoolean GENESISCC geBitmap_BlitMip(const geBitmap * Src, int SrcMip, geBitmap * Dst, int DstMip ) +{ + assert( geBitmap_IsValid(Src) ); + assert( geBitmap_IsValid(Dst) ); + return geBitmap_BlitMipRect(Src,SrcMip,0,0,Dst,DstMip,0,0,-1,-1); +} + +geBoolean geBitmap_BlitMipRect(const geBitmap * Src, int SrcMip, int SrcX,int SrcY, + geBitmap * Dst, int DstMip, int DstX,int DstY, + int SizeX,int SizeY) +{ +geBitmap * SrcLock=NULL,* DstLock=NULL; +geBoolean SrcUnLock,DstUnLock; +geBitmap_Info *SrcLockInfo,*DstLockInfo; +uint8 *SrcBits,*DstBits; + + assert(Src && Dst); + assert( Src != Dst ); + // <> if Src == Dst we could still do this, but we assert SrcMip != DstMip & be smart + + SrcUnLock = DstUnLock = GE_FALSE; + + if ( Src->LockOwner ) + { + assert( Src->LockOwner->LockCount ); + if ( SrcMip != 0 ) + { + geErrorLog_AddString(-1,"BlitMipRect : Src is a lock and mip != 0", NULL); + goto fail; + } + + SrcLock = (geBitmap *)Src; + } + else + { + if ( ! geBitmap_LockForReadNative((geBitmap *)Src,&SrcLock,SrcMip,SrcMip) ) + { + geErrorLog_AddString(-1,"BlitMipRect : LockForReadNative", NULL); + goto fail; + } + SrcUnLock = GE_TRUE; + } + + if ( Dst->LockOwner ) + { + if ( DstMip != 0 ) + goto fail; +// if ( Dst->LockOwner->LockCount >= 0 ) +// goto fail; +// {} can't check this, cuz we use _BlitMip to create locks for read + DstLock = Dst; + } + else + { + if ( ! geBitmap_LockForWrite(Dst,&DstLock,DstMip,DstMip) ) + { + geErrorLog_AddString(-1,"BlitMipRect : LockForWrite", NULL); + goto fail; + } + DstUnLock = GE_TRUE; + } + + Src = Dst = NULL; + + if ( SrcLock->DriverHandle ) + SrcLockInfo = &(SrcLock->DriverInfo); + else + SrcLockInfo = &(SrcLock->Info); + + if ( DstLock->DriverHandle ) + DstLockInfo = &(DstLock->DriverInfo); + else + DstLockInfo = &(DstLock->Info); + + if ( ! (SrcBits = geBitmap_GetBits(SrcLock)) || + ! (DstBits = geBitmap_GetBits(DstLock)) ) + { + geErrorLog_AddString(-1,"BlitMipRect : GetBits", NULL); + goto fail; + } + + if ( SizeX < 0 ) + SizeX = min(SrcLockInfo->Width,DstLockInfo->Width); + if ( SizeY < 0 ) + SizeY = min(SrcLockInfo->Height,DstLockInfo->Height); + + if (( (SrcX + SizeX) > SrcLockInfo->Width ) || + ( (SrcY + SizeY) > SrcLockInfo->Height) || + ( (DstX + SizeX) > DstLockInfo->Width ) || + ( (DstY + SizeY) > DstLockInfo->Height)) + { + geErrorLog_AddString(-1,"BlitMipRect : dimensions bad", NULL); + goto fail; + } + + SrcBits += gePixelFormat_BytesPerPel(SrcLockInfo->Format) * ( SrcY * SrcLockInfo->Stride + SrcX ); + DstBits += gePixelFormat_BytesPerPel(DstLockInfo->Format) * ( DstY * DstLockInfo->Stride + DstX ); + + // _BlitMipRect : made palette + if ( ! geBitmap_BlitData( SrcLockInfo,SrcBits,SrcLock, + DstLockInfo,DstBits,DstLock, + SizeX,SizeY) ) + { + goto fail; + } + + if ( SrcUnLock ) geBitmap_UnLock(SrcLock); + if ( DstUnLock ) geBitmap_UnLock(DstLock); + + return GE_TRUE; + + fail: + + if ( SrcUnLock ) geBitmap_UnLock(SrcLock); + if ( DstUnLock ) geBitmap_UnLock(DstLock); + + return GE_FALSE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_SetFormatMin(geBitmap *Bmp,gePixelFormat NewFormat) +{ +geBitmap_Palette * Pal; + + assert(geBitmap_IsValid(Bmp)); + + Pal = geBitmap_GetPalette(Bmp); + if ( Bmp->Info.HasColorKey ) + { + uint32 CK=0; + if ( gePixelFormat_IsRaw(NewFormat) ) + { + if ( gePixelFormat_IsRaw(Bmp->Info.Format) ) + { + CK = gePixelFormat_ConvertPixel(Bmp->Info.Format,Bmp->Info.ColorKey,NewFormat); + } + else if ( gePixelFormat_HasPalette(Bmp->Info.Format) ) + { + assert(Pal); + geBitmap_Palette_GetEntry(Pal,Bmp->Info.ColorKey,&CK); + CK = gePixelFormat_ConvertPixel(Pal->Format,CK,NewFormat); + if ( ! CK ) CK = 1; + } + } + else + { + if ( gePixelFormat_HasPalette(NewFormat) ) + { + CK = 255; + } + else + { + CK = 1; + } + } + + return geBitmap_SetFormat(Bmp,NewFormat,GE_TRUE,CK,Pal); + } + else + { + return geBitmap_SetFormat(Bmp,NewFormat,GE_FALSE,0,Pal); + } +} + +GENESISAPI geBoolean GENESISCC geBitmap_SetFormat(geBitmap *Bmp, + gePixelFormat NewFormat, + geBoolean HasColorKey, uint32 ColorKey, + const geBitmap_Palette *Palette ) +{ + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner || Bmp->LockCount || Bmp->DataOwner ) + { + geErrorLog_AddString(-1,"SetFormat : not an original bitmap", NULL); + return GE_FALSE; + } + // can't do _SetFormat on a locked mip, cuz it would change the size of all the locked mips = no good + + // always affects the non-Driver copy + + if ( NewFormat == GE_PIXELFORMAT_WAVELET ) + { + geErrorLog_AddString(-1,"Genesis3D 1.0 does not support Wavelet Images",NULL); + return GE_FALSE; + } + + if ( NewFormat == Bmp->Info.Format ) + { + // but not wavelet + + if ( gePixelFormat_HasPalette(NewFormat) && Palette ) + { + if ( ! geBitmap_SetPalette(Bmp,(geBitmap_Palette *)Palette) ) + return GE_FALSE; + } + + if ( (! HasColorKey ) + || ( HasColorKey && Bmp->Info.HasColorKey && ColorKey == Bmp->Info.ColorKey ) ) + { + Bmp->Info.HasColorKey = HasColorKey; + Bmp->Info.ColorKey = ColorKey; + return GE_TRUE; + } + else + { + geBitmap_Info OldInfo; + + OldInfo = Bmp->Info; + + assert(HasColorKey); + + // just change the colorkey + + Bmp->Info.HasColorKey = HasColorKey; + Bmp->Info.ColorKey = ColorKey; + + if ( Bmp->Data[Bmp->Info.MinimumMip] == NULL ) + return GE_TRUE; + + assert(Bmp->Info.MinimumMip == 0); //{} this is just out of laziness + + // _SetFormat : same format + if ( ! geBitmap_BlitData( &OldInfo, Bmp->Data[Bmp->Info.MinimumMip], NULL, + &(Bmp->Info), Bmp->Data[Bmp->Info.MinimumMip], NULL, + Bmp->Info.Width, Bmp->Info.Height) ) + { + return GE_FALSE; + } + + return GE_TRUE; + } + } + else + { + geBitmap_Info OldInfo; + int OldBPP,NewBPP; + int OldMaxMips; + DRV_Driver * Driver; + + if ( gePixelFormat_HasPalette(NewFormat) ) + { + if ( Palette ) + { + if ( ! geBitmap_SetPalette(Bmp,(geBitmap_Palette *)Palette) ) + return GE_FALSE; + } + else + { + if ( ! geBitmap_GetPalette(Bmp) && ! gePixelFormat_HasPalette(Bmp->Info.Format) ) + { + geBitmap_Palette *NewPal; + NewPal = geBitmap_Palette_CreateFromBitmap(Bmp,GE_FALSE); + if ( ! NewPal ) + { + geErrorLog_AddString(-1,"_SetFormat : createPaletteFromBitmap failed", NULL); + return GE_FALSE; + } + if ( ! geBitmap_SetPalette(Bmp,NewPal) ) + return GE_FALSE; + geBitmap_Palette_Destroy(&NewPal); + } + } + } + + Driver = Bmp->Driver; + if ( Driver ) + if ( ! geBitmap_DetachDriver(Bmp,GE_TRUE) ) + return GE_FALSE; + + OldBPP = gePixelFormat_BytesPerPel(Bmp->Info.Format); + NewBPP = gePixelFormat_BytesPerPel(NewFormat); + + OldInfo = Bmp->Info; + Bmp->Info.Format = NewFormat; + Bmp->Info.HasColorKey = HasColorKey; + Bmp->Info.ColorKey = ColorKey; + + // {} this is not very polite; we do restore them later, though... + OldMaxMips = max(Bmp->Info.MaximumMip,Bmp->DriverInfo.MaximumMip); + geBitmap_ClearMips(Bmp); + + if ( Bmp->Data[Bmp->Info.MinimumMip] == NULL && + Bmp->DriverHandle == NULL ) + return GE_TRUE; + + if ( OldBPP == NewBPP ) + { + geBitmap * Lock; + void * Bits; + // can work in place + if ( ! geBitmap_LockForWrite(Bmp,&Lock,0,0) ) + return GE_FALSE; + + if ( ! (Bits = geBitmap_GetBits(Lock)) ) + { + geBitmap_UnLock(Lock); + return GE_FALSE; + } + + // _SetFormat : new format + if ( ! geBitmap_BlitData( &OldInfo, Bits, Lock, + &(Lock->Info), Bits, Lock, + Lock->Info.Width, Lock->Info.Height) ) + { + geBitmap_UnLock(Lock); + return GE_FALSE; + } + + geBitmap_UnLock(Lock); + } + else // NewFormat is raw && != OldFormat + { + geBitmap OldBmp; + geBitmap *Lock,*SrcLock; + void *Bits,*OldBits; + + OldBmp = *Bmp; + OldBmp.Info = OldInfo; + + // clear out the Bmp for putting the new format in + Bmp->Info.Stride = Bmp->Info.Width; + Bmp->Data[0] = NULL; + Bmp->Alpha = NULL; + + if ( ! geBitmap_AllocSystemMip(Bmp,0) ) + return GE_FALSE; + + if ( ! geBitmap_LockForReadNative(&OldBmp,&SrcLock,0,0) ) + return GE_FALSE; + + if ( ! geBitmap_LockForWrite(Bmp,&Lock,0,0) ) + return GE_FALSE; + + if ( ! (Bits = geBitmap_GetBits(Lock)) ) + { + geBitmap_UnLock(Lock); + return GE_FALSE; + } + if ( ! (OldBits = geBitmap_GetBits(SrcLock)) ) + { + geBitmap_UnLock(Lock); + return GE_FALSE; + } + + // _SetFormat : new format + if ( ! geBitmap_BlitData( &OldInfo, OldBits, SrcLock, + &(Lock->Info), Bits, Lock, + Lock->Info.Width, Lock->Info.Height) ) + { + // try to undo as well as possible + return GE_FALSE; + } + + geBitmap_UnLock(Lock); + geBitmap_UnLock(SrcLock); + + if ( OldBmp.Data[0] ) + { + geRam_Free(OldBmp.Data[0]); + OldBmp.Data[0] = NULL; + } + + if ( gePixelFormat_HasGoodAlpha(NewFormat) ) + { + geBitmap_Destroy(&(OldBmp.Alpha)); + } + else + { + Bmp->Alpha = OldBmp.Alpha; + } + } + + { + int mip; + mip = Bmp->Info.MinimumMip; + while( mip < OldMaxMips ) + { + geBitmap_UpdateMips(Bmp,mip,mip+1); + mip++; + } + } + + if ( Driver ) + { + if ( ! geBitmap_AttachToDriver(Bmp,Driver,0) ) + return GE_FALSE; + } + } + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_SetColorKey(geBitmap *Bmp, geBoolean HasColorKey, uint32 ColorKey , geBoolean Smart) +{ + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner || Bmp->LockCount || Bmp->DataOwner ) + { + geErrorLog_AddString(-1,"SetColorKey : not an original bitmap", NULL); + return GE_FALSE; + } + + // see comments in SetFormat + + if ( Bmp->DriverHandle ) + geBitmap_Update_DriverToSystem(Bmp); + + if ( HasColorKey && + ((uint32)ColorKey>>1) >= ((uint32)1<<(gePixelFormat_BytesPerPel(Bmp->Info.Format)*8 - 1)) ) + { + geErrorLog_AddString(-1,"geBitmap_SetColorKey : invalid ColorKey pixel!", NULL); + return GE_FALSE; + } + if ( HasColorKey && gePixelFormat_HasAlpha(Bmp->Info.Format) ) + { + geErrorLog_AddString(-1,"geBitmap_SetColorKey : non-fatal : Alpha and ColorKey together won't work right", NULL); + } + + if ( HasColorKey && Smart && Bmp->Data[0] ) + { + Bmp->Info.HasColorKey = GE_TRUE; + Bmp->Info.ColorKey = ColorKey; + if ( ! geBitmap_UsesColorKey(Bmp) ) + { + Bmp->Info.HasColorKey = GE_FALSE; + Bmp->Info.ColorKey = 1; + } + } + else + { + Bmp->Info.HasColorKey = HasColorKey; + Bmp->Info.ColorKey = ColorKey; + } + + if ( Bmp->DriverHandle ) + geBitmap_Update_SystemToDriver(Bmp); + +return GE_TRUE; +} + +geBoolean geBitmap_UsesColorKey(const geBitmap * Bmp) +{ +void * Bits; +const gePixelFormat_Operations * ops; +int x,y,w,h,s; +uint32 pel,ColorKey; + + if ( ! Bmp->Info.HasColorKey ) + return GE_FALSE; + + if ( ! Bmp->Data[0] ) + { + geErrorLog_AddString(-1,"UsesColorKey : no data!", NULL); + return GE_TRUE; + } + + assert( Bmp->Info.MinimumMip == 0 ); + + Bits = Bmp->Data[0]; + ops = gePixelFormat_GetOperations(Bmp->Info.Format); + assert(ops); + + w = Bmp->Info.Width; + h = Bmp->Info.Height; + s = Bmp->Info.Stride; + + ColorKey = Bmp->Info.ColorKey; + + switch(ops->BytesPerPel) + { + case 0: + geErrorLog_AddString(-1,"UsesColorKey : invalid format", NULL); + return GE_TRUE; +//Start Dec2001DCS - Added new case 3 below +// case 3: +// #pragma message("Bitmap : UsesColorKey : no 24bit Smart ColorKey") +// geErrorLog_AddString(-1,"UsesColorKey : no 24bit Smart ColorKey", NULL); +// return GE_TRUE; +//End Dec2001DCS + case 1: + { + uint8 * ptr; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + pel = *ptr++; + if ( pel == ColorKey ) + { + return GE_TRUE; + } + } + ptr += (s-w); + } + break; + } + case 2: + { + uint16 * ptr; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + pel = *ptr++; + if ( pel == ColorKey ) + { + return GE_TRUE; + } + } + ptr += (s-w); + } + break; + } +//Start Dec2001DCS - Added new case 3 + case 3: + { + uint8 * ptr; + uint8 ckR, ckG, ckB; + + ckB = (uint8) (ColorKey & 0x000000ff); + ckG = (uint8) ((ColorKey >> 8) & 0x000000ff); + ckR = (uint8) ((ColorKey >> 16) & 0x000000ff); + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + if ((*ptr == ckR) && (*(ptr+1) == ckG) && (*(ptr+2) == ckB)) + { + return GE_TRUE; + } + ptr += 3; + } + ptr += ((s-w)*3); + } + break; + } +//End Dec2001DCS + case 4: + { + uint32 * ptr; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + pel = *ptr++; + if ( pel == ColorKey ) + { + return GE_TRUE; + } + } + ptr += (s-w); + } + break; + } + } +return GE_FALSE; +} + + +GENESISAPI geBoolean GENESISCC geBitmap_SetPalette(geBitmap *Bmp, const geBitmap_Palette *Palette) +{ + assert(Bmp); // not nec. valid + assert( geBitmap_Palette_IsValid(Palette) ); + + if ( Bmp->LockOwner ) + Bmp = Bmp->LockOwner; + +/* //{} breaks PalCreate + if ( Bmp->LockCount > 0 || Bmp->DataOwner ) + { + geErrorLog_AddString(-1,"SetPalette : not an original bitmap", NULL); + return GE_FALSE; + } +*/ + + // warning : Bitmap_Blitdata calls us when it auto-creates a palette! + + // note that when we _SetPalette on a bitmap, all its write-locked children + // also get new palettes + + if ( Bmp->Info.Palette != Palette ) + { + // save the palette even if we're not palettized, for later use + if ( Palette->Driver ) + { + if ( ! geBitmap_AllocPalette(Bmp,Palette->Format,NULL) ) + return GE_FALSE; + + if ( ! geBitmap_Palette_Copy(Palette,Bmp->Info.Palette) ) + return GE_FALSE; + } + else + { + if ( Bmp->Info.Palette ) + geBitmap_Palette_Destroy(&(Bmp->Info.Palette)); + + Bmp->Info.Palette = (geBitmap_Palette *)Palette; + geBitmap_Palette_CreateRef(Bmp->Info.Palette); + } + } + + if ( gePixelFormat_HasPalette(Bmp->DriverInfo.Format) && + Bmp->DriverInfo.Palette != Palette ) + { + if ( Palette->Driver == Bmp->Driver && + ( ! Palette->HasColorKey || ! Bmp->DriverInfo.ColorKey || + (uint32)Palette->ColorKeyIndex == Bmp->DriverInfo.ColorKey ) ) + { + if ( Bmp->DriverInfo.Palette ) + geBitmap_Palette_Destroy(&(Bmp->DriverInfo.Palette)); + Bmp->DriverInfo.Palette = (geBitmap_Palette *)Palette; + geBitmap_Palette_CreateRef(Bmp->DriverInfo.Palette); + } + else if ( Bmp->DriverInfo.Palette ) + { + if ( ! geBitmap_Palette_Copy(Palette,Bmp->DriverInfo.Palette) ) + return GE_FALSE; + } + else + { + if ( ! geBitmap_AllocPalette(Bmp,0,Bmp->Driver) ) + return GE_FALSE; + + if ( ! geBitmap_Palette_Copy(Palette,Bmp->DriverInfo.Palette) ) + return GE_FALSE; + } + } + + if ( Bmp->DriverHandle ) + { + // if one has pal and other doesn't this is real change! + if ( gePixelFormat_HasPalette(Bmp->Info.Format) && + ! gePixelFormat_HasPalette(Bmp->DriverInfo.Format) ) + { + // this over-rides any driver changes! + Bmp->DriverDataChanged = GE_FALSE; + if ( ! geBitmap_Update_SystemToDriver(Bmp) ) + return GE_FALSE; + } + else if ( ! gePixelFormat_HasPalette(Bmp->Info.Format) && + gePixelFormat_HasPalette(Bmp->DriverInfo.Format) ) + { + Bmp->DriverDataChanged = GE_TRUE; + } + } + + assert( geBitmap_IsValid(Bmp) ); + +return GE_TRUE; +} + +GENESISAPI geBitmap_Palette * GENESISCC geBitmap_GetPalette(const geBitmap *Bmp) +{ + if ( ! Bmp ) return NULL; + + if ( Bmp->Driver && Bmp->DriverInfo.Palette ) + { + assert(Bmp->Info.Palette); + return Bmp->DriverInfo.Palette; + } + + return Bmp->Info.Palette; +} + + +GENESISAPI geBitmap * GENESISCC geBitmap_GetAlpha(const geBitmap *Bmp) +{ + if ( ! Bmp ) return NULL; + return Bmp->Alpha; +} + +GENESISAPI geBoolean GENESISCC geBitmap_SetAlpha(geBitmap *Bmp, const geBitmap *AlphaBmp) +{ + assert( geBitmap_IsValid(Bmp) ); + + if ( Bmp->LockOwner ) + Bmp = Bmp->LockOwner; + if ( Bmp->LockCount > 0 || Bmp->DataOwner ) + { + geErrorLog_AddString(-1,"SetAlpha : not an original bitmap", NULL); + return GE_FALSE; + } + + if ( AlphaBmp == Bmp->Alpha ) + return GE_TRUE; + + if ( Bmp->DriverHandle ) + { + geBitmap_Update_DriverToSystem(Bmp); + } + + if ( Bmp->Alpha ) + { + geBitmap_Destroy(&(Bmp->Alpha)); + } + + Bmp->Alpha = (geBitmap *)AlphaBmp; + if ( AlphaBmp ) + { + assert( geBitmap_IsValid(AlphaBmp) ); + geBitmap_CreateRef(Bmp->Alpha); + } + + if ( Bmp->DriverHandle ) + { + // upload the new alpha to the driver bitmap + geBitmap_Update_SystemToDriver(Bmp); + } + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_SetPreferredFormat(geBitmap *Bmp,gePixelFormat Format) +{ + + if ( Bmp->LockOwner ) + Bmp = Bmp->LockOwner; + if ( Bmp->LockCount > 0 || Bmp->DataOwner ) + { + geErrorLog_AddString(-1,"SetPrefferedFormat : not an original bitmap", NULL); + return GE_FALSE; + } + + if ( Bmp->PreferredFormat != Format ) + { + DRV_Driver * Driver; + Bmp->PreferredFormat = Format; + Driver = Bmp->Driver; + if ( Driver ) + { + if ( ! geBitmap_DetachDriver(Bmp,GE_TRUE) ) + return GE_FALSE; + if ( ! geBitmap_AttachToDriver(Bmp,Driver,0) ) + return GE_FALSE; + } + } + +return GE_TRUE; +} + +GENESISAPI gePixelFormat GENESISCC geBitmap_GetPreferredFormat(const geBitmap *Bmp) +{ + if ( ! Bmp ) return 0; +return Bmp->PreferredFormat; +} + +/*}{ ************** FILE I/O ************************/ + +GENESISAPI geBitmap * GENESISCC geBitmap_CreateFromFileName(const geVFile *BaseFS,const char *Name) +{ + geVFile * File; + geBitmap * Bitmap; + + + if ( BaseFS ) + { + File = geVFile_Open((geVFile *)BaseFS, Name, GE_VFILE_OPEN_READONLY); + } + else + { + File = geVFile_OpenNewSystem(NULL,GE_VFILE_TYPE_DOS,Name,NULL,GE_VFILE_OPEN_READONLY); + } + if ( ! File ) + return NULL; + + Bitmap = geBitmap_CreateFromFile(File); + geVFile_Close(File); + + return Bitmap; +} + +GENESISAPI geBoolean GENESISCC geBitmap_WriteToFileName(const geBitmap * Bmp,const geVFile *BaseFS,const char *Name) +{ +geVFile * File; +geBoolean Ret; + + if ( BaseFS ) + { + File = geVFile_Open((geVFile *)BaseFS, Name, GE_VFILE_OPEN_CREATE); + } + else + { + File = geVFile_OpenNewSystem(NULL,GE_VFILE_TYPE_DOS,Name,NULL,GE_VFILE_OPEN_CREATE); + } + + if ( ! File ) + return GE_FALSE; + + Ret = geBitmap_WriteToFile(Bmp,File); + + geVFile_Close(File); + +return Ret; +} + +// GeBm Tag in 4 bytes {} +typedef uint32 geBmTag_t; +#define GEBM_TAG ((geBmTag_t)0x6D426547) // "GeBm" + +// version in a byte +#define GEBM_VERSION (((uint32)GEBM_VERSION_MAJOR<<4) + (uint32)GEBM_VERSION_MINOR) +#define VERSION_MAJOR(Version) (((Version)>>4)&0x0F) +#define VERSION_MINOR(Version) ((Version)&0x0F) + +#define MIP_MASK (0xF) +#define MIP_FLAG_COMPRESSED (1<<4) +#define MIP_FLAG_PAETH_FILTERED (1<<5) + +static geBoolean geBitmap_ReadFromBMP(geBitmap * Bmp,geVFile * F); +// change QuestOfDreams +static geBoolean geBitmap_IsTGA(geVFile * F); +static geBoolean geBitmap_ReadFromTGA(geBitmap * Bmp, geVFile * File); +// end change QuestOfDreams +GENESISAPI geBitmap * GENESISCC geBitmap_CreateFromFile(geVFile *F) +{ + geBitmap * Bmp; + geBmTag_t Tag; + + assert(F); + + if ( ! geVFile_Read(F, &Tag, sizeof(Tag)) ) + return NULL; + + Bmp = geBitmap_Create_Base(); + if ( ! Bmp ) + return NULL; + + if ( Tag == GEBM_TAG ) + { + uint8 flags; + uint8 Version; + int mip; + + // see WriteToFile for comments on the file format + + if ( ! geVFile_Read(F, &Version, sizeof(Version)) ) + goto fail; + + if ( VERSION_MAJOR(Version) != VERSION_MAJOR(GEBM_VERSION) ) + { + geErrorLog_AddString(-1,"CreateFromFile : incompatible GeBm version", NULL); + goto fail; + } + + if ( ! geBitmap_ReadInfo(Bmp,F) ) + goto fail; + + if ( Bmp->Info.Palette ) + { + Bmp->Info.Palette = NULL; + if ( ! ( Bmp->Info.Palette = geBitmap_Palette_CreateFromFile(F)) ) + goto fail; + } + + if ( Bmp->Info.Format == GE_PIXELFORMAT_WAVELET ) + { + geErrorLog_AddString(-1,"Genesis3D 1.0 does not support Wavelet Images",NULL); + } + else + { + for(;;) + { + if ( ! geVFile_Read(F, &flags, sizeof(flags)) ) + goto fail; + + mip = flags & MIP_MASK; + + if ( mip > Bmp->Info.MaximumMip ) + break; + + assert(mip >= Bmp->Info.MinimumMip ); + assert( Bmp->Info.Stride == Bmp->Info.Width ); + + if ( ! geBitmap_AllocSystemMip(Bmp,mip) ) + goto fail; + + if ( flags & MIP_FLAG_COMPRESSED ) + { + #ifdef DO_LZ + geVFile * LzF; + + LzF = geVFile_OpenNewSystem(F,GE_VFILE_TYPE_LZ,NULL,NULL,GE_VFILE_OPEN_READONLY); + if ( ! LzF ) + { + geErrorLog_AddString(-1,"Bitmap_CreateFromFile : LZ File Open failed",NULL); + return GE_FALSE; + } + + if ( ! geVFile_Read(LzF, Bmp->Data[mip], geBitmap_MipBytes(Bmp,mip) ) ) + { + geVFile_Close(LzF); + geErrorLog_AddString(-1,"Bitmap_CreateFromFile : LZ File Read failed",NULL); + return GE_FALSE; + } + + if ( ! geVFile_Close(LzF) ) + { + geErrorLog_AddString(-1,"Bitmap_CreateFromFile : LZ File Close failed",NULL); + return GE_FALSE; + } + #endif + } + else + { + if ( ! geVFile_Read(F, Bmp->Data[mip], geBitmap_MipBytes(Bmp,mip) ) ) + goto fail; + } + + if ( flags & MIP_FLAG_PAETH_FILTERED ) + { + geErrorLog_AddString(-1,"Bitmap_CreateFromFile : Paeth Filter not supported in this version!",NULL); + return GE_FALSE; + } + + Bmp->Modified[mip] = GE_TRUE; + } + } + + if( Bmp->Alpha ) + { + if ( ! (Bmp->Alpha = geBitmap_CreateFromFile(F)) ) + goto fail; + } + } // end geBitmap reader + else + { + if ( ! geVFile_Seek(F, - (int)sizeof(Tag), GE_VFILE_SEEKCUR) ) + goto fail; + + if ( (Tag&0xFFFF) == 0x4D42 ) // 'BM' + { + + if ( ! geBitmap_ReadFromBMP(Bmp,F) ) + goto fail; + } + else + { + +// change QuestOfDreams + if (geBitmap_IsTGA(F)) + { + if( ! geBitmap_ReadFromTGA(Bmp, F)) + goto fail; + } + else + // geErrorLog_AddString(-1,"CreateFromFile : unknown format", NULL); + goto fail; +// end change QuestOfDreams + } + } + + return Bmp; + +fail: + assert(Bmp); + + geBitmap_Destroy(&Bmp); + return NULL; +} + +GENESISAPI geBoolean GENESISCC geBitmap_WriteToFile(const geBitmap *Bmp, geVFile *F) +{ +geBmTag_t geBM_Tag; +uint8 geBM_Version; +uint8 flags; +int mip; + + assert(Bmp && F); + assert( geBitmap_IsValid(Bmp) ); + + geBM_Tag = GEBM_TAG; + geBM_Version = GEBM_VERSION; + + if ( Bmp->DriverHandle ) + { + if ( ! geBitmap_Update_DriverToSystem((geBitmap *)Bmp) ) + { + geErrorLog_AddString(-1,"WriteToFile : Update_DriverToSystem", NULL); + return GE_FALSE; + } + } + + if ( ! geVFile_Write(F, &geBM_Tag, sizeof(geBM_Tag)) ) + return GE_FALSE; + + if ( ! geVFile_Write(F, &geBM_Version, sizeof(geBM_Version)) ) + return GE_FALSE; + + if ( ! geBitmap_WriteInfo(Bmp,F) ) + return GE_FALSE; + + #ifdef COUNT_HEADER_SIZES + Header_Sizes += 15; + #endif + + // the pointer Bmp->Info.Palette serves as boolean : HasPalette + if ( Bmp->Info.Palette ) + { + if ( ! geBitmap_Palette_WriteToFile(Bmp->Info.Palette,F) ) + return GE_FALSE; + } + + if ( Bmp->Info.Format == GE_PIXELFORMAT_WAVELET ) + { + geErrorLog_AddString(-1,"Genesis3D 1.0 does not support Wavelet Images",NULL); + } + else + { + for( mip = Bmp->Info.MinimumMip; mip <= Bmp->Info.MaximumMip; mip++ ) + { + + // write out all the interesting mips : + // the first one, and then mips which are not just + // sub-samples of the first (eg. that have been user-set) + + if ( (mip == Bmp->Info.MinimumMip || Bmp->Modified[mip]) && Bmp->Data[mip] ) + { + uint8 * MipData; + geBoolean MipDataAlloced; + uint32 MipDataLen; + + MipDataLen = SHIFT_R_ROUNDUP(Bmp->Info.Width,mip) * SHIFT_R_ROUNDUP(Bmp->Info.Height,mip) * + gePixelFormat_BytesPerPel(Bmp->Info.Format); + + if ( Bmp->Info.Stride == Bmp->Info.Width ) + { + MipData = Bmp->Data[mip]; + MipDataAlloced = GE_FALSE; + } + else + { + int w,h,s,y; + uint8 * fptr,*tptr; + + if ( ! (MipData = geRam_Allocate(MipDataLen) ) ) + { + geErrorLog_AddString(-1,"Bitmap_WriteToFile : Ram_Alloc failed!",NULL); + return GE_FALSE; + } + + MipDataAlloced = GE_TRUE; + + s = SHIFT_R_ROUNDUP(Bmp->Info.Stride,mip)* gePixelFormat_BytesPerPel(Bmp->Info.Format); + w = SHIFT_R_ROUNDUP(Bmp->Info.Width,mip) * gePixelFormat_BytesPerPel(Bmp->Info.Format); + h = SHIFT_R_ROUNDUP(Bmp->Info.Height,mip); + + fptr = Bmp->Data[mip]; + tptr = MipData; + for(y=h;y--;) + { + memcpy(tptr,fptr,w); + fptr += s; + tptr += w; + } + } + + assert( mip <= MIP_MASK ); + flags = mip; + #ifdef DO_LZ + flags |= MIP_FLAG_COMPRESSED; + #endif + + if ( ! geVFile_Write(F, &flags, sizeof(flags)) ) + return GE_FALSE; + + #ifdef DO_LZ + { + geVFile * LzF; + LzF = geVFile_OpenNewSystem(F,GE_VFILE_TYPE_LZ,NULL,NULL,GE_VFILE_OPEN_CREATE); + if ( ! LzF ) + { + if ( MipDataAlloced ) + geRam_Free(MipData); + geErrorLog_AddString(-1,"Bitmap_WriteToFile : LZ File Open failed",NULL); + return GE_FALSE; + } + + if ( ! geVFile_Write(LzF, MipData, MipDataLen ) ) + return GE_FALSE; + + if ( ! geVFile_Close(LzF) ) + { + if ( MipDataAlloced ) + geRam_Free(MipData); + geErrorLog_AddString(-1,"Bitmap_WriteToFile : LZ File Close failed",NULL); + return GE_FALSE; + } + } + #else + if ( ! geVFile_Write(F, MipData, MipDataLen ) ) + return GE_FALSE; + #endif + + if ( MipDataAlloced ) + geRam_Free(MipData); + } + } + + // mip > MaximumMip signals End-Of-Mips + + flags = MIP_MASK; + if ( ! geVFile_Write(F, &flags, sizeof(flags)) ) + return GE_FALSE; + } + + // the pointer Bmp->Alpha serves as boolean : HasAlpha + + if( Bmp->Alpha ) + { + if ( ! geBitmap_WriteToFile(Bmp->Alpha,F) ) + return GE_FALSE; + } + +return GE_TRUE; +} + +/*}{********** Windows BMP Types *******/ + +#pragma pack(1) + +typedef struct TGAHEADER +{ + char IDLength; + char ColorMapType; + char ImageType; + uint16 CMFirstEntry; + uint16 CMLength; + char CMEntrySize; + uint16 Xorigin; + uint16 Yorigin; + uint16 Width; + uint16 Height; + char PixelDepth; + char ImageDescriptor; +} TGAHEADER; + +typedef struct +{ + uint32 biSize; + long biWidth; + long biHeight; + uint16 biPlanes; + uint16 biBitCount; + uint32 biCompression; + uint32 biSizeImage; + long biXPelsPerMeter; + long biYPelsPerMeter; + uint32 biClrUsed; + uint32 biClrImportant; +} BITMAPINFOHEADER; + +typedef struct +{ + uint16 bfType; + uint32 bfSize; + uint16 bfReserved1; + uint16 bfReserved2; + uint32 bfOffBits; +} BITMAPFILEHEADER; + +typedef struct +{ + uint8 B; + uint8 G; + uint8 R; + uint8 rgbReserved; +} RGBQUAD; +#pragma pack() + + + +static geBoolean geBitmap_ReadFromBMP(geBitmap * Bmp,geVFile * F) +{ +BITMAPFILEHEADER bmfh; +BITMAPINFOHEADER bmih; +int bPad,myRowWidth,bmpRowWidth,pelBytes; + + // Windows Bitmap + + if ( ! geVFile_Read(F, &bmfh, sizeof(bmfh)) ) + return GE_FALSE; + + assert(bmfh.bfType == 0x4D42); + + bPad = bmfh.bfOffBits; + + if ( ! geVFile_Read(F, &bmih, sizeof(bmih)) ) + return GE_FALSE; + + if ( bmih.biSize > sizeof(bmih) ) + { + geVFile_Seek(F, bmih.biSize - sizeof(bmih), GE_VFILE_SEEKCUR); + } + else if ( bmih.biSize < sizeof(bmih) ) + { + geErrorLog_AddString(-1,"CreateFromFile : bmih size bad", NULL); + return GE_FALSE; + } + + if ( bmih.biCompression ) + { + geErrorLog_AddString(-1,"CreateFromFile : only BI_RGB BMP compression supported", NULL); + return GE_FALSE; + } + + bPad -= sizeof(bmih) + sizeof(bmfh); + + switch (bmih.biBitCount) + { + case 8: /* colormapped image */ + if ( bmih.biClrUsed == 0 ) bmih.biClrUsed = 256; + + if ( ! (Bmp->Info.Palette = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_XRGB,bmih.biClrUsed)) ) + return GE_FALSE; + + if ( ! geVFile_Read(F, Bmp->Info.Palette->Data, bmih.biClrUsed * 4) ) + return GE_FALSE; + + bPad -= bmih.biClrUsed * 4; + + Bmp->Info.Format = GE_PIXELFORMAT_8BIT_PAL; + pelBytes = 1; + break; + case 16: + Bmp->Info.Format = GE_PIXELFORMAT_16BIT_555_RGB; + // tried 555,565_BGR & RGB, seems to have too much green + pelBytes = 2; + break; + case 24: + Bmp->Info.Format = GE_PIXELFORMAT_24BIT_BGR; + pelBytes = 3; + break; + case 32: + Bmp->Info.Format = GE_PIXELFORMAT_32BIT_XRGB; // surprisingly sane !? + pelBytes = 4; + break; + default: + return GE_FALSE; + } + + if ( bPad < 0 ) + { + geErrorLog_AddString(-1,"CreateFromFile : bPad bad", NULL); + return GE_FALSE; + } + + geVFile_Seek(F, bPad, GE_VFILE_SEEKCUR); + + Bmp->Info.Width = bmih.biWidth; + Bmp->Info.Height = abs(bmih.biHeight); + Bmp->Info.Stride = ((bmih.biWidth+3)&(~3)); + + Bmp->Info.HasColorKey = GE_FALSE; + + myRowWidth = Bmp->Info.Stride * pelBytes; + bmpRowWidth = (((bmih.biWidth * pelBytes) + 3)&(~3)); + + assert( bmpRowWidth <= myRowWidth ); + + if ( ! geBitmap_AllocSystemMip(Bmp,0) ) + return GE_FALSE; + + if ( bmih.biHeight > 0 ) + { + int y; + char * row; + row = Bmp->Data[0]; + row += (Bmp->Info.Height - 1) * myRowWidth; + for(y= Bmp->Info.Height;y--;) + { + if ( ! geVFile_Read(F, row, bmpRowWidth) ) + return GE_FALSE; + row -= myRowWidth; + } + } + else + { + int y; + char * row; + row = Bmp->Data[0]; + for(y= Bmp->Info.Height;y--;) + { + if ( ! geVFile_Read(F, row, bmpRowWidth) ) + return GE_FALSE; + row += myRowWidth; + } + } + +return GE_TRUE; +} // end BMP reader + + +/*******************************************************************************/ +static geBoolean geBitmap_IsTGA(geVFile * F) +{ + char targa[18]; + TGAHEADER tgah; + + if (!geVFile_Seek(F, - 18, GE_VFILE_SEEKEND)) + return GE_FALSE; + + if(!geVFile_Read(F, &targa, 18)) + return GE_FALSE; + geVFile_Seek(F, 0, GE_VFILE_SEEKSET); + + //if we find the TRUEVISION-XFILE. signature this should be a tga file + if(!strcmp(targa, "TRUEVISION-XFILE.")) + return GE_TRUE; + + // older versions don't have a signature so do further checks + if(!geVFile_Read(F, &tgah, 18)) + return GE_FALSE; + geVFile_Seek(F, 0, GE_VFILE_SEEKSET); + + if(tgah.ColorMapType != 0 && tgah.ColorMapType != 1) + return GE_FALSE; + else if(tgah.ImageType != 1 && tgah.ImageType != 2 && tgah.ImageType != 9 && tgah.ImageType != 10) + return GE_FALSE; + else if(tgah.PixelDepth != 8 && tgah.PixelDepth != 16 && tgah.PixelDepth != 24 && tgah.PixelDepth != 32) + return GE_FALSE; + else + return GE_TRUE; + + + return GE_FALSE; +} + +/*****************************************************************************/ + +static geBoolean geBitmap_ReadFromTGA(geBitmap * Bmp, geVFile * File) +{ + TGAHEADER tgah; + int alphabits; + int fliphoriz; + int flipvert; + int myRowWidth,bmpRowWidth,pelBytes; + long ImageOffset = 0; + geBitmap *AlphaBmp = NULL; + + + //read the header fields + if(!geVFile_Read(File, &tgah, 18)) + return GE_FALSE; + + Bmp->Info.Width = tgah.Width; + Bmp->Info.Height = tgah.Height; + Bmp->Info.Stride = ((tgah.Width+3)&(~3)); + Bmp->Info.HasColorKey = GE_FALSE; + + alphabits = tgah.ImageDescriptor & 0x0f; + fliphoriz = (tgah.ImageDescriptor & 0x10) ? 0 : 1; + flipvert = (tgah.ImageDescriptor & 0x20) ? 1 : 0; + //flipvert is ignored at the moment, because it appears rather rarely + //+ you can flip textures in editors + + switch (tgah.PixelDepth) + { + case 8 : + pelBytes=1; + Bmp->Info.Format = GE_PIXELFORMAT_8BIT_PAL; + ImageOffset = 0; + + // if ( tgah.CMLength == 0 ) tgah.CMLength = 256; + if(tgah.CMEntrySize == 16) + { + if ( ! (Bmp->Info.Palette = geBitmap_Palette_Create(GE_PIXELFORMAT_16BIT_555_RGB, tgah.CMLength)) ) + return GE_FALSE; + } + else if(tgah.CMEntrySize == 24) + { + if ( ! (Bmp->Info.Palette = geBitmap_Palette_Create(GE_PIXELFORMAT_24BIT_BGR, tgah.CMLength)) ) + return GE_FALSE; + } + else if(tgah.CMEntrySize == 32) + { + if ( ! (Bmp->Info.Palette = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_XRGB, tgah.CMLength)) ) + return GE_FALSE; + } + else + return GE_FALSE; + + // move to the palette data + geVFile_Seek(File, tgah.IDLength, GE_VFILE_SEEKCUR); + + if ( ! geVFile_Read(File, Bmp->Info.Palette->Data, tgah.CMLength*(tgah.CMEntrySize/8)) ) + return GE_FALSE; + + break; + + case 16 : + pelBytes = 2; + Bmp->Info.Format = GE_PIXELFORMAT_16BIT_555_RGB; + ImageOffset = tgah.IDLength+((tgah.CMEntrySize/8) * tgah.CMLength); + break; + + case 24 : + pelBytes = 3; + Bmp->Info.Format = GE_PIXELFORMAT_24BIT_BGR; + ImageOffset = tgah.IDLength+((tgah.CMEntrySize/8) * tgah.CMLength); + break; + + case 32 : + // Alpha map base creation *************************** + AlphaBmp = geBitmap_Create_Base(); + + if (!AlphaBmp) + return GE_FALSE; + + AlphaBmp->Info.Width = tgah.Width; + AlphaBmp->Info.Height = tgah.Height; + AlphaBmp->Info.Stride = ((tgah.Width+3)&(~3)); + AlphaBmp->Info.HasColorKey = GE_FALSE; + AlphaBmp->Info.Format = GE_PIXELFORMAT_8BIT_GRAY; + + if ( ! geBitmap_AllocSystemMip(AlphaBmp,0) ) + goto fail; + // Alpha map base creation done ********************** + + pelBytes = 3; + Bmp->Info.Format = GE_PIXELFORMAT_24BIT_BGR; + // Bmp->Info.Format = GE_PIXELFORMAT_32BIT_ARGB; + ImageOffset = tgah.IDLength+((tgah.CMEntrySize/8) * tgah.CMLength); + + break; + + default : + return GE_FALSE; + } + + + + if ( ! geBitmap_AllocSystemMip(Bmp,0) ) + goto fail; + + // move to the image data + geVFile_Seek(File, ImageOffset, GE_VFILE_SEEKCUR); + + myRowWidth = Bmp->Info.Stride * pelBytes; + bmpRowWidth = (((tgah.Width * pelBytes) + 3)&(~3)); + assert( bmpRowWidth <= myRowWidth ); + + // NOTE: to avoid the if(tgah.PixelDepth == 32) statements in the following code + // you can write a separate reading code for 32bit in the switch statement above + // this may be longer but faster ... + + //Uncompressed images + if(tgah.ImageType == 1 || tgah.ImageType == 2) + { + int count, y; + char *row; + char * alpharow; + row = Bmp->Data[0]; + alpharow = NULL; + + if(tgah.PixelDepth == 32) + alpharow = AlphaBmp->Data[0]; + + if(fliphoriz) + { + row += (Bmp->Info.Height - 1) * myRowWidth; + if(tgah.PixelDepth == 32) + alpharow += (AlphaBmp->Info.Height - 1) * (AlphaBmp->Info.Stride); + } + + for(y= Bmp->Info.Height;y--;) + { + // uff... since this could be 32bit we have to read each pixel separately + for(count=0; countInfo.Stride; count++ ) + { + geVFile_Read(File, row, pelBytes); + row += pelBytes; + if(tgah.PixelDepth == 32) + { + geVFile_Read(File, alpharow, 1); + alpharow++; + } + } + if(fliphoriz) + { + // go back this row and to the row above + row -= 2*myRowWidth; + if(tgah.PixelDepth == 32) + alpharow -= 2*(AlphaBmp->Info.Stride); + } + } + } + //Run-Length Encoded images + else if(tgah.ImageType == 9 || tgah.ImageType == 10) + { + int i, j, k, y; + char buff[4]; + char * row; + char * alpharow; + row = Bmp->Data[0]; + alpharow = NULL; + y = 0; + k = 1; + + if(tgah.PixelDepth == 32) + alpharow = AlphaBmp->Data[0]; + + if(fliphoriz) + { + row += (Bmp->Info.Height - 1) * myRowWidth; + if(tgah.PixelDepth == 32) + alpharow += (AlphaBmp->Info.Height - 1) * (AlphaBmp->Info.Stride); + } + while(y < Bmp->Info.Height) + { + // read in the Repetition Count byte: + // 1bit = packet type (RLE/Raw packet), 7bits = pixel count + // The pixel count can range from 0 to 127. Since a packet never + // encodes zero pixels, the value in pixel count is always 1 less + // than the actual number of pixels encoded in the packet + geVFile_Read(File, buff, 1); + + j = buff[0] & 0x7f; // number of encoded pixels-1 + + if(buff[0] & 0x80) // RLE packet + { + geVFile_Read(File, buff, pelBytes); + if(tgah.PixelDepth == 32) + geVFile_Read(File, &(buff[3]), 1); + + for(i = 0; i <= j; i++) + { + *row++ = buff[0]; + if(pelBytes>1) *row++ = buff[1]; + if(pelBytes>2) *row++ = buff[2]; + if(tgah.PixelDepth == 32) *alpharow++ = buff[3]; + k++; + if(k > Bmp->Info.Stride) + { + k=1; + y++; + if(fliphoriz) + { + // go back this row and to the row above + row -= 2*myRowWidth; + if(tgah.PixelDepth == 32) + alpharow -= 2*(AlphaBmp->Info.Stride); + } + } + } + } + else //Raw packet + { + for(i = 0; i <= j; i++) + { + geVFile_Read(File, row, pelBytes); + row += pelBytes; + if(tgah.PixelDepth == 32) + { + geVFile_Read(File, alpharow, 1); + alpharow++; + } + k++; + if(k > Bmp->Info.Stride) + { + k=1; + y++; + if(fliphoriz) + { + // go back this row and to the row above + row -= 2*myRowWidth; + if(tgah.PixelDepth == 32) + alpharow -= 2*(AlphaBmp->Info.Stride); + } + } + } + } + } + } + else + goto fail; + + //set alphamap + if(tgah.PixelDepth == 32) + { + assert(AlphaBmp); + if(!geBitmap_SetAlpha( Bmp, AlphaBmp)) + goto fail; + geBitmap_Destroy(&AlphaBmp); + geBitmap_SetPreferredFormat(Bmp,GE_PIXELFORMAT_32BIT_ARGB); + } + + return GE_TRUE; + +fail: + if(AlphaBmp); + geBitmap_Destroy(&AlphaBmp); + return GE_FALSE; +} + + +/*}{ *** Packed Info IO ***/ + +#define INFO_FLAG_WH_ARE_LOG2 (1<<0) +#define INFO_FLAG_HAS_CK (1<<1) +#define INFO_FLAG_HAS_ALPHA (1<<2) +#define INFO_FLAG_HAS_PAL (1<<3) + +#define INFO_FLAG_IF_NOT_LOG2_ARE_BYTE (1<<5) + +geBoolean geBitmap_ReadInfo(geBitmap *Bmp,geVFile * F) +{ +uint8 data[4]; +uint8 flags; +uint8 b; +uint16 w; +geBitmap_Info * pi; + + pi = &(Bmp->Info); + + if ( ! geVFile_Read(F,data,3) ) + return GE_FALSE; + + flags = data[0]; + + pi->Format = data[1]; // could go in 5 bits + + b = data[2]; + + pi->MaximumMip = (b>>4)&0xF; + Bmp->SeekMipCount = (b)&0xF; + + if ( flags & INFO_FLAG_HAS_PAL ) + pi->Palette = (geBitmap_Palette *)1; + if ( flags & INFO_FLAG_HAS_ALPHA ) + Bmp->Alpha = (geBitmap *)1; + + if ( flags & INFO_FLAG_WH_ARE_LOG2 ) + { + int logw,logh; + + if ( ! geVFile_Read(F,&b,1) ) + return GE_FALSE; + + logw = (b>>4)&0xF; + logh = (b )&0xF; + + pi->Width = 1<Height= 1<Width = b; + if ( ! geVFile_Read(F,&b,1) ) + return GE_FALSE; + pi->Height = b; + } + else + { + if ( ! geVFile_Read(F,&w,2) ) + return GE_FALSE; + pi->Width = w; + if ( ! geVFile_Read(F,&w,2) ) + return GE_FALSE; + pi->Height = w; + } + + if ( (flags & INFO_FLAG_HAS_CK) && gePixelFormat_BytesPerPel(pi->Format) > 0 ) + { + uint8 * ptr; + pi->HasColorKey = GE_TRUE; + + if ( ! geVFile_Read(F,data,gePixelFormat_BytesPerPel(pi->Format)) ) + return GE_FALSE; + + ptr = data; + pi->ColorKey = gePixelFormat_GetPixel(pi->Format,&ptr); + } + + pi->Stride = pi->Width; + + return GE_TRUE; +} + +geBoolean geBitmap_WriteInfo(const geBitmap *Bmp,geVFile * F) +{ +uint8 data[64]; +uint8 * ptr; +uint8 flags; +uint8 b; +int len,logw,logh; +const geBitmap_Info * pi; + +/* + bit flags : + W&H are log2 + HasCK + HasAlpha + HasPal + + W&H logs in 1 byte, or W & H each in 2 bytes + + Format in 5 bits + MaxMip in 3 bits + Bmp->SeekMipCount in 3 bits + + CK in bpp bytes +*/ + + pi = &(Bmp->Info); + flags = 0; + ptr = data + 1; // flags will go there + + assert( pi->Width < 65536 && pi->Height < 65536 ); + assert( pi->MinimumMip == 0 ); + assert( gePixelFormat_IsValid(pi->Format) ); + + *ptr++ = pi->Format; // could go in 5 bits + + b = (pi->MaximumMip << 4) + Bmp->SeekMipCount; // could go in 6 bits + *ptr++ = b; + + if ( pi->Palette ) + flags |= INFO_FLAG_HAS_PAL; + if ( Bmp->Alpha ) + flags |= INFO_FLAG_HAS_ALPHA; + + for(logw=0;(1<Width;logw++); + for(logh=0;(1<Height;logh++); + + if ( (1<Width && (1<Height ) + { + flags |= INFO_FLAG_WH_ARE_LOG2; + assert( logw <= 0xF && logh <= 0xF ); + b = (logw<<4) + logh; + *ptr++ = b; + } + else + { + if ( pi->Width < 256 && pi->Height < 256 ) + { + flags |= INFO_FLAG_IF_NOT_LOG2_ARE_BYTE; + *ptr++ = pi->Width; + *ptr++ = pi->Height; + } + else + { + *((uint16 *)ptr) = pi->Width; ptr += 2; + *((uint16 *)ptr) = pi->Height; ptr += 2; + } + } + + if ( pi->HasColorKey && gePixelFormat_BytesPerPel(pi->Format) > 0 ) + { + flags |= INFO_FLAG_HAS_CK; + + gePixelFormat_PutPixel(pi->Format,&ptr,pi->ColorKey); + } + + *data = flags; + len = (int)(ptr - data); + + if ( ! geVFile_Write(F,data,len) ) + return GE_FALSE; + + return GE_TRUE; +} + +/*}{ ***************** Palette Functions *******************/ + +geBoolean geBitmap_Palette_BlitData(gePixelFormat SrcFormat,const void *SrcData,const geBitmap_Palette * SrcPal, + gePixelFormat DstFormat, void *DstData,const geBitmap_Palette * DstPal, + int Pixels) +{ +char *SrcPtr,*DstPtr; +geBoolean SrcHasCK,DstHasCK; +uint32 SrcCK=0,DstCK=0; +int SrcCKi=0,DstCKi=0; + + assert( SrcData && DstData ); + + assert( gePixelFormat_IsRaw(SrcFormat) ); + assert( gePixelFormat_IsRaw(DstFormat) ); + + SrcPtr = (char *)SrcData; + DstPtr = (char *)DstData; + + if ( SrcPal && SrcPal->HasColorKey ) + { + SrcHasCK = GE_TRUE; + SrcCK = SrcPal->ColorKey; + SrcCKi = SrcPal->ColorKeyIndex; + } + else + { + SrcHasCK = GE_FALSE; + } + + if ( DstPal && DstPal->HasColorKey ) + { + DstHasCK = GE_TRUE; + DstCK = DstPal->ColorKey; + DstCKi = DstPal->ColorKeyIndex; + } + else + { + DstHasCK = GE_FALSE; + } + +#if 0 // {} ? + if ( SrcHasCK && DstHasCK ) + { + if ( DstCKi == -1 ) + DstCKi = SrcCKi; + } +#endif + + // no, can't do this, and if SrcCKi < 0 then it's just ignored, which is correct + //assert( SrcCKi >= 0 ); + //assert( DstCKi >= 0 ); + + // CK -> no CK : do nothing + // no CK -> CK : avoid CK + // CK -> CK : assert the CKI's are the same; change color at CKI + + { + uint32 Pixel; + int p,R,G,B,A; + const gePixelFormat_Operations *SrcOps,*DstOps; + gePixelFormat_Composer ComposePixel; + gePixelFormat_Decomposer DecomposePixel; + gePixelFormat_PixelPutter PutPixel; + gePixelFormat_PixelGetter GetPixel; + + SrcOps = gePixelFormat_GetOperations(SrcFormat); + DstOps = gePixelFormat_GetOperations(DstFormat); + assert(SrcOps && DstOps); + + GetPixel = SrcOps->GetPixel; + DecomposePixel = SrcOps->DecomposePixel; + ComposePixel = DstOps->ComposePixel; + PutPixel = DstOps->PutPixel; + + if ( SrcOps->AMask && ! DstOps->AMask ) + { + // alpha -> CK in the palette + for(p=0;pAMask && DstOps->AMask ) + { + // CK -> alpha in the palette + for(p=0;pRMask ) + { + geErrorLog_AddString(-1,"geBitmap_Palette_Create : Invalid format for a palette!", NULL); + return NULL; + } + + DataBytes = gePixelFormat_BytesPerPel(Format) * Size; + if ( DataBytes == 0 ) + { + geErrorLog_AddString(-1,"geBitmap_Palette_Create : Invalid format for a palette!", NULL); + return NULL; + } + + allocate(P); + if ( ! P ) return NULL; + clear(P); + + P->Size = Size; + P->Format = Format; + if ( ! (P->Data = geRam_Allocate(DataBytes)) ) + { + geRam_Free(P); + return NULL; + } + + P->RefCount = 1; + P->LockCount = 0; + + P->HasColorKey = GE_FALSE; + +return P; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_CreateRef(geBitmap_Palette *P) +{ + if ( ! P || P->RefCount < 1 ) + return GE_FALSE; + P->RefCount ++; +return GE_TRUE; +} + +GENESISAPI geBitmap_Palette * GENESISCC geBitmap_Palette_CreateFromBitmap(geBitmap * Bmp,geBoolean Slow) +{ +geBitmap_Palette * Pal; + Pal = geBitmap_GetPalette(Bmp); + if ( Pal ) + { + geBitmap_Palette_CreateRef(Pal); + return Pal; + } + else + { + return createPaletteFromBitmap(Bmp, Slow); + } +} + +geBitmap_Palette * BITMAP_GENESIS_INTERNAL geBitmap_Palette_CreateFromDriver(DRV_Driver * Driver,gePixelFormat Format,int Size) +{ +geBitmap_Palette * P; +geRDriver_THandleInfo TInfo; + + assert(Driver); + + allocate(P); + if ( ! P ) return NULL; + clear(P); + + P->Size = Size; + P->Driver = Driver; + + // {} the pixelformat passed in here has non-trivial implications when the + // driver provides more than one possible palette type + + assert( gePixelFormat_IsRaw(Format) ); + + P->DriverHandle = geBitmap_CreateTHandle(Driver,Size,1,1, + Format,0,0,gePixelFormat_HasAlpha(Format),0,RDRIVER_PF_PALETTE); + if ( ! P->DriverHandle ) + { + geErrorLog_AddString(-1,"Palette_CreateFromDriver : CreateTHandle", NULL); + geRam_Free(P); + return NULL; + } + + Driver->THandle_GetInfo(P->DriverHandle,0,&TInfo); + P->Format = TInfo.PixelFormat.PixelFormat; + + P->HasColorKey = (TInfo.Flags & RDRIVER_THANDLE_HAS_COLORKEY) ? GE_TRUE : GE_FALSE; + P->ColorKey = TInfo.ColorKey; + P->ColorKeyIndex = -1; + + P->RefCount = 1; + +return P; +} + +GENESISAPI geBitmap_Palette * GENESISCC geBitmap_Palette_CreateCopy(const geBitmap_Palette *Palette) +{ +geBitmap_Palette * P; + + if ( ! Palette ) + return NULL; + + if ( Palette->Driver ) + { + P = geBitmap_Palette_CreateFromDriver(Palette->Driver,Palette->Format,Palette->Size); + } + else + { + P = geBitmap_Palette_Create(Palette->Format,Palette->Size); + } + + if ( ! P ) return NULL; + + if ( ! geBitmap_Palette_Copy(Palette,P) ) + { + geBitmap_Palette_Destroy(&P); + return NULL; + } + +return P; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_Destroy(geBitmap_Palette ** ppPalette) +{ +geBitmap_Palette * Palette; + assert(ppPalette); + if ( Palette = *ppPalette ) + { + if ( Palette->LockCount ) + return GE_FALSE; + Palette->RefCount --; + if ( Palette->RefCount <= 0 ) + { + if ( Palette->Data ) + geRam_Free(Palette->Data); + if ( Palette->DriverHandle ) + { + Palette->Driver->THandle_Destroy(Palette->DriverHandle); + Palette->DriverHandle = NULL; + } + geRam_Free(Palette); + } + } + *ppPalette = NULL; +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_Lock(geBitmap_Palette *P, void **pBits, gePixelFormat *pFormat,int *pSize) +{ + assert(P); + assert(pBits); + + if ( P->LockCount ) + return GE_FALSE; + P->LockCount++; + + *pBits = NULL; + + if ( P->Data ) + { + *pBits = P->Data; + if ( pFormat ) + *pFormat= P->Format; + if ( pSize ) + *pSize = P->Size; + } + else if ( P->DriverHandle ) + { + geRDriver_THandleInfo TInfo; + + if ( ! P->Driver->THandle_GetInfo(P->DriverHandle,0,&TInfo) ) + return GE_FALSE; + + if ( TInfo.Height != 1 ) + return GE_FALSE; + + if ( ! (P->Driver->THandle_Lock(P->DriverHandle,0,pBits)) ) + *pBits = NULL; + + P->DriverBits = *pBits; + + if ( pFormat ) + *pFormat = TInfo.PixelFormat.PixelFormat; + if ( pSize ) + *pSize = TInfo.Width; + } + + return (*pBits) ? GE_TRUE : GE_FALSE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_UnLock(geBitmap_Palette *P) +{ + assert(P); + if ( P->LockCount <= 0 ) + return GE_FALSE; + P->LockCount--; + if ( P->LockCount == 0 ) + { + if ( P->HasColorKey ) + { + if ( P->ColorKeyIndex >= 0 && P->ColorKeyIndex < P->Size ) + { + uint8 *Bits=NULL,*pBits=NULL; + uint32 Pixel; + int p; + const gePixelFormat_Operations *ops; + gePixelFormat_PixelPutter PutPixel; + gePixelFormat_PixelGetter GetPixel; + + if ( P->Data ) + { + Bits = P->Data; + } + else if ( P->DriverBits ) + { + Bits = P->DriverBits; + } + + ops = gePixelFormat_GetOperations(P->Format); + assert(ops); + + GetPixel = ops->GetPixel; + PutPixel = ops->PutPixel; + + for(p=0;pSize;p++) + { + pBits = Bits; + Pixel = GetPixel(&Bits); + if ( p == P->ColorKeyIndex ) + { + PutPixel(&pBits,P->ColorKey); + } + else if ( Pixel == P->ColorKey ) + { + Pixel ^= 1; + PutPixel(&pBits,Pixel); + } + } + } + } + if ( P->DriverHandle ) + { + if ( ! P->Driver->THandle_UnLock(P->DriverHandle,0) ) + return GE_FALSE; + P->DriverBits = NULL; + } + } +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_SetFormat(geBitmap_Palette * P,gePixelFormat Format) +{ +void * NewData; + + assert(P); + + if ( P->DriverHandle ) // can't change format on card! + return GE_FALSE; + + assert( ! P->HasColorKey ); // can't have colorkey accept on Glide + + if ( Format == P->Format ) + return GE_TRUE; + + NewData = geRam_Allocate( gePixelFormat_BytesPerPel(Format) * P->Size ); + if ( ! NewData ) + return GE_FALSE; + + if ( ! geBitmap_Palette_BlitData(P->Format,P->Data,NULL,Format,NewData,NULL,P->Size) ) + { + geRam_Free(NewData); + return GE_FALSE; + } + + geRam_Free(P->Data); + P->Data = NewData; + P->Format = Format; + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_GetData(const geBitmap_Palette *P,void *Into,gePixelFormat Format,int Size) +{ +gePixelFormat FmFormat; +const void *FmData; +int FmSize; +geBoolean Ret; + + assert(P); + assert(Into); + + if ( ! geBitmap_Palette_Lock((geBitmap_Palette *)P,(void **)&FmData,&FmFormat,&FmSize) ) + return GE_FALSE; + + if ( FmSize < Size ) + Size = FmSize; + + Ret = geBitmap_Palette_BlitData(FmFormat,FmData,P,Format,Into,NULL,Size); + + geBitmap_Palette_UnLock((geBitmap_Palette *)P); + +return Ret; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_GetInfo(const geBitmap_Palette *P,geBitmap_Info *pInfo) +{ + assert(P && pInfo); + + pInfo->Width = pInfo->Stride = P->Size; + pInfo->Height = 1; + + pInfo->Format = P->Format; + pInfo->HasColorKey = P->HasColorKey; + pInfo->ColorKey = P->ColorKey; + pInfo->MaximumMip = pInfo->MinimumMip = 0; + pInfo->Palette = NULL; + +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_SetData(geBitmap_Palette *P,const void *From,gePixelFormat Format,int Colors) +{ +gePixelFormat PalFormat; +void *PalData; +int PalSize; +geBoolean Ret; + + assert(P); + assert(From); + + if ( ! geBitmap_Palette_Lock(P,&PalData,&PalFormat,&PalSize) ) + return GE_FALSE; + + if ( PalSize < Colors ) + Colors = PalSize; + + Ret = geBitmap_Palette_BlitData(Format,From,NULL,PalFormat,PalData,P,Colors); + + if ( ! geBitmap_Palette_UnLock(P) ) + return GE_FALSE; + +return Ret; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_Copy(const geBitmap_Palette * Fm,geBitmap_Palette * To) +{ +gePixelFormat FmFormat,ToFormat; +void *FmData,*ToData; +int FmSize,ToSize; +geBoolean Ret; + + assert(Fm); + assert(To); + if ( Fm == To ) + return GE_TRUE; + + if ( ! geBitmap_Palette_Lock((geBitmap_Palette *)Fm,&FmData,&FmFormat,&FmSize) ) + return GE_FALSE; + + if ( ! geBitmap_Palette_Lock(To,&ToData,&ToFormat,&ToSize) ) + { + geBitmap_Palette_UnLock((geBitmap_Palette *)Fm); + return GE_FALSE; + } + + if ( FmSize > ToSize ) + { + Ret = GE_FALSE; + } + else + { + Ret = geBitmap_Palette_BlitData(FmFormat,FmData,Fm,ToFormat,ToData,To,FmSize); + } + + geBitmap_Palette_UnLock((geBitmap_Palette *)Fm); + geBitmap_Palette_UnLock(To); + +return Ret; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_SetEntryColor(geBitmap_Palette *P,int Color,int R,int G,int B,int A) +{ + assert(P); + + if ( A < 80 && ! gePixelFormat_HasAlpha(P->Format) && P->HasColorKey ) + { + return geBitmap_Palette_SetEntry(P,Color,P->ColorKey); + } + else if ( P->HasColorKey ) + { + uint32 Pixel; + + // might have alpha AND colorkey ! + + if ( Color == P->ColorKeyIndex ) // and A > 80 because of the above + return GE_FALSE; + + Pixel = gePixelFormat_ComposePixel(P->Format,R,G,B,A); + if ( Pixel == P->ColorKey ) + Pixel ^= 1; + + return geBitmap_Palette_SetEntry(P,Color,Pixel); + } + else + { + return geBitmap_Palette_SetEntry(P,Color,gePixelFormat_ComposePixel(P->Format,R,G,B,A)); + } +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_GetEntryColor(const geBitmap_Palette *P,int Color,int *R,int *G,int *B,int *A) +{ +uint32 Pixel; + assert(P); + if ( P->HasColorKey ) + { + if ( Color == P->ColorKeyIndex ) + { + *R = *G = *B = *A = 0; + return GE_TRUE; + } + else + { + if ( ! geBitmap_Palette_GetEntry(P,Color,&Pixel) ) + return GE_FALSE; + if ( Pixel == P->ColorKey ) + { + *R = *G = *B = *A = 0; + } + else + { + gePixelFormat_DecomposePixel(P->Format,Pixel,R,G,B,A); + } + } + } + else + { + if ( ! geBitmap_Palette_GetEntry(P,Color,&Pixel) ) + return GE_FALSE; + gePixelFormat_DecomposePixel(P->Format,Pixel,R,G,B,A); + } + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_SetEntry(geBitmap_Palette *P,int Color,uint32 Pixel) +{ + assert(P); + + if ( P->HasColorKey ) + { + if ( Color == P->ColorKeyIndex ) + return GE_TRUE; + } + + if ( P->Data ) + { + char *Data; + + if ( Color >= P->Size ) + return GE_FALSE; + + Data = (char *)(P->Data) + Color * gePixelFormat_BytesPerPel(P->Format); + gePixelFormat_PutPixel(P->Format,&Data,Pixel); + } + else + { + char *Data; + gePixelFormat Format; + int Size; + + if ( ! geBitmap_Palette_Lock(P,&Data,&Format,&Size) ) + return GE_FALSE; + + if ( Color >= Size ) + { + geBitmap_Palette_UnLock(P); + return GE_FALSE; + } + + Data += Color * gePixelFormat_BytesPerPel(Format); + gePixelFormat_PutPixel(Format,&Data,Pixel); + + geBitmap_Palette_UnLock(P); + } +return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_GetEntry(const geBitmap_Palette *P,int Color,uint32 *Pixel) +{ + + assert(P); + + if ( P->Data ) + { + char *Data; + + if ( Color >= P->Size ) + return GE_FALSE; + + Data = (char *)(P->Data) + Color * gePixelFormat_BytesPerPel(P->Format); + *Pixel = gePixelFormat_GetPixel(P->Format,&Data); + } + else + { + char *Data; + gePixelFormat Format; + int Size; + + // must cast away const cuz we don't have a lockforread/write on palettes + + if ( ! geBitmap_Palette_Lock((geBitmap_Palette *)P,&Data,&Format,&Size) ) + return GE_FALSE; + + if ( Color >= Size ) + { + geBitmap_Palette_UnLock((geBitmap_Palette *)P); + return GE_FALSE; + } + + Data += Color * gePixelFormat_BytesPerPel(Format); + *Pixel = gePixelFormat_GetPixel(Format,&Data); + + geBitmap_Palette_UnLock((geBitmap_Palette *)P); + } +return GE_TRUE; +} + +#define PALETTE_INFO_FORMAT_MASK (0x1F) +#define PALETTE_INFO_FLAG_SIZE256 (1<<5) // 5 is the low +#define PALETTE_INFO_FLAG_COMPRESS (1<<6) + +GENESISAPI geBitmap_Palette * GENESISCC geBitmap_Palette_CreateFromFile(geVFile *F) +{ +geBitmap_Palette * P; +int Size; +gePixelFormat Format; +uint8 flags,b; + + if ( ! geVFile_Read(F, &flags, sizeof(flags)) ) + return NULL; + + Format = flags & PALETTE_INFO_FORMAT_MASK; + + if ( flags & PALETTE_INFO_FLAG_SIZE256 ) + { + Size = 256; + } + else + { + if ( ! geVFile_Read(F, &b, sizeof(b)) ) + return NULL; + Size = b; + } + + P = geBitmap_Palette_Create(Format,Size); + if ( ! P ) + return NULL; + + if ( flags & PALETTE_INFO_FLAG_COMPRESS ) + { + geErrorLog_AddString(-1,"Bitmap_Palette_CreateFromFile : codePal failed!",NULL); + return GE_FALSE; + } + else + { + if ( ! geVFile_Read(F, P->Data, gePixelFormat_BytesPerPel(P->Format) * P->Size) ) + { + geRam_Free(P); + return NULL; + } + } + +return P; +} + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_WriteToFile(const geBitmap_Palette *P,geVFile *F) +{ +int Size; +gePixelFormat Format; +void *Data; + + assert(P); + + assert( P->HasColorKey == GE_FALSE ); // system palettes can't have color key! + + // we usually write the palette's header in one byte :^) + + if ( ! geBitmap_Palette_Lock((geBitmap_Palette *)P,&Data,&Format,&Size) ) + return GE_FALSE; + + { + uint8 b; + + b = Format; + assert( b < 32 ); + if ( Size == 256 ) + b |= PALETTE_INFO_FLAG_SIZE256; + + if ( ! geVFile_Write(F, &b, sizeof(b)) ) + { + geBitmap_Palette_UnLock((geBitmap_Palette *)P); + return GE_FALSE; + } + + if ( Size != 256 ) + { + assert(Size < 256); + b = Size; + + if ( ! geVFile_Write(F, &b, sizeof(b)) ) + { + geBitmap_Palette_UnLock((geBitmap_Palette *)P); + return GE_FALSE; + } + } + } + + if ( ! geVFile_Write(F, Data, gePixelFormat_BytesPerPel(Format) * Size) ) + { + geBitmap_Palette_UnLock((geBitmap_Palette *)P); + return GE_FALSE; + } + + geBitmap_Palette_UnLock((geBitmap_Palette *)P); + +return GE_TRUE; +} + +/*}{ ******************** IsValid funcs **************************/ + +// {} put ErrorLogs indicating where we failed in _IsValid + +geBoolean geBitmap_IsValid(const geBitmap *Bmp) +{ + if ( ! Bmp ) return GE_FALSE; + + assert( Bmp->RefCount >= 1 ); + + assert( ! (Bmp->LockCount && Bmp->LockOwner) ); + + assert( !( (Bmp->DriverDataChanged || Bmp->DriverBitsLocked) && + ! Bmp->DriverHandle ) ); + assert( ! (Bmp->DriverHandle && ! Bmp->Driver) ); + + if ( ! geBitmap_Info_IsValid(&(Bmp->Info)) ) + return GE_FALSE; + + if ( Bmp->DriverHandle && ! geBitmap_Info_IsValid(&(Bmp->DriverInfo)) ) + return GE_FALSE; + + if ( Bmp->LockOwner && Bmp->Alpha ) + assert( Bmp->Alpha->LockOwner ); + + if ( Bmp->LockOwner ) + { + assert(Bmp->LockOwner != Bmp); + assert( Bmp->LockOwner->LockCount ); + } + + if ( Bmp->DataOwner ) + { + assert(Bmp->DataOwner != Bmp); + assert( Bmp->DataOwner->RefCount >= 2 ); + } + + if ( Bmp->Alpha ) + { + assert(Bmp->Alpha != Bmp); + if ( ! geBitmap_IsValid(Bmp->Alpha) ) + return GE_FALSE; + } + +return GE_TRUE; +} + +geBoolean geBitmap_Info_IsValid(const geBitmap_Info *Info) +{ + if ( ! Info ) return GE_FALSE; + + assert( Info->Width > 0 && Info->Height > 0 && Info->Stride >= Info->Width ); + + assert( Info->MinimumMip >= 0 && Info->MaximumMip < MAXMIPLEVELS && Info->MinimumMip <= Info->MaximumMip ); + + assert( Info->Format > GE_PIXELFORMAT_NO_DATA && Info->Format < GE_PIXELFORMAT_COUNT ); + +// ok to have palette on non-palettized +// if ( ! gePixelFormat_HasPalette(Info->Format) && Info->Palette ) +// return GE_FALSE; + + if ( Info->Palette ) + if ( ! geBitmap_Palette_IsValid(Info->Palette) ) + return GE_FALSE; + +return GE_TRUE; +} + +geBoolean geBitmap_Palette_IsValid(const geBitmap_Palette *Pal) +{ + if ( ! Pal ) return GE_FALSE; + + assert( Pal->Data || Pal->DriverHandle ); + assert( !Pal->Data || !Pal->DriverHandle ); + + assert( (Pal->Driver && Pal->DriverHandle) || + (! Pal->Driver && ! Pal->DriverHandle) ); + + assert( Pal->RefCount >= 1 && Pal->Size >= 1 ); + assert( Pal->Format > GE_PIXELFORMAT_NO_DATA && Pal->Format < GE_PIXELFORMAT_COUNT ); + +return GE_TRUE; +} + +#ifdef _DEBUG +GENESISAPI uint32 GENESISCC geBitmap_Debug_GetCount(void) +{ + + return _Bitmap_Debug_ActiveCount; +} +GENESISAPI uint32 GENESISCC geBitmap_Debug_GetRefs(void) +{ + + return _Bitmap_Debug_ActiveRefs; +} +#endif + +/*}{ ******************** Average Color **************************/ + +GENESISAPI geBoolean GENESISCC geBitmap_GetAverageColor(const geBitmap *Bmp,int *pR,int *pG,int *pB) +{ + { + int bpp,x,y,w,h,xtra,dock; + gePixelFormat Format; + uint8 * ptr; + uint32 R,G,B,A,Rt,Gt,Bt,cnt,ck; + + //{} Rt == Rtotal , probably won't overflow; we can handle a 4096x4095 solid-white image + + if ( Bmp->DriverHandle && Bmp->DriverDataChanged ) + { + // must use the driver bits + if ( ! geBitmap_Update_DriverToSystem((geBitmap *)Bmp) ) + { + geErrorLog_AddString(-1,"Bitmap_AverageColor : DriverToSystem failed!",NULL); + return GE_FALSE; + } + } + + Format = Bmp->Info.Format; + bpp = gePixelFormat_BytesPerPel(Format); + ptr = Bmp->Data[0]; + + if ( ! ptr || bpp < 1 ) + { + geErrorLog_AddString(-1,"Bitmap_AverageColor : no data!",NULL); + return GE_FALSE; + } + + w = Bmp->Info.Width; + h = Bmp->Info.Height; + xtra = (Bmp->Info.Stride - w)*bpp; + ck = Bmp->Info.ColorKey; + dock = Bmp->Info.HasColorKey; + + Rt = Gt = Bt = cnt = 0; + + if ( gePixelFormat_HasPalette(Format) ) + { + // <> Blech! + geErrorLog_AddString(-1,"Bitmap_AverageColor : doesn't support palettized yet!",NULL); + #pragma message("Bitmap_AverageColor : doesn't support palettized yet!") + return GE_FALSE; + } + else + { + const gePixelFormat_Operations * ops; + gePixelFormat_ColorGetter GetColor; + gePixelFormat_PixelGetter GetPixel; + gePixelFormat_Decomposer Decomposer; + + assert( gePixelFormat_IsRaw(Format) ); + + ops = gePixelFormat_GetOperations(Format); + GetColor = ops->GetColor; + GetPixel = ops->GetPixel; + Decomposer = ops->DecomposePixel; + + if ( dock ) + { + for(y=h;y--;) + { + for(x=w;x--;) + { + uint32 Pixel; + Pixel = GetPixel(&ptr); + if ( Pixel != ck ) + { + Decomposer(Pixel,&R,&G,&B,&A); + Rt += R; Gt += G; Bt += B; + cnt ++; + } + } + ptr += xtra; + } + } + else + { + for(y=h;y--;) + { + for(x=w;x--;) + { + GetColor(&ptr,&R,&G,&B,&A); + if ( A > 80 ) + { + Rt += R; Gt += G; Bt += B; + cnt ++; + } + } + ptr += xtra; + } + } + } + + if ( pR ) *pR = (Rt + (cnt>>1)) / cnt; + if ( pG ) *pG = (Gt + (cnt>>1)) / cnt; + if ( pB ) *pB = (Bt + (cnt>>1)) / cnt; + } + +return GE_TRUE; +} + +/*}{ ******************** EOF **************************/ + diff --git a/G3D/Bitmap/bitmap.h b/G3D/Bitmap/bitmap.h new file mode 100644 index 0000000..9263a42 --- /dev/null +++ b/G3D/Bitmap/bitmap.h @@ -0,0 +1,627 @@ +#ifndef BITMAP_H +#define BITMAP_H + +/****************************************************************************************/ +/* Bitmap.h */ +/* */ +/* Author: Charles Bloom */ +/* Description: Abstract Bitmap system */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "basetype.h" +#include "pixelformat.h" +#include "vfile.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/***********************************************************************************/ + +typedef struct geBitmap geBitmap; +typedef struct geBitmap_Palette geBitmap_Palette; + +typedef struct geBitmap_Info +{ + int Width; + int Height; + int Stride; // stride is in *pixels* ; it is the step to the next line : Stride >= Width + gePixelFormat Format; + int MinimumMip; //*including* minimumMip == 0 often + int MaximumMip; //*including* maximumMip == nummips-1 + geBoolean HasColorKey; + uint32 ColorKey; // meaningless unless HasColorKey ; the ColorKey is a Pixel in Format + geBitmap_Palette * Palette; +} geBitmap_Info; + +/***********************************************************************************/ +// Bitmap methods + +// see a big comment at the end of this file + +/************************************************************************/ + +GENESISAPI geBitmap * GENESISCC geBitmap_Create(int Width, int Height, int MipCount, gePixelFormat Format ); +GENESISAPI void GENESISCC geBitmap_CreateRef(geBitmap *Bmp); + +GENESISAPI geBitmap * GENESISCC geBitmap_CreateFromInfo(const geBitmap_Info * pInfo); + +GENESISAPI geBitmap * GENESISCC geBitmap_CreateFromFile( geVFile *F ); +GENESISAPI geBitmap * GENESISCC geBitmap_CreateFromFileName(const geVFile *BaseFS,const char *Name); +GENESISAPI geBoolean GENESISCC geBitmap_WriteToFile( const geBitmap *Bmp, geVFile *F ); +GENESISAPI geBoolean GENESISCC geBitmap_WriteToFileName(const geBitmap * Bmp,const geVFile *BaseFS,const char *Name); + // BaseFS is not really const if it is a virtual file; + // it *is* const if it is a dos directory + +GENESISAPI geBoolean GENESISCC geBitmap_Destroy(geBitmap **Bmp); + // returns whether Bmp was actually destroyed : not success/failure + +GENESISAPI geBoolean GENESISCC geBitmap_GetInfo(const geBitmap *Bmp, geBitmap_Info *Info, geBitmap_Info *SecondaryInfo); + //LockForWrite returns data in Info's format + +GENESISAPI geBoolean GENESISCC geBitmap_Blit(const geBitmap *Src, int SrcPositionX, int SrcPositionY, + geBitmap *Dst, int DstPositionX, int DstPositionY, + int SizeX, int SizeY ); + +GENESISAPI geBoolean GENESISCC geBitmap_BlitMip(const geBitmap * Src, int SrcMip, geBitmap * Dst, int DstMip ); + // don't use this with Src == Dst, use UpdateMips instead ! + +GENESISAPI geBoolean GENESISCC geBitmap_BlitBitmap(const geBitmap * Src, geBitmap * Dst); + +GENESISAPI geBoolean GENESISCC geBitmap_BlitBestMip(const geBitmap * Src, geBitmap * Dst); + // blits the largest mip from Src that fits in Dst + +GENESISAPI geBoolean GENESISCC geBitmap_LockForRead( // a non-exclusive lock + const geBitmap * Bmp, + geBitmap ** Target, + int MinimumMip, + int MaximumMip, + gePixelFormat Format, + geBoolean RespectColorKey, + uint32 ColorKey); + // not really const, stores lock-count, but *data* is const + // will do a format conversion! + +GENESISAPI geBoolean GENESISCC geBitmap_LockForReadNative( + const geBitmap * Bmp, + geBitmap ** Target, + int MinimumMip, + int MaximumMip); + // lock for read in a format that gaurantee no conversions + // then do GetInfo on the locks to see what you have! + +GENESISAPI geBoolean GENESISCC geBitmap_LockForWrite( // an exclusive lock + geBitmap * Bmp, + geBitmap ** Target, + int MinimumMip, + int MaximumMip); + +GENESISAPI geBoolean GENESISCC geBitmap_LockForWriteFormat( + geBitmap * Bmp, + geBitmap ** Target, + int MinimumMip, + int MaximumMip, + gePixelFormat Format); + // Format must be one of the two returned in GetInfo !! + +GENESISAPI geBoolean GENESISCC geBitmap_UnLock(geBitmap *Bmp); // must be done on All locked mips +GENESISAPI geBoolean GENESISCC geBitmap_UnLockArray(geBitmap **Locks,int Size); + +GENESISAPI geBoolean GENESISCC geBitmap_SetFormat(geBitmap *Bmp, + gePixelFormat NewFormat, + geBoolean RespectColorKey, uint32 ColorKey, + const geBitmap_Palette * Palette); + // _SetFormat may cause you to lose color information! + // SetFormat does a conversion! + // if NewFormat is palettized and Palette is NULL, we create a palette for the bitmap! + +GENESISAPI geBoolean GENESISCC geBitmap_SetFormatMin(geBitmap *Bmp,gePixelFormat NewFormat); + // the Min version keeps colorkey & palette from the old format + +GENESISAPI geBoolean GENESISCC geBitmap_SetColorKey(geBitmap *Bmp, geBoolean HasColorKey, uint32 ColorKey, geBoolean Smart); + // SetColorKey discards old colorkey information! + // does not do a conversion (changes the colorkey in the current data + // if 'Smart' is on, we don't set HasColorKey to true unless it is actually used! + +GENESISAPI geBoolean GENESISCC geBitmap_GetAverageColor(const geBitmap *Bmp,int *pR,int *pG,int *pB); + // tells you the average color; computes it and caches it out + +GENESISAPI geBitmap_Palette * GENESISCC geBitmap_GetPalette(const geBitmap *Bmp); +GENESISAPI geBoolean GENESISCC geBitmap_SetPalette(geBitmap *Bmp, const geBitmap_Palette *Palette); + // _SetPal tries to _CreateRef your Palette, so no copy occurs & palettes may be shared + // you may _Destroy() palette after using it to set (though its bits may not be freed) + // (hence Palette is *not* const) + // Warning : SetPalette on any mip changes the palette of ALL mips ! + // see Palette note at _UnLock + // _SetPal destroys the bitmap's original palette and refs the new one, + // so if you setpal with the bitmap's palette, there is no net change in ref counts (good!) + +GENESISAPI geBoolean GENESISCC geBitmap_HasAlpha(const geBitmap * Bmp); + // returns true if bitmap has *any* type of alpha + +GENESISAPI geBitmap * GENESISCC geBitmap_GetAlpha(const geBitmap *Bmp); +GENESISAPI geBoolean GENESISCC geBitmap_SetAlpha(geBitmap *Bmp, const geBitmap *AlphaBmp); + // we Ref the AlphaBmp, so you may destroy it after calling Set() + // it may be NULL + // there's only one Alpha per bitmap (for the top Mip) right now + +GENESISAPI geBoolean GENESISCC geBitmap_SetGammaCorrection(geBitmap *Bmp,geFloat Gamma,geBoolean Apply); + // this Gamma does not change the *original* (system/secondary) bits + // it only affects the appearance when drawn + // note : if you write to the gamma corrected bits, you must gamma correct manually if you + // wish to fit in smoothly with the previous data + // warning : if you use this function with many different gammas, performance will suffer! + // use one global gamma for all bitmaps! try to let the engine manage gamma for you, + // via geEngine_SetGamma ! + +GENESISAPI geBoolean GENESISCC geBitmap_SetPreferredFormat(geBitmap *Bmp,gePixelFormat Format); +GENESISAPI gePixelFormat GENESISCC geBitmap_GetPreferredFormat(const geBitmap *Bmp); + +GENESISAPI void * GENESISCC geBitmap_GetBits(geBitmap *Bmp); // works only on a Lock() + +GENESISAPI geBoolean GENESISCC geBitmap_RefreshMips(geBitmap *Bmp); // rebuilds mips; *tries* to be smart & not overwrite manually-fixed mips + // RefreshMips does *not* build mips that don't exist +GENESISAPI geBoolean GENESISCC geBitmap_UpdateMips(geBitmap *Bmp,int SourceMip,int TargetMip); + // will create the target if it doesn't exist; + // will overwrite manually-fixed mips! +GENESISAPI geBoolean GENESISCC geBitmap_SetMipCount(geBitmap *Bmp,int Count); + // creates or destroys to match the new count + +GENESISAPI geBoolean GENESISCC geBitmap_ClearMips(geBitmap *Bmp); // Destroy all mips (except the first) ! + // use with care! this is not polite! + +// Shortcuts +GENESISAPI int GENESISCC geBitmap_Width(const geBitmap *Bitmap); +GENESISAPI int GENESISCC geBitmap_Height(const geBitmap *Bitmap); +GENESISAPI uint32 GENESISCC geBitmap_MipBytes(const geBitmap * Bitmap,int mip); + +/** +* +* if Bitmap is a lock for read, functions that modify it return failure +* if Bitmap is a lock for write, functions that modify it attempt to +* modify the owner of the lock +* +* warning : if you lock multiple mips for write, and then modify one of the mips +* (such as via SetPalette) it may affect the owner and all sibling mips! +* doing different SetPalettes with different palettes on different locked mips +* has undefined behavior! +* +**/ + +#ifdef _DEBUG + +GENESISAPI uint32 GENESISCC geBitmap_Debug_GetCount(void); + +GENESISAPI uint32 GENESISCC geBitmap_Debug_GetRefs(void); + // assert this is zero before you shutdown ! + +#endif + +/***********************************************************************************/ + +typedef enum +{ + GE_BITMAP_STREAMING_ERROR=0, + GE_BITMAP_STREAMING_NOT, + GE_BITMAP_STREAMING_STARTED, + GE_BITMAP_STREAMING_IDLE, + GE_BITMAP_STREAMING_CHANGED, + GE_BITMAP_STREAMING_DATADONE, + GE_BITMAP_STREAMING_DONE, +} geBitmap_StreamingStatus; + +GENESISAPI geBitmap_StreamingStatus GENESISCC geBitmap_GetStreamingStatus(const geBitmap *Bmp); + + /** on a file which is streaming, the sequence of returns looks like : + + GE_BITMAP_STREAMING_IDLE + GE_BITMAP_STREAMING_CHANGED + GE_BITMAP_STREAMING_IDLE + GE_BITMAP_STREAMING_IDLE + GE_BITMAP_STREAMING_CHANGED + ... + GE_BITMAP_STREAMING_DONE + GE_BITMAP_STREAMING_NOT + GE_BITMAP_STREAMING_NOT + GE_BITMAP_STREAMING_NOT + ... + + Status >= GE_BITMAP_STREAMING_STARTED means streaming has started & is in progress + + the user should never see _STARTED or _DATADONE + + ***/ + +/***********************************************************************************/ + +// palette methods : + +GENESISAPI geBitmap_Palette * GENESISCC geBitmap_Palette_Create(gePixelFormat Format,int Size); + +GENESISAPI geBitmap_Palette * GENESISCC geBitmap_Palette_CreateCopy(const geBitmap_Palette *Palette); + +GENESISAPI geBitmap_Palette * GENESISCC geBitmap_Palette_CreateFromFile(geVFile *F); + +GENESISAPI geBitmap_Palette * GENESISCC geBitmap_Palette_CreateFromBitmap(geBitmap * Bmp,geBoolean Slow); + // does GetPalette, and if NULL, then + // it create an optimal palette for a + // non-palettized bitmap + // (this is a create, you must destroy later!) + // put Slow == TRUE for higher quality & slower + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_SortColors(geBitmap_Palette * P,geBoolean Slower); + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_CreateRef(geBitmap_Palette *Palette); + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_Destroy(geBitmap_Palette ** ppPalette); + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_WriteToFile(const geBitmap_Palette *Palette,geVFile *F); + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_SetFormat(geBitmap_Palette * Palette,gePixelFormat Format); + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_Copy(const geBitmap_Palette * Src,geBitmap_Palette * Target); + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_GetInfo(const geBitmap_Palette *P,geBitmap_Info *Into); + // get the info as if it were a bitmap; Into->Height == 1 + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_Lock(geBitmap_Palette *Palette, void **pBits, gePixelFormat *pFormat,int *pSize); + // pFormat & pSize are optional + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_UnLock(geBitmap_Palette *Palette); + // palette unlock does NOT notify the bitmap that the palette has changed. + // call Bitmap_SetPalette() with the same palette pointer + // to tell the bitmap that it must to some processing + // (don't worry, it won't duplicate it or copy it onto itself) + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_GetData(const geBitmap_Palette *P, void *Into,gePixelFormat Format,int Colors); +GENESISAPI geBoolean GENESISCC geBitmap_Palette_SetData( geBitmap_Palette *P,const void *From,gePixelFormat Format,int Colors); + // does Lock/UnLock for you + // From and Into are arrays of Colors*gePixelFormat_BytesPerPel bytes + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_SetEntryColor( geBitmap_Palette *P,int Color,int R,int G,int B,int A); +GENESISAPI geBoolean GENESISCC geBitmap_Palette_GetEntryColor(const geBitmap_Palette *P,int Color,int *R,int *G,int *B,int *A); + // Set/Get does Lock/Unlock for you ; these are slow! do not use these to work on all the colors! + +GENESISAPI geBoolean GENESISCC geBitmap_Palette_SetEntry( geBitmap_Palette *P,int Color,uint32 Pixel); +GENESISAPI geBoolean GENESISCC geBitmap_Palette_GetEntry(const geBitmap_Palette *P,int Color,uint32 *Pixel); + +/***********************************************************************************/ + +/************************************************************************ + +A brief tutorial on the Bitmap system, by Charles Bloom, cbloom@wildtangent.com + +The Bitmap is a smart wrapper for complex functionality. You give it hints to +the opaque Bitmap object, and it tries its best to follow those hints, but it +may not always do so. The Bitmap is the owner of its bits; you must Lock the +bitmap to get permission to touch those bits, and UnLock to tell the bitmap +you are done. The format may change between two Locks. Bitmaps can also be +multiply owned, so you should account for the fact that others may touch your +bitmap between your uses. + +The Bitmap contains one or two pixel-sets representing an image. The "primary" is +a fast-blitting version of the image, and the "secondary" is a storage version +(eventually wavelet compressed) which can be used to rebuild the primary if it is +freed or damaged. Both cary a generalized format. + +Let's do an example. I want to load a bitmap, set it up for drawing with the +genesis Engine, and then blit some interactive stuff into it. + +************************************************************************/ + +#if 0 +// { +//----------------------------------------------------------------------------- + +void Init(geEngine * Engine); +void Shutdown(void); +void Draw(void); +void DrawPolite(void); + +static geBitmap * myBM = NULL; +static geEngine * myEngine = NULL; + +void Init(geEngine * Engine) +{ +geBoolean success; +geBitmap_Info Info; + + myEngine = Engine; // this is not looked well upon; for ease of demonstration only! + assert(Engine); + + myBM = geBitmap_CreateFromFileName(NULL,"mybitmap.bmp"); + + // CreateFromFile can load windows BMP files, or custom GeBm files. + + assert(myBM); + + // get the main info; I don't care about the secondary, so leave it NULL + + success = geBitmap_GetInfo(myBM,&Info,NULL); + assert(success); + + // make sure I loaded a bitmap in the format I understand ! + + if ( Info.Format == GE_PIXELFORMAT_8BIT_PAL ) + { + // I want palette index 255 to act as transparency, so I must use SetColorKey + + success = geBitmap_SetColorKey(myBM,GE_TRUE,255); + assert(success); + + // just for fun, let's modify the palette: + if (1) + { + geBitmap_Palette * Pal; + + // get the palette ; I don't care if its primary or secondary, so + /// I don't use the Info.Palette field + + Pal = geBitmap_GetPalette(myBM); + assert(Pal); + + // I'm only fiddling one entry, so don't bother with a full Lock() UnLock() + // sequence on the palette + + // make palette index zero bright red; we use alpha = 255 for opaque + + success = geBitmap_Palette_SetEntryColor(Pal,0,255,0,0,255); + assert(success); + + // tell the bitmap system you've changed the palette; this function + // is smart enough to not do unecessary copies or whatever. + + success = geBitmap_SetPalette(myBM,Pal); + assert(success); + } + + } + else + { + // otherwise, treat black as transparent, in whatever format I have + + success = geBitmap_SetColorKey(myBM,GE_TRUE,gePixelFormat_ComposePixel(Info.Format,0,0,0,0)); + assert(success); + } + + // note that I did NOT use SetFormat. SetFormat may do a conversion, and since the original + // bitmap was created without colorkey, it would have been converted to a new format but + // kept its property of having no colorkey! + // (SetFormat will fiddle the bits and whatever way necessary to keep bitmaps as visually similar + // as possible) + + // I want to fiddle the fast format in 565 later, so cue the bitmap to try to give me that format. + + success = geBitmap_SetPreferredFormat(myBM,GE_PIXELFORMAT_16BIT_565_RGB); + assert(success); + + // Add it to the engine so it can be used for drawing. + + success = geEngine_AddBitmap(myEngine,myBM); + assert(success); +} + +void Shutdown(void) +{ +geBoolean WasDestroyed; + + assert(myBM); + + // clean up + + geEngine_RemoveBitmap(myEngine,myBM); + + WasDestroyed = geBitmap_Destroy(&myBM); + + // someone else might have done _CreateRef on our bitmap, + // so we can't be sure it's actually destroyed. + // this code is still ready to be run again with a new call to Init() + + //assert(WasDestroyed); + + myBM = NULL; + myEngine = NULL; +} + +void Draw(void) +{ +geBitmap * Lock; +geBoolean success; +geBitmap_Info Info; +uint16 *bits,*bptr; +int x,y; + + // lets fiddle the bits. + // we need to lock the bitmap for write. + // LockForWrite is an exclusive lock, unlike LockForRead which is non-blocking + // request our favorite format, and only lock Mip 0 (the full size bitmap) + + success = geBitmap_LockForWriteFormat(myBM,&Lock,0,0,GE_PIXELFORMAT_16BIT_565_RGB); + if ( ! success ) + { + // well, we tried to be nice; if we were very polite, we would do a LockForWrite + // here, and try to fiddle the bits in whatever format we got; However, we aren't + // that polite, so we just do a _SetFormat + // + // note that we are destroying the original bitmap by changing its format + // we should only do this if we are going to draw into the bitmap + + success = geBitmap_SetFormat(myBM,GE_PIXELFORMAT_16BIT_565_RGB,GE_TRUE,0,NULL); + assert(success); + + // now we should be able to get the bits we want, *but* they may not be the + // primary (fast) format; oh well, it's the best we can do... + // (if you must have the fastest bits, then use only _LockForWrite, never LockForWriteFormat, + // which might have to do a conversion) + + success = geBitmap_LockForWriteFormat(myBM,&Lock,0,0,GE_PIXELFORMAT_16BIT_565_RGB); + assert(success); + } + + // now Lock is our bitmap in 565 + // we do a GetInfo because the Lock's info could be different than + // the original bitmap's (particularly the Palette & the Stride) + + success = geBitmap_GetInfo(Lock,&Info,NULL); + assert(success); + + // you can only call _GetBits on a locked bitmap + + bits = geBitmap_GetBits(Lock); + assert( bits ); + + bptr = bits; + for(y=0; y < Info.Height; y++) + { + for(x=0; x < Info.Width; x++) + { + uint16 R,G,B; + // make a silly 565 gradient + R = x & 0x1F; + G = x & 0x3F; + B = y & 0x1F; + + *bptr++ = (R<<11) + (G<<5) + B; + } + + // note that bptr is a word pointer, and Stride is in pixels : + + bptr += Info.Stride - Info.Width; + } + bits = bptr = NULL; + + // you call Unlock on all the mips you locked - not on the original bitmap! + + success = geBitmap_UnLock(Lock); + assert(success); + + // now, we only fiddled the full-size Mip, and there might be more, + // so lets percolate the changes into the smaller mips: + + success = geBitmap_RefreshMips(myBM); + assert(success); + + // a null rect means use the whole bitmap; + // Engine_DrawBitmap blits a 2d decal to the framebuffer (fast) + + success = geEngine_DrawBitmap(myEngine,myBM,NULL,0,0); + assert(success); + +} + +void DrawPolite(void) +{ +geBitmap * Lock; +geBoolean success; +geBitmap_Info Info; +void *bits; +int x,y; + + // this function does the same thing as Draw() , but is more polite + // lock in the fastest format (whatever it is) + // because we did SetPreferred, this should be 565_RGB, but might not be + + success = geBitmap_LockForWrite(myBM,&Lock,0,0); + assert(success); + + success = geBitmap_GetInfo(Lock,&Info,NULL); + assert(success); + + bits = geBitmap_GetBits(Lock); + assert( bits ); + + if ( Info.Format == GE_PIXELFORMAT_16BIT_565_RGB ) + { + uint16 *wptr; + + // our favorite format + + wptr = bits; + for(y=0; y < Info.Height; y++) + { + for(x=0; x < Info.Width; x++) + { + uint16 R,G,B; + // make a silly 565 gradient + R = x & 0x1F; + G = x & 0x3F; + B = y & 0x1F; + + *wptr++ = (R<<11) + (G<<5) + B; + } + wptr += Info.Stride - Info.Width; + } + } + else + { + uint8 * bptr; + + // oh well, do our best + // bitmaps must have had a good reason to not give us the format we preferred, + + bptr = bits; + for(y=0; y < Info.Height; y++) + { + for(x=0; x < Info.Width; x++) + { + uint32 R,G,B; + + // put a color in any format + + R = (x & 0x1F)<<3; + G = (x & 0x3F)<<2; + B = (y & 0x1F)<<3; + + // we use alpha of 255 for opaque + + gePixelFormat_PutColor(Info.Format,&bptr,R,G,B,255); + } + + bptr += (Info.Stride - Info.Width) * gePixelFormat_BytesPerPel(Info.Format); + } + } + bits = NULL; + + // same as before: + + success = geBitmap_UnLock(Lock); + assert(success); + + success = geBitmap_RefreshMips(myBM); + assert(success); + + success = geEngine_DrawBitmap(myEngine,myBM,NULL,0,0); + assert(success); + +} + +// end tutorial on the Bitmap system +//----------------------------------------------------------------------------- +// } + +/***********************************************************************************/ + +#endif +#ifdef __cplusplus +} +#endif + + +#endif + + diff --git a/G3D/Bitmap/bitmap_blitdata.c b/G3D/Bitmap/bitmap_blitdata.c new file mode 100644 index 0000000..314c337 --- /dev/null +++ b/G3D/Bitmap/bitmap_blitdata.c @@ -0,0 +1,1847 @@ +/****************************************************************************************/ +/* Bitmap_BlitData.c */ +/* */ +/* Author: Charles Bloom */ +/* Description: The Bitmap_BlitData function */ +/* Does all format conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +/*}{*********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "basetype.h" +#include "getypes.h" +#include "ram.h" + +#include "bitmap.h" +#include "bitmap._h" +#include "bitmap.__h" +#include "bitmap_blitdata.h" + +#include "vfile.h" +#include "ErrorLog.h" + +#include "palcreate.h" +#include "palettize.h" + +#include "tsc.h" + +#ifdef DO_TIMER +#include "timer.h" +#endif + +//#define DONT_USE_ASM + +/*}{*********************************************************************/ + +// parameters to the main BlitData call are set up in here & shared +// with all the children functions + +// this may actually be better than being thread-friendly +// because we prevent cache-thrashing + +static int SrcXtra,DstXtra; +static int SrcPelBytes,DstPelBytes; +static int SrcRowBytes,DstRowBytes; +static int SrcXtraBytes,DstXtraBytes; +static const gePixelFormat_Operations *SrcOps,*DstOps; +static gePixelFormat SrcFormat,DstFormat; + +static const geBitmap_Info * SrcInfo; +static geBitmap_Info * DstInfo; +static const void *SrcData; +static void *DstData; +static const geBitmap *SrcBmp; +static geBitmap *DstBmp; +static const geBitmap_Palette *SrcPal; +static geBitmap_Palette *DstPal; +static int SizeX,SizeY; + +static gePixelFormat_Decomposer SrcDecomposePixel; +static gePixelFormat_Composer DstComposePixel; +static gePixelFormat_ColorGetter SrcGetColor; +static gePixelFormat_ColorPutter DstPutColor; +static gePixelFormat_PixelGetter SrcGetPixel; +static gePixelFormat_PixelPutter DstPutPixel; + +/*}{*********************************************************************/ + +geBoolean BlitData_Raw(void); +geBoolean BlitData_SameFormat(void); +geBoolean BlitData_Palettize(void); +geBoolean BlitData_DePalettize(void); +geBoolean BlitData_FromSeparateAlpha(void); +geBoolean BlitData_ToSeparateAlpha(void); + +geBoolean geBitmap_BlitData_Sub( const geBitmap_Info * iSrcInfo,const void *iSrcData, const geBitmap *iSrcBmp, + geBitmap_Info * iDstInfo,void *iDstData, const geBitmap *iDstBmp, + int iSizeX,int iSizeY) +{ + + // warming up... + + SrcInfo = iSrcInfo; + DstInfo = iDstInfo; + SrcData = iSrcData; + DstData = iDstData; + SrcBmp = iSrcBmp; + DstBmp = (geBitmap *)iDstBmp; + SizeX = iSizeX; + SizeY = iSizeY; + + assert(SrcInfo && SrcData && DstInfo && DstData); + + // SrcData & DstData may be the same! + // SrcBmp & DstBmp may be NULL ! + + if ( SizeX > SrcInfo->Width || SizeX > DstInfo->Width || + SizeY > SrcInfo->Height|| SizeY > DstInfo->Height) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : size mismatch", NULL); + return GE_FALSE; + } + + SrcFormat = SrcInfo->Format; + DstFormat = DstInfo->Format; + + SrcOps = gePixelFormat_GetOperations(SrcFormat); + DstOps = gePixelFormat_GetOperations(DstFormat); + + if ( ! SrcOps || ! DstOps ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData: SrcOps != DstOps",NULL); + return GE_FALSE; + } + + SrcPelBytes = SrcOps->BytesPerPel; + DstPelBytes = DstOps->BytesPerPel; + + SrcRowBytes = SrcPelBytes * SrcInfo->Stride; + DstRowBytes = DstPelBytes * DstInfo->Stride; + + SrcXtra = SrcInfo->Stride - SizeX; + DstXtra = DstInfo->Stride - SizeX; + + SrcXtraBytes = SrcXtra * SrcPelBytes; + DstXtraBytes = DstXtra * DstPelBytes; + + DstComposePixel = DstOps->ComposePixel; + DstPutColor = DstOps->PutColor; + DstPutPixel = DstOps->PutPixel; + SrcDecomposePixel = SrcOps->DecomposePixel; + SrcGetColor = SrcOps->GetColor; + SrcGetPixel = SrcOps->GetPixel; + + SrcPal = SrcInfo->Palette; + if ( ! SrcPal && SrcBmp ) + SrcPal = geBitmap_GetPalette(SrcBmp); + DstPal = DstInfo->Palette; + if ( ! DstPal && DstBmp ) + DstPal = geBitmap_GetPalette(DstBmp); + + // all systems go! + + /** copy the palette **/ + + if ( gePixelFormat_HasPalette(SrcFormat) && ! SrcPal ) + { + geErrorLog_AddString(-1, "geBitmap_BlitData: Palettized format, with no palette.", NULL); + return GE_FALSE; + } + + if ( SrcPal && gePixelFormat_HasPalette(DstFormat) ) + { + if ( ! DstInfo->Palette ) + { + gePixelFormat Format; + Format = SrcPal->Format; + if ( ! gePixelFormat_HasAlpha(Format) ) + { + if ( SrcInfo->HasColorKey && ! DstInfo->HasColorKey ) + Format = GE_PIXELFORMAT_32BIT_ARGB; + } + geBitmap_AllocPalette(DstBmp,Format,DstBmp->Driver); + if ( ! DstInfo->Palette ) + DstInfo->Palette = geBitmap_GetPalette(DstBmp); + } + DstPal = DstInfo->Palette; + if ( ! DstPal ) + { + geErrorLog_AddString(-1, "geBitmap_BlitData: couldn't alloc new dest palette.", NULL); + return GE_FALSE; + } + + if ( ! geBitmap_Palette_Copy(SrcPal,DstPal) ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : Palette_Copy failed", NULL); + return GE_FALSE; + } + + if ( SrcInfo->HasColorKey ) + { + if ( ! geBitmap_Palette_SetEntryColor(DstInfo->Palette,SrcInfo->ColorKey,0,0,0,0) ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData: geBitmap_Palette_SetEntryColor failed",NULL); + return GE_FALSE; + } + } + } + + /**** + ** + * + modes: + 0. types are same + 1. Wavelet <-> raw + 2. Pal -> raw (easy) (now raw means "not wavelet or pal") + 3. raw -> Pal (hard) + 4. raw <-> raw (just bit-ops) + + each of these also exists for separate alpha types + * + ** + ****/ + + /****/ + + if ( SrcBmp && SrcBmp->Alpha && SrcBmp->Alpha->LockOwner && + DstBmp && DstBmp->Alpha && DstBmp->Alpha->LockOwner ) + { + if ( ! geBitmap_BlitBitmap(SrcBmp->Alpha,DstBmp->Alpha) ) + { + geErrorLog_AddString(-1,"geBitmap_BlitData: geBitmap_BlitBitmap Failed",NULL); + return GE_FALSE; + } + // now continue through to blit the main bitmap + } + else if ( SrcBmp && SrcBmp->Alpha && SrcBmp->Alpha->LockOwner && + ( gePixelFormat_HasAlpha(DstFormat) || DstInfo->HasColorKey ) ) + { + // there is no separate alpha -> color key conversion + // note that we cannot add separate alpha -> CK because the + // separate-alpha *target* type has colorkey too ! + if (BlitData_FromSeparateAlpha()==GE_FALSE) + { + geErrorLog_AddString(-1,"geBitmap_BlitData: geBitmap_FromSeparateAlpha Failed",NULL); + return GE_FALSE; + } + else + return GE_TRUE; + + } + else if ( DstBmp && DstBmp->Alpha && DstBmp->Alpha->LockOwner && + gePixelFormat_HasAlpha(SrcFormat) ) + { + // there is no separate alpha -> color key conversion + // note that we cannot add separate alpha -> CK because the + // separate-alpha *target* type has colorkey too ! + if (BlitData_ToSeparateAlpha()==GE_FALSE) + { + geErrorLog_AddString(-1,"geBitmap_BlitData: geBitmap_ToSeparateAlpha Failed",NULL); + return GE_FALSE; + } + else + return GE_TRUE; + } + + /****/ + + if ( SrcFormat == GE_PIXELFORMAT_WAVELET || + DstFormat == GE_PIXELFORMAT_WAVELET ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : no wavelets in Genesis 1.0", NULL); + return GE_FALSE; + } + else if ( SrcFormat == DstFormat ) + { + if (BlitData_SameFormat()==GE_FALSE) + { + geErrorLog_AddString(-1,"geBitmap_BlitData: BlitData_SameFormat failed",NULL); + return GE_FALSE; + } + else + return GE_TRUE; + } + else if ( gePixelFormat_HasPalette(SrcFormat) || + gePixelFormat_HasPalette(DstFormat) ) + { + assert(SrcFormat != DstFormat); + if ( gePixelFormat_HasPalette(SrcFormat) && + gePixelFormat_HasPalette(DstFormat) ) + { + geErrorLog_AddString(-1,"geBitmap_BlitData: two different palettized.",NULL); + return GE_FALSE; // already picked up by SameFormat , or two different palettized = abort! + } + + if ( gePixelFormat_HasPalette(SrcFormat) ) + { + if (BlitData_DePalettize()==GE_FALSE) + { + geErrorLog_AddString(-1,"geBitmap_BlitData: BlitData_DePalettize() failed.",NULL); + return GE_FALSE; + } + else + return GE_TRUE; + } + else + { + if ( ! DstInfo->Palette ) + { + // make it + if ( DstBmp && DstBmp->Driver ) + { + gePixelFormat Format; + Format = SrcInfo->Palette ? SrcInfo->Palette->Format : GE_PIXELFORMAT_32BIT_XRGB; + if ( ! gePixelFormat_HasAlpha(Format) ) + { + if ( SrcInfo->HasColorKey && ! DstInfo->HasColorKey ) + Format = GE_PIXELFORMAT_32BIT_ARGB; + } + geBitmap_AllocPalette(DstBmp,Format,DstBmp->Driver); + if ( ! DstInfo->Palette ) + DstInfo->Palette = geBitmap_GetPalette(DstBmp); + } + else + { + DstInfo->Palette = geBitmap_Palette_Create(PALETTE_FORMAT_DEFAULT,256); + } + if ( ! DstInfo->Palette ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : Pal create failed", NULL); + return GE_FALSE; + } + + if ( SrcPal ) + { + geBitmap_Palette_Copy(SrcPal,DstInfo->Palette); + } + else if ( DstPal ) + { + geBitmap_Palette_Copy(DstPal,DstInfo->Palette); + } + else // Nobody had a palette ! + { + geBitmap_Palette * NewPal; + geBitmap_Info Info; + Info = *SrcInfo; + Info.Width = SizeX; + Info.Height = SizeY; + NewPal = createPalette(&Info,SrcData); + if ( ! NewPal ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : createPalette failed", NULL); + return GE_FALSE; + } + geBitmap_Palette_Copy(NewPal,DstInfo->Palette); + if ( SrcBmp && ((SizeX*SizeY) > ((SrcInfo->Width * SrcInfo->Height)>>2)) ) + { + geBitmap_SetPalette((geBitmap *)SrcBmp,NewPal); + } + geBitmap_Palette_Destroy(&NewPal); + } + + DstPal = DstInfo->Palette; + + SrcPal = SrcInfo->Palette; + if ( ! SrcPal && SrcBmp ) + SrcPal = geBitmap_GetPalette(SrcBmp); + } + + if (BlitData_Palettize()==GE_FALSE) + { + geErrorLog_AddString(-1,"geBitmap_BlitData: BlitData_Palettize failed.",NULL); + return GE_FALSE; + } + else + return GE_TRUE; + } + } + else + { + if (BlitData_Raw()==GE_FALSE) + { + geErrorLog_AddString(-1,"geBitmap_BlitData: BlitData_Raw failed.",NULL); + return GE_FALSE; + } + else + return GE_TRUE; + } + + assert(0); + // must have returned before here + //return GE_FALSE; +} + +geBoolean geBitmap_BlitData( const geBitmap_Info * iSrcInfo,const void *iSrcData, const geBitmap *iSrcBmp, + geBitmap_Info * iDstInfo,void *iDstData, const geBitmap *iDstBmp, + int iSizeX,int iSizeY) +{ +geBoolean Ret; + + Ret = geBitmap_BlitData_Sub( + iSrcInfo,iSrcData,iSrcBmp, + iDstInfo,iDstData,iDstBmp, + iSizeX,iSizeY); + +return Ret; +} + +/*}{*********************************************************************/ + +geBoolean BlitData_Raw(void) +{ +int x,y; +char *SrcPtr,*DstPtr; +int R,G,B,A; +uint32 ColorKey,Pixel; + + if ( ! SrcOps || ! DstOps ) + return GE_FALSE; + + SrcPtr = (char *)SrcData; + DstPtr = (char *)DstData; + + // this generic converter is pretty slow. + // fortunately genesis uses mostly the (Pal -> UnPal) conversion + // or the (Wavelet -> UnPal) conversion + + if ( SrcPelBytes == 0 || DstPelBytes == 0 ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : invalid format", NULL); + return GE_FALSE; + } + else if ( SrcOps->AMask && ! (DstOps->AMask) && DstInfo->HasColorKey ) + { + ColorKey = DstInfo->ColorKey; + + // special case for "Src has alpha & Dst doesn't, but has ColorKey" + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + SrcGetColor(&SrcPtr,&R,&G,&B,&A); + if ( A < ALPHA_TO_TRANSPARENCY_THRESHOLD ) + { + Pixel = ColorKey; + } + else + { + Pixel = DstComposePixel(R,G,B,A); + if ( Pixel == ColorKey ) + { + Pixel ^= 1; + } + } + DstPutPixel(&DstPtr,Pixel); + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + } + + return GE_TRUE; + } + else if ( SrcInfo->HasColorKey && DstInfo->HasColorKey ) + { + uint32 DstColorKey; + + ColorKey = SrcInfo->ColorKey; + DstColorKey = DstInfo->ColorKey; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = SrcGetPixel(&SrcPtr); + if ( Pixel == ColorKey ) + { + DstPutPixel(&DstPtr,DstColorKey); + } + else + { + SrcDecomposePixel(Pixel,&R,&G,&B,&A); + Pixel = DstComposePixel(R,G,B,A); + if ( Pixel == DstColorKey ) + Pixel ^= 1; + DstPutPixel(&DstPtr,Pixel); + } + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + } + + return GE_TRUE; + } + else if ( DstInfo->HasColorKey ) + { + ColorKey = DstInfo->ColorKey; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + SrcGetColor(&SrcPtr,&R,&G,&B,&A); + Pixel = DstComposePixel(R,G,B,A); + if ( Pixel == ColorKey ) + { + Pixel ^= 1; + } + DstPutPixel(&DstPtr,Pixel); + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + } + + return GE_TRUE; + } + else if ( SrcInfo->HasColorKey ) + { + // generic converter does the cases we don't understand + + ColorKey = SrcInfo->ColorKey; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = SrcGetPixel(&SrcPtr); + if ( Pixel == ColorKey ) + { + DstPutColor(&DstPtr,0,0,0,0); + } + else + { + SrcDecomposePixel(Pixel,&R,&G,&B,&A); + DstPutColor(&DstPtr,R,G,B,A); + } + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + } + + return GE_TRUE; + } + else + { + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + SrcGetColor(&SrcPtr,&R,&G,&B,&A); + DstPutColor(&DstPtr,R,G,B,A); + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + } + + return GE_TRUE; + } +} + +/*}{*********************************************************************/ + +geBoolean BlitData_FromSeparateAlpha(void) +{ +geBitmap_Info AlphaInfo; +void * AlphaData; +uint8 *SrcPtr,*DstPtr,*AlphaPtr; +int x,y,R,G,B,A; +uint32 ColorKey,Pixel; +int AlphaXtra; + + /******* + ** + support the extra Alpha Bmp + the common case is 8bit + 8bit -> 4444 + + we're pretty lazy about this; it's not optimized for speed + + ** + ******/ + + #pragma message("Bitmap_BlitData: inconsistent handling of separates with color keys!") + + SrcPtr = (uint8 *)SrcData; + DstPtr = (uint8 *)DstData; + + if ( ! geBitmap_GetInfo(SrcBmp->Alpha,&AlphaInfo,NULL) ) + return GE_FALSE; + if ( AlphaInfo.Format != GE_PIXELFORMAT_8BIT_GRAY ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : Alpha must be grayscale", NULL); + return GE_FALSE; + } + + AlphaData = geBitmap_GetBits(SrcBmp->Alpha); + if ( ! AlphaData ) + return GE_FALSE; + + AlphaPtr = (uint8 *)AlphaData; + AlphaXtra = AlphaInfo.Stride - SizeX; + + if ( gePixelFormat_HasPalette(SrcFormat) ) + { + if ( SrcFormat == DstFormat ) + { + uint8 Pixel,DstColorKey; + + assert(DstInfo->HasColorKey); + + DstColorKey = (uint8)DstInfo->ColorKey; + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = *SrcPtr++; + A = *AlphaPtr++; + if ( A < ALPHA_TO_TRANSPARENCY_THRESHOLD ) + *DstPtr++ = DstColorKey; + else + *DstPtr++ = Pixel; + } + SrcPtr += SrcXtra; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + return GE_TRUE; + } + else if ( SrcFormat == GE_PIXELFORMAT_8BIT ) + { + uint8 *PalPtr,PalData[768]; + int pal; + + if ( ! geBitmap_Palette_GetData(SrcPal,PalData,GE_PIXELFORMAT_24BIT_RGB,256) ) + return GE_FALSE; + + // with seperate alpha + + if ( ! gePixelFormat_HasAlpha(DstFormat) && DstInfo->HasColorKey ) + { + uint32 Pixel,DstColorKey; + // source is palettized + // dest has color key and no alpha + DstColorKey = DstInfo->ColorKey; + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + pal = *SrcPtr++; + PalPtr = &PalData[3*pal]; + R = *PalPtr++; + G = *PalPtr++; + B = *PalPtr; + A = *AlphaPtr++; + if ( A < 128 ) + { + DstPutPixel(&DstPtr,DstColorKey); + } + else + { + Pixel = DstComposePixel(R,G,B,255); + if ( Pixel == DstColorKey ) + Pixel ^= 1; + DstPutPixel(&DstPtr,Pixel); + } + } + SrcPtr += SrcXtra; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + } + else if ( DstInfo->HasColorKey ) + { + uint32 Pixel,DstColorKey; + // source is palettized + // dest has alpha and color key + DstColorKey = DstInfo->ColorKey; + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + pal = *SrcPtr++; + PalPtr = &PalData[3*pal]; + R = *PalPtr++; + G = *PalPtr++; + B = *PalPtr; + A = *AlphaPtr++; + Pixel = DstComposePixel(R,G,B,A); + if ( Pixel == DstColorKey ) + Pixel ^= 1; + DstPutPixel(&DstPtr,Pixel); + } + SrcPtr += SrcXtra; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + } + else + { + // source is palettized + // dest has alpha and no color key + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + pal = *SrcPtr++; + PalPtr = &PalData[3*pal]; + R = *PalPtr++; + G = *PalPtr++; + B = *PalPtr; + A = *AlphaPtr++; + DstPutColor(&DstPtr,R,G,B,A); + } + SrcPtr += SrcXtra; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + } + + return GE_TRUE; + } + else + { + return GE_FALSE; + } + assert("should not get here" == NULL); + } + else + { + // this generic converter is pretty slow. + // fortunately genesis uses mostly the (Pal -> UnPal) conversion + // or the (Wavelet -> UnPal) conversion + + // Src is not palettized + + assert( ! SrcOps->AMask ); + assert( DstOps->AMask || DstInfo->HasColorKey ); + + // <> doesn't do -> palettize + // should never get a (separates)->(palettized) with current driver, but bad to assume... + // perhaps the best thing is to do separates -> 32bitRGBA then do 32bitRGBA -> Dest with the normal converters + + if ( gePixelFormat_HasPalette(DstFormat) ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : FromSeparateAlpha : doesn't do Palettize!", NULL); + return GE_FALSE; + } + + if ( SrcPelBytes == 0 ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : FromSeparateAlpha : bad Src format", NULL); + return GE_FALSE; + } + else if ( DstPelBytes == 0 || ! DstPutColor || ! DstComposePixel ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : FromSeparateAlpha : bad Dst format", NULL); + return GE_FALSE; + } + + + if ( DstOps->AMask ) + { + + //separates -> alpha + + if ( SrcInfo->HasColorKey && DstInfo->HasColorKey ) + { + uint32 DstColorKey; + + ColorKey = SrcInfo->ColorKey; + DstColorKey = DstInfo->ColorKey; + + // with seperate alpha + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = SrcGetPixel(&SrcPtr); + if ( Pixel == ColorKey ) + { + AlphaPtr++; + DstPutPixel(&DstPtr,DstColorKey); + } + else + { + SrcDecomposePixel(Pixel,&R,&G,&B,&A); + A = *AlphaPtr++; + Pixel = DstComposePixel(R,G,B,A); + if ( Pixel == DstColorKey ) + Pixel ^= 1; + DstPutPixel(&DstPtr,Pixel); + } + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + + return GE_TRUE; + } + else if ( DstInfo->HasColorKey ) + { + ColorKey = DstInfo->ColorKey; + + // with seperate alpha + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + SrcGetColor(&SrcPtr,&R,&G,&B,&A); + A = *AlphaPtr++; + Pixel = DstComposePixel(R,G,B,A); + if ( Pixel == ColorKey ) + { + Pixel ^= 1; + } + DstPutPixel(&DstPtr,Pixel); + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + + return GE_TRUE; + } + else if ( SrcInfo->HasColorKey ) + { + // with seperate alpha + + ColorKey = SrcInfo->ColorKey; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = SrcGetPixel(&SrcPtr); + if ( Pixel == ColorKey ) + { + AlphaPtr++; + DstPutColor(&DstPtr,0,0,0,0); + } + else + { + SrcDecomposePixel(Pixel,&R,&G,&B,&A); + A = *AlphaPtr++; + DstPutColor(&DstPtr,R,G,B,A); + } + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + + return GE_TRUE; + } + else + { + // with seperate alpha + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + SrcGetColor(&SrcPtr,&R,&G,&B,&A); + A = *AlphaPtr++; + DstPutColor(&DstPtr,R,G,B,A); + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + + return GE_TRUE; + } + + } + else + { + uint32 DstColorKey; + + ColorKey = SrcInfo->ColorKey; + DstColorKey = DstInfo->ColorKey; + + assert(DstInfo->HasColorKey); + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + SrcGetColor(&SrcPtr,&R,&G,&B,&A); + A = *AlphaPtr++; + if ( A < 128 ) + { + DstPutPixel(&DstPtr,DstColorKey); + } + else + { + Pixel = DstComposePixel(R,G,B,255); + if ( Pixel == ColorKey ) + Pixel ^= 1; + DstPutPixel(&DstPtr,Pixel); + } + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + + return GE_TRUE; + } + } + + assert("should not get here" == NULL); +return GE_FALSE; +// end Seperate Alpha conversions +} + +/*}{*********************************************************************/ + +geBoolean BlitData_ToSeparateAlpha(void) +{ +geBitmap_Info AlphaInfo; +void * AlphaData; +uint8 *SrcPtr,*DstPtr,*AlphaPtr; +int x,y,R,G,B,A; +uint32 ColorKey,Pixel; +int AlphaXtra; + + /******* + ** + support the extra Alpha Bmp + the common case is (4444) -> (8bit + 8bit) + + we're pretty lazy about this; it's not optimized for speed + + ** + ******/ + + SrcPtr = (uint8 *)SrcData; + DstPtr = (uint8 *)DstData; + + if ( ! geBitmap_GetInfo(DstBmp->Alpha,&AlphaInfo,NULL) ) + return GE_FALSE; + if ( AlphaInfo.Format != GE_PIXELFORMAT_8BIT_GRAY ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : Alpha must be grayscale", NULL); + return GE_FALSE; + } + + AlphaData = geBitmap_GetBits(DstBmp->Alpha); + if ( ! AlphaData ) + return GE_FALSE; + + AlphaPtr = (uint8 *)AlphaData; + AlphaXtra = AlphaInfo.Stride - SizeX; + + if ( gePixelFormat_HasPalette(DstFormat) ) + { + // <> + geErrorLog_AddString(-1,"BlitData : doesn't support blit to palettized separates now", NULL); + // (alpha) -> pal + separate + // requires palettization !! + return GE_FALSE; + } + else + { + // this generic converter is pretty slow. + // fortunately genesis uses mostly the (Pal -> UnPal) conversion + // or the (Wavelet -> UnPal) conversion + + assert( SrcOps->AMask && !(DstOps->AMask) ); + + if ( SrcPelBytes == 0 || DstPelBytes == 0 ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : bad formats", NULL); + return GE_FALSE; + } + else if ( SrcInfo->HasColorKey && DstInfo->HasColorKey ) + { + uint32 DstColorKey; + + ColorKey = SrcInfo->ColorKey; + DstColorKey = DstInfo->ColorKey; + + // with seperate alpha + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = SrcGetPixel(&SrcPtr); + if ( Pixel == ColorKey ) + { + *AlphaPtr++ = 0; + DstPutPixel(&DstPtr,DstColorKey); + } + else + { + SrcDecomposePixel(Pixel,&R,&G,&B,&A); + Pixel = DstComposePixel(R,G,B,255); + if ( Pixel == DstColorKey ) Pixel ^= 1; + DstPutPixel(&DstPtr,Pixel); + *AlphaPtr++ = A; + } + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + } + else if ( DstInfo->HasColorKey ) + { + ColorKey = DstInfo->ColorKey; + + // with seperate alpha + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + SrcGetColor(&SrcPtr,&R,&G,&B,&A); + Pixel = DstComposePixel(R,G,B,255); + if ( Pixel == ColorKey ) Pixel ^= 1; + *AlphaPtr++ = A; + DstPutPixel(&DstPtr,Pixel); + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + } + else if ( SrcInfo->HasColorKey ) + { + // with seperate alpha + + ColorKey = SrcInfo->ColorKey; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = SrcGetPixel(&SrcPtr); + if ( Pixel == ColorKey ) + { + *AlphaPtr++ = 0; + DstPutColor(&DstPtr,0,0,0,0); + } + else + { + SrcDecomposePixel(Pixel,&R,&G,&B,&A); + DstPutColor(&DstPtr,R,G,B,255); + *AlphaPtr++ = A; + } + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + } + else + { + // with seperate alpha + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + SrcGetColor(&SrcPtr,&R,&G,&B,&A); + DstPutColor(&DstPtr,R,G,B,255); + *AlphaPtr++ = A; + } + SrcPtr += SrcXtraBytes; + DstPtr += DstXtraBytes; + AlphaPtr += AlphaXtra; + } + } + + assert( AlphaPtr == (((uint8 *)AlphaData) + AlphaInfo.Stride * SizeY) ); + assert( SrcPtr == (((uint8 *)SrcData) + SrcRowBytes * SizeY ) ); + assert( DstPtr == (((uint8 *)DstData) + DstRowBytes * SizeY ) ); + + return GE_TRUE; + } + + // end Seperate Alpha conversions + +return GE_FALSE; +} + +/*}{*********************************************************************/ + +geBoolean BlitData_SameFormat(void) +{ +char *SrcPtr,*DstPtr; +gePixelFormat Format; + + Format = SrcFormat; + SrcPtr = (char *)SrcData; + DstPtr = (char *)DstData; + + if ( (!DstInfo->HasColorKey) || + ( SrcInfo->HasColorKey && DstInfo->HasColorKey && SrcInfo->ColorKey == DstInfo->ColorKey ) ) + { + int RowBytes,SrcStepBytes,DstStepBytes,y; + // just a mem-copy, with strides + + RowBytes = SizeX * SrcPelBytes; + SrcStepBytes = SrcXtraBytes + RowBytes; + DstStepBytes = DstXtraBytes + RowBytes; + for(y=SizeY;y--;) + { + memcpy( DstPtr, SrcPtr, RowBytes ); + SrcPtr += SrcStepBytes; + DstPtr += DstStepBytes; + } + + return GE_TRUE; + } + else // same format, different color key + { + int x,y; + uint32 Pixel,DstColorKey; + + //this is common + + assert(DstInfo->HasColorKey); + DstColorKey = DstInfo->ColorKey; + + if ( SrcInfo->HasColorKey ) + { + uint32 SrcColorKey ; + + SrcColorKey = SrcInfo->ColorKey; + + assert(SrcColorKey != DstColorKey); + + // start : formats same, source & dest have different color key + + switch(SrcPelBytes) + { + default: + return GE_FALSE; + case 1: + { + uint8 *pSrc,*pDst; + pSrc = (uint8 *)SrcPtr; + pDst = (uint8 *)DstPtr; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = *pSrc++; + if ( Pixel == SrcColorKey ) + Pixel = DstColorKey; + else if ( Pixel == DstColorKey ) + Pixel = SrcColorKey; + *pDst++ = (uint8)Pixel; + } + pSrc += SrcXtra; + pDst += DstXtra; + } + return GE_TRUE; + } + case 2: + { + uint16 *pSrc,*pDst; + pSrc = (uint16 *)SrcPtr; + pDst = (uint16 *)DstPtr; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = *pSrc++; + if ( Pixel == SrcColorKey ) + Pixel = DstColorKey; + else if ( Pixel == DstColorKey ) + Pixel = SrcColorKey; + *pDst++ = (uint16)Pixel; + } + pSrc += SrcXtra; + pDst += DstXtra; + } + return GE_TRUE; + } + case 3: + { + uint8 *pSrc,*pDst; + pSrc = (uint8 *)SrcPtr; + pDst = (uint8 *)DstPtr; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = (pSrc[0]<<16) + (pSrc[1]<<8) + pSrc[2]; + if ( Pixel == SrcColorKey ) + Pixel = DstColorKey; + else if ( Pixel == DstColorKey ) + Pixel = SrcColorKey; + pDst[0] = (uint8)(Pixel>>16); + pDst[1] = (uint8)((Pixel>>8)&0xFF); + pDst[2] = (uint8)(Pixel&0xFF); + pSrc += 3; + pDst += 3; + } + pSrc += SrcXtraBytes; + pDst += DstXtraBytes; + } + return GE_TRUE; + } + case 4: + { + uint32 *pSrc,*pDst; + pSrc = (uint32 *)SrcPtr; + pDst = (uint32 *)DstPtr; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = *pSrc++; + if ( Pixel == SrcColorKey ) + Pixel = DstColorKey; + else if ( Pixel == DstColorKey ) + Pixel = SrcColorKey; + *pDst++ = Pixel; + } + pSrc += SrcXtra; + pDst += DstXtra; + } + return GE_TRUE; + } + } + + // end : formats same, source & dest have different color key + } + else + { + + // start : formats same, dest had color key, source doesn't + + switch(SrcPelBytes) + { + default: + return GE_FALSE; + case 1: + { + uint8 *pSrc,*pDst; + pSrc = (uint8 *)SrcPtr; + pDst = (uint8 *)DstPtr; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = *pSrc++; + if ( Pixel == DstColorKey ) + Pixel ^= 1; + *pDst++ = (uint8)Pixel; + } + pSrc += SrcXtra; + pDst += DstXtra; + } + return GE_TRUE; + } + case 2: + { + uint16 *pSrc,*pDst; + pSrc = (uint16 *)SrcPtr; + pDst = (uint16 *)DstPtr; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = *pSrc++; + if ( Pixel == DstColorKey ) + Pixel ^= 1; + *pDst++ = (uint16)Pixel; + } + pSrc += SrcXtra; + pDst += DstXtra; + } + return GE_TRUE; + } + case 3: + { + uint8 *pSrc,*pDst; + pSrc = (uint8 *)SrcPtr; + pDst = (uint8 *)DstPtr; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = (pSrc[0]<<16) + (pSrc[1]<<8) + pSrc[2]; + if ( Pixel == DstColorKey ) + Pixel ^= 1; + pDst[0] = (uint8)(Pixel>>16); + pDst[1] = (uint8)((Pixel>>8)&0xFF); + pDst[2] = (uint8)(Pixel&0xFF); + pSrc += 3; + pDst += 3; + } + pSrc += SrcXtraBytes; + pDst += DstXtraBytes; + } + return GE_TRUE; + } + case 4: + { + uint32 *pSrc,*pDst; + pSrc = (uint32 *)SrcPtr; + pDst = (uint32 *)DstPtr; + + for(y=SizeY;y--;) + { + for(x=SizeX;x--;) + { + Pixel = *pSrc++; + if ( Pixel == DstColorKey ) + Pixel ^= 1; + *pDst++ = Pixel; + } + pSrc += SrcXtra; + pDst += DstXtra; + } + return GE_TRUE; + } + } + + // end : formats same, dest had color key, source doesn't + } + + return GE_TRUE; + } +// must have returned by now +} +/*}{*********************************************************************/ + +geBoolean BlitData_DePalettize(void) +{ + // pal -> unpal : easy + if ( SrcFormat == GE_PIXELFORMAT_8BIT ) + { + uint8 * SrcPtr; + geBitmap_Palette * DstPal; + int x,y,pal; + const gePixelFormat_Operations *SrcOps,*DstOps; + + x = y = pal = 0; //touch 'em + + SrcOps = gePixelFormat_GetOperations(SrcPal->Format); + DstOps = gePixelFormat_GetOperations(DstFormat); + if ( ! SrcOps || ! DstOps ) + { + return GE_FALSE; + } + + // NO special cases + // just convert the Palette to the desired format, then do raw writes! + + DstPal = geBitmap_Palette_Create(DstFormat,256); + if ( ! DstPal ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : Palette_Create failed", NULL); + return GE_FALSE; + } + + // we do all alpha & colorkey by manipulating the DstPal lookup table ! + + //{} all these _geBitmap_Palette functions need failure checking + + if ( ! geBitmap_Palette_Copy(SrcPal,DstPal) ) + { + geErrorLog_AddString(-1,"Bitmap_BlitData : Palette_Copy failed", NULL); + geBitmap_Palette_Destroy(&DstPal); + return GE_FALSE; + } + + if ( SrcInfo->HasColorKey ) + { + if ( ! geBitmap_Palette_SetEntryColor(DstPal,SrcInfo->ColorKey,0,0,0,0) ) + { + geBitmap_Palette_Destroy(&DstPal); + return GE_FALSE; + } + } + + if ( DstInfo->HasColorKey ) // everything in genesis has colorkey! + { + int pal; + uint32 Pixel; + for(pal=0;palSize;pal++) + { + //{} all this GetEntry/SetEntry is awfully slow + geBitmap_Palette_GetEntry(DstPal,pal,&Pixel); + if ( Pixel == DstInfo->ColorKey ) + { + geBitmap_Palette_SetEntry(DstPal,pal,Pixel^1); + } + } + + } + + if ( SrcInfo->HasColorKey && DstInfo->HasColorKey ) + { + if ( ! geBitmap_Palette_SetEntry(DstPal,SrcInfo->ColorKey,DstInfo->ColorKey) ) + { + geBitmap_Palette_Destroy(&DstPal); + return GE_FALSE; + } + } + + if ( SrcOps->AMask && ! DstOps->AMask && DstInfo->HasColorKey ) + { + int pal,R,G,B,A; + uint32 Pixel; + + // if Src format has alpha & Dst format doesn't, turn it into color key + + for(pal=0;palSize;pal++) + { + geBitmap_Palette_GetEntry(SrcPal,pal,&Pixel); + if ( SrcInfo->HasColorKey && Pixel == SrcInfo->ColorKey ) + { + A = 0; + } + else + { + gePixelFormat_DecomposePixel(SrcPal->Format,Pixel,&R,&G,&B,&A); + } + if ( A < ALPHA_TO_TRANSPARENCY_THRESHOLD ) + geBitmap_Palette_SetEntry(DstPal,pal,DstInfo->ColorKey); + } + } + + SrcPtr = (uint8 *)SrcData; + + // Pal -> UnPal loops : very common & very fast + + switch( gePixelFormat_BytesPerPel(DstFormat) ) + { + default: + { + geBitmap_Palette_Destroy(&DstPal); + return GE_FALSE; + } + case 1: + { + uint8 *DstPtr,*PalData; + PalData = (uint8 *)DstPal->Data; + DstPtr = (uint8 *)DstData; + for(y=SizeY;y--;) + { + + #ifdef DONT_USE_ASM + + for(x=SizeX;x--;) + { + pal = *SrcPtr++; + *DstPtr++ = PalData[pal]; + } + + #else + + #pragma message("Bitmap_Blitdata :using assembly DePalettize code") + // {} is this minimal push safe in _fastcall ? aparently so! + + __asm + { + push ebp + + mov ecx,SizeX + mov esi,SrcPtr + mov edi,DstPtr + mov ebp,PalData + + xor eax,eax + xor edx,edx + + moredata1: + + mov al, BYTE PTR [esi] + mov dl, BYTE PTR [ebp + eax] + mov BYTE PTR [edi], dl + + inc esi + inc edi + dec ecx + + jnz moredata1 + + pop ebp + } + + SrcPtr += SizeX; + DstPtr += SizeX; + + #endif + + SrcPtr += SrcXtra; + DstPtr += DstXtra; + } + break; + } + case 2: + { + uint16 *DstPtr,*PalData; + + PalData = (uint16 *)DstPal->Data; + DstPtr = (uint16 *)DstData; + + #ifdef DO_TIMER + { + #pragma message("Blitdata : doing timer") + TIMER_VARS(WordCopy); + + timerFP = fopen("q:\\timer.log","at+"); + Timer_Start(); + TIMER_P(WordCopy); + #endif // DO_TIMER + + for(y=SizeY;y--;) + { + #ifdef DONT_USE_ASM + + for(x=SizeX;x--;) + { + pal = *SrcPtr++; + *DstPtr++ = PalData[pal]; + } + + #else + + #if 1 // { + if ( (SizeX&1) == 0 ) + { + assert( (((uint32)PalData)&3) == 0 ); + assert( (((uint32)DstPtr )&3) == 0 ); + + // pair two pixels so we can output in dwords + + __asm + { + //pusha + push ebp + + mov ecx,SizeX + mov esi,SrcPtr + mov edi,DstPtr + mov ebp,PalData + + xor eax,eax + + moredata2_z: + + //WordCopy : 0.000664 secs + // about 12 clocks per pixel (!?) + + // this is godly fast + + movzx eax, BYTE PTR [esi+0] + movzx eax, WORD PTR [ebp + eax*2] + + movzx edx, BYTE PTR [esi+1] + movzx edx, WORD PTR [ebp + edx*2] + shl edx,16 + + xor eax,edx + + mov DWORD PTR [edi], eax + + add esi,2 + add edi,4 + + sub ecx,2 + jnz moredata2_z + +#if 0 //{ + // the old bad way: + // 0.000710 secs + moredata2_z: + + //xor edx,edx //xor edx,0 ; sneaky trick? + + //mov al, BYTE PTR [esi] + movzx eax, BYTE PTR [esi] + inc esi + + movzx edx, WORD PTR [ebp + eax*2] + //mov dx, WORD PTR [ebp + eax*2] + + movzx eax, BYTE PTR [esi] + inc esi + + // make room fo a new dx + //shl edx,16 + //mov dx, WORD PTR [ebp + eax*2] // !! STALL !! ; movzx eax, [] instead? + // byte order is wrong; fix with rol; 1 clock + //rol edx,16 + + movzx eax, WORD PTR [ebp + eax*2] // can I do this? + shl eax,16 + xor edx,eax + + mov DWORD PTR [edi], edx + add edi,4 + + sub ecx,2 + jnz moredata2_z +#endif //} + + pop ebp + //popa + } + + } + else + #endif //} + { + + __asm + { + //pusha + push ebp + + mov ecx,SizeX + mov esi,SrcPtr + mov edi,DstPtr + mov ebp,PalData + + xor eax,eax + xor edx,edx + + moredata2: + + // about 14 clocks (!) + + //mov al, BYTE PTR [esi] + movzx eax, BYTE PTR [esi] + //movzx edx, WORD PTR [ebp + eax*2] + mov dx, WORD PTR [ebp + eax*2] + mov WORD PTR [edi], dx + + inc esi + add edi,2 + + dec ecx + jnz moredata2 + + pop ebp + //popa + } + } + + SrcPtr += SizeX; + DstPtr += SizeX; + + #endif + + SrcPtr += SrcXtra; + DstPtr += DstXtra; + } + + #ifdef DO_TIMER + TIMER_Q(WordCopy); + TIMER_COUNT(); + Timer_Stop(); + if ( timerFP ) + { + TIMER_REPORT(WordCopy); + } + } + #endif + + // C , Debug : + //WordCopy : 0.001243 : 99.4 % + // asm paired : mov al, + //WordCopy : 0.000858 : 99.1 % + // asm paired : movzx eax, + //WordCopy : 0.000798 : 98.9 % + // asm paired : with xor edx,0 & movzx edx, + //WordCopy : 0.000903 : 99.2 % + // asm paired : with xor edx,0 & mov dx, + //WordCopy : 0.000941 : 99.4 % + // asm : not paired + //WordCopy : 0.000765 : 98.8 % + // asm : paired, using xor edx,eax ! + //WordCopy : 0.000710 : 98.9 % + + break; + } + case 3: + { + uint8 *DstPtr,*PalData; + PalData = (uint8 *)DstPal->Data; + DstPtr = (uint8 *)DstData; + +// pushTSC(); + + for(y=SizeY;y--;) + { + + #ifdef DONT_USE_ASM + { + uint8 *PalPtr; + + for(x=SizeX;x--;) + { + pal = *SrcPtr++; + PalPtr = PalData + (3*pal); + *DstPtr++ = *PalPtr++; + *DstPtr++ = *PalPtr++; + *DstPtr++ = *PalPtr; + } + + } + #else + + __asm + { + push ebp + + mov ecx,SizeX + mov esi,SrcPtr + mov edi,DstPtr + mov ebp,PalData + + xor eax,eax + xor edx,edx + + moredata3: + + movzx eax, BYTE PTR [esi] + inc esi + + imul eax,3 + add eax,ebp + mov dl, BYTE PTR [eax] + mov BYTE PTR [edi], dl + inc edi + mov dl, BYTE PTR [eax + 1] + mov BYTE PTR [edi], dl + inc edi + mov dl, BYTE PTR [eax + 2] + mov BYTE PTR [edi], dl + inc edi + + dec ecx + jnz moredata3 + + pop ebp + } + + SrcPtr += SizeX; + DstPtr += SizeX*3; + + #endif + + SrcPtr += SrcXtra; + DstPtr += DstXtra; + } + +// showPopTSCper("depal 24bit",SizeX*SizeY,"pixel"); + + break; + } + case 4: + { + uint32 *DstPtr,*PalData; + PalData = (uint32 *)DstPal->Data; + DstPtr = (uint32 *)DstData; + for(y=SizeY;y--;) + { + #ifdef DONT_USE_ASM + + for(x=SizeX;x--;) + { + pal = *SrcPtr++; + *DstPtr++ = PalData[pal]; + } + + #else + + assert( (((uint32)PalData)&3) == 0); + assert( (((uint32)DstPtr)&3) == 0); + + __asm + { + push ebp + + mov ecx,SizeX + mov esi,SrcPtr + mov edi,DstPtr + mov ebp,PalData + + xor eax,eax + + moredata4: + + mov al, BYTE PTR [esi] + mov edx, DWORD PTR [ebp + eax*4] + mov DWORD PTR [edi], edx + + inc esi + add edi,4 + + dec ecx + jnz moredata4 + + pop ebp + } + + SrcPtr += SizeX; + DstPtr += SizeX; + + #endif + + SrcPtr += SrcXtra; + DstPtr += DstXtra; + } + break; + } + } + + geBitmap_Palette_Destroy(&DstPal); + + return GE_TRUE; + } +return GE_FALSE; +} + +/*}{*********************************************************************/ + +geBoolean BlitData_Palettize(void) +{ + // unpal -> pal : hard +return palettizePlane( SrcInfo,SrcData, + DstInfo,DstData, + SizeX,SizeY); +} + +/*}{*********************************************************************/ + diff --git a/G3D/Bitmap/bitmap_blitdata.h b/G3D/Bitmap/bitmap_blitdata.h new file mode 100644 index 0000000..3f70005 --- /dev/null +++ b/G3D/Bitmap/bitmap_blitdata.h @@ -0,0 +1,37 @@ +#ifndef BITMAP_BLITDATA_H +#define BITMAP_BLITDATA_H + +#ifndef BITMAP_PRIVATE_H +Intentional Error : bitmap_blidata only allowed in bitmap internals! +#endif +/****************************************************************************************/ +/* Bitmap_BlitData.h */ +/* */ +/* Author: Charles Bloom */ +/* Description: The Bitmap_BlitData function */ +/* Does all format conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + + +extern geBoolean geBitmap_BlitData( + const geBitmap_Info * SrcInfo,const void *SrcData,const geBitmap *SrcBmp, + geBitmap_Info * DstInfo, void *DstData,const geBitmap *DstBmp, + int SizeX, + int SizeY); + +#endif //BITMAP_BLITDATA_H diff --git a/G3D/Bitmap/bitmap_gamma.c b/G3D/Bitmap/bitmap_gamma.c new file mode 100644 index 0000000..fe17bdb --- /dev/null +++ b/G3D/Bitmap/bitmap_gamma.c @@ -0,0 +1,604 @@ +/****************************************************************************************/ +/* Bitmap_Gamma.c */ +/* */ +/* Author: Charles Bloom */ +/* Description: The Bitmap_Gamma_Apply function */ +/* Fast Gamma correction routines for various pixel formats */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + + +#include "bitmap._h" +#include "bitmap.__h" +#include "bitmap_gamma.h" +#include "pixelformat.h" +#include "errorlog.h" +#include +#include + +/*}{*******************************************************/ + +static uint32 Gamma_Lut[256]; +static uint32 Gamma_Lut_Inverse[256]; +static geFloat ComputedGamma_Lut = 0.0f; + +static uint16 Gamma_565_RGB[1<<16]; +static geFloat ComputedGamma_565_RGB = 0.0f; +static uint16 Gamma_4444_ARGB[1<<16]; +static geFloat ComputedGamma_4444_ARGB = 0.0f; + +/*}{*******************************************************/ + +void geBitmap_Gamma_Compute_Lut(double Gamma); +void geBitmap_GammaCorrect_Data_4444_ARGB(void * Bits,geBitmap_Info * pInfo); +void geBitmap_GammaCorrect_Data_565_RGB(void * Bits,geBitmap_Info * pInfo); +geBoolean geBitmap_GammaCorrect_Data(void * Bits,geBitmap_Info * pInfo, geBoolean Invert); + +/*}{*******************************************************/ + +geBoolean geBitmap_Gamma_Apply(geBitmap * Bitmap,geBoolean Invert) +{ +geBoolean Ret = GE_TRUE; +geFloat Gamma; + + assert(Bitmap); + + Gamma = Bitmap->DriverGamma; + if ( Gamma <= 0.1f ) // assume they meant 1.0f + return GE_TRUE; + + // Gamma only works on driver data + + // do-nothing gamma: + if ( fabs(Gamma - 1.0) < 0.1 ) + return GE_TRUE; + + if ( Bitmap->LockOwner ) + Bitmap = Bitmap->LockOwner; + if ( Bitmap->LockCount || Bitmap->DataOwner ) + return GE_FALSE; + + if ( ! Bitmap->DriverHandle ) // nothing to do + return GE_TRUE; + + if ( ComputedGamma_Lut != Gamma ) + { + geBitmap_Gamma_Compute_Lut(Gamma); + } + + if ( gePixelFormat_HasPalette(Bitmap->DriverInfo.Format) ) + { + geBitmap_Palette * Pal; + geBitmap_Info PalInfo; + void * Bits; + int Size; + gePixelFormat Format; + + // gamma correct the palette + + assert(Bitmap->DriverInfo.Palette); + Pal = Bitmap->DriverInfo.Palette; + + if ( ! geBitmap_Palette_Lock(Pal,&Bits,&Format,&Size) ) + return GE_FALSE; + + geBitmap_Palette_GetInfo(Pal,&PalInfo); + + if ( ! geBitmap_GammaCorrect_Data(Bits,&PalInfo,Invert) ) + Ret = GE_FALSE; + + geBitmap_Palette_UnLock(Pal); + } + else + { + geBitmap_Info Info; + void * Bits; + int mip,mipCount; + geBitmap *Locks[8],*Lock; + + assert( Bitmap->DriverInfo.MinimumMip == 0 ); + mipCount = Bitmap->DriverInfo.MaximumMip + 1; + + // old: work directly on the driver bits so that + // we don't get any DriverDataChanged or Modified[mip] flags ! + // new: just use UnLock_NoChange + + assert(Bitmap->Driver); + assert(Bitmap->DriverHandle); + + //if ( mipCount > 1 ) ; true, but pointless + // assert(mipCount == 4); + + if ( ! geBitmap_LockForWrite(Bitmap,Locks,0,mipCount-1) ) + { + geErrorLog_AddString(-1,"geBitmap_Gamma_Apply : LockforWrite failed", NULL); + return GE_FALSE; + } + + for(mip=0;mipFormat; + ops = gePixelFormat_GetOperations(Format); + if ( ! ops ) + return GE_FALSE; + + Decompose = ops->DecomposePixel; + Compose = ops->ComposePixel; + GetColor = ops->GetColor; + PutColor = ops->PutColor; + + assert( Compose && Decompose && GetColor && PutColor ); + + if ( ! Invert ) + { + if ( Format == GE_PIXELFORMAT_16BIT_565_RGB ) + { + geBitmap_GammaCorrect_Data_565_RGB(Bits,pInfo); + return GE_TRUE; + } + else if ( Format == GE_PIXELFORMAT_16BIT_4444_ARGB ) + { + geBitmap_GammaCorrect_Data_4444_ARGB(Bits,pInfo); + return GE_TRUE; + } + } + + if ( Invert ) + Lut = Gamma_Lut_Inverse; + else + Lut = Gamma_Lut; + + bpp = ops->BytesPerPel; + w = pInfo->Width; + h = pInfo->Height; + xtra = pInfo->Stride - w; + + if ( pInfo->HasColorKey ) + { + switch(bpp) + { + default: + case 0: + return GE_FALSE; + case 1: + { + uint8 *ptr,ck; + ck = (uint8)pInfo->ColorKey; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + if ( *ptr != ck ) + { + *ptr = (uint8)Lut[*ptr]; + if ( *ptr == ck ) + *ptr ^= 1; + } + ptr++; + } + ptr += xtra; + } + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride ) ); + break; + } + case 2: + { + uint16 *ptr,ck; + uint32 R,G,B,A,Pixel; + ck = (uint16)pInfo->ColorKey; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + if ( *ptr == ck ) + { + ptr++; + } + else + { + Decompose(*ptr,&R,&G,&B,&A); + R = Lut[R]; + G = Lut[G]; + B = Lut[B]; + Pixel = Compose(R,G,B,A); + if ( Pixel == ck ) + Pixel ^= 1; + *ptr++ = (uint16)Pixel; + } + } + ptr += xtra; + } + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 2 ) ); + break; + } + + case 3: + { + uint8 *ptr; + uint32 R,G,B,A,Pixel,ck; + ptr = Bits; + xtra *= 3; + ck = pInfo->ColorKey; + for(y=h;y--;) + { + for(x=w;x--;) + { + Pixel = (ptr[0]<<16) + (ptr[1]<<8) + ptr[2]; + if ( Pixel == ck ) + { + ptr+=3; + } + else + { + Decompose(Pixel,&R,&G,&B,&A); + R = Lut[R]; + G = Lut[G]; + B = Lut[B]; + Pixel = Compose(R,G,B,A); + if ( Pixel == ck ) + Pixel ^= 1; + *ptr++ = (uint8)((Pixel>>16)&0xFF); + *ptr++ = (uint8)((Pixel>>8)&0xFF); + *ptr++ = (uint8)((Pixel)&0xFF); + } + } + ptr += xtra; + } + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 3 ) ); + break; + } + + case 4: + { + uint32 *ptr,ck; + uint32 R,G,B,A,Pixel; + ck = pInfo->ColorKey; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + if ( *ptr == ck ) + { + ptr++; + } + else + { + Decompose(*ptr,&R,&G,&B,&A); + R = Lut[R]; + G = Lut[G]; + B = Lut[B]; + Pixel = Compose(R,G,B,A); + if ( Pixel == ck ) + Pixel ^= 1; + *ptr++ = Pixel; + } + } + ptr += xtra; + } + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 4 ) ); + break; + } + } + } + else + { + switch(bpp) + { + default: + case 0: + return GE_FALSE; + case 1: + { + uint8 *ptr; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + *ptr++ = (uint8)Lut[*ptr]; + } + ptr += xtra; + } + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride ) ); + break; + } + case 2: + { + uint16 *ptr; + uint32 R,G,B,A; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + Decompose(*ptr,&R,&G,&B,&A); + R = Lut[R]; + G = Lut[G]; + B = Lut[B]; + *ptr++ = (uint16)Compose(R,G,B,A); + } + ptr += xtra; + } + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 2 ) ); + break; + } + + case 3: + { + uint8 *ptr,*ptrz; + uint32 R,G,B,A; + ptr = Bits; + xtra *= 3; + for(y=h;y--;) + { + for(x=w;x--;) + { + ptrz = ptr; + GetColor(&ptrz,&R,&G,&B,&A); + R = Lut[R]; + G = Lut[G]; + B = Lut[B]; + PutColor(&ptr,R,G,B,A); + } + ptr += xtra; + } + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 3 ) ); + break; + } + + case 4: + { + uint32 *ptr; + uint32 R,G,B,A; + ptr = Bits; + for(y=h;y--;) + { + for(x=w;x--;) + { + Decompose(*ptr,&R,&G,&B,&A); + R = Lut[R]; + G = Lut[G]; + B = Lut[B]; + *ptr++ = Compose(R,G,B,A); + } + ptr += xtra; + } + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 4 ) ); + break; + } + } + } + + return GE_TRUE; +} + +/*}{*******************************************************/ + +void geBitmap_GammaCorrect_Data_565_RGB(void * Bits,geBitmap_Info * pInfo) +{ +uint32 w,h,xtra,x,y; +uint16 * ptr; + + if ( ComputedGamma_Lut != ComputedGamma_565_RGB ) + { + uint32 r,g,b,R,G,B; + uint32 ipel,opel; + + // compute 565 lookup table + for(r=0;r<32;r++) + { + R = Gamma_Lut[ (r<<3) ] >> 3; + for(g=0;g<64;g++) + { + G = Gamma_Lut[ (g<<2) ] >> 2; + for(b=0;b<32;b++) + { + B = Gamma_Lut[ (b<<3) ] >> 3; + ipel = (r<<11) + (g<<5) + b; + opel = (R<<11) + (G<<5) + B; + assert( opel < 65536 ); + Gamma_565_RGB[ipel] = (uint16)opel; + } + } + } + ComputedGamma_565_RGB = ComputedGamma_Lut; + } + + w = pInfo->Width; + h = pInfo->Height; + xtra = pInfo->Stride - w; + ptr = Bits; + + if ( pInfo->HasColorKey ) + { + uint16 ck; + ck = (uint16) pInfo->ColorKey; + + for(y=h;y--;) + { + for(x=w;x--;) + { + if ( *ptr != ck ) + { + *ptr = Gamma_565_RGB[ *ptr ]; + if ( *ptr == ck ) + *ptr ^= 1; + } + ptr ++; + } + ptr += xtra; + } + } + else + { + for(y=h;y--;) + { + for(x=w;x--;) + { + *ptr++ = Gamma_565_RGB[ *ptr ]; + } + ptr += xtra; + } + } + + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 2 ) ); + +} + +void geBitmap_GammaCorrect_Data_4444_ARGB(void * Bits,geBitmap_Info * pInfo) +{ +uint32 w,h,xtra,x,y; +uint16 * ptr; + + if ( ComputedGamma_Lut != ComputedGamma_4444_ARGB ) + { + uint32 r,g,b,a,R,G,B; + uint32 ipel,opel; + + // compute 4444 lookup table + for(r=0;r<16;r++) + { + R = Gamma_Lut[r<<4] >> 4; + for(g=0;g<16;g++) + { + G = Gamma_Lut[g<<4] >> 4; + for(b=0;b<16;b++) + { + B = Gamma_Lut[b<<4] >> 4; + for(a=0;a<16;a++) + { + ipel = (a<<12) + (r<<8) + (g<<4) + b; + opel = (a<<12) + (R<<8) + (G<<4) + B; + assert( opel < 65536 ); + Gamma_4444_ARGB[ipel] = (uint16)opel; + } + } + } + } + ComputedGamma_4444_ARGB = ComputedGamma_Lut; + } + + w = pInfo->Width; + h = pInfo->Height; + xtra = pInfo->Stride - w; + ptr = Bits; + + if ( pInfo->HasColorKey ) + { + uint16 ck; + ck = (uint16) pInfo->ColorKey; + + for(y=h;y--;) + { + for(x=w;x--;) + { + if ( *ptr != ck ) + { + *ptr = Gamma_4444_ARGB[ *ptr ]; + if ( *ptr == ck ) + *ptr ^= 1; + } + ptr ++; + } + ptr += xtra; + } + } + else + { + for(y=h;y--;) + { + for(x=w;x--;) + { + *ptr++ = Gamma_4444_ARGB[ *ptr ]; + } + ptr += xtra; + } + } + + assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 2 ) ); +} + +void geBitmap_Gamma_Compute_Lut(double Gamma) +{ +uint32 c=0,gc=0,lgc=0; + + for(c=0;c<256;c++) + { + gc = (uint32)( 255.0 * pow( c * (1.0/255.0) , 1.0 / Gamma ) + 0.4 ); + if ( gc > 255 ) gc = 255; + Gamma_Lut[c] = gc; + assert( lgc <= gc ); + for(lgc;lgc<=gc;lgc++) + Gamma_Lut_Inverse[lgc] = c; + lgc = gc; + } + for(gc;gc<256;gc++) + Gamma_Lut_Inverse[gc] = 255; + + Gamma_Lut[0] = 0; + Gamma_Lut_Inverse[0] = 0; + Gamma_Lut[255] = 255; + Gamma_Lut_Inverse[255] = 255; + + ComputedGamma_Lut = (geFloat)Gamma; +} + +/*}{*******************************************************/ diff --git a/G3D/Bitmap/bitmap_gamma.h b/G3D/Bitmap/bitmap_gamma.h new file mode 100644 index 0000000..493daad --- /dev/null +++ b/G3D/Bitmap/bitmap_gamma.h @@ -0,0 +1,35 @@ +#ifndef BITMAP_GAMMA_H +#define BITMAP_GAMMA_H + +#ifndef BITMAP_PRIVATE_H +Intentional Error : bitmap_blidata only allowed in bitmap internals! +#endif + +/****************************************************************************************/ +/* Bitmap_Gamma.h */ +/* */ +/* Author: Charles Bloom */ +/* Description: The Bitmap_Gamma_Apply function */ +/* Fast Gamma correction routines for various pixel formats */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + + +extern geBoolean geBitmap_Gamma_Apply(geBitmap * Bitmap,geBoolean Invert); + +#endif //BITMAP_GAMMA_H + diff --git a/G3D/Bitmap/pixelformat.c b/G3D/Bitmap/pixelformat.c new file mode 100644 index 0000000..4a8ec0d --- /dev/null +++ b/G3D/Bitmap/pixelformat.c @@ -0,0 +1,890 @@ +/****************************************************************************************/ +/* PixelFormat.c */ +/* */ +/* Author: Charles Bloom */ +/* Description: The abstract Pixel primitives */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +/*}{****************************************************************************************/ + +/*** + +this code only work on Intel-Endian CPU's + + { + uint32 x = (('A'<<24) + ('B'<<16) + ('C'<<8) + 'D'); + + assert( memcmp(&x,"DCBA",4) == 0 ); + } + +***/ + +#include +#include +#include "pixelformat.h" + +#define isinrange(x,lo,hi) ( (x)>=(lo) && (x)<=(hi) ) + +#define SHIFTL(val,shift) ( (shift) >= 0 ? ((val)<<(shift)) : ((val)>>(-(shift))) ) +#define SHIFTR(val,shift) ( (shift) >= 0 ? ((val)>>(shift)) : ((val)<<(-(shift))) ) + +// internal protos + +extern const gePixelFormat_Operations * gePixelFormat_Operations_Array; + +/*}{****************************************************************************************/ + +GENESISAPI uint32 GENESISCC gePixelFormat_ComposePixel(gePixelFormat Format,int R,int G,int B,int A) +{ +const gePixelFormat_Operations * ops; + ops = &gePixelFormat_Operations_Array[Format]; + assert(ops); + assert(ops->ComposePixel); + return ops->ComposePixel(R,G,B,A); +} + +GENESISAPI void GENESISCC gePixelFormat_DecomposePixel(gePixelFormat Format,uint32 Pixel,int *R,int *G,int *B,int *A) +{ +const gePixelFormat_Operations * ops; + ops = &gePixelFormat_Operations_Array[Format]; + assert(ops); + assert(ops->DecomposePixel); + ops->DecomposePixel(Pixel,R,G,B,A); +} + +GENESISAPI uint32 GENESISCC gePixelFormat_GetPixel(gePixelFormat Format,uint8 **ppData) +{ +const gePixelFormat_Operations * ops; + ops = &gePixelFormat_Operations_Array[Format]; + assert(ops); + assert(ops->GetPixel); + return ops->GetPixel(ppData); +} + +GENESISAPI void GENESISCC gePixelFormat_PutPixel(gePixelFormat Format,uint8 **ppData,uint32 Pixel) +{ +const gePixelFormat_Operations * ops; + ops = &gePixelFormat_Operations_Array[Format]; + assert(ops); + assert(ops->PutPixel); + ops->PutPixel(ppData,Pixel); +} + +GENESISAPI void GENESISCC gePixelFormat_GetColor(gePixelFormat Format,uint8 **ppData,int *R,int *G,int *B,int *A) +{ +const gePixelFormat_Operations * ops; + ops = &gePixelFormat_Operations_Array[Format]; + assert(ops); + assert(ops->GetColor); + ops->GetColor(ppData,R,G,B,A); +} +GENESISAPI void GENESISCC gePixelFormat_PutColor(gePixelFormat Format,uint8 **ppData,int R,int G,int B,int A) +{ +const gePixelFormat_Operations * ops; + ops = &gePixelFormat_Operations_Array[Format]; + assert(ops); + assert(ops->PutColor); + ops->PutColor(ppData,R,G,B,A); +} + +/*}{****************************************************************************************/ + +GENESISAPI uint32 GENESISCC gePixelFormat_ConvertPixel(gePixelFormat Format,uint32 Pixel,gePixelFormat ToFormat) +{ +int R,G,B,A; + gePixelFormat_DecomposePixel(Format,Pixel,&R,&G,&B,&A); +return gePixelFormat_ComposePixel(ToFormat,R,G,B,A); +} + +GENESISAPI const gePixelFormat_Operations * GENESISCC gePixelFormat_GetOperations( gePixelFormat Format ) +{ + if ( ! gePixelFormat_IsValid(Format) ) + return NULL; + else + return & gePixelFormat_Operations_Array[Format]; +} + +/*}{****************************************************************************************/ + +GENESISAPI unsigned int GENESISCC gePixelFormat_BytesPerPel( gePixelFormat Format ) +{ + assert( gePixelFormat_IsValid(Format) ); +return gePixelFormat_Operations_Array[Format].BytesPerPel; +} + +GENESISAPI geBoolean GENESISCC gePixelFormat_HasPalette( gePixelFormat Format ) +{ + assert( gePixelFormat_IsValid(Format) ); +return gePixelFormat_Operations_Array[Format].HasPalette; +} + +GENESISAPI geBoolean GENESISCC gePixelFormat_HasAlpha( gePixelFormat Format ) +{ + assert( gePixelFormat_IsValid(Format) ); +// if ( Format == GE_PIXELFORMAT_16BIT_1555_ARGB ) @@ +// return 0; +return gePixelFormat_Operations_Array[Format].AMask; +} + +static int NumBitsOn(uint32 val) +{ +uint32 count = 0; + while(val) + { + count += val&1; + val >>= 1; + } +return count; +} + +GENESISAPI geBoolean GENESISCC gePixelFormat_HasGoodAlpha( gePixelFormat Format ) +{ + assert( gePixelFormat_IsValid(Format) ); + + if ( NumBitsOn(gePixelFormat_Operations_Array[Format].AMask) > 1 ) + return GE_TRUE; + else + return GE_FALSE; +} + +GENESISAPI geBoolean GENESISCC gePixelFormat_IsRaw( gePixelFormat Format ) +{ + assert( gePixelFormat_IsValid(Format) ); + if ( gePixelFormat_Operations_Array[Format].ComposePixel ) + return GE_TRUE; + else + return GE_FALSE; +} + +GENESISAPI const char * GENESISCC gePixelFormat_Description( gePixelFormat Format ) +{ + assert( gePixelFormat_IsValid(Format) ); +return gePixelFormat_Operations_Array[Format].Description; +} + +GENESISAPI geBoolean GENESISCC gePixelFormat_IsValid(gePixelFormat Format) +{ + if ( (int)Format < 0 || (int)Format >= GE_PIXELFORMAT_COUNT ) + return GE_FALSE; + return GE_TRUE; +} + +/*}{****************************************************************************************/ + +/*}{****************************************************************************************/ + +uint32 GetPixel_8bit(uint8 **ppData) +{ +uint32 pel; + pel = *((uint8 *)(*ppData)); + (*ppData) += 1; +return pel; +} + +void PutPixel_8bit(uint8 **ppData,uint32 Pixel) +{ + *((uint8 *)(*ppData)) = (uint8)Pixel; + (*ppData) += 1; +} + +uint32 GetPixel_16bit(uint8 **ppData) +{ +uint32 pel; + pel = *((uint16 *)(*ppData)); + (*ppData) += 2; +return pel; +} + +void PutPixel_16bit(uint8 **ppData,uint32 Pixel) +{ + *((uint16 *)(*ppData)) = (uint16)Pixel; + (*ppData) += 2; +} + +uint32 GetPixel_24bit(uint8 **ppData) +{ +uint32 pel; + pel = (*ppData)[0] <<16; + pel += (*ppData)[1] << 8; + pel += (*ppData)[2]; + (*ppData) += 3; +return pel; +} + +void PutPixel_24bit(uint8 **ppData,uint32 Pixel) +{ + (*ppData)[0] = (uint8)(Pixel>>16); + (*ppData)[1] = (uint8)(Pixel>>8); + (*ppData)[2] = (uint8)(Pixel); + (*ppData) += 3; +} + +uint32 GetPixel_32bit(uint8 **ppData) +{ +uint32 pel; + pel = *((uint32 *)(*ppData)); + (*ppData) += 4; +return pel; +} + +void PutPixel_32bit(uint8 **ppData,uint32 Pixel) +{ + *((uint32 *)(*ppData)) = (uint32)Pixel; + (*ppData) += 4; +} + +/*}{****************************************************************************************/ + +//#define RGB_to_Gray(R,G,B) ((R + G + B)/3) +#define RGB_to_Gray(R,G,B) max(max(R,G),B) + +uint32 Compose_8bitGray (int R,int G,int B,int A) +{ +return (uint32)RGB_to_Gray(R,G,B); +} + +void Decompose_8bitGray (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *R = *G = *B = (int)Pixel; + *A = 255; +} + +void Get_8bitGray(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +int V; + V = **ppData; + (*ppData) += 1; + *R = *G = *B = V; *A = 255; +} + +void Put_8bitGray(uint8 **ppData,int R,int G,int B,int A) +{ +int V; + V = RGB_to_Gray(R,G,B); + **ppData = V; + (*ppData) += 1; +} + +/*}{****************************************************************************************/ + +uint32 Compose_nada (int R,int G,int B,int A) +{ +return 0; +} + +void Decompose_nada (uint32 Pixel,int *R,int *G,int *B,int *A) +{ +} + +void Get_nada(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +} + +void Put_nada(uint8 **ppData,int R,int G,int B,int A) +{ +} + +/*}{****************************************************************************************/ + +uint32 Compose_555rgb (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return ( ((R>>3)<<10) + ((G>>3)<<5) + ((B>>3)) ); +} + +void Decompose_555rgb (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *R = ((Pixel & 0x7C00)>>7) + 4; + *G = ((Pixel & 0x03E0)>>2) + 4; + *B = ((Pixel & 0x001F)<<3) + 4; + *A = 255; +} + +void Get_555rgb(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +uint16 Pixel; + Pixel = *((uint16 *)*ppData); + (*ppData) += 2; + *R = ((Pixel & 0x7C00)>>7) + 4; + *G = ((Pixel & 0x03E0)>>2) + 4; + *B = ((Pixel & 0x001F)<<3) + 4; + *A = 255; +} + +void Put_555rgb(uint8 **ppData,int R,int G,int B,int A) +{ +uint16 Pixel; + Pixel = ( ((R>>3)<<10) + ((G>>3)<<5) + ((B>>3)) ); + *((uint16 *)*ppData) = Pixel; + (*ppData) += 2; +} + +uint32 Compose_555bgr (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return ( ((B>>3)<<10) + ((G>>3)<<5) + ((R>>3)) ); +} + +void Decompose_555bgr (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *B = ((Pixel & 0x7C00)>>7) + 4; + *G = ((Pixel & 0x03E0)>>2) + 4; + *R = ((Pixel & 0x001F)<<3) + 4; + *A = 255; +} + +void Get_555bgr(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +uint16 Pixel; + Pixel = *((uint16 *)*ppData); + (*ppData) += 2; + *B = ((Pixel & 0x7C00)>>7) + 4; + *G = ((Pixel & 0x03E0)>>2) + 4; + *R = ((Pixel & 0x001F)<<3) + 4; + *A = 255; +} + +void Put_555bgr(uint8 **ppData,int R,int G,int B,int A) +{ +uint16 Pixel; + Pixel = ( ((B>>3)<<10) + ((G>>3)<<5) + ((R>>3)) ); + *((uint16 *)*ppData) = Pixel; + (*ppData) += 2; +} + + +/*}{****************************************************************************************/ + +uint32 Compose_565rgb (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return ( ((R>>3)<<11) + ((G>>2)<<5) + ((B>>3)) ); +} + +void Decompose_565rgb (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *R = ((Pixel & 0xF800)>>8) + 4; + *G = ((Pixel & 0x07E0)>>3) + 2; + *B = ((Pixel & 0x001F)<<3) + 4; + *A = 255; +} + +void Get_565rgb(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +uint16 Pixel; + Pixel = *((uint16 *)*ppData); + (*ppData) += 2; + *R = ((Pixel & 0xF800)>>8) + 4; + *G = ((Pixel & 0x07E0)>>3) + 2; + *B = ((Pixel & 0x001F)<<3) + 4; + *A = 255; +} + +void Put_565rgb(uint8 **ppData,int R,int G,int B,int A) +{ +uint16 Pixel; + Pixel = ( ((R>>3)<<11) + ((G>>2)<<5) + ((B>>3)) ); + *((uint16 *)*ppData) = Pixel; + (*ppData) += 2; +} + +uint32 Compose_565bgr (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return ( ((B>>3)<<11) + ((G>>2)<<5) + ((R>>3)) ); +} + +void Decompose_565bgr (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *B = ((Pixel & 0xF800)>>8) + 4; + *G = ((Pixel & 0x07E0)>>3) + 2; + *R = ((Pixel & 0x001F)<<3) + 4; + *A = 255; +} + +void Get_565bgr(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +uint16 Pixel; + Pixel = *((uint16 *)*ppData); + (*ppData) += 2; + *B = ((Pixel & 0xF800)>>8) + 4; + *G = ((Pixel & 0x07E0)>>3) + 2; + *R = ((Pixel & 0x001F)<<3) + 4; + *A = 255; +} + +void Put_565bgr(uint8 **ppData,int R,int G,int B,int A) +{ +uint16 Pixel; + Pixel = ( ((B>>3)<<11) + ((G>>2)<<5) + ((R>>3)) ); + *((uint16 *)*ppData) = Pixel; + (*ppData) += 2; +} + +/*}{****************************************************************************************/ + +uint32 Compose_4444 (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B && (A&0xFF) == A ); + return ((A>>4)<<12) + ((R>>4)<<8) + ((G>>4)<<4) + (B>>4); +} + +void Decompose_4444 (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *A = ((Pixel & 0xF000)>>8); + *R = ((Pixel & 0x0F00)>>4) + 8; + *G = ((Pixel & 0x00F0) ) + 8; + *B = ((Pixel & 0x000F)<<4) + 8; +} + +void Get_4444(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +uint16 Pixel; + Pixel = *((uint16 *)*ppData); + (*ppData) += 2; + *A = ((Pixel & 0xF000)>>8); + *R = ((Pixel & 0x0F00)>>4) + 8; + *G = ((Pixel & 0x00F0) ) + 8; + *B = ((Pixel & 0x000F)<<4) + 8; +} + +void Put_4444(uint8 **ppData,int R,int G,int B,int A) +{ +uint16 Pixel; + Pixel = ((A>>4)<<12) + ((R>>4)<<8) + ((G>>4)<<4) + (B>>4); + *((uint16 *)*ppData) = Pixel; + (*ppData) += 2; +} + +uint32 Compose_1555 (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B && (A&0xFF) == A ); + return ((A>>7)<<15) + ((R>>3)<<10) + ((G>>3)<<5) + ((B>>3)) ; +} + +void Decompose_1555 (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *R = ((Pixel & 0x7C00)>>7) + 4; + *G = ((Pixel & 0x03E0)>>2) + 4; + *B = ((Pixel & 0x001F)<<3) + 4; + *A = (Pixel>>15)<<7; +} + +void Get_1555(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +uint16 Pixel; + Pixel = *((uint16 *)*ppData); + (*ppData) += 2; + *R = ((Pixel & 0x7C00)>>7) + 4; + *G = ((Pixel & 0x03E0)>>2) + 4; + *B = ((Pixel & 0x001F)<<3) + 4; + *A = (Pixel>>15)<<7; +} + +void Put_1555(uint8 **ppData,int R,int G,int B,int A) +{ +uint16 Pixel; + Pixel = ((A>>7)<<15) + ( ((R>>3)<<10) + ((G>>3)<<5) + ((B>>3)) ); + *((uint16 *)*ppData) = Pixel; + (*ppData) += 2; +} + + +/*}{****************************************************************************************/ + +uint32 Compose_24rgb (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return (R<<16) + (G<<8) + B; +} + +void Decompose_24rgb (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *A = 255; + *R = (Pixel>>16)&0xFF; + *G = (Pixel>>8)&0xFF; + *B = (Pixel)&0xFF; +} + +void Get_24rgb(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +uint8 * ptr = *ppData; + *R = ptr[0]; + *G = ptr[1]; + *B = ptr[2]; + *A = 255; + *ppData = ptr + 3; +} + +void Put_24rgb(uint8 **ppData,int R,int G,int B,int A) +{ +uint8 * ptr = *ppData; + ptr[0] = R; + ptr[1] = G; + ptr[2] = B; + *ppData = ptr + 3; +} + +uint32 Compose_24bgr (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return (B<<16) + (G<<8) + R; +} + +void Decompose_24bgr (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *A = 255; + *B = (Pixel>>16)&0xFF; + *G = (Pixel>>8)&0xFF; + *R = (Pixel)&0xFF; +} + +void Get_24bgr(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +uint8 * ptr = *ppData; + *B = ptr[0]; + *G = ptr[1]; + *R = ptr[2]; + *A = 255; + *ppData = ptr + 3; +} + +void Put_24bgr(uint8 **ppData,int R,int G,int B,int A) +{ +uint8 * ptr = *ppData; + ptr[0] = B; + ptr[1] = G; + ptr[2] = R; + *ppData = ptr + 3; +} + +/*}{****************************************************************************************/ + +// RGBX in 32 bit is XBGR in bytes !!! + +uint32 Compose_32rgbx (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return (R<<24) + (G<<16) + (B<<8); +} + +void Decompose_32rgbx (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *A = 255; + *R = (Pixel>>24)&0xFF; + *G = (Pixel>>16)&0xFF; + *B = (Pixel>> 8)&0xFF; +} + +void Get_32rgbx(uint8 **ppData,int *R,int *G,int *B,int *A) +{ + (*ppData) += 1; + *B = **ppData; (*ppData) += 1; + *G = **ppData; (*ppData) += 1; + *R = **ppData; (*ppData) += 1; + *A = 255; +} + +void Put_32rgbx(uint8 **ppData,int R,int G,int B,int A) +{ + (*ppData) += 1; + **ppData = B; (*ppData) += 1; + **ppData = G; (*ppData) += 1; + **ppData = R; (*ppData) += 1; +} + +uint32 Compose_32xrgb (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return (R<<16) + (G<<8) + (B); +} + +void Decompose_32xrgb (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *A = 255; + *R = (Pixel>>16)&0xFF; + *G = (Pixel>> 8)&0xFF; + *B = (Pixel )&0xFF; +} + +void Get_32xrgb(uint8 **ppData,int *R,int *G,int *B,int *A) +{ + *B = **ppData; (*ppData) += 1; + *G = **ppData; (*ppData) += 1; + *R = **ppData; (*ppData) += 1; + (*ppData) += 1; + *A = 255; +} + +void Put_32xrgb(uint8 **ppData,int R,int G,int B,int A) +{ + **ppData = B; (*ppData) += 1; + **ppData = G; (*ppData) += 1; + **ppData = R; (*ppData) += 1; + (*ppData) += 1; +} + +uint32 Compose_32bgrx (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return (B<<24) + (G<<16) + (R<<8); +} + +void Decompose_32bgrx (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *A = 255; + *B = (Pixel>>24)&0xFF; + *G = (Pixel>>16)&0xFF; + *R = (Pixel>> 8)&0xFF; +} + +void Get_32bgrx(uint8 **ppData,int *R,int *G,int *B,int *A) +{ + (*ppData) += 1; + *R = **ppData; (*ppData) += 1; + *G = **ppData; (*ppData) += 1; + *B = **ppData; (*ppData) += 1; + *A = 255; +} + +void Put_32bgrx(uint8 **ppData,int R,int G,int B,int A) +{ + (*ppData) += 1; + **ppData = R; (*ppData) += 1; + **ppData = G; (*ppData) += 1; + **ppData = B; (*ppData) += 1; +} + +uint32 Compose_32xbgr (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B ); + return (B<<16) + (G<<8) + (R); +} + +void Decompose_32xbgr (uint32 Pixel,int *R,int *G,int *B,int *A) +{ + *A = 255; + *B = (Pixel>>16)&0xFF; + *G = (Pixel>> 8)&0xFF; + *R = (Pixel )&0xFF; +} + +void Get_32xbgr(uint8 **ppData,int *R,int *G,int *B,int *A) +{ + *R = **ppData; (*ppData) += 1; + *G = **ppData; (*ppData) += 1; + *B = **ppData; (*ppData) += 1; + (*ppData) += 1; + *A = 255; +} + +void Put_32xbgr(uint8 **ppData,int R,int G,int B,int A) +{ + **ppData = R; (*ppData) += 1; + **ppData = G; (*ppData) += 1; + **ppData = B; (*ppData) += 1; + (*ppData) += 1; +} + +/*}{****************************************************************************************/ + +uint32 Compose_32rgba (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B && (A&0xFF) == A ); + return (R<<24) + (G<<16) + (B<<8) + A; +} + +void Decompose_32rgba (uint32 pixel,int *R,int *G,int *B,int *A) +{ + *R = (pixel>>24)&0xFF; + *G = (pixel>>16)&0xFF; + *B = (pixel>> 8)&0xFF; + *A = (pixel )&0xFF; +} + +void Get_32rgba(uint8 **ppData,int *R,int *G,int *B,int *A) +{ + *A = **ppData; (*ppData) += 1; + *B = **ppData; (*ppData) += 1; + *G = **ppData; (*ppData) += 1; + *R = **ppData; (*ppData) += 1; +} + +void Put_32rgba(uint8 **ppData,int R,int G,int B,int A) +{ + **ppData = A; (*ppData) += 1; + **ppData = B; (*ppData) += 1; + **ppData = G; (*ppData) += 1; + **ppData = R; (*ppData) += 1; +} + +uint32 Compose_32argb (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B && (A&0xFF) == A ); + return (A<<24) + (R<<16) + (G<<8) + (B); +} + +void Decompose_32argb (uint32 pixel,int *R,int *G,int *B,int *A) +{ + *A = (pixel>>24)&0xFF; + *R = (pixel>>16)&0xFF; + *G = (pixel>> 8)&0xFF; + *B = (pixel )&0xFF; +} + +void Get_32argb(uint8 **ppData,int *R,int *G,int *B,int *A) +{ + *B = **ppData; (*ppData) += 1; + *G = **ppData; (*ppData) += 1; + *R = **ppData; (*ppData) += 1; + *A = **ppData; (*ppData) += 1; +} + +void Put_32argb(uint8 **ppData,int R,int G,int B,int A) +{ + **ppData = B; (*ppData) += 1; + **ppData = G; (*ppData) += 1; + **ppData = R; (*ppData) += 1; + **ppData = A; (*ppData) += 1; +} + +uint32 Compose_32bgra (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B && (A&0xFF) == A ); + return (B<<24) + (G<<16) + (R<<8) + A; +} + +void Decompose_32bgra (uint32 pixel,int *R,int *G,int *B,int *A) +{ + *B = (pixel>>24)&0xFF; + *G = (pixel>>16)&0xFF; + *R = (pixel>> 8)&0xFF; + *A = (pixel )&0xFF; +} + +void Get_32bgra(uint8 **ppData,int *R,int *G,int *B,int *A) +{ + *A = **ppData; (*ppData) += 1; + *R = **ppData; (*ppData) += 1; + *G = **ppData; (*ppData) += 1; + *B = **ppData; (*ppData) += 1; +} + +void Put_32bgra(uint8 **ppData,int R,int G,int B,int A) +{ + **ppData = A; (*ppData) += 1; + **ppData = R; (*ppData) += 1; + **ppData = G; (*ppData) += 1; + **ppData = B; (*ppData) += 1; +} + +uint32 Compose_32abgr (int R,int G,int B,int A) +{ + assert( (R&0xFF) == R && (G&0xFF) == G && (B&0xFF) == B && (A&0xFF) == A ); + return (A<<24) + (B<<16) + (G<<8) + (R); +} + +void Decompose_32abgr (uint32 pixel,int *R,int *G,int *B,int *A) +{ + *A = (pixel>>24)&0xFF; + *B = (pixel>>16)&0xFF; + *G = (pixel>> 8)&0xFF; + *R = (pixel )&0xFF; +} + +void Get_32abgr(uint8 **ppData,int *R,int *G,int *B,int *A) +{ + *R = **ppData; (*ppData) += 1; + *G = **ppData; (*ppData) += 1; + *B = **ppData; (*ppData) += 1; + *A = **ppData; (*ppData) += 1; +} + +void Put_32abgr(uint8 **ppData,int R,int G,int B,int A) +{ + **ppData = R; (*ppData) += 1; + **ppData = G; (*ppData) += 1; + **ppData = B; (*ppData) += 1; + **ppData = A; (*ppData) += 1; +} + + +/*}{********* the giant format-ops definition ****************/ + +static const gePixelFormat_Operations gePixelFormat_Operations_Array_Def[] = +{ + {0,0,0,0, 0,0,0,0, 0,0,0,0, 0 ,0, "invalid"}, + + {0,0,0,0, 0,0,0,0, 0,0,0,0, 1 ,1, "8bit pal", NULL,NULL, NULL,NULL, GetPixel_8bit, PutPixel_8bit}, + // Gray = (R>>2) + (G>>1) + (B>>2) + {0x3F,0x7F,0x3F,0, -2,-1,-2,0, 3,0,3,0xFF, 1 ,0, "8bit gray", Compose_8bitGray,Decompose_8bitGray, Get_8bitGray,Put_8bitGray, GetPixel_8bit, PutPixel_8bit}, + + // 16 bit (in uwords) + {0x7C00 ,0x03E0 ,0x001F ,0, 7, 2, -3, 0, 4,4,4,0xFF, 2,0, "555 RGB", Compose_555rgb,Decompose_555rgb, Get_555rgb,Put_555rgb, GetPixel_16bit,PutPixel_16bit}, + {0x001F ,0x03E0 ,0x7C00 ,0, -3, 2, 7, 0, 4,4,4,0xFF, 2,0, "555 BGR", Compose_555bgr,Decompose_555bgr, Get_555bgr,Put_555bgr, GetPixel_16bit,PutPixel_16bit}, + {0xF800 ,0x07E0 ,0x001F ,0, 8, 3, -3, 0, 4,2,4,0xFF, 2,0, "565 RGB", Compose_565rgb,Decompose_565rgb, Get_565rgb,Put_565rgb, GetPixel_16bit,PutPixel_16bit}, + {0x001F ,0x07E0 ,0xF800 ,0, -3, 3, 8, 0, 4,2,4,0xFF, 2,0, "565 BGR", Compose_565bgr,Decompose_565bgr, Get_565bgr,Put_565bgr, GetPixel_16bit,PutPixel_16bit}, + {0x0F00 ,0x00F0 ,0x000F ,0xF000, 4, 0, -4, 8, 8,8,8,8, 2,0, "4444 ARGB", Compose_4444,Decompose_4444, Get_4444,Put_4444, GetPixel_16bit,PutPixel_16bit}, + {0x7C00 ,0x03E0 ,0x001F ,0x8000, 7, 2, -3, 8, 4,4,4,0x40, 2,0, "1555 ARGB", Compose_1555,Decompose_1555, Get_1555,Put_1555, GetPixel_16bit,PutPixel_16bit}, + + // 24 bit (in bytes!) + {0x00FF0000,0x0000FF00,0x000000FF,0, 16, 8, 0,0, 0,0,0,0xFF, 3,0, "24bit RGB", Compose_24rgb,Decompose_24rgb, Get_24rgb,Put_24rgb, GetPixel_24bit,PutPixel_24bit}, + {0x000000FF,0x0000FF00,0x00FF0000,0, 0 , 8,16,0, 0,0,0,0xFF, 3,0, "24bit BGR", Compose_24bgr,Decompose_24bgr, Get_24bgr,Put_24bgr, GetPixel_24bit,PutPixel_24bit}, + {0x00FF0000,0x0000FF00,0x000000FF,0, 16, 8, 0,0, 0,0,0,0xFF, 3,0, "24bit YUV", Compose_24rgb,Decompose_24rgb, Get_24rgb,Put_24rgb, GetPixel_24bit,PutPixel_24bit}, + + // 32 bit (in ulongs) + {0xFF000000,0x00FF0000,0x0000FF00,0, 24,16, 8,0, 0,0,0,0xFF, 4,0, "32 bit RGBX", Compose_32rgbx,Decompose_32rgbx, Get_32rgbx,Put_32rgbx, GetPixel_32bit,PutPixel_32bit}, + {0x00FF0000,0x0000FF00,0x000000FF,0, 16, 8, 0,0, 0,0,0,0xFF, 4,0, "32 bit XRGB", Compose_32xrgb,Decompose_32xrgb, Get_32xrgb,Put_32xrgb, GetPixel_32bit,PutPixel_32bit}, + {0x0000FF00,0x00FF0000,0xFF000000,0, 8 ,16,24,0, 0,0,0,0xFF, 4,0, "32 bit BGRX", Compose_32bgrx,Decompose_32bgrx, Get_32bgrx,Put_32bgrx, GetPixel_32bit,PutPixel_32bit}, + {0x000000FF,0x0000FF00,0x00FF0000,0, 0 , 8,16,0, 0,0,0,0xFF, 4,0, "32 bit XBGR", Compose_32xbgr,Decompose_32xbgr, Get_32xbgr,Put_32xbgr, GetPixel_32bit,PutPixel_32bit}, + + {0xFF000000,0x00FF0000,0x0000FF00,0x000000FF, 24,16, 8, 0, 0,0,0,0,4,0,"32 bit RGBA", Compose_32rgba,Decompose_32rgba, Get_32rgba,Put_32rgba, GetPixel_32bit,PutPixel_32bit}, + {0x00FF0000,0x0000FF00,0x000000FF,0xFF000000, 16, 8, 0,24, 0,0,0,0,4,0,"32 bit ARGB", Compose_32argb,Decompose_32argb, Get_32argb,Put_32argb, GetPixel_32bit,PutPixel_32bit}, + {0x0000FF00,0x00FF0000,0xFF000000,0x000000FF, 8 ,16,24, 0, 0,0,0,0,4,0,"32 bit BGRA", Compose_32bgra,Decompose_32bgra, Get_32bgra,Put_32bgra, GetPixel_32bit,PutPixel_32bit}, + {0x000000FF,0x0000FF00,0x00FF0000,0xFF000000, 0 , 8,16,24, 0,0,0,0,4,0,"32 bit ABGR", Compose_32abgr,Decompose_32abgr, Get_32abgr,Put_32abgr, GetPixel_32bit,PutPixel_32bit}, + + {0,0,0,0, 0,0,0,0, 0,0,0,0, 0 ,0, "wavelet"}, + + {0,0,0,0, 0,0,0,0, 0,0,0,0, 0 ,0, "invalid"} +}; + +const gePixelFormat_Operations * gePixelFormat_Operations_Array = gePixelFormat_Operations_Array_Def; + + +/*}{************************************************/ + +/* +uint32 Compose_ (int R,int G,int B,int A) +{ +} + +void Decompose_ (uint32 Pixel,int *R,int *G,int *B,int *A) +{ +} + +void Get_(uint8 **ppData,int *R,int *G,int *B,int *A) +{ +} + +void Put_(uint8 **ppData,int R,int G,int B,int A) +{ +} +*/ + +/*}{****************************************************************************************/ + diff --git a/G3D/Bitmap/pixelformat.h b/G3D/Bitmap/pixelformat.h new file mode 100644 index 0000000..d8bf5ad --- /dev/null +++ b/G3D/Bitmap/pixelformat.h @@ -0,0 +1,152 @@ +#ifndef PIXELFORMAT_H +#define PIXELFORMAT_H + +/****************************************************************************************/ +/* PixelFormat.h */ +/* */ +/* Author: Charles Bloom */ +/* Description: The abstract Pixel primitives */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum // all supported formats (including shifts) +{ + GE_PIXELFORMAT_NO_DATA = 0, + GE_PIXELFORMAT_8BIT, // PAL + GE_PIXELFORMAT_8BIT_GRAY, // no palette (intensity from bit value) + GE_PIXELFORMAT_16BIT_555_RGB, + GE_PIXELFORMAT_16BIT_555_BGR, + GE_PIXELFORMAT_16BIT_565_RGB, // #5 + GE_PIXELFORMAT_16BIT_565_BGR, + GE_PIXELFORMAT_16BIT_4444_ARGB, // #7 + GE_PIXELFORMAT_16BIT_1555_ARGB, + GE_PIXELFORMAT_24BIT_RGB, // #9 + GE_PIXELFORMAT_24BIT_BGR, + GE_PIXELFORMAT_24BIT_YUV, // * see note below + GE_PIXELFORMAT_32BIT_RGBX, + GE_PIXELFORMAT_32BIT_XRGB, + GE_PIXELFORMAT_32BIT_BGRX, + GE_PIXELFORMAT_32BIT_XBGR, + GE_PIXELFORMAT_32BIT_RGBA, + GE_PIXELFORMAT_32BIT_ARGB, // #17 + GE_PIXELFORMAT_32BIT_BGRA, + GE_PIXELFORMAT_32BIT_ABGR, + + GE_PIXELFORMAT_WAVELET, // #20 , Wavelet Compression + + GE_PIXELFORMAT_COUNT +} gePixelFormat; + +/****** + +there's something wacked out about these format names : + + for 16 bit & 32 bit , the _RGB or _BGR refers to their order + *in the word or dword* ; since we're on intel, this means + the bytes in the data file have the *opposite* order !! + (for example the 32 bit _ARGB is actually B,G,R,A in raw bytes) + for 24 bit , the _RGB or _BGR refers to their order in the + actual bytes, so that windows bitmaps actually have + _RGB order in a dword !! + +* YUV : the pixelformat ops here are identical to those of 24bit_RGB ; + this is just a place-keeper to notify you that you should to a YUV_to_RGB conversion + +*********/ + +#define GE_PIXELFORMAT_8BIT_PAL GE_PIXELFORMAT_8BIT + +typedef uint32 (*gePixelFormat_Composer )(int R,int G,int B,int A); +typedef void (*gePixelFormat_Decomposer )(uint32 Pixel,int *R,int *G,int *B,int *A); + +typedef void (*gePixelFormat_ColorGetter)(uint8 **ppData,int *R,int *G,int *B,int *A); +typedef void (*gePixelFormat_ColorPutter)(uint8 **ppData,int R,int G,int B,int A); + +typedef uint32 (*gePixelFormat_PixelGetter)(uint8 **ppData); +typedef void (*gePixelFormat_PixelPutter)(uint8 **ppData,uint32 Pixel); + +typedef struct gePixelFormat_Operations +{ + uint32 RMask; + uint32 GMask; + uint32 BMask; + uint32 AMask; + + int RShift; + int GShift; + int BShift; + int AShift; + + int RAdd; + int GAdd; + int BAdd; + int AAdd; + + int BytesPerPel; + geBoolean HasPalette; + char * Description; + + gePixelFormat_Composer ComposePixel; + gePixelFormat_Decomposer DecomposePixel; + + gePixelFormat_ColorGetter GetColor; + gePixelFormat_ColorPutter PutColor; + + gePixelFormat_PixelGetter GetPixel; + gePixelFormat_PixelPutter PutPixel; +} gePixelFormat_Operations; + + // the Masks double as boolean "HaveAlpha" .. etc.. + +GENESISAPI const gePixelFormat_Operations * GENESISCC gePixelFormat_GetOperations( gePixelFormat Format ); + + // quick accessors to _GetOps +GENESISAPI geBoolean GENESISCC gePixelFormat_IsValid( gePixelFormat Format); +GENESISAPI unsigned int GENESISCC gePixelFormat_BytesPerPel( gePixelFormat Format ); +GENESISAPI geBoolean GENESISCC gePixelFormat_HasPalette( gePixelFormat Format ); +GENESISAPI geBoolean GENESISCC gePixelFormat_HasAlpha( gePixelFormat Format ); +GENESISAPI geBoolean GENESISCC gePixelFormat_HasGoodAlpha( gePixelFormat Format ); // more than 1 bit of alpha +GENESISAPI const char * GENESISCC gePixelFormat_Description( gePixelFormat Format ); +GENESISAPI geBoolean GENESISCC gePixelFormat_IsRaw( gePixelFormat Format ); + // 'Raw' means pixels can be made with the Compose operations + +GENESISAPI uint32 GENESISCC gePixelFormat_ComposePixel( gePixelFormat Format,int R,int G,int B,int A); +GENESISAPI void GENESISCC gePixelFormat_DecomposePixel( gePixelFormat Format,uint32 Pixel,int *R,int *G,int *B,int *A); + + // these four functions move ppData to the next pixel + +GENESISAPI void GENESISCC gePixelFormat_GetColor(gePixelFormat Format,uint8 **ppData,int *R,int *G,int *B,int *A); +GENESISAPI void GENESISCC gePixelFormat_PutColor(gePixelFormat Format,uint8 **ppData,int R,int G,int B,int A); + +GENESISAPI uint32 GENESISCC gePixelFormat_GetPixel(gePixelFormat Format,uint8 **ppData); +GENESISAPI void GENESISCC gePixelFormat_PutPixel(gePixelFormat Format,uint8 **ppData,uint32 Pixel); + +GENESISAPI uint32 GENESISCC gePixelFormat_ConvertPixel(gePixelFormat Format,uint32 Pixel,gePixelFormat ToFormat); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/CSNetMgr.c b/G3D/CSNetMgr.c new file mode 100644 index 0000000..92dbaab --- /dev/null +++ b/G3D/CSNetMgr.c @@ -0,0 +1,653 @@ +/****************************************************************************************/ +/* CSNetMgr.c */ +/* */ +/* Author: John Pollard/Brian Adelberg */ +/* Description: Client/Server network code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +//#define INITGUID +#include +#include + +#include "CSNetMgr.h" +#include "NetPlay.h" + +#include "BaseType.h" +#include "Ram.h" +#include "ErrorLog.h" + +#include + +#pragma message(" some assertions in here would be nice:") + +#define PACKET_HEADER_SIZE 1 + +#define NET_TIMEOUT 15000 // Givem 15 secs + + +// {33925241-05F8-11d0-8063-00A0C90AE891} +DEFINE_GUID(GENESIS_GUID, +//0x33925241, 0x5f8, 0x11d0, 0x80, 0x63, 0x0, 0xa0, 0xc9, 0xa, 0xe8, 0x91); +0x33925241, 0x0, 0x11d0, 0x80, 0x63, 0x0, 0xa0, 0xc9, 0xa, 0xe8, 0x91); + + +static geBoolean NetSession = GE_FALSE; +static geBoolean WeAreTheServer = GE_FALSE; +static DPID OurPlayerId; +static DPID ServerId; // The servers Id we are connected too + +#define BUFFER_SIZE 20000 +//#define BUFFER_SIZE 65535 + +static uint8 Packet[BUFFER_SIZE]; + +static geCSNetMgr_NetClient gClient; + +static BOOL geCSNetMgr_ProcessSystemMessage(geCSNetMgr *M,geCSNetMgr_NetID IdTo, LPDPMSG_GENERIC lpMsg, geCSNetMgr_NetMsgType *Type, geCSNetMgr_NetClient *Client); + +typedef struct geCSNetMgr +{ + // instance data goes here + geCSNetMgr *Valid; +} geCSNetMgr; + + +geBoolean geCSNetMgr_IsValid(geCSNetMgr *M) +{ + if ( M == NULL ) + return GE_FALSE; + + if ( M->Valid != M ) + return GE_FALSE; + + return GE_TRUE; +} + +GENESISAPI geCSNetMgr * GENESISCC geCSNetMgr_Create(void) +{ + geCSNetMgr *M; + + M = GE_RAM_ALLOCATE_STRUCT(geCSNetMgr); + + if ( M == NULL) + { + geErrorLog_Add(-1, NULL); //FIXME + return NULL; + } + + M->Valid = M; + + return M; +} + + +GENESISAPI void GENESISCC geCSNetMgr_Destroy(geCSNetMgr **ppM) +{ + assert( ppM != NULL ); + assert( geCSNetMgr_IsValid(*ppM)!=GE_FALSE ); + + (*ppM) -> Valid = 0; + geRam_Free(*ppM); + *ppM = NULL; +}; + +//================================================================================ +// geCSNetMgr_ReceiveFromServer +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveFromServer(geCSNetMgr *M, geCSNetMgr_NetMsgType *Type, int32 *Size, uint8 **Data) +{ + DPID IdTo; + DWORD BSize = BUFFER_SIZE; + HRESULT Result; + + *Size = 0; + *Data = NULL; + *Type = NET_MSG_NONE; + + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + + if (!NetSession) + { + geErrorLog_AddString(-1, "geCSNetMgr_ReceiveFromServer: No net session.\n", NULL); + return GE_FALSE; + } + +#if 1 + // Empty out all the system msg's first + if (!geCSNetMgr_ReceiveSystemMessage(M, OurPlayerId, Type, &gClient)) + { + geErrorLog_AddString(-1, "geCSNetMgr_ReceiveFromServer: geCSNetMgr_ReceiveSystemMessage failed.\n", NULL); + return GE_FALSE; + } + + if (*Type != NET_MSG_NONE) + { + *Size = sizeof( geCSNetMgr_NetClient ); + *Data = (uint8*)&gClient; + return( GE_TRUE ); + } +#endif + + // Find the server player + IdTo = 0; + + Result = NetPlayReceive(&ServerId, &IdTo, DPRECEIVE_FROMPLAYER, (uint8*)&Packet, &BSize); + + if (Result != DP_OK) + { + if (Result == DPERR_NOMESSAGES) + return GE_TRUE; // Not an error, there is simply no msg's. (*Size will == 0, so they will know) + + geErrorLog_AddString(-1, "geCSNetMgr_ReceiveFromServer: NetPlayReceive failed.\n", NULL); + return GE_FALSE; + } + + if (BSize > 0) + { + *Type = Packet[0]; + *Size = BSize - PACKET_HEADER_SIZE; + *Data = (uint8*)&Packet[1]; + } + + return GE_TRUE; +} + +//================================================================================ +// geCSNetMgr_ReceiveFromClient +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveFromClient(geCSNetMgr *M, geCSNetMgr_NetMsgType *Type, geCSNetMgr_NetID *IdClient, int32 *Size, uint8 **Data) +{ + DPID IdTo; + DWORD BSize = BUFFER_SIZE; + HRESULT Result; + + *Size = 0; + *Data = NULL; + *Type = NET_MSG_NONE; + + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + + if (!NetSession) + return GE_FALSE; + + // Empty out all the system msg's first + if (!geCSNetMgr_ReceiveSystemMessage(M, ServerId, Type, &gClient)) + return GE_FALSE; + + if (*Type != NET_MSG_NONE) + { + *Size = sizeof( geCSNetMgr_NetClient ); + *Data = (uint8*)&gClient; + return( GE_TRUE ); + } + + // Find the client player + IdTo = ServerId; + + Result = NetPlayReceive((DPID*)IdClient, &IdTo, DPRECEIVE_TOPLAYER, (uint8*)&Packet, &BSize); + + if (Result != DP_OK) + { + if (Result == DPERR_NOMESSAGES) + return GE_TRUE; // Not an error, there is simply no msg's. (*Size will == 0, so they will know) + + return GE_FALSE; + } + + if (BSize > 0) + { + *Type = Packet[0]; + *Size = BSize - PACKET_HEADER_SIZE; + *Data = (uint8*)&Packet[1]; + } + + return GE_TRUE; +} + +//================================================================================ +// geCSNetMgr_ReceiveSystemMessage +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveSystemMessage(geCSNetMgr *M, geCSNetMgr_NetID IdFor, geCSNetMgr_NetMsgType *Type, geCSNetMgr_NetClient *Client) +{ + DPID SystemId, IdTo; + DWORD BSize = BUFFER_SIZE; + HRESULT Result; + + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + + *Type = NET_MSG_NONE; + + if (!NetSession) + return GE_FALSE; + + // Find system messages + SystemId = DPID_SYSMSG; + IdTo = IdFor; + + Result = NetPlayReceive(&SystemId,&IdTo, DPRECEIVE_FROMPLAYER | DPRECEIVE_TOPLAYER, &Packet, &BSize); + + if (Result != DP_OK) + { + if (Result == DPERR_NOMESSAGES) + return GE_TRUE; // Not an error, there is simply no msg's. (*Size will == 0, so they will know) + + return GE_FALSE; + } + + if (BSize > 0) + { + if (!geCSNetMgr_ProcessSystemMessage(M, IdFor, (LPDPMSG_GENERIC)&Packet, Type, Client)) + return GE_FALSE; + } + + return GE_TRUE; +} + +//================================================================================ +// geCSNetMgr_ProcessSystemMessage +//================================================================================ +static geBoolean geCSNetMgr_ProcessSystemMessage(geCSNetMgr *M, geCSNetMgr_NetID IdTo, LPDPMSG_GENERIC lpMsg, geCSNetMgr_NetMsgType *Type, geCSNetMgr_NetClient *Client) +{ + DWORD dwSize; + + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + + *Type = NET_MSG_NONE; + + switch( lpMsg->dwType) + { + case DPSYS_CREATEPLAYERORGROUP: + { + if(WeAreTheServer && IdTo == ServerId) + { + LPDPMSG_CREATEPLAYERORGROUP lpAddMsg = (LPDPMSG_CREATEPLAYERORGROUP) lpMsg; + + // Don't broadcast the server being created... + if( lpAddMsg->dpId == ServerId ) + return GE_TRUE; + + // Name the player, and return it as a NET_MSG_CREATE_CLIENT message + *Type = NET_MSG_CREATE_CLIENT; + + strncpy(Client->Name, lpAddMsg->dpnName.lpszShortNameA, MAX_CLIENT_NAME); + Client->Id = lpAddMsg->dpId; + + // The client is waiting for this message, so send it now. + // It contains our ServerId, which the client needs... + dwSize = sizeof( ServerId ) + PACKET_HEADER_SIZE; + + assert(dwSize < BUFFER_SIZE); + + Packet[0] = NET_MSG_SERVER_ID; + memcpy( &Packet[1], &ServerId, sizeof( ServerId ) ); + + // Fire it off... + if (NetPlaySend( ServerId, Client->Id, DPSEND_GUARANTEED, (void*)&Packet, dwSize ) != DP_OK) + return GE_FALSE; + } + + break; + } + + case DPSYS_DESTROYPLAYERORGROUP: + { + if (WeAreTheServer && IdTo == ServerId) + { + LPDPMSG_DESTROYPLAYERORGROUP lpDestroyMsg = (LPDPMSG_DESTROYPLAYERORGROUP)lpMsg; + + Client->Id = lpDestroyMsg->dpId; + *Type = NET_MSG_DESTROY_CLIENT; + } + + break; + } + + case DPSYS_HOST: + { + WeAreTheServer = GE_TRUE; + *Type = NET_MSG_HOST; + break; + } + + case DPSYS_SESSIONLOST: + { + *Type = NET_MSG_SESSIONLOST; + break; + } + + } + + return GE_TRUE; +} + +//================================================================================ +// geCSNetMgr_ReceiveAllMessages +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveAllMessages(geCSNetMgr *M, geCSNetMgr_NetID *IdFrom, geCSNetMgr_NetID *IdTo, geCSNetMgr_NetMsgType *Type, int32 *Size, uint8 **Data) +{ + DWORD BSize = BUFFER_SIZE; + HRESULT Result; + + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + + *Size = 0; + *Data = NULL; + *Type = NET_MSG_NONE; + + if (!NetSession) + return GE_FALSE; + + *IdFrom = 0; + *IdTo = 0; + //*IdTo = ServerId; + + Result = NetPlayReceive((DPID*)IdFrom, (DPID*)IdTo, DPRECEIVE_ALL, &Packet, &BSize); + //Result = NetPlayReceive((DPID*)IdFrom, (DPID*)IdTo, DPRECEIVE_TOPLAYER, &Packet, &BSize); + + if (*IdTo != ServerId) + return GE_TRUE; + + if (Result != DP_OK) + { + if (Result == DPERR_NOMESSAGES) + return GE_TRUE; // Not an error, there is simply no msg's. (*Size will == 0, so they will know) + + return GE_FALSE; + } + + if (BSize > 0) + { + if (*IdFrom == DPID_SYSMSG) + { + // IdTo used to be DPID_ALLPLAYERS... + // Had to change to IdTo so it would work correctly. + if (!geCSNetMgr_ProcessSystemMessage(M, *IdTo, (LPDPMSG_GENERIC)&Packet, Type, &gClient)) + return GE_FALSE; + + if (*Type != NET_MSG_NONE) + { + *Size = sizeof( geCSNetMgr_NetClient ); + *Data = (uint8*)&gClient; + } + } + else + { + *Type = Packet[0]; + *Size = BSize - PACKET_HEADER_SIZE; + *Data = (uint8*)&Packet[1]; + return GE_TRUE; + } + } + + return GE_TRUE; +} + + +//================================================================================ +// geCSNetMgr_GetServerID +//================================================================================ +GENESISAPI geCSNetMgr_NetID GENESISCC geCSNetMgr_GetServerID(geCSNetMgr *M) +{ + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + return(ServerId); +} + +//================================================================================ +// geCSNetMgr_GetOurID +//================================================================================ +GENESISAPI geCSNetMgr_NetID GENESISCC geCSNetMgr_GetOurID(geCSNetMgr *M) +{ + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + return(OurPlayerId); +} + +//================================================================================ +// geCSNetMgr_GetAllPlayerID +//================================================================================ +GENESISAPI geCSNetMgr_NetID GENESISCC geCSNetMgr_GetAllPlayerID(geCSNetMgr *M) +{ + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + return(DPID_ALLPLAYERS); +} + +//================================================================================ +// geCSNetMgr_WeAreTheServer +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_WeAreTheServer(geCSNetMgr *M) +{ + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + return (WeAreTheServer); +} + +//================================================================================ +// geCSNetMgr_StartSession +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_StartSession(geCSNetMgr *M, const char *SessionName, const char *PlayerName) +{ + char Name2[MAX_CLIENT_NAME]; + + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + assert(PlayerName); + + NetSession = GE_FALSE; + WeAreTheServer = GE_FALSE; + + if (!InitNetPlay((LPGUID)&GENESIS_GUID)) + return GE_FALSE; + + if (!NetPlayCreateSession((char*)SessionName, 16)) + return GE_FALSE; + + if (!NetPlayCreatePlayer(&ServerId, "Server", NULL, NULL, 0, GE_TRUE)) + { + geErrorLog_AddString(-1, "geCSNetMgr_StartSession: NetPlayCreatePlayer failed for server player.\n", NULL); + return GE_FALSE; + } + + strncpy(Name2, PlayerName, MAX_CLIENT_NAME); + + if (!NetPlayCreatePlayer(&OurPlayerId, Name2, NULL, NULL, 0, GE_FALSE)) + { + geErrorLog_AddString(-1, "geCSNetMgr_StartSession: NetPlayCreatePlayer failed for client player.\n", NULL); + return GE_FALSE; + } + + WeAreTheServer = GE_TRUE; + NetSession = GE_TRUE; + + return GE_TRUE; +} + +//================================================================================ +// geCSNetMgr_FindSession +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_FindSession(geCSNetMgr *M, const char *IPAdress, geCSNetMgr_NetSession **SessionList, int32 *SessionNum) +{ + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + + NetSession = GE_FALSE; + WeAreTheServer = GE_FALSE; + + if (!InitNetPlay((LPGUID)&GENESIS_GUID)) + return GE_FALSE; + + if(!NetPlayEnumSession((char*)IPAdress, (SESSION_DESC**)SessionList, SessionNum) ) + return GE_FALSE; + + return( GE_TRUE ); +} + +//================================================================================ +// geCSNetMgr_JoinSession +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_JoinSession(geCSNetMgr *M, const char *Name, const geCSNetMgr_NetSession* Session) +{ + + uint32 StartTime; + DWORD BSize = BUFFER_SIZE; + + WeAreTheServer = GE_FALSE; + NetSession = GE_FALSE; + + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + + if (!NetPlayJoinSession( (SESSION_DESC*)Session) ) + { + geErrorLog_AddString(-1, "geCSNetMgr_JoinSession: NetPlayJoinSession failed.\n", NULL); + return GE_FALSE; + } + + if (!NetPlayCreatePlayer(&OurPlayerId, (char*)Name, NULL, NULL, 0, GE_FALSE)) + { + geErrorLog_AddString(-1, "geCSNetMgr_JoinSession: NetPlayCreatePlayer failed.\n", NULL); + return GE_FALSE; + } + + //Clients must wait until they get a Server Id. + // All other System messages. are ignored, until this happens. + // The only system message that should come before this is + // Create Client message. Since Clients don't need this message + // this should not be a problem. + + StartTime = timeGetTime(); +#if 1 + while( NET_TIMEOUT > (timeGetTime() - StartTime) ) + { + DPID IdFrom, IdTo; + HRESULT Result; + + BSize = BUFFER_SIZE; + + IdFrom = IdTo = 0; + + Result = NetPlayReceive(&IdFrom, &IdTo, DPRECEIVE_ALL, &Packet, &BSize); + + if (Result == DP_OK) + { + if (BSize > 0) + { + if( (IdFrom != DPID_SYSMSG) &&(Packet[0] == NET_MSG_SERVER_ID) ) + { + memcpy( &ServerId, &Packet[1], sizeof( ServerId ) ); + NetSession = GE_TRUE; + return GE_TRUE; + } + } + } + else if (Result != DPERR_NOMESSAGES) + return GE_FALSE; + } +#else + NetSession = GE_TRUE; + ServerId = DPID_SERVERPLAYER; + return( GE_TRUE); +#endif + + return( GE_FALSE); +} + +//================================================================================ +// geCSNetMgr_StopSession +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_StopSession(geCSNetMgr *M) +{ + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + + if (NetSession) + { + NetSession = GE_FALSE; + + if (WeAreTheServer) // If we are the server, then free the server player + { + if (!NetPlayDestroyPlayer(ServerId)) + return GE_FALSE; + } + + if (!NetPlayDestroyPlayer(OurPlayerId)) + return GE_FALSE; + + if (!DeInitNetPlay()) + { + //AFX_CPrintf("AFX_DestroyNetSession: There was a problem while De-Intializing NetPlay.\n"); + return GE_FALSE; + } + + } + + WeAreTheServer = GE_FALSE; + return GE_TRUE; +} + +//================================================================================ +// geCSNetMgr_SendToServer +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_SendToServer(geCSNetMgr *M, BOOL Guaranteed, uint8 *Data, int32 DataSize) +{ + DWORD dwFlags = 0; + + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + assert(DataSize+PACKET_HEADER_SIZE < BUFFER_SIZE); + + if (!NetSession) + return GE_FALSE; + + if( DataSize+PACKET_HEADER_SIZE >= BUFFER_SIZE ) + return GE_FALSE; + + if (Guaranteed) + dwFlags |= DPSEND_GUARANTEED; + + memcpy( &Packet[1], Data, DataSize ); + DataSize += PACKET_HEADER_SIZE; + Packet[0] = NET_MSG_USER; + + if (NetPlaySend(OurPlayerId, ServerId, dwFlags, (void*)&Packet, DataSize) != DP_OK) + return GE_FALSE; + + return GE_TRUE; +} + +//================================================================================ +// geCSNetMgr_SendToClient +//================================================================================ +GENESISAPI geBoolean GENESISCC geCSNetMgr_SendToClient(geCSNetMgr *M, geCSNetMgr_NetID To, BOOL Guaranteed, uint8 *Data, int32 DataSize) +{ + DWORD dwFlags = 0; + + assert( geCSNetMgr_IsValid(M)!=GE_FALSE ); + assert(DataSize+PACKET_HEADER_SIZE < BUFFER_SIZE); + + if (!NetSession) + return GE_FALSE; + + if( DataSize+PACKET_HEADER_SIZE >= BUFFER_SIZE ) + return GE_FALSE; + + if (Guaranteed) + dwFlags |= DPSEND_GUARANTEED; + + memcpy( &Packet[1], Data, DataSize ); + DataSize += PACKET_HEADER_SIZE; + Packet[0] = NET_MSG_USER; + + if (NetPlaySend(ServerId, To, dwFlags, (void*)&Packet, DataSize) != DP_OK) + return GE_FALSE; + + return GE_TRUE; +} diff --git a/G3D/CSNetMgr.h b/G3D/CSNetMgr.h new file mode 100644 index 0000000..d2801c6 --- /dev/null +++ b/G3D/CSNetMgr.h @@ -0,0 +1,97 @@ +/****************************************************************************************/ +/* CSNetMgr.h */ +/* */ +/* Author: John Pollard/Brian Adelberg */ +/* Description: Client/Server network code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_CSNETMGR_H +#define GE_CSNETMGR_H + +#include "BaseType.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +//================================================================================ +// Structure defines +//================================================================================ + +// GENESIS_PUBLIC_APIS + +typedef struct geCSNetMgr geCSNetMgr; + +typedef uint32 geCSNetMgr_NetID; +#define MAX_CLIENT_NAME 256 + +// Types for messages received from GE_ReceiveSystemMessage +typedef enum +{ + NET_MSG_NONE, // No msg + NET_MSG_USER, // User message + NET_MSG_CREATE_CLIENT, // A new client has joined in + NET_MSG_DESTROY_CLIENT, // An existing client has left + NET_MSG_HOST, // We are the server now + NET_MSG_SESSIONLOST, // Connection was lost + NET_MSG_SERVER_ID, // Internal, for hand shaking process +} geCSNetMgr_NetMsgType; + +typedef struct +{ + char Name[MAX_CLIENT_NAME]; + geCSNetMgr_NetID Id; +} geCSNetMgr_NetClient; + + +#ifdef _INC_WINDOWS + // Windows.h must be included previously for this api to be exposed. + + typedef struct geCSNetMgr_NetSession + { + char SessionName[200]; // Description of Service provider + GUID Guid; // Service Provider GUID + #pragma message("define a geGUID?.. wouldn't need a windows dependency here...") + } geCSNetMgr_NetSession; + +GENESISAPI geBoolean GENESISCC geCSNetMgr_FindSession(geCSNetMgr *M, const char *IPAdress, geCSNetMgr_NetSession **SessionList, int32 *SessionNum ); +GENESISAPI geBoolean GENESISCC geCSNetMgr_JoinSession(geCSNetMgr *M, const char *Name, const geCSNetMgr_NetSession* Session); +#endif + +GENESISAPI geCSNetMgr * GENESISCC geCSNetMgr_Create(void); +GENESISAPI void GENESISCC geCSNetMgr_Destroy(geCSNetMgr **ppM); +GENESISAPI geCSNetMgr_NetID GENESISCC geCSNetMgr_GetServerID(geCSNetMgr *M); +GENESISAPI geCSNetMgr_NetID GENESISCC geCSNetMgr_GetOurID(geCSNetMgr *M); +GENESISAPI geCSNetMgr_NetID GENESISCC geCSNetMgr_GetAllPlayerID(geCSNetMgr *M); +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveFromServer(geCSNetMgr *M, geCSNetMgr_NetMsgType *Type, int32 *Size, uint8 **Data); +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveFromClient(geCSNetMgr *M, geCSNetMgr_NetMsgType *Type, geCSNetMgr_NetID *IdClient, int32 *Size, uint8 **Data); +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveSystemMessage(geCSNetMgr *M, geCSNetMgr_NetID IdFor, geCSNetMgr_NetMsgType *Type, geCSNetMgr_NetClient *Client); +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveAllMessages(geCSNetMgr *M, geCSNetMgr_NetID *IdFrom, geCSNetMgr_NetID *IdTo, geCSNetMgr_NetMsgType *Type, int32 *Size, uint8 **Data); +GENESISAPI geBoolean GENESISCC geCSNetMgr_WeAreTheServer(geCSNetMgr *M); +GENESISAPI geBoolean GENESISCC geCSNetMgr_StartSession(geCSNetMgr *M, const char *SessionName, const char *PlayerName ); +GENESISAPI geBoolean GENESISCC geCSNetMgr_StopSession(geCSNetMgr *M); +GENESISAPI geBoolean GENESISCC geCSNetMgr_SendToServer(geCSNetMgr *M, geBoolean Guaranteed, uint8 *Data, int32 DataSize); +GENESISAPI geBoolean GENESISCC geCSNetMgr_SendToClient(geCSNetMgr *M, geCSNetMgr_NetID To, geBoolean Guaranteed, uint8 *Data, int32 DataSize); + + +// GENESIS_PRIVATE_APIS +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Camera.c b/G3D/Camera.c new file mode 100644 index 0000000..75d7a2e --- /dev/null +++ b/G3D/Camera.c @@ -0,0 +1,732 @@ +/****************************************************************************************/ +/* Camera.c */ +/* */ +/* Author: John Pollard/Charles Bloom */ +/* Description: Creation/Transformation/projection code for a camera */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include // memset + +#include "Camera.h" +#include "Ram.h" +#include "ErrorLog.h" + + +#include "DCommon.h" + +typedef struct geCamera +{ + geFloat Fov; // Field of View for Camera + geFloat Width; // Width of viewport + geFloat Height; // Height of viewport + geFloat Left,Right,Top,Bottom; // Clipping rect + + geFloat XRatio; // Screen Width / Fov + geFloat YRatio; // Screen Height / Fov + geFloat Scale; // X and Y Scale based on Fov + geFloat XCenter; // Screen Width/2 + geFloat YCenter; // Screen Height/2 + + geXForm3d XForm; // View transform + + geBoolean UseVisPov; // == GE_TRUE is vis uses VisXPov + geXForm3d VisXForm; + geXForm3d TransposeVisXForm; + geVec3d VisPov; // For vising info + + geXForm3d TransposeXForm; // Original model xform... + + geVec3d Pov; // Un rotated Pov in XForm + + geFloat SinViewAngleX; // sin(2.0 /Fov * Scale/XRatio); + geFloat CosViewAngleX; // cos(2.0 /Fov * Scale/XRatio); + geFloat SinViewAngleY; // sin(2.0 /Fov * Scale/YRatio); + geFloat CosViewAngleY; // cos(2.0 /Fov * Scale/YRatio); + + geFloat ZScale; // Projected Z Scalar value + + geBoolean ZFarEnable; // GE_TRUE == Use ZFar clipplane + geFloat ZFar; // ZFar clip plane distance + +} geCamera; + + +#ifndef max + #define max(AA,BB) ( ((AA)>(BB)) ?(AA):(BB) ) +#endif + +#define CAMERA_MINIMUM_PROJECTION_DISTANCE (0.010f) + +//===================================================================================== +// geCamera_Create +//===================================================================================== +GENESISAPI geCamera *GENESISCC geCamera_Create(geFloat Fov, const geRect *Rect) +{ + geCamera *Camera; + + assert( Rect != NULL ); + + Camera = GE_RAM_ALLOCATE_STRUCT(geCamera); + if (Camera == NULL) + { + geErrorLog_Add(-1, NULL); //FIXME + return NULL; + } + + memset(Camera, 0, sizeof(geCamera)); + + Camera->ZScale = 0.5f; + +#if 0 + Camera->ZFar = 1000.0f; + Camera->ZFarEnable = GE_TRUE; +#endif + + geCamera_SetAttributes(Camera,Fov,Rect); + return Camera; +} + +//===================================================================================== +// geCamera_Destroy +//===================================================================================== +GENESISAPI void GENESISCC geCamera_Destroy(geCamera **pCamera) +{ + assert( pCamera != NULL ); + assert( *pCamera != NULL ); + geRam_Free(*pCamera); + *pCamera = NULL; +} + +//===================================================================================== +// geCamera_SetZScale +//===================================================================================== +GENESISAPI void GENESISCC geCamera_SetZScale(geCamera *Camera, geFloat ZScale) +{ + assert(Camera); + Camera->ZScale = ZScale; +} + +//===================================================================================== +// geCamera_GetZScale +//===================================================================================== +GENESISAPI geFloat GENESISCC geCamera_GetZScale(const geCamera *Camera) +{ + assert(Camera); + return Camera->ZScale; +} + +//===================================================================================== +// geCamera_SetFarClipPlane +//===================================================================================== +GENESISAPI void GENESISCC geCamera_SetFarClipPlane(geCamera *Camera, geBoolean Enable, geFloat ZFar) +{ + assert(Camera); + + Camera->ZFarEnable = Enable; + Camera->ZFar = ZFar; +} + +//===================================================================================== +// geCamera_GetFarClipPlane +//===================================================================================== +GENESISAPI void GENESISCC geCamera_GetFarClipPlane(const geCamera *Camera, geBoolean *Enable, geFloat *ZFar) +{ + assert(Camera); + + *Enable = Camera->ZFarEnable; + *ZFar = Camera->ZFar; +} + +//===================================================================================== +// geCamera_GetClippingRect +//===================================================================================== +GENESISAPI void GENESISCC geCamera_GetClippingRect(const geCamera *Camera, geRect *Rect) +{ + assert( Camera != NULL ); + assert( Rect != NULL ); + Rect->Left = (int32)Camera->Left; + Rect->Right = (int32)Camera->Right; + Rect->Top = (int32)Camera->Top; + Rect->Bottom = (int32)Camera->Bottom; +} + +//===================================================================================== +// geCamera_GetWidthHeight +//===================================================================================== +void GENESISCC geCamera_GetWidthHeight(const geCamera *Camera,geFloat *Width,geFloat *Height) +{ + assert( Width != NULL ); + assert( Height != NULL ); + assert( Camera != NULL ); + + *Width = Camera->Width; + *Height = Camera->Height; +} + +//===================================================================================== +// geCamera_GetScale +//===================================================================================== +geFloat GENESISCC geCamera_GetScale(const geCamera *Camera) +{ + assert( Camera != NULL ); + + return Camera->Scale; +} + +//===================================================================================== +// geCamera_SetAttributes +//===================================================================================== +GENESISAPI void GENESISCC geCamera_SetAttributes(geCamera *Camera, geFloat Fov, const geRect *Rect) +{ + +#define TOO_SMALL (0.0001f) // width and Fov must be >= TOO_SMALL + + geFloat Width, Height; + geFloat OneOverFov; + + assert (Camera != NULL); + assert (Rect != NULL); + assert (! ((Fov < TOO_SMALL) && (Fov > -TOO_SMALL))); + + Width = (geFloat)(Rect->Right - Rect->Left)+1.0f; + Height = (geFloat)(Rect->Bottom - Rect->Top)+1.0f; + + assert( Width > 0.0f ); + assert( Height > 0.0f ); + + Camera->Width = Width; + Camera->Height = Height; + + Camera->Fov = Fov; + + if ((Camera->Fov < TOO_SMALL) && (Camera->Fov > -TOO_SMALL)) + Camera->Fov = TOO_SMALL; // Just in case + + OneOverFov = 1.0f/Fov; + + if (Width <=0.0f) + Width = TOO_SMALL; // Just in case + if (Height <=0.0f) + Height = TOO_SMALL; // Just in case + + Camera->XRatio = Width * OneOverFov; + Camera->YRatio = Height * OneOverFov; + + Camera->Scale = max(Camera->XRatio, Camera->YRatio); + //Camera->YScale = Camera->XScale; + + Camera->Left = (geFloat)Rect->Left; + Camera->Right = (geFloat)Rect->Right; + Camera->Top = (geFloat)Rect->Top; + Camera->Bottom = (geFloat)Rect->Bottom; + + Camera->XCenter = Camera->Left + ( Width * 0.5f ) - 0.5f; + Camera->YCenter = Camera->Top + ( Height * 0.5f ) - 0.5f; + + { + geFloat Numerator = 2.0f * OneOverFov * Camera->Scale; + double Angle; + Angle = atan(Numerator / Camera->XRatio); + Camera->CosViewAngleX = (geFloat)cos(Angle); + Camera->SinViewAngleX = (geFloat)sin(Angle); + + Angle = atan(Numerator / Camera->YRatio); + Camera->CosViewAngleY = (geFloat)cos(Angle); + Camera->SinViewAngleY = (geFloat)sin(Angle); + } +} + +//======================================================================================== +// geCamera_FillDriverInfo +// HACK!!!! +//======================================================================================== +void geCamera_FillDriverInfo(geCamera *Camera) +{ + // this is for the software driver to cache out some stuff + +#pragma message ("Camera.c : remove _FillDriverInfo, and thereby GlobalInfo!" ) +extern GInfo GlobalInfo; + assert(Camera); + + GlobalInfo.XScale =-Camera->Scale; + GlobalInfo.YScale =-Camera->Scale; + GlobalInfo.XScaleInv =1.0f / GlobalInfo.XScale; + GlobalInfo.YScaleInv =1.0f / GlobalInfo.YScale; + GlobalInfo.XCenter =Camera->XCenter; + GlobalInfo.YCenter =Camera->YCenter; + + // Temp hack + GlobalInfo.CXForm =Camera->XForm; + GlobalInfo.Pov =Camera->Pov; + GlobalInfo.ZScale =Camera->ZScale; + + geXForm3d_Rotate(&Camera->XForm, &GlobalInfo.Pov, &GlobalInfo.CPov); +} + +//======================================================================================== +// geCamera_ScreenPointToWorld +//======================================================================================== +GENESISAPI void GENESISCC geCamera_ScreenPointToWorld ( const geCamera *Camera, + int32 ScreenX, + int32 ScreenY, + geVec3d *Vector) +// Takes a screen X and Y pair, and a camera and generates a vector pointing +// in the direction from the camera position to the screen point. +{ + geVec3d In,Left,Up; + geVec3d ScaledIn,ScaledLeft,ScaledUp ; + geFloat XCenter ; + geFloat YCenter ; + geFloat Scale ; + const geXForm3d *pM; + + pM = &(Camera->TransposeXForm); + XCenter = Camera->XCenter ; + YCenter = Camera->YCenter ; + Scale = Camera->Scale ; + + geXForm3d_GetIn( pM, &In ) ; + geXForm3d_GetLeft( pM, &Left ) ; + geXForm3d_GetUp( pM, &Up ) ; + + geVec3d_Scale(&In, Scale, &ScaledIn); + geVec3d_Scale(&Left, XCenter - ((geFloat)ScreenX), &ScaledLeft ); + geVec3d_Scale(&Up, YCenter - ((geFloat)ScreenY), &ScaledUp ); + + geVec3d_Copy(&ScaledIn, Vector); + geVec3d_Add(Vector, &ScaledLeft, Vector ); + geVec3d_Add(Vector, &ScaledUp, Vector ); + geVec3d_Normalize(Vector); +} + + +//======================================================================================== +// geCamera_Project +//======================================================================================== +GENESISAPI void GENESISCC geCamera_Project(const geCamera *Camera, + const geVec3d *PointInCameraSpace, + geVec3d *ProjectedPoint) + // project from camera space to projected space + // projected space is left-handed. + // projection is onto x-y plane x is right, y is down, z is in +{ + geFloat ScaleOverZ; + geFloat Z; + assert( Camera != NULL ); + assert( PointInCameraSpace != NULL ); + assert( ProjectedPoint != NULL ); + + Z = -PointInCameraSpace->Z; + + if (Z < CAMERA_MINIMUM_PROJECTION_DISTANCE) + { + Z = CAMERA_MINIMUM_PROJECTION_DISTANCE; + } + + ScaleOverZ = Camera->Scale / Z; + + ProjectedPoint->Z = Z*Camera->ZScale; + + ProjectedPoint->X = ( PointInCameraSpace->X * ScaleOverZ ) + Camera->XCenter; + + ProjectedPoint->Y = Camera->YCenter - ( PointInCameraSpace->Y * ScaleOverZ ); +} + + +//======================================================================================== +// geCamera_ProjectZ +//======================================================================================== +GENESISAPI void GENESISCC geCamera_ProjectZ(const geCamera *Camera, + const geVec3d *PointInCameraSpace, + geVec3d *ProjectedPoint) + // project from camera space to projected space + // projected space is not right-handed. + // projection is onto x-y plane x is right, y is down, z is in + // projected point.z is set to 1/Z +{ + geFloat OneOverZ; + geFloat ScaleOverZ; + geFloat Z; + assert( Camera != NULL ); + assert( PointInCameraSpace != NULL ); + assert( ProjectedPoint != NULL ); + + Z = -PointInCameraSpace->Z; + + if (Z < CAMERA_MINIMUM_PROJECTION_DISTANCE) + { + Z = CAMERA_MINIMUM_PROJECTION_DISTANCE; + } + + OneOverZ = 1.0f / Z; + ScaleOverZ = Camera->Scale * (OneOverZ); + + ProjectedPoint->Z = OneOverZ; + + ProjectedPoint->X = ( PointInCameraSpace->X * ScaleOverZ ) + Camera->XCenter; + + ProjectedPoint->Y = Camera->YCenter - ( PointInCameraSpace->Y * ScaleOverZ ); +} + + + + +//======================================================================================== +// geCamera_ProjectAndClamp +//======================================================================================== +void GENESISCC geCamera_ProjectAndClamp(const geCamera *Camera, + const geVec3d *PointInCameraSpace, + geVec3d *ProjectedPoint) + // project from camera space to projected space + // projected space is not right-handed. + // projection is onto x-y plane x is right, y is down, z is in + // points outside the clipping rect are clamped to the clipping rect +{ + geFloat ScaleOverZ; + geFloat X,Y,Z; + assert( Camera != NULL ); + assert( PointInCameraSpace != NULL ); + assert( ProjectedPoint != NULL ); + + Z = -PointInCameraSpace->Z; + + if (Z < CAMERA_MINIMUM_PROJECTION_DISTANCE) + { + Z = CAMERA_MINIMUM_PROJECTION_DISTANCE; + } + + ScaleOverZ = Camera->Scale / Z; + + ProjectedPoint->Z = Z*Camera->ZScale; + + X = ( PointInCameraSpace->X * ScaleOverZ ) + Camera->XCenter; + + if (X < Camera->Left) + X = Camera->Left; + else if (X > Camera->Right) + X = Camera->Right; + + ProjectedPoint->X = X; + + Y = Camera->YCenter - ( PointInCameraSpace->Y * ScaleOverZ ); + + if (Y < Camera->Top) + Y = Camera->Top; + else if (Y > Camera->Bottom) + Y = Camera->Bottom; + + ProjectedPoint->Y = Y; +} + + +//======================================================================================== +// geCamera_GetViewAngleXSinCos +//======================================================================================== +void GENESISCC geCamera_GetViewAngleXSinCos( const geCamera *Camera, geFloat *SinAngle, geFloat *CosAngle ) +{ + assert( Camera != NULL ); + assert( SinAngle ); + assert( CosAngle ); + *SinAngle = Camera->SinViewAngleX; + *CosAngle = Camera->CosViewAngleX; +} + +//======================================================================================== +// geCamera_GetViewAngleYSinCos +//======================================================================================== +void GENESISCC geCamera_GetViewAngleYSinCos( const geCamera *Camera, geFloat *SinAngle, geFloat *CosAngle ) +{ + assert( Camera != NULL ); + assert( SinAngle ); + assert( CosAngle ); + *SinAngle = Camera->SinViewAngleY; + *CosAngle = Camera->CosViewAngleY; +} + +//============================================================================================ +// geCamera_Transform +//============================================================================================ +GENESISAPI void GENESISCC geCamera_Transform(const geCamera *Camera, + const geVec3d *WorldSpacePoint, + geVec3d *CameraSpacePoint) +{ + assert( Camera ); + assert( WorldSpacePoint ); + assert( CameraSpacePoint ); + + // Would be better if xform3d_transform was assembly, or a macro, or anything + geXForm3d_Transform(&(Camera->XForm),WorldSpacePoint,CameraSpacePoint); +} + + +//============================================================================================ +// geCamera_TransformArray +//============================================================================================ +GENESISAPI void GENESISCC geCamera_TransformArray(const geCamera *Camera, + const geVec3d *WorldSpacePointPtr, + geVec3d *CameraSpacePointPtr, int count) +{ + assert( Camera ); + assert( WorldSpacePointPtr ); + assert( CameraSpacePointPtr ); + // use transformarray!! + while(count--) + { + geXForm3d_Transform(&(Camera->XForm),WorldSpacePointPtr++,CameraSpacePointPtr++); + } +} + +//============================================================================================ +// geCamera_TransformAndProjectArray +//============================================================================================ +GENESISAPI void GENESISCC geCamera_TransformAndProjectArray(const geCamera *Camera, + const geVec3d *WorldSpacePointPtr, + geVec3d *ProjectedSpacePointPtr, + int count) +{ + assert( Camera ); + assert( WorldSpacePointPtr ); + assert( ProjectedSpacePointPtr ); + while(count--) + { + geCamera_TransformAndProject(Camera,WorldSpacePointPtr++,ProjectedSpacePointPtr++); + } +} + +//============================================================================================ +// geCamera_TransformAndProjectLArray +//============================================================================================ +GENESISAPI void GENESISCC geCamera_TransformAndProjectLArray(const geCamera *Camera, + const GE_LVertex *WorldSpacePointPtr, + GE_TLVertex *ProjectedSpacePointPtr, int count) +{ + assert( Camera ); + assert( WorldSpacePointPtr ); + assert( ProjectedSpacePointPtr ); + while(count--) + { + geCamera_TransformAndProjectL(Camera,WorldSpacePointPtr++,ProjectedSpacePointPtr++); + } +} + +//============================================================================================ +// geCamera_TransformAndProject +//============================================================================================ +GENESISAPI void GENESISCC geCamera_TransformAndProject(const geCamera *Camera, + const geVec3d *Point, + geVec3d *ProjectedPoint) + // project from *WORLD* space to projected space + // projected space is not right-handed. + // projection is onto x-y plane x is right, y is down, z is in +{ + geFloat Z; + + assert( Camera ); + assert( Point ); + assert( ProjectedPoint ); + + geXForm3d_Transform(&(Camera->XForm),Point,ProjectedPoint); + + Z = - ProjectedPoint->Z; + + Z = max(Z,CAMERA_MINIMUM_PROJECTION_DISTANCE); + + ProjectedPoint->Z = Z*Camera->ZScale; + + Z = Camera->Scale / Z; + + ProjectedPoint->X = ( ProjectedPoint->X * Z ) + Camera->XCenter; + ProjectedPoint->Y = - ( ProjectedPoint->Y * Z ) + Camera->YCenter; +} + + +//============================================================================================ +// geCamera_TransformAndProjectL +//============================================================================================ +GENESISAPI void GENESISCC geCamera_TransformAndProjectL(const geCamera *Camera, + const GE_LVertex *Point, + GE_TLVertex *ProjectedPoint) + // project from *WORLD* space to projected space + // projected space is not right-handed. + // projection is onto x-y plane x is right, y is down, z is in +{ + geFloat ScaleOverZ; + geFloat Z; + + assert( Camera ); + assert( Point ); + assert( ProjectedPoint ); + + geXForm3d_Transform(&(Camera->XForm),(geVec3d *)Point,(geVec3d *)ProjectedPoint); + + Z = - ProjectedPoint->z; + + Z = max(Z,CAMERA_MINIMUM_PROJECTION_DISTANCE); + + ScaleOverZ = Camera->Scale / Z; + + ProjectedPoint->z = Z*Camera->ZScale; + ProjectedPoint->x = ( ProjectedPoint->x * ScaleOverZ ) + Camera->XCenter; + ProjectedPoint->y = - ( ProjectedPoint->y * ScaleOverZ ) + Camera->YCenter; + + ProjectedPoint->u = Point->u; + ProjectedPoint->v = Point->v; + ProjectedPoint->r = Point->r; + ProjectedPoint->g = Point->g; + ProjectedPoint->b = Point->b; + ProjectedPoint->a = Point->a; +} + +//======================================================================================== +// geCamera_SetWorldSpaceXForm +//======================================================================================== +GENESISAPI geBoolean GENESISCC geCamera_SetWorldSpaceXForm(geCamera *Camera, const geXForm3d *XForm) +{ + assert(Camera != NULL); + assert(XForm != NULL); + + Camera->TransposeXForm = *XForm; // Make a copy of the model XForm + + // Convert the model transform into a camera xform... + //geCamera_ConvertModelToCamera(XForm, &Camera->XForm); + geXForm3d_GetTranspose(XForm, &Camera->XForm); + + Camera->Pov = XForm->Translation; + + return GE_TRUE; +} + +//======================================================================================== +// geCamera_SetWorldSpaceVisXForm +//======================================================================================== +GENESISAPI geBoolean GENESISCC geCamera_SetWorldSpaceVisXForm(geCamera *Camera, const geXForm3d *XForm) +{ + assert(Camera != NULL); + + if (XForm) + { + Camera->TransposeVisXForm = *XForm; // Make a copy of the original XForm + Camera->VisPov = XForm->Translation; + geXForm3d_GetTranspose(XForm, &Camera->VisXForm); + + Camera->UseVisPov = GE_TRUE; + } + else + { + Camera->UseVisPov = GE_FALSE; + } + + return GE_TRUE; +} + +//============================================================================================ +// geCamera_GetWorldSpaceXForm +// Gets the xform originally set by the user +//============================================================================================ +GENESISAPI const geXForm3d * GENESISCC geCamera_GetWorldSpaceXForm( const geCamera *Camera) +{ + assert(Camera ); + return &(Camera->TransposeXForm); +} + +//======================================================================================== +// geCamera_GetCameraSpaceXForm +//======================================================================================== +GENESISAPI const geXForm3d * GENESISCC geCamera_GetCameraSpaceXForm( const geCamera *Camera) +{ + assert(Camera != NULL); + return &(Camera->XForm); +} + +//============================================================================================ +// geCamera_GetCameraSpaceVisXForm +//============================================================================================ +GENESISAPI const geXForm3d * GENESISCC geCamera_GetCameraSpaceVisXForm( const geCamera *Camera) +{ + assert(Camera != NULL); + + if (Camera->UseVisPov) + return &(Camera->VisXForm); + else + return &(Camera->XForm); +} + +//============================================================================================ +// geCamera_GetWorldSpaceVisXForm +//============================================================================================ +GENESISAPI const geXForm3d * GENESISCC geCamera_GetWorldSpaceVisXForm( const geCamera *Camera) +{ + assert(Camera != NULL); + + if (Camera->UseVisPov) + return &(Camera->TransposeVisXForm); + else + return &(Camera->TransposeXForm); +} + +//===================================================================================== +// geCamera_GetPov +//===================================================================================== +const geVec3d *GENESISCC geCamera_GetPov(const geCamera *Camera) +{ + assert( Camera != NULL ); + return &(Camera->Pov); +} + +//===================================================================================== +// geCamera_GetVisPov +//===================================================================================== +const geVec3d *GENESISCC geCamera_GetVisPov(const geCamera *Camera) +{ + assert( Camera != NULL ); + + if (Camera->UseVisPov) + return &(Camera->VisPov); + else + return &(Camera->Pov); +} + +//======================================================================================== +// geCamera_ConvertWorldSpaceToCameraSpace +// Converts a worldspace Xform to a cameraspace xform +//======================================================================================== +GENESISAPI geBoolean GENESISCC geCamera_ConvertWorldSpaceToCameraSpace(const geXForm3d *WXForm, geXForm3d *CXForm) +{ + // The rotation portion is just the transpose of the model xform + CXForm->AX = WXForm->AX; + CXForm->AY = WXForm->BX; + CXForm->AZ = WXForm->CX; + + CXForm->BX = WXForm->AY; + CXForm->BY = WXForm->BY; + CXForm->BZ = WXForm->CY; + + CXForm->CX = WXForm->AZ; + CXForm->CY = WXForm->BZ; + CXForm->CZ = WXForm->CZ; + + CXForm->Translation = WXForm->Translation; + + geVec3d_Inverse(&CXForm->Translation); + + // Rotate the translation in the new camera matrix + geXForm3d_Rotate(CXForm, &CXForm->Translation, &CXForm->Translation); + + return GE_TRUE; +} diff --git a/G3D/Camera.h b/G3D/Camera.h new file mode 100644 index 0000000..2c9e10f --- /dev/null +++ b/G3D/Camera.h @@ -0,0 +1,102 @@ +/****************************************************************************************/ +/* Camera.h */ +/* */ +/* Author: John Pollard/Charles Bloom */ +/* Description: Creation/Transformation/projection code for a camera */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_CAMERA_H +#define GE_CAMERA_H + +#include "BaseType.h" +#include "Vec3d.h" +#include "XForm3d.h" +#include "GETypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//================================================================================ +// Structure defines +//================================================================================ +typedef struct geCamera geCamera; + + +//================================================================================ +// Function ProtoTypes +//================================================================================ +GENESISAPI geCamera *GENESISCC geCamera_Create(geFloat Fov, const geRect *Rect); +GENESISAPI void GENESISCC geCamera_Destroy(geCamera **pCamera); +GENESISAPI void GENESISCC geCamera_SetZScale(geCamera *Camera, geFloat ZScale); +GENESISAPI geFloat GENESISCC geCamera_GetZScale(const geCamera *Camera); +GENESISAPI void GENESISCC geCamera_SetFarClipPlane(geCamera *Camera, geBoolean Enable, geFloat ZFar); +GENESISAPI void GENESISCC geCamera_GetFarClipPlane(const geCamera *Camera, geBoolean *Enable, geFloat *ZFar); +GENESISAPI void GENESISCC geCamera_GetClippingRect(const geCamera *Camera, geRect *Rect); +void GENESISCC geCamera_GetWidthHeight(const geCamera *Camera,geFloat *Width,geFloat *Height); +geFloat GENESISCC geCamera_GetScale(const geCamera *Camera); +GENESISAPI void GENESISCC geCamera_SetAttributes(geCamera *Camera, geFloat Fov, const geRect *Rect); +void geCamera_FillDriverInfo(geCamera *Camera); +GENESISAPI void GENESISCC geCamera_ScreenPointToWorld ( const geCamera *Camera, + int32 ScreenX, + int32 ScreenY, + geVec3d *Vector); +GENESISAPI void GENESISCC geCamera_Project(const geCamera *Camera, + const geVec3d *PointInCameraSpace, + geVec3d *ProjectedPoint); +GENESISAPI void GENESISCC geCamera_ProjectZ(const geCamera *Camera, + const geVec3d *PointInCameraSpace, + geVec3d *ProjectedPoint); +void GENESISCC geCamera_ProjectAndClamp(const geCamera *Camera, + const geVec3d *PointInCameraSpace, + geVec3d *ProjectedPoint); +void GENESISCC geCamera_GetViewAngleXSinCos( const geCamera *Camera, geFloat *SinAngle, geFloat *CosAngle ); +void GENESISCC geCamera_GetViewAngleYSinCos( const geCamera *Camera, geFloat *SinAngle, geFloat *CosAngle ); +GENESISAPI void GENESISCC geCamera_Transform(const geCamera *Camera, + const geVec3d *WorldSpacePoint, + geVec3d *CameraSpacePoint); +GENESISAPI void GENESISCC geCamera_TransformArray(const geCamera *Camera, + const geVec3d *WorldSpacePointPtr, + geVec3d *CameraSpacePointPtr, int count); +GENESISAPI void GENESISCC geCamera_TransformAndProjectArray(const geCamera *Camera, + const geVec3d *WorldSpacePointPtr, + geVec3d *ProjectedSpacePointPtr, int count); +GENESISAPI void GENESISCC geCamera_TransformAndProjectLArray(const geCamera *Camera, + const GE_LVertex *WorldSpacePointPtr, + GE_TLVertex *ProjectedSpacePointPtr, int count); +GENESISAPI void GENESISCC geCamera_TransformAndProject(const geCamera *Camera, + const geVec3d *Point, + geVec3d *ProjectedPoint); +GENESISAPI void GENESISCC geCamera_TransformAndProjectL(const geCamera *Camera, + const GE_LVertex *Point, + GE_TLVertex *ProjectedPoint); + +GENESISAPI geBoolean GENESISCC geCamera_SetWorldSpaceXForm(geCamera *Camera, const geXForm3d *XForm); +GENESISAPI geBoolean GENESISCC geCamera_SetWorldSpaceVisXForm(geCamera *Camera, const geXForm3d *XForm); +GENESISAPI const geXForm3d * GENESISCC geCamera_GetWorldSpaceXForm( const geCamera *Camera); +GENESISAPI const geXForm3d * GENESISCC geCamera_GetCameraSpaceXForm( const geCamera *Camera); +GENESISAPI const geXForm3d * GENESISCC geCamera_GetCameraSpaceVisXForm( const geCamera *Camera); +GENESISAPI const geXForm3d * GENESISCC geCamera_GetWorldSpaceVisXForm( const geCamera *Camera); +GENESISAPI const geVec3d *GENESISCC geCamera_GetPov(const geCamera *Camera); +const geVec3d *GENESISCC geCamera_GetVisPov(const geCamera *Camera); +GENESISAPI geBoolean GENESISCC geCamera_ConvertWorldSpaceToCameraSpace(const geXForm3d *WXForm, geXForm3d *CXForm); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Engine/BitmapList.c b/G3D/Engine/BitmapList.c new file mode 100644 index 0000000..9e05bb6 --- /dev/null +++ b/G3D/Engine/BitmapList.c @@ -0,0 +1,382 @@ +/****************************************************************************************/ +/* BitmapList.c */ +/* */ +/* Author: Charles Bloom */ +/* Description: Maintains a pool of bitmap pointers. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#ifdef _DEBUG +#include +#endif + +#include +#include + + +#include "BitmapList.h" +#include "DCommon.h" +#include "Bitmap.h" +#include "Bitmap._h" +#include "list.h" +#include "mempool.h" +#include "errorlog.h" +#include "ram.h" +//#include "tsc.h" + +struct BitmapList +{ +#ifdef _DEBUG + BitmapList * MySelf; +#endif + Hash * Hash; + int Members,Adds; +}; + + +geBoolean BitmapList_IsValid(BitmapList *pList); + +//================================================================================ +// BitmapList_Create +//================================================================================ +BitmapList *BitmapList_Create(void) +{ +BitmapList * pList; + pList = geRam_Allocate(sizeof(*pList)); + if (! pList ) + return NULL; + memset(pList,0,sizeof(*pList)); + pList->Hash = Hash_Create(); + if ( ! pList->Hash ) + { + geRam_Free(pList); + return NULL; + } + #ifdef _DEBUG + pList->MySelf = pList; + #endif +return pList; +} + +//================================================================================ +// BitmapList_Destroy +//================================================================================ +geBoolean BitmapList_Destroy(BitmapList *pList) +{ +geBoolean Ret = GE_TRUE; + + if ( ! pList ) + return GE_TRUE; + + if ( pList->Hash ) + { + HashNode *pNode; + pNode = NULL; + + while( (pNode = Hash_WalkNext(pList->Hash,pNode)) != NULL ) + { + geBitmap *Bmp; + uint32 TimesAdded; + + HashNode_GetData(pNode,(uint32 *)&Bmp,&TimesAdded); + + if (!geBitmap_DetachDriver(Bmp, GE_TRUE)) + Ret = GE_FALSE; + + assert( pList->Members >= 1 && pList->Adds >= (int)TimesAdded ); + + pList->Members --; + + assert( TimesAdded >= 1 ); + + while(TimesAdded --) + { + assert(Bmp); + geBitmap_Destroy(&Bmp); + pList->Adds --; + } + } + + // Finally, destroy the entire hash table + Hash_Destroy(pList->Hash); + } + + geRam_Free(pList); + + return Ret; +} + +//================================================================================ +// BitmapList_SetGamma +//================================================================================ +geBoolean BitmapList_SetGamma(BitmapList *pList, geFloat Gamma) +{ +HashNode *pNode; + + assert(BitmapList_IsValid(pList)); + +#ifdef _DEBUG + //pushTSC(); +#endif + + pNode = NULL; + while( (pNode = Hash_WalkNext(pList->Hash,pNode)) != NULL ) + { + geBitmap *Bmp; + Bmp = (geBitmap *)HashNode_Key(pNode); + + if (!geBitmap_SetGammaCorrection(Bmp, Gamma, GE_TRUE) ) + { + geErrorLog_AddString(-1,"BitmapList_SetGamma : SetGamma failed.", NULL); + return GE_FALSE; + } + } + +#ifdef _DEBUG + //showPopTSCper("BitmapList_SetGamma",pList->MembersAttached,"bitmap"); +#endif + +return GE_TRUE; +} + +//================================================================================ +// BitmapList_AttachAll +//================================================================================ +geBoolean BitmapList_AttachAll(BitmapList *pList, DRV_Driver *Driver, geFloat Gamma) +{ +HashNode *pNode; +int MembersAttached; + + assert(BitmapList_IsValid(pList)); + + //pushTSC(); + + pNode = NULL; + MembersAttached = 0; + while( (pNode = Hash_WalkNext(pList->Hash,pNode)) != NULL ) + { + geBitmap *Bmp; + + Bmp = (geBitmap *)HashNode_Key(pNode); + + if (!geBitmap_SetGammaCorrection_DontChange(Bmp, Gamma) ) + { + geErrorLog_AddString(-1,"BitmapList_AttachAll : SetGamma failed", NULL); + return GE_FALSE; + } + + if (!geBitmap_AttachToDriver(Bmp, Driver, 0) ) + { + geErrorLog_AddString(-1,"BitmapList_AttachAll : AttachToDriver failed", NULL); + return GE_FALSE; + } + + MembersAttached ++; + } + + //showPopTSC("BitmapList_AttachAll"); + + assert( MembersAttached == pList->Members ); + + return GE_TRUE; +} + +//================================================================================ +// BitmapList_DetachAll +//================================================================================ +geBoolean BitmapList_DetachAll(BitmapList *pList) +{ +HashNode *pNode; +geBoolean Ret = GE_TRUE; +int MembersAttached; + + assert(BitmapList_IsValid(pList)); + + pNode = NULL; + while( (pNode = Hash_WalkNext(pList->Hash,pNode)) != NULL ) + { + geBitmap *Bmp; + uint32 TimesAdded; + + HashNode_GetData(pNode,(uint32 *)&Bmp,&TimesAdded); + + if (!geBitmap_DetachDriver(Bmp, GE_TRUE)) + Ret = GE_FALSE; + } + + MembersAttached = 0; + + return Ret; +} + +//================================================================================ +// BitmapList_CountMembers +//================================================================================ +int BitmapList_CountMembers(BitmapList *pList) +{ +#ifdef NDEBUG + return pList->Members; +#else +HashNode *pNode; +int Count; + + Count = 0; + pNode = NULL; + while( (pNode = Hash_WalkNext(pList->Hash,pNode)) != NULL ) + { + Count ++; + } + + assert( Count == pList->Members ); + assert( pList->Adds >= pList->Members ); + +return Count; +#endif +} +int BitmapList_CountMembersAttached(BitmapList *pList) +{ +HashNode *pNode; +int Count; + + Count = 0; + pNode = NULL; + while( (pNode = Hash_WalkNext(pList->Hash,pNode)) != NULL ) + { + geBitmap *Bmp; + uint32 TimesAdded; + + HashNode_GetData(pNode,(uint32 *)&Bmp,&TimesAdded); + + if ( geBitmap_GetTHandle(Bmp) ) + Count ++; + } + + assert( pList->Adds >= pList->Members && pList->Members >= Count ); + +return Count; +} + +//================================================================================ +// BitmapList_Has +//================================================================================ +geBoolean BitmapList_Has(BitmapList *pList, geBitmap *Bitmap) +{ +HashNode *pNode; +uint32 TimesAdded; + + assert(pList && Bitmap); + + pNode = Hash_Get(pList->Hash,(uint32)Bitmap,&TimesAdded); + + assert( pList->Adds >= (int)TimesAdded ); + +return (pNode && TimesAdded) ? GE_TRUE : GE_FALSE; +} + +//================================================================================ +// BitmapList_Add +//================================================================================ +geBoolean BitmapList_Add(BitmapList *pList, geBitmap *Bitmap) +{ +HashNode *pNode; +uint32 TimesAdded; + + assert(BitmapList_IsValid(pList)); + assert(Bitmap); + + // Increase reference count on this Bitmap + geBitmap_CreateRef(Bitmap); + + pList->Adds ++; + + if ( (pNode = Hash_Get(pList->Hash, (uint32)Bitmap, &TimesAdded)) != NULL ) + { + HashNode_SetData(pNode,TimesAdded+1); + return GE_FALSE; + } + else + { + pList->Members ++; + Hash_Add(pList->Hash,(uint32)Bitmap,1); + return GE_TRUE; + } +} + +//================================================================================ +// BitmapList_Remove +//================================================================================ +geBoolean BitmapList_Remove(BitmapList *pList,geBitmap *Bitmap) +{ +HashNode *pNode; +uint32 TimesAdded; +uint32 Key; + + assert(BitmapList_IsValid(pList)); + assert(Bitmap); + + Key = (uint32) Bitmap; + pNode = Hash_Get(pList->Hash,Key,&TimesAdded); + + assert(pNode); + + pList->Adds --; + TimesAdded --; + + if ( TimesAdded <= 0 ) + { + if ( ! geBitmap_DetachDriver(Bitmap, GE_TRUE) ) + { + geErrorLog_AddString(-1, "BitmapList_Remove: geBitmap_DetachDriver failed.", NULL); + return GE_FALSE; + } + } + + geBitmap_Destroy(&Bitmap); + + if ( TimesAdded <= 0 ) + { + pList->Members --; + Hash_DeleteNode(pList->Hash,pNode); + return GE_TRUE; + } + else + { + HashNode_SetData(pNode,TimesAdded); + return GE_FALSE; + } +} + + +geBoolean BitmapList_IsValid(BitmapList *pList) +{ + if ( ! pList ) + return GE_FALSE; + + if ( pList->Adds < pList->Members ) + return GE_FALSE; + +#ifdef _DEBUG + if ( pList->MySelf != pList ) + return GE_FALSE; +#endif + + if ( pList->Members != BitmapList_CountMembers(pList) ) + return GE_FALSE; + +return GE_TRUE; +} diff --git a/G3D/Engine/BitmapList.h b/G3D/Engine/BitmapList.h new file mode 100644 index 0000000..dcf09d2 --- /dev/null +++ b/G3D/Engine/BitmapList.h @@ -0,0 +1,58 @@ +/****************************************************************************************/ +/* BitmapList.h */ +/* */ +/* Author: Charles Bloom */ +/* Description: Maintains a pool of bitmap pointers. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef BITMAPLIST_H +#define BITMAPLIST_H + +#include "GeTypes.h" +#include "DCommon.h" +#include "Bitmap.h" + +typedef struct BitmapList BitmapList; + +#ifdef __cplusplus +extern "C" { +#endif + +BitmapList *BitmapList_Create(void); +geBoolean BitmapList_Destroy(BitmapList *pList); + +geBoolean BitmapList_SetGamma(BitmapList *pList, geFloat Gamma); + +geBoolean BitmapList_AttachAll(BitmapList *pList, DRV_Driver *Drivera, geFloat Gamma); +geBoolean BitmapList_DetachAll(BitmapList *pList); + + // _Add & _Remove do NOT return Ok/NOk +geBoolean BitmapList_Add(BitmapList *pList, geBitmap *Bitmap); // returns Was It New ? +geBoolean BitmapList_Remove(BitmapList *pList,geBitmap *Bitmap);// returns Was It Removed ? + // _Add & _Remove also do not do any Attach or Detach + +geBoolean BitmapList_Has(BitmapList *pList, geBitmap *Bitmap); + +#ifndef NDEBUG +int BitmapList_CountMembers(BitmapList *pList); +int BitmapList_CountMembersAttached(BitmapList *pList); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/G3D/Engine/Drivers/Bmp.c b/G3D/Engine/Drivers/Bmp.c new file mode 100644 index 0000000..b998d99 --- /dev/null +++ b/G3D/Engine/Drivers/Bmp.c @@ -0,0 +1,141 @@ +/****************************************************************************************/ +/* Bmp.c */ +/* */ +/* Author: Eli Boling */ +/* Description: Converts data to bmp format. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define WIN32_LEAN_AND_MEAN +#include + +#include + +#define WIDTH 640 +#define HEIGHT 480 + +BITMAPFILEHEADER bfh = +{ + ((unsigned short)'B' | ((unsigned short)'M' << 8)), + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFO) + WIDTH * HEIGHT * 2, + 0, + 0, + sizeof(BITMAPINFOHEADER) +}; + +BITMAPINFO bi = +{ + { + sizeof(BITMAPINFOHEADER), + WIDTH, + HEIGHT, + 1, + 24, + BI_RGB, + 0, + 0, + 0, + 0, + 0 + } +}; + +#ifdef BITS16 + #define RED(x) ((unsigned short)((x>>11) & 0x1f)) + #define GREEN(x) ((unsigned short)((x>>6 ) & 0x1f)) + #define BLUE(x) ((unsigned short)((x>>0 ) & 0x1f)) +#else + #define RED(x) ((unsigned short)((x>>11) & 0x1f)) + #define GREEN(x) ((unsigned short)((x>>5 ) & 63)) + #define BLUE(x) ((unsigned short)((x>>0 ) & 0x1f)) +#endif + +int WriteBMP(unsigned short *ScreenBuffer, const char *Name) +{ + FILE * out; + int y; + + out = fopen(Name, "wb"); + + if (!out) + return 0; + + if (fwrite(&bfh, sizeof(bfh), 1, out) != 1) + return 0; + + if (fwrite(&bi, sizeof(bi), 1, out) != 1) + return 0; + + for (y = HEIGHT-1; y >= 0; y--) + { + int i; + unsigned short *p; + unsigned char Buff[WIDTH * 3]; + unsigned char * BuffPtr; + + BuffPtr = &Buff[0]; + p = &ScreenBuffer[y*WIDTH]; + for (i = 0; i < WIDTH; i++) + { + #ifdef BIT16 + unsigned short c; + + c = p[i]; + c = (RED(c) << 10) + (GREEN(c) << 5) + BLUE(c); + p[i] = c; + #else + + #ifdef VER1 + char c[3]; + c = (char)(GREEN(p[i]) << 2); + fwrite(&c, 1, 1, out); + c = (char)(RED(p[i]) << 3); + fwrite(&c, 1, 1, out); + c = (char)(BLUE(p[i]) << 3); + fwrite(&c, 1, 1, out); + #else + #if 0 + char c[3]; + c = (char)(BLUE(p[i]) << 3); + fwrite(&c, 1, 1, out); + c = (char)(GREEN(p[i]) << 2); + fwrite(&c, 1, 1, out); + c = (char)(RED(p[i]) << 3); + fwrite(&c, 1, 1, out); + #else + *BuffPtr++ = (char)(BLUE(p[i]) << 3); + *BuffPtr++ = (char)(GREEN(p[i]) << 2); + *BuffPtr++ = (char)(RED(p[i]) << 3); +// fwrite(&c[0], 3, 1, out); + #endif + #endif + #endif + } + + fwrite(&Buff[0], WIDTH * 3, 1, out); + #ifdef BIT16 + p = &ScreenBuffer[y*WIDTH]; + for (i = 0; i < WIDTH; i++) + fwrite(&p[(i+2)%WIDTH], 2, 1, out); + #endif + } + + if (fclose(out)) + return 0; + + return 1; +} + diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3DDrv.mak b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv.mak new file mode 100644 index 0000000..454edfc --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv.mak @@ -0,0 +1,284 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on D3DDrv.dsp +!IF "$(CFG)" == "" +CFG=D3DDrv - Win32 Debug +!MESSAGE No configuration specified. Defaulting to D3DDrv - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "D3DDrv - Win32 Release" && "$(CFG)" != "D3DDrv - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "D3DDrv.mak" CFG="D3DDrv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "D3DDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "D3DDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "D3DDrv - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +ALL : "$(OUTDIR)\D3DDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\D3d_err.obj" + -@erase "$(INTDIR)\D3d_fx.obj" + -@erase "$(INTDIR)\D3d_main.obj" + -@erase "$(INTDIR)\D3dcache.obj" + -@erase "$(INTDIR)\D3ddrv.obj" + -@erase "$(INTDIR)\DDMemMgr.obj" + -@erase "$(INTDIR)\Gspan.obj" + -@erase "$(INTDIR)\Pcache.obj" + -@erase "$(INTDIR)\Render.obj" + -@erase "$(INTDIR)\Scene.obj" + -@erase "$(INTDIR)\THandle.obj" + -@erase "$(INTDIR)\tpage.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\D3DDrv.dll" + -@erase "$(OUTDIR)\D3DDrv.exp" + -@erase "$(OUTDIR)\D3DDrv.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MT /W3 /GX /O2 /X /I "..\..\.." /I "..\..\..\..\SdkDx6Sdk\Include" /I "..\\" /I "..\..\..\..\Sdk\Dx6Sdk\Include" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\Math" /I "..\..\..\Bitmap" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /Fp"$(INTDIR)\D3DDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\D3DDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:no /pdb:"$(OUTDIR)\D3DDrv.pdb" /machine:I386 /nodefaultlib /out:"$(OUTDIR)\D3DDrv.dll" /implib:"$(OUTDIR)\D3DDrv.lib" +LINK32_OBJS= \ + "$(INTDIR)\D3d_err.obj" \ + "$(INTDIR)\D3d_fx.obj" \ + "$(INTDIR)\D3d_main.obj" \ + "$(INTDIR)\D3dcache.obj" \ + "$(INTDIR)\D3ddrv.obj" \ + "$(INTDIR)\DDMemMgr.obj" \ + "$(INTDIR)\Gspan.obj" \ + "$(INTDIR)\Pcache.obj" \ + "$(INTDIR)\Render.obj" \ + "$(INTDIR)\Scene.obj" \ + "$(INTDIR)\THandle.obj" \ + "$(INTDIR)\tpage.obj" \ + "..\..\..\..\MSDev60\lib\Wininet.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmt.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\dxguid.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\ddraw.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\d3dim.lib" + +"$(OUTDIR)\D3DDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "D3DDrv - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\D3DDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\D3d_err.obj" + -@erase "$(INTDIR)\D3d_fx.obj" + -@erase "$(INTDIR)\D3d_main.obj" + -@erase "$(INTDIR)\D3dcache.obj" + -@erase "$(INTDIR)\D3ddrv.obj" + -@erase "$(INTDIR)\DDMemMgr.obj" + -@erase "$(INTDIR)\Gspan.obj" + -@erase "$(INTDIR)\Pcache.obj" + -@erase "$(INTDIR)\Render.obj" + -@erase "$(INTDIR)\Scene.obj" + -@erase "$(INTDIR)\THandle.obj" + -@erase "$(INTDIR)\tpage.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\D3DDrv.dll" + -@erase "$(OUTDIR)\D3DDrv.exp" + -@erase "$(OUTDIR)\D3DDrv.ilk" + -@erase "$(OUTDIR)\D3DDrv.lib" + -@erase "$(OUTDIR)\D3DDrv.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MTd /W3 /GX /Zi /Od /X /I "..\..\.." /I "..\..\..\Math" /I "..\\" /I "..\..\..\..\Sdk\Dx6Sdk\Include" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\Bitmap" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /Fp"$(INTDIR)\D3DDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\D3DDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:yes /pdb:"$(OUTDIR)\D3DDrv.pdb" /debug /machine:I386 /nodefaultlib /out:"$(OUTDIR)\D3DDrv.dll" /implib:"$(OUTDIR)\D3DDrv.lib" /pdbtype:sept +LINK32_OBJS= \ + "$(INTDIR)\D3d_err.obj" \ + "$(INTDIR)\D3d_fx.obj" \ + "$(INTDIR)\D3d_main.obj" \ + "$(INTDIR)\D3dcache.obj" \ + "$(INTDIR)\D3ddrv.obj" \ + "$(INTDIR)\DDMemMgr.obj" \ + "$(INTDIR)\Gspan.obj" \ + "$(INTDIR)\Pcache.obj" \ + "$(INTDIR)\Render.obj" \ + "$(INTDIR)\Scene.obj" \ + "$(INTDIR)\THandle.obj" \ + "$(INTDIR)\tpage.obj" \ + "..\..\..\..\MSDev60\lib\Wininet.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmtd.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\dxguid.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\ddraw.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\d3dim.lib" + +"$(OUTDIR)\D3DDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("D3DDrv.dep") +!INCLUDE "D3DDrv.dep" +!ELSE +!MESSAGE Warning: cannot find "D3DDrv.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "D3DDrv - Win32 Release" || "$(CFG)" == "D3DDrv - Win32 Debug" +SOURCE=.\D3d_err.cpp + +"$(INTDIR)\D3d_err.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3d_fx.cpp + +"$(INTDIR)\D3d_fx.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3d_main.cpp + +"$(INTDIR)\D3d_main.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3dcache.cpp + +"$(INTDIR)\D3dcache.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3ddrv.cpp + +"$(INTDIR)\D3ddrv.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\DDMemMgr.c + +"$(INTDIR)\DDMemMgr.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Gspan.cpp + +"$(INTDIR)\Gspan.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Pcache.cpp + +"$(INTDIR)\Pcache.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Render.cpp + +"$(INTDIR)\Render.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Scene.cpp + +"$(INTDIR)\Scene.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\THandle.cpp + +"$(INTDIR)\THandle.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\tpage.cpp + +"$(INTDIR)\tpage.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3DDrv.ncb b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv.ncb new file mode 100644 index 0000000000000000000000000000000000000000..c9427db7239d057c1dfaeb71973217c8f15bf2af GIT binary patch literal 214016 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 z zZ!&!2p^XPmBPWfoW;z+%Fv1NZoUviFj-WV8d3WlC%5k~40ko9~Tz~q$d|WAQa}uXD z3jGZxE$Tr^DRW7j);Y8iqw$+&U@8Tg6%U{ebjA&)ZRm|Fr?1GzXtv|5mvLI zzVz8iTruB(Byjy{H#_47Q#Uk9*8E$mKw95Y%~S84girq~jLK;Or~XDW*}m{9|PV8X?<)t zpa``8+H+txIl$6)`>#C*+H>IFGzUI->w~vqr2W~W_;32S>C-oDNsUS!zHY;~v8hGX z>#J99u5L@7UVY3d$C(+ER#q-rIBU_=`Kg(6=FM2Va{in{7A;)7aORTKvN?;FPMw!p zyyXA4cP>zJ6=edhNWcdu14ck(u@fQ+Vi*Vz6at-OCIL;DHklBFL1r@3N#>Z$j58CS zJ{lSXeC>!Js3-%=BR*DV6_NFyuj9Hqp2gQ$W%v8~-s8a}Kx^@5htLoOBd+YydZQH3GUCTOFt?D?fYt@>z_S0W}eAm)bPwP6*;uj3` zu766U^bU_cf>KMuotQp)o z+?(%8gZ6=q{R8=~w&DJB^TQ)uiRlRX&dCoCFX$Z_3MXR4zQOZG7Hm2xoQPq2&P!qo z+YIM%#5wI`-84@F6B``v99%Ox+&{1}^ls`I&Kw?2S>3*7?aIy!B@PakZB;h~H`TAW z4d*A-9U1NGAB(L%o&PMrXt{d(j&9@Kqtf&04)@hvIa)X;M*f=<_YOt?-YP4Os zs-vwv6BCwh##%Gk&s@HBpjVxjt;#K5d)l&0{GOh!&+uqExBS<{C8IkhE*sAGjK&!x3>?maOrv2GfslW-mTVVu_M z)oYS_gE}gh-fYxMzs}@_p`JrI7FoAe9vxyXud9aM9B{3PH#}{tm#kZ}cJ=Zl%i0%Z zUUb&+XV?BE-VD_`EdF-Na2Uwv`|^EZBtM$z$qbio6Guk5*T`%g;7)ub(?6Q&9|Tj71!-HEwulH27&X_rT^H5vcnyteddV2HW-2VJ| zZ9Sts-c_A`YWuoe$Lh{SwU4VljNJSubLz78w)Qp4cFaHXZDHF?yxLTi;$tD@Y}M!I zPK`T%|2yCodeMdP#@H{+?DHxGSn8sTitUh8X_HvX#ja&T<{gxT@$UgGNz8x#TqL}+ zxN!B4iO`%{a$#2j?z@)qU2N?FQk}~VeF3kudB=VT@7rB0TVlP#wNFccemb-XqtFRQ z=VP4*b)41#ZqCwB241)c#IgR9nu_2Wp%OZIyYY@Nxa^rBtYwj{PSH_Z)b65M7s(5` zh_e0JF_wfnq$)Za>@08PJVMI8PZ>JX30`r*sh}zyP(Ot(Pb8mU0l6}{FbS`x&Qb2( z4Vc{i$+x%94dn&wE~J0t6c)ZNPGFUSrEVhMcGfz4kF^{>*gb@GtO@ExU!9mAr#u&Y z>xijS$(7VsCn|wO0(W%0&_T~lM_e?0HvM5C?~--+7D{jli(D_J%@iG(Uf|jTq=3zC z=bSqDpSUDR^Y2}puRnuLX$v=;)RFYlq%Y-t{Q*2pd@;KIlJycgQMqA_j!Z7VcXKxv zWb0Ue>_N0O^>t%4;YB(E35pXa)XV41=zMUN#ks_FEEa@yAY}?fQA)4ICfHoSxL^oH zXB-`Ggr7yx$>~n?R9;A5x{-2SSR6&riB1WEDFnv|oVfI?_$x3&`lF&ln;^2CWuGjN zERGkZpa@8L6?S*w{|`?}(u64d0-L;WiHo% zH|N;@ump@5(}k;4i_jCDr*$U!59<80Z1t~PHz-@@%=Osz!}Rt0u!m0VLT?_=@Gz@2 zl%1Caq6sQo+EIKPjxtD&Xyat^GJSip8 z7SQHXw6mf^ODA>^e9>3KUP-PU|LTOQ)2nh9?0Zdm9od^Ujv_=(**lYf zXa!?^65Fk#KfD-QzmHE8!8QU0qhuLVijGI`Z)1F-YX)0BvWR6SE0f>iUmZ{`h-RQd)Pv?=d%~a^36*WzgSc*ht_<3--p;Wzl(7C~vjw#yNBpy_Nij zyfg)=QeF?~I<}9HSpc36<2q*R)Fp`Z!-P7Cw$Ua!MPJQtcThJSS=W;;wBg6-yF2Z% z7Cm$-)>%gfoNBqKs{QZaniPK)xTeGIbN1j`iaxKvRu^-;fGvSoZl)n{Vaf4~ANt>I z^s%)ZBY^0)UDapUF@8CHSWsJ$wiiC9qx5UB}MFyw2pz+0EluKcbO;Dz)>9TtRh z{et#92Kx#&5=J7-N1#kAw%Az&b=8u4&{>)F%p{C|---^xDyl`m(e_mUSku1fZ#vxy zdio-^7Ah&A<9zhdLFzWrcjKeen@$;m{Dj0jg8d)CW)E=8HPqpU^d}ugb=dqCX*%@i zm?O|f=RBRn?>~_1G{?Uey@Vca#3njw=?E&=<{>@;EOe~bsZ$Ybb{peCr&%{yyq|W^ z(M#|{wfurKML@C+hQdUI_T5A|*_G6nG6ix9WVsSOe)me|uhWxb+)Uz*LuhCEqZ<=m zPCaxM)M;gsW0hM7pGE(0!(l;xZ#<6cDCOzIcT1M*JmntP$-J?adz1yV@sa3Edkgp! zb##bUghUEvd?FD(cq{pJ!oBtAnOtwcHcB7ojPi2weH9y=$hn1F3FfF4 zofprcZIpG?O<>EdoO{J97)RLrU9&=53@XAQPLiZq=o-LzQ;CY{6uS_%6+w1fGJ_$JZ>3%r+Og+d8exsK!Kyb7Cfe6^fQ zx`44aa(=~4*%Y0A6&>_+qTZc6f+A03%tR3)AQ-HdbFfmR45relc@Ojyl3Xo1ZRsfc zdiu(o)m)p==Y&m$s zKLV~49ZiKP3R)C=BWP9`T$zOaJ()Z^i|`yB*A)S$0zh@Z71AtFQs+M*d*7svdo2fS z&v=W$(N90{mWzD@tRoa>1YP(h1AC^FAUe)F%; zpni0Gkl)Y8Za18QZ5X?P5Cka*{Zs@43OSAP5N)Ykwv;hR`HJw#KPCc|g_Lfjd?Cj_ zrq2i)nnVYk^q-MUj$Yw;Df8`5qi=96xB*+}2q@e&%7e78AT8w~>RT;>eFZT_*+{#5 zVLttvdJ2~NK!*PKO0E-}f8klo>C{1(ldwwVJ)G-D*x3zbqX-371nNGK=qM{ROK_#m z@B%^ zha1od$c-YTWoOxrt%bY^3B7U;>Oeo;ivCX{F2G0dsL;x| zre2WcI?T1<4CXoI2Fg){qA5!l+XC>S2zK3B1g9T}K0VlObydIk0rnR7^sjSwK7#wj zXC-Mv)Lo#3ATpht1)h~?-zbOEj|Yxr4q^NWFLD!4L58PM?k%MKW_PZ^)JssQP}1}H zO()?fUpkb$*h3Js0E@3-7r_x{k!OrP@J`xg1??d)ribw@JgAqlvmA3a^%5%ft}|n4 zoR8y$KxK}^cC=j-;f=!Ju4Oz6cvReEVgu(Kp^rs5>&UA-kGK$JMF^>KBjZBIqc9kOkT)^L+$_Y6$X-i3 z3n`z4odsP9%n;ZmEZ_ms-kjmON`F^2rF~Aom7?HE6#V$f!mSI=HTE)Y$J!46jrLd7-^ZUiv?A`POp_7V` z5MdwZaeS1w&1VdrnS2viC4^Ji#Q6k4f1mc(DO_04qE5yWZ6w@jH@++H$wud9oNxqVm$5J4 zX%YSPCD;p(h%$s#pmDVbxfWC-gh6PjpsXktSLySgT*IG*J@)0(nZf4d{{VIt1od-{ z7Xl^JM_54%{h*WYg4Din93Sc-_)fTkn`*eRmLf>|B5byeexV4bQa(pHhjN}D(N@CL z*Pp=ry&L@}OTQ<-atU?bjvb;1u)2-&eQS5@vn-}2p-{;C=W(4NzksbMg3<(V{$YK7{6k+B$fA^%b8pG` ziXxy>5t8;`TN1xJJwExyn4oPGH)RmI+JWtbS_}8@=DW}p!JyCMvpb)?nJd}}kLC06 zZ28bK#8Tj9l>Hd{%GXG{n>L%Dem5=8ac->Rh8BXZS8y%aO4?<7PQV^l(S`!UPDGD8 zx;%paArHW|ss6$wh4r6>T?8*bKpV2My$o;=fGccolrj&+F6%ju5WcP4nMO|ufzFXf>+=25Q+1{;`?`?(0 z{*q&T)lxneWk$C55R9mwF^o+gIunj^YV!8brRB6t6>GA+GvxPmly=^Loth8aD9$T7C9aH;HlE+6QrcV&}RfA=I2^}Kadz|#h_8uetqEyc@@5D>H)GR(*No?= zS7dv4Gq2TRd&@BN49s4xQ~X+lO^u0p?%;=TFOU-rcb}KSYdl-$m1hb^E^VHT5RtE_Ka-rG1@n> zy{GSCo=wNs*ip>0+~!%%*C@x=1)gh)Jdy1^N!+CsrcV&}meu@MkUz4$$4U3`nt8@J zZ)AHHNUz2AZrQh3VS7)#p;%#iXPG;$Nz1QhduJ)fR|uZ>RL&dO-s9Nc*VCqNBi(<4 z)geRv$o9^Dh`p`SYsE*%6WQK@JU%Y;*lMo+$WpFTS<>>?+o!; zZ117H7z=Zg{DC}??cK`tDzd#N(I>LKr|v3L*xudDao~NV@=QdJlf)z2dxCf^w)Z&cwbJr)BW8{x)Z}&oUS(-WwksjIJ z<1Or4azxS}o`~(8BfrZGJhqj&*vG=t!uFnGoJO{H>xbCO;>C$>CowMW$tE@#<5-ted2ESmT4Z| zfoh zws#hr_=?o@DdzOZ_8#Nd$o7`Q8rj}*k$nv7IIU)Tcay#=ws(#^F6k@la4-ASr0sh$ zHjHfV7TPhgy$f8sd_`maz_F3-Eju}~y)y?FYqGuNC`Y#U)NJO3)P^npTdc6X$H`M+ zdowOdsU33Mhex*e5P5u6VSN{)=dRe^-Q@SRuR2dKcSN>#mh{N>mXjLU-hul1y21QI z)Hkxd19>9bJD^)+dzT)n&Gwd&+?V#BN#Z^pFY7@3@z}ofHXo65BHLRQ@}X&cKSp|Fd*?1JR@mNSWElD7M+Io4%GvpH9eJTC9@yjkKt);8WsJhHvVu(PlFOm89GWlqKeabMkN|7y1P z^qJfPq;)TShkJmRC3$k3*Cjh1o1?z%X-Z{omWP1m6j%@F7%K1rp-ZA2}*xm)w zBip;>gY?x@=Wfz#vAs+D&t8k|oh5%Qws$M(k?lRXC;P;v{bw4Mc4T``pufuot>g5! zXV~5);x4<=RuWr%M6CT=8JoVUEZY;EBinnN{4V1)eS*287Tdc(9+xIqW;NSe7II{J z%Ri26?<{d&1)IN`?cIGsTT^vc0p|JhHu8D6Ot z_MT+^y)4Z?NPd?BTFy8&jBM|5j*V>Z5_4H(drxy+^)-+BSF^oaXuDmpy}Kzhvb}S} zBilQ?jk!CuNj2L$L;s9y?`(nRmd{M|oH_|xr8$si!YRWe~kbhTf?-KR;$d!8TBe~cH%?^0RgleEjMg^3Q;Z0~OJ zG}+#NS!{1#vdR9hu%fxR&QF+dJ~U>&f=snd>ddZqjBk0~vb`hg`>C?MBhx!Fz9ZY4J8kNg;d=Sx+1`=sEe(=Ig_N@= z;a+@dvAx|-VFC9NNAi1yTz^??@5uCyjPEAfyUF(cYiE1Q^_KkpWZ2&Oa*TZMCfmEo z_HMGh|NhwCa=j%;H`(4zws({5&8=!v{wx-7O=eS?7HC@F@6!U2|1Hi!5FVVlCjYz1 z|9&#O^CtiMubKb-r(o@&Uq?Q7O{`{<|GBKQ%;T(}IG-y2bMYR@bkwAFLMd7^Gc`A< zoh&KjN&h7)Av<&>c5#XF-x{?uws@1;nOLGp?QBvz?Frf4lm5`8b|!X+f1A|K#1gu+ zG^w486XwSzwKI;6By3VU6FWQ=YNsVMshx=(o77H7nTr!!G^w459sJv*cFx$MN$qS> zJDb$bWIQyfolR#aP3%n;to@nj8y{5hWR#pr?Rwzntr>To^bL0qmrO6XO2lJHRqnIb%c z?~f6Bm74w7wprtpJBKjG_xXe?x$GQ6cso~?Ho_~o>~yBT_Yt;|f0WRx?xlneq0iNX zKSiUP{hjpN3E$55y9j?v_zlAAQS4DdXNAWIJ4v7Yt8KF~e4j&jC*S829>e!z2(RW! z*+$sS`8o+FxQzA@TK*`Zv(Tk!cr~F{*_#Qi-|d9vyNl5JeS^^YJxbV3{T?H&}i@qGb!oEuPvCqY##|94gVZI7Cs&(!oP%1umjUrcvrY8ygOVSt_kl6*Rs#h zb>Y3?ec}D#`tX79!Ei$u4>vN`{8P9Y7VoX$Hs;Vd%+LEVcOAg|cOY}!LCkvxGdE_K z-{vtl&1b$jl)3XI%&&(trys%mxPUpVm3i}M=D1^+$B$zUKR&#JJ*Kv?f6D9NWo!v2 zhiq69mWE}ajoE!UywD56h2f&`hVaJlrm#5-h1Z8m!f?10s_|RGXxPfm6XypybyJ!a WXj-6Yfu;qT7HC?aX@S2(3;ZAMt4X5( literal 0 HcmV?d00001 diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3DDrv.opt b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv.opt new file mode 100644 index 0000000000000000000000000000000000000000..d3ac452c1a93dc9dbb0ea43853a341b169d9b96b GIT binary patch literal 51712 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 literal 0 HcmV?d00001 diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsp b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsp new file mode 100644 index 0000000..b7bd355 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="D3DDrv7x" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=D3DDrv7x - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "D3DDrv7x.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "D3DDrv7x.mak" CFG="D3DDrv7x - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "D3DDrv7x - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "D3DDrv7x - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Source/Engine/Drivers/D3DDrv7x", DVPBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "D3DDrv7x - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV7x_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /YX /FD /c +# SUBTRACT CPP /X +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +# SUBTRACT RSC /x +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 Wininet.lib comdlg32.lib gdi32.lib kernel32.lib libcmt.lib libcmtd.lib oldnames.lib shell32.lib user32.lib uuid.lib advapi32.lib dxguid.lib ddraw.lib d3dim.lib /nologo /dll /machine:I386 +# SUBTRACT LINK32 /nodefaultlib + +!ELSEIF "$(CFG)" == "D3DDrv7x - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV7x_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /X /I "..\..\.." /I "..\..\..\Math" /I "..\\" /I "e:\mssdk7a\include" /I "..\D3DDrv7x" /I "..\..\..\Support" /I "e:\program files\microsoft visual studio\vc98\include" /I "..\..\..\Bitmap" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV7x_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /x /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "D3DDrv7x - Win32 Release" +# Name "D3DDrv7x - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\D3d_err.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_err.h +# End Source File +# Begin Source File + +SOURCE=.\D3d_fx.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_fx.h +# End Source File +# Begin Source File + +SOURCE=.\D3d_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_main.h +# End Source File +# Begin Source File + +SOURCE=.\D3dcache.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3dcache.h +# End Source File +# Begin Source File + +SOURCE=.\D3ddrv7x.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3ddrv7x.h +# End Source File +# Begin Source File + +SOURCE=..\Dcommon.h +# End Source File +# Begin Source File + +SOURCE=.\DDMemMgr.c +# End Source File +# Begin Source File + +SOURCE=.\DDMemMgr.h +# End Source File +# Begin Source File + +SOURCE=.\Gspan.cpp +# End Source File +# Begin Source File + +SOURCE=.\Gspan.h +# End Source File +# Begin Source File + +SOURCE=.\Pcache.cpp +# End Source File +# Begin Source File + +SOURCE=.\Pcache.h +# End Source File +# Begin Source File + +SOURCE=.\Render.cpp +# End Source File +# Begin Source File + +SOURCE=.\Render.h +# End Source File +# Begin Source File + +SOURCE=.\Scene.cpp +# End Source File +# Begin Source File + +SOURCE=.\Scene.h +# End Source File +# Begin Source File + +SOURCE=.\THandle.cpp +# End Source File +# Begin Source File + +SOURCE=.\THandle.h +# End Source File +# Begin Source File + +SOURCE=.\tpage.cpp +# End Source File +# Begin Source File + +SOURCE=.\TPage.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# End Group +# End Target +# End Project diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsw b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsw new file mode 100644 index 0000000..f94560c --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "D3DDrv7x"=".\D3DDrv7x.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.ncb b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.ncb new file mode 100644 index 0000000000000000000000000000000000000000..e6d0618fddd74c393b1c20ed64e3442a90e834d0 GIT binary patch literal 230400 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 E17rricmMzZ literal 0 HcmV?d00001 diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.opt b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.opt new file mode 100644 index 0000000000000000000000000000000000000000..f2d62788d42716b03a5d5ade4f124f3941d3eb12 GIT binary patch literal 50688 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 Hh6wy0bC0a+ literal 0 HcmV?d00001 diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.plg b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.plg new file mode 100644 index 0000000..a6cfd82 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3DDrv7x.plg @@ -0,0 +1,44 @@ + + +
+

Build Log

+

+--------------------Configuration: D3DDrv7x - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP1D.tmp" with contents +[ +/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /Fp"Release/D3DDrv7x.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c +"D:\Release\G3D\Engine\Drivers\D3D7xDrv\D3d_main.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP1D.tmp" +Creating temporary file "C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP1E.tmp" with contents +[ +Wininet.lib comdlg32.lib gdi32.lib kernel32.lib libcmt.lib libcmtd.lib oldnames.lib shell32.lib user32.lib uuid.lib advapi32.lib dxguid.lib ddraw.lib d3dim.lib /nologo /dll /incremental:no /pdb:"Release/D3DDrv7x.pdb" /machine:I386 /out:"Release/D3DDrv7x.dll" /implib:"Release/D3DDrv7x.lib" +.\Release\D3d_err.obj +.\Release\D3d_fx.obj +.\Release\D3d_main.obj +.\Release\D3dcache.obj +.\Release\D3ddrv7x.obj +.\Release\DDMemMgr.obj +.\Release\Gspan.obj +.\Release\Pcache.obj +.\Release\Render.obj +.\Release\Scene.obj +.\Release\THandle.obj +.\Release\tpage.obj +] +Creating command line "link.exe @C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP1E.tmp" +

Output Window

+Compiling... +D3d_main.cpp +Linking... + Creating library Release/D3DDrv7x.lib and object Release/D3DDrv7x.exp + + + +

Results

+D3DDrv7x.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.CPP b/G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.CPP new file mode 100644 index 0000000..378c1fc --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.CPP @@ -0,0 +1,271 @@ +/****************************************************************************************/ +/* D3D_Err.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D Error code conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "D3D_Err.h" + +//================================================================================ +// D3DErrorToString +//================================================================================ +char *D3DErrorToString(HRESULT error) +{ + switch(error) { + case DD_OK: + return "No error.\0"; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized.\0"; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0"; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface.\0"; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface.\0"; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs.\0"; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0"; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0"; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation.\0"; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available.\0"; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process.\0"; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation.\0"; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive.\0"; + case DDERR_GENERIC: + return "Generic failure.\0"; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment.\0"; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created.\0"; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state.\0"; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface.\0"; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface.\0"; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect.\0"; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist.\0"; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0"; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode.\0"; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0"; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect.\0"; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified.\0"; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0"; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid.\0"; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked.\0"; + case DDERR_NO3D: + return "There is no 3D present.\0"; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0"; + case DDERR_NOBLTHW: + return "No blitter hardware present.\0"; + case DDERR_NOCLIPLIST: + return "No cliplist available.\0"; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object.\0"; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or available.\0"; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key\0"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color key.\0"; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0"; + case DDERR_NODC: + return "No DC was ever created for this surface.\0"; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware.\0"; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0"; + case DDERR_NOEMULATION: + return "Software emulation not available.\0"; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive mode.\0"; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported.\0"; + case DDERR_NOGDI: + return "There is no GDI present.\0"; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0"; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available.\0"; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination.\0"; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available.\0"; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface.\0"; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes.\0"; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0"; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available.\0"; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching.\0"; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0"; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0"; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0"; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface.\0"; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable.\0"; + case DDERR_NOTFOUND: + return "Requested item was not found.\0"; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, has been attempted.\0"; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface.\0"; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations.\0"; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0"; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated.\0"; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough video memory to perform the operation.\0"; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays.\0"; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays.\0"; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread.\0"; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface.\0"; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small.\0"; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to.\0"; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of.\0"; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread.\0"; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured.\0"; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.\0"; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached.\0"; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large.\0"; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large.\0"; + case DDERR_UNSUPPORTED: + return "Action not supported.\0"; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw.\0"; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress.\0"; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete.\0"; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode.\0"; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary.\0"; + case D3DERR_BADMAJORVERSION: + return "D3DERR_BADMAJORVERSION\0"; + case D3DERR_BADMINORVERSION: + return "D3DERR_BADMINORVERSION\0"; + case D3DERR_EXECUTE_LOCKED: + return "D3DERR_EXECUTE_LOCKED\0"; + case D3DERR_EXECUTE_NOT_LOCKED: + return "D3DERR_EXECUTE_NOT_LOCKED\0"; + case D3DERR_EXECUTE_CREATE_FAILED: + return "D3DERR_EXECUTE_CREATE_FAILED\0"; + case D3DERR_EXECUTE_DESTROY_FAILED: + return "D3DERR_EXECUTE_DESTROY_FAILED\0"; + case D3DERR_EXECUTE_LOCK_FAILED: + return "D3DERR_EXECUTE_LOCK_FAILED\0"; + case D3DERR_EXECUTE_UNLOCK_FAILED: + return "DDERR_EXECUTE_UNLOCK_FAILED\0"; + case D3DERR_EXECUTE_FAILED: + return "D3DERR_EXECUTE_FAILED\0"; + case D3DERR_EXECUTE_CLIPPED_FAILED: + return "D3DERR_EXECUTE_CLIPPED_FAILED\0"; + case D3DERR_TEXTURE_NO_SUPPORT: + return "D3DERR_TEXTURE_NO_SUPPORT\0"; + case D3DERR_TEXTURE_NOT_LOCKED: + return "D3DERR_TEXTURE_NOT_LOCKED\0"; + case D3DERR_TEXTURE_LOCKED: + return "D3DERR_TEXTURELOCKED\0"; + case D3DERR_TEXTURE_CREATE_FAILED: + return "D3DERR_TEXTURE_CREATE_FAILED\0"; + case D3DERR_TEXTURE_DESTROY_FAILED: + return "D3DERR_TEXTURE_DESTROY_FAILED\0"; + case D3DERR_TEXTURE_LOCK_FAILED: + return "D3DERR_TEXTURE_LOCK_FAILED\0"; + case D3DERR_TEXTURE_UNLOCK_FAILED: + return "D3DERR_TEXTURE_UNLOCK_FAILED\0"; + case D3DERR_TEXTURE_LOAD_FAILED: + return "D3DERR_TEXTURE_LOAD_FAILED\0"; + case D3DERR_MATRIX_CREATE_FAILED: + return "D3DERR_MATRIX_CREATE_FAILED\0"; + case D3DERR_MATRIX_DESTROY_FAILED: + return "D3DERR_MATRIX_DESTROY_FAILED\0"; + case D3DERR_MATRIX_SETDATA_FAILED: + return "D3DERR_MATRIX_SETDATA_FAILED\0"; + case D3DERR_SETVIEWPORTDATA_FAILED: + return "D3DERR_SETVIEWPORTDATA_FAILED\0"; + case D3DERR_MATERIAL_CREATE_FAILED: + return "D3DERR_MATERIAL_CREATE_FAILED\0"; + case D3DERR_MATERIAL_DESTROY_FAILED: + return "D3DERR_MATERIAL_DESTROY_FAILED\0"; + case D3DERR_MATERIAL_SETDATA_FAILED: + return "D3DERR_MATERIAL_SETDATA_FAILED\0"; + case D3DERR_LIGHT_SET_FAILED: + return "D3DERR_LIGHT_SET_FAILED\0"; + default: + return "Unrecognized error value.\0"; + } +} diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.H b/G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.H new file mode 100644 index 0000000..bc65c56 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3D_ERR.H @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* D3D_Err.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D Error code conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_ERR_H +#define D3D_ERR_H + +#include +#include +#include + +//================================================================================ +// Global functions +//================================================================================ +char *D3DErrorToString(HRESULT error); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3d_fx.cpp b/G3D/Engine/Drivers/D3D7xDrv/D3d_fx.cpp new file mode 100644 index 0000000..58af1d4 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3d_fx.cpp @@ -0,0 +1,308 @@ +/****************************************************************************************/ +/* D3D_Fx.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D renderstate wrapper */ +/* */ +/* 02/28/2001 Wendell Buckner */ +/* The flags at the end of DrawPrimitive are no longer supported in d3d 7.0, use the */ +/* combination of flags in the renderstate call */ +/* Optimization from GeForce_Optimization2.doc */ +/* 9. Do not duplicate render state commands. Worse is useless renderstates. */ +/* Do not set a renderstate unless it is needed. */ +/* These render states are unsupported d3d 7.0 */ +/* 07/16/2000 Wendell Buckner */ +/* Convert to Directx7... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +#include "D3DDrv.h" */ +#include "D3DDrv7x.h" + +#include "DCommon.h" +#include "Render.h" +#include "Scene.h" +#include "D3D_FX.h" +#include "D3D_Main.h" +#include "D3D_Err.h" + +static D3DTEXTUREHANDLE OldTexHandle = NULL; + +//====================================================================================================== +//====================================================================================================== +void D3DSetTexHandle(D3DTEXTUREHANDLE TexHandle) +{ + if (TexHandle == OldTexHandle) + return; + + OldTexHandle = TexHandle; + +/* 02/28/2001 Wendell Buckner + These render states are unsupported d3d 7.0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, TexHandle);*/ +} + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +static LPDIRECT3DTEXTURE2 OldTexture[8];*/ +static LPDIRECTDRAWSURFACE7 OldTexture[8]; + + +//====================================================================================================== +//====================================================================================================== + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +void D3DSetTexture(int32 Stage, LPDIRECT3DTEXTURE2 Texture) */ +void D3DSetTexture(int32 Stage, LPDIRECTDRAWSURFACE7 Texture) + +{ + if (Texture == OldTexture[Stage]) + return; + + OldTexture[Stage] = Texture; + + AppInfo.lpD3DDevice->SetTexture(Stage, Texture); +} + +//====================================================================================================== +//====================================================================================================== +void D3DBilinearFilter(D3DTEXTUREFILTER Min, D3DTEXTUREFILTER Mag) +{ + AppInfo.lpD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR); + AppInfo.lpD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + + if (AppInfo.CanDoMultiTexture) + { + AppInfo.lpD3DDevice->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFN_LINEAR); + AppInfo.lpD3DDevice->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + } +} + +//====================================================================================================== +// Old one uses D3DTLVERTEX vertex format +//====================================================================================================== +void D3DTexturedPolyOld(void *Pnts, int32 NumPoints) +{ +/* 02/28/2001 Wendell Buckner + The flags at the end of DrawPrimitive are no longer supported in d3d 7.0, use the combination of flags in + the renderstate call */ + HRESULT Hr; + +/* 02/08/2002 Wendell Buckner + Optimization from GeForce_Optimization2.doc + 9. Do not duplicate render state commands. Worse is useless renderstates. Do not set a renderstate unless it is needed. + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPING,FALSE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING,FALSE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_EXTENTS,FALSE); + AppInfo.lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_TLVERTEX, Pnts, NumPoints, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT | D3DDP_DONOTCLIP);*/ + Hr = AppInfo.lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_TLVERTEX, Pnts, NumPoints, NULL); + if( Hr != DD_OK ) D3DMain_Log("D3DTExturedPolOld failed...\n\n"); +} + +//====================================================================================================== +// D3DTexturedPoly +//====================================================================================================== +void D3DTexturedPoly(void *Pnts, int32 NumPoints) +{ +/* 02/28/2001 Wendell Buckner + The flags at the end of DrawPrimitive are no longer supported in d3d 7.0, use the combination of flags in + the renderstate call */ + HRESULT Hr; + +/* 02/08/2002 Wendell Buckner + Optimization from GeForce_Optimization2.doc + 9. Do not duplicate render state commands. Worse is useless renderstates. Do not set a renderstate unless it is needed. + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPING,FALSE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING,FALSE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_EXTENTS,FALSE); + AppInfo.lpD3DDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, + //D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2, + Pnts, + NumPoints, + D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT | D3DDP_DONOTCLIP); + //D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTCLIP);*/ + Hr = AppInfo.lpD3DDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2, + Pnts, + NumPoints, + NULL); + + if( Hr != DD_OK ) D3DMain_Log("D3DTexturedPoly failed...\n\n"); +} + +//====================================================================================================== +// D3DViewport +//====================================================================================================== +void D3DViewport (int32 x, int32 y, int32 width, int32 height) +{ +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + D3DVIEWPORT2 vport; */ + D3DVIEWPORT7 vport; + +//03/01/2002 Wendell Buckner +//This wasn't commented in the original code but it was in my genesis 1.0 converted code... +//not sure I should do this. +// return; +// +// vport.dwSize = sizeof(D3DVIEWPORT2); + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + AppInfo.lpD3DViewport->GetViewport2(&vport); */ + AppInfo.lpD3DDevice->GetViewport(&vport); + + vport.dwX = x; + vport.dwY = AppInfo.OldHeight - (y + height); + vport.dwWidth = width; + vport.dwHeight = height; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + vport.dvClipX = -1.0f; + vport.dvClipY = 1.0f; + vport.dvClipWidth = (float)width /2.0f; + vport.dvClipHeight = (float)height/2.0f;*/ + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + AppInfo.lpD3DViewport->SetViewport2(&vport); */ + AppInfo.lpD3DDevice->SetViewport(&vport); +} + +//====================================================================================================== +//====================================================================================================== +void D3DDepthRange (float zNear, float zFar) +{ +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + D3DVIEWPORT2 vport;*/ + D3DVIEWPORT7 vport; + +//03/01/2002 Wendell Buckner +//This wasn't commented in the original code but it was in my genesis 1.0 converted code... +//not sure I should do this. +// vport.dwSize = sizeof(D3DVIEWPORT2); + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + AppInfo.lpD3DViewport->GetViewport2(&vport);*/ + AppInfo.lpD3DDevice->GetViewport(&vport); + +//03/01/2002 Wendell Buckner +//This wasn't commented in the original code but it was in my genesis 1.0 converted code... +//not sure I should do this. +// vport.dvMinZ = (D3DVALUE)(((-1.0) * (zFar + zNear)) / (zFar - zNear)); +// vport.dvMaxZ = (D3DVALUE)(((-1.0) * (zFar + zNear - 2.0)) / (zFar - zNear)); + vport.dvMinZ = zNear; + vport.dvMaxZ = zFar; + + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + AppInfo.lpD3DViewport->SetViewport2(&vport);*/ + AppInfo.lpD3DDevice->SetViewport(&vport); + +} + +static D3DBLEND OldSFunc = D3DBLEND_ONE; +static D3DBLEND OldDFunc = D3DBLEND_ONE; + +//====================================================================================================== +//====================================================================================================== +void D3DBlendFunc (D3DBLEND SFunc, D3DBLEND DFunc) +{ + if (SFunc != OldSFunc) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, SFunc); + OldSFunc = SFunc; + } + if (DFunc != OldDFunc) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, DFunc); + OldDFunc = DFunc; + } + +} + +static BOOL OldBlend = FALSE; + +//====================================================================================================== +//====================================================================================================== +void D3DBlendEnable(BOOL Enable) +{ + if (OldBlend == Enable) + return; + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, Enable); + + OldBlend = Enable; +} + +static BOOL OldWrap = FALSE; + +void D3DTexWrap(DWORD Stage, BOOL Wrap) +{ + if (OldWrap == Wrap) + return; + + OldWrap = Wrap; + + if (Wrap) + { + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); + } + else + { + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); + } +} + +void D3DZWriteEnable (BOOL Enable) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, Enable); +} + +void D3DZFunc (D3DCMPFUNC Func) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, Func); +} + +void D3DZEnable(BOOL Enable) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, Enable); +} + +void D3DPolygonMode (D3DFILLMODE Mode) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID); +} + + + diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3d_fx.h b/G3D/Engine/Drivers/D3D7xDrv/D3d_fx.h new file mode 100644 index 0000000..4cb9047 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3d_fx.h @@ -0,0 +1,59 @@ +/****************************************************************************************/ +/* D3D_Fx.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D renderstate wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_FX_H +#define D3D_FX_H + +#include +#include +#include + +#include "D3D_Main.h" +#include "DCommon.h" + +void D3DSetTexHandle(D3DTEXTUREHANDLE TexHandle); + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +void D3DSetTexture(int32 Stage, LPDIRECT3DTEXTURE2 Texture); */ +void D3DSetTexture(int32 Stage, LPDIRECTDRAWSURFACE7 Texture); + + +void D3DTexturedPolyOld(void *Pnts, int32 NumPoints); +void D3DTexturedPoly(void *Pnts, int32 NumPoints); + +void D3DBilinearFilter(D3DTEXTUREFILTER Min, D3DTEXTUREFILTER Mag); +void D3DBlendEnable(BOOL Enable); + +void D3DBlendFunc (D3DBLEND SFunc, D3DBLEND DFunc); + +void D3DZWriteEnable (BOOL Enable); +void D3DZFunc (D3DCMPFUNC Func); +void D3DZEnable(BOOL Enable); + +void D3DTexWrap(DWORD Stage, BOOL Wrap); + +void D3DPolygonMode (D3DFILLMODE Mode); + +void D3DViewport (int32 x, int32 y, int32 width, int32 height); +void D3DDepthRange (float zNear, float zFar); + +#endif diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3d_main.cpp b/G3D/Engine/Drivers/D3D7xDrv/D3d_main.cpp new file mode 100644 index 0000000..556f9ab --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3d_main.cpp @@ -0,0 +1,3071 @@ +/****************************************************************************************/ +/* D3D_Main.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: DD/D3D wrapper */ +/* 03/01/2002 Wendell Buckner */ +/* This wasn't commented in the original code but it was in my genesis 1.0 converted */ +/* code...not sure I should do this. */ +/* 12/06/2001 Wendell Buckner */ +/* ENHANCEMENT - Allow triple buffering */ +/* 01/24/2002 Wendell Buckner */ +/* Change flags for speed... */ +/* 12/06/2001 Wendell Buckner */ +/* ENHANCEMENT - Allow full-scene anti-aliasing */ +/* 02/28/2001 Wendell Buckner */ +/* Lighting is on by default so turn it off... */ +/* Optimization from GeForce_Optimization2.doc */ +/* 9. Do not duplicate render state commands. Worse is useless renderstates. Do */ +/* not set a renderstate unless it is needed. */ +/* Optimization from GeForce_Optimization2.doc */ +/* Lights */ +/* Apps should be sure to turn off per-vertex color material support when */ +/* appropriate for increased performance. */ +/* Optimization from GeForce_Optimization2.doc */ +/* Lights */ +/* Also turning D3DRENDERSTATE_LOCALVIEWER to false saves transform cycles when exact*/ +/* specular highlights are not necessary. */ +/* 07/16/2000 Wendell Buckner */ +/* Convert to Directx7... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "D3D_Main.h" +#include "D3D_Err.h" +#include "D3D_fx.h" +#include "d3dcache.h" + +#include "Render.h" +#include "D3DCache.h" +#include "THandle.h" +#include "PCache.h" + +#undef ATTEMPT +#define ATTEMPT(x) if (!(x)) goto exit_with_error + +#undef RELEASE +#define RELEASE(x) if (x) { x->Release(); x = NULL; } + +static BOOL bInitDone =FALSE; +#ifdef STRICT +WNDPROC pOldWndProc; +#else +FARPROC pOldWndProc; +#endif + +//================================================================================ +// Globals +//================================================================================ +App_Info AppInfo; // Our global structure that knows all... (once initialized) + +// start 32 bit changes +int BPP32 = 16; // Our bpp variable +int ZbufferD = 16; // our Z buffer depths +FILE *stream; // The variable we open our config file to +int gWidth, gHeight; // Global variables for our width and height +// end 32 bit changes + +#define MAX_DRIVERS 64 + +typedef struct +{ + geBoolean IsPrimary; + GUID Guid; + char Name[MAX_DRIVER_NAME]; +} D3D_DRIVER; + +typedef struct +{ + int32 NumDrivers; + D3D_DRIVER *Drivers; +} DDEnumInfo; + +//================================================================================ +// Local static functions +//================================================================================ +static BOOL D3DMain_CreateD3D(void); +static BOOL D3DMain_EnumDevices(void); +static BOOL D3DMain_CreateViewPort(int w, int h); +static BOOL D3DMain_ClearBuffers(void); +static BOOL OutputDriverInfo(const char *Filename, DDMain_D3DDriver *Driver); +static BOOL D3DMain_RememberOldMode(HWND hWnd); +static BOOL D3DMain_SetDisplayMode(HWND hWnd, int w, int h, int bpp, BOOL FullScreen); +static BOOL D3DMain_PickDevice(void); +static BOOL D3DMain_CreateDevice(void); +static BOOL D3DMain_CreateBuffers(void); +static void D3DMain_DestroyBuffers(void); +static BOOL D3DMain_CreateZBuffer(void); +static void D3DMain_DestroyZBuffer(void); +static BOOL D3DMain_RestoreDisplayMode(void); +static BOOL D3DMain_CreateDDFromName(const char *DriverName); +static geBoolean CreateDDFromDriver(D3D_DRIVER *pDriver); +static geBoolean CreateDDFromName(const char *DriverName, const DDEnumInfo *Info); + +BOOL D3DMain_RestoreAllSurfaces(void) +{ + HRESULT ddrval; + +#ifdef _DEBUG + OutputDebugString("--- D3DMain_RestoreAllSurfaces ---\n"); +#endif + + if (AppInfo.lpDD) + { + if (!D3DMain_SetDisplayMode(AppInfo.hWnd, AppInfo.CurrentWidth, AppInfo.CurrentHeight, AppInfo.CurrentBpp, AppInfo.FullScreen)) + return FALSE; + + // Restore all the surfaces + ddrval = AppInfo.lpDD->RestoreAllSurfaces(); + + if(ddrval!=DD_OK) + { + D3DMain_Log("D3DMain_RestoreAllSurfaces: AppInfo.lpDD->RestoreAllSurfaces() failed:\n %s\n", D3DErrorToString(ddrval)); + return FALSE; + } + } + + // Force an update in the cache system + if (TextureCache) + if (!D3DCache_EvictAllSurfaces(TextureCache)) + return FALSE; + + if (LMapCache) + if (!D3DCache_EvictAllSurfaces(LMapCache)) + return FALSE; + + return TRUE; +} + +//================================================================================ +// BPPToDDBD +// Convert an integer bit per pixel number to a DirectDraw bit depth flag +//================================================================================ +static DWORD BPPToDDBD(int bpp) +{ + switch(bpp) + { + case 1: + return DDBD_1; + case 2: + return DDBD_2; + case 4: + return DDBD_4; + case 8: + return DDBD_8; + case 16: + return DDBD_16; + case 24: + return DDBD_24; + case 32: + return DDBD_32; + default: + assert(!"BOGUS bpp"); + } + + return DDBD_1; // Shutup compiler warning +} + +//================================================================================ +// D3DMain_InitD3D +// Does all what is needed to get an app ready to go at a specified with height +// NOTE - It only makes 16 bit modes availible +//================================================================================ +BOOL D3DMain_InitD3D(HWND hWnd, const char *DriverName, int32 Width, int32 Height) +{ + HRESULT LastError; + SYSTEMTIME Time; + + memset(&AppInfo, 0, sizeof(App_Info)); + + GetSystemTime(&Time); + + unlink(D3DMAIN_LOG_FILENAME); + + D3DMain_Log("=================================================================\n"); + D3DMain_Log(" D3DDrv v%i.%i\n", DRV_VERSION_MAJOR, DRV_VERSION_MINOR); + D3DMain_Log(" Build Date: "__DATE__", Time: "__TIME__"\n"); + D3DMain_Log("=================================================================\n\n"); + + D3DMain_Log("Current Time: %2i:%2i:%2i\n", Time.wHour, Time.wMinute, Time.wSecond); + D3DMain_Log("Current Date: %2i-%2i-%4i\n", Time.wMonth, Time.wDay, Time.wYear); + D3DMain_Log("\n ** D3D Driver Initializing **\n\n"); + + AppInfo.hWnd = hWnd; + + // Create DD + ATTEMPT(D3DMain_CreateDDFromName(DriverName)); + + ATTEMPT(D3DMain_GetTextureMemory()); + + // We must do this after the DD object is created!!! + ATTEMPT(D3DMain_RememberOldMode(hWnd)); // Store old mode + + // Get available fullscreen display modes + ATTEMPT(D3DMain_EnumDisplayModes()); + + // Create D3D, and enum it's devices + ATTEMPT(D3DMain_CreateD3D()); + ATTEMPT(D3DMain_EnumDevices()); + + // start 32 bit changes + // Open the config file and read the bpp variable + stream = fopen("D3D24.ini","r"); + if(stream) + { + fscanf(stream,"%d",&BPP32); + fscanf(stream,"%d",&ZbufferD); + fclose(stream); + } + else + { + BPP32 = 16; + ZbufferD = 16; + } + + // Set our global width and height to the real width and height + gWidth = Width; + gHeight = Height; + + if (Width == -1 && Height == -1) // Window Mode + { + // Force Width/Height to client window area size + Width = AppInfo.OldWindowWidth; + Height = AppInfo.OldWindowHeight; + + ATTEMPT(D3DMain_SetDisplayMode(hWnd, Width, Height, AppInfo.OldBpp, FALSE)); + } + else + { + ATTEMPT(D3DMain_SetDisplayMode(hWnd, Width, Height, BPP32, TRUE)); + } +// end 32 bit changes + + + // Pick a device we will be happy with + ATTEMPT(D3DMain_PickDevice()); + + // Create front/back buffer + ATTEMPT(D3DMain_CreateBuffers()); + + // For some reason, we have to create the zbuffer BEFORE the device??? Why??? + ATTEMPT(D3DMain_CreateZBuffer()); + + // Create the device and viewport + ATTEMPT(D3DMain_CreateDevice()); + ATTEMPT(D3DMain_CreateViewPort(Width, Height)); + + // Get the surface formats for textures, and 2d surfaces + ATTEMPT(D3DMain_GetSurfaceFormats()); + +#if 0 // For selective debugging + AppInfo.CanDoMultiTexture = GE_FALSE; +#else + AppInfo.CanDoMultiTexture = (AppInfo.Drivers[AppInfo.CurrentDriver].MaxSimultaneousTextures > 1) ? GE_TRUE : GE_FALSE; +#endif + + D3DMain_Log("--- D3DMain_SetRenderState --- \n"); + + // Set some defaults render states + LastError = AppInfo.lpD3DDevice->BeginScene(); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: BeginScene failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + LastError = AppInfo.lpD3DDevice->SetCurrentViewport(AppInfo.lpD3DViewport);*/ + LastError = AppInfo.lpD3DDevice->SetViewport(AppInfo.lpD3DViewport); + + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: SetViewport failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + //D3DMain_SetFogEnable(GE_TRUE, 255.0f, 0.0f, 0.0f, 500.0f, 1500.0f); + D3DMain_SetFogEnable(GE_FALSE, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + +/* 02/28/2001 Wendell Buckner + Lighting is on by default so turn it off...*/ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE); + +/* 02/08/2002 Wendell Buckner + Optimization from GeForce_Optimization2.doc + 9. Do not duplicate render state commands. Worse is useless renderstates. Do not set a renderstate unless it is needed. */ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPING,FALSE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_EXTENTS,FALSE); + +/* 02/08/2002 Wendell Buckner + Optimization from GeForce_Optimization2.doc + Lights + Apps should be sure to turn off per-vertex color material support when appropriate for increased performance. */ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_COLORVERTEX,FALSE); + +/* 02/08/2002 Wendell Buckner + Optimization from GeForce_Optimization2.doc + Lights + Also turning D3DRENDERSTATE_LOCALVIEWER to false saves transform cycles when exact specular highlights are not necessary.*/ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_LOCALVIEWER,FALSE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE); + +/* 12/06/2001 Wendell Buckner + ENHANCEMENT - Allow full-scene anti-aliasing + if ( AppInfo.Drivers[AppInfo.CurrentDriver].Desc.dpcLineCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT ) + { + D3DMain_Log("sort independent anti-aliasing available"); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ANTIALIAS,D3DANTIALIAS_SORTINDEPENDENT ); + }*/ + +#if 0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ANTIALIAS, D3DANTIALIAS_SORTINDEPENDENT); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_EDGEANTIALIAS, TRUE); +#endif + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, TRUE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPNEAREST); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_LINEAR); + + LastError = AppInfo.lpD3DDevice->EndScene(); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: EndScene failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.RenderingIsOK = TRUE; + + ATTEMPT(D3DMain_ClearBuffers()); + ATTEMPT(D3DMain_GetTextureMemory()); + + if (!THandle_Startup()) + return GE_FALSE; + + D3DViewport (0, 0, Width, Height); + D3DDepthRange (0.0f, 1.0f); + + D3DMain_Log("\n ** Initialization was successful **\n\n"); + + return TRUE; + + exit_with_error:; + D3DMain_Log(" ** Initialization was NOT successful **\n"); + D3DMain_ShutdownD3D(); + return FALSE; +} + +//================================================================================ +// D3DMain_ShutdownD3D +//================================================================================ +BOOL D3DMain_ShutdownD3D(void) +{ + D3DMain_Log("\n--- D3DMain_ShutdownD3D ---\n"); + + THandle_Shutdown(); + + // Destroys all objects including Direct Draw. + AppInfo.RenderingIsOK = FALSE; + + if (AppInfo.lpD3DViewport) + { + assert(AppInfo.lpD3DDevice); + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + AppInfo.lpD3DDevice->DeleteViewport(AppInfo.lpD3DViewport); */ + AppInfo.lpD3DDevice->Clear(0,0,0,0,0,0); + +//03/01/2002 Wendell Buckner +//This wasn't commented in the original code but it was in my genesis 1.0 converted code... +//not sure I should do this. +// RELEASE(AppInfo.lpD3DViewport); + } + + RELEASE(AppInfo.lpD3DDevice); + +/* 03/09/2002 Wendell Buckner + The BackgroundMaterial variable is a copy of lpD3Device, so don't release it just set it to NULL + RELEASE(AppInfo.BackgroundMaterial); */ + AppInfo.BackgroundMaterial = NULL; + + if (AppInfo.lpZBuffer) + { + assert(AppInfo.lpBackBuffer); + AppInfo.lpBackBuffer->DeleteAttachedSurface(0, AppInfo.lpZBuffer); + RELEASE(AppInfo.lpZBuffer); + } + + if (AppInfo.lpFrontBuffer) + AppInfo.lpFrontBuffer->SetClipper(NULL); + + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); + + D3DMain_RestoreDisplayMode(); + + RELEASE(AppInfo.lpD3D); + RELEASE(AppInfo.lpDD); + + memset(&AppInfo, 0, sizeof(App_Info)); + + D3DMain_Log(" Shutdown was successful...\n\n"); + + return TRUE; +} + +extern uint32 CurrentLRU; +//================================================================================ +//================================================================================ +geBoolean D3DMain_Reset(void) +{ + THandle_Shutdown(); + PCache_Reset(); + + if (!THandle_Startup()) + return GE_FALSE; + + CurrentLRU = 0; + + return GE_TRUE; +} + +//================================================================================ +// D3DMain_Log +//================================================================================ +void D3DMain_Log(LPSTR Str, ... ) +{ + char Buffer[2048]; + FILE *f; + + wvsprintf(Buffer, Str, (char*)(&Str+1)); + + f = fopen(D3DMAIN_LOG_FILENAME, "a+t"); + + if (!f) + return; + + fprintf(f, "%s", Buffer); + + fclose(f); +} + +//================================================================================ +// CompareModes +//================================================================================ +static int CompareModes(const void* element1, const void* element2) +{ + App_Mode *lpMode1, *lpMode2; + + lpMode1 = (App_Mode*)element1; + lpMode2 = (App_Mode*)element2; + + if (lpMode1->Bpp > lpMode2->Bpp) + return -1; + else if (lpMode2->Bpp > lpMode1->Bpp) + return 1; + else if (lpMode1->Width > lpMode2->Width) + return -1; + else if (lpMode2->Width > lpMode1->Width) + return 1; + else if (lpMode1->Height > lpMode2->Height) + return -1; + else if (lpMode2->Height > lpMode1->Height) + return 1; + else + return 0; +} + +//================================================================================ +// EnumDisplayModesCallback +//================================================================================ +static HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC2 pddsd, LPVOID lpContext) +{ + App_Mode *pMode; + + if (!pddsd) + return DDENUMRET_OK; + + if (pddsd->dwWidth > 1280 || pddsd->dwHeight > 960) + return DDENUMRET_OK; + + if (AppInfo.NumModes >= MAX_APP_MODES) + return DDENUMRET_CANCEL; + + pMode = &AppInfo.Modes[AppInfo.NumModes++]; + + // Save this mode at the end of the mode array and increment mode count + pMode->Width = pddsd->dwWidth; + pMode->Height = pddsd->dwHeight; + pMode->Bpp = pddsd->ddpfPixelFormat.dwRGBBitCount; + pMode->ThisDriverCanDo = FALSE; + + return DDENUMRET_OK; +} + +//================================================================================ +// D3DMain_EnumDisplayModes +//================================================================================ +BOOL D3DMain_EnumDisplayModes(void) +{ + HRESULT LastError; + + D3DMain_Log("--- D3DMain_EnumDisplayModes ---\n"); + + // Get a list of available display modes from DirectDraw + AppInfo.NumModes = 0; + + LastError = AppInfo.lpDD->EnumDisplayModes(0, NULL, 0, EnumDisplayModesCallback); + + if(LastError != DD_OK ) + { + D3DMain_Log("EnumDisplayModes failed.\n %s\n", D3DErrorToString(LastError)); + AppInfo.NumModes = 0; + return FALSE; + } + + // Sort the list of display modes + qsort((void *)&AppInfo.Modes[0], (size_t)AppInfo.NumModes, sizeof(App_Mode), CompareModes); + + return TRUE; +} + + + +//================================================================================ +// D3DMain_CreateD3D +//================================================================================ +static BOOL D3DMain_CreateD3D(void) +{ + HRESULT LastError; + + assert(AppInfo.lpDD); + + D3DMain_Log("--- D3DMain_CreateD3D ---\n"); + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + LastError = AppInfo.lpDD->QueryInterface(IID_IDirect3D3, (LPVOID*)&AppInfo.lpD3D); */ + LastError = AppInfo.lpDD->QueryInterface(IID_IDirect3D7, (LPVOID*)&AppInfo.lpD3D); + + if (LastError != DD_OK) + { + D3DMain_Log("Creation of IDirect3D failed.\n %s\n", D3DErrorToString(LastError)); + goto exit_with_error; + } + + return TRUE; + + exit_with_error: + return FALSE; +} +/* +#define MUST_BLEND (D3DPBLENDCAPS_BOTHINVSRCALPHA | \ + D3DPBLENDCAPS_BOTHSRCALPHA | \ + D3DPBLENDCAPS_DESTALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_INVDESTALPHA | \ + D3DPBLENDCAPS_INVDESTCOLOR | \ + D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_INVSRCCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_SRCALPHASAT | \ + D3DPBLENDCAPS_SRCCOLOR | \ + D3DPBLENDCAPS_ZERO) +*/ +#if 0 +#define MUST_BLEND_SRC (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#define MUST_BLEND_DEST (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_SRCCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#else +#define MUST_BLEND_SRC (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#define MUST_BLEND_DEST (D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) +#endif + +//================================================================================ +// EnumDeviceFunc +//================================================================================ + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +static HRESULT WINAPI EnumDeviceFunc(LPGUID lpGuid, LPSTR lpDeviceDescription, + LPSTR lpDeviceName, LPD3DDEVICEDESC lpHWDesc, + LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext)*/ +static HRESULT WINAPI EnumDeviceFunc(LPSTR lpDeviceDescription, + LPSTR lpDeviceName, LPD3DDEVICEDESC7 lpHWDesc, + LPVOID lpContext) +{ + DDMain_D3DDriver *Driver; + BOOL Good; + +// D3DMain_Log("%s\n",lpDeviceDescription); +// D3DMain_Log("%s\n",lpDeviceName); + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + if (!lpGuid|| !lpDeviceDescription || !lpDeviceName || !lpHWDesc || !lpHELDesc) + return (D3DENUMRET_OK);*/ + if (!lpDeviceDescription || !lpDeviceName || !lpHWDesc) + return (D3DENUMRET_OK); + + if (strlen(lpDeviceDescription) >= MAX_DRIVER_NAME) + return (D3DENUMRET_OK); + + if (strlen(lpDeviceName) >= MAX_DRIVER_NAME) + return (D3DENUMRET_OK); + +// D3DMain_Log("--- EnumDeviceFunc ---\n"); + + lpContext = lpContext; + + Good = TRUE; + + AppInfo.CurrentDriver = AppInfo.NumDrivers; + + Driver = &AppInfo.Drivers[AppInfo.NumDrivers]; + + // Record the D3D driver's inforamation + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Guid, lpGuid, sizeof(GUID));*/ + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Guid, &lpHWDesc->deviceGUID, sizeof(GUID)); + lstrcpy(AppInfo.Drivers[AppInfo.NumDrivers].About, lpDeviceDescription); + lstrcpy(AppInfo.Drivers[AppInfo.NumDrivers].Name, lpDeviceName); + + // Is this a hardware device or software emulation? Checking the color + // model for a valid model works. + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + if (lpHWDesc->dcmColorModel) */ + if (lpHWDesc->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) + { + AppInfo.Drivers[AppInfo.NumDrivers].IsHardware = TRUE; +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHWDesc, sizeof(D3DDEVICEDESC));*/ + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHWDesc, sizeof(D3DDEVICEDESC7)); + } + else + { + // Skip if this is not a hardware driver + AppInfo.Drivers[AppInfo.NumDrivers].IsHardware = FALSE; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHWDec, sizeof(D3DDEVICEDESC));*/ + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHWDesc, sizeof(D3DDEVICEDESC7)); + Good = FALSE; + } + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPD3DDEVICEDESC Desc = &AppInfo.Drivers[AppInfo.NumDrivers].Desc; */ + LPD3DDEVICEDESC7 Desc = &AppInfo.Drivers[AppInfo.NumDrivers].Desc; + + + Driver->MaxTextureBlendStages = Desc->wMaxTextureBlendStages; + Driver->MaxSimultaneousTextures = Desc->wMaxSimultaneousTextures; + + if (!(Desc->dwDeviceZBufferBitDepth)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesZBuffer = TRUE; + + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesTextures = TRUE; + + // Skip if it does not support alpha blending + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHA)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesAlpha = TRUE; + + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_TRANSPARENCY)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesTransparency = TRUE; + + //if (!(lpHWDesc->dpcTriCaps.dwTextureAddressCaps & D3DPTADDRESSCAPS_CLAMP)) + // Good = FALSE; + //else + AppInfo.Drivers[AppInfo.NumDrivers].DoesClamping = TRUE; + + if ((Desc->dpcTriCaps.dwSrcBlendCaps & MUST_BLEND_SRC) != MUST_BLEND_SRC) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesSrcBlending = TRUE; + + if ((Desc->dpcTriCaps.dwDestBlendCaps & MUST_BLEND_DEST) != MUST_BLEND_DEST) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesDestBlending = TRUE; + + // Stop as soon as we find a driver that can render into a window + if ((Desc->dwDeviceRenderBitDepth & BPPToDDBD(AppInfo.OldBpp)) && AppInfo.IsPrimary && Good) + { + AppInfo.Drivers[AppInfo.NumDrivers].CanDoWindow = TRUE; + AppInfo.CanDoWindow = TRUE; + } + else + AppInfo.Drivers[AppInfo.NumDrivers].CanDoWindow = FALSE; + + // Store if we can use this driver + AppInfo.Drivers[AppInfo.NumDrivers].CanUse = Good; + + #if 0 + if (AppInfo.LogToFile) + OutputDriverInfo(D3DMAIN_LOG_FILENAME, &AppInfo.Drivers[AppInfo.NumDrivers]); + #endif + + if (!Good) + return (D3DENUMRET_OK); + + // Tell global structure that we found a good device + AppInfo.FoundGoodDevice = TRUE; + + // If all was good, increment the number of drivers + AppInfo.NumDrivers++; + + if (AppInfo.NumDrivers+1 >= DDMAIN_MAX_D3D_DRIVERS) + return (D3DENUMRET_CANCEL); + + return (D3DENUMRET_OK); +} + +//================================================================================ +// EnumDevices +//================================================================================ +static BOOL D3DMain_EnumDevices(void) +{ + HRESULT LastError; + + D3DMain_Log("--- D3DMain_EnumDevices ---\n"); + + AppInfo.NumDrivers = 0; + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + LastError = AppInfo.lpD3D->EnumDevices(EnumDeviceFunc, NULL); */ + LastError = AppInfo.lpD3D->EnumDevices( (LPD3DENUMDEVICESCALLBACK7) EnumDeviceFunc, NULL); + + if (LastError != DD_OK) + { + D3DMain_Log("Enumeration of drivers failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + + AppInfo.CurrentDriver = 0; + + return TRUE; +} + +//================================================================================ +// CreateSurface +//================================================================================ +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +static HRESULT CreateSurface(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE4 FAR *lpDDSurface) */ +static HRESULT CreateSurface(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE7 FAR *lpDDSurface) +{ + HRESULT Result; + + //if (AppInfo.OnlySystemMemory) + // lpDDSurfDesc->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + + Result = AppInfo.lpDD->CreateSurface(lpDDSurfDesc, lpDDSurface, NULL); + + return Result; +} + +//================================================================================ +// GetSurfDesc +//================================================================================ + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +static HRESULT GetSurfDesc(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE4 lpDDSurf)*/ +static HRESULT GetSurfDesc(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE7 lpDDSurf) +{ + HRESULT Result; + + memset(lpDDSurfDesc, 0, sizeof(DDSURFACEDESC2)); + + lpDDSurfDesc->dwSize = sizeof(DDSURFACEDESC2); + + Result = lpDDSurf->GetSurfaceDesc(lpDDSurfDesc); + + return Result; +} + +//================================================================================ +// D3DMain_CreateViewPort +//================================================================================ + +/* 07/16/2000 Wendell Buckner + I assume a local viewport will go out of scope so use a project static/global one... */ +D3DVIEWPORT7 viewData; + +static BOOL D3DMain_CreateViewPort(int w, int h) +{ +/* 07/16/2000 Wendell Buckner + There is no CreateViewport and the following calls to setviewport will fail under DX7! + Convert to Directx7... + LPDIRECT3DVIEWPORT3 lpD3DViewport;*/ + + HRESULT rval; + + D3DMain_Log("--- D3DMain_CreateViewPort ---\n"); + +/* 07/16/2000 Wendell Buckner + There is no CreateViewport and the following calls to setviewport will fail under DX7! + Convert to Directx7... + + // Create the D3D viewport object + rval = AppInfo.lpD3D->CreateViewport(&lpD3DViewport, NULL); + + if (rval != D3D_OK) + { + D3DMain_Log("Create D3D viewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Add the viewport to the D3D device + rval = AppInfo.lpD3DDevice->AddViewport(lpD3DViewport); + if (rval != D3D_OK) + { + D3DMain_Log("Add D3D viewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Setup the viewport for a reasonable viewing area + D3DVIEWPORT2 viewData;*/ + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + memset(&viewData, 0, sizeof(D3DVIEWPORT2)); */ + memset(&viewData, 0, sizeof(D3DVIEWPORT7)); + +// viewData.dwSize = sizeof(D3DVIEWPORT2); + viewData.dwX = viewData.dwY = 0; + viewData.dwWidth = w; + viewData.dwHeight = h; +// viewData.dvClipX = -1.0f; +// viewData.dvClipWidth = 2.0f; +// viewData.dvClipHeight = h * 2.0f / w; +// viewData.dvClipY = viewData.dvClipHeight / 2.0f; + viewData.dvMinZ = 0.0f; + viewData.dvMaxZ = 1.0f; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + rval = lpD3DViewport->SetViewport2(&viewData); */ + rval = AppInfo.lpD3DDevice->SetViewport(&viewData); + + if (rval != D3D_OK) + { + D3DMain_Log("SetViewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + +/* I assume a local viewport will go out of scope so use a project static/global one... + AppInfo.lpD3DViewport = lpD3DViewport;*/ + AppInfo.lpD3DViewport =(LPD3DVIEWPORT7) &viewData; + +/* // Create the material that will be used for the background + { +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + D3DMATERIAL Material; + D3DMATERIALHANDLE MatHandle; */ + D3DMATERIAL7 Material; + + + // Create the material + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + rval = AppInfo.lpD3D->CreateMaterial(&AppInfo.BackgroundMaterial, NULL ); + + if (rval != D3D_OK) + { + D3DMain_Log("D3DMain_CreateViewPort: CreateMaterial failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } */ + AppInfo.BackgroundMaterial = AppInfo.lpD3DDevice; + + + // Fill in the material with the data + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + memset(&Material, 0, sizeof(D3DMATERIAL)); + Material.dwSize = sizeof(D3DMATERIAL); */ + memset(&Material, 0, sizeof(D3DMATERIAL7)); + + Material.dcvDiffuse.r = Material.dcvAmbient.r = 0.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = 0.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = 0.0f; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + Material.dwRampSize = 16L; // A default ramp size */ + + AppInfo.BackgroundMaterial->SetMaterial(&Material); + + // Attach the material to the viewport + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + AppInfo.BackgroundMaterial->GetHandle( AppInfo.lpD3DDevice, &MatHandle); + AppInfo.lpD3DViewport->SetBackground(MatHandle); * + }*/ + + return TRUE; +} + +//================================================================================ +// EnumTextureFormatsCallback +// Record information about each texture format the current D3D driver can +// support. Choose one as the default format and return it through lpContext. +//================================================================================ +static HRESULT CALLBACK EnumTextureFormatsCallback(LPDDPIXELFORMAT lpddpfPixelFormat, LPVOID lpContext) +{ + DDMain_SurfFormat *pTexFormat; + + if(!lpddpfPixelFormat) + return DDENUMRET_OK; + + if (AppInfo.NumTextureFormats+1 >= DDMAIN_MAX_TEXTURE_FORMATS ) + { + return DDENUMRET_CANCEL; + } + + pTexFormat = &AppInfo.TextureFormats[AppInfo.NumTextureFormats]; + + // Clear out this texture format slot + memset(pTexFormat, 0, sizeof(DDMain_SurfFormat)); + + if(lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + { + if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0x8000) + { + if(lpddpfPixelFormat->dwRBitMask != 0x7c00 || + lpddpfPixelFormat->dwGBitMask != 0x3e0 || + lpddpfPixelFormat->dwBBitMask != 0x1f) + return DDENUMRET_OK; + + pTexFormat->HasOneBitAlpha = TRUE; + pTexFormat->HasFourBitAlpha = FALSE; + } + else if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0xf000) + { + if(lpddpfPixelFormat->dwRBitMask != 0xf00 || + lpddpfPixelFormat->dwGBitMask != 0xf0 || + lpddpfPixelFormat->dwBBitMask != 0xf) + return DDENUMRET_OK; + + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = TRUE; + } + else + { + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = FALSE; + } + } + else + { + if(!(lpddpfPixelFormat->dwFlags & DDPF_RGB)) + return DDENUMRET_OK; + + #if 0 + if(lpddpfPixelFormat->dwRGBBitCount != 16) + return DDENUMRET_OK; + + if( (lpddpfPixelFormat->dwRBitMask != 0xf800 && lpddpfPixelFormat->dwRBitMask != 0x7c00) || + (lpddpfPixelFormat->dwGBitMask != 0x7e0 && lpddpfPixelFormat->dwGBitMask != 0x3e0) || + (lpddpfPixelFormat->dwBBitMask != 0x1f)) + return DDENUMRET_OK; + #endif + + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = FALSE; + } + + // Record the PixelFormat of this texture + memcpy(&pTexFormat->ddsd.ddpfPixelFormat, lpddpfPixelFormat, sizeof(DDPIXELFORMAT)); + + AppInfo.NumTextureFormats++; + + return DDENUMRET_OK; +} + +//================================================================================ +// Main_EnumTextureFormats +// Get a list of available texture map formats from the Direct3D driver by +// enumeration. Choose a default format. +//================================================================================ +BOOL Main_EnumTextureFormats(void) +{ + HRESULT LastError; + + assert(AppInfo.lpD3DDevice); + + AppInfo.NumTextureFormats = 0; + + LastError = AppInfo.lpD3DDevice->EnumTextureFormats(EnumTextureFormatsCallback, NULL); + + if (LastError != DD_OK) + { + D3DMain_Log("Main_EnumTextureFormats: Enumeration of texture formats failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + + +//================================================================================ +// EnumSurfaceFormatsCallback +//================================================================================ +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +HRESULT WINAPI EnumSurfaceFormatsCallback(LPDIRECTDRAWSURFACE4 lpDDSurface, LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext) */ +HRESULT WINAPI EnumSurfaceFormatsCallback(LPDIRECTDRAWSURFACE7 lpDDSurface, LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext) + +{ + LPDDPIXELFORMAT lpddpfPixelFormat; + DDMain_SurfFormat *pSurfFormat; + + // Don't need this. + RELEASE(lpDDSurface); + + lpddpfPixelFormat = &lpDDSurfaceDesc->ddpfPixelFormat; + + if(!lpddpfPixelFormat) + return DDENUMRET_OK; + + if (AppInfo.NumSurfFormats+1 >= DDMAIN_MAX_SURFACE_FORMATS ) + return DDENUMRET_CANCEL; + + pSurfFormat = &AppInfo.SurfFormats[AppInfo.NumSurfFormats]; + + // Clear out this texture format slot + memset(pSurfFormat, 0, sizeof(DDMain_SurfFormat)); + + if(lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + { + if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0x8000) + { + // 1555 + if(lpddpfPixelFormat->dwRBitMask != 0x7c00 || + lpddpfPixelFormat->dwGBitMask != 0x3e0 || + lpddpfPixelFormat->dwBBitMask != 0x1f) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = TRUE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + else if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0xf000) + { + // 4444 + if(lpddpfPixelFormat->dwRBitMask != 0xf00 || + lpddpfPixelFormat->dwGBitMask != 0xf0 || + lpddpfPixelFormat->dwBBitMask != 0xf) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = TRUE; + } + else + { + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + } + else + { + if(!(lpddpfPixelFormat->dwFlags & DDPF_RGB)) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + + // Record the PixelFormat of this texture + memcpy(&pSurfFormat->ddsd.ddpfPixelFormat, lpddpfPixelFormat,sizeof(DDPIXELFORMAT)); + + AppInfo.NumSurfFormats++; + + return DDENUMRET_OK; +} + +//================================================================================ +// Main_EnumSurfaceFormats +//================================================================================ +BOOL Main_EnumSurfaceFormats(void) +{ + HRESULT LastError; + + assert(AppInfo.lpDD); + + AppInfo.NumSurfFormats = 0; + + LastError = AppInfo.lpDD->EnumSurfaces(DDENUMSURFACES_DOESEXIST|DDENUMSURFACES_ALL, + NULL, NULL, EnumSurfaceFormatsCallback); + + if (LastError != DD_OK) + { + D3DMain_Log("Main_EnumSurfaceFormats: Enumeration of texture formats failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + + +//----------------------------------------------------------------------------- +// Name: EnumZBufferFormatsCallback() +// Desc: Enumeration function to report valid pixel formats for z-buffers. +//----------------------------------------------------------------------------- +static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf, + VOID* pddpfDesired ) +{ + if( NULL==pddpf || NULL==pddpfDesired ) + return D3DENUMRET_CANCEL; + + // If the current pixel format's match the desired ones (DDPF_ZBUFFER and + // possibly DDPF_STENCILBUFFER), lets copy it and return. This function is + // not choosy...it accepts the first valid format that comes along. + if( pddpf->dwFlags == ((DDPIXELFORMAT*)pddpfDesired)->dwFlags ) + { + memcpy( pddpfDesired, pddpf, sizeof(DDPIXELFORMAT) ); + + // We're happy with a 16-bit z-buffer. Otherwise, keep looking. + if( pddpf->dwZBufferBitDepth == 16 ) + return D3DENUMRET_CANCEL; + } + + return D3DENUMRET_OK; +} + +//================================================================================ +// D3DMain_ClearBuffers +//================================================================================ +static BOOL D3DMain_ClearBuffers(void) +{ + DDSURFACEDESC2 ddsd; + RECT dst; + DDBLTFX ddbltfx; + HRESULT LastError; + + // Find the width and height of the front buffer by getting its + // DDSURFACEDESC2 + if (AppInfo.lpFrontBuffer) + { + LastError = GetSurfDesc(&ddsd, AppInfo.lpFrontBuffer); + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_ClearBuffers: Failure getting the surface description of the front buffer before clearing.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + // Clear the front buffer to black + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(DDBLTFX); + SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight); + +/* 01/24/2002 Wendell Buckner + Change flags for speed... + LastError = AppInfo.lpFrontBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, + &ddbltfx);*/ + LastError = AppInfo.lpFrontBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_DONOTWAIT | DDBLT_ASYNC, + &ddbltfx); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("D3DMain_ClearBuffers: D3DMain_RestoreAllSurfaces failed...\n"); + return FALSE; + } + } + else + { + D3DMain_Log("D3DMain_ClearBuffers: Clearing the front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + } + + if (AppInfo.lpBackBuffer) + { + // Find the width and height of the back buffer by getting its + // DDSURFACEDESC2 + + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_ClearBuffers: Failure while getting the surface description of the back buffer before clearing.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + // Clear the back buffer to black + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(DDBLTFX); + SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight); + +/* 01/24/2002 Wendell Buckner + Change flags for speed... + LastError = AppInfo.lpBackBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, + &ddbltfx); */ + LastError = AppInfo.lpBackBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_DONOTWAIT | DDBLT_ASYNC, + &ddbltfx); + + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("D3DMain_ClearBuffers: D3DMain_RestoreAllSurfaces failed.\n"); + return FALSE; + } + } + else + { + D3DMain_Log("D3DMain_ClearBuffers: Clearing the back buffer failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + } + + return TRUE; +} + +//================================================================================ +// Main_ShowBackBuffer +//================================================================================ +BOOL Main_ShowBackBuffer(void) +{ + HRESULT LastError; + + if (!AppInfo.RenderingIsOK) + return TRUE; + + if (AppInfo.FullScreen) + { + // Flip the back and front buffers + #if 1 + +/* 01/24/2002 Wendell Buckner + Change flags for speed... + LastError = AppInfo.lpFrontBuffer->Flip(AppInfo.lpBackBuffer, DDFLIP_WAIT);*/ + LastError = AppInfo.lpFrontBuffer->Flip(AppInfo.lpBackBuffer, DDFLIP_DONOTWAIT | DDFLIP_NOVSYNC); + + #else +/* 01/24/2002 Wendell Buckner + Change flags for speed... + LastError = AppInfo.lpFrontBuffer->Flip(AppInfo.lpBackBuffer, DDFLIP_NOVSYNC);*/ + LastError = AppInfo.lpFrontBuffer->Flip(AppInfo.lpBackBuffer, DDFLIP_DONOTWAIT | DDFLIP_NOVSYNC); + #endif + + if (LastError == DDERR_SURFACELOST) + { + D3DMain_RestoreAllSurfaces(); + //AppInfo.lpFrontBuffer->Restore(); + //AppInfo.lpBackBuffer->Restore(); + + D3DMain_ClearBuffers(); + + } + else if (LastError == DDERR_WASSTILLDRAWING) + { + } + else if (LastError != DD_OK) + { + D3DMain_Log("Flipping complex display surface failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + } + else + { + RECT FRect, BRect; + + FRect.left = AppInfo.WindowXOffset; + FRect.right = FRect.left + AppInfo.CurrentWidth; + FRect.top = AppInfo.WindowYOffset; + FRect.bottom = FRect.top + AppInfo.CurrentHeight; + + BRect.left = 0; + BRect.right = AppInfo.CurrentWidth; + BRect.top = 0; + BRect.bottom = AppInfo.CurrentHeight; + +/* 03/10/2002 Wendell Buckner + Optimization from GeForce_Optimization2.doc + Procedural Textures + Also, Load is even faster than BLT under Dx7. + * 01/24/2002 Wendell Buckner + Change flags for speed... + LastError = AppInfo.lpFrontBuffer->Blt(&FRect, AppInfo.lpBackBuffer, + &BRect, DDBLT_WAIT, NULL); */ + LastError = AppInfo.lpFrontBuffer->Blt(&FRect, AppInfo.lpBackBuffer, + &BRect, DDBLT_DONOTWAIT | DDBLT_ASYNC, NULL); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("Main_ShowBackBuffer: D3DMain_RestoreAllSurfaces.\n"); + return FALSE; + } + } + else + { + D3DMain_Log("Main_ShowBackBuffer: Blt of back buffer to front buffer failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + } + } + + return TRUE; +} + +//================================================================================ +// Main_ClearBackBuffer +//================================================================================ +BOOL Main_ClearBackBuffer(BOOL Clear, BOOL ClearZ) +{ + int ClearFlags; + D3DRECT Dummy; + HRESULT LastError; + + if (!AppInfo.RenderingIsOK) + return TRUE; + + // Default to clear nothing + ClearFlags = 0; + + // Then set in what callers wants to clear + if (Clear) + ClearFlags |= D3DCLEAR_TARGET; + + if (ClearZ) + ClearFlags |= D3DCLEAR_ZBUFFER; + + Dummy.x1 = Dummy.y1 = 0; + Dummy.x2 = AppInfo.CurrentWidth; + Dummy.y2 = AppInfo.CurrentHeight; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... / + LastError = AppInfo.lpD3DViewport->Clear(1, &Dummy, ClearFlags); + + POTENTIAL GOTCHA + Need to understand this value => 1.0f better, the original code above has it set to 0 but my + sample code won't work with this value set to 0 */ + LastError = AppInfo.lpD3DDevice->Clear( 1, &Dummy, ClearFlags, 0, 1.0f, 0L ); + + + if (LastError != D3D_OK) + { + D3DMain_Log("Viewport clear failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + +//================================================================================ +// Surface manipulation +//================================================================================ + +typedef struct +{ + unsigned char r, g, b; +} MY_D3D_RGB; + +typedef struct +{ + DWORD R_Shift; + DWORD G_Shift; + DWORD B_Shift; + DWORD A_Shift; + + DWORD R_Mask; + DWORD G_Mask; + DWORD B_Mask; + DWORD A_Mask; + + DWORD R_Width; + DWORD G_Width; + DWORD B_Width; + DWORD A_Width; +} D3D_PixelMask; + +//================================================================================ +// GetSurfacePixelMask +//================================================================================ +static void GetSurfacePixelMask(DDSURFACEDESC2 *ddsd, D3D_PixelMask *PixelMask) +{ + DWORD red_mask, grn_mask, blu_mask, a_mask; + DWORD red_shift, grn_shift, blu_shift, a_shift; + DWORD red_width, grn_width, blu_width, a_width; + int i; + + red_mask = ddsd->ddpfPixelFormat.dwRBitMask; + grn_mask = ddsd->ddpfPixelFormat.dwGBitMask; + blu_mask = ddsd->ddpfPixelFormat.dwBBitMask; + a_mask = ddsd->ddpfPixelFormat.dwRGBAlphaBitMask; + + // + // Derive shift, width values from masks + // + + for (i=31; i >= 0; i--) + { + if (red_mask & (1 << i)) + red_shift = i; + + if (grn_mask & (1 << i)) + grn_shift = i; + + if (blu_mask & (1 << i)) + blu_shift = i; + + if (a_mask & (1 << i)) + a_shift = i; + } + + for (i=0; i <= 31; i++) + { + if (red_mask & (1 << i)) + red_width = i - red_shift + 1; + + if (grn_mask & (1 << i)) + grn_width = i - grn_shift + 1; + + if (blu_mask & (1 << i)) + blu_width = i - blu_shift + 1; + + if (a_mask & (1 << i)) + a_width = i - a_shift + 1; + } + // + // Pass all requested values back to the caller + // + + PixelMask->R_Shift = red_shift; + PixelMask->G_Shift = grn_shift; + PixelMask->B_Shift = blu_shift; + PixelMask->A_Shift = a_shift; + + PixelMask->R_Mask = red_mask; + PixelMask->G_Mask = grn_mask; + PixelMask->B_Mask = blu_mask; + PixelMask->A_Mask = a_mask; + + PixelMask->R_Width = red_width; + PixelMask->G_Width = grn_width; + PixelMask->B_Width = blu_width; + PixelMask->A_Width = a_width; +} + +//================================================================================ +// MyRGB +//================================================================================ +static unsigned int MyRGB(DWORD R, DWORD G, DWORD B, D3D_PixelMask *PixelMask) +{ + DWORD R_Left, G_Left, B_Left; + DWORD R_Right, G_Right, B_Right; + + + // Get shift constants for current video mode + R_Left = PixelMask->R_Shift; + G_Left = PixelMask->G_Shift; + B_Left = PixelMask->B_Shift; + + R_Right = 8 - PixelMask->R_Width; + G_Right = 8 - PixelMask->G_Width; + B_Right = 8 - PixelMask->B_Width; + // Shift R,G, and B into one value + return( + (((((unsigned int) R) >> R_Right) << R_Left) & PixelMask->R_Mask) | + (((((unsigned int) G) >> G_Right) << G_Left) & PixelMask->G_Mask) | + (((((unsigned int) B) >> B_Right) << B_Left) & PixelMask->B_Mask) + ); +} + +//========================================================================================== +// D3DMain_GetSurfaceFormats +//========================================================================================== +BOOL D3DMain_GetSurfaceFormats(void) +{ + int32 i; + + D3DMain_Log("--- D3DMain_GetSurfaceFormats ---\n"); + + if (!Main_EnumTextureFormats()) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Main_EnumTextureFormats failed.\n"); + return FALSE; + } + + if (!Main_EnumSurfaceFormats()) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Main_EnumSurfaceFormats failed.\n"); + return FALSE; + } + +#if 1 + for(i = 0; i < AppInfo.NumSurfFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + lpddpfPixelFormat = &AppInfo.SurfFormats[i].ddsd.ddpfPixelFormat; + + if(lpddpfPixelFormat->dwRGBBitCount != AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount) + continue; + + if (lpddpfPixelFormat->dwRGBAlphaBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask) + continue; + if (lpddpfPixelFormat->dwRBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRBitMask) + continue; + if (lpddpfPixelFormat->dwGBitMask != AppInfo.ddsd.ddpfPixelFormat.dwGBitMask) + continue; + if (lpddpfPixelFormat->dwBBitMask != AppInfo.ddsd.ddpfPixelFormat.dwBBitMask) + continue; + + #if 0 // For debugging (This is the surface it is going to use for 2d decals) + D3DMain_Log("Bits: %i, A:%x, R:%x, G:%x, B:%x\n", AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount, + AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwRBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwGBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwBBitMask); + return FALSE; + #endif + + + AppInfo.ddSurfFormat = AppInfo.SurfFormats[i].ddsd; + + break; + } + + if(i == AppInfo.NumSurfFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find a 2d surface format that matches current bit depth.\n"); + return FALSE; + } + +#else + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + lpddpfPixelFormat = &AppInfo.TextureFormats[i].ddsd.ddpfPixelFormat; + + if(lpddpfPixelFormat->dwRGBBitCount != AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount) + continue; + + if (lpddpfPixelFormat->dwRGBAlphaBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask) + continue; + if (lpddpfPixelFormat->dwRBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRBitMask) + continue; + if (lpddpfPixelFormat->dwGBitMask != AppInfo.ddsd.ddpfPixelFormat.dwGBitMask) + continue; + if (lpddpfPixelFormat->dwBBitMask != AppInfo.ddsd.ddpfPixelFormat.dwBBitMask) + continue; + + #if 0 // For debugging (This is the surface it is going to use for 2d decals) + D3DMain_Log("Bits: %i, A:%x, R:%x, G:%x, B:%x\n", AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount, + AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwRBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwGBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwBBitMask); + return FALSE; + #endif + + + AppInfo.ddSurfFormat = AppInfo.TextureFormats[i].ddsd; + + break; + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find a 2d surface format that matches current bit depth.\n"); + return FALSE; + } +#endif + + // Now get the 3d surface formats + + // Get 1555 + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + if(AppInfo.TextureFormats[i].HasOneBitAlpha == TRUE) + { + AppInfo.ddOneBitAlphaSurfFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 1555 texture support.\n"); + return FALSE; + } + + // Get 4444 + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + if(AppInfo.TextureFormats[i].HasFourBitAlpha == TRUE) + { + AppInfo.ddFourBitAlphaSurfFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 4444 texture support.\n"); + return FALSE; + } + + // Get either 555, or 565. + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + if(AppInfo.TextureFormats[i].HasOneBitAlpha == TRUE) + continue; + + if (AppInfo.TextureFormats[i].HasFourBitAlpha == TRUE) + continue; + + lpddpfPixelFormat = &AppInfo.TextureFormats[i].ddsd.ddpfPixelFormat; + + // For now, force 3d textures with RGB only info to be either 565 or 555 + // We could enum all formats and let the caller pick between several different RGB formats... + if (lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + continue; // We don't want any surface that has alpha, just pure RGB... + + if(lpddpfPixelFormat->dwRGBBitCount != 16) + continue; + + if( (lpddpfPixelFormat->dwRBitMask != 0xf800 && lpddpfPixelFormat->dwRBitMask != 0x7c00) || + (lpddpfPixelFormat->dwGBitMask != 0x7e0 && lpddpfPixelFormat->dwGBitMask != 0x3e0) || + (lpddpfPixelFormat->dwBBitMask != 0x1f)) + continue; + + + // This is it + AppInfo.ddTexFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 555 or 565 texture support.\n"); + return FALSE; + } + + Main_BuildRGBGammaTables(1.0f); + + return TRUE; +} + +//========================================================================================== +// Main_CheckDD +// Checks to see if current DD driver has any usable D3D Devices... +//========================================================================================== +BOOL Main_CheckDD(void) +{ + AppInfo.NumDrivers = 0; + AppInfo.CurrentDriver = 0; + AppInfo.FoundGoodDevice = FALSE; + AppInfo.CanDoWindow = FALSE; + + assert(AppInfo.lpDD); + + if (!D3DMain_RememberOldMode(GetDesktopWindow())) + return FALSE; + + memset(AppInfo.Drivers, 0, sizeof(DDMain_D3DDriver)*DDMAIN_MAX_D3D_DRIVERS); + + if (!D3DMain_CreateD3D()) + return FALSE; + + if (!D3DMain_EnumDevices()) // See if we can enumerate at least one good device for this DD Driver + return FALSE; + + if (!AppInfo.FoundGoodDevice) // Return FALSE if not... + return FALSE; + + return TRUE; // Found at least one!!! +} + +//========================================================================================== +// OutputDriverInfo +//========================================================================================== +static BOOL OutputDriverInfo(const char *FileName, DDMain_D3DDriver *Driver) +{ + FILE *f; + SYSTEMTIME Time; + char YesNo[2][10]; + + f = fopen(FileName, "a+t"); + + if (!f) + return FALSE; + + GetSystemTime(&Time); + + strcpy(YesNo[0], "No\n"); + strcpy(YesNo[1], "Yes\n"); + + fprintf(f,"=================================================================\n"); + fprintf(f,"Time: %2i:%2i:%2i\n", Time.wHour, Time.wMinute, Time.wSecond); + fprintf(f,"Date: %2i-%2i-%4i\n", Time.wMonth, Time.wDay, Time.wYear); + + fprintf(f, "DirectDraw Name: \n"); + fprintf(f, " %s\n", AppInfo.DDName); + + fprintf(f, "D3D Driver Name: \n"); + fprintf(f, " %s\n", Driver->Name); + + fprintf(f, "D3D Driver Description: \n"); + fprintf(f, " %s\n", Driver->About); + + fprintf(f, "3D Acceleration : %s", YesNo[Driver->IsHardware]); + fprintf(f, "Texture Support : %s", YesNo[Driver->DoesTextures]); + fprintf(f, "Transparency Support : %s", YesNo[Driver->DoesTransparency]); + fprintf(f, "Alpha Support : %s", YesNo[Driver->DoesAlpha]); + fprintf(f, "UV Clamping Support : %s", YesNo[Driver->DoesClamping]); + fprintf(f, "Src Blending Support : %s", YesNo[Driver->DoesSrcBlending]); + fprintf(f, "Dest Blending Support : %s", YesNo[Driver->DoesDestBlending]); + fprintf(f, "Window Support : %s", YesNo[Driver->CanDoWindow]); + fprintf(f, "Can Use : %s", YesNo[Driver->CanUse]); + + fclose(f); + + return TRUE; +} + +//========================================================================================== +// D3DMain_GetTextureMemory +//========================================================================================== +BOOL D3DMain_GetTextureMemory(void) +{ + + DDSCAPS2 ddsCaps; + DWORD dwTotal; + DWORD dwFree; + HRESULT Error; + + D3DMain_Log("--- D3DMain_GetTextureMemory ---\n"); + + memset(&ddsCaps, 0, sizeof(ddsCaps)); + + //ddsCaps.dwSize = sizeof(DDSCAPS2); + ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + + Error = AppInfo.lpDD->GetAvailableVidMem(&ddsCaps, &dwTotal, &dwFree); + + if(Error !=DD_OK) + { + D3DMain_Log("Getting DD capabilities failed while checking total video memory.\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + AppInfo.VidMemFree = dwFree; + + D3DMain_Log(" Ram free: %i\n", AppInfo.VidMemFree); + + return TRUE; +} + + +//========================================================================================== +//========================================================================================== +void Main_BuildRGBGammaTables(float Gamma) +{ + int32 i, Val; + int32 GammaTable[256]; + D3D_PixelMask PixelMask; + DWORD R_Left, G_Left, B_Left, A_Left; + DWORD R_Right, G_Right, B_Right, A_Right; + + + AppInfo.Gamma = Gamma; + + if (Gamma == 1.0) + { + for (i=0 ; i<256 ; i++) + GammaTable[i] = i; + } + else for (i=0 ; i<256 ; i++) + { + float Ratio = (i+0.5f)/255.5f; + + float RGB = (float)(255.0 * pow((double)Ratio, 1.0/(double)Gamma) + 0.5); + + if (RGB < 0.0f) + RGB = 0.0f; + if (RGB > 255.0f) + RGB = 255.0f; + + GammaTable[i] = (int32)RGB; + } + + GetSurfacePixelMask(&AppInfo.ddTexFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut1.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut1.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut1.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut1.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } + GetSurfacePixelMask(&AppInfo.ddFourBitAlphaSurfFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut2.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut2.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut2.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut2.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } + GetSurfacePixelMask(&AppInfo.ddOneBitAlphaSurfFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut3.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut3.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut3.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut3.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } +} + +//==================================================================================================== +// D3DMain_UpdateWindow +//==================================================================================================== +geBoolean DRIVERCC D3DMain_UpdateWindow(void) +{ + D3DMain_GetClientWindowOffset(AppInfo.hWnd); + return GE_TRUE; +} + +//==================================================================================================== +// D3DMain_SetActive +//==================================================================================================== +geBoolean DRIVERCC D3DMain_SetActive(geBoolean wParam) +{ + if (AppInfo.lpFrontBuffer) + AppInfo.RenderingIsOK = wParam; + + if(AppInfo.RenderingIsOK) // Regaining focus + { + HRESULT Result; + + if (AppInfo.lpFrontBuffer) + { + Result = AppInfo.lpFrontBuffer->IsLost(); + + if(Result == DDERR_SURFACELOST) + { + if(!D3DMain_RestoreAllSurfaces()) + { + OutputDebugString("Couldn't restore surfaces!\n"); + return GE_FALSE; + } + + OutputDebugString("D3DMain_SetActive: Regained Focus...\n"); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); // Dx doesn't restore it + } + else + OutputDebugString("D3DMain_SetActive: No surfaces lost...\n"); + } + } + + return GE_TRUE; +} + +//======================================================================================================== +// D3DMain_SetFogEnable +//======================================================================================================== +geBoolean DRIVERCC D3DMain_SetFogEnable(geBoolean Enable, float r, float g, float b, float Start, float End) +{ +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + D3DMATERIAL Material; */ + D3DMATERIAL7 Material; + + AppInfo.FogEnable = Enable; + AppInfo.FogR = r; + AppInfo.FogG = g; + AppInfo.FogB = b; + AppInfo.FogStart = Start; + AppInfo.FogEnd = End; + + // Fill in the material with the data +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + memset(&Material, 0, sizeof(D3DMATERIAL)); + Material.dwSize = sizeof(D3DMATERIAL); */ + memset(&Material, 0, sizeof(D3DMATERIAL7)); + + if (Enable) + { + Material.dcvDiffuse.r = Material.dcvAmbient.r = r/255.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = g/255.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = b/255.0f; + } + else + { + Material.dcvDiffuse.r = Material.dcvAmbient.r = 0.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = 0.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = 0.0f; + } + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + Material.dwRampSize = 16L; // A default ramp size */ + + AppInfo.BackgroundMaterial->SetMaterial(&Material); + + return GE_TRUE; +} + +//================================================================================ +// D3DMain_GetClientWindowOffset +//================================================================================ +BOOL D3DMain_GetClientWindowOffset(HWND hWnd) +{ + POINT CPoint; + + CPoint.x = CPoint.y = 0; + + ClientToScreen(hWnd, &CPoint); + + AppInfo.WindowXOffset = CPoint.x; + AppInfo.WindowYOffset = CPoint.y; + + return TRUE; +} + +//================================================================================ +// D3DMain_RememberOldMode +//================================================================================ +static BOOL D3DMain_RememberOldMode(HWND hWnd) +{ + DDSURFACEDESC2 ddsd; + HRESULT LastError; + RECT CRect; + + D3DMain_Log("--- D3DMain_RememberOldMode ---\n"); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + + LastError = AppInfo.lpDD->GetDisplayMode(&ddsd); + + if (LastError != DD_OK) + { + D3DMain_Log("Getting the current display mode failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + + GetClientRect(hWnd, &CRect); + + // Get old fulscreen width/height/bpp + AppInfo.OldWidth = ddsd.dwWidth; + AppInfo.OldHeight = ddsd.dwHeight; + AppInfo.OldBpp = ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Get old window width/pos + AppInfo.OldWindowWidth = CRect.right; + AppInfo.OldWindowHeight = CRect.bottom; + + GetWindowRect(hWnd, &CRect); + AppInfo.OldWindowRect = CRect; + + AppInfo.OldGWL_STYLE = GetWindowLong(hWnd, GWL_STYLE); + + D3DMain_GetClientWindowOffset(hWnd); + + return TRUE; +} + +//========================================================================================== +// D3DMain_SetDisplayMode +//========================================================================================== +static BOOL D3DMain_SetDisplayMode(HWND hWnd, int w, int h, int bpp, BOOL FullScreen) +{ + HRESULT LastError; + int DWidth, DHeight; + char YN[2][32]; + + strcpy(YN[0], "NO"); + strcpy(YN[1], "YES"); + + D3DMain_Log("--- D3DMain_SetDisplayMode ---\n"); + D3DMain_Log(" W: %i, H: %i, Bpp: %i, FullScreen: %s\n", w, h, bpp, YN[FullScreen]); + + if (FullScreen) + { + LastError = AppInfo.lpDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);// | DDSCL_ALLOWREBOOT); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to fullscreen failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + LastError = AppInfo.lpDD->SetDisplayMode(w, h, bpp,0,0); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetFullScreenDisplayMode: Mode %dx%dx%d failed\n %s\n", w, h, bpp, D3DErrorToString(LastError)); + return FALSE; + } + + DWidth = GetSystemMetrics(SM_CXSCREEN); + DHeight = GetSystemMetrics(SM_CYSCREEN); + + // + // Set window boundaries to cover entire desktop, and show it + // + SetWindowLong(hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE | WS_POPUP); + + SetWindowLong(hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE & + ~(WS_OVERLAPPED | + WS_CAPTION | + WS_SYSMENU | + WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | + WS_THICKFRAME)); + + + SetWindowPos(AppInfo.hWnd, + HWND_TOP, + 0, + 0, + DWidth, + DHeight, + SWP_NOCOPYBITS | SWP_NOZORDER); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); + } + else + { + LastError = AppInfo.lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to normal failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + + AppInfo.hWnd = hWnd; + AppInfo.CurrentWidth = w; + AppInfo.CurrentHeight = h; + AppInfo.CurrentBpp = bpp; + AppInfo.FullScreen = FullScreen; + + AppInfo.ModeSet = GE_TRUE; + + return TRUE; +} + +//================================================================================ +// D3DMain_PickDevice +//================================================================================ +static BOOL D3DMain_PickDevice(void) +{ + int32 i; + DWORD Depths; + + D3DMain_Log("--- D3DMain_PickDevice ---\n"); + + // Find a device with the same bpp as the mode set + // start 32 bit change + if (gWidth == -1 && gHeight == -1) + { + // Find a device with the same bpp as the mode set + Depths = BPPToDDBD(AppInfo.CurrentBpp); + } + else + { + // Find a device with the same bpp as the mode set + Depths = BPPToDDBD(BPP32); + } + + //Depths = BPPToDDBD(AppInfo.CurrentBpp); +// end 32 bit change + + + for (i = 0; i < AppInfo.NumDrivers; i++) + { + if (!(AppInfo.Drivers[i].IsHardware)) // ONLY hardware + continue; + + // Only choose drivers that can support our draw buffer bpp + if (!(AppInfo.Drivers[i].Desc.dwDeviceRenderBitDepth & Depths)) + continue; + + // Only choose drivers that can create the zbuffer we need +// start 32 bit changes + // Get the Z buffer depth + if ( ZbufferD == 24) + { + // Only choose drivers that can create the zbuffer we need + if (!(AppInfo.Drivers[i].Desc.dwDeviceZBufferBitDepth & DDBD_24)) + continue; + } + else + { + // Only choose drivers that can create the zbuffer we need + if (!(AppInfo.Drivers[i].Desc.dwDeviceZBufferBitDepth & DDBD_16)) + continue; + } + //if (!(AppInfo.Drivers[i].Desc.dwDeviceZBufferBitDepth & DDBD_16)) + //continue; +// end 32 bit changes + + +/* 07/16/2000 Wendell Buckner + POTENTIAL GOTCHA * DOCS SAY DCMCOLORMODEL IS SUPPORTED BUT IT IS NO LONGER AVAILABLE + if (!(AppInfo.Drivers[i].Desc.dcmColorModel & D3DCOLOR_RGB)) + continue; */ + + if (!AppInfo.Drivers[i].CanDoWindow && !AppInfo.FullScreen) + continue; + + // Remember the current driver + AppInfo.CurrentDriver = i; + + return TRUE; + } + + return FALSE; +} + +//================================================================================ +// D3DMain_CreateDevice +//================================================================================ +static BOOL D3DMain_CreateDevice(void) +{ + HRESULT Error; + + D3DMain_Log("--- D3DMain_CreateDevice ---\n"); + + // Release old device + RELEASE(AppInfo.lpD3DDevice); + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + Error = AppInfo.lpD3D->CreateDevice(AppInfo.Drivers[AppInfo.CurrentDriver].Guid, + AppInfo.lpBackBuffer, + &AppInfo.lpD3DDevice,NULL); */ + Error = AppInfo.lpD3D->CreateDevice(AppInfo.Drivers[AppInfo.CurrentDriver].Guid, + AppInfo.lpBackBuffer, + &AppInfo.lpD3DDevice); + + + if (Error != DD_OK) + { + D3DMain_Log("D3DMain_CreateDevice: lpD3D->CreateDevice failed:\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + #if 0 + { + // Get some info from the device + D3DDEVICEDESC hw, sw; + + hw.dwSize = sw.dwSize = D3DDEVICEDESCSIZE; + + AppInfo.lpD3DDevice->GetCaps(&hw, &sw); + } + #endif + + // Get Device Identifier + Error = AppInfo.lpDD->GetDeviceIdentifier(&AppInfo.DeviceIdentifier, 0); + + if (Error != DD_OK) + { + D3DMain_Log("D3DMain_CreateDevice: lpDD->GetDeviceIdentifier failed:\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + // Print the debug ID + D3DMain_Log(" Vender ID = %6i\n", AppInfo.DeviceIdentifier.dwVendorId); + D3DMain_Log(" Device ID = %6i\n", AppInfo.DeviceIdentifier.dwDeviceId); + + return TRUE; +} + +//================================================================================ +// D3DMain_CreateBuffers +//================================================================================ +static BOOL D3DMain_CreateBuffers(void) +{ + DDSURFACEDESC2 ddsd; + DDSCAPS2 ddscaps; + HRESULT LastError; + + D3DMain_Log("--- D3DMain_CreateBuffers ---\n"); + + // Release any old objects that might be lying around. This should have + // already been taken care of, but just in case... + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); + + if (AppInfo.FullScreen) + { + // Create a complex flipping surface for fullscreen mode with one + // back buffer. + memset(&ddsd,0,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | + DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX; + +/* 12/06/2001 Wendell Buckner + ENHANCEMENT - Allow triple buffering + ddsd.dwBackBufferCount = 1; */ + ddsd.dwBackBufferCount = 2; + + + + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + + LastError = CreateSurface(&ddsd, &AppInfo.lpFrontBuffer); + + if(LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n Please restart the program and try another fullscreen mode with less resolution or lower bit depth.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for fullscreen flipping surface failed.\n %s\n", + D3DErrorToString(LastError)); + } + + goto exit_with_error; + } + + // Obtain a pointer to the back buffer surface created above so we + // can use it later. For now, just check to see if it ended up in + // video memory (FYI). + memset(&ddscaps,0,sizeof(DDSCAPS2)); + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + LastError = AppInfo.lpFrontBuffer->GetAttachedSurface(&ddscaps, &AppInfo.lpBackBuffer); + + if(LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: GetAttachedSurface failed to get back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: Failed to get surface description of back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.BackBufferInVideo = + (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + AppInfo.ddsd = ddsd; // Save the format of the back buffer + } + else + { + // In the window case, create a front buffer which is the primary + // surface and a back buffer which is an offscreen plane surface. + + memset(&ddsd,0,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + + LastError = AppInfo.lpDD->CreateSurface(&ddsd, &AppInfo.lpFrontBuffer, NULL); + + if(LastError != DD_OK ) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n To run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for window front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + goto exit_with_error; + } + + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwWidth = AppInfo.CurrentWidth; + ddsd.dwHeight = AppInfo.CurrentHeight; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + + LastError = CreateSurface(&ddsd, &AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n To run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for window back buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + goto exit_with_error; + } + + // Check to see if the back buffer is in video memory (FYI). + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: Failed to get surface description for back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.BackBufferInVideo = (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + // Create the DirectDraw Clipper object and attach it to the window + // and front buffer. + LastError = AppInfo.lpDD->CreateClipper(0, &AppInfo.lpClipper, NULL); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: CreateClipper failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = AppInfo.lpClipper->SetHWnd(0, AppInfo.hWnd); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: Attaching clipper to window failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + + LastError = AppInfo.lpFrontBuffer->SetClipper(AppInfo.lpClipper); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: Attaching clipper to front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.ddsd = ddsd; // Save the format of the back buffer + } + + D3DMain_ClearBuffers(); + + return TRUE; + + exit_with_error: + + RELEASE(AppInfo.lpFrontBuffer); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpClipper); + return FALSE; +} + +//================================================================================ +// D3DMain_DestroyBuffers +//================================================================================ +static void D3DMain_DestroyBuffers(void) +{ + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); +} + +//================================================================================ +// D3DMain_CreateZBuffer +// Create a Z-Buffer of the appropriate depth and attach it to the back buffer. +//================================================================================ +static BOOL D3DMain_CreateZBuffer(void) +{ + DDSURFACEDESC2 ddsd; + HRESULT LastError; + + assert(AppInfo.lpBackBuffer); + + D3DMain_Log("--- D3DMain_CreateZBuffer ---\n"); + + // Release any Z-Buffer that might be around just in case. + RELEASE(AppInfo.lpZBuffer); + + memset(&ddsd, 0 ,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;//DDSD_ZBUFFERBITDEPTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; + ddsd.dwWidth = AppInfo.CurrentWidth; + ddsd.dwHeight = AppInfo.CurrentHeight; + + ddsd.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER; + + // Find a valid zbuffer, from the current device + AppInfo.lpD3D->EnumZBufferFormats(AppInfo.Drivers[AppInfo.CurrentDriver].Guid, EnumZBufferFormatsCallback, + (VOID*)&ddsd.ddpfPixelFormat); + + + if( sizeof(DDPIXELFORMAT) != ddsd.ddpfPixelFormat.dwSize ) + { + D3DMain_Log("CreateZBuffer: No zbuffer found for 3d device.\n"); + return FALSE; + } + + LastError = AppInfo.lpDD->CreateSurface(&ddsd, &AppInfo.lpZBuffer, NULL); + + if(LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + if (AppInfo.FullScreen) + { + D3DMain_Log("CreateZBuffer: There was not enough video memory to create the Z-buffer surface.\n Please try another mode with less resolution.\n"); + } + else + { + D3DMain_Log("CreateZBuffer: There was not enough video memory to create the Z-buffer surface.\n Please try another mode with less resolution.\n"); + } + } + else + { + D3DMain_Log("CreateZBuffer: CreateSurface for Z-buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + + goto exit_with_error; + } + + // Attach the Z-buffer to the back buffer so D3D will find it + LastError = AppInfo.lpBackBuffer->AddAttachedSurface(AppInfo.lpZBuffer); + + if(LastError != DD_OK) + { + D3DMain_Log("CreateZBuffer: AddAttachedBuffer failed for Z-Buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + // Find out if it ended up in video memory. + LastError = GetSurfDesc(&ddsd, AppInfo.lpZBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateZBuffer: Failed to get surface description of Z buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.ZBufferInVideo = (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + return TRUE; + + exit_with_error: + RELEASE(AppInfo.lpZBuffer); + return FALSE; +} + +//================================================================================ +// D3DMain_DestroyZBuffer +//================================================================================ +static void D3DMain_DestroyZBuffer(void) +{ + RELEASE(AppInfo.lpZBuffer) +} + +//================================================================================ +// D3DMain_RestoreDisplayMode +// Does nothing if mode has not been set yet +//================================================================================ +static BOOL D3DMain_RestoreDisplayMode(void) +{ + HRESULT LastError; + + if (!AppInfo.ModeSet) + return TRUE; + + AppInfo.ModeSet = GE_FALSE; + + assert(AppInfo.lpDD); + + if (AppInfo.FullScreen) + { + LastError = AppInfo.lpDD->RestoreDisplayMode(); + + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_RestoreDisplayMode: RestoreDisplayMode failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + LastError = AppInfo.lpDD->SetCooperativeLevel(AppInfo.hWnd, DDSCL_NORMAL); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to normal failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + + // Restore window width/height + SetWindowLong(AppInfo.hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE); + + SetWindowPos(AppInfo.hWnd, + HWND_TOP, + AppInfo.OldWindowRect.left, + AppInfo.OldWindowRect.top, + (AppInfo.OldWindowRect.right - AppInfo.OldWindowRect.left), + (AppInfo.OldWindowRect.bottom - AppInfo.OldWindowRect.top), + SWP_NOCOPYBITS | SWP_NOZORDER); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); + + return TRUE; +} + + +// +// Enum drivers +// + +D3D_DRIVER Drivers[MAX_DRIVERS]; + +//======================================================================================================== +// EnumDriversCB2 +//======================================================================================================== + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +BOOL FAR PASCAL EnumDriversCB2(GUID FAR *lpGUID, LPSTR lpDriverDesc, LPSTR lpDriverName, LPVOID lpContext) */ +BOOL FAR PASCAL EnumDriversCB2(GUID FAR *lpGUID, LPSTR lpDriverDesc, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm) +{ + DDEnumInfo *Info; + D3D_DRIVER *pDriver; + + if (!lpDriverDesc || !lpDriverName) + return (D3DENUMRET_OK); + + if (strlen(lpDriverDesc) + 5 >= MAX_DRIVER_NAME) + return DDENUMRET_OK; + + Info = (DDEnumInfo*)lpContext; + + if (Info->NumDrivers >= MAX_DRIVERS) + return DDENUMRET_CANCEL; + + pDriver = &Info->Drivers[Info->NumDrivers++]; + + if (lpGUID) + { + pDriver->IsPrimary = GE_FALSE; + memcpy(&pDriver->Guid, lpGUID, sizeof(GUID)); + } + else + { + pDriver->IsPrimary = GE_TRUE; + } + + // Save name + sprintf(pDriver->Name, "(D3D)%s", lpDriverDesc); + + return DDENUMRET_OK; +} + +//======================================================================================================== +// EnumSubDrivers2 +//======================================================================================================== +BOOL DRIVERCC EnumSubDrivers2(DRV_ENUM_DRV_CB *Cb, void *Context) +{ + HRESULT hr; + int32 i; + DDEnumInfo Info; + + unlink(D3DMAIN_LOG_FILENAME); + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); */ + hr = DirectDrawEnumerateEx((LPDDENUMCALLBACKEX) EnumDriversCB2, &Info, NULL); + + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_EnumSubDrivers: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + for (i=0; i< Info.NumDrivers; i++) + { + // Create the DD object for this driver + if (!CreateDDFromDriver(&Info.Drivers[i])) + return GE_FALSE; + + if (Main_CheckDD()) + { + if (!Cb(i, Info.Drivers[i].Name, Context)) + { + RELEASE(AppInfo.lpD3D); + AppInfo.lpD3D = NULL; + + //D3DMain_ShutdownD3D(); + RELEASE(AppInfo.lpDD); + AppInfo.lpDD = NULL; + memset(&AppInfo, 0, sizeof(AppInfo)); + break; + } + } + + RELEASE(AppInfo.lpD3D); + AppInfo.lpD3D = NULL; + + //D3DMain_ShutdownD3D(); + RELEASE(AppInfo.lpDD); + AppInfo.lpDD = NULL; + memset(&AppInfo, 0, sizeof(AppInfo)); + } + + //Cb(i, "(D3D)HackDriver", Context); + + return TRUE; +} + +//======================================================================================================== +// EnumModes2 +//======================================================================================================== +BOOL DRIVERCC EnumModes2(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context) +{ + HRESULT hr; + int32 i, Width, Height; + char ModeName[MAX_DRIVER_NAME]; + DDEnumInfo Info; + + //Cb(0, "HackMode 2", 640, 480, Context); + //return GE_TRUE; + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); */ + hr = DirectDrawEnumerateEx((LPDDENUMCALLBACKEX) EnumDriversCB2, &Info, NULL); + + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_EnumModes: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + + if (!CreateDDFromName(DriverName, &Info)) + return GE_FALSE; + + if (!D3DMain_EnumDisplayModes()) + { + D3DMain_ShutdownD3D(); + + D3DMain_Log("D3DMain_EnumModes: D3DMain_EnumDisplayModes failed.\n"); + return FALSE; + } + + for (i=0; i< AppInfo.NumModes; i++) + { + if (AppInfo.Modes[i].Bpp != 16) + continue; + + // Get the width/height of mode + Width = AppInfo.Modes[i].Width; + Height = AppInfo.Modes[i].Height; + + // Make a unique name + sprintf(ModeName, "%ix%i", Width, Height); + + // Call their callback with this driver mode + if (!Cb(i, ModeName, Width, Height, Context)) + { + D3DMain_ShutdownD3D(); + return GE_TRUE; + } + } + + if (AppInfo.CanDoWindow) + { + if (!Cb(i, "WindowMode", -1, -1, Context)) + { + D3DMain_ShutdownD3D(); + return GE_TRUE; + } + } + + D3DMain_ShutdownD3D(); + + return TRUE; +} + +//================================================================================ +// DDEnumCallback +//================================================================================ +static BOOL FAR PASCAL DDEnumCallback( GUID FAR* lpGUID, + LPSTR lpDriverDesc, + LPSTR lpDriverName, + LPVOID lpContext) +{ +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAW4 pDD6; */ + LPDIRECTDRAW7 pDD6; + + DDCAPS DriverCaps, HELCaps; + DD_Enum *DDEnum; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAW pDD1; */ + LPDIRECTDRAW7 pDD1; + + HRESULT hr; + + DDEnum = (DD_Enum*)lpContext; + + if(strncmp(lpDriverDesc, DDEnum->DriverName, strlen(DDEnum->DriverName))) + return DDENUMRET_OK; // Next... This is not the one they wanted + + pDD1 = NULL; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + hr = DirectDrawCreate( lpGUID, &pDD1, NULL ); */ + hr = DirectDrawCreateEx( lpGUID, (void **) &pDD1, IID_IDirectDraw7, NULL ); + + if(FAILED( hr )) + return DDENUMRET_CANCEL; // Assume this is bad, and stop + + assert(pDD1); + + // Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw + // represents the DX6 version of the API. + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + hr = pDD1->QueryInterface( IID_IDirectDraw4, (VOID**)&pDD6); */ + hr = pDD1->QueryInterface( IID_IDirectDraw7, (VOID**)&pDD6); + + // Don't need this anymore + RELEASE(pDD1); + + if( FAILED( hr ) ) + return DDENUMRET_CANCEL; + + memset(&DriverCaps, 0, sizeof(DDCAPS)); + DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + if (FAILED(pDD6->GetCaps(&DriverCaps, &HELCaps))) + { + RELEASE(pDD6); + return DDENUMRET_CANCEL; + } + + // Make sure it's a 3d compatible device + if (!(DriverCaps.dwCaps & DDCAPS_3D)) + { + RELEASE(pDD6); + return DDENUMRET_CANCEL; + } + + if (!lpGUID) + AppInfo.IsPrimary = TRUE; + else + AppInfo.IsPrimary = FALSE; + + DDEnum->lpDD = pDD6; + DDEnum->FoundDD = TRUE; + + return DDENUMRET_CANCEL; // We are done +} + +//================================================================================ +// D3DMain_CreateDDFromName +// Creates DD, searching for the specified DD name using DriverName +//================================================================================ +static BOOL D3DMain_CreateDDFromName(const char *DriverName) +{ + HRESULT hr; + DDCAPS DriverCaps, HELCaps; + DDEnumInfo Info; + + D3DMain_Log("--- D3DMain_CreateDDFromName ---\n"); + + if (strlen(DriverName) >= MAX_DRIVER_NAME) + return GE_FALSE; + + D3DMain_Log(" Name: %s\n", DriverName); + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + hr = DirectDrawEnumerate(EnumDriversCB2, &Info);; */ + hr = DirectDrawEnumerateEx((LPDDENUMCALLBACKEX) EnumDriversCB2, &Info, NULL); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_CreateDDFromName: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + { + char TempName[1024]; + + sprintf(TempName, "(D3D)%s", DriverName); + + if (!CreateDDFromName(TempName, &Info)) + return GE_FALSE; + } + + assert(AppInfo.lpDD); + + memset(&DriverCaps, 0, sizeof(DDCAPS)); + DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + if (FAILED(AppInfo.lpDD->GetCaps(&DriverCaps, &HELCaps))) + { + D3DMain_Log("D3DMain_CreateDDFromName: GetCaps failed.\n"); + D3DMain_ShutdownD3D(); + return FALSE; + } + + if (DriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED) + D3DMain_Log(" DDCAPS2_CANRENDERWINDOWED : YES\n"); + else + D3DMain_Log(" DDCAPS2_CANRENDERWINDOWED : NO\n"); + + if (DriverCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) + D3DMain_Log(" DDCAPS2_NO2DDURING3DSCENE : YES\n"); + else + D3DMain_Log(" DDCAPS2_NO2DDURING3DSCENE : NO\n"); + + // Save the DD object + strcpy(AppInfo.DDName, DriverName); + + return TRUE; +} + +//======================================================================================================== +// CreateDDFromDriver +//======================================================================================================== +static geBoolean CreateDDFromDriver(D3D_DRIVER *pDriver) +{ +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAW pDD1; */ + LPDIRECTDRAW7 pDD1; + HRESULT hr; + + AppInfo.IsPrimary = pDriver->IsPrimary; + + + if (pDriver->IsPrimary) + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAW pDD1; + hr = DirectDrawCreate(NULL, &pDD1, NULL ); + else + hr = DirectDrawCreate(&pDriver->Guid, &pDD1, NULL );*/ + hr = DirectDrawCreateEx(NULL, (void **) &pDD1, IID_IDirectDraw7, NULL ); + else + hr = DirectDrawCreateEx(&pDriver->Guid, (void **) &pDD1, IID_IDirectDraw7, NULL ); + + if( FAILED( hr ) ) + return GE_FALSE; + + // Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw + // represents the DX6 version of the API. +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAW pDD1; + hr = pDD1->QueryInterface(IID_IDirectDraw4, (VOID**)&AppInfo.lpDD);*/ + hr = pDD1->QueryInterface(IID_IDirectDraw7, (VOID**)&AppInfo.lpDD); + + // Don't need this guy anymore + RELEASE(pDD1); + + if(FAILED(hr)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +// CreateDDFromName +//======================================================================================================== +static geBoolean CreateDDFromName(const char *DriverName, const DDEnumInfo *Info) +{ + int32 i; + + for (i=0; i < Info->NumDrivers; i++) + { + if (!strcmp(Info->Drivers[i].Name, DriverName)) + break; + } + + if (i == Info->NumDrivers) + return GE_FALSE; + + // Create the DD object for this driver + if (!CreateDDFromDriver(&Info->Drivers[i])) + return GE_FALSE; + + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3d_main.h b/G3D/Engine/Drivers/D3D7xDrv/D3d_main.h new file mode 100644 index 0000000..f421ddf --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3d_main.h @@ -0,0 +1,257 @@ +/****************************************************************************************/ +/* D3D_Main.h */ +/* */ +/* Author: John Pollard */ +/* Description: DD/D3D wrapper */ +/* 07/16/2000 Wendell Buckner */ +/* Convert to Directx7... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_MAIN_H +#define D3D_MAIN_H + +#include +#include +#include + +#define INITGUID + +#include "DCommon.h" + +#define MAX_APP_MODES 50 +#define DDMAIN_MAX_D3D_DRIVERS 10 +#define DDMAIN_MAX_TEXTURE_FORMATS 128 +#define DDMAIN_MAX_SURFACE_FORMATS 128 + +#define D3DMAIN_LOG_FILENAME "D3DDrv.Log" + +#define MAX_DRIVER_NAME 1024 + +//================================================================================ +// Structure defs +//================================================================================ + +typedef struct +{ + char Name[MAX_DRIVER_NAME]; // Short name of the driver + char About[MAX_DRIVER_NAME]; // Short string about the driver + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + D3DDEVICEDESC Desc; // D3DDEVICEDESC for complete information */ + D3DDEVICEDESC7 Desc; // D3DDEVICEDESC for complete information + + GUID Guid; // it's GUID + BOOL IsHardware; // does this driver represent a hardware device? + BOOL DoesTextures; // does this driver do texture mapping? + BOOL DoesZBuffer; // can this driver use a z-buffer? + BOOL CanDoWindow; // can it render to Window's display depth? + BOOL DoesTransparency; + BOOL DoesAlpha; + BOOL DoesClamping; + BOOL DoesSrcBlending; + BOOL DoesDestBlending; + + WORD MaxTextureBlendStages; + WORD MaxSimultaneousTextures; + + BOOL CanUse; // We can use this driver +} DDMain_D3DDriver; + +typedef struct +{ + int32 Width; // width + int32 Height; // height + int32 Bpp; // bits per pixel + BOOL ThisDriverCanDo; // == TRUE if d3d driver can render into +} App_Mode; + +typedef struct +{ + DDSURFACEDESC2 ddsd; // DDSURFACEDESC for complete information + BOOL HasOneBitAlpha; + BOOL HasFourBitAlpha; +} DDMain_SurfFormat; + +typedef struct +{ + uint32 R[256]; + uint32 G[256]; + uint32 B[256]; + uint32 A[256]; +} RGB_LUT; + +// App_Info, used for everything global. +typedef struct +{ + // Window info + HWND hWnd; // Handle to parent Window + + DDSURFACEDESC2 ddsd; + + // Mode that we were in before initializing + int32 OldWidth; // Old screen width + int32 OldHeight; + int32 OldBpp; + + int32 CurrentWidth; + int32 CurrentHeight; + int32 CurrentBpp; + + int32 OldWindowWidth; // Old client width + int32 OldWindowHeight; + int32 WindowXOffset; + int32 WindowYOffset; + + RECT OldWindowRect; + ULONG OldGWL_STYLE; + + geBoolean ModeSet; + + char DDName[MAX_DRIVER_NAME]; // Have no idea how big to make this. Anyone? + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAW4 lpDD; // The current initialized DD object + LPDIRECT3D3 lpD3D; // The current initialized D3D object + LPDIRECTDRAWSURFACE4 lpFrontBuffer; // front buffer surface + LPDIRECTDRAWSURFACE4 lpBackBuffer; // back buffer surface + LPDIRECTDRAWSURFACE4 lpZBuffer; // z-buffer surface */ + + LPDIRECTDRAW7 lpDD; // The current initialized DD object + LPDIRECT3D7 lpD3D; // The current initialized D3D object + LPDIRECTDRAWSURFACE7 lpFrontBuffer; // front buffer surface + LPDIRECTDRAWSURFACE7 lpBackBuffer; // back buffer surface + LPDIRECTDRAWSURFACE7 lpZBuffer; // z-buffer surface + + + + LPDIRECTDRAWCLIPPER lpClipper; // Clipper in windowed case + BOOL BackBufferInVideo; // back buf in video mem? + BOOL ZBufferInVideo; // is Z-buf in video mem? + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECT3DDEVICE3 lpD3DDevice; // D3D device + LPDIRECT3DVIEWPORT3 lpD3DViewport; // D3D viewport + LPDIRECT3DMATERIAL3 BackgroundMaterial; */ + LPDIRECT3DDEVICE7 lpD3DDevice; // D3D device + LPD3DVIEWPORT7 lpD3DViewport; // D3D viewport + LPDIRECT3DDEVICE7 BackgroundMaterial; + + // 2d surface format (for blt'ing to the display) + DDSURFACEDESC2 ddSurfFormat; // 555 or 565 surface desc + + // Texture formats (for the D3D device) + DDSURFACEDESC2 ddTexFormat; // 555 or 565 surface desc + DDSURFACEDESC2 ddFourBitAlphaSurfFormat; // 4444 surface desc + DDSURFACEDESC2 ddOneBitAlphaSurfFormat; // 1555 surface desc + + RGB_LUT Lut1; + RGB_LUT Lut2; + RGB_LUT Lut3; + + BOOL IsPrimary; // + BOOL FullScreen; + + int32 NumModes; + App_Mode Modes[MAX_APP_MODES]; + + int32 NumDrivers; + DDMain_D3DDriver Drivers[DDMAIN_MAX_D3D_DRIVERS]; + int32 CurrentDriver; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + DDDEVICEIDENTIFIER DeviceIdentifier; */ + DDDEVICEIDENTIFIER2 DeviceIdentifier; + + // Surface formats + int32 NumSurfFormats; // Num 2D texture formats avail (from DD4 object) + DDMain_SurfFormat SurfFormats[DDMAIN_MAX_SURFACE_FORMATS]; + + // Texture formats + int32 NumTextureFormats; // Num 3D texture formats avail (from device) + DDMain_SurfFormat TextureFormats[DDMAIN_MAX_TEXTURE_FORMATS]; + + BOOL LogToFile; + BOOL FoundGoodDevice; + BOOL CanDoWindow; + + BOOL RenderingIsOK; + + DWORD VidMemFree; + + float Gamma; + BOOL GammaChanged; + + geBoolean CanDoMultiTexture; + + geBoolean FogEnable; + float FogStart; + float FogEnd; + float FogR; + float FogG; + float FogB; + + // DD / D3D Flags + uint32 Flags; +} App_Info; + +// DD enum strcuture. Used when enuming dd +typedef struct +{ +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAW4 lpDD; */ + LPDIRECTDRAW7 lpDD; + + char DriverName[MAX_DRIVER_NAME]; + BOOL FoundDD; +} DD_Enum; + +//================================================================================ +// Globals +//================================================================================ +extern App_Info AppInfo; // Our global structure that knows all... (once initialized) + +//================================================================================ +// Global functions +//================================================================================ +BOOL D3DMain_InitD3D(HWND hWnd, const char *DriverName, int32 Width, int32 Height); +BOOL D3DMain_ShutdownD3D(void); +geBoolean D3DMain_Reset(void); +void D3DMain_Log(LPSTR Str, ... ); +BOOL D3DMain_RestoreAllSurfaces(void); + +BOOL Main_EnumTextureFormats(void); +BOOL D3DMain_EnumDisplayModes(void); +BOOL Main_ClearBackBuffer(BOOL Clear, BOOL ClearZ); +BOOL Main_ShowBackBuffer(void); + +BOOL D3DMain_GetSurfaceFormats(void); + +BOOL Main_CheckDD(void); +BOOL D3DMain_GetTextureMemory(void); +void Main_BuildRGBGammaTables(float Gamma); + +BOOL D3DMain_GetClientWindowOffset(HWND hWnd); +geBoolean DRIVERCC D3DMain_UpdateWindow(void); +geBoolean DRIVERCC D3DMain_SetActive(geBoolean wParam); +geBoolean DRIVERCC D3DMain_SetFogEnable(geBoolean Enable, float r, float g, float b, float Start, float End); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3dcache.cpp b/G3D/Engine/Drivers/D3D7xDrv/D3dcache.cpp new file mode 100644 index 0000000..591f40d --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3dcache.cpp @@ -0,0 +1,823 @@ +/****************************************************************************************/ +/* D3DCache.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager */ +/* */ +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include +#include + +#include "D3DCache.h" + +// Cache types are just the different types of textures +// Texutres may vary from width/height/num miplevels/etc... +// Cache types is just a way to combine them to similar types... +#define D3DCACHE_MAX_CACHE_TYPES 128 + +//======================================================================================================== +//======================================================================================================== +typedef struct D3DCache_Type +{ + int32 Log; + int32 Width; // Width/Height + int32 Height; + int32 NumMipLevels; + int32 Stage; + int32 RefCount; // How many references to this cache_type + + DDSURFACEDESC2 ddsd; // DD surface description + + D3DCache_Slot *Slots; // Cache slots for this Cache type + int32 NumUsedSlots; // Number of slots being used + + D3DCache_Type *SelfCheck; + D3DCache *Cache; +} D3DCache_Type; + +typedef struct D3DCache +{ + struct D3DCache *SelfCheck; + + char Name[D3DCACHE_MAX_NAME]; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAW4 lpDD; // DD object for the cache manager */ + LPDIRECTDRAW7 lpDD; // DD object for the cache manager + + + DDMemMgr_Partition *Partition; + + geBoolean UseStages; + + D3DCache_Type CacheTypes[D3DCACHE_MAX_CACHE_TYPES]; // CacheTypes +} D3DCache; + +typedef struct D3DCache_Slot +{ + struct D3DCache_Slot *SelfCheck; + + D3DCache_Type *CacheType; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this slot + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface */ + LPDIRECTDRAWSURFACE7 Surface; // The DD surface for this slot + LPDIRECTDRAWSURFACE7 Texture; // The texture interface to the surface + + uint32 LRU; // Current LRU for cache slot + + void *UserData; + +} D3DCache_Slot; + +//======================================================================================================== +//======================================================================================================== + +//======================================================================================================== +// D3DCache_Create +//======================================================================================================== + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW4 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages) */ +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW7 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages) +{ + D3DCache *Cache; + + assert(strlen(Name) < D3DCACHE_MAX_NAME); + + Cache = (D3DCache*)malloc(sizeof(D3DCache)); + + if (!Cache) + return NULL; + + memset(Cache, 0, sizeof(D3DCache)); + + Cache->lpDD = lpDD; + + Cache->Partition = Partition; + + Cache->UseStages = UseStages; + + Cache->SelfCheck = Cache; + + strcpy(Cache->Name, Name); + + return Cache; +} + +//======================================================================================================== +// D3DCache_Destroy +//======================================================================================================== +void D3DCache_Destroy(D3DCache *Cache) +{ + assert(Cache); + + D3DCache_FreeAllSlots(Cache); + + free(Cache); +} + +//======================================================================================================== +// D3DCache_IsValid +//======================================================================================================== +geBoolean D3DCache_IsValid(D3DCache *Cache) +{ + if (!Cache) + return GE_FALSE; + + if (Cache->SelfCheck != Cache) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +geBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + int32 s; + + if (!pCacheType->RefCount) + continue; + + assert(D3DCache_TypeIsValid(pCacheType)); + + for (pSlot = pCacheType->Slots, s=0; sNumUsedSlots; s++, pSlot++) + { + D3DCache_SlotSetUserData(pSlot, NULL); + } + } + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + continue; + + assert(D3DCache_TypeIsValid(pCacheType)); + + if (pCacheType->Width != Width) + continue; + if (pCacheType->Height != Height) + continue; + + if (pCacheType->NumMipLevels != NumMipLevels) + continue; + + if (pCacheType->Stage != Stage) + continue; + + if (memcmp(&pCacheType->ddsd, ddsd, sizeof(DDSURFACEDESC2))) + continue; + + return pCacheType; // Found a match + } + + return NULL; // Cache Type not found!!! +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + break; + } + + if (i == D3DCACHE_MAX_CACHE_TYPES) // No types left + return NULL; + + assert(pCacheType->Slots == NULL); + assert(pCacheType->NumUsedSlots == 0); + + pCacheType->Width = Width; + pCacheType->Height = Height; + pCacheType->NumMipLevels = NumMipLevels; + pCacheType->Stage = Stage; + pCacheType->ddsd = *ddsd; + + pCacheType->SelfCheck = pCacheType; + pCacheType->Cache = Cache; + + pCacheType->Log = GetLog(Width, Height); + + // Found one + pCacheType->RefCount++; + + return pCacheType; +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + D3DCache_Type *CacheType; + + assert(D3DCache_IsValid(Cache)); + + CacheType = D3DCache_FindCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd); + + if (CacheType) + { + CacheType->RefCount++; + return CacheType; + } + + // Could not find one allready in the list, so add a new one... + return D3DCache_InsertCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd); +} + +//======================================================================================================== +// D3DCache_TypeDestroy +//======================================================================================================== +void D3DCache_TypeDestroy(D3DCache_Type *CacheType) +{ + assert(CacheType->RefCount > 0); + assert(D3DCache_TypeIsValid(CacheType)); + + CacheType->RefCount--; + + if (CacheType->RefCount == 0) + { + if (CacheType->Slots) + { + D3DCache_Slot *pSlot; + int32 k; + + // Go through each slot, and free all the surfaces on them + for (pSlot = CacheType->Slots, k=0; k< CacheType->NumUsedSlots; k++, pSlot++) + { + assert(D3DCache_SlotIsValid(pSlot)); + assert(pSlot->Surface); + assert(pSlot->Texture); + +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. + if (pSlot->Texture) + pSlot->Texture->Release();*/ + if (pSlot->Surface) + pSlot->Surface->Release(); + } + + free(CacheType->Slots); + CacheType->Slots = NULL; + CacheType->NumUsedSlots = 0; + } + } +} + +//======================================================================================================== +// D3DCache_TypeIsValid +//======================================================================================================== +geBoolean D3DCache_TypeIsValid(D3DCache_Type *Type) +{ + if (!Type) + return GE_FALSE; + + if (Type->SelfCheck != Type) + return GE_FALSE; + + if (!D3DCache_IsValid(Type->Cache)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_FreeAllSlots +//======================================================================================================== +geBoolean D3DCache_FreeAllSlots(D3DCache *Cache) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + int32 k; + + assert(pCacheType->RefCount >= 0); + + if (pCacheType->RefCount == 0) + { + assert(pCacheType->Slots == NULL); + continue; + } + + assert(D3DCache_TypeIsValid(pCacheType)); + + // Go through each slot, and free all the surfaces on them + for (pSlot = pCacheType->Slots, k=0; k< pCacheType->NumUsedSlots; k++, pSlot++) + { + assert(D3DCache_SlotIsValid(pSlot)); + assert(pSlot->Surface); + assert(pSlot->Texture); + +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. + if (pSlot->Texture) + pSlot->Texture->Release();*/ + if (pSlot->Surface) + pSlot->Surface->Release(); + } + + if (pCacheType->Slots) + free(pCacheType->Slots); + + pCacheType->Slots = NULL; + pCacheType->NumUsedSlots = 0; + } + + DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_WriteToFile +//======================================================================================================== +geBoolean D3DCache_WriteToFile(D3DCache *Cache, const char *FileName, geBoolean Append) +{ + int32 i; + D3DCache_Type *pCacheType; + int32 TotalRef, TotalUsed; + SYSTEMTIME Time; + FILE *f; + + if (Append) + f = fopen(FileName, "a+t"); + else + f = fopen(FileName, "w"); + + if (!f) + return GE_FALSE; + + GetSystemTime(&Time); + + fprintf(f, "=======================================================\n"); + fprintf(f, "Date: %i/%i/%i, Time: %i:%i\n", Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute); + fprintf(f, "Cache Name: %s\n", Cache->Name); + fprintf(f, "Total Mem: %5i\n", DDMemMgr_PartitionGetTotalMem(Cache->Partition)); + fprintf(f, "Free Mem: %5i\n", DDMemMgr_PartitionGetFreeMem(Cache->Partition)); + fprintf(f, " --- Slots ---\n"); + + TotalRef = TotalUsed = 0; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (!pCacheType->RefCount) + continue; + + fprintf(f, "Width: %3i, Height %3i, Mips: %2i, Stage: %2i, Ref: %4i, Used: %4i\n", + pCacheType->Width, pCacheType->Height, pCacheType->NumMipLevels, pCacheType->Stage, pCacheType->RefCount, pCacheType->NumUsedSlots); + + TotalRef += pCacheType->RefCount; + TotalUsed += pCacheType->NumUsedSlots; + } + + fprintf(f, "Total Ref: %4i, Total Used: %4i\n", TotalRef, TotalUsed); + + fclose(f); + + return GE_TRUE; +} + +static geBoolean AppendHack = GE_FALSE; + +// HACK!!!! +void D3DMain_Log(LPSTR Str, ... ); +//======================================================================================================== +// D3DCache_AdjustSlots +//======================================================================================================== +geBoolean D3DCache_AdjustSlots(D3DCache *Cache, const int32 *MaxTable, geBoolean UsePartition) +{ + D3DCache_Type *pCacheType; + int32 i, Total, NumPasses; + + assert(D3DCache_IsValid(Cache)); + + D3DCache_FreeAllSlots(Cache); // Just get rid of everything for now... + DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager + + Total = 0; + NumPasses = 0; + + while(1) + { + D3DCache_Slot *LastSlot; + + LastSlot = NULL; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + uint32 Size, Width, Height, Result; + + if (pCacheType->RefCount <= 0) + { + assert(pCacheType->Slots == NULL); + continue; + } + + if (pCacheType->NumUsedSlots >= pCacheType->RefCount) + continue; // This is all we need for this slot... + + if (pCacheType->NumUsedSlots >= MaxTable[pCacheType->Log]) + continue; + + if (!pCacheType->Slots) // If no slots have been allocated, allocate them now... + { + pCacheType->Slots = (D3DCache_Slot*)malloc(sizeof(D3DCache_Type)*pCacheType->RefCount); + memset(pCacheType->Slots, 0, sizeof(D3DCache_Type)*pCacheType->RefCount); + } + + Width = pCacheType->Width; + Height = pCacheType->Height; + + Size = Width*Height*(pCacheType->ddsd.ddpfPixelFormat.dwRGBBitCount>>3); // (BitCount/8) + + if (UsePartition) + { + if (!DDMemMgr_PartitionAllocMem(Cache->Partition, Size)) + { + LastSlot = NULL; // Make a complete stop + break; // No more memory in the partition, stop now... + } + } + + pSlot = &pCacheType->Slots[pCacheType->NumUsedSlots]; + pSlot->SelfCheck = pSlot; + + pSlot->CacheType = pCacheType; + + // Allocate surfaces now + Result = D3DCache_SetupSlot(Cache, pSlot, Width, Height, &pCacheType->ddsd, Cache->UseStages, pCacheType->Stage); + + if (!Result) + { + memset(pSlot, 0, sizeof(D3DCache_Slot)); + break; + } + else if (Result == -1) + { + D3DMain_Log("D3DCache_AdjustSlots: D3DCache_SetupSlot failed.\n"); + return GE_FALSE; + } + + pCacheType->NumUsedSlots++; + Total++; + + LastSlot = pSlot; + } + + NumPasses++; + + if (!LastSlot) // Nothing was allocated on that pass, so assume we are out of memory + break; + } + + pCacheType = Cache->CacheTypes; + + // Go through one last time, and make sure all got allocated + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (pCacheType->RefCount <= 0) + { + assert(pCacheType->Slots == NULL); + continue; + } + + if (pCacheType->NumUsedSlots <= 0) + { + D3DMain_Log("D3DCache_AdjustSlots: Out of ram creating surfaces for cache.\n"); + D3DMain_Log("D3DCache_AdjustSlots: Pick a display mode with a smaller resolution.\n"); + return GE_FALSE; // Not all slots with refs got a texture + } + + assert(pCacheType->Slots != NULL); + } + + D3DCache_WriteToFile(Cache, "D3DCache.Log", AppendHack); + AppendHack = GE_TRUE; + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_SlotIsValid +//======================================================================================================== +geBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot) +{ + if (!Slot) + return GE_FALSE; + + if (Slot->SelfCheck != Slot) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// D3DCache_SetupSlot +// +// Returns -1 on failure +// Returns 0 on out of memory +// Returns 1 on success +//===================================================================================== +int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, geBoolean UseStage, int32 Stage) +{ +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAWSURFACE4 Surface; */ + LPDIRECTDRAWSURFACE7 Surface; + + DDSURFACEDESC2 ddsd; + HRESULT Hr; + + assert(D3DCache_IsValid(Cache)); + assert(D3DCache_SlotIsValid(Slot)); + + memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + + if (UseStage) + ddsd.dwFlags |= DDSD_TEXTURESTAGE; + + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_HINTDYNAMIC; + ddsd.ddsCaps.dwCaps3 = 0; + ddsd.ddsCaps.dwCaps4 = 0; + ddsd.dwHeight = Width; + ddsd.dwWidth = Height; + + ddsd.dwTextureStage = Stage; + + Hr = Cache->lpDD->CreateSurface(&ddsd, &Surface, NULL); + + if(Hr != DD_OK) + { + if (Hr == DDERR_OUTOFVIDEOMEMORY) + { + return 0; + } + + return -1; + } + + Slot->Surface = Surface; + + // Set the color key +#if 0 + { + DDCOLORKEY CKey; + + // Create the color key for this surface + CKey.dwColorSpaceLowValue = 1; + CKey.dwColorSpaceHighValue = 1; + + if (Slot->Surface->SetColorKey(DDCKEY_SRCBLT , &CKey) != DD_OK) + { + Slot->Surface->Release(); + Slot->Surface = NULL; + return -1; + } + } + #endif + +/* 02/25/2001 Wendell Buckner + This texture pointer is no longer valid under directx 7. Set it to TRUE so there is + something there when the code does assert checks. + Hr = Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Slot->Texture); + + if(Hr != DD_OK) + { + Surface->Release(); + return -1; + }*/ + Slot->Texture = Surface; + + return 1; // All good dude +} + + +//======================================================================================================== +// D3DCache_TypeFindSlot +//======================================================================================================== +D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType) +{ + D3DCache_Slot *pBestSlot, *pSlot; + uint32 BestLRU; + int32 i; + + assert(D3DCache_TypeIsValid(CacheType)); + + assert(CacheType->Slots); + + pSlot = CacheType->Slots; + pBestSlot = pSlot; + BestLRU = pBestSlot->LRU; + + for (i=0; i< CacheType->NumUsedSlots; i++, pSlot++) + { + assert(D3DCache_SlotIsValid(pSlot)); + + if (pSlot->LRU < BestLRU) + { + pBestSlot = pSlot; + BestLRU = pSlot->LRU; + } + } + + pBestSlot->LRU = 0; + pBestSlot->UserData = NULL; + + return pBestSlot; +} + +//======================================================================================================== +// D3DCache_SlotSetUserData +//======================================================================================================== +void D3DCache_SlotSetUserData(D3DCache_Slot *Slot, void *UserData) +{ + assert(D3DCache_SlotIsValid(Slot)); + + Slot->UserData = UserData; +} + +//======================================================================================================== +// D3DCache_SlotGetUserData +//======================================================================================================== +void *D3DCache_SlotGetUserData(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->UserData; +} + +//======================================================================================================== +// D3DCache_SlotSetLRU +//======================================================================================================== +void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU) +{ + assert(D3DCache_SlotIsValid(Slot)); + + Slot->LRU = LRU; +} + +//======================================================================================================== +// D3DCache_SlotGetLRU +//======================================================================================================== +uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->LRU; +} + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +LPDIRECT3DTEXTURE2 D3DCache_SlotGetTexture(D3DCache_Slot *Slot) */ +LPDIRECTDRAWSURFACE7 D3DCache_SlotGetTexture(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->Texture; +} + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +LPDIRECTDRAWSURFACE4 D3DCache_SlotGetSurface(D3DCache_Slot *Slot) */ +LPDIRECTDRAWSURFACE7 D3DCache_SlotGetSurface(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->Surface; +} + +//===================================================================================== +// Log2 +// Return the log of a size +//===================================================================================== +uint32 Log2(uint32 P2) +{ + uint32 p = 0; + int32 i = 0; + + for (i = P2; i > 0; i>>=1) + p++; + + return (p-1); +} + +//===================================================================================== +// SnapToPower2 +// Snaps a number to a power of 2 +//===================================================================================== +int32 SnapToPower2(int32 Width) +{ +#if 1 + if (Width > 0 && Width <= 1) Width = 1; + else if (Width > 1 && Width <= 2) Width = 2; + else if (Width > 2 && Width <= 4) Width = 4; + else if (Width > 4 && Width <= 8) Width = 8; + else if (Width > 8 && Width <= 16) Width =16; + else if (Width > 16 && Width <= 32) Width = 32; + else if (Width > 32 && Width <= 64) Width = 64; + else if (Width > 64 && Width <= 128) Width = 128; + else if (Width > 128 && Width <= 256) Width = 256; + else + return -1; +#else + + if (Width > 1 && Width <= 8) Width = 8; + else if (Width > 8 && Width <= 16) Width =16; + else if (Width > 16 && Width <= 32) Width = 32; + else if (Width > 32 && Width <= 64) Width = 64; + else if (Width > 64 && Width <= 128) Width = 128; + else if (Width > 128 && Width <= 256) Width = 256; + else + return -1; +#endif + + return Width; +} + +//===================================================================================== +// Return the max log of a (power of 2) width and height +//===================================================================================== +int32 GetLog(int32 Width, int32 Height) +{ + int32 LWidth = SnapToPower2(max(Width, Height)); + + return Log2(LWidth); +} + diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3dcache.h b/G3D/Engine/Drivers/D3D7xDrv/D3dcache.h new file mode 100644 index 0000000..162129a --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3dcache.h @@ -0,0 +1,73 @@ +/****************************************************************************************/ +/* D3DCache.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3DCache_H +#define D3DCache_H + +#include +#include +#include + +#include "BaseType.h" +#include "DDMemMgr.h" + +#define D3DCACHE_MAX_NAME 256 + +typedef struct D3DCache D3DCache; +typedef struct D3DCache_Type D3DCache_Type; +typedef struct D3DCache_Slot D3DCache_Slot; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW4 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages); */ +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW7 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages); + +void D3DCache_Destroy(D3DCache *Cache); +geBoolean D3DCache_IsValid(D3DCache *Cache); +geBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache); +D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +void D3DCache_TypeDestroy(D3DCache_Type *CacheType); +geBoolean D3DCache_TypeIsValid(D3DCache_Type *Type); +geBoolean D3DCache_FreeAllSlots(D3DCache *Cache); +geBoolean D3DCache_AdjustSlots(D3DCache *Cache, const int32 *MaxTable, geBoolean UsePartition); +geBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot); +int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, geBoolean UseStage, int32 Stage); +D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType); +void D3DCache_SlotSetUserData(D3DCache_Slot *Slot, void *UserData); +void *D3DCache_SlotGetUserData(D3DCache_Slot *Slot); +void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU); +uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot); + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +LPDIRECT3DTEXTURE2 D3DCache_SlotGetTexture(D3DCache_Slot *Slot); +LPDIRECTDRAWSURFACE4 D3DCache_SlotGetSurface(D3DCache_Slot *Slot); */ +LPDIRECTDRAWSURFACE7 D3DCache_SlotGetTexture(D3DCache_Slot *Slot); +LPDIRECTDRAWSURFACE7 D3DCache_SlotGetSurface(D3DCache_Slot *Slot); + +uint32 Log2(uint32 P2); +int32 SnapToPower2(int32 Width); +int32 GetLog(int32 Width, int32 Height); + +#endif + diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.cpp b/G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.cpp new file mode 100644 index 0000000..245d407 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.cpp @@ -0,0 +1,377 @@ +/****************************************************************************************/ +/* D3DDrv7x.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D driver */ +/* */ +/* 07/16/2000 Wendell Buckner */ +/* Convert to Directx7... */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +#include "D3DDrv.h" */ +#include "D3DDrv7x.h" + +#include "DCommon.h" + +#include "Scene.h" +#include "Render.h" +#include "D3DCache.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "THandle.h" + + +DRV_Window ClientWindow; +BOOL ExitHandlerActive = FALSE; + +int32 LastError; +char LastErrorStr[200]; + +geBoolean DRIVERCC DrvShutdown(void); +geBoolean DRIVERCC ScreenShot(const char *Name); + +BOOL DRIVERCC DrvInit(DRV_DriverHook *Hook) +{ + RECT WRect; + + // Start up + if (!D3DMain_InitD3D(Hook->hWnd, Hook->DriverName+5, Hook->Width, Hook->Height)) + { + //SetLastDrvError(DRV_ERROR_INIT_ERROR, "D3D_DrvInit: Could not init driver.\n"); + return FALSE; + } + + // If they are asking for a window mode, use there hWnd for the size + if (Hook->Width ==-1 && Hook->Height == -1) + { + GetClientRect(Hook->hWnd, &WRect); + + Hook->Width = (WRect.right - WRect.left); + Hook->Height = (WRect.bottom - WRect.top); + } + + ClientWindow.Width = Hook->Width; + ClientWindow.Height = Hook->Height; + ClientWindow.hWnd = Hook->hWnd; + + return TRUE; +} + +//============================================================================================ +//============================================================================================ +BOOL DRIVERCC DrvShutdown(void) +{ + D3DMain_ShutdownD3D(); + return TRUE; +} + +//============================================================================================ +// DrvResetAll +//============================================================================================ +geBoolean DRIVERCC DrvResetAll(void) +{ + return D3DMain_Reset(); +} + +geRDriver_PixelFormat PixelFormat[10]; + +#define NUM_PIXEL_FORMATS (sizeof(PixelFormats)/sizeof(geRDriver_PixelFormat)) + +geBoolean DRIVERCC EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context) +{ + int32 i; + gePixelFormat Format3d, Format2d; + uint32 CurrentBpp; + + CurrentBpp = AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Setup the 2d surface format + if (CurrentBpp == 32 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwRGBAlphaBitMask == 0xff000000) + Format2d = GE_PIXELFORMAT_32BIT_ARGB; + else if (CurrentBpp == 32 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwBBitMask == 0xff) + Format2d = GE_PIXELFORMAT_32BIT_XRGB; + else if (CurrentBpp == 24 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwBBitMask == 0xff) + Format2d = GE_PIXELFORMAT_24BIT_RGB; + else if (AppInfo.ddSurfFormat.ddpfPixelFormat.dwGBitMask == (31<<5)) + Format2d = GE_PIXELFORMAT_16BIT_555_RGB; + else + Format2d = GE_PIXELFORMAT_16BIT_565_RGB; + + // Setup the 3d (Texture) format + if (AppInfo.ddTexFormat.ddpfPixelFormat.dwGBitMask == (31<<5)) + Format3d = GE_PIXELFORMAT_16BIT_555_RGB; + else + Format3d = GE_PIXELFORMAT_16BIT_565_RGB; + + + // Create the surface formats now + PixelFormat[0].PixelFormat = Format3d; // 3d 565/555 surface + PixelFormat[0].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + PixelFormat[1].PixelFormat = GE_PIXELFORMAT_16BIT_4444_ARGB; // 3d 4444 surface + PixelFormat[1].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + PixelFormat[2].PixelFormat = Format2d; // 2d 565/555 surface + PixelFormat[2].Flags = RDRIVER_PF_2D | RDRIVER_PF_CAN_DO_COLORKEY; + + PixelFormat[3].PixelFormat = Format3d; // Lightmap 565/555 surface + PixelFormat[3].Flags = RDRIVER_PF_LIGHTMAP; + + PixelFormat[4].PixelFormat = GE_PIXELFORMAT_16BIT_1555_ARGB; + PixelFormat[4].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + // Then hand them off to the caller + for (i=0; i<5; i++) + { + if (!Cb(&PixelFormat[i], Context)) + return GE_TRUE; + } + + return TRUE; +} + +geBoolean DRIVERCC SetGamma(float Gamma) +{ + return GE_TRUE; +} + +geBoolean DRIVERCC GetGamma(float *Gamma) +{ + *Gamma = 1.0f; + + return GE_TRUE; +} + +BOOL DRIVERCC EnumSubDrivers2(DRV_ENUM_DRV_CB *Cb, void *Context); +BOOL DRIVERCC EnumModes2(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context); + +DRV_Driver D3DDRV = +{ + "D3D driver. v"DRV_VMAJS"."DRV_VMINS". Copyright 1999, WildTangent Inc.; All Rights Reserved.", + DRV_VERSION_MAJOR, + DRV_VERSION_MINOR, + + DRV_ERROR_NONE, + NULL, + + EnumSubDrivers2, + EnumModes2, + + EnumPixelFormats, + + DrvInit, + DrvShutdown, + DrvResetAll, + D3DMain_UpdateWindow, + D3DMain_SetActive, + + THandle_Create, + THandle_Destroy, + + THandle_Lock, + THandle_UnLock, + + NULL, // SetPal + NULL, // GetPal + + NULL, // SetAlpha + NULL, // GetAlpha + + THandle_GetInfo, + + BeginScene, + EndScene, + BeginWorld, + EndWorld, + BeginMeshes, + EndMeshes, + BeginModels, + EndModels, + + RenderGouraudPoly, + RenderWorldPoly, + RenderMiscTexturePoly, + + DrawDecal, + + 0,0,0, + + &CacheInfo, + + ScreenShot, + + SetGamma, + GetGamma, + + D3DMain_SetFogEnable, + + NULL, + NULL, // Init to NULL, engine SHOULD set this (SetupLightmap) + NULL +}; + +DRV_EngineSettings EngineSettings; + +DllExport BOOL DriverHook(DRV_Driver **Driver) +{ + EngineSettings.CanSupportFlags = (DRV_SUPPORT_ALPHA | DRV_SUPPORT_COLORKEY); + EngineSettings.PreferenceFlags = 0;//DRV_PREFERENCE_NO_MIRRORS; + + D3DDRV.EngineSettings = &EngineSettings; + + *Driver = &D3DDRV; + + // Make sure the error string ptr is not null, or invalid!!! + D3DDRV.LastErrorStr = LastErrorStr; + + SetLastDrvError(DRV_ERROR_NONE, "D3DDrv: No error."); + + return TRUE; +} + +void SetLastDrvError(int32 Error, char *ErrorStr) +{ + LastError = Error; + + if (ErrorStr) + { + strcpy(LastErrorStr, ErrorStr); + } + else + LastErrorStr[0] = NULL; + + D3DDRV.LastErrorStr = LastErrorStr; + D3DDRV.LastError = LastError; +} + +BOOL DRIVERCC ScreenShot(const char *Name) +{ + DDSURFACEDESC2 ddsd; + BITMAPFILEHEADER bfh; + BITMAPINFOHEADER bih; + HRESULT result; + HDC surfDC = NULL; + HDC memDC = NULL; + HBITMAP bitmap = NULL; + HGDIOBJ oldbit = NULL; + FILE *file = NULL; + void *data= NULL; + int width, height, bpp; + int datasize; + BOOL success = FALSE; + + memset(&ddsd,0,sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + result = AppInfo.lpBackBuffer->GetSurfaceDesc(&ddsd); + + if (FAILED(result)) + goto cleanup; + + width = ddsd.dwWidth; + height= ddsd.dwHeight; + bpp = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + + if (bpp < 2) + bpp = 2; + + if (bpp > 3) + bpp = 3; + + datasize = width * bpp * height; + + if (width * bpp % 4) + datasize += height * (4 - width * bpp % 4); + + memset((void*)&bfh, 0, sizeof(bfh)); + + bfh.bfType = 'B'+('M'<<8); + bfh.bfSize = sizeof(bfh) + sizeof(bih) + datasize; + bfh.bfOffBits = sizeof(bfh) + sizeof(bih); + + memset((void*)&bih, 0, sizeof(bih)); + + bih.biSize = sizeof(bih); + bih.biWidth = ddsd.dwWidth; + bih.biHeight = ddsd.dwHeight; + bih.biPlanes = 1; + bih.biBitCount = (unsigned short)(bpp * 8); + bih.biCompression = BI_RGB; + + result = AppInfo.lpBackBuffer->GetDC(&surfDC); + + if (FAILED(result)) + goto cleanup; + + bitmap = CreateDIBSection(NULL, (BITMAPINFO *)&bih, DIB_RGB_COLORS, &data, NULL, 0); + + if (!bitmap) + goto cleanup; + + if (!data) + goto cleanup; + + memDC = CreateCompatibleDC(surfDC); + + if (!memDC) + goto cleanup; + + oldbit = SelectObject(memDC, bitmap); + + if (!oldbit || FAILED(oldbit)) + goto cleanup; + + result = BitBlt(memDC, 0, 0, width, height, surfDC, 0, 0, SRCCOPY); + + if (!result) + goto cleanup; + + AppInfo.lpBackBuffer->ReleaseDC(surfDC); + surfDC = NULL; + file = fopen(Name, "wb"); + + if (!file) + goto cleanup; + + fwrite((void*)&bfh, sizeof(bfh), 1, file); + fwrite((void*)&bih, sizeof(bih), 1, file); + fwrite((void*)data, 1, datasize, file); + + success = TRUE; + +cleanup: + + if (oldbit && !FAILED(oldbit)) + SelectObject(memDC, oldbit); + + if (memDC) + DeleteDC(memDC); + + if (surfDC) + AppInfo.lpBackBuffer->ReleaseDC(surfDC); + + if (bitmap) + DeleteObject(bitmap); + + if (file) + fclose(file); + + return success; +} diff --git a/G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.h b/G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.h new file mode 100644 index 0000000..e18fdac --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/D3ddrv7x.h @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* D3DDrv.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3DDRV_H +#define D3DDRV_H + +#include "DCommon.h" + +extern DRV_Window ClientWindow; +extern DRV_Driver D3DDRV; + +void DRIVERCC ErrorBox(char *Str); +BOOL DRIVERCC DrvShutdown(void); +void SetLastDrvError(int32 Error, char *ErrorStr); + +#endif diff --git a/G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.c b/G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.c new file mode 100644 index 0000000..d5979e6 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.c @@ -0,0 +1,195 @@ +/****************************************************************************************/ +/* DDMemMgr.c */ +/* */ +/* Author: John Pollard */ +/* Description: Mini D3D memory manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "BaseType.h" +#include "DDMemMgr.h" + +#define DDMEMMGR_MAX_PARTITIONS 16 + +typedef struct DDMemMgr_Partition +{ + geBoolean Active; + uint32 FreeMem; + uint32 TotalMem; + +} DDMemMgr_Partition; + +typedef struct DDMemMgr +{ + uint32 TotalMem; + uint32 FreeMem; + DDMemMgr_Partition Partitions[DDMEMMGR_MAX_PARTITIONS]; +} DDMemMgr; + +//============================================================================ +// DDMemMgr_Create +//============================================================================ +DDMemMgr *DDMemMgr_Create(uint32 Size) +{ + DDMemMgr *MemMgr; + + MemMgr = (DDMemMgr*)malloc(sizeof(DDMemMgr)); + + if (!MemMgr) + return NULL; + + memset(MemMgr, 0, sizeof(DDMemMgr)); + + MemMgr->TotalMem = Size; + MemMgr->FreeMem = Size; + + return MemMgr; +} + +//============================================================================ +// DDMemMgr_Destroy +//============================================================================ +void DDMemMgr_Destroy(DDMemMgr *MemMgr) +{ + assert(MemMgr); + + free(MemMgr); +} + +//============================================================================ +// DDMemMgr_Reset +//============================================================================ +void DDMemMgr_Reset(DDMemMgr *MemMgr) +{ + int32 i; + + assert(MemMgr); + + MemMgr->FreeMem = MemMgr->TotalMem; + + for (i=0; iPartitions[i], 0, sizeof(DDMemMgr_Partition)); +} + +//============================================================================ +// DDMemMgr_GetFreeMem +//============================================================================ +uint32 DDMemMgr_GetFreeMem(DDMemMgr *MemMgr) +{ + assert(MemMgr); + return MemMgr->FreeMem; +} + +//============================================================================ +// DDMemMgr_PartitionCreate +//============================================================================ +DDMemMgr_Partition *DDMemMgr_PartitionCreate(DDMemMgr *MemMgr, uint32 Size) +{ + int32 i; + DDMemMgr_Partition *pPartition; + + assert(MemMgr); + + if (Size > MemMgr->FreeMem) + return NULL; + + pPartition = MemMgr->Partitions; + + for (i=0; i< DDMEMMGR_MAX_PARTITIONS; i++, pPartition++) + { + if (!pPartition->Active) + { + assert(pPartition->TotalMem == 0); + assert(pPartition->FreeMem == 0); + + pPartition->TotalMem = Size; + pPartition->FreeMem = Size; + pPartition->Active = GE_TRUE; + + MemMgr->FreeMem -= Size; + + assert(MemMgr->FreeMem >= 0); + + return pPartition; + } + } + + return NULL; +} + +//============================================================================ +// DDMemMgr_PartitionDestroy +//============================================================================ +void DDMemMgr_PartitionDestroy(DDMemMgr_Partition *Partition) +{ + assert(Partition); + assert(Partition->Active); + + memset(Partition, 0, sizeof(DDMemMgr_Partition)); +} + +//============================================================================ +// DDMemMgr_PartitionReset +//============================================================================ +void DDMemMgr_PartitionReset(DDMemMgr_Partition *Partition) +{ + assert(Partition->Active); + assert(Partition->FreeMem >= 0); + + Partition->FreeMem = Partition->TotalMem; +} + +//============================================================================ +// DDMemMgr_PArtitionGetTotalMem +//============================================================================ +uint32 DDMemMgr_PartitionGetTotalMem(DDMemMgr_Partition *Partition) +{ + assert(Partition); + assert(Partition->TotalMem >= 0); + + return Partition->TotalMem; +} + +//============================================================================ +// DDMemMgr_PArtitionGetFreeMem +//============================================================================ +uint32 DDMemMgr_PartitionGetFreeMem(DDMemMgr_Partition *Partition) +{ + assert(Partition); + assert(Partition->FreeMem >= 0); + + return Partition->FreeMem; +} + +//============================================================================ +// DDMemMgr_PartitionAllocMem +//============================================================================ +geBoolean DDMemMgr_PartitionAllocMem(DDMemMgr_Partition *Partition, uint32 Size) +{ + assert(Partition->Active); + + if (Partition->FreeMem < Size) + return GE_FALSE; + + Partition->FreeMem -= Size; + + assert(Partition->FreeMem >= 0); + + return GE_TRUE; +} diff --git a/G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.h b/G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.h new file mode 100644 index 0000000..a575f73 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/DDMemMgr.h @@ -0,0 +1,51 @@ +/****************************************************************************************/ +/* DDMemMgr.h */ +/* */ +/* Author: John Pollard */ +/* Description: Mini D3D memory manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DDMEMMGR_H +#define DDMEMMGR_H + +#include +#include + +#include "BaseType.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DDMemMgr DDMemMgr; +typedef struct DDMemMgr_Partition DDMemMgr_Partition; + +DDMemMgr *DDMemMgr_Create(uint32 Size); +void DDMemMgr_Destroy(DDMemMgr *MemMgr); +void DDMemMgr_Reset(DDMemMgr *MemMgr); +uint32 DDMemMgr_GetFreeMem(DDMemMgr *MemMgr); +DDMemMgr_Partition *DDMemMgr_PartitionCreate(DDMemMgr *MemMgr, uint32 Size); +void DDMemMgr_PartitionDestroy(DDMemMgr_Partition *Partition); +void DDMemMgr_PartitionReset(DDMemMgr_Partition *Partition); +uint32 DDMemMgr_PartitionGetTotalMem(DDMemMgr_Partition *Partition); +uint32 DDMemMgr_PartitionGetFreeMem(DDMemMgr_Partition *Partition); +geBoolean DDMemMgr_PartitionAllocMem(DDMemMgr_Partition *Partition, uint32 Size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/G3D/Engine/Drivers/D3D7xDrv/GSPAN.H b/G3D/Engine/Drivers/D3D7xDrv/GSPAN.H new file mode 100644 index 0000000..5c2f7ab --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/GSPAN.H @@ -0,0 +1,68 @@ +/****************************************************************************************/ +/* GSpan.h */ +/* */ +/* Author: John Pollard */ +/* Description: Front to back span code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GSPAN +#define GSPAN + +#include + +#define MAX_SPAN_LINES 1024 +#define MAX_SPANS 35000 + +typedef struct +{ + int32 x1; // Starting x on screen + int32 x2; // Ending x on screen +} SPAN; + +typedef struct _SList +{ + int32 Min, Max; + uint8 Used; + uint32 Flags; + _SList *Last; + _SList *Next; +} SLIST; + +typedef struct +{ + SLIST *First; + SLIST *Current; +} SPAN_MINMAX; + +extern SPAN SpanLines[MAX_SPAN_LINES]; + +extern SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +extern SLIST ScanHash[MAX_SPANS]; // hash table for SList + +extern int32 NumWorldPixels; +extern int32 NumSpans; +extern int32 NumSpanPixels[MAX_SPAN_LINES]; +extern int32 PolysRendered; + +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2); +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y); + +void ResetSList(void); +SLIST *NewSList(void); +void ResetSpans(int32 Rows); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D7xDrv/Gspan.cpp b/G3D/Engine/Drivers/D3D7xDrv/Gspan.cpp new file mode 100644 index 0000000..93e1518 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/Gspan.cpp @@ -0,0 +1,287 @@ +/****************************************************************************************/ +/* GSpan.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Front to back span code */ +/* */ +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +#include "D3DDrv.h" */ +#include "D3DDrv7x.h" + +#include "GSpan.h" + +SPAN SpanLines[MAX_SPAN_LINES]; + +SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +SLIST ScanHash[MAX_SPANS]; // hash table for SList + +BOOL PolyVisible = FALSE; + +int32 NumWorldPixels = 0; +int32 NumSpans = 0; +int32 NumSpanPixels[MAX_SPAN_LINES]; +int32 PolysRendered = 0; + +int32 CurrentSList = 0; + +const int32 CEIL_FRACT = ( ( 1 << 16)-1); +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2) +{ + int32 Ctmp; + int32 y; + int32 x,m; + + int32 ydelta; + int32 Dir; + int32 Cx1, Cx2, Cy1, Cy2; + SPAN *pSpans; + + Cx1 = x1; + Cx2 = x2; + Cy1 = y1; + Cy2 = y2; + + if (Cy2 != Cy1) // This isn't a horizontal line + { + Dir =0; // Left side + + if (Cy2 < Cy1) // Make sure y2 is greater than y1 + { + Dir =1; // Right side + + Ctmp = Cx1; + Cx1 = Cx2; + Cx2 = Ctmp; + + Ctmp = Cy1; + Cy1 = Cy2; + Cy2 = Ctmp; + + } + + ydelta = (Cy2 - Cy1); + + x = (Cx1 << 16) + CEIL_FRACT; // Allign on int amounts + m = (((Cx2 - Cx1))<<16) / ydelta; // How much to increase x each iteration + + pSpans = &SpanLines[Cy1]; + + if (!Dir) + { + for (y = Cy1; y <= Cy2; y++, pSpans++) + { + pSpans->x1 = (x>>16); + x += m; // Add our constant to x + } + } + else + { + for (y = Cy1; y <= Cy2; y++, pSpans++) + { + pSpans->x2 = (x>>16); + x += m; // Add our constant to x + } + } + } +} + +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y) +{ + int32 i, xx2; + SLIST *LineStart; + SLIST *Current; + SPAN_MINMAX *pSList; + + assert(y >=0 && y < MAX_SPAN_LINES); + + if (NumSpanPixels[y] >= ClientWindow.Width) + return; + + if (x1 > x2) // Swap all the coordinates so x1 < x2 + { + i = x1; + x1 = x2; + x2 = i; + } + + //if ( (x2 - x1) < 0) + // return; // Invalid line + + Current = SMinMax[y].First; + + LineStart = NULL; + + pSList = &SMinMax[y]; + + // Check to see if there are spans + // in the list yet... + if (!pSList->First) + { + pSList->First = NewSList(); + pSList->First->Last = NULL; + pSList->First->Next = NULL; + pSList->First->Min = x1; + pSList->First->Max = x2; + } + else while (Current != NULL) + { + if (x1 >= Current->Min && x2 <= Current->Max) + return; // This line totally hidden... + + //if falls before the entire min, max + if (LineStart == NULL) + { + if (Current == pSList->First) + if (x2 < Current->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current; + NewMinMax->Last = NULL; + Current->Last = NewMinMax; + pSList->First = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if falls in the middle (but not touching) + if (Current->Next != NULL) + if (x1 > Current->Max && x2 < (Current->Next)->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current->Next; + NewMinMax->Last = Current; + Current->Next->Last = NewMinMax; + Current->Next = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if it falls to the right of all spans + if (Current->Next == NULL) + if (x1 > Current->Max) + { + SLIST *NewMinMax = NewSList(); + Current->Next = NewMinMax; + NewMinMax->Next = NULL; + NewMinMax->Last = Current; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + } + //if we have already started crossing spans, and we find out + // that we are in front of a span, then we can bail out... + if (LineStart != NULL) + if (x2 < Current->Min) + goto WasNull; + + + // We now know that we have not fallen into any empty holes. + // We must now check to see what spans, we've crossed... + + // if split by a min/max + if (x1 < Current->Min && x2 > Current->Max) + { + xx2 = Current->Min-1; + Current->Min = x1; + + NumWorldPixels += xx2 - x1 + 1; + NumSpanPixels[y] += xx2 - x1 + 1; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + x1 = Current->Max+1; + Current->Max = x2; + if (LineStart!=NULL) + LineStart->Max = x2; + else + LineStart = Current; + goto next; + } + + if (x1 <= Current->Max && x2 > Current->Max) + { + x1 = Current->Max+1; + Current->Max = x2; + LineStart = Current; + goto next; + } + if (x1 < Current->Min && x2 >= Current->Min) + { + x2 = Current->Min-1; + Current->Min = x1; + if (LineStart!=NULL) + LineStart->Max = Current->Max; + goto WasNull; + } + next:; + Current = Current->Next; + } + WasNull:; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + NumWorldPixels += x2 - x1 + 1; + NumSpanPixels[y] += x2 - x1 + 1; +} + +void ResetSList(void) +{ + CurrentSList = 0; + NumSpans = 0; +} + +SLIST *NewSList(void) +{ + + CurrentSList++; + NumSpans++; + + assert(CurrentSList < MAX_SPANS); + + return &ScanHash[CurrentSList-1]; + + return NULL; +} + +void ResetSpans(int32 Rows) +{ + int32 i; + + for (i=0; i +#include + +#include "D3DCache.h" +#include "D3D_Fx.h" + +#include "PCache.h" + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +#include "D3DDrv.h" */ +#include "D3DDrv7x.h" + +#include "THandle.h" +#include "D3D_Err.h" + + +//#define D3D_MANAGE_TEXTURES +#define SUPER_FLUSH + +//==================================================================================== +// Local static variables +//==================================================================================== + +DRV_CacheInfo CacheInfo; + +// +// World Cache +// + +#if 1 + +#define MAX_WORLD_POLYS 256 +#define MAX_WORLD_POLY_VERTS 1024 + +#define MAX_MISC_POLYS 256 +#define MAX_MISC_POLY_VERTS 1024 + +#else + +#define MAX_WORLD_POLYS 256 +#define MAX_WORLD_POLY_VERTS 4096 + +#define MAX_MISC_POLYS 256 +#define MAX_MISC_POLY_VERTS 4096 + +#endif + +typedef struct +{ + float u; + float v; + //float a; + uint32 Color; +} PCache_TVert; + +typedef struct +{ + geRDriver_THandle *THandle; + + DRV_LInfo *LInfo; // Original pointer to linfo + uint32 Flags; // Flags for this poly + float ShiftU; + float ShiftV; + float ScaleU; + float ScaleV; + int32 MipLevel; + uint32 SortKey; + int32 FirstVert; + int32 NumVerts; +} World_Poly; + +#define MAX_TEXTURE_STAGES 2 // Up to 2 tmu's (stages) + +// Verts we defined in the D3D flexible vertex format (FVF) +// This is a transformed and lit vertex definition, with up to 8 sets of uvs +typedef struct +{ + float u,v; +} PCache_UVSet; + +typedef struct +{ + float x,y,z; // Screen x, y, z + float rhw; // homogenous w + DWORD color; // color + DWORD specular; + PCache_UVSet uv[MAX_TEXTURE_STAGES]; // uv sets for each stage +} PCache_Vert; + +typedef struct +{ + World_Poly Polys[MAX_WORLD_POLYS]; + World_Poly *SortedPolys[MAX_WORLD_POLYS]; + World_Poly *SortedPolys2[MAX_WORLD_POLYS]; + PCache_Vert Verts[MAX_WORLD_POLY_VERTS]; + + PCache_TVert TVerts[MAX_WORLD_POLY_VERTS]; // Original uv + + int32 NumPolys; + int32 NumPolys2; + int32 NumVerts; +} World_Cache; + +static World_Cache WorldCache; + +#define PREP_WORLD_VERTS_NORMAL 1 // Prep verts as normal +#define PREP_WORLD_VERTS_LMAP 2 // Prep verts as lightmaps +#define PREP_WORLD_VERTS_SINGLE_PASS 3 // Prep verts for a single pass + +#define RENDER_WORLD_POLYS_NORMAL 1 // Render polys as normal +#define RENDER_WORLD_POLYS_LMAP 2 // Render polys as lightmaps +#define RENDER_WORLD_POLYS_SINGLE_PASS 3 + +// +// Misc cache +// + +typedef struct +{ + geRDriver_THandle *THandle; + uint32 Flags; // Flags for this poly + int32 MipLevel; + int32 FirstVert; + int32 NumVerts; + + uint32 SortKey; +} Misc_Poly; + +typedef struct +{ + Misc_Poly Polys[MAX_MISC_POLYS]; + Misc_Poly *SortedPolys[MAX_MISC_POLYS]; + PCache_Vert Verts[MAX_MISC_POLY_VERTS]; + //float ZVert[MAX_MISC_POLY_VERTS]; + + int32 NumPolys; + int32 NumVerts; +} Misc_Cache; + +static Misc_Cache MiscCache; + +//==================================================================================== +// Local static functions prototypes +//==================================================================================== +geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2); + +static BOOL RenderWorldPolys(int32 RenderMode); +static BOOL ClearWorldCache(void); +static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, float ScaleU, float ScaleV, int32 MaxMipLevel); + +#include + +//==================================================================================== +// PCache_InsertWorldPoly +//==================================================================================== +BOOL PCache_InsertWorldPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ + int32 Mip; + float ZRecip, DrawScaleU, DrawScaleV; + World_Poly *pCachePoly; + DRV_TLVertex *pVerts; + PCache_TVert *pTVerts; + PCache_Vert *pD3DVerts; + int32 i; + uint32 Alpha; + + #ifdef _DEBUG + if (LInfo) + { + assert(LInfo->THandle); + } + #endif + + if ((WorldCache.NumVerts + NumVerts) >= MAX_WORLD_POLY_VERTS) + { + // If the cache is full, we must flush it before going on... + if (!PCache_FlushWorldPolys()) + return GE_FALSE; + } + else if (WorldCache.NumPolys+1 >= MAX_WORLD_POLYS) + { + // If the cache is full, we must flush it before going on... + if (!PCache_FlushWorldPolys()) + return GE_FALSE; + } + + DrawScaleU = 1.0f / TexInfo->DrawScaleU; + DrawScaleV = 1.0f / TexInfo->DrawScaleV; + + Mip = GetMipLevel(Verts, NumVerts, DrawScaleU, DrawScaleV, THandle->NumMipLevels-1); + + // Get a pointer to the original polys verts + pVerts = Verts; + + // Store info about this poly in the cache + pCachePoly = &WorldCache.Polys[WorldCache.NumPolys]; + + pCachePoly->THandle = THandle; + pCachePoly->LInfo = LInfo; + pCachePoly->Flags = Flags; + pCachePoly->FirstVert = WorldCache.NumVerts; + pCachePoly->NumVerts = NumVerts; + pCachePoly->ShiftU = TexInfo->ShiftU; + pCachePoly->ShiftV = TexInfo->ShiftV; + pCachePoly->ScaleU = DrawScaleU; + pCachePoly->ScaleV = DrawScaleV; + pCachePoly->MipLevel = Mip; + + // Don't forget the sort key: + pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip; + + // Get a pointer into the world verts + pD3DVerts = &WorldCache.Verts[WorldCache.NumVerts]; + pTVerts = &WorldCache.TVerts[WorldCache.NumVerts]; + + if (Flags & DRV_RENDER_ALPHA) + Alpha = (uint32)pVerts->a<<24; + else + Alpha = (uint32)(255<<24); + + for (i=0; i< NumVerts; i++) + { + ZRecip = 1.0f/(pVerts->z); + + pD3DVerts->x = pVerts->x; + pD3DVerts->y = pVerts->y; + + pD3DVerts->z = (1.0f - ZRecip); // ZBUFFER + pD3DVerts->rhw = ZRecip; + + if (AppInfo.FogEnable && !(Flags & DRV_RENDER_POLY_NO_FOG)) // poly fog + { + DWORD FogVal; + float Val; + + Val = pVerts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DVerts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DVerts->specular = 0; + + // Store the uv's so the prep pass can use them... + pTVerts->u = pVerts->u; + pTVerts->v = pVerts->v; + + pTVerts->Color = Alpha | ((uint32)pVerts->r<<16) | ((uint32)pVerts->g<<8) | (uint32)pVerts->b; + + pTVerts++; + pVerts++; + pD3DVerts++; + + } + + // Update globals about the world poly cache + WorldCache.NumVerts += NumVerts; + WorldCache.NumPolys++; + + return TRUE; +} + +//==================================================================================== +// PCache_FlushWorldPolys +//==================================================================================== +BOOL PCache_FlushWorldPolys(void) +{ + if (!WorldCache.NumPolys) + return TRUE; + + if (!THandle_CheckCache()) + return GE_FALSE; + + if (AppInfo.CanDoMultiTexture) + { + RenderWorldPolys(RENDER_WORLD_POLYS_SINGLE_PASS); + } + else + { + // Render them as normal + if (!RenderWorldPolys(RENDER_WORLD_POLYS_NORMAL)) + return GE_FALSE; + + // Render them as lmaps + RenderWorldPolys(RENDER_WORLD_POLYS_LMAP); + } + + ClearWorldCache(); + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +static int MiscBitmapHandleComp(const void *a, const void *b) +{ + uint32 Id1, Id2; + + Id1 = (uint32)(*(Misc_Poly**)a)->SortKey; + Id2 = (uint32)(*(Misc_Poly**)b)->SortKey; + + if ( Id1 == Id2) + return 0; + + if (Id1 < Id2) + return -1; + + return 1; +} + +//==================================================================================== +//==================================================================================== +static void SortMiscPolysByHandle(void) +{ + Misc_Poly *pPoly; + int32 i; + + pPoly = MiscCache.Polys; + + for (i=0; iTHandle; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + Size = 1<Log; + + Lut = &AppInfo.Lut1; + + THandle_Lock(THandle, 0, (void**)&pTempBits); + + Extra = Size - Width; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + U8 R, G, B; + U16 Color; + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + THandle_UnLock(THandle, 0); +} + +#ifdef USE_TPAGES +//===================================================================================== +// FillLMapSurface +//===================================================================================== +static void FillLMapSurface2(DRV_LInfo *LInfo, int32 LNum) +{ + U16 *pTempBits; + int32 w, h, Width, Height, Stride; + U8 *pBitPtr; + RGB_LUT *Lut; + geRDriver_THandle *THandle; + HRESULT Result; + const RECT *pRect; + DDSURFACEDESC2 SurfDesc; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAWSURFACE4 Surface; */ + LPDIRECTDRAWSURFACE7 Surface; + + int32 Extra; + + THandle = LInfo->THandle; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + + Lut = &AppInfo.Lut1; + + pRect = TPage_BlockGetRect(THandle->Block); + Surface = TPage_BlockGetSurface(THandle->Block); + + memset(&SurfDesc, 0, sizeof(DDSURFACEDESC2)); + SurfDesc.dwSize = sizeof(DDSURFACEDESC2); + +/* 03/10/2002 Wendell Buckner + Procedural Textures + if you must lock a texture specify the flags WRITEONLY and DISCARDCONTENTS when + Result = Surface->Lock((RECT*)pRect, &SurfDesc, DDLOCK_WAIT, NULL); */ + Result = Surface->Lock((RECT*)pRect, &SurfDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY | DDLOCK_DISCARDCONTENTS , NULL); + + assert(Result == DD_OK); + + Stride = SurfDesc.dwWidth; + + pTempBits = (U16*)SurfDesc.lpSurface; + + Extra = Stride - Width; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + U8 R, G, B; + U16 Color; + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + Result = Surface->Unlock((RECT*)pRect); + + assert(Result == DD_OK); +} +#endif + +//===================================================================================== +// LoadLMapFromSystem +//===================================================================================== +static void LoadLMapFromSystem(DRV_LInfo *LInfo, int32 Log, int32 LNum) +{ + U16 *pTempBits; + int32 w, h, Width, Height, Size, Extra; + U8 *pBitPtr; + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... + LPDIRECTDRAWSURFACE4 Surface; */ + LPDIRECTDRAWSURFACE7 Surface; + + RGB_LUT *Lut; + DDSURFACEDESC2 ddsd; + HRESULT ddrval; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + Size = 1<Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);*/ + ddrval = Surface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY | DDLOCK_DISCARDCONTENTS, NULL); + + assert(ddrval == DD_OK); + + pTempBits = (USHORT*)ddsd.lpSurface; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + U8 R, G, B; + U16 Color; + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + ddrval = Surface->Unlock(NULL); + assert(ddrval == DD_OK); +} + +static BOOL IsKeyDown(int KeyCode) +{ + if (GetAsyncKeyState(KeyCode) & 0x8000) + return TRUE; + + return FALSE; +} + +extern uint32 CurrentLRU; + +//===================================================================================== +// SetupMipData +//===================================================================================== +geBoolean SetupMipData(THandle_MipData *MipData) +{ + if (!MipData->Slot || D3DCache_SlotGetUserData(MipData->Slot) != MipData) + { + MipData->Slot = D3DCache_TypeFindSlot(MipData->CacheType); + assert(MipData->Slot); + + D3DCache_SlotSetUserData(MipData->Slot, MipData); + + + #ifdef SUPER_FLUSH +/* 02/28/2001 Wendell Buckner + These render states are unsupported d3d 7.0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0);*/ + #endif + + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// SetupLMap +//===================================================================================== +geBoolean SetupLMap(int32 Stage, DRV_LInfo *LInfo, int32 LNum, geBoolean Dynamic) +{ +#ifdef D3D_MANAGE_TEXTURES + #ifdef USE_TPAGES + { + geRDriver_THandle *THandle; + + THandle = LInfo->THandle; + + if (Dynamic) + THandle->Flags |= THANDLE_UPDATE; + + if (!THandle->Block) + { + THandle->Block = TPage_MgrFindOptimalBlock(TPageMgr, CurrentLRU); + THandle->Flags |= THANDLE_UPDATE; + TPage_BlockSetUserData(THandle->Block, THandle); + assert(THandle->Block); + } + else if (TPage_BlockGetUserData(THandle->Block) != THandle) + { + // Find another block + THandle->Block = TPage_MgrFindOptimalBlock(TPageMgr, CurrentLRU); + assert(THandle->Block); + + THandle->Flags |= THANDLE_UPDATE; + TPage_BlockSetUserData(THandle->Block, THandle); + } + + if (THandle->Flags & THANDLE_UPDATE) + FillLMapSurface2(LInfo, LNum); + + TPage_BlockSetLRU(THandle->Block, CurrentLRU); + D3DSetTexture(Stage, TPage_BlockGetTexture(THandle->Block)); + + if (Dynamic) + THandle->Flags |= THANDLE_UPDATE; + else + THandle->Flags &= ~THANDLE_UPDATE; + + return GE_TRUE; + } + #else + { + geRDriver_THandle *THandle; + + THandle = LInfo->THandle; + + if (Dynamic) + THandle->MipData[0].Flags |= THANDLE_UPDATE; + + if (THandle->MipData[0].Flags & THANDLE_UPDATE) + FillLMapSurface(LInfo, LNum); + +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. + D3DSetTexture(Stage, THandle->MipData[0].Texture);*/ + D3DSetTexture(Stage, THandle->MipData[0].Surface); + + if (Dynamic) + THandle->MipData[0].Flags |= THANDLE_UPDATE; + else + THandle->MipData[0].Flags &= ~THANDLE_UPDATE; + + return GE_TRUE; + } + #endif + +#else + geRDriver_THandle *THandle; + THandle_MipData *MipData; + + THandle = LInfo->THandle; + MipData = &THandle->MipData[0]; + + if (Dynamic) + MipData->Flags |= THANDLE_UPDATE; + + if (!SetupMipData(MipData)) + { + MipData->Flags |= THANDLE_UPDATE; // Force an upload + CacheInfo.LMapMisses++; + } + + if (MipData->Flags & THANDLE_UPDATE) + { + HRESULT Error; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAWSURFACE4 Surface; */ + LPDIRECTDRAWSURFACE7 Surface; + + + assert(MipData->Slot); + + Surface = D3DCache_SlotGetSurface(MipData->Slot); + + assert(Surface); + assert(THandle->Log < MAX_LMAP_LOG_SIZE); + assert(SystemToVideo[THandle->Log].Surface); + + LoadLMapFromSystem(LInfo, THandle->Log, LNum); + +/* 03/10/2002 Wendell Buckner + Optimization from GeForce_Optimization2.doc + Procedural Textures + Also, Load is even faster than BLT under Dx7. + Error = AppInfo.lpD3DDevice->Load ( Surface, NULL, SystemToVideo[THandle->Log].Surface, NULL, NULL ); */ + +/* 01/24/2002 Wendell Buckner + Change flags for speed... + Error = Surface->BltFast(0, 0, SystemToVideo[THandle->Log].Surface, NULL, DDBLTFAST_WAIT); */ + Error = Surface->BltFast(0, 0, SystemToVideo[THandle->Log].Surface, NULL, DDBLTFAST_DONOTWAIT ); + + + //Error = Surface->BltFast(0, 0, SystemToVideo[THandle->Log].Surface, NULL, 0); + //Error = Surface->Blt(NULL, SystemToVideo[THandle->Log].Surface, NULL, DDBLT_WAIT, NULL); + //Error = Surface->Blt(NULL, SystemToVideo[THandle->Log].Surface, NULL, 0, NULL); + + if (Error != DD_OK) + { + if(Error==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return GE_FALSE; + } + else + { + D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error)); + return GE_FALSE; + } + } + } + + if (Dynamic) // If it was dynmamic, force an update for one more frame + MipData->Flags |= THANDLE_UPDATE; + else + MipData->Flags &= ~THANDLE_UPDATE; + + D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU); + D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot)); + + return GE_TRUE; +#endif +} + +//===================================================================================== +// SetupTexture +//===================================================================================== +geBoolean SetupTexture(int32 Stage, geRDriver_THandle *THandle, int32 MipLevel) +{ +#ifdef D3D_MANAGE_TEXTURES + D3DSetTexture(Stage, THandle->MipData[MipLevel].Texture); + return GE_TRUE; +#else + THandle_MipData *MipData; + + MipData = &THandle->MipData[MipLevel]; + + if (!SetupMipData(MipData)) + { + MipData->Flags |= THANDLE_UPDATE; // Force an upload + CacheInfo.TexMisses++; + } + + if (MipData->Flags & THANDLE_UPDATE) + { + HRESULT Error; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAWSURFACE4 Surface; */ + LPDIRECTDRAWSURFACE7 Surface; + + + Surface = D3DCache_SlotGetSurface(MipData->Slot); + +/* 03/10/2002 Wendell Buckner + Optimization from GeForce_Optimization2.doc + Procedural Textures + Also, Load is even faster than BLT under Dx7. + Error = AppInfo.lpD3DDevice->Load ( Surface, NULL, MipData->Surface, NULL, NULL );*/ + +/* 01/24/2002 Wendell Buckner + Change flags for speed... + Error = Surface->BltFast(0, 0, MipData->Surface, NULL, DDBLTFAST_WAIT);*/ + Error = Surface->BltFast(0, 0, MipData->Surface, NULL, DDBLTFAST_DONOTWAIT ); + + + if (Error != DD_OK) + { + if(Error==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return FALSE; + } + else + { + D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error)); + return GE_FALSE; + } + } + } + + MipData->Flags &= ~THANDLE_UPDATE; + + D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU); + D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot)); + + return GE_TRUE; +#endif +} + +//==================================================================================== +// PCache_FlushMiscPolys +//==================================================================================== +BOOL PCache_FlushMiscPolys(void) +{ + int32 i; + Misc_Poly *pPoly; + + if (!MiscCache.NumPolys) + return TRUE; + + if (!THandle_CheckCache()) + return GE_FALSE; + + // Set the render states + if (AppInfo.CanDoMultiTexture) + { + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + D3DSetTexture(1, NULL); // Reset texture stage 1 + } + + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); + + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + D3DBlendEnable(TRUE); + + // Sort the polys by handle + SortMiscPolysByHandle(); + + for (i=0; i< MiscCache.NumPolys; i++) + { + pPoly = MiscCache.SortedPolys[i]; + + if (pPoly->Flags & DRV_RENDER_NO_ZMASK) // We are assuming that this is not going to change all that much + D3DZEnable(FALSE); + else + D3DZEnable(TRUE); + + if (pPoly->Flags & DRV_RENDER_NO_ZWRITE) // We are assuming that this is not going to change all that much + D3DZWriteEnable(FALSE); + else + D3DZWriteEnable(TRUE); + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(0, FALSE); + else + D3DTexWrap(0, TRUE); + + if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + + D3DTexturedPoly(&MiscCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + + // Turn z stuff back on... + D3DZWriteEnable (TRUE); + D3DZEnable(TRUE); + + MiscCache.NumPolys = 0; + MiscCache.NumVerts = 0; + +#ifdef SUPER_FLUSH +/* 02/28/2001 Wendell Buckner + These render states are unsupported d3d 7.0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0);*/ + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); +#endif + + return TRUE; +} + +//==================================================================================== +// PCache_InsertMiscPoly +//==================================================================================== +BOOL PCache_InsertMiscPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, uint32 Flags) +{ + int32 Mip; + float ZRecip, u, v, ScaleU, ScaleV, InvScale; + Misc_Poly *pCachePoly; + DRV_TLVertex *pVerts; + PCache_Vert *pD3DVerts; + int32 i, SAlpha; + + if ((MiscCache.NumVerts + NumVerts) >= MAX_MISC_POLY_VERTS) + { + // If the cache is full, we must flush it before going on... + PCache_FlushMiscPolys(); + } + else if (MiscCache.NumPolys+1 >= MAX_MISC_POLYS) + { + // If the cache is full, we must flush it before going on... + PCache_FlushMiscPolys(); + } + + Mip = GetMipLevel(Verts, NumVerts, (float)THandle->Width, (float)THandle->Height, THandle->NumMipLevels-1); + + // Store info about this poly in the cache + pCachePoly = &MiscCache.Polys[MiscCache.NumPolys]; + + pCachePoly->THandle = THandle; + pCachePoly->Flags = Flags; + pCachePoly->FirstVert = MiscCache.NumVerts; + pCachePoly->NumVerts = NumVerts; + pCachePoly->MipLevel = Mip; + pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip; + + // Get scale value for vertices + //TCache_GetUVInvScale(Bitmap, Mip, &InvScale); + InvScale = 1.0f / (float)((1<Log)); + + // Convert them to take account that the vertices are allready from 0 to 1 + ScaleU = (float)THandle->Width * InvScale; + ScaleV = (float)THandle->Height * InvScale; + + // Precompute the alpha value... + SAlpha = ((int32)Verts->a)<<24; + + // Get a pointer to the original polys verts + pVerts = Verts; + // Get a pointer into the world verts + pD3DVerts = &MiscCache.Verts[MiscCache.NumVerts]; + + for (i=0; i< NumVerts; i++) + { + ZRecip = 1/(pVerts->z); + + pD3DVerts->x = pVerts->x; + pD3DVerts->y = pVerts->y; + + pD3DVerts->z = (1.0f - ZRecip); // ZBUFFER + pD3DVerts->rhw = ZRecip; + + u = pVerts->u * ScaleU; + v = pVerts->v * ScaleV; + + pD3DVerts->uv[0].u = u; + pD3DVerts->uv[0].v = v; + + pD3DVerts->color = SAlpha | ((int32)pVerts->r<<16) | ((int32)pVerts->g<<8) | (int32)pVerts->b; + + if (AppInfo.FogEnable && !(Flags & DRV_RENDER_POLY_NO_FOG) ) // poly fog + { + DWORD FogVal; + float Val; + + Val = pVerts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DVerts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DVerts->specular = 0; + + pVerts++; + pD3DVerts++; + } + + // Update globals about the misc poly cache + MiscCache.NumVerts += NumVerts; + MiscCache.NumPolys++; + + return TRUE; +} + +//==================================================================================== +// **** LOCAL STATIC FUNCTIONS ***** +//==================================================================================== + +//==================================================================================== +// World_PolyPrepVerts +//==================================================================================== +geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2) +{ + float InvScale, u, v; + PCache_TVert *pTVerts; + PCache_Vert *pVerts; + float ShiftU, ShiftV, ScaleU, ScaleV; + int32 j; + + switch (PrepMode) + { + case PREP_WORLD_VERTS_NORMAL: + { + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + + ShiftU = pPoly->ShiftU; + ShiftV = pPoly->ShiftV; + ScaleU = pPoly->ScaleU; + ScaleV = pPoly->ScaleV; + + // Get scale value for vertices + InvScale = 1.0f / (float)((1<THandle->Log)); + + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u*ScaleU+ShiftU; + v = pTVerts->v*ScaleV+ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + pVerts->color = pTVerts->Color; + + pTVerts++; + pVerts++; + } + + break; + } + + case PREP_WORLD_VERTS_LMAP: + { + if (!pPoly->LInfo) + return GE_TRUE; + + ShiftU = (float)-pPoly->LInfo->MinU + 8.0f; + ShiftV = (float)-pPoly->LInfo->MinV + 8.0f; + + // Get scale value for vertices + InvScale = 1.0f/(float)((1<LInfo->THandle->Log)<<4); + + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u + ShiftU; + v = pTVerts->v + ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + pVerts->color = 0xffffffff; + + pTVerts++; + pVerts++; + } + break; + } + + case PREP_WORLD_VERTS_SINGLE_PASS: + { + float InvScale2, ShiftU2, ShiftV2; + + assert(pPoly->LInfo); + + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + + // Set up shifts and scaled for texture uv's + ShiftU = pPoly->ShiftU; + ShiftV = pPoly->ShiftV; + ScaleU = pPoly->ScaleU; + ScaleV = pPoly->ScaleV; + + // Get scale value for vertices + InvScale = 1.0f / (float)((1<THandle->Log)); + + // Set up shifts and scaled for lightmap uv's + ShiftU2 = (float)-pPoly->LInfo->MinU + 8.0f; + ShiftV2 = (float)-pPoly->LInfo->MinV + 8.0f; + InvScale2 = 1.0f/(float)((1<LInfo->THandle->Log)<<4); + + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u*ScaleU+ShiftU; + v = pTVerts->v*ScaleV+ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + u = pTVerts->u + ShiftU2; + v = pTVerts->v + ShiftV2; + + pVerts->uv[Stage2].u = u * InvScale2; + pVerts->uv[Stage2].v = v * InvScale2; + + pVerts->color = pTVerts->Color; + + pTVerts++; + pVerts++; + } + + break; + } + + default: + return FALSE; + } + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +static int BitmapHandleComp(const void *a, const void *b) +{ + int32 Id1, Id2; + + Id1 = (*(World_Poly**)a)->SortKey; + Id2 = (*(World_Poly**)b)->SortKey; + + if ( Id1 == Id2) + return 0; + + if (Id1 < Id2) + return -1; + + return 1; +} + +//==================================================================================== +//==================================================================================== +static void SortWorldPolysByHandle(void) +{ + World_Poly *pPoly; + int32 i; + + pPoly = WorldCache.Polys; + + for (i=0; iSetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); + + // Set the default state for the normal poly render mode for the world + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + // Get the first poly in the sorted list + SortWorldPolysByHandle(); + + for (i=0; i< WorldCache.NumPolys; i++) + { + pPoly = WorldCache.SortedPolys[i]; + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(0, FALSE); + else + D3DTexWrap(0, TRUE); + + if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, 0, 0); + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + } + + break; + } + + case RENDER_WORLD_POLYS_LMAP: + { + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); + + D3DTexWrap(0, FALSE); + + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO); + + pPoly = WorldCache.Polys; + + for (i=0; i< WorldCache.NumPolys; i++, pPoly++) + { + BOOL Dynamic = 0; + + if (!pPoly->LInfo) + continue; + + // Call the engine to set this sucker up, because it's visible... + D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic); + + if (!SetupLMap(0, pPoly->LInfo, 0, Dynamic)) + return GE_FALSE; + + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_LMAP, 0, 0); + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if (pPoly->LInfo->RGBLight[1]) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE); + + D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE); // Change to a fog state + + // For some reason, some cards can't upload data to the same texture twice, and have it take. + // So we force Fog maps to use a different slot than the lightmap was using... + pPoly->LInfo->THandle->MipData[0].Slot = NULL; + + if (!SetupLMap(0, pPoly->LInfo, 1, 1)) // Dynamic is 1, because fog is always dynamic + return GE_FALSE; + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO); // Restore state + + if (AppInfo.FogEnable) + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + } + break; + } + + case RENDER_WORLD_POLYS_SINGLE_PASS: + { + // Setup texture stage states + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT ); + //AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + + // Setup frame buffer blend modes + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + // Set the default state for the normal poly render mode for the world + D3DTexWrap(TSTAGE_0, TRUE); + D3DTexWrap(TSTAGE_1, FALSE); + + // Sort the list for front back operation to get the least number of world texture misses + SortWorldPolysByHandle(); + + // Reset non lightmaps faces to 0 + WorldCache.NumPolys2 = 0; + + for (i=0; i< WorldCache.NumPolys; i++) + { + BOOL Dynamic = 0; + + pPoly = WorldCache.SortedPolys[i]; + + if (!pPoly->LInfo) + { + // Put gouraud only polys in a seperate list, and render last + WorldCache.SortedPolys2[WorldCache.NumPolys2++] = pPoly; + continue; + } + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(TSTAGE_0, FALSE); + else + D3DTexWrap(TSTAGE_0, TRUE); + + if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + // Call the engine to set this sucker up, because it's visible... + D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic); + + if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 0, Dynamic)) + return GE_FALSE; + + // Prep the verts for a lightmap and texture map + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_SINGLE_PASS, TSTAGE_0, TSTAGE_1); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + + // Draw the texture + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + + // Render any fog maps + if (pPoly->LInfo->RGBLight[1]) + { + D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE); // Change to a fog state + + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + #endif + + // For some reason, some cards can't upload data to the same texture twice, and have it take. + // So we force Fog maps to use a different slot other than what the lightmap was using... + pPoly->LInfo->THandle->MipData[0].Slot = NULL; + + if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 1, 1)) // Dynamic is 1, because fog is always dynamic + return GE_FALSE; + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + // Restore states to the last state before fag map + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + #endif + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + } + + + } + + // Setup for any non-lightmaped faces faces, turn tmu1 off + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + #endif + + // Render all the faces without lightmaps + for (i=0; i< WorldCache.NumPolys2; i++) + { + BOOL Dynamic = 0; + + pPoly = WorldCache.SortedPolys2[i]; + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(TSTAGE_0, FALSE); + else + D3DTexWrap(TSTAGE_0, TRUE); + + if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + // Prep verts as if there was no lightmap + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, TSTAGE_0, TSTAGE_1); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + + // Draw the texture + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + + break; + } + + default: + return FALSE; + } + + + return TRUE; +} + +//==================================================================================== +// ClearWorldCache +//==================================================================================== +static BOOL ClearWorldCache(void) +{ + WorldCache.NumPolys = 0; + WorldCache.NumVerts = 0; + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +BOOL PCache_Reset(void) +{ + WorldCache.NumPolys = 0; + WorldCache.NumVerts = 0; + + MiscCache.NumPolys = 0; + MiscCache.NumVerts = 0; + + return TRUE; +} + +//==================================================================================== +// GetMipLevel +//==================================================================================== +static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, float ScaleU, float ScaleV, int32 MaxMipLevel) +{ + int32 Mip; + + if (MaxMipLevel == 0) + return 0; + + // + // Get the MipLevel + // + { + float du, dv, dx, dy, MipScale; + + #if 1 // WAY slower, but more accurate + int32 i; + + MipScale = 999999.0f; + + for (i=0; i< NumVerts; i++) + { + float MipScaleT; + DRV_TLVertex *pVert0, *pVert1; + int32 i2; + + i2 = i+1; + + if (i2 >= NumVerts) + i2=0; + + pVert0 = &Verts[i]; + pVert1 = &Verts[i2]; + + du = pVert1->u - pVert0->u; + dv = pVert1->v - pVert0->v; + dx = pVert1->x - pVert0->x; + dy = pVert1->y - pVert0->y; + + du *= ScaleU; + dv *= ScaleV; + + MipScaleT = ((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy)); + + if (MipScaleT < MipScale) + MipScale = MipScaleT; // Record the best MipScale (the one closest to the the eye) + } + #else // Faster, less accurate + du = Verts[1].u - Verts[0].u; + dv = Verts[1].v - Verts[0].v; + dx = Verts[1].x - Verts[0].x; + dy = Verts[1].y - Verts[0].y; + + du *= ScaleU; + dv *= ScaleV; + + MipScale = ((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy)); + #endif + + #if 0 + if (MipScale <= 5) // 2, 6, 12 + Mip = 0; + else if (MipScale <= 20) + Mip = 1; + else if (MipScale <= 45) + Mip = 2; + else + Mip = 3; + #else + if (MipScale <= 4) // 2, 6, 12 + Mip = 0; + else if (MipScale <= 15) + Mip = 1; + else if (MipScale <= 40) + Mip = 2; + else + Mip = 3; + #endif + } + + if (Mip > MaxMipLevel) + Mip = MaxMipLevel; + + return Mip; +} \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D7xDrv/Pcache.h b/G3D/Engine/Drivers/D3D7xDrv/Pcache.h new file mode 100644 index 0000000..5e55574 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/Pcache.h @@ -0,0 +1,35 @@ +/****************************************************************************************/ +/* PCache.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D poly cache */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef PCACHE_H +#define PCACHE_H + +extern DRV_CacheInfo CacheInfo; + +BOOL PCache_InsertWorldPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +BOOL PCache_FlushWorldPolys(void); + +BOOL PCache_FlushMiscPolys(void); +BOOL PCache_InsertMiscPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, uint32 Flags); + +BOOL PCache_Reset(void); + +#endif diff --git a/G3D/Engine/Drivers/D3D7xDrv/RENDER.H b/G3D/Engine/Drivers/D3D7xDrv/RENDER.H new file mode 100644 index 0000000..f000b0a --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/RENDER.H @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* Render.h */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render polys under D3D */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef RENDER_H +#define RENDER_H + +#include + +#include "DCommon.h" + +geBoolean DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags); +geBoolean DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +geBoolean DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags); +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y); + +#endif diff --git a/G3D/Engine/Drivers/D3D7xDrv/Render.cpp b/G3D/Engine/Drivers/D3D7xDrv/Render.cpp new file mode 100644 index 0000000..e9d2dc0 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/Render.cpp @@ -0,0 +1,336 @@ +/****************************************************************************************/ +/* Render.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render polys under D3D */ +/* */ +/* 01/24/2002 Wendell Buckner */ +/* Change flags for speed... */ +/* 02/28/2001 Wendell Buckner */ +/* These render states are unsupported d3d 7.0 */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +#include "D3DDrv.h" */ +#include "D3DDrv7x.h" + +#include "DCommon.h" +#include "Render.h" +#include "Scene.h" +#include "GSpan.h" +#include "D3D_Fx.h" +#include "D3DCache.h" +#include "D3D_Err.h" +#include "THandle.h" + +#include "PCache.h" + +#define SNAP_VERT(v) ( ( v ) = ( float )( ( long )( ( v ) * 16 ) ) / 16.0f ) + +geBoolean DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags) +{ + int32 i; + DRV_TLVertex *pPnts; + D3DTLVERTEX D3DPnts[30], *pD3DPnts; + float ZRecip; + float Alpha; + + if(!AppInfo.RenderingIsOK) + return TRUE; + + if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + if (!PCache_FlushMiscPolys()) + return FALSE; + } + + Alpha = Pnts->a; + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + D3DSetTexture(0, NULL); + + int32 SAlpha = (int32)Alpha<<24; + pPnts = Pnts; + pD3DPnts = D3DPnts; + for (i=0; i< NumPoints; i++) + { + ZRecip = 1/pPnts->z; + + pD3DPnts->sx = pPnts->x; + pD3DPnts->sy = pPnts->y; + pD3DPnts->sz = (1.0f - ZRecip); // ZBUFFER + pD3DPnts->rhw = ZRecip; + pD3DPnts->color = SAlpha | ((int32)pPnts->r<<16) | ((int32)pPnts->g<<8) | (int32)pPnts->b; + + if (AppInfo.FogEnable && !(Flags & DRV_RENDER_POLY_NO_FOG)) // poly fog + { + DWORD FogVal; + float Val; + + Val = pPnts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DPnts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DPnts->specular = 0; + + pPnts++; + pD3DPnts++; + } + + D3DTexturedPolyOld(D3DPnts, NumPoints); + + if (Flags & DRV_RENDER_FLUSH) + { +/* 02/28/2001 Wendell Buckner + These render states are unsupported d3d 7.0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0);*/ + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + } + + return TRUE; +} + +geBoolean DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ +#ifdef USE_SPANS + int32 i; + DRV_TLVertex *CPnt; + int32 OldPixels; + int32 Mip = 0; + int32 MinY, MaxY, MinX, MaxX; + int32 FirstX, FirstY, x1, y1, x2, y2; + SPAN *pSpans; + int32 WidthHeight; +#endif + + if(!AppInfo.RenderingIsOK) + { + return TRUE; + } + else if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + } + +#ifdef USE_SPANS + if (RenderMode != RENDER_WORLD) + goto NotWorld; + + CPnt = Pnts; // Set to the first points in the array + + x1 = (int32)CPnt->x; + y1 = (int32)CPnt->y; + + FirstX = MinX = MaxX = x1; + FirstY = MinY = MaxY = y1; + + for (i = 1; i < NumPoints; i++) + { + CPnt++; + + x2 = (int32)CPnt->x; + y2 = (int32)CPnt->y; + + EdgeOutNoUV (x1, y1, x2, y2); + + if (x2 > MaxX) + MaxX = x2; + else if (x2 < MinX) + MinX = x2; + + if (y2 > MaxY) + MaxY = y2; + else if (y2 < MinY) + MinY = y2; + + // Swap + x1 = x2; + y1 = y2; + } + + // Close the poly + EdgeOutNoUV (x1, y1, FirstX, FirstY); + + OldPixels = NumWorldPixels; + + pSpans = &SpanLines[MinY]; + + WidthHeight = ClientWindow.Width*ClientWindow.Height; + for (i = MinY; i <= MaxY; i++, pSpans++) + { + AddSpanNoUV(pSpans->x1, pSpans->x2, i); + + if (NumWorldPixels >= WidthHeight) + break; + } + + if ((MaxY - MinY) < 3) + goto NotWorld; + + if ((MaxX - MinX) < 3) + goto NotWorld; + + if (NumWorldPixels == OldPixels) + return TRUE; + + NotWorld:; +#endif + + D3DDRV.NumRenderedPolys++; + + // Insert the poly into the world cache, for later rendering + PCache_InsertWorldPoly(Pnts, NumPoints, THandle, TexInfo, LInfo, Flags); + + if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + } + + return TRUE; +} + +geBoolean DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags) +{ + if(!AppInfo.RenderingIsOK) + { + return TRUE; + } + else if (Flags & DRV_RENDER_FLUSH) + { + PCache_FlushMiscPolys(); + } + + PCache_InsertMiscPoly(Pnts, NumPoints, THandle, Flags); + + if (Flags & DRV_RENDER_FLUSH) + { + PCache_FlushMiscPolys(); + } + + return TRUE; +} + +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) +{ + RECT SRect2, *pSRect; + int32 Width, Height; + HRESULT ddrval; + + if(!AppInfo.RenderingIsOK) + return TRUE; + + if (!SRect) + { + SRect2.left = 0; + SRect2.right = THandle->Width; + SRect2.top = 0; + SRect2.bottom = THandle->Height; + pSRect = &SRect2; + Width = (THandle->Width); + Height = (THandle->Height); + } + else + { + pSRect = SRect; + Width = (pSRect->right - pSRect->left)+1; + Height = (pSRect->bottom - pSRect->top)+1; + } + + if (x + Width <= 0) + return TRUE; + if (y + Height <= 0) + return TRUE; + + if (x >= ClientWindow.Width) + return TRUE; + + if (y >= ClientWindow.Height) + return TRUE; + + if (x + Width >= (ClientWindow.Width-1)) + pSRect->right -= ((x + Width) - (ClientWindow.Width-1)); + if (y + Height >= (ClientWindow.Height-1)) + pSRect->bottom -= ((y + Height) - (ClientWindow.Height-1)); + + if (x < 0) + { + pSRect->left += -x; + x=0; + } + if (y < 0) + { + pSRect->top += -y; + y=0; + } + +#if 0 + +/* 01/24/2002 Wendell Buckner + Change flags for speed... + AppInfo.lpBackBuffer->BltFast(x, y, THandle->MipData[0].Surface, pSRect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);*/ + AppInfo.lpBackBuffer->BltFast(x, y, THandle->MipData[0].Surface, pSRect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DONOTWAIT ); + +#else + RECT DRect; + + Width = (pSRect->right - pSRect->left); + Height = (pSRect->bottom - pSRect->top); + + DRect.left = x; + DRect.right = x+Width; + DRect.top = y; + DRect.bottom = y+Height; + +/* 01/24/2002 Wendell Buckner + Change flags for speed... + ddrval= AppInfo.lpBackBuffer->Blt(&DRect, THandle->MipData[0].Surface, pSRect, + (DDBLT_KEYSRC | DDBLT_WAIT), NULL);*/ + ddrval= AppInfo.lpBackBuffer->Blt(&DRect, THandle->MipData[0].Surface, pSRect, + (DDBLT_KEYSRC | DDBLT_DONOTWAIT | DDBLT_ASYNC ), NULL); + + if(ddrval==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return GE_FALSE; + } + //AppInfo.lpBackBuffer->Blt(&DRect, Decals[Handle].Surface, pSRect, (DDBLT_WAIT), NULL); +#endif + + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/D3D7xDrv/SCENE.H b/G3D/Engine/Drivers/D3D7xDrv/SCENE.H new file mode 100644 index 0000000..624f9c6 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/SCENE.H @@ -0,0 +1,46 @@ +/****************************************************************************************/ +/* Scene.h */ +/* */ +/* Author: John Pollard */ +/* Description: Begin/EndScene code, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SCENE_H +#define SCENE_H + +#include + +#include "DCommon.h" + +#define RENDER_NONE 0 +#define RENDER_WORLD 1 +#define RENDER_MESHES 2 +#define RENDER_MODELS 3 + +extern int32 RenderMode; + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *WorldRect); +BOOL DRIVERCC EndScene(void); +BOOL DRIVERCC BeginWorld(void); +BOOL DRIVERCC EndWorld(void); +BOOL DRIVERCC BeginMeshes(void); +BOOL DRIVERCC EndMeshes(void); +BOOL DRIVERCC BeginModels(void); +BOOL DRIVERCC EndModels(void); + +#endif + diff --git a/G3D/Engine/Drivers/D3D7xDrv/Scene.cpp b/G3D/Engine/Drivers/D3D7xDrv/Scene.cpp new file mode 100644 index 0000000..fbf2ef1 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/Scene.cpp @@ -0,0 +1,232 @@ +/****************************************************************************************/ +/* Scene.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Begin/EndScene code, etc */ +/* */ +/* 02/28/2001 Wendell Buckner +/* These render states are unsupported d3d 7.0 +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... */ +/* +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +#include "D3DDrv.h" */ +#include "D3DDrv7x.h" + +#include "DCommon.h" +#include "Scene.h" +#include "Render.h" +#include "GSpan.h" +#include "D3DCache.h" +#include "D3D_Fx.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "D3D_Err.h" +#include "THandle.h" + +//#define D3D_MANAGE_TEXTURES +#define SUPER_FLUSH + +int32 RenderMode; + +uint32 CurrentLRU; + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *WorldRect) +{ + HRESULT Result; + + CurrentLRU++; + + if (!AppInfo.lpD3DDevice) + { + D3DMain_Log("BeginScene: No D3D Device!."); + return FALSE; + } + + // Make sure we clear the cache info structure... + memset(&CacheInfo, 0, sizeof(DRV_CacheInfo)); + + if (!THandle_CheckCache()) + return GE_FALSE; + + // Watch for inactive app or minimize + if(AppInfo.RenderingIsOK) + { + if (!Main_ClearBackBuffer(Clear, ClearZ)) + { + D3DMain_Log("D3DClearBuffers failed."); + return FALSE; + } + + D3DDRV.NumRenderedPolys = 0; + + Result = AppInfo.lpD3DDevice->BeginScene(); + + if (Result != D3D_OK) + { + D3DMain_Log("BeginScene: D3D BeginScene Failed.\n%s.", D3DErrorToString(Result)); + return FALSE; + } + + D3DBilinearFilter(D3DFILTER_LINEAR, D3DFILTER_LINEAR); + D3DPolygonMode (D3DFILL_SOLID); + + D3DZWriteEnable (TRUE); + D3DZEnable(TRUE); + D3DZFunc(D3DCMP_LESSEQUAL); + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + D3DBlendEnable(TRUE); + + if (AppInfo.FogEnable) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR , ((DWORD)AppInfo.FogR<<16)|((DWORD)AppInfo.FogG<<8)|(DWORD)AppInfo.FogB); + } + else + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + } + } + + return TRUE; +} + +BOOL DRIVERCC EndScene(void) +{ + HRESULT Result; + + if (!AppInfo.lpD3DDevice) + return FALSE; + + if(AppInfo.RenderingIsOK) + { + // Flush everything one last time... + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + Result = AppInfo.lpD3DDevice->EndScene(); + + if (Result != D3D_OK) + { + D3DMain_Log("EndScene: D3D EndScene Failed.\n%s", D3DErrorToString(Result)); + return FALSE; + } + + if (!Main_ShowBackBuffer()) + return FALSE; + } + return TRUE; +} + +BOOL DRIVERCC BeginWorld(void) +{ + #ifdef USE_SPANS + if(AppInfo.RenderingIsOK) + { + ResetSpans(ClientWindow.Height); + } + #endif + + RenderMode = RENDER_WORLD; + return TRUE; +} + +BOOL DRIVERCC EndWorld(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + assert(AppInfo.lpD3DDevice); + #ifdef SUPER_FLUSH +/* 02/28/2001 Wendell Buckner + These render states are unsupported d3d 7.0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0);*/ + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + #endif + + } + return TRUE; +} + +BOOL GlobalMeshHack; + +BOOL DRIVERCC BeginMeshes(void) +{ + GlobalMeshHack = TRUE; + RenderMode = RENDER_MESHES; + return TRUE; +} + +BOOL DRIVERCC EndMeshes(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushMiscPolys(); + PCache_FlushWorldPolys(); + + #ifdef SUPER_FLUSH +/* 02/28/2001 Wendell Buckner + These render states are unsupported d3d 7.0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0);*/ + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + #endif + + GlobalMeshHack = FALSE; + } + return TRUE; +} + +BOOL DRIVERCC BeginModels(void) +{ + RenderMode = RENDER_MODELS; + return TRUE; +} + +BOOL DRIVERCC EndModels(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + #ifdef SUPER_FLUSH +/* 02/28/2001 Wendell Buckner + These render states are unsupported d3d 7.0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0);*/ + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + #endif + + } + return TRUE; +} diff --git a/G3D/Engine/Drivers/D3D7xDrv/THandle.cpp b/G3D/Engine/Drivers/D3D7xDrv/THandle.cpp new file mode 100644 index 0000000..39efea2 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/THandle.cpp @@ -0,0 +1,886 @@ +/****************************************************************************************/ +/* THandle.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for D3DDrv */ +/* */ +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. +/* 05/28/2000 Wendell Buckner +/* Running out of texture handles... +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "THandle.h" +#include "BaseType.h" + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +#include "D3DDrv.h" */ +#include "D3DDrv7x.h" + +#include "DCommon.h" +#include "D3DCache.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "D3d_FX.h" + +#include "TPage.h" + +//#define D3D_MANAGE_TEXTURES + +//#define USE_ONE_CACHE + +//05/28/2000 Wendell Buckner +//Running out of texture handles... +//#define MAX_TEXTURE_HANDLES 15000 + #define MAX_TEXTURE_HANDLES 32000 + +#define TEXTURE_CACHE_PERCENT 0.75f +#define LMAP_CACHE_PERCENT 0.25f + +#define TSTAGE_0 0 +#define TSTAGE_1 1 + +//============================================================================================ +//============================================================================================ + +geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; + +DDMemMgr *MemMgr; +DDMemMgr_Partition *Partition[2]; + +D3DCache *TextureCache; +D3DCache *LMapCache; + +TPage_Mgr *TPageMgr; + +DDSURFACEDESC2 CurrentSurfDesc; + +THandle_MipData SystemToVideo[MAX_LMAP_LOG_SIZE]; + +geBoolean CacheNeedsUpdate; +/* +#ifdef D3D_MANAGE_TEXTURES + #define NUM_LMAP_VIDEO_SURFACES 10; + THandle_MipData SystemToVideo[MAX_LMAP_LOG_SIZE]; +#endif +*/ + +//============================================================================================ +//============================================================================================ + +//============================================================================================ +// FreeAllcaches +//============================================================================================ +void FreeAllCaches(void) +{ + if (LMapCache) + D3DCache_Destroy(LMapCache); + + if (TextureCache) + D3DCache_Destroy(TextureCache); + + LMapCache = NULL; + TextureCache = NULL; + + if (Partition[1]) + DDMemMgr_PartitionDestroy(Partition[1]); + if (Partition[0]) + DDMemMgr_PartitionDestroy(Partition[0]); + if (MemMgr) + DDMemMgr_Destroy(MemMgr); + + +#ifdef USE_TPAGES + if (TPageMgr) + { + TPage_MgrDestroy(&TPageMgr); + TPageMgr = NULL; + } +#endif + + Partition[1] = NULL; + Partition[0] = NULL; + MemMgr = NULL; +} + +//============================================================================================ +// FindTextureHandle +//============================================================================================ +geRDriver_THandle *FindTextureHandle(void) +{ + int32 i; + geRDriver_THandle *pHandle; + + pHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pHandle++) + { + if (!pHandle->Active) + { + memset(pHandle, 0, sizeof(geRDriver_THandle)); + pHandle->Active = 1; + return pHandle; + } + } + + SetLastDrvError(DRV_ERROR_GENERIC, "D3D_FindTextureHandle: No more handles left.\n"); + + return NULL; +} + +//============================================================================================ +// FreeAllTextureHandles +//============================================================================================ +geBoolean FreeAllTextureHandles(void) +{ + int32 i; + geRDriver_THandle *pHandle; + + pHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pHandle++) + { + if (!pHandle->Active) + continue; + + if (!THandle_Destroy(pHandle)) + return GE_FALSE; + } + + return GE_TRUE; +} + +//============================================================================================ +//============================================================================================ +geBoolean THandle_Startup(void) +{ + // Create the main memory manager + MemMgr = DDMemMgr_Create(AppInfo.VidMemFree); + + if (!MemMgr) + goto ExitWithError; + + // Create partition 0 + Partition[0] = DDMemMgr_PartitionCreate(MemMgr, (uint32)((float)DDMemMgr_GetFreeMem(MemMgr)*TEXTURE_CACHE_PERCENT)); + + if (!Partition[0]) + goto ExitWithError; + + // Create partition 1 + Partition[1] = DDMemMgr_PartitionCreate(MemMgr, DDMemMgr_GetFreeMem(MemMgr)); + + if (!Partition[1]) + goto ExitWithError; + + // Create the texture cache from partition 0 + TextureCache = D3DCache_Create("Main Texture Cache", AppInfo.lpDD, Partition[0], AppInfo.CanDoMultiTexture); + + if (!TextureCache) + goto ExitWithError; + +#ifndef USE_ONE_CACHE + // Create the lmap cache from partition 1 + LMapCache = D3DCache_Create("Lightmap Cache", AppInfo.lpDD, Partition[1], AppInfo.CanDoMultiTexture); + + if (!LMapCache) + goto ExitWithError; +#endif + + // Create all the system to video surfaces (for lmaps) + if (!CreateSystemToVideoSurfaces()) + goto ExitWithError; + + #ifdef USE_TPAGES + TPageMgr = TPage_MgrCreate(AppInfo.lpDD, &AppInfo.ddTexFormat, 512); + if (!TPageMgr) + goto ExitWithError; + #endif + + return GE_TRUE; + + ExitWithError: + { + THandle_Shutdown(); + return GE_FALSE; + } +} + +//============================================================================================ +//============================================================================================ +void THandle_Shutdown(void) +{ + FreeAllTextureHandles(); + FreeAllCaches(); + DestroySystemToVideoSurfaces(); + + CacheNeedsUpdate = GE_FALSE; +} + +//============================================================================================ +// Create3DTHandle +//============================================================================================ +geRDriver_THandle *Create3DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 Size, i; + + assert(NumMipLevels < THANDLE_MAX_MIP_LEVELS); + assert(NumMipLevels <= 4); + + // Store width/height info + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = (1<Log); + + // Create the surfaces to hold all the mips + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + if (!THandle->MipData) + { + THandle_Destroy(THandle); + return NULL; + } + + Size = 1<Log; + + // Create all the surfaces for each mip level + for (i=0; i< NumMipLevels; i++) + { + int32 Stage; + + if (!THandle_CreateSurfaces(&THandle->MipData[i], Size, Size, &CurrentSurfDesc, GE_FALSE, 0)) + { + THandle_Destroy(THandle); + return NULL; + } + + // get a cache type for this surface since it is a 3d surface, and will need to be cached on the video card + //THandle->MipData[i].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, NumMipLevels, &CurrentSurfDesc); + // We can use 1 miplevel for the type, since we are createing types for each miplevel... + if (AppInfo.CanDoMultiTexture) + Stage = TSTAGE_0; + else + Stage = 0; + + THandle->MipData[i].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, 1, Stage, &CurrentSurfDesc); + + if (!THandle->MipData[i].CacheType) + { + THandle_Destroy(THandle); + return NULL; + } + + Size>>=1; + } + + return THandle; +} + +//============================================================================================ +// CreateLightmapTHandle +//============================================================================================ +geRDriver_THandle *CreateLightmapTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 Size, Stage; + + assert(NumMipLevels < THANDLE_MAX_MIP_LEVELS); + + assert(NumMipLevels == 1); + + // Save some info about the lightmap + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = 1<Log; + + assert(THandle->Log < MAX_LMAP_LOG_SIZE); + + Size = 1<Log; + + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + THandle->MipData[0].Flags = THANDLE_UPDATE; + +#ifdef D3D_MANAGE_TEXTURES + #ifndef USE_TPAGES + { + int32 Stage; + + if (AppInfo.CanDoMultiTexture) + Stage = STAGE_1; + else + Stage = 0; + + if (!THandle_CreateSurfaces(&THandle->MipData[0], Size, Size, &CurrentSurfDesc, GE_FALSE, Stage)) + { + THandle_Destroy(THandle); + return NULL; + } + +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. + D3DSetTexture(0, THandle->MipData[0].Texture); */ + D3DSetTexture(0, THandle->MipData[0].Surface); + + } + #endif +#endif + + if (AppInfo.CanDoMultiTexture) + Stage = TSTAGE_1; + else + Stage = 0; + +#ifdef USE_ONE_CACHE + THandle->MipData[0].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, NumMipLevels, Stage, &CurrentSurfDesc); +#else + THandle->MipData[0].CacheType = D3DCache_TypeCreate(LMapCache, Size, Size, NumMipLevels, Stage, &CurrentSurfDesc); +#endif + + if (!THandle->MipData[0].CacheType) + { + THandle_Destroy(THandle); + return NULL; + } + + return THandle; +} + +//============================================================================================ +// Create2DTHandle +//============================================================================================ +geRDriver_THandle *Create2DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + assert(NumMipLevels < THANDLE_MAX_MIP_LEVELS); + assert(NumMipLevels == 1); + + // Save some info about the lightmap + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = Width; + + // Create the surfaces to hold all the mips + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + if (!THandle->MipData) + { + THandle_Destroy(THandle); + return NULL; + } + + if (!THandle_CreateSurfaces(&THandle->MipData[0], Width, Height, &CurrentSurfDesc, GE_TRUE, 0)) + { + THandle_Destroy(THandle); + return NULL; + } + + return THandle; +} + +//============================================================================================ +// SetupCurrent3dDesc +//============================================================================================ +geBoolean SetupCurrent3dDesc(gePixelFormat PixelFormat) +{ + switch (PixelFormat) + { + case GE_PIXELFORMAT_16BIT_555_RGB: + case GE_PIXELFORMAT_16BIT_565_RGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddTexFormat, sizeof(DDSURFACEDESC2)); + break; + } + case GE_PIXELFORMAT_16BIT_4444_ARGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddFourBitAlphaSurfFormat, sizeof(DDSURFACEDESC2)); + break; + } + case GE_PIXELFORMAT_16BIT_1555_ARGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddOneBitAlphaSurfFormat, sizeof(DDSURFACEDESC2)); + break; + } + + default: + { + SetLastDrvError(DRV_ERROR_GENERIC, "SetupCurrent3dDesc: Invalid pixel format.\n"); + return GE_FALSE; + } + } + + return GE_TRUE; +} +//============================================================================================ +// THandle_Create +//============================================================================================ +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + geRDriver_THandle *THandle; + + THandle = FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "D3DDRV:THandle_Create: Out of texture handles.\n"); + return NULL; + } + + THandle->PixelFormat = *PixelFormat; + + if (PixelFormat->Flags & RDRIVER_PF_3D) + { + // Get the pixel format desc for this thandle + if (!SetupCurrent3dDesc(PixelFormat->PixelFormat)) + return NULL; + + if (!Create3DTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + + CacheNeedsUpdate = GE_TRUE; + } + else if (PixelFormat->Flags & RDRIVER_PF_LIGHTMAP) + { + // Get the pixel format desc for this thandle + if (!SetupCurrent3dDesc(PixelFormat->PixelFormat)) + return NULL; + + if (!CreateLightmapTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + + CacheNeedsUpdate = GE_TRUE; + } + else if (PixelFormat->Flags & RDRIVER_PF_2D) + { + // 2d surfaces are always this format for now + memcpy(&CurrentSurfDesc, &AppInfo.ddSurfFormat, sizeof(DDSURFACEDESC2)); + + if (!Create2DTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + } + + return THandle; +} + +//============================================================================================ +// THandle_Destroy +//============================================================================================ +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle) +{ + int32 i; + + assert(THandle); + assert(THandle->Active); + + for (i=0; i< THandle->NumMipLevels; i++) + { + assert(THandle->MipData); + + if (THandle->MipData[i].CacheType) + { + D3DCache_TypeDestroy(THandle->MipData[i].CacheType); + CacheNeedsUpdate = GE_TRUE; + THandle->MipData[i].CacheType = NULL; + } + + if (THandle->MipData[i].Surface) + { + assert(THandle->MipData[i].Texture); + + THandle_DestroySurfaces(&THandle->MipData[i]); + THandle->MipData[i].Surface = NULL; + THandle->MipData[i].Texture = NULL; + } + } + + if (THandle->MipData) + free(THandle->MipData); + + memset(THandle, 0, sizeof(geRDriver_THandle)); + + return GE_TRUE; +} + +//===================================================================================== +//===================================================================================== +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Bits) +{ + DDSURFACEDESC2 SurfDesc; + HRESULT Result; + + assert(!(THandle->MipData[MipLevel].Flags & THANDLE_LOCKED)); + + // Lock the surface so it can be filled with the data + memset(&SurfDesc, 0, sizeof(DDSURFACEDESC2)); + SurfDesc.dwSize = sizeof(DDSURFACEDESC2); + +/* 03/10/2002 Wendell Buckner + Procedural Textures + if you must lock a texture specify the flags WRITEONLY and DISCARDCONTENTS when + Result = THandle->MipData[MipLevel].Surface->Lock(NULL, &SurfDesc , DDLOCK_WAIT, NULL);*/ + Result = THandle->MipData[MipLevel].Surface->Lock(NULL, &SurfDesc , DDLOCK_WAIT | DDLOCK_WRITEONLY | DDLOCK_DISCARDCONTENTS, NULL); + + if (Result != DD_OK) + { + return GE_FALSE; + } + + THandle->MipData[MipLevel].Flags |= THANDLE_LOCKED; + + *Bits = (void*)SurfDesc.lpSurface; + + return GE_TRUE; +} + +//===================================================================================== +// THandle_UnLock +//===================================================================================== +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel) +{ + HRESULT Result; + + assert(MipLevel <= THandle->NumMipLevels); + assert(THandle->MipData[MipLevel].Flags & THANDLE_LOCKED); + + // Unlock the surface + Result = THandle->MipData[MipLevel].Surface->Unlock(NULL); + + if (Result != DD_OK) + { + return GE_FALSE; + } + + THandle->MipData[MipLevel].Flags |= THANDLE_UPDATE; + THandle->MipData[MipLevel].Flags &= ~THANDLE_LOCKED; + + return GE_TRUE; +} + +#ifndef NDEBUG +#define DebugIf(a, b) if (a) b +#else +#define DebugIf(a, b) +#endif + +//===================================================================================== +// THandle_GetInfo +//===================================================================================== +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info) +{ + DebugIf (MipLevel > THandle->Log, return GE_FALSE); + + Info->Width = THandle->Width>>MipLevel; + Info->Height = THandle->Height>>MipLevel; + Info->Stride = THandle->Stride>>MipLevel; + + if (THandle->PixelFormat.Flags & RDRIVER_PF_CAN_DO_COLORKEY) + { + Info->Flags = RDRIVER_THANDLE_HAS_COLORKEY; + Info->ColorKey = 1; + } + else + { + Info->Flags = 0; + Info->ColorKey = 0; + } + + Info->PixelFormat = THandle->PixelFormat; + + return GE_TRUE; +} + +//===================================================================================== +// CreateSystemToVideoSurfaces +// System surfaces to copy from system to video +//===================================================================================== +geBoolean CreateSystemToVideoSurfaces(void) +{ + int32 i; + DDSURFACEDESC2 SurfDesc; + + memcpy(&SurfDesc, &AppInfo.ddTexFormat, sizeof(DDSURFACEDESC2)); + + for (i=0; iCreateSurface(&ddsd, &Surface, NULL); + + if(Hr != DD_OK) + { + return FALSE; + } + + Surf->Surface = Surface; + +/* 02/25/2001 Wendell Buckner + This texture pointer is no longer valid under directx 7. Set it to TRUE so there is + something there when the code does assert checks. + Surf->Texture = NULL; */ + Surf->Texture = Surface; + +/* 02/25/2001 Wendell Buckner + This texture pointer is no longer valid under directx 7. Set it to TRUE so there is + something there when the code does assert checks. + Hr = Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Surf->Texture); + + if(Hr != DD_OK) + { + Surface->Release(); + return GE_FALSE; + }*/ + + if (ColorKey) + { + DDCOLORKEY CKey; + + // Create the color key for this surface + CKey.dwColorSpaceLowValue = 1; + CKey.dwColorSpaceHighValue = 1; + + if (Surf->Surface->SetColorKey(DDCKEY_SRCBLT , &CKey) != DD_OK) + { + SetLastDrvError(DRV_ERROR_GENERIC, "THandle_CreateSurfaces: SetColorKey failed for texture."); + Surf->Surface->Release(); + Surf->Surface = NULL; + +/* 02/25/2001 Wendell Buckner + This texture pointer is no longer valid under directx 7. Set it to TRUE so there is + Surf->Texture->Release();*/ + Surf->Texture = NULL; + + return FALSE; + } + } + return GE_TRUE; // All good dude +} + +//===================================================================================== +// DestroySystemSurface +//===================================================================================== +void THandle_DestroySurfaces(THandle_MipData *Surf) +{ +/* 02/25/2001 Wendell Buckner + This texture pointer is no longer valid under directx 7. Set it to TRUE so there is + if (Surf->Texture) + Surf->Texture->Release();*/ + + if (Surf->Surface) + Surf->Surface->Release(); + + memset(Surf, 0, sizeof (THandle_MipData)); +} + +//===================================================================================== +// THandle_CheckCache +//===================================================================================== +geBoolean THandle_CheckCache(void) +{ + geRDriver_THandle *pTHandle; + int32 i, Stage0, Stage1; + int32 MaxTable1[9], MaxTable2[9]; + + if (!CacheNeedsUpdate) + return GE_TRUE; + +#ifndef D3D_MANAGE_TEXTURES // If D3D is managing textures, then we don't ned to do any of this... + D3DMain_Log("THandle_CheckCache: Resetting texture cache...\n"); + +#ifdef USE_ONE_CACHE + #pragma message ("There numbers ARE NOT DONE. So if USE_ONE_CACHE is defined, please finish this...") + // Texture cache & Lightmap cache (we are only using one cache, so the combine into the TextureCache) + MaxTable1[0] = 256; // 1x1 + MaxTable1[1] = 256; // 2x2 + MaxTable1[2] = 256; // 4x4 + MaxTable1[3] = 512; // 8x8 + MaxTable1[4] = 512; // 16x16 + MaxTable1[5] = 512; // 32x32 + MaxTable1[6] = 512; // 64x64 + MaxTable1[7] = 256; //128x128 + MaxTable1[8] = 256; //256x256 +#else + if (AppInfo.DeviceIdentifier.dwVendorId == 4634) // 3dfx series have a limit on the number of texture handles + { + D3DMain_Log(" 3dfx card detected, using smaller number of handles...\n"); + + // Texture cache + MaxTable1[0] = 24; // 1x1 + MaxTable1[1] = 24; // 2x2 + MaxTable1[2] = 24; // 4x4 + MaxTable1[3] = 24; // 8x8 + MaxTable1[4] = 24; // 16x16 + MaxTable1[5] = 128; // 32x32 + MaxTable1[6] = 128; // 64x64 + MaxTable1[7] = 128; //128x128 + MaxTable1[8] = 128; //256x256 + + // Lightmap cache + MaxTable2[0] = 128; // 1x1 + MaxTable2[1] = 128; // 2x2 + MaxTable2[2] = 256; // 4x4 + MaxTable2[3] = 256; // 8x8 + MaxTable2[4] = 256; // 16x16 + MaxTable2[5] = 128; // 32x32 + MaxTable2[6] = 128; // 64x64 + MaxTable2[7] = 128; //128x128 + MaxTable2[8] = 128; //256x256 + } + else + { + D3DMain_Log(" NO 3dfx card detected, using larger number of handles...\n"); + + // Texture cache + MaxTable1[0] = 32; // 1x1 + MaxTable1[1] = 32; // 2x2 + MaxTable1[2] = 32; // 4x4 + MaxTable1[3] = 32; // 8x8 + MaxTable1[4] = 32; // 16x16 + MaxTable1[5] = 32; // 32x32 + MaxTable1[6] = 128; // 64x64 + MaxTable1[7] = 128; //128x128 + MaxTable1[8] = 128; //256x256 + + MaxTable2[0] = 128; // 1x1 + MaxTable2[1] = 128; // 2x2 + MaxTable2[2] = 256; // 4x4 + MaxTable2[3] = 1024; // 8x8 + MaxTable2[4] = 1024; // 16x16 + MaxTable2[5] = 512; // 32x32 + MaxTable2[6] = 256; // 64x64 + MaxTable2[7] = 256; //128x128 + MaxTable2[8] = 256; //256x256 + } +#endif + + if (AppInfo.CanDoMultiTexture) + { + Stage0 = TSTAGE_0; + Stage1 = TSTAGE_1; + } + else + { + Stage0 = 0; + Stage1 = 0; + } + + #ifndef USE_ONE_CACHE + if (!D3DCache_AdjustSlots(LMapCache, MaxTable2, GE_TRUE)) + { + D3DMain_Log("THandle_CheckCache: D3DCache_AdjustSlots failed for LMapCache.\n"); + return GE_FALSE; + } + #endif + + if (!D3DCache_AdjustSlots(TextureCache, MaxTable1, GE_FALSE)) + { + D3DMain_Log("THandle_CheckCache: D3DCache_AdjustSlots failed for TextureCache.\n"); + return GE_FALSE; + } + +#endif + + // Make sure no THandles reference any slots, because they mave have been moved around, or gotten destroyed... + // (Evict all textures in the cache) + pTHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pTHandle++) + { + int32 m; + + for (m=0; m< pTHandle->NumMipLevels; m++) + { + pTHandle->MipData[m].Slot = NULL; + } + } + + CacheNeedsUpdate = GE_FALSE; + + return GE_TRUE; +} diff --git a/G3D/Engine/Drivers/D3D7xDrv/THandle.h b/G3D/Engine/Drivers/D3D7xDrv/THandle.h new file mode 100644 index 0000000..88c7d0d --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/THandle.h @@ -0,0 +1,116 @@ +/****************************************************************************************/ +/* THandle.h */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for D3DDrv */ +/* */ +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef THANDLE_H +#define THANDLE_H + +#include + +#include "BaseType.h" +#include "DCommon.h" +#include "D3DCache.h" + +#include "TPage.h" + +//============================================================================================ +//============================================================================================ +#define THANDLE_MAX_MIP_LEVELS 255 +//#define MAX_LMAP_LOG_SIZE 8 // Max lightmap size in pixels will be 128x128 +//#define MAX_LMAP_LOG_SIZE 7 // Max lightmap size in pixels will be 64x64 +#define MAX_LMAP_LOG_SIZE 6 // Max lightmap size in pixels will be 32x32 + +typedef struct +{ +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAWSURFACE4 Surface; // The DD surface*/ + LPDIRECTDRAWSURFACE7 Surface; // The DD surface + + D3DCache_Type *CacheType; + D3DCache_Slot *Slot; + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECT3DTEXTURE2 Texture; // The DD surface*/ + LPDIRECTDRAWSURFACE7 Texture; // The texture interface to the surface + + uint8 Flags; +} THandle_MipData; + +// THandle flags +#define THANDLE_LOCKED (1<<0) +#define THANDLE_UPDATE (1<<1) + +typedef struct geRDriver_THandle +{ + uint8 Active; + int32 Width; + int32 Height; + int32 Stride; + uint8 NumMipLevels; + uint8 Log; + + THandle_MipData *MipData; // A mipdata per miplevel + + geRDriver_PixelFormat PixelFormat; + +#ifdef USE_TPAGES + TPage_Block *Block; +#endif + +} geRDriver_THandle; + +extern geRDriver_THandle TextureHandles[]; + +extern D3DCache *TextureCache; +extern D3DCache *LMapCache; + +extern TPage_Mgr *TPageMgr; + +extern THandle_MipData SystemToVideo[]; + +extern CacheNeedsUpdate; + +//============================================================================================ +//============================================================================================ +void FreeAllCaches(void); +geRDriver_THandle *FindTextureHandle(void); +geBoolean FreeAllTextureHandles(void); +geBoolean THandle_Startup(void); +void THandle_Shutdown(void); +geRDriver_THandle *Create3DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *CreateLightmapTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *Create2DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle); +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Bits); +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel); +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info); +geBoolean CreateSystemToVideoSurfaces(void); +void DestroySystemToVideoSurfaces(void); +geBoolean THandle_CreateSurfaces(THandle_MipData *MipData, int32 Width, int32 Height, DDSURFACEDESC2 *SurfDesc, geBoolean ColorKey, int32 Stage); +void THandle_DestroySurfaces(THandle_MipData *MipData); +geBoolean THandle_CheckCache(void); + +#endif diff --git a/G3D/Engine/Drivers/D3D7xDrv/TPage.h b/G3D/Engine/Drivers/D3D7xDrv/TPage.h new file mode 100644 index 0000000..9925847 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/TPage.h @@ -0,0 +1,98 @@ +/****************************************************************************************/ +/* TPage.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager using pages */ +/* */ +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef TPAGE_H +#define TPAGE_H + +#include + +#include +#include + +typedef struct TPage_Mgr TPage_Mgr; +typedef struct TPage TPage; +typedef struct TPage_Block TPage_Block; + +// +// TPage_Mgr +// + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages); */ +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW7 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages); + +void TPage_MgrDestroy(TPage_Mgr **TPageMgr); +geBoolean TPage_MgrHasTPage(TPage_Mgr *Mgr, TPage *Page); +geBoolean TPage_MgrAttachTPage(TPage_Mgr *Mgr, TPage *TPage); +void TPage_MgrDetachTPage(TPage_Mgr *Mgr, TPage *TPage); +TPage_Block *TPage_MgrFindOptimalBlock(TPage_Mgr *Mgr, uint32 LRU); + +// +// TPage +// + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +TPage *TPage_Create(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc); */ +TPage *TPage_Create(LPDIRECTDRAW7 lpDD, const DDSURFACEDESC2 *SurfDesc); + +void TPage_CreateRef(TPage *Page); +void TPage_Destroy(TPage **Page1); +geBoolean TPage_HasBlock(TPage *TPage, TPage_Block *Block); +geBoolean TPage_AttachBlock(TPage *Page, TPage_Block *Block); +void TPage_DetachBlock(TPage *TPage, TPage_Block *Block); + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc);*/ +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW7 lpDD, const DDSURFACEDESC2 *SurfDesc); + +void TPage_DestroySurfaces(TPage *Page); + +// +//TPage_Block +// + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE4 Surface, LPDIRECT3DTEXTURE2 Texture, const RECT *Rect);*/ +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE7 Surface, LPDIRECTDRAWSURFACE7 Texture, const RECT *Rect); + + +geBoolean TPage_BlockCreateRef(TPage_Block *Block); +void TPage_BlockDestroy(TPage_Block **Block); + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +LPDIRECT3DTEXTURE2 TPage_BlockGetTexture(TPage_Block *Block); +LPDIRECTDRAWSURFACE4 TPage_BlockGetSurface(TPage_Block *Block);*/ +LPDIRECTDRAWSURFACE7 TPage_BlockGetTexture(TPage_Block *Block); +LPDIRECTDRAWSURFACE7 TPage_BlockGetSurface(TPage_Block *Block); + +const RECT *TPage_BlockGetRect(TPage_Block *Block); +void TPage_BlockSetLRU(TPage_Block *Block, uint32 LRU); +void TPage_BlockSetUserData(TPage_Block *Block, void *UserData); +void *TPage_BlockGetUserData(TPage_Block *Block); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D7xDrv/mssccprj.scc b/G3D/Engine/Drivers/D3D7xDrv/mssccprj.scc new file mode 100644 index 0000000..848e217 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/mssccprj.scc @@ -0,0 +1,4 @@ +SCC = This is a Source Code Control file + +[D3DDrv.mak] +SCC_Project_Name = "$/Genesis10/Source/Engine/Drivers/D3DDrv", LQQBAAAA diff --git a/G3D/Engine/Drivers/D3D7xDrv/tpage.cpp b/G3D/Engine/Drivers/D3D7xDrv/tpage.cpp new file mode 100644 index 0000000..901ae26 --- /dev/null +++ b/G3D/Engine/Drivers/D3D7xDrv/tpage.cpp @@ -0,0 +1,739 @@ +/****************************************************************************************/ +/* TPage.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager using pages */ +/* */ +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. +/* 07/16/2000 Wendell Buckner +/* Convert to Directx7... +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "BaseType.h" +#include "TPage.h" + +// These must be a power of 2!!! +#define TPAGE_WIDTH 16 // Width of TPAges +#define TPAGE_HEIGHT 16 // Height of TPages + +#define TPAGE_GRID_X 16 // Must be <= TPAGE_WIDTH, and power of 2 +#define TPAGE_GRID_Y 16 // Must be <= TPAGE_HEIGHT, and power of 2 + +// NOTE - Blocks Width/Height that go into TPages MUST be <= AlignX/AlignY!!! + +typedef struct TPage_Block +{ + int32 RefCount; // Number of references to this object + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this Block + LPDIRECT3DTEXTURE2 Texture; // The Texture interface to the surface*/ + LPDIRECTDRAWSURFACE7 Surface; // The DD surface for this Block + LPDIRECTDRAWSURFACE7 Texture; // The Texture interface to the surface + + RECT Rect; // The Rect into the surface that this block can use + + uint32 LRU; // Set to the TPage->TPageMgr->LRU when accesed... + + void *UserData; + + struct TPage_Block *Prev; + struct TPage_Block *Next; + +} TPage_Block; + +typedef struct TPage +{ + int32 RefCount; + + DDSURFACEDESC2 SurfaceDesc; // Surface description of this page (note all blocks must use this format!!!) + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this TPage + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface */ + LPDIRECTDRAWSURFACE7 Surface; // The DD surface for this TPage + LPDIRECTDRAWSURFACE7 Texture; // The texture interface to the surface + + TPage_Block *Blocks; // Linked list of blocks + + uint32 LRU; + + struct TPage *Prev; + struct TPage *Next; +} TPage; + +typedef struct TPage_Mgr +{ + int32 NumPages; + + TPage *TPages; // Linked list of TPages + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... + LPDIRECTDRAW4 lpDD; // DD object used to create surfaces */ + LPDIRECTDRAW7 lpDD; // DD object used to create surfaces + +} TPage_Mgr; + +//============================================================================ +// *** TPage_Mgr *** +//============================================================================ + +//============================================================================ +// TPage_MgrCreate +//============================================================================ + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages) */ +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW7 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages) + +{ + TPage_Mgr *TPageMgr; + int32 i; + + TPageMgr = (TPage_Mgr*)malloc(sizeof(TPage_Mgr)); + + if (!TPageMgr) + return NULL; + + memset(TPageMgr, 0, sizeof(TPage_Mgr)); + + // Remeber the DD object + TPageMgr->lpDD = lpDD; + // Ref the dd object + lpDD->AddRef(); + + TPageMgr->NumPages = NumPages; + + // Create the pages + for (i=0; iTPages; Page; Page = Next) + { + Next = Page->Next; + + TPage_MgrDetachTPage(Mgr, Page); + TPage_Destroy(&Page); + } + + assert(Mgr->TPages == NULL); + + // Release our ref on the DD object + Mgr->lpDD->Release(); + + free(*TPageMgr); + + *TPageMgr = NULL; +} + +//============================================================================ +// TPage_MgrHasTPage +//============================================================================ +geBoolean TPage_MgrHasTPage(TPage_Mgr *Mgr, TPage *Page) +{ + TPage *Page2; + + assert(Mgr); + assert(Page); + + for (Page2 = Mgr->TPages; Page2; Page2 = Page2->Next) + { + if (Page2 == Page) + { + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//============================================================================ +// TPage_MgrAttachTPage +// NOTE - A TPage can only attach to one TPage_Mgr, and only ONCE!! +//============================================================================ +geBoolean TPage_MgrAttachTPage(TPage_Mgr *Mgr, TPage *TPage) +{ + assert(TPage_MgrHasTPage(Mgr, TPage) == GE_FALSE); + assert(TPage->Prev == NULL); + assert(TPage->Next == NULL); + + if (Mgr->TPages) + Mgr->TPages->Prev = TPage; + + TPage->Prev = NULL; + TPage->Next = Mgr->TPages; + Mgr->TPages = TPage; + + return GE_TRUE; +} + +//============================================================================ +// TPage_MgrDetachTPage +//============================================================================ +void TPage_MgrDetachTPage(TPage_Mgr *Mgr, TPage *TPage) +{ + assert(Mgr); + assert(TPage); + assert(TPage_MgrHasTPage(Mgr, TPage) == GE_TRUE); + + if (TPage->Next) + TPage->Next->Prev = TPage->Prev; + + if (TPage->Prev) + TPage->Prev->Next = TPage->Prev; + else + { + // If we get here, this better be the first TPage in the list! + assert(Mgr->TPages == TPage); + Mgr->TPages = TPage->Next; + } + + TPage->Next = NULL; + TPage->Prev = NULL; +} + +//============================================================================ +// TPage_MgrFindOptimalBlock +//============================================================================ +TPage_Block *TPage_MgrFindOptimalBlock(TPage_Mgr *Mgr, uint32 LRU) +{ +#if 0 + TPage *Page, *BestPage; + TPage_Block *Block, *BestBlock; + uint32 BestLRU; + + // We really should make a TPage_GetOptimalBlock... + + // First, find the page that has the highest LRU + BestLRU = 0; + BestPage = Mgr->TPages; + + for (Page = Mgr->TPages; Page; Page = Page->Next) + { + if (Page->LRU > BestLRU && Page->NumFull) + { + BestPage = Page; + BestLRU = Page->LRU; + } + } + + // Now, find the block with the lowest LRU in this page + BestBlock = BestPage->Blocks; + BestLRU = 0xffffffff; + + for (Block = BestPage->Blocks; Block; Block = Block->Next) + { + if (Block->LRU < BestLRU) + { + BestBlock = Block; + BestLRU = Block->LRU; + } + } + /* + if (BestBlock->LRU == LRU) + BestPage->NumFull++; + else + */ + BestBlock->LRU = LRU; + BestPage->LRU = LRU; +#else + TPage *Page; + TPage_Block *Block, *BestBlock; + uint32 BestLRU; + + // We really should make a TPage_GetOptimalBlock... + BestBlock = NULL; + BestLRU = 0xffffffff; + + for (Page = Mgr->TPages; Page; Page = Page->Next) + { + for (Block = Page->Blocks; Block; Block = Block->Next) + { + if (Block->LRU < BestLRU) + { + BestBlock = Block; + BestLRU = Block->LRU; + } + } + } + + BestBlock->LRU = LRU; +#endif + + return BestBlock; +} + +//============================================================================ +// *** TPage *** +//============================================================================ + +//============================================================================ +// TPage_Create +//============================================================================ + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +TPage *TPage_Create(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc) */ +TPage *TPage_Create(LPDIRECTDRAW7 lpDD, const DDSURFACEDESC2 *SurfDesc) + +{ + TPage *Page; + int32 w, h; + + Page = (TPage*)malloc(sizeof(TPage)); + + if (!Page) + return NULL; + + memset(Page, 0, sizeof(TPage)); + + Page->SurfaceDesc = *SurfDesc; + + TPage_CreateRef(Page); // Create the very first ref + + if (!TPage_CreateSurfaces(Page, lpDD, SurfDesc)) + { + free(Page); + return NULL; + } + + // Create the blocks + for (h=0; hSurface, Page->Texture, &Rect); + + if (!Block) + goto ExitWithError; + + if (!TPage_AttachBlock(Page, Block)) + goto ExitWithError; + } + } + + return Page; + + ExitWithError: + { + if (Page) + TPage_Destroy(&Page); + + return NULL; + } +} + +//============================================================================ +// TPage_CreateRef +//============================================================================ +void TPage_CreateRef(TPage *Page) +{ + assert(Page->RefCount >= 0); // Refs can == 0, because thats what they are when TPages are first created + + Page->RefCount++; +} + +//============================================================================ +// TPage_Destroy +//============================================================================ +void TPage_Destroy(TPage **Page1) +{ + TPage *Page; + TPage_Block *Block, *Next; + + assert(Page1); + Page = *Page1; + + assert(Page); + assert(Page->RefCount > 0); + + Page->RefCount--; + + if (Page->RefCount > 0) + return; + + // Destroy any dd surfaces for this page + TPage_DestroySurfaces(Page); + + // Destroy all the blocks this page has + for (Block = Page->Blocks; Block; Block = Next) + { + Next = Block->Next; + + TPage_DetachBlock(Page, Block); + TPage_BlockDestroy(&Block); + } + + assert(Page->Blocks == NULL); + + free(*Page1); + + *Page1 = NULL; +} + +//============================================================================ +// TPage_HasBlock +//============================================================================ +geBoolean TPage_HasBlock(TPage *TPage, TPage_Block *Block) +{ + TPage_Block *Block2; + + assert(TPage); + assert(Block); + + for (Block2 = TPage->Blocks; Block2; Block2 = Block2->Next) + { + if (Block2 == Block) + { + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//============================================================================ +// TPage_AttachBlock +// NOTE - A Block can only attach to one TPage, and only ONCE!! +//============================================================================ +geBoolean TPage_AttachBlock(TPage *Page, TPage_Block *Block) +{ + assert(TPage_HasBlock(Page, Block) == GE_FALSE); + assert(Block->Prev == NULL); + assert(Block->Next == NULL); + + // Insert the block into the list of blocks for this Page + if (Page->Blocks) + Page->Blocks->Prev = Block; + + Block->Prev = NULL; + Block->Next = Page->Blocks; + + Page->Blocks = Block; + + return GE_TRUE; +} + +//============================================================================ +// TPage_DetachBlock +//============================================================================ +void TPage_DetachBlock(TPage *TPage, TPage_Block *Block) +{ + assert(TPage); + assert(Block); + assert(TPage_HasBlock(TPage, Block) == GE_TRUE); + + if (Block->Next) + Block->Next->Prev = Block->Prev; + + if (Block->Prev) + Block->Prev->Next = Block->Prev; + else + { + // If we get here, this better be the first Block in the list! + assert(TPage->Blocks == Block); + TPage->Blocks = Block->Next; + } + + // Reset the Block link + Block->Next = NULL; + Block->Prev = NULL; +} + +//===================================================================================== +// TPage_CreateSurfaces +//===================================================================================== + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc) */ +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW7 lpDD, const DDSURFACEDESC2 *SurfDesc) +{ + HRESULT Hr; + DDSURFACEDESC2 ddsd; + + assert(Page); + + memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTDYNAMIC; + + ddsd.ddsCaps.dwCaps3 = 0; + ddsd.ddsCaps.dwCaps4 = 0; + + ddsd.dwWidth = TPAGE_WIDTH; + ddsd.dwHeight = TPAGE_HEIGHT; + + Hr = lpDD->CreateSurface(&ddsd, &Page->Surface, NULL); + + if (Hr != DD_OK) + return GE_FALSE; + +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. + Hr = Page->Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Page->Texture); + + if(Hr != DD_OK) + { + Page->Surface->Release(); + Page->Surface = NULL; + Page->Texture = NULL; + return GE_FALSE; + }*/ + Page->Texture = Page->Surface; + + return GE_TRUE; // All good dude +} + + +//===================================================================================== +// TPage_DestroySurfaces +//===================================================================================== +void TPage_DestroySurfaces(TPage *Page) +{ + assert(Page); + + if (Page->Texture) + { +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. + Page->Texture->Release();*/ + Page->Texture = NULL; + } + + if (Page->Surface) + { + Page->Surface->Release(); + Page->Surface = NULL; + } +} + +//============================================================================ +// *** TPage_Block *** +//============================================================================ + +//============================================================================ +// TPage_BlockCreate +//============================================================================ + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE4 Surface, LPDIRECT3DTEXTURE2 Texture, const RECT *Rect) */ +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE7 Surface, LPDIRECTDRAWSURFACE7 Texture, const RECT *Rect) + +{ + TPage_Block *Block; + + Block = (TPage_Block*)malloc(sizeof(TPage_Block)); + + if (!Block) + return NULL; + + memset(Block, 0, sizeof(TPage_Block)); + + Surface->AddRef(); // Ref the surface + +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. + Texture->AddRef(); // Ditto...*/ + + // Save off the surface, texture, and rect into the surface + Block->Surface = Surface; + Block->Texture = Texture; + Block->Rect = *Rect; + + TPage_BlockCreateRef(Block); // Create very first ref + + return Block; +} + +//============================================================================ +// TPage_BlockCreateRef +//============================================================================ +geBoolean TPage_BlockCreateRef(TPage_Block *Block) +{ + assert(Block); + + Block->RefCount++; + + return GE_TRUE; +} + +//============================================================================ +// TPage_BlockDestroy +//============================================================================ +void TPage_BlockDestroy(TPage_Block **Block) +{ + TPage_Block *Block2; + + assert(Block); + + Block2 = *Block; + + assert(Block2); + assert(Block2->RefCount > 0); + + Block2->RefCount--; + + if (Block2->RefCount > 0) + return; + + // Destroy references to the surface and texture + if (Block2->Surface) + Block2->Surface->Release(); + +/* 02/25/2001 Wendell Buckner +/* This texture pointer is no longer valid under directx 7. Set it to TRUE so there is +/* something there when the code does assert checks. + if (Block2->Texture) + Block2->Texture->Release();*/ + + + // Free the block + free(Block2); + + *Block = NULL; +} + +//============================================================================ +// TPage_BlockGetTexture +//============================================================================ + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +LPDIRECT3DTEXTURE2 TPage_BlockGetTexture(TPage_Block *Block) */ +LPDIRECTDRAWSURFACE7 TPage_BlockGetTexture(TPage_Block *Block) + +{ + assert(Block); + + return Block->Texture; +} + +//============================================================================ +// TPage_BlockGetSurface +//============================================================================ + +/* 07/16/2000 Wendell Buckner + Convert to Directx7... +LPDIRECTDRAWSURFACE4 TPage_BlockGetSurface(TPage_Block *Block) */ +LPDIRECTDRAWSURFACE7 TPage_BlockGetSurface(TPage_Block *Block) + +{ + assert(Block); + + return Block->Surface; +} + +//============================================================================ +// TPage_BlockGetRect +//============================================================================ +const RECT *TPage_BlockGetRect(TPage_Block *Block) +{ + assert(Block); + + return &Block->Rect; +} + +//============================================================================ +// TPage_BlockSetLRU +//============================================================================ +void TPage_BlockSetLRU(TPage_Block *Block, uint32 LRU) +{ + assert(Block); + + Block->LRU = LRU; +} + +//============================================================================ +// TPage_BlockSetUserData +//============================================================================ +void TPage_BlockSetUserData(TPage_Block *Block, void *UserData) +{ + assert(Block); + + Block->UserData = UserData; +} + +//============================================================================ +// TPage_BlockGetUserData +//============================================================================ +void *TPage_BlockGetUserData(TPage_Block *Block) +{ + assert(Block); + + return Block->UserData; +} diff --git a/G3D/Engine/Drivers/D3D8Drv/D3DDRV.H b/G3D/Engine/Drivers/D3D8Drv/D3DDRV.H new file mode 100644 index 0000000..e18fdac --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3DDRV.H @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* D3DDrv.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3DDRV_H +#define D3DDRV_H + +#include "DCommon.h" + +extern DRV_Window ClientWindow; +extern DRV_Driver D3DDRV; + +void DRIVERCC ErrorBox(char *Str); +BOOL DRIVERCC DrvShutdown(void); +void SetLastDrvError(int32 Error, char *ErrorStr); + +#endif diff --git a/G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsp b/G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsp new file mode 100644 index 0000000..48953e3 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsp @@ -0,0 +1,199 @@ +# Microsoft Developer Studio Project File - Name="D3DDriver" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=D3DDriver - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "D3DDriver.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "D3DDriver.mak" CFG="D3DDriver - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "D3DDriver - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "D3DDriver - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "D3DDriver - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRIVER_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRIVER_EXPORTS" /D "STRICT" /D "D3DDRV_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dxguid.lib ddraw.lib d3d8.lib /nologo /dll /machine:I386 /out:"..\Release\D3DDrv.dll" /libpath:"..\geGlobals\Lib" + +!ELSEIF "$(CFG)" == "D3DDriver - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRIVER_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\geGlobals\Include" /I "..\geGlobals\GenesisInclude" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRIVER_EXPORTS" /D "STRICT" /D "D3DDRV_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dxguid.lib ddraw.lib /nologo /dll /debug /machine:I386 /out:"..\Binaries\Debug\D3DDrv.dll" /pdbtype:sept /libpath:"..\geGlobals\Lib" + +!ENDIF + +# Begin Target + +# Name "D3DDriver - Win32 Release" +# Name "D3DDriver - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\D3D_ERR.CPP +# End Source File +# Begin Source File + +SOURCE=.\D3d_fx.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3dcache.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3ddrv.cpp +# End Source File +# Begin Source File + +SOURCE=.\DDMemMgr.cpp +# End Source File +# Begin Source File + +SOURCE=.\GSPAN.CPP +# End Source File +# Begin Source File + +SOURCE=.\Pcache.cpp +# End Source File +# Begin Source File + +SOURCE=.\Render.cpp +# End Source File +# Begin Source File + +SOURCE=.\Scene.cpp +# End Source File +# Begin Source File + +SOURCE=.\THandle.cpp +# End Source File +# Begin Source File + +SOURCE=.\tpage.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\D3D_ERR.H +# End Source File +# Begin Source File + +SOURCE=.\D3D_FX.H +# End Source File +# Begin Source File + +SOURCE=.\D3d_main.h +# End Source File +# Begin Source File + +SOURCE=.\D3dcache.h +# End Source File +# Begin Source File + +SOURCE=.\D3DDRV.H +# End Source File +# Begin Source File + +SOURCE=.\DDMemMgr.h +# End Source File +# Begin Source File + +SOURCE=.\GSPAN.H +# End Source File +# Begin Source File + +SOURCE=.\Pcache.h +# End Source File +# Begin Source File + +SOURCE=.\RENDER.H +# End Source File +# Begin Source File + +SOURCE=.\SCENE.H +# End Source File +# Begin Source File + +SOURCE=.\THandle.h +# End Source File +# Begin Source File + +SOURCE=.\TPage.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsw b/G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsw new file mode 100644 index 0000000..6109fe3 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3DDriver.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "D3DDriver"=.\D3DDriver.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/G3D/Engine/Drivers/D3D8Drv/D3DDriver.ncb b/G3D/Engine/Drivers/D3D8Drv/D3DDriver.ncb new file mode 100644 index 0000000000000000000000000000000000000000..e9fea99ce7f282247a958ff5068cf216308cedb5 GIT binary patch literal 115712 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 literal 0 HcmV?d00001 diff --git a/G3D/Engine/Drivers/D3D8Drv/D3DDriver.plg b/G3D/Engine/Drivers/D3D8Drv/D3DDriver.plg new file mode 100644 index 0000000..e4e67e9 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3DDriver.plg @@ -0,0 +1,44 @@ + + +
+

Build Log

+

+--------------------Configuration: D3DDriver - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP35.tmp" with contents +[ +/nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRIVER_EXPORTS" /D "STRICT" /D "D3DDRV_EXPORTS" /Fp"Release/D3DDriver.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c +"D:\Release\G3D\Engine\Drivers\D3D8Drv\D3d_main.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP35.tmp" +Creating temporary file "C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP36.tmp" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dxguid.lib ddraw.lib d3d8.lib /nologo /dll /incremental:no /pdb:"Release/D3DDrv.pdb" /machine:I386 /out:"..\Release\D3DDrv.dll" /implib:"Release/D3DDrv.lib" /libpath:"..\geGlobals\Lib" +.\Release\D3D_ERR.OBJ +.\Release\D3d_fx.obj +.\Release\D3d_main.obj +.\Release\D3dcache.obj +.\Release\D3ddrv.obj +.\Release\DDMemMgr.obj +.\Release\GSPAN.OBJ +.\Release\Pcache.obj +.\Release\Render.obj +.\Release\Scene.obj +.\Release\THandle.obj +.\Release\tpage.obj +] +Creating command line "link.exe @C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP36.tmp" +

Output Window

+Compiling... +D3d_main.cpp +Linking... + Creating library Release/D3DDrv.lib and object Release/D3DDrv.exp + + + +

Results

+D3DDrv.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/G3D/Engine/Drivers/D3D8Drv/D3D_ERR.CPP b/G3D/Engine/Drivers/D3D8Drv/D3D_ERR.CPP new file mode 100644 index 0000000..fcf64ad --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3D_ERR.CPP @@ -0,0 +1,273 @@ +/****************************************************************************************/ +/* D3D_Err.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D Error code conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "D3D_Err.h" + + + +//================================================================================ +// D3DErrorToString +//================================================================================ +char *D3DErrorToString(HRESULT error) +{ + switch(error) { + case DD_OK: + return "No error.\0"; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized.\0"; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0"; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface.\0"; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface.\0"; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs.\0"; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0"; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0"; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation.\0"; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available.\0"; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process.\0"; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation.\0"; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive.\0"; + case DDERR_GENERIC: + return "Generic failure.\0"; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment.\0"; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created.\0"; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state.\0"; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface.\0"; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface.\0"; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect.\0"; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist.\0"; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0"; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode.\0"; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0"; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect.\0"; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified.\0"; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0"; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid.\0"; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked.\0"; + case DDERR_NO3D: + return "There is no 3D present.\0"; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0"; + case DDERR_NOBLTHW: + return "No blitter hardware present.\0"; + case DDERR_NOCLIPLIST: + return "No cliplist available.\0"; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object.\0"; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or available.\0"; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key\0"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color key.\0"; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0"; + case DDERR_NODC: + return "No DC was ever created for this surface.\0"; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware.\0"; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0"; + case DDERR_NOEMULATION: + return "Software emulation not available.\0"; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive mode.\0"; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported.\0"; + case DDERR_NOGDI: + return "There is no GDI present.\0"; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0"; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available.\0"; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination.\0"; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available.\0"; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface.\0"; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes.\0"; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0"; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available.\0"; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching.\0"; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0"; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0"; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0"; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface.\0"; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable.\0"; + case DDERR_NOTFOUND: + return "Requested item was not found.\0"; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, has been attempted.\0"; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface.\0"; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations.\0"; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0"; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated.\0"; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough video memory to perform the operation.\0"; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays.\0"; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays.\0"; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread.\0"; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface.\0"; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small.\0"; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to.\0"; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of.\0"; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread.\0"; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured.\0"; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.\0"; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached.\0"; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large.\0"; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large.\0"; + case DDERR_UNSUPPORTED: + return "Action not supported.\0"; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw.\0"; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress.\0"; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete.\0"; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode.\0"; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary.\0"; + case D3DERR_BADMAJORVERSION: + return "D3DERR_BADMAJORVERSION\0"; + case D3DERR_BADMINORVERSION: + return "D3DERR_BADMINORVERSION\0"; + case D3DERR_EXECUTE_LOCKED: + return "D3DERR_EXECUTE_LOCKED\0"; + case D3DERR_EXECUTE_NOT_LOCKED: + return "D3DERR_EXECUTE_NOT_LOCKED\0"; + case D3DERR_EXECUTE_CREATE_FAILED: + return "D3DERR_EXECUTE_CREATE_FAILED\0"; + case D3DERR_EXECUTE_DESTROY_FAILED: + return "D3DERR_EXECUTE_DESTROY_FAILED\0"; + case D3DERR_EXECUTE_LOCK_FAILED: + return "D3DERR_EXECUTE_LOCK_FAILED\0"; + case D3DERR_EXECUTE_UNLOCK_FAILED: + return "DDERR_EXECUTE_UNLOCK_FAILED\0"; + case D3DERR_EXECUTE_FAILED: + return "D3DERR_EXECUTE_FAILED\0"; + case D3DERR_EXECUTE_CLIPPED_FAILED: + return "D3DERR_EXECUTE_CLIPPED_FAILED\0"; + case D3DERR_TEXTURE_NO_SUPPORT: + return "D3DERR_TEXTURE_NO_SUPPORT\0"; + case D3DERR_TEXTURE_NOT_LOCKED: + return "D3DERR_TEXTURE_NOT_LOCKED\0"; + case D3DERR_TEXTURE_LOCKED: + return "D3DERR_TEXTURELOCKED\0"; + case D3DERR_TEXTURE_CREATE_FAILED: + return "D3DERR_TEXTURE_CREATE_FAILED\0"; + case D3DERR_TEXTURE_DESTROY_FAILED: + return "D3DERR_TEXTURE_DESTROY_FAILED\0"; + case D3DERR_TEXTURE_LOCK_FAILED: + return "D3DERR_TEXTURE_LOCK_FAILED\0"; + case D3DERR_TEXTURE_UNLOCK_FAILED: + return "D3DERR_TEXTURE_UNLOCK_FAILED\0"; + case D3DERR_TEXTURE_LOAD_FAILED: + return "D3DERR_TEXTURE_LOAD_FAILED\0"; + case D3DERR_MATRIX_CREATE_FAILED: + return "D3DERR_MATRIX_CREATE_FAILED\0"; + case D3DERR_MATRIX_DESTROY_FAILED: + return "D3DERR_MATRIX_DESTROY_FAILED\0"; + case D3DERR_MATRIX_SETDATA_FAILED: + return "D3DERR_MATRIX_SETDATA_FAILED\0"; + case D3DERR_SETVIEWPORTDATA_FAILED: + return "D3DERR_SETVIEWPORTDATA_FAILED\0"; + case D3DERR_MATERIAL_CREATE_FAILED: + return "D3DERR_MATERIAL_CREATE_FAILED\0"; + case D3DERR_MATERIAL_DESTROY_FAILED: + return "D3DERR_MATERIAL_DESTROY_FAILED\0"; + case D3DERR_MATERIAL_SETDATA_FAILED: + return "D3DERR_MATERIAL_SETDATA_FAILED\0"; + case D3DERR_LIGHT_SET_FAILED: + return "D3DERR_LIGHT_SET_FAILED\0"; + default: + return "Unrecognized error value.\0"; + } +} diff --git a/G3D/Engine/Drivers/D3D8Drv/D3D_ERR.H b/G3D/Engine/Drivers/D3D8Drv/D3D_ERR.H new file mode 100644 index 0000000..bc65c56 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3D_ERR.H @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* D3D_Err.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D Error code conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_ERR_H +#define D3D_ERR_H + +#include +#include +#include + +//================================================================================ +// Global functions +//================================================================================ +char *D3DErrorToString(HRESULT error); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D8Drv/D3D_FX.H b/G3D/Engine/Drivers/D3D8Drv/D3D_FX.H new file mode 100644 index 0000000..e51996f --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3D_FX.H @@ -0,0 +1,53 @@ +/****************************************************************************************/ +/* D3D_Fx.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D renderstate wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_FX_H +#define D3D_FX_H + +#include +#include +#include + +#include "D3D_Main.h" +#include "DCommon.h" + +void D3DSetTexHandle(D3DTEXTUREHANDLE TexHandle); +void D3DSetTexture(int32 Stage, LPDIRECT3DTEXTURE2 Texture); +void D3DTexturedPolyOld(void *Pnts, int32 NumPoints); +void D3DTexturedPoly(void *Pnts, int32 NumPoints); + +void D3DBilinearFilter(D3DTEXTUREFILTER Min, D3DTEXTUREFILTER Mag); +void D3DBlendEnable(BOOL Enable); + +void D3DBlendFunc (D3DBLEND SFunc, D3DBLEND DFunc); + +void D3DZWriteEnable (BOOL Enable); +void D3DZFunc (D3DCMPFUNC Func); +void D3DZEnable(BOOL Enable); + +void D3DTexWrap(DWORD Stage, BOOL Wrap); + +void D3DPolygonMode (D3DFILLMODE Mode); + +void D3DViewport (int32 x, int32 y, int32 width, int32 height); +void D3DDepthRange (float zNear, float zFar); + +#endif diff --git a/G3D/Engine/Drivers/D3D8Drv/D3d_fx.cpp b/G3D/Engine/Drivers/D3D8Drv/D3d_fx.cpp new file mode 100644 index 0000000..94bae1d --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3d_fx.cpp @@ -0,0 +1,214 @@ +/****************************************************************************************/ +/* D3D_Fx.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D renderstate wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" +#include "Render.h" +#include "Scene.h" +#include "D3D_FX.h" +#include "D3D_Main.h" +#include "D3D_Err.h" + + + + +static D3DTEXTUREHANDLE OldTexHandle = NULL; + +//====================================================================================================== +//====================================================================================================== +void D3DSetTexHandle(D3DTEXTUREHANDLE TexHandle) +{ + if (TexHandle == OldTexHandle) + return; + + OldTexHandle = TexHandle; + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, TexHandle); +} + +static LPDIRECT3DTEXTURE2 OldTexture[8]; + +//====================================================================================================== +//====================================================================================================== +void D3DSetTexture(int32 Stage, LPDIRECT3DTEXTURE2 Texture) +{ + if (Texture == OldTexture[Stage]) + return; + + OldTexture[Stage] = Texture; + + AppInfo.lpD3DDevice->SetTexture(Stage, Texture); +} + +//====================================================================================================== +//====================================================================================================== +void D3DBilinearFilter(D3DTEXTUREFILTER Min, D3DTEXTUREFILTER Mag) +{ + AppInfo.lpD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR); + AppInfo.lpD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + + if (AppInfo.CanDoMultiTexture) + { + AppInfo.lpD3DDevice->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFN_LINEAR); + AppInfo.lpD3DDevice->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + } +} + +//====================================================================================================== +// Old one uses D3DTLVERTEX vertex format +//====================================================================================================== +void D3DTexturedPolyOld(void *Pnts, int32 NumPoints) +{ + AppInfo.lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_TLVERTEX, Pnts, NumPoints, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT | D3DDP_DONOTCLIP); +} + +//====================================================================================================== +// D3DTexturedPoly +//====================================================================================================== +void D3DTexturedPoly(void *Pnts, int32 NumPoints) +{ + AppInfo.lpD3DDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, + //D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2, + Pnts, + NumPoints, + D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT | D3DDP_DONOTCLIP); + //D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTCLIP); +} + +//====================================================================================================== +// D3DViewport +//====================================================================================================== +void D3DViewport (int32 x, int32 y, int32 width, int32 height) +{ + D3DVIEWPORT2 vport; + + return; + + vport.dwSize = sizeof(D3DVIEWPORT2); + AppInfo.lpD3DViewport->GetViewport2(&vport); + vport.dwX = x; + vport.dwY = AppInfo.OldHeight - (y + height); + vport.dwWidth = width; + vport.dwHeight = height; + vport.dvClipX = -1.0f; + vport.dvClipY = 1.0f; + vport.dvClipWidth = (float)width /2.0f; + vport.dvClipHeight = (float)height/2.0f; + AppInfo.lpD3DViewport->SetViewport2(&vport); +} + +//====================================================================================================== +//====================================================================================================== +void D3DDepthRange (float zNear, float zFar) +{ + D3DVIEWPORT2 vport; + vport.dwSize = sizeof(D3DVIEWPORT2); + AppInfo.lpD3DViewport->GetViewport2(&vport); + vport.dvMinZ = (D3DVALUE)(((-1.0) * (zFar + zNear)) / (zFar - zNear)); + vport.dvMaxZ = (D3DVALUE)(((-1.0) * (zFar + zNear - 2.0)) / (zFar - zNear)); + AppInfo.lpD3DViewport->SetViewport2(&vport); +} + +static D3DBLEND OldSFunc = D3DBLEND_ONE; +static D3DBLEND OldDFunc = D3DBLEND_ONE; + +//====================================================================================================== +//====================================================================================================== +void D3DBlendFunc (D3DBLEND SFunc, D3DBLEND DFunc) +{ + if (SFunc != OldSFunc) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, SFunc); + OldSFunc = SFunc; + } + if (DFunc != OldDFunc) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, DFunc); + OldDFunc = DFunc; + } + +} + +static BOOL OldBlend = FALSE; + +//====================================================================================================== +//====================================================================================================== +void D3DBlendEnable(BOOL Enable) +{ + if (OldBlend == Enable) + return; + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, Enable); + + OldBlend = Enable; +} + +static BOOL OldWrap = FALSE; + +void D3DTexWrap(DWORD Stage, BOOL Wrap) +{ + if (OldWrap == Wrap) + return; + + OldWrap = Wrap; + + if (Wrap) + { + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); + } + else + { + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); + } +} + +void D3DZWriteEnable (BOOL Enable) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, Enable); +} + +void D3DZFunc (D3DCMPFUNC Func) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, Func); +} + +void D3DZEnable(BOOL Enable) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, Enable); +} + +void D3DPolygonMode (D3DFILLMODE Mode) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID); +} + + + diff --git a/G3D/Engine/Drivers/D3D8Drv/D3d_main.cpp b/G3D/Engine/Drivers/D3D8Drv/D3d_main.cpp new file mode 100644 index 0000000..fd1dbaa --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3d_main.cpp @@ -0,0 +1,2605 @@ +/****************************************************************************************/ +/* D3D_Main.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: DD/D3D wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include +#include + +#include "D3D_Main.h" +#include "D3D_Err.h" +#include "D3D_fx.h" +#include "d3dcache.h" +#include "Render.h" +#include "D3DCache.h" +#include "THandle.h" +#include "PCache.h" + + + + + +#undef ATTEMPT +#define ATTEMPT(x) if (!(x)) goto exit_with_error + +#undef RELEASE +#define RELEASE(x) if (x) { x->Release(); x = NULL; } + +static BOOL bInitDone =FALSE; + +WNDPROC pOldWndProc; + +//================================================================================ +// Globals +//================================================================================ +App_Info AppInfo; // Our global structure that knows all... (once initialized) + +#define MAX_DRIVERS 64 + +typedef struct +{ + geBoolean IsPrimary; + GUID Guid; + char Name[MAX_DRIVER_NAME]; +} D3D_DRIVER; + +typedef struct +{ + int32 NumDrivers; + D3D_DRIVER *Drivers; +} DDEnumInfo; + +//================================================================================ +// Local static functions +//================================================================================ +static BOOL D3DMain_CreateD3D(void); +static BOOL D3DMain_EnumDevices(void); +static BOOL D3DMain_CreateViewPort(int w, int h); +static BOOL D3DMain_ClearBuffers(void); +static BOOL OutputDriverInfo(const char *Filename, DDMain_D3DDriver *Driver); +static BOOL D3DMain_RememberOldMode(HWND hWnd); +static BOOL D3DMain_SetDisplayMode(HWND hWnd, int w, int h, int bpp, BOOL FullScreen); +static BOOL D3DMain_PickDevice(void); +static BOOL D3DMain_CreateDevice(void); +static BOOL D3DMain_CreateBuffers(void); +static void D3DMain_DestroyBuffers(void); +static BOOL D3DMain_CreateZBuffer(void); +static void D3DMain_DestroyZBuffer(void); +static BOOL D3DMain_RestoreDisplayMode(void); +static BOOL D3DMain_CreateDDFromName(const char *DriverName); +static geBoolean CreateDDFromDriver(D3D_DRIVER *pDriver); +static geBoolean CreateDDFromName(const char *DriverName, const DDEnumInfo *Info); + + + + + +//================================================================================ +// D3DMain_RestoreAllSurfaces() +//================================================================================ +BOOL D3DMain_RestoreAllSurfaces(void) +{ + HRESULT ddrval; + + if (AppInfo.lpDD) + { + if (!D3DMain_SetDisplayMode(AppInfo.hWnd, AppInfo.CurrentWidth, AppInfo.CurrentHeight, AppInfo.CurrentBpp, AppInfo.FullScreen)) + return FALSE; + + // Restore all the surfaces + ddrval = AppInfo.lpDD->RestoreAllSurfaces(); + + if(ddrval!=DD_OK) + { + D3DMain_Log("D3DMain_RestoreAllSurfaces: AppInfo.lpDD->RestoreAllSurfaces() failed:\n %s\n", D3DErrorToString(ddrval)); + return FALSE; + } + } + + // Force an update in the cache system + if (TextureCache) + if (!D3DCache_EvictAllSurfaces(TextureCache)) + return FALSE; + + if (LMapCache) + if (!D3DCache_EvictAllSurfaces(LMapCache)) + return FALSE; + + return TRUE; +} + +//================================================================================ +// BPPToDDBD +// Convert an integer bit per pixel number to a DirectDraw bit depth flag +//================================================================================ +static DWORD BPPToDDBD(int bpp) +{ + switch(bpp) + { + case 1: + return DDBD_1; + case 2: + return DDBD_2; + case 4: + return DDBD_4; + case 8: + return DDBD_8; + case 16: + return DDBD_16; + case 24: + return DDBD_24; + case 32: + return DDBD_32; + default: + return DDBD_1; + } +} + +//================================================================================ +// D3DMain_InitD3D +// Does all what is needed to get an app ready to go at a specified with height +// NOTE - It only makes 16 bit modes availible +//================================================================================ +BOOL D3DMain_InitD3D(HWND hWnd, const char *DriverName, int32 Width, int32 Height) +{ + HRESULT LastError; + SYSTEMTIME Time; + + memset(&AppInfo, 0, sizeof(App_Info)); + + GetSystemTime(&Time); + + unlink(D3DMAIN_LOG_FILENAME); + + D3DMain_Log("=================================================================\n"); + D3DMain_Log(" D3DDrv v%i.%i\n", DRV_VERSION_MAJOR, DRV_VERSION_MINOR); + D3DMain_Log(" Build Date: "__DATE__", Time: "__TIME__"\n"); + D3DMain_Log("=================================================================\n\n"); + + D3DMain_Log("Current Time: %2i:%2i:%2i\n", Time.wHour, Time.wMinute, Time.wSecond); + D3DMain_Log("Current Date: %2i-%2i-%4i\n", Time.wMonth, Time.wDay, Time.wYear); + D3DMain_Log("\n ** D3D Driver Initializing **\n\n"); + + AppInfo.hWnd = hWnd; + + // Create DD + ATTEMPT(D3DMain_CreateDDFromName(DriverName)); + + ATTEMPT(D3DMain_GetTextureMemory()); + + // We must do this after the DD object is created!!! + ATTEMPT(D3DMain_RememberOldMode(hWnd)); // Store old mode + + // Get available fullscreen display modes + ATTEMPT(D3DMain_EnumDisplayModes()); + + // Create D3D, and enum it's devices + ATTEMPT(D3DMain_CreateD3D()); + ATTEMPT(D3DMain_EnumDevices()); + + if (Width == -1 && Height == -1) // Window Mode + { + // Force Width/Height to client window area size + Width = AppInfo.OldWindowWidth; + Height = AppInfo.OldWindowHeight; + + ATTEMPT(D3DMain_SetDisplayMode(hWnd, Width, Height, AppInfo.OldBpp, FALSE)); + } + else + { + ATTEMPT(D3DMain_SetDisplayMode(hWnd, Width, Height, 16, TRUE)); + } + + // Pick a device we will be happy with + ATTEMPT(D3DMain_PickDevice()); + + // Create front/back buffer + ATTEMPT(D3DMain_CreateBuffers()); + + // For some reason, we have to create the zbuffer BEFORE the device??? Why??? + ATTEMPT(D3DMain_CreateZBuffer()); + + // Create the device and viewport + ATTEMPT(D3DMain_CreateDevice()); + ATTEMPT(D3DMain_CreateViewPort(Width, Height)); + + // Get the surface formats for textures, and 2d surfaces + ATTEMPT(D3DMain_GetSurfaceFormats()); + + AppInfo.CanDoMultiTexture = (AppInfo.Drivers[AppInfo.CurrentDriver].MaxSimultaneousTextures > 1) ? GE_TRUE : GE_FALSE; + + D3DMain_Log("--- D3DMain_SetRenderState --- \n"); + + // Set some defaults render states + LastError = AppInfo.lpD3DDevice->BeginScene(); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: BeginScene failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = AppInfo.lpD3DDevice->SetCurrentViewport(AppInfo.lpD3DViewport); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: SetViewport failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + //D3DMain_SetFogEnable(GE_TRUE, 255.0f, 0.0f, 0.0f, 500.0f, 1500.0f); + D3DMain_SetFogEnable(GE_FALSE, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL); + //AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, TRUE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPNEAREST); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_LINEAR); + + LastError = AppInfo.lpD3DDevice->EndScene(); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: EndScene failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.RenderingIsOK = TRUE; + + ATTEMPT(D3DMain_ClearBuffers()); + ATTEMPT(D3DMain_GetTextureMemory()); + + if (!THandle_Startup()) + return GE_FALSE; + + D3DViewport (0, 0, Width, Height); + D3DDepthRange (0.0f, 1.0f); + + D3DMain_Log("\n ** Initialization was successful **\n\n"); + + return TRUE; + + exit_with_error:; + D3DMain_Log(" ** Initialization was NOT successful **\n"); + D3DMain_ShutdownD3D(); + return FALSE; +} + +//================================================================================ +// D3DMain_ShutdownD3D +//================================================================================ +BOOL D3DMain_ShutdownD3D(void) +{ + D3DMain_Log("\n--- D3DMain_ShutdownD3D ---\n"); + + THandle_Shutdown(); + + // Destroys all objects including Direct Draw. + AppInfo.RenderingIsOK = FALSE; + + if (AppInfo.lpD3DViewport) + { + AppInfo.lpD3DDevice->DeleteViewport(AppInfo.lpD3DViewport); + RELEASE(AppInfo.lpD3DViewport); + } + + RELEASE(AppInfo.lpD3DDevice); + + RELEASE(AppInfo.BackgroundMaterial); + + if (AppInfo.lpZBuffer) + { + AppInfo.lpBackBuffer->DeleteAttachedSurface(0, AppInfo.lpZBuffer); + RELEASE(AppInfo.lpZBuffer); + } + + if (AppInfo.lpFrontBuffer) + AppInfo.lpFrontBuffer->SetClipper(NULL); + + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); + + D3DMain_RestoreDisplayMode(); + + RELEASE(AppInfo.lpD3D); + RELEASE(AppInfo.lpDD); + + memset(&AppInfo, 0, sizeof(App_Info)); + + D3DMain_Log(" Shutdown was successful...\n\n"); + + return TRUE; +} + +extern uint32 CurrentLRU; +//================================================================================ +//================================================================================ +geBoolean D3DMain_Reset(void) +{ + THandle_Shutdown(); + PCache_Reset(); + + if (!THandle_Startup()) + return GE_FALSE; + + CurrentLRU = 0; + + return GE_TRUE; +} + +//================================================================================ +// D3DMain_Log +//================================================================================ +void D3DMain_Log(LPSTR Str, ... ) +{ + char Buffer[2048]; + FILE *f; + + wvsprintf(Buffer, Str, (char*)(&Str+1)); + + f = fopen(D3DMAIN_LOG_FILENAME, "a+t"); + + if (!f) + return; + + fprintf(f, "%s", Buffer); + + fclose(f); +} + +//================================================================================ +// CompareModes +//================================================================================ +static int CompareModes(const void* element1, const void* element2) +{ + App_Mode *lpMode1, *lpMode2; + + lpMode1 = (App_Mode*)element1; + lpMode2 = (App_Mode*)element2; + + if (lpMode1->Bpp > lpMode2->Bpp) + return -1; + else if (lpMode2->Bpp > lpMode1->Bpp) + return 1; + else if (lpMode1->Width > lpMode2->Width) + return -1; + else if (lpMode2->Width > lpMode1->Width) + return 1; + else if (lpMode1->Height > lpMode2->Height) + return -1; + else if (lpMode2->Height > lpMode1->Height) + return 1; + else + return 0; +} + +//================================================================================ +// EnumDisplayModesCallback +//================================================================================ +static HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC2 pddsd, LPVOID lpContext) +{ + App_Mode *pMode; + + if (!pddsd) + return DDENUMRET_OK; + + if (pddsd->dwWidth > 1024 || pddsd->dwHeight > 768) + return DDENUMRET_OK; + + if (AppInfo.NumModes >= MAX_APP_MODES) + return DDENUMRET_CANCEL; + + pMode = &AppInfo.Modes[AppInfo.NumModes++]; + + // Save this mode at the end of the mode array and increment mode count + pMode->Width = pddsd->dwWidth; + pMode->Height = pddsd->dwHeight; + pMode->Bpp = pddsd->ddpfPixelFormat.dwRGBBitCount; + pMode->ThisDriverCanDo = FALSE; + + return DDENUMRET_OK; +} + +//================================================================================ +// D3DMain_EnumDisplayModes +//================================================================================ +BOOL D3DMain_EnumDisplayModes(void) +{ + HRESULT LastError; + + D3DMain_Log("--- D3DMain_EnumDisplayModes ---\n"); + + // Get a list of available display modes from DirectDraw + AppInfo.NumModes = 0; + + LastError = AppInfo.lpDD->EnumDisplayModes(0, NULL, 0, EnumDisplayModesCallback); + + if(LastError != DD_OK ) + { + D3DMain_Log("EnumDisplayModes failed.\n %s\n", D3DErrorToString(LastError)); + AppInfo.NumModes = 0; + return FALSE; + } + + // Sort the list of display modes + qsort((void *)&AppInfo.Modes[0], (size_t)AppInfo.NumModes, sizeof(App_Mode), CompareModes); + + return TRUE; +} + + + +//================================================================================ +// D3DMain_CreateD3D +//================================================================================ +static BOOL D3DMain_CreateD3D(void) +{ + HRESULT LastError; + + D3DMain_Log("--- D3DMain_CreateD3D ---\n"); + + LastError = AppInfo.lpDD->QueryInterface(IID_IDirect3D3, (LPVOID*)&AppInfo.lpD3D); + + if (LastError != DD_OK) + { + D3DMain_Log("Creation of IDirect3D failed.\n %s\n", D3DErrorToString(LastError)); + goto exit_with_error; + } + + return TRUE; + + exit_with_error: + return FALSE; +} + +#define MUST_BLEND_SRC (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#define MUST_BLEND_DEST (D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +//================================================================================ +// EnumDeviceFunc +//================================================================================ +static HRESULT WINAPI EnumDeviceFunc(LPGUID lpGuid, LPSTR lpDeviceDescription, + LPSTR lpDeviceName, LPD3DDEVICEDESC lpHWDesc, + LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext) +{ + DDMain_D3DDriver *Driver; + BOOL Good; + + if (!lpGuid|| !lpDeviceDescription || !lpDeviceName || !lpHWDesc || !lpHELDesc) + return (D3DENUMRET_OK); + + if (strlen(lpDeviceDescription) >= MAX_DRIVER_NAME) + return (D3DENUMRET_OK); + + if (strlen(lpDeviceName) >= MAX_DRIVER_NAME) + return (D3DENUMRET_OK); + + lpContext = lpContext; + + Good = TRUE; + + AppInfo.CurrentDriver = AppInfo.NumDrivers; + + Driver = &AppInfo.Drivers[AppInfo.NumDrivers]; + + // Record the D3D driver's inforamation + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Guid, lpGuid, sizeof(GUID)); + lstrcpy(AppInfo.Drivers[AppInfo.NumDrivers].About, lpDeviceDescription); + lstrcpy(AppInfo.Drivers[AppInfo.NumDrivers].Name, lpDeviceName); + + // Is this a hardware device or software emulation? Checking the color + // model for a valid model works. + if (lpHWDesc->dcmColorModel) + { + AppInfo.Drivers[AppInfo.NumDrivers].IsHardware = TRUE; + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHWDesc, sizeof(D3DDEVICEDESC)); + } + else + { + // Skip if this is not a hardware driver + AppInfo.Drivers[AppInfo.NumDrivers].IsHardware = FALSE; + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHELDesc, sizeof(D3DDEVICEDESC)); + Good = FALSE; + } + + LPD3DDEVICEDESC Desc = &AppInfo.Drivers[AppInfo.NumDrivers].Desc; + + Driver->MaxTextureBlendStages = Desc->wMaxTextureBlendStages; + Driver->MaxSimultaneousTextures = Desc->wMaxSimultaneousTextures; + + if (!(Desc->dwDeviceZBufferBitDepth)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesZBuffer = TRUE; + + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesTextures = TRUE; + + // Skip if it does not support alpha blending + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHA)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesAlpha = TRUE; + + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_TRANSPARENCY)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesTransparency = TRUE; + AppInfo.Drivers[AppInfo.NumDrivers].DoesClamping = TRUE; + + if ((Desc->dpcTriCaps.dwSrcBlendCaps & MUST_BLEND_SRC) != MUST_BLEND_SRC) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesSrcBlending = TRUE; + + if ((Desc->dpcTriCaps.dwDestBlendCaps & MUST_BLEND_DEST) != MUST_BLEND_DEST) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesDestBlending = TRUE; + + // Stop as soon as we find a driver that can render into a window + if ((Desc->dwDeviceRenderBitDepth & BPPToDDBD(AppInfo.OldBpp)) && AppInfo.IsPrimary && Good) + { + AppInfo.Drivers[AppInfo.NumDrivers].CanDoWindow = TRUE; + AppInfo.CanDoWindow = TRUE; + } + else + AppInfo.Drivers[AppInfo.NumDrivers].CanDoWindow = FALSE; + + // Store if we can use this driver + AppInfo.Drivers[AppInfo.NumDrivers].CanUse = Good; + + if (!Good) + return (D3DENUMRET_OK); + + // Tell global structure that we found a good device + AppInfo.FoundGoodDevice = TRUE; + + // If all was good, increment the number of drivers + AppInfo.NumDrivers++; + + if (AppInfo.NumDrivers+1 >= DDMAIN_MAX_D3D_DRIVERS) + return (D3DENUMRET_CANCEL); + + return (D3DENUMRET_OK); +} + +//================================================================================ +// EnumDevices +//================================================================================ +static BOOL D3DMain_EnumDevices(void) +{ + HRESULT LastError; + + D3DMain_Log("--- D3DMain_EnumDevices ---\n"); + + AppInfo.NumDrivers = 0; + + LastError = AppInfo.lpD3D->EnumDevices(EnumDeviceFunc, NULL); + + if (LastError != DD_OK) + { + D3DMain_Log("Enumeration of drivers failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + + AppInfo.CurrentDriver = 0; + + return TRUE; +} + +//================================================================================ +// CreateSurface +//================================================================================ +static HRESULT CreateSurface(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE4 FAR *lpDDSurface) +{ + HRESULT Result; + + Result = AppInfo.lpDD->CreateSurface(lpDDSurfDesc, lpDDSurface, NULL); + + return Result; +} + +//================================================================================ +// GetSurfDesc +//================================================================================ +static HRESULT GetSurfDesc(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE4 lpDDSurf) +{ + HRESULT Result; + + memset(lpDDSurfDesc, 0, sizeof(DDSURFACEDESC2)); + + lpDDSurfDesc->dwSize = sizeof(DDSURFACEDESC2); + + Result = lpDDSurf->GetSurfaceDesc(lpDDSurfDesc); + + return Result; +} + +//================================================================================ +// D3DMain_CreateViewPort +//================================================================================ +static BOOL D3DMain_CreateViewPort(int w, int h) +{ + LPDIRECT3DVIEWPORT3 lpD3DViewport; + HRESULT rval; + + D3DMain_Log("--- D3DMain_CreateViewPort ---\n"); + + // Create the D3D viewport object + rval = AppInfo.lpD3D->CreateViewport(&lpD3DViewport, NULL); + + if (rval != D3D_OK) + { + D3DMain_Log("Create D3D viewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Add the viewport to the D3D device + rval = AppInfo.lpD3DDevice->AddViewport(lpD3DViewport); + if (rval != D3D_OK) + { + D3DMain_Log("Add D3D viewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Setup the viewport for a reasonable viewing area + D3DVIEWPORT2 viewData; + + memset(&viewData, 0, sizeof(D3DVIEWPORT2)); + viewData.dwSize = sizeof(D3DVIEWPORT2); + viewData.dwX = viewData.dwY = 0; + viewData.dwWidth = w; + viewData.dwHeight = h; + viewData.dvClipX = -1.0f; + viewData.dvClipWidth = 2.0f; + viewData.dvClipHeight = h * 2.0f / w; + viewData.dvClipY = viewData.dvClipHeight / 2.0f; + viewData.dvMinZ = 0.0f; + viewData.dvMaxZ = 1.0f; + + rval = lpD3DViewport->SetViewport2(&viewData); + if (rval != D3D_OK) + { + D3DMain_Log("SetViewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + AppInfo.lpD3DViewport = lpD3DViewport; + + // Create the material that will be used for the background + { + D3DMATERIAL Material; + D3DMATERIALHANDLE MatHandle; + + // Create the material + rval = AppInfo.lpD3D->CreateMaterial(&AppInfo.BackgroundMaterial, NULL ); + + if (rval != D3D_OK) + { + D3DMain_Log("D3DMain_CreateViewPort: CreateMaterial failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Fill in the material with the data + memset(&Material, 0, sizeof(D3DMATERIAL)); + + Material.dwSize = sizeof(D3DMATERIAL); + Material.dcvDiffuse.r = Material.dcvAmbient.r = 0.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = 0.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = 0.0f; + Material.dwRampSize = 16L; // A default ramp size + + AppInfo.BackgroundMaterial->SetMaterial(&Material); + + // Attach the material to the viewport + AppInfo.BackgroundMaterial->GetHandle( AppInfo.lpD3DDevice, &MatHandle); + AppInfo.lpD3DViewport->SetBackground(MatHandle); + } + + return TRUE; +} + +//================================================================================ +// EnumTextureFormatsCallback +// Record information about each texture format the current D3D driver can +// support. Choose one as the default format and return it through lpContext. +//================================================================================ +static HRESULT CALLBACK EnumTextureFormatsCallback(LPDDPIXELFORMAT lpddpfPixelFormat, LPVOID lpContext) +{ + DDMain_SurfFormat *pTexFormat; + + if(!lpddpfPixelFormat) + return DDENUMRET_OK; + + if (AppInfo.NumTextureFormats+1 >= DDMAIN_MAX_TEXTURE_FORMATS ) + { + return DDENUMRET_CANCEL; + } + + pTexFormat = &AppInfo.TextureFormats[AppInfo.NumTextureFormats]; + + // Clear out this texture format slot + memset(pTexFormat, 0, sizeof(DDMain_SurfFormat)); + + if(lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + { + if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0x8000) + { + if(lpddpfPixelFormat->dwRBitMask != 0x7c00 || + lpddpfPixelFormat->dwGBitMask != 0x3e0 || + lpddpfPixelFormat->dwBBitMask != 0x1f) + return DDENUMRET_OK; + + pTexFormat->HasOneBitAlpha = TRUE; + pTexFormat->HasFourBitAlpha = FALSE; + } + else if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0xf000) + { + if(lpddpfPixelFormat->dwRBitMask != 0xf00 || + lpddpfPixelFormat->dwGBitMask != 0xf0 || + lpddpfPixelFormat->dwBBitMask != 0xf) + return DDENUMRET_OK; + + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = TRUE; + } + else + { + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = FALSE; + } + } + else + { + if(!(lpddpfPixelFormat->dwFlags & DDPF_RGB)) + return DDENUMRET_OK; + + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = FALSE; + } + + // Record the PixelFormat of this texture + memcpy(&pTexFormat->ddsd.ddpfPixelFormat, lpddpfPixelFormat, sizeof(DDPIXELFORMAT)); + + AppInfo.NumTextureFormats++; + + return DDENUMRET_OK; +} + +//================================================================================ +// Main_EnumTextureFormats +// Get a list of available texture map formats from the Direct3D driver by +// enumeration. Choose a default format. +//================================================================================ +BOOL Main_EnumTextureFormats(void) +{ + HRESULT LastError; + + + AppInfo.NumTextureFormats = 0; + + LastError = AppInfo.lpD3DDevice->EnumTextureFormats(EnumTextureFormatsCallback, NULL); + + if (LastError != DD_OK) + { + D3DMain_Log("Main_EnumTextureFormats: Enumeration of texture formats failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + + +//================================================================================ +// EnumSurfaceFormatsCallback +//================================================================================ +HRESULT WINAPI EnumSurfaceFormatsCallback(LPDIRECTDRAWSURFACE4 lpDDSurface, LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext) +{ + LPDDPIXELFORMAT lpddpfPixelFormat; + DDMain_SurfFormat *pSurfFormat; + + // Don't need this. + RELEASE(lpDDSurface); + + lpddpfPixelFormat = &lpDDSurfaceDesc->ddpfPixelFormat; + + if(!lpddpfPixelFormat) + return DDENUMRET_OK; + + if (AppInfo.NumSurfFormats+1 >= DDMAIN_MAX_SURFACE_FORMATS ) + return DDENUMRET_CANCEL; + + pSurfFormat = &AppInfo.SurfFormats[AppInfo.NumSurfFormats]; + + // Clear out this texture format slot + memset(pSurfFormat, 0, sizeof(DDMain_SurfFormat)); + + if(lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + { + if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0x8000) + { + // 1555 + if(lpddpfPixelFormat->dwRBitMask != 0x7c00 || + lpddpfPixelFormat->dwGBitMask != 0x3e0 || + lpddpfPixelFormat->dwBBitMask != 0x1f) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = TRUE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + else if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0xf000) + { + // 4444 + if(lpddpfPixelFormat->dwRBitMask != 0xf00 || + lpddpfPixelFormat->dwGBitMask != 0xf0 || + lpddpfPixelFormat->dwBBitMask != 0xf) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = TRUE; + } + else + { + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + } + else + { + if(!(lpddpfPixelFormat->dwFlags & DDPF_RGB)) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + + // Record the PixelFormat of this texture + memcpy(&pSurfFormat->ddsd.ddpfPixelFormat, lpddpfPixelFormat,sizeof(DDPIXELFORMAT)); + + AppInfo.NumSurfFormats++; + + return DDENUMRET_OK; +} + +//================================================================================ +// Main_EnumSurfaceFormats +//================================================================================ +BOOL Main_EnumSurfaceFormats(void) +{ + HRESULT LastError; + + AppInfo.NumSurfFormats = 0; + + LastError = AppInfo.lpDD->EnumSurfaces(DDENUMSURFACES_DOESEXIST|DDENUMSURFACES_ALL, + NULL, NULL, EnumSurfaceFormatsCallback); + + if (LastError != DD_OK) + { + D3DMain_Log("Main_EnumSurfaceFormats: Enumeration of texture formats failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + + +//----------------------------------------------------------------------------- +// Name: EnumZBufferFormatsCallback() +// Desc: Enumeration function to report valid pixel formats for z-buffers. +//----------------------------------------------------------------------------- +static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf, + VOID* pddpfDesired ) +{ + if( NULL==pddpf || NULL==pddpfDesired ) + return D3DENUMRET_CANCEL; + + // If the current pixel format's match the desired ones (DDPF_ZBUFFER and + // possibly DDPF_STENCILBUFFER), lets copy it and return. This function is + // not choosy...it accepts the first valid format that comes along. + if( pddpf->dwFlags == ((DDPIXELFORMAT*)pddpfDesired)->dwFlags ) + { + memcpy( pddpfDesired, pddpf, sizeof(DDPIXELFORMAT) ); + + // We're happy with a 16-bit z-buffer. Otherwise, keep looking. + if( pddpf->dwZBufferBitDepth == 16 ) + return D3DENUMRET_CANCEL; + } + + return D3DENUMRET_OK; +} + +//================================================================================ +// D3DMain_ClearBuffers +//================================================================================ +static BOOL D3DMain_ClearBuffers(void) +{ + DDSURFACEDESC2 ddsd; + RECT dst; + DDBLTFX ddbltfx; + HRESULT LastError; + + // Find the width and height of the front buffer by getting its + // DDSURFACEDESC2 + if (AppInfo.lpFrontBuffer) + { + LastError = GetSurfDesc(&ddsd, AppInfo.lpFrontBuffer); + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_ClearBuffers: Failure getting the surface description of the front buffer before clearing.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + // Clear the front buffer to black + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(DDBLTFX); + SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight); + + LastError = AppInfo.lpFrontBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, + &ddbltfx); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("D3DMain_ClearBuffers: D3DMain_RestoreAllSurfaces failed...\n"); + return FALSE; + } + } + else + { + D3DMain_Log("D3DMain_ClearBuffers: Clearing the front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + } + + if (AppInfo.lpBackBuffer) + { + // Find the width and height of the back buffer by getting its + // DDSURFACEDESC2 + + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_ClearBuffers: Failure while getting the surface description of the back buffer before clearing.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + // Clear the back buffer to black + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(DDBLTFX); + SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight); + LastError = AppInfo.lpBackBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, + &ddbltfx); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("D3DMain_ClearBuffers: D3DMain_RestoreAllSurfaces failed.\n"); + return FALSE; + } + } + else + { + D3DMain_Log("D3DMain_ClearBuffers: Clearing the back buffer failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + } + + return TRUE; +} + +//================================================================================ +// Main_ShowBackBuffer +//================================================================================ +BOOL Main_ShowBackBuffer(void) +{ + HRESULT LastError; + + if (!AppInfo.RenderingIsOK) + return TRUE; + + if (AppInfo.FullScreen) + { + // Flip the back and front buffers + LastError = AppInfo.lpFrontBuffer->Flip(AppInfo.lpBackBuffer, DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC); + + if (LastError == DDERR_SURFACELOST) + { + D3DMain_RestoreAllSurfaces(); + //AppInfo.lpFrontBuffer->Restore(); + //AppInfo.lpBackBuffer->Restore(); + + D3DMain_ClearBuffers(); + + } + else if (LastError == DDERR_WASSTILLDRAWING) + { + } + else if (LastError != DD_OK) + { + D3DMain_Log("Flipping complex display surface failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + } + else + { + RECT FRect, BRect; + + FRect.left = AppInfo.WindowXOffset; + FRect.right = FRect.left + AppInfo.CurrentWidth; + FRect.top = AppInfo.WindowYOffset; + FRect.bottom = FRect.top + AppInfo.CurrentHeight; + + BRect.left = 0; + BRect.right = AppInfo.CurrentWidth; + BRect.top = 0; + BRect.bottom = AppInfo.CurrentHeight; + + LastError = AppInfo.lpFrontBuffer->Blt(&FRect, AppInfo.lpBackBuffer, + &BRect, DDBLT_WAIT, NULL); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("Main_ShowBackBuffer: D3DMain_RestoreAllSurfaces.\n"); + return FALSE; + } + } + else + { + D3DMain_Log("Main_ShowBackBuffer: Blt of back buffer to front buffer failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + } + } + + return TRUE; +} + +//================================================================================ +// Main_ClearBackBuffer +//================================================================================ +BOOL Main_ClearBackBuffer(BOOL Clear, BOOL ClearZ) +{ + int ClearFlags; + D3DRECT Dummy; + HRESULT LastError; + + if (!AppInfo.RenderingIsOK) + return TRUE; + + // Default to clear nothing + ClearFlags = 0; + + // Then set in what callers wants to clear + if (Clear) + ClearFlags |= D3DCLEAR_TARGET; + + if (ClearZ) + ClearFlags |= D3DCLEAR_ZBUFFER; + + Dummy.x1 = Dummy.y1 = 0; + Dummy.x2 = AppInfo.CurrentWidth; + Dummy.y2 = AppInfo.CurrentHeight; + + LastError = AppInfo.lpD3DViewport->Clear(1, &Dummy, ClearFlags); + + if (LastError != D3D_OK) + { + D3DMain_Log("Viewport clear failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + +//================================================================================ +// Surface manipulation +//================================================================================ + +typedef struct +{ + unsigned char r, g, b; +} MY_D3D_RGB; + +typedef struct +{ + DWORD R_Shift; + DWORD G_Shift; + DWORD B_Shift; + DWORD A_Shift; + + DWORD R_Mask; + DWORD G_Mask; + DWORD B_Mask; + DWORD A_Mask; + + DWORD R_Width; + DWORD G_Width; + DWORD B_Width; + DWORD A_Width; +} D3D_PixelMask; + +//================================================================================ +// GetSurfacePixelMask +//================================================================================ +static void GetSurfacePixelMask(DDSURFACEDESC2 *ddsd, D3D_PixelMask *PixelMask) +{ + DWORD red_mask, grn_mask, blu_mask, a_mask; + DWORD red_shift, grn_shift, blu_shift, a_shift; + DWORD red_width, grn_width, blu_width, a_width; + int i; + + red_mask = ddsd->ddpfPixelFormat.dwRBitMask; + grn_mask = ddsd->ddpfPixelFormat.dwGBitMask; + blu_mask = ddsd->ddpfPixelFormat.dwBBitMask; + a_mask = ddsd->ddpfPixelFormat.dwRGBAlphaBitMask; + + // + // Derive shift, width values from masks + // + + for (i=31; i >= 0; i--) + { + if (red_mask & (1 << i)) + red_shift = i; + + if (grn_mask & (1 << i)) + grn_shift = i; + + if (blu_mask & (1 << i)) + blu_shift = i; + + if (a_mask & (1 << i)) + a_shift = i; + } + + for (i=0; i <= 31; i++) + { + if (red_mask & (1 << i)) + red_width = i - red_shift + 1; + + if (grn_mask & (1 << i)) + grn_width = i - grn_shift + 1; + + if (blu_mask & (1 << i)) + blu_width = i - blu_shift + 1; + + if (a_mask & (1 << i)) + a_width = i - a_shift + 1; + } + // + // Pass all requested values back to the caller + // + + PixelMask->R_Shift = red_shift; + PixelMask->G_Shift = grn_shift; + PixelMask->B_Shift = blu_shift; + PixelMask->A_Shift = a_shift; + + PixelMask->R_Mask = red_mask; + PixelMask->G_Mask = grn_mask; + PixelMask->B_Mask = blu_mask; + PixelMask->A_Mask = a_mask; + + PixelMask->R_Width = red_width; + PixelMask->G_Width = grn_width; + PixelMask->B_Width = blu_width; + PixelMask->A_Width = a_width; +} + +//================================================================================ +// MyRGB +//================================================================================ +static unsigned int MyRGB(DWORD R, DWORD G, DWORD B, D3D_PixelMask *PixelMask) +{ + DWORD R_Left, G_Left, B_Left; + DWORD R_Right, G_Right, B_Right; + + + // Get shift constants for current video mode + R_Left = PixelMask->R_Shift; + G_Left = PixelMask->G_Shift; + B_Left = PixelMask->B_Shift; + + R_Right = 8 - PixelMask->R_Width; + G_Right = 8 - PixelMask->G_Width; + B_Right = 8 - PixelMask->B_Width; + // Shift R,G, and B into one value + return( + (((((unsigned int) R) >> R_Right) << R_Left) & PixelMask->R_Mask) | + (((((unsigned int) G) >> G_Right) << G_Left) & PixelMask->G_Mask) | + (((((unsigned int) B) >> B_Right) << B_Left) & PixelMask->B_Mask) + ); +} + +//========================================================================================== +// D3DMain_GetSurfaceFormats +//========================================================================================== +BOOL D3DMain_GetSurfaceFormats(void) +{ + int32 i; + + D3DMain_Log("--- D3DMain_GetSurfaceFormats ---\n"); + + if (!Main_EnumTextureFormats()) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Main_EnumTextureFormats failed.\n"); + return FALSE; + } + + if (!Main_EnumSurfaceFormats()) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Main_EnumSurfaceFormats failed.\n"); + return FALSE; + } + + for(i = 0; i < AppInfo.NumSurfFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + lpddpfPixelFormat = &AppInfo.SurfFormats[i].ddsd.ddpfPixelFormat; + + if(lpddpfPixelFormat->dwRGBBitCount != AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount) + continue; + + if (lpddpfPixelFormat->dwRGBAlphaBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask) + continue; + if (lpddpfPixelFormat->dwRBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRBitMask) + continue; + if (lpddpfPixelFormat->dwGBitMask != AppInfo.ddsd.ddpfPixelFormat.dwGBitMask) + continue; + if (lpddpfPixelFormat->dwBBitMask != AppInfo.ddsd.ddpfPixelFormat.dwBBitMask) + continue; + + AppInfo.ddSurfFormat = AppInfo.SurfFormats[i].ddsd; + + break; + } + + if(i == AppInfo.NumSurfFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find a 2d surface format that matches current bit depth.\n"); + return FALSE; + } + + + // Now get the 3d surface formats + + // Get 1555 + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + if(AppInfo.TextureFormats[i].HasOneBitAlpha == TRUE) + { + AppInfo.ddOneBitAlphaSurfFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 1555 texture support.\n"); + return FALSE; + } + + // Get 4444 + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + if(AppInfo.TextureFormats[i].HasFourBitAlpha == TRUE) + { + AppInfo.ddFourBitAlphaSurfFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 4444 texture support.\n"); + return FALSE; + } + + // Get either 555, or 565. + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + if(AppInfo.TextureFormats[i].HasOneBitAlpha == TRUE) + continue; + + if (AppInfo.TextureFormats[i].HasFourBitAlpha == TRUE) + continue; + + lpddpfPixelFormat = &AppInfo.TextureFormats[i].ddsd.ddpfPixelFormat; + + // For now, force 3d textures with RGB only info to be either 565 or 555 + // We could enum all formats and let the caller pick between several different RGB formats... + if (lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + continue; // We don't want any surface that has alpha, just pure RGB... + + if(lpddpfPixelFormat->dwRGBBitCount != 16) + continue; + + if( (lpddpfPixelFormat->dwRBitMask != 0xf800 && lpddpfPixelFormat->dwRBitMask != 0x7c00) || + (lpddpfPixelFormat->dwGBitMask != 0x7e0 && lpddpfPixelFormat->dwGBitMask != 0x3e0) || + (lpddpfPixelFormat->dwBBitMask != 0x1f)) + continue; + + + // This is it + AppInfo.ddTexFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 555 or 565 texture support.\n"); + return FALSE; + } + + Main_BuildRGBGammaTables(1.0f); + + return TRUE; +} + +//========================================================================================== +// Main_CheckDD +// Checks to see if current DD driver has any usable D3D Devices... +//========================================================================================== +BOOL Main_CheckDD(void) +{ + AppInfo.NumDrivers = 0; + AppInfo.CurrentDriver = 0; + AppInfo.FoundGoodDevice = FALSE; + AppInfo.CanDoWindow = FALSE; + + + if (!D3DMain_RememberOldMode(GetDesktopWindow())) + return FALSE; + + memset(AppInfo.Drivers, 0, sizeof(DDMain_D3DDriver)*DDMAIN_MAX_D3D_DRIVERS); + + if (!D3DMain_CreateD3D()) + return FALSE; + + if (!D3DMain_EnumDevices()) // See if we can enumerate at least one good device for this DD Driver + return FALSE; + + if (!AppInfo.FoundGoodDevice) // Return FALSE if not... + return FALSE; + + return TRUE; // Found at least one!!! +} + +//========================================================================================== +// OutputDriverInfo +//========================================================================================== +static BOOL OutputDriverInfo(const char *FileName, DDMain_D3DDriver *Driver) +{ + FILE *f; + SYSTEMTIME Time; + char YesNo[2][10]; + + f = fopen(FileName, "a+t"); + + if (!f) + return FALSE; + + GetSystemTime(&Time); + + strcpy(YesNo[0], "No\n"); + strcpy(YesNo[1], "Yes\n"); + + fprintf(f,"=================================================================\n"); + fprintf(f,"Time: %2i:%2i:%2i\n", Time.wHour, Time.wMinute, Time.wSecond); + fprintf(f,"Date: %2i-%2i-%4i\n", Time.wMonth, Time.wDay, Time.wYear); + + fprintf(f, "DirectDraw Name: \n"); + fprintf(f, " %s\n", AppInfo.DDName); + + fprintf(f, "D3D Driver Name: \n"); + fprintf(f, " %s\n", Driver->Name); + + fprintf(f, "D3D Driver Description: \n"); + fprintf(f, " %s\n", Driver->About); + + fprintf(f, "3D Acceleration : %s", YesNo[Driver->IsHardware]); + fprintf(f, "Texture Support : %s", YesNo[Driver->DoesTextures]); + fprintf(f, "Transparency Support : %s", YesNo[Driver->DoesTransparency]); + fprintf(f, "Alpha Support : %s", YesNo[Driver->DoesAlpha]); + fprintf(f, "UV Clamping Support : %s", YesNo[Driver->DoesClamping]); + fprintf(f, "Src Blending Support : %s", YesNo[Driver->DoesSrcBlending]); + fprintf(f, "Dest Blending Support : %s", YesNo[Driver->DoesDestBlending]); + fprintf(f, "Window Support : %s", YesNo[Driver->CanDoWindow]); + fprintf(f, "Can Use : %s", YesNo[Driver->CanUse]); + + fclose(f); + + return TRUE; +} + +//========================================================================================== +// D3DMain_GetTextureMemory +//========================================================================================== +BOOL D3DMain_GetTextureMemory(void) +{ + + DDSCAPS2 ddsCaps; + DWORD dwTotal; + DWORD dwFree; + HRESULT Error; + + D3DMain_Log("--- D3DMain_GetTextureMemory ---\n"); + + memset(&ddsCaps, 0, sizeof(ddsCaps)); + + //ddsCaps.dwSize = sizeof(DDSCAPS2); + ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + + Error = AppInfo.lpDD->GetAvailableVidMem(&ddsCaps, &dwTotal, &dwFree); + + if(Error !=DD_OK) + { + D3DMain_Log("Getting DD capabilities failed while checking total video memory.\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + AppInfo.VidMemFree = dwFree; + + D3DMain_Log(" Ram free: %i\n", AppInfo.VidMemFree); + + return TRUE; +} + + +//========================================================================================== +//========================================================================================== +void Main_BuildRGBGammaTables(float Gamma) +{ + int32 i, Val; + int32 GammaTable[256]; + D3D_PixelMask PixelMask; + DWORD R_Left, G_Left, B_Left, A_Left; + DWORD R_Right, G_Right, B_Right, A_Right; + + + AppInfo.Gamma = Gamma; + + if (Gamma == 1.0) + { + for (i=0 ; i<256 ; i++) + GammaTable[i] = i; + } + else for (i=0 ; i<256 ; i++) + { + float Ratio = (i+0.5f)/255.5f; + + float RGB = (float)(255.0 * pow((double)Ratio, 1.0/(double)Gamma) + 0.5); + + if (RGB < 0.0f) + RGB = 0.0f; + if (RGB > 255.0f) + RGB = 255.0f; + + GammaTable[i] = (int32)RGB; + } + + GetSurfacePixelMask(&AppInfo.ddTexFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut1.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut1.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut1.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut1.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } + GetSurfacePixelMask(&AppInfo.ddFourBitAlphaSurfFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut2.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut2.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut2.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut2.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } + GetSurfacePixelMask(&AppInfo.ddOneBitAlphaSurfFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut3.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut3.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut3.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut3.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } +} + +//==================================================================================================== +// D3DMain_UpdateWindow +//==================================================================================================== +geBoolean DRIVERCC D3DMain_UpdateWindow(void) +{ + D3DMain_GetClientWindowOffset(AppInfo.hWnd); + return GE_TRUE; +} + +//==================================================================================================== +// D3DMain_SetActive +//==================================================================================================== +geBoolean DRIVERCC D3DMain_SetActive(geBoolean wParam) +{ + if (AppInfo.lpFrontBuffer) + AppInfo.RenderingIsOK = wParam; + + if(AppInfo.RenderingIsOK) // Regaining focus + { + HRESULT Result; + + if (AppInfo.lpFrontBuffer) + { + Result = AppInfo.lpFrontBuffer->IsLost(); + + if(Result == DDERR_SURFACELOST) + { + if(!D3DMain_RestoreAllSurfaces()) + { + OutputDebugString("Couldn't restore surfaces!\n"); + return GE_FALSE; + } + + OutputDebugString("D3DMain_SetActive: Regained Focus...\n"); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); // Dx doesn't restore it + } + else + OutputDebugString("D3DMain_SetActive: No surfaces lost...\n"); + } + } + + return GE_TRUE; +} + +//======================================================================================================== +// D3DMain_SetFogEnable +//======================================================================================================== +geBoolean DRIVERCC D3DMain_SetFogEnable(geBoolean Enable, float r, float g, float b, float Start, float End) +{ + D3DMATERIAL Material; + + AppInfo.FogEnable = Enable; + AppInfo.FogR = r; + AppInfo.FogG = g; + AppInfo.FogB = b; + AppInfo.FogStart = Start; + AppInfo.FogEnd = End; + + // Fill in the material with the data + memset(&Material, 0, sizeof(D3DMATERIAL)); + + Material.dwSize = sizeof(D3DMATERIAL); + + if (Enable) + { + Material.dcvDiffuse.r = Material.dcvAmbient.r = r/255.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = g/255.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = b/255.0f; + } + else + { + Material.dcvDiffuse.r = Material.dcvAmbient.r = 0.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = 0.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = 0.0f; + } + + Material.dwRampSize = 16L; // A default ramp size + + AppInfo.BackgroundMaterial->SetMaterial(&Material); + + return GE_TRUE; +} + +//================================================================================ +// D3DMain_GetClientWindowOffset +//================================================================================ +BOOL D3DMain_GetClientWindowOffset(HWND hWnd) +{ + POINT CPoint; + + CPoint.x = CPoint.y = 0; + + ClientToScreen(hWnd, &CPoint); + + AppInfo.WindowXOffset = CPoint.x; + AppInfo.WindowYOffset = CPoint.y; + + return TRUE; +} + +//================================================================================ +// D3DMain_RememberOldMode +//================================================================================ +static BOOL D3DMain_RememberOldMode(HWND hWnd) +{ + DDSURFACEDESC2 ddsd; + HRESULT LastError; + RECT CRect; + + D3DMain_Log("--- D3DMain_RememberOldMode ---\n"); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + + LastError = AppInfo.lpDD->GetDisplayMode(&ddsd); + + if (LastError != DD_OK) + { + D3DMain_Log("Getting the current display mode failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + + GetClientRect(hWnd, &CRect); + + // Get old fulscreen width/height/bpp + AppInfo.OldWidth = ddsd.dwWidth; + AppInfo.OldHeight = ddsd.dwHeight; + AppInfo.OldBpp = ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Get old window width/pos + AppInfo.OldWindowWidth = CRect.right; + AppInfo.OldWindowHeight = CRect.bottom; + + GetWindowRect(hWnd, &CRect); + AppInfo.OldWindowRect = CRect; + + AppInfo.OldGWL_STYLE = GetWindowLong(hWnd, GWL_STYLE); + + D3DMain_GetClientWindowOffset(hWnd); + + return TRUE; +} + +//========================================================================================== +// D3DMain_SetDisplayMode +//========================================================================================== +static BOOL D3DMain_SetDisplayMode(HWND hWnd, int w, int h, int bpp, BOOL FullScreen) +{ + HRESULT LastError; + int DWidth, DHeight; + char YN[2][32]; + + strcpy(YN[0], "NO"); + strcpy(YN[1], "YES"); + + D3DMain_Log("--- D3DMain_SetDisplayMode ---\n"); + D3DMain_Log(" W: %i, H: %i, Bpp: %i, FullScreen: %s\n", w, h, bpp, YN[FullScreen]); + + if (FullScreen) + { + LastError = AppInfo.lpDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);// | DDSCL_ALLOWREBOOT); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to fullscreen failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + LastError = AppInfo.lpDD->SetDisplayMode(w, h, bpp,0,0); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetFullScreenDisplayMode: Mode %dx%dx%d failed\n %s\n", w, h, bpp, D3DErrorToString(LastError)); + return FALSE; + } + + DWidth = GetSystemMetrics(SM_CXSCREEN); + DHeight = GetSystemMetrics(SM_CYSCREEN); + + // + // Set window boundaries to cover entire desktop, and show it + // + SetWindowLong(hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE | WS_POPUP); + + SetWindowLong(hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE & + ~(WS_OVERLAPPED | + WS_CAPTION | + WS_SYSMENU | + WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | + WS_THICKFRAME)); + + + SetWindowPos(AppInfo.hWnd, + HWND_TOP, + 0, + 0, + DWidth, + DHeight, + SWP_NOCOPYBITS | SWP_NOZORDER); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); + } + else + { + LastError = AppInfo.lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to normal failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + + AppInfo.hWnd = hWnd; + AppInfo.CurrentWidth = w; + AppInfo.CurrentHeight = h; + AppInfo.CurrentBpp = bpp; + AppInfo.FullScreen = FullScreen; + + AppInfo.ModeSet = GE_TRUE; + + return TRUE; +} + +//================================================================================ +// D3DMain_PickDevice +//================================================================================ +static BOOL D3DMain_PickDevice(void) +{ + int32 i; + DWORD Depths; + + D3DMain_Log("--- D3DMain_PickDevice ---\n"); + + // Find a device with the same bpp as the mode set + Depths = BPPToDDBD(AppInfo.CurrentBpp); + + for (i = 0; i < AppInfo.NumDrivers; i++) + { + if (!(AppInfo.Drivers[i].IsHardware)) // ONLY hardware + continue; + + // Only choose drivers that can support our draw buffer bpp + if (!(AppInfo.Drivers[i].Desc.dwDeviceRenderBitDepth & Depths)) + continue; + + // Only choose drivers that can create the zbuffer we need + if (!(AppInfo.Drivers[i].Desc.dwDeviceZBufferBitDepth & DDBD_16)) + continue; + + if (!(AppInfo.Drivers[i].Desc.dcmColorModel & D3DCOLOR_RGB)) + continue; + + if (!AppInfo.Drivers[i].CanDoWindow && !AppInfo.FullScreen) + continue; + + // Remember the current driver + AppInfo.CurrentDriver = i; + + return TRUE; + } + + return FALSE; +} + +//================================================================================ +// D3DMain_CreateDevice +//================================================================================ +static BOOL D3DMain_CreateDevice(void) +{ + HRESULT Error; + + D3DMain_Log("--- D3DMain_CreateDevice ---\n"); + + // Release old device + RELEASE(AppInfo.lpD3DDevice); + + Error = AppInfo.lpD3D->CreateDevice(AppInfo.Drivers[AppInfo.CurrentDriver].Guid, + AppInfo.lpBackBuffer, + &AppInfo.lpD3DDevice,NULL); + + if (Error != DD_OK) + { + D3DMain_Log("D3DMain_CreateDevice: lpD3D->CreateDevice failed:\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + // Get Device Identifier + Error = AppInfo.lpDD->GetDeviceIdentifier(&AppInfo.DeviceIdentifier, 0); + + if (Error != DD_OK) + { + D3DMain_Log("D3DMain_CreateDevice: lpDD->GetDeviceIdentifier failed:\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + // Print the debug ID + D3DMain_Log(" Vender ID = %6i\n", AppInfo.DeviceIdentifier.dwVendorId); + D3DMain_Log(" Device ID = %6i\n", AppInfo.DeviceIdentifier.dwDeviceId); + + return TRUE; +} + +//================================================================================ +// D3DMain_CreateBuffers +//================================================================================ +static BOOL D3DMain_CreateBuffers(void) +{ + DDSURFACEDESC2 ddsd; + DDSCAPS2 ddscaps; + HRESULT LastError; + + D3DMain_Log("--- D3DMain_CreateBuffers ---\n"); + + // Release any old objects that might be lying around. This should have + // already been taken care of, but just in case... + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); + + if (AppInfo.FullScreen) + { + // Create a complex flipping surface for fullscreen mode with one + // back buffer. + memset(&ddsd,0,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | + DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX; + ddsd.dwBackBufferCount = 1; + + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + + LastError = CreateSurface(&ddsd, &AppInfo.lpFrontBuffer); + + if(LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n Please restart the program and try another fullscreen mode with less resolution or lower bit depth.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for fullscreen flipping surface failed.\n %s\n", + D3DErrorToString(LastError)); + } + + goto exit_with_error; + } + + // Obtain a pointer to the back buffer surface created above so we + // can use it later. For now, just check to see if it ended up in + // video memory (FYI). + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + LastError = AppInfo.lpFrontBuffer->GetAttachedSurface(&ddscaps, &AppInfo.lpBackBuffer); + + if(LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: GetAttachedSurface failed to get back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: Failed to get surface description of back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.BackBufferInVideo = + (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + AppInfo.ddsd = ddsd; // Save the format of the back buffer + } + else + { + // In the window case, create a front buffer which is the primary + // surface and a back buffer which is an offscreen plane surface. + + memset(&ddsd,0,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + + LastError = AppInfo.lpDD->CreateSurface(&ddsd, &AppInfo.lpFrontBuffer, NULL); + + if(LastError != DD_OK ) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n To run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for window front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + goto exit_with_error; + } + + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwWidth = AppInfo.CurrentWidth; + ddsd.dwHeight = AppInfo.CurrentHeight; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + + LastError = CreateSurface(&ddsd, &AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n To run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for window back buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + goto exit_with_error; + } + + // Check to see if the back buffer is in video memory (FYI). + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: Failed to get surface description for back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.BackBufferInVideo = (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + // Create the DirectDraw Clipper object and attach it to the window + // and front buffer. + LastError = AppInfo.lpDD->CreateClipper(0, &AppInfo.lpClipper, NULL); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: CreateClipper failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = AppInfo.lpClipper->SetHWnd(0, AppInfo.hWnd); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: Attaching clipper to window failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + + LastError = AppInfo.lpFrontBuffer->SetClipper(AppInfo.lpClipper); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: Attaching clipper to front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.ddsd = ddsd; // Save the format of the back buffer + } + + D3DMain_ClearBuffers(); + + return TRUE; + + exit_with_error: + + RELEASE(AppInfo.lpFrontBuffer); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpClipper); + return FALSE; +} + +//================================================================================ +// D3DMain_DestroyBuffers +//================================================================================ +static void D3DMain_DestroyBuffers(void) +{ + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); +} + +//================================================================================ +// D3DMain_CreateZBuffer +// Create a Z-Buffer of the appropriate depth and attach it to the back buffer. +//================================================================================ +static BOOL D3DMain_CreateZBuffer(void) +{ + DDSURFACEDESC2 ddsd; + HRESULT LastError; + + D3DMain_Log("--- D3DMain_CreateZBuffer ---\n"); + + // Release any Z-Buffer that might be around just in case. + RELEASE(AppInfo.lpZBuffer); + + memset(&ddsd, 0 ,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;//DDSD_ZBUFFERBITDEPTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; + ddsd.dwWidth = AppInfo.CurrentWidth; + ddsd.dwHeight = AppInfo.CurrentHeight; + + ddsd.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER; + + // Find a valid zbuffer, from the current device + AppInfo.lpD3D->EnumZBufferFormats(AppInfo.Drivers[AppInfo.CurrentDriver].Guid, EnumZBufferFormatsCallback, + (VOID*)&ddsd.ddpfPixelFormat); + + + if( sizeof(DDPIXELFORMAT) != ddsd.ddpfPixelFormat.dwSize ) + { + D3DMain_Log("CreateZBuffer: No zbuffer found for 3d device.\n"); + return FALSE; + } + + LastError = AppInfo.lpDD->CreateSurface(&ddsd, &AppInfo.lpZBuffer, NULL); + + if(LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + if (AppInfo.FullScreen) + { + D3DMain_Log("CreateZBuffer: There was not enough video memory to create the Z-buffer surface.\n Please try another mode with less resolution.\n"); + } + else + { + D3DMain_Log("CreateZBuffer: There was not enough video memory to create the Z-buffer surface.\n Please try another mode with less resolution.\n"); + } + } + else + { + D3DMain_Log("CreateZBuffer: CreateSurface for Z-buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + + goto exit_with_error; + } + + // Attach the Z-buffer to the back buffer so D3D will find it + LastError = AppInfo.lpBackBuffer->AddAttachedSurface(AppInfo.lpZBuffer); + + if(LastError != DD_OK) + { + D3DMain_Log("CreateZBuffer: AddAttachedBuffer failed for Z-Buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + // Find out if it ended up in video memory. + LastError = GetSurfDesc(&ddsd, AppInfo.lpZBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateZBuffer: Failed to get surface description of Z buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.ZBufferInVideo = (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + return TRUE; + + exit_with_error: + RELEASE(AppInfo.lpZBuffer); + return FALSE; +} + +//================================================================================ +// D3DMain_DestroyZBuffer +//================================================================================ +static void D3DMain_DestroyZBuffer(void) +{ + RELEASE(AppInfo.lpZBuffer) +} + +//================================================================================ +// D3DMain_RestoreDisplayMode +// Does nothing if mode has not been set yet +//================================================================================ +static BOOL D3DMain_RestoreDisplayMode(void) +{ + HRESULT LastError; + + if (!AppInfo.ModeSet) + return TRUE; + + AppInfo.ModeSet = GE_FALSE; + + + if (AppInfo.FullScreen) + { + LastError = AppInfo.lpDD->RestoreDisplayMode(); + + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_RestoreDisplayMode: RestoreDisplayMode failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + LastError = AppInfo.lpDD->SetCooperativeLevel(AppInfo.hWnd, DDSCL_NORMAL); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to normal failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + + // Restore window width/height + SetWindowLong(AppInfo.hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE); + + SetWindowPos(AppInfo.hWnd, + HWND_TOP, + AppInfo.OldWindowRect.left, + AppInfo.OldWindowRect.top, + (AppInfo.OldWindowRect.right - AppInfo.OldWindowRect.left), + (AppInfo.OldWindowRect.bottom - AppInfo.OldWindowRect.top), + SWP_NOCOPYBITS | SWP_NOZORDER); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); + + return TRUE; +} + + +// +// Enum drivers +// + +D3D_DRIVER Drivers[MAX_DRIVERS]; + +//======================================================================================================== +// EnumDriversCB2 +//======================================================================================================== +BOOL FAR PASCAL EnumDriversCB2(GUID FAR *lpGUID, LPSTR lpDriverDesc, LPSTR lpDriverName, LPVOID lpContext) +{ + DDEnumInfo *Info; + D3D_DRIVER *pDriver; + + if (!lpDriverDesc || !lpDriverName) + return (D3DENUMRET_OK); + + if (strlen(lpDriverDesc) + 5 >= MAX_DRIVER_NAME) + return DDENUMRET_OK; + + Info = (DDEnumInfo*)lpContext; + + if (Info->NumDrivers >= MAX_DRIVERS) + return DDENUMRET_CANCEL; + + pDriver = &Info->Drivers[Info->NumDrivers++]; + + if (lpGUID) + { + pDriver->IsPrimary = GE_FALSE; + memcpy(&pDriver->Guid, lpGUID, sizeof(GUID)); + } + else + { + pDriver->IsPrimary = GE_TRUE; + } + + // Save name + sprintf(pDriver->Name, "(D3D)%s", lpDriverDesc); + + return DDENUMRET_OK; +} + +//======================================================================================================== +// EnumSubDrivers2 +//======================================================================================================== +BOOL DRIVERCC EnumSubDrivers2(DRV_ENUM_DRV_CB *Cb, void *Context) +{ + HRESULT hr; + int32 i; + DDEnumInfo Info; + + unlink(D3DMAIN_LOG_FILENAME); + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_EnumSubDrivers: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + for (i=0; i< Info.NumDrivers; i++) + { + // Create the DD object for this driver + if (!CreateDDFromDriver(&Info.Drivers[i])) + return GE_FALSE; + + if (Main_CheckDD()) + { + if (!Cb(i, Info.Drivers[i].Name, Context)) + { + RELEASE(AppInfo.lpD3D); + AppInfo.lpD3D = NULL; + + //D3DMain_ShutdownD3D(); + RELEASE(AppInfo.lpDD); + AppInfo.lpDD = NULL; + memset(&AppInfo, 0, sizeof(AppInfo)); + break; + } + } + + RELEASE(AppInfo.lpD3D); + AppInfo.lpD3D = NULL; + + //D3DMain_ShutdownD3D(); + RELEASE(AppInfo.lpDD); + AppInfo.lpDD = NULL; + memset(&AppInfo, 0, sizeof(AppInfo)); + } + + return TRUE; +} + +//======================================================================================================== +// EnumModes2 +//======================================================================================================== +BOOL DRIVERCC EnumModes2(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context) +{ + HRESULT hr; + int32 i, Width, Height; + char ModeName[MAX_DRIVER_NAME]; + DDEnumInfo Info; + + //Cb(0, "HackMode 2", 640, 480, Context); + //return GE_TRUE; + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_EnumModes: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + + if (!CreateDDFromName(DriverName, &Info)) + return GE_FALSE; + + if (!D3DMain_EnumDisplayModes()) + { + D3DMain_ShutdownD3D(); + + D3DMain_Log("D3DMain_EnumModes: D3DMain_EnumDisplayModes failed.\n"); + return FALSE; + } + + for (i=0; i< AppInfo.NumModes; i++) + { + if (AppInfo.Modes[i].Bpp != 16) + continue; + + // Get the width/height of mode + Width = AppInfo.Modes[i].Width; + Height = AppInfo.Modes[i].Height; + + // Make a unique name + sprintf(ModeName, "%ix%i", Width, Height); + + // Call their callback with this driver mode + if (!Cb(i, ModeName, Width, Height, Context)) + { + D3DMain_ShutdownD3D(); + return GE_TRUE; + } + } + + if (AppInfo.CanDoWindow) + { + if (!Cb(i, "WindowMode", -1, -1, Context)) + { + D3DMain_ShutdownD3D(); + return GE_TRUE; + } + } + + D3DMain_ShutdownD3D(); + + return TRUE; +} + +//================================================================================ +// DDEnumCallback +//================================================================================ +static BOOL FAR PASCAL DDEnumCallback( GUID FAR* lpGUID, + LPSTR lpDriverDesc, + LPSTR lpDriverName, + LPVOID lpContext) +{ + LPDIRECTDRAW4 pDD6; + DDCAPS DriverCaps, HELCaps; + DD_Enum *DDEnum; + LPDIRECTDRAW pDD1; + HRESULT hr; + + DDEnum = (DD_Enum*)lpContext; + + if(strncmp(lpDriverDesc, DDEnum->DriverName, strlen(DDEnum->DriverName))) + return DDENUMRET_OK; // Next... This is not the one they wanted + + pDD1 = NULL; + hr = DirectDrawCreate( lpGUID, &pDD1, NULL ); + + if(FAILED( hr )) + return DDENUMRET_CANCEL; // Assume this is bad, and stop + + // Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw + // represents the DX6 version of the API. + hr = pDD1->QueryInterface( IID_IDirectDraw4, (VOID**)&pDD6); + + // Don't need this anymore + RELEASE(pDD1); + + if( FAILED( hr ) ) + return DDENUMRET_CANCEL; + + memset(&DriverCaps, 0, sizeof(DDCAPS)); + DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + if (FAILED(pDD6->GetCaps(&DriverCaps, &HELCaps))) + { + RELEASE(pDD6); + return DDENUMRET_CANCEL; + } + + // Make sure it's a 3d compatible device + if (!(DriverCaps.dwCaps & DDCAPS_3D)) + { + RELEASE(pDD6); + return DDENUMRET_CANCEL; + } + + if (!lpGUID) + AppInfo.IsPrimary = TRUE; + else + AppInfo.IsPrimary = FALSE; + + DDEnum->lpDD = pDD6; + DDEnum->FoundDD = TRUE; + + return DDENUMRET_CANCEL; // We are done +} + +//================================================================================ +// D3DMain_CreateDDFromName +// Creates DD, searching for the specified DD name using DriverName +//================================================================================ +static BOOL D3DMain_CreateDDFromName(const char *DriverName) +{ + HRESULT hr; + DDCAPS DriverCaps, HELCaps; + DDEnumInfo Info; + + D3DMain_Log("--- D3DMain_CreateDDFromName ---\n"); + + if (strlen(DriverName) >= MAX_DRIVER_NAME) + return GE_FALSE; + + D3DMain_Log(" Name: %s\n", DriverName); + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_CreateDDFromName: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + { + char TempName[1024]; + + sprintf(TempName, "(D3D)%s", DriverName); + + if (!CreateDDFromName(TempName, &Info)) + return GE_FALSE; + } + + memset(&DriverCaps, 0, sizeof(DDCAPS)); + DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + if (FAILED(AppInfo.lpDD->GetCaps(&DriverCaps, &HELCaps))) + { + D3DMain_Log("D3DMain_CreateDDFromName: GetCaps failed.\n"); + D3DMain_ShutdownD3D(); + return FALSE; + } + + if (DriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED) + D3DMain_Log(" DDCAPS2_CANRENDERWINDOWED : YES\n"); + else + D3DMain_Log(" DDCAPS2_CANRENDERWINDOWED : NO\n"); + + if (DriverCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) + D3DMain_Log(" DDCAPS2_NO2DDURING3DSCENE : YES\n"); + else + D3DMain_Log(" DDCAPS2_NO2DDURING3DSCENE : NO\n"); + + // Save the DD object + strcpy(AppInfo.DDName, DriverName); + + return TRUE; +} + +//======================================================================================================== +// CreateDDFromDriver +//======================================================================================================== +static geBoolean CreateDDFromDriver(D3D_DRIVER *pDriver) +{ + LPDIRECTDRAW pDD1; + HRESULT hr; + + AppInfo.IsPrimary = pDriver->IsPrimary; + + if (pDriver->IsPrimary) + hr = DirectDrawCreate(NULL, &pDD1, NULL ); + else + hr = DirectDrawCreate(&pDriver->Guid, &pDD1, NULL ); + + if( FAILED( hr ) ) + return GE_FALSE; + + // Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw + // represents the DX6 version of the API. + hr = pDD1->QueryInterface(IID_IDirectDraw4, (VOID**)&AppInfo.lpDD); + + // Don't need this guy anymore + RELEASE(pDD1); + + if(FAILED(hr)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +// CreateDDFromName +//======================================================================================================== +static geBoolean CreateDDFromName(const char *DriverName, const DDEnumInfo *Info) +{ + int32 i; + + for (i=0; i < Info->NumDrivers; i++) + { + if (!strcmp(Info->Drivers[i].Name, DriverName)) + break; + } + + if (i == Info->NumDrivers) + return GE_FALSE; + + // Create the DD object for this driver + if (!CreateDDFromDriver(&Info->Drivers[i])) + return GE_FALSE; + + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/D3D8Drv/D3d_main.h b/G3D/Engine/Drivers/D3D8Drv/D3d_main.h new file mode 100644 index 0000000..03d97ed --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3d_main.h @@ -0,0 +1,227 @@ +/****************************************************************************************/ +/* D3D_Main.h */ +/* */ +/* Author: John Pollard */ +/* Description: DD/D3D wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_MAIN_H +#define D3D_MAIN_H + +#include +#include +#include + +#define INITGUID + +#include "DCommon.h" + +#define MAX_APP_MODES 50 +#define DDMAIN_MAX_D3D_DRIVERS 10 +#define DDMAIN_MAX_TEXTURE_FORMATS 128 +#define DDMAIN_MAX_SURFACE_FORMATS 128 + +#define D3DMAIN_LOG_FILENAME "D3DDrv.Log" + +#define MAX_DRIVER_NAME 1024 + +//================================================================================ +// Structure defs +//================================================================================ + +typedef struct +{ + char Name[MAX_DRIVER_NAME]; // Short name of the driver + char About[MAX_DRIVER_NAME]; // Short string about the driver + D3DDEVICEDESC Desc; // D3DDEVICEDESC for complete information + GUID Guid; // it's GUID + BOOL IsHardware; // does this driver represent a hardware device? + BOOL DoesTextures; // does this driver do texture mapping? + BOOL DoesZBuffer; // can this driver use a z-buffer? + BOOL CanDoWindow; // can it render to Window's display depth? + BOOL DoesTransparency; + BOOL DoesAlpha; + BOOL DoesClamping; + BOOL DoesSrcBlending; + BOOL DoesDestBlending; + + WORD MaxTextureBlendStages; + WORD MaxSimultaneousTextures; + + BOOL CanUse; // We can use this driver +} DDMain_D3DDriver; + +typedef struct +{ + int32 Width; // width + int32 Height; // height + int32 Bpp; // bits per pixel + BOOL ThisDriverCanDo; // == TRUE if d3d driver can render into +} App_Mode; + +typedef struct +{ + DDSURFACEDESC2 ddsd; // DDSURFACEDESC for complete information + BOOL HasOneBitAlpha; + BOOL HasFourBitAlpha; +} DDMain_SurfFormat; + +typedef struct +{ + uint32 R[256]; + uint32 G[256]; + uint32 B[256]; + uint32 A[256]; +} RGB_LUT; + +// App_Info, used for everything global. +typedef struct +{ + // Window info + HWND hWnd; // Handle to parent Window + + DDSURFACEDESC2 ddsd; + + // Mode that we were in before initializing + int32 OldWidth; // Old screen width + int32 OldHeight; + int32 OldBpp; + + int32 CurrentWidth; + int32 CurrentHeight; + int32 CurrentBpp; + + int32 OldWindowWidth; // Old client width + int32 OldWindowHeight; + int32 WindowXOffset; + int32 WindowYOffset; + + RECT OldWindowRect; + ULONG OldGWL_STYLE; + + geBoolean ModeSet; + + char DDName[MAX_DRIVER_NAME]; // Have no idea how big to make this. Anyone? + + LPDIRECTDRAW4 lpDD; // The current initialized DD object + LPDIRECT3D3 lpD3D; // The current initialized D3D object + + LPDIRECTDRAWSURFACE4 lpFrontBuffer; // front buffer surface + LPDIRECTDRAWSURFACE4 lpBackBuffer; // back buffer surface + LPDIRECTDRAWSURFACE4 lpZBuffer; // z-buffer surface + LPDIRECTDRAWCLIPPER lpClipper; // Clipper in windowed case + BOOL BackBufferInVideo; // back buf in video mem? + BOOL ZBufferInVideo; // is Z-buf in video mem? + LPDIRECT3DDEVICE3 lpD3DDevice; // D3D device + LPDIRECT3DVIEWPORT3 lpD3DViewport; // D3D viewport + + LPDIRECT3DMATERIAL3 BackgroundMaterial; + + // 2d surface format (for blt'ing to the display) + DDSURFACEDESC2 ddSurfFormat; // 555 or 565 surface desc + + // Texture formats (for the D3D device) + DDSURFACEDESC2 ddTexFormat; // 555 or 565 surface desc + DDSURFACEDESC2 ddFourBitAlphaSurfFormat; // 4444 surface desc + DDSURFACEDESC2 ddOneBitAlphaSurfFormat; // 1555 surface desc + + RGB_LUT Lut1; + RGB_LUT Lut2; + RGB_LUT Lut3; + + BOOL IsPrimary; // + BOOL FullScreen; + + int32 NumModes; + App_Mode Modes[MAX_APP_MODES]; + + int32 NumDrivers; + DDMain_D3DDriver Drivers[DDMAIN_MAX_D3D_DRIVERS]; + int32 CurrentDriver; + DDDEVICEIDENTIFIER DeviceIdentifier; + + // Surface formats + int32 NumSurfFormats; // Num 2D texture formats avail (from DD4 object) + DDMain_SurfFormat SurfFormats[DDMAIN_MAX_SURFACE_FORMATS]; + + // Texture formats + int32 NumTextureFormats; // Num 3D texture formats avail (from device) + DDMain_SurfFormat TextureFormats[DDMAIN_MAX_TEXTURE_FORMATS]; + + BOOL LogToFile; + BOOL FoundGoodDevice; + BOOL CanDoWindow; + + BOOL RenderingIsOK; + + DWORD VidMemFree; + + float Gamma; + BOOL GammaChanged; + + geBoolean CanDoMultiTexture; + + geBoolean FogEnable; + float FogStart; + float FogEnd; + float FogR; + float FogG; + float FogB; + + // DD / D3D Flags + uint32 Flags; +} App_Info; + +// DD enum strcuture. Used when enuming dd +typedef struct +{ + LPDIRECTDRAW4 lpDD; + char DriverName[MAX_DRIVER_NAME]; + BOOL FoundDD; +} DD_Enum; + +//================================================================================ +// Globals +//================================================================================ +extern App_Info AppInfo; // Our global structure that knows all... (once initialized) + +//================================================================================ +// Global functions +//================================================================================ +BOOL D3DMain_InitD3D(HWND hWnd, const char *DriverName, int32 Width, int32 Height); +BOOL D3DMain_ShutdownD3D(void); +geBoolean D3DMain_Reset(void); +void D3DMain_Log(LPSTR Str, ... ); +BOOL D3DMain_RestoreAllSurfaces(void); + +BOOL Main_EnumTextureFormats(void); +BOOL D3DMain_EnumDisplayModes(void); +BOOL Main_ClearBackBuffer(BOOL Clear, BOOL ClearZ); +BOOL Main_ShowBackBuffer(void); + +BOOL D3DMain_GetSurfaceFormats(void); + +BOOL Main_CheckDD(void); +BOOL D3DMain_GetTextureMemory(void); +void Main_BuildRGBGammaTables(float Gamma); + +BOOL D3DMain_GetClientWindowOffset(HWND hWnd); +geBoolean DRIVERCC D3DMain_UpdateWindow(void); +geBoolean DRIVERCC D3DMain_SetActive(geBoolean wParam); +geBoolean DRIVERCC D3DMain_SetFogEnable(geBoolean Enable, float r, float g, float b, float Start, float End); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D8Drv/D3dcache.cpp b/G3D/Engine/Drivers/D3D8Drv/D3dcache.cpp new file mode 100644 index 0000000..8614873 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3dcache.cpp @@ -0,0 +1,694 @@ +/****************************************************************************************/ +/* D3DCache.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include + +#include "D3DCache.h" + + + + + + + + +// Cache types are just the different types of textures +// Texutres may vary from width/height/num miplevels/etc... +// Cache types is just a way to combine them to similar types... +#define D3DCACHE_MAX_CACHE_TYPES 128 + +//======================================================================================================== +//======================================================================================================== +typedef struct D3DCache_Type +{ + int32 Log; + int32 Width; // Width/Height + int32 Height; + int32 NumMipLevels; + int32 Stage; + int32 RefCount; // How many references to this cache_type + + DDSURFACEDESC2 ddsd; // DD surface description + + D3DCache_Slot *Slots; // Cache slots for this Cache type + int32 NumUsedSlots; // Number of slots being used + + D3DCache_Type *SelfCheck; + D3DCache *Cache; +} D3DCache_Type; + +typedef struct D3DCache +{ + struct D3DCache *SelfCheck; + + char Name[D3DCACHE_MAX_NAME]; + + LPDIRECTDRAW4 lpDD; // DD object for the cache manager + + DDMemMgr_Partition *Partition; + + geBoolean UseStages; + + D3DCache_Type CacheTypes[D3DCACHE_MAX_CACHE_TYPES]; // CacheTypes +} D3DCache; + +typedef struct D3DCache_Slot +{ + struct D3DCache_Slot *SelfCheck; + + D3DCache_Type *CacheType; + + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this slot + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface + + uint32 LRU; // Current LRU for cache slot + + void *UserData; + +} D3DCache_Slot; + +//======================================================================================================== +//======================================================================================================== + +//======================================================================================================== +// D3DCache_Create +//======================================================================================================== +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW4 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages) +{ + D3DCache *Cache; + + Cache = (D3DCache*)malloc(sizeof(D3DCache)); + + if (!Cache) + return NULL; + + memset(Cache, 0, sizeof(D3DCache)); + + Cache->lpDD = lpDD; + + Cache->Partition = Partition; + + Cache->UseStages = UseStages; + + Cache->SelfCheck = Cache; + + strcpy(Cache->Name, Name); + + return Cache; +} + +//======================================================================================================== +// D3DCache_Destroy +//======================================================================================================== +void D3DCache_Destroy(D3DCache *Cache) +{ + D3DCache_FreeAllSlots(Cache); + + free(Cache); +} + +//======================================================================================================== +// D3DCache_IsValid +//======================================================================================================== +geBoolean D3DCache_IsValid(D3DCache *Cache) +{ + if (!Cache) + return GE_FALSE; + + if (Cache->SelfCheck != Cache) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +geBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache) +{ + int32 i; + D3DCache_Type *pCacheType; + + + for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + int32 s; + + if (!pCacheType->RefCount) + continue; + + for (pSlot = pCacheType->Slots, s=0; sNumUsedSlots; s++, pSlot++) + { + D3DCache_SlotSetUserData(pSlot, NULL); + } + } + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + int32 i; + D3DCache_Type *pCacheType; + + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + continue; + + if (pCacheType->Width != Width) + continue; + if (pCacheType->Height != Height) + continue; + + if (pCacheType->NumMipLevels != NumMipLevels) + continue; + + if (pCacheType->Stage != Stage) + continue; + + if (memcmp(&pCacheType->ddsd, ddsd, sizeof(DDSURFACEDESC2))) + continue; + + return pCacheType; // Found a match + } + + return NULL; // Cache Type not found!!! +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + int32 i; + D3DCache_Type *pCacheType; + + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + break; + } + + if (i == D3DCACHE_MAX_CACHE_TYPES) // No types left + return NULL; + + pCacheType->Width = Width; + pCacheType->Height = Height; + pCacheType->NumMipLevels = NumMipLevels; + pCacheType->Stage = Stage; + pCacheType->ddsd = *ddsd; + + pCacheType->SelfCheck = pCacheType; + pCacheType->Cache = Cache; + + pCacheType->Log = GetLog(Width, Height); + + // Found one + pCacheType->RefCount++; + + return pCacheType; +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + D3DCache_Type *CacheType; + + + CacheType = D3DCache_FindCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd); + + if (CacheType) + { + CacheType->RefCount++; + return CacheType; + } + + // Could not find one allready in the list, so add a new one... + return D3DCache_InsertCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd); +} + +//======================================================================================================== +// D3DCache_TypeDestroy +//======================================================================================================== +void D3DCache_TypeDestroy(D3DCache_Type *CacheType) +{ + CacheType->RefCount--; + + if (CacheType->RefCount == 0) + { + if (CacheType->Slots) + { + D3DCache_Slot *pSlot; + int32 k; + + // Go through each slot, and free all the surfaces on them + for (pSlot = CacheType->Slots, k=0; k< CacheType->NumUsedSlots; k++, pSlot++) + { + if (pSlot->Texture) + pSlot->Texture->Release(); + if (pSlot->Surface) + pSlot->Surface->Release(); + } + + free(CacheType->Slots); + CacheType->Slots = NULL; + CacheType->NumUsedSlots = 0; + } + } +} + +//======================================================================================================== +// D3DCache_TypeIsValid +//======================================================================================================== +geBoolean D3DCache_TypeIsValid(D3DCache_Type *Type) +{ + if (!Type) + return GE_FALSE; + + if (Type->SelfCheck != Type) + return GE_FALSE; + + if (!D3DCache_IsValid(Type->Cache)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_FreeAllSlots +//======================================================================================================== +geBoolean D3DCache_FreeAllSlots(D3DCache *Cache) +{ + int32 i; + D3DCache_Type *pCacheType; + + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + int32 k; + + if (pCacheType->RefCount == 0) + continue; + + // Go through each slot, and free all the surfaces on them + for (pSlot = pCacheType->Slots, k=0; k< pCacheType->NumUsedSlots; k++, pSlot++) + { + if (pSlot->Texture) + pSlot->Texture->Release(); + if (pSlot->Surface) + pSlot->Surface->Release(); + } + + if (pCacheType->Slots) + free(pCacheType->Slots); + + pCacheType->Slots = NULL; + pCacheType->NumUsedSlots = 0; + } + + DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_WriteToFile +//======================================================================================================== +geBoolean D3DCache_WriteToFile(D3DCache *Cache, const char *FileName, geBoolean Append) +{ + int32 i; + D3DCache_Type *pCacheType; + int32 TotalRef, TotalUsed; + SYSTEMTIME Time; + FILE *f; + + if (Append) + f = fopen(FileName, "a+t"); + else + f = fopen(FileName, "w"); + + if (!f) + return GE_FALSE; + + GetSystemTime(&Time); + + fprintf(f, "=======================================================\n"); + fprintf(f, "Date: %i/%i/%i, Time: %i:%i\n", Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute); + fprintf(f, "Cache Name: %s\n", Cache->Name); + fprintf(f, "Total Mem: %5i\n", DDMemMgr_PartitionGetTotalMem(Cache->Partition)); + fprintf(f, "Free Mem: %5i\n", DDMemMgr_PartitionGetFreeMem(Cache->Partition)); + fprintf(f, " --- Slots ---\n"); + + TotalRef = TotalUsed = 0; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (!pCacheType->RefCount) + continue; + + fprintf(f, "Width: %3i, Height %3i, Mips: %2i, Stage: %2i, Ref: %4i, Used: %4i\n", + pCacheType->Width, pCacheType->Height, pCacheType->NumMipLevels, pCacheType->Stage, pCacheType->RefCount, pCacheType->NumUsedSlots); + + TotalRef += pCacheType->RefCount; + TotalUsed += pCacheType->NumUsedSlots; + } + + fprintf(f, "Total Ref: %4i, Total Used: %4i\n", TotalRef, TotalUsed); + + fclose(f); + + return GE_TRUE; +} + +static geBoolean AppendHack = GE_FALSE; + +// HACK!!!! +void D3DMain_Log(LPSTR Str, ... ); +//======================================================================================================== +// D3DCache_AdjustSlots +//======================================================================================================== +geBoolean D3DCache_AdjustSlots(D3DCache *Cache, const int32 *MaxTable, geBoolean UsePartition) +{ + D3DCache_Type *pCacheType; + int32 i, Total, NumPasses; + D3DCache_FreeAllSlots(Cache); // Just get rid of everything for now... + DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager + Total = 0; + NumPasses = 0; + + while(1) + { + D3DCache_Slot *LastSlot; + + LastSlot = NULL; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + uint32 Size, Width, Height, Result; + + if (pCacheType->RefCount <= 0) + continue; + + if (pCacheType->NumUsedSlots >= pCacheType->RefCount) + continue; // This is all we need for this slot... + + if (pCacheType->NumUsedSlots >= MaxTable[pCacheType->Log]) + continue; + + if (!pCacheType->Slots) // If no slots have been allocated, allocate them now... + { + pCacheType->Slots = (D3DCache_Slot*)malloc(sizeof(D3DCache_Type)*pCacheType->RefCount); + memset(pCacheType->Slots, 0, sizeof(D3DCache_Type)*pCacheType->RefCount); + } + + Width = pCacheType->Width; + Height = pCacheType->Height; + + Size = Width*Height*(pCacheType->ddsd.ddpfPixelFormat.dwRGBBitCount>>3); // (BitCount/8) + + if (UsePartition) + { + if (!DDMemMgr_PartitionAllocMem(Cache->Partition, Size)) + { + LastSlot = NULL; // Make a complete stop + break; // No more memory in the partition, stop now... + } + } + + pSlot = &pCacheType->Slots[pCacheType->NumUsedSlots]; + pSlot->SelfCheck = pSlot; + + pSlot->CacheType = pCacheType; + + // Allocate surfaces now + Result = D3DCache_SetupSlot(Cache, pSlot, Width, Height, &pCacheType->ddsd, Cache->UseStages, pCacheType->Stage); + + if (!Result) + { + memset(pSlot, 0, sizeof(D3DCache_Slot)); + break; + } + else if (Result == -1) + { + D3DMain_Log("D3DCache_AdjustSlots: D3DCache_SetupSlot failed.\n"); + return GE_FALSE; + } + + pCacheType->NumUsedSlots++; + Total++; + + LastSlot = pSlot; + } + + NumPasses++; + + if (!LastSlot) // Nothing was allocated on that pass, so assume we are out of memory + break; + } + + pCacheType = Cache->CacheTypes; + + // Go through one last time, and make sure all got allocated + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (pCacheType->RefCount <= 0) + continue; + + if (pCacheType->NumUsedSlots <= 0) + { + D3DMain_Log("D3DCache_AdjustSlots: Out of ram creating surfaces for cache.\n"); + D3DMain_Log("D3DCache_AdjustSlots: Pick a display mode with a smaller resolution.\n"); + return GE_FALSE; // Not all slots with refs got a texture + } + } + + D3DCache_WriteToFile(Cache, "D3DCache.Log", AppendHack); + AppendHack = GE_TRUE; + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_SlotIsValid +//======================================================================================================== +geBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot) +{ + if (!Slot) + return GE_FALSE; + + if (Slot->SelfCheck != Slot) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// D3DCache_SetupSlot +// +// Returns -1 on failure +// Returns 0 on out of memory +// Returns 1 on success +//===================================================================================== +int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, geBoolean UseStage, int32 Stage) +{ + LPDIRECTDRAWSURFACE4 Surface; + DDSURFACEDESC2 ddsd; + HRESULT Hr; + + memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + + if (UseStage) + ddsd.dwFlags |= DDSD_TEXTURESTAGE; + + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_HINTDYNAMIC; + ddsd.ddsCaps.dwCaps3 = 0; + ddsd.ddsCaps.dwCaps4 = 0; + ddsd.dwHeight = Width; + ddsd.dwWidth = Height; + ddsd.dwTextureStage = Stage; + + Hr = Cache->lpDD->CreateSurface(&ddsd, &Surface, NULL); + + if(Hr != DD_OK) + { + if (Hr == DDERR_OUTOFVIDEOMEMORY) + { + return 0; + } + + return -1; + } + + Slot->Surface = Surface; + + + Hr = Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Slot->Texture); + + if(Hr != DD_OK) + { + Surface->Release(); + return -1; + } + + return 1; // All good dude +} + + +//======================================================================================================== +// D3DCache_TypeFindSlot +//======================================================================================================== +D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType) +{ + D3DCache_Slot *pBestSlot, *pSlot; + uint32 BestLRU; + int32 i; + + pSlot = CacheType->Slots; + pBestSlot = pSlot; + BestLRU = pBestSlot->LRU; + + for (i=0; i< CacheType->NumUsedSlots; i++, pSlot++) + { + if (pSlot->LRU < BestLRU) + { + pBestSlot = pSlot; + BestLRU = pSlot->LRU; + } + } + + pBestSlot->LRU = 0; + pBestSlot->UserData = NULL; + + return pBestSlot; +} + +//======================================================================================================== +// D3DCache_SlotSetUserData +//======================================================================================================== +void D3DCache_SlotSetUserData(D3DCache_Slot *Slot, void *UserData) +{ + Slot->UserData = UserData; +} + +//======================================================================================================== +// D3DCache_SlotGetUserData +//======================================================================================================== +void *D3DCache_SlotGetUserData(D3DCache_Slot *Slot) +{ + return Slot->UserData; +} + +//======================================================================================================== +// D3DCache_SlotSetLRU +//======================================================================================================== +void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU) +{ + Slot->LRU = LRU; +} + +//======================================================================================================== +// D3DCache_SlotGetLRU +//======================================================================================================== +uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot) +{ + return Slot->LRU; +} + +LPDIRECT3DTEXTURE2 D3DCache_SlotGetTexture(D3DCache_Slot *Slot) +{ + return Slot->Texture; +} + +LPDIRECTDRAWSURFACE4 D3DCache_SlotGetSurface(D3DCache_Slot *Slot) +{ + return Slot->Surface; +} + +//===================================================================================== +// Log2 +// Return the log of a size +//===================================================================================== +uint32 Log2(uint32 P2) +{ + uint32 p = 0; + int32 i = 0; + + for (i = P2; i > 0; i>>=1) + p++; + + return (p-1); +} + +//===================================================================================== +// SnapToPower2 +// Snaps a number to a power of 2 +//===================================================================================== +int32 SnapToPower2(int32 Width) +{ + if (Width > 0 && Width <= 1) Width = 1; + else if (Width > 1 && Width <= 2) Width = 2; + else if (Width > 2 && Width <= 4) Width = 4; + else if (Width > 4 && Width <= 8) Width = 8; + else if (Width > 8 && Width <= 16) Width =16; + else if (Width > 16 && Width <= 32) Width = 32; + else if (Width > 32 && Width <= 64) Width = 64; + else if (Width > 64 && Width <= 128) Width = 128; + else if (Width > 128 && Width <= 256) Width = 256; + else + return -1; + + return Width; +} + +//===================================================================================== +// Return the max log of a (power of 2) width and height +//===================================================================================== +int32 GetLog(int32 Width, int32 Height) +{ + int32 LWidth = SnapToPower2(max(Width, Height)); + + return Log2(LWidth); +} + diff --git a/G3D/Engine/Drivers/D3D8Drv/D3dcache.h b/G3D/Engine/Drivers/D3D8Drv/D3dcache.h new file mode 100644 index 0000000..bc2351e --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3dcache.h @@ -0,0 +1,64 @@ +/****************************************************************************************/ +/* D3DCache.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3DCache_H +#define D3DCache_H + +#include +#include +#include + +#include "BaseType.h" +#include "DDMemMgr.h" + +#define D3DCACHE_MAX_NAME 256 + +typedef struct D3DCache D3DCache; +typedef struct D3DCache_Type D3DCache_Type; +typedef struct D3DCache_Slot D3DCache_Slot; + +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW4 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages); +void D3DCache_Destroy(D3DCache *Cache); +geBoolean D3DCache_IsValid(D3DCache *Cache); +geBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache); +D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +void D3DCache_TypeDestroy(D3DCache_Type *CacheType); +geBoolean D3DCache_TypeIsValid(D3DCache_Type *Type); +geBoolean D3DCache_FreeAllSlots(D3DCache *Cache); +geBoolean D3DCache_AdjustSlots(D3DCache *Cache, const int32 *MaxTable, geBoolean UsePartition); +geBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot); +int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, geBoolean UseStage, int32 Stage); +D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType); +void D3DCache_SlotSetUserData(D3DCache_Slot *Slot, void *UserData); +void *D3DCache_SlotGetUserData(D3DCache_Slot *Slot); +void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU); +uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot); +LPDIRECT3DTEXTURE2 D3DCache_SlotGetTexture(D3DCache_Slot *Slot); +LPDIRECTDRAWSURFACE4 D3DCache_SlotGetSurface(D3DCache_Slot *Slot); + +uint32 Log2(uint32 P2); +int32 SnapToPower2(int32 Width); +int32 GetLog(int32 Width, int32 Height); + +#endif + diff --git a/G3D/Engine/Drivers/D3D8Drv/D3ddrv.cpp b/G3D/Engine/Drivers/D3D8Drv/D3ddrv.cpp new file mode 100644 index 0000000..1531aa0 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/D3ddrv.cpp @@ -0,0 +1,386 @@ +/****************************************************************************************/ +/* D3DDrv.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" + +#include "Scene.h" +#include "Render.h" +#include "D3DCache.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "THandle.h" + + + + + + + + +DRV_Window ClientWindow; +BOOL ExitHandlerActive = FALSE; + +int32 LastError; +char LastErrorStr[200]; + +geBoolean DRIVERCC DrvShutdown(void); +geBoolean DRIVERCC ScreenShot(const char *Name); + +BOOL DRIVERCC DrvInit(DRV_DriverHook *Hook) +{ + RECT WRect; + + // Start up + if (!D3DMain_InitD3D(Hook->hWnd, Hook->DriverName+5, Hook->Width, Hook->Height)) + { + //SetLastDrvError(DRV_ERROR_INIT_ERROR, "D3D_DrvInit: Could not init driver.\n"); + return FALSE; + } + + // If they are asking for a window mode, use there hWnd for the size + if (Hook->Width ==-1 && Hook->Height == -1) + { + GetClientRect(Hook->hWnd, &WRect); + + Hook->Width = (WRect.right - WRect.left); + Hook->Height = (WRect.bottom - WRect.top); + } + + ClientWindow.Width = Hook->Width; + ClientWindow.Height = Hook->Height; + ClientWindow.hWnd = Hook->hWnd; + + return TRUE; +} + +//============================================================================================ +//============================================================================================ +BOOL DRIVERCC DrvShutdown(void) +{ + D3DMain_ShutdownD3D(); + + return TRUE; +} + +//============================================================================================ +// DrvResetAll +//============================================================================================ +geBoolean DRIVERCC DrvResetAll(void) +{ + return D3DMain_Reset(); +} + +geRDriver_PixelFormat PixelFormat[10]; + +#define NUM_PIXEL_FORMATS (sizeof(PixelFormats)/sizeof(geRDriver_PixelFormat)) + +geBoolean DRIVERCC EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context) +{ + int32 i; + gePixelFormat Format3d, Format2d; + uint32 CurrentBpp; + + CurrentBpp = AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Setup the 2d surface format + if (CurrentBpp == 32 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwRGBAlphaBitMask == 0xff000000) + Format2d = GE_PIXELFORMAT_32BIT_ARGB; + else if (CurrentBpp == 32 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwBBitMask == 0xff) + Format2d = GE_PIXELFORMAT_32BIT_XRGB; + else if (CurrentBpp == 24 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwBBitMask == 0xff) + Format2d = GE_PIXELFORMAT_24BIT_RGB; + else if (AppInfo.ddSurfFormat.ddpfPixelFormat.dwGBitMask == (31<<5)) + Format2d = GE_PIXELFORMAT_16BIT_555_RGB; + else + Format2d = GE_PIXELFORMAT_16BIT_565_RGB; + + // Setup the 3d (Texture) format + if (AppInfo.ddTexFormat.ddpfPixelFormat.dwGBitMask == (31<<5)) + Format3d = GE_PIXELFORMAT_16BIT_555_RGB; + else + Format3d = GE_PIXELFORMAT_16BIT_565_RGB; + + + // Create the surface formats now + PixelFormat[0].PixelFormat = Format3d; // 3d 565/555 surface + PixelFormat[0].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + PixelFormat[1].PixelFormat = GE_PIXELFORMAT_16BIT_4444_ARGB; // 3d 4444 surface + PixelFormat[1].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + PixelFormat[2].PixelFormat = Format2d; // 2d 565/555 surface + PixelFormat[2].Flags = RDRIVER_PF_2D | RDRIVER_PF_CAN_DO_COLORKEY; + + PixelFormat[3].PixelFormat = Format3d; // Lightmap 565/555 surface + PixelFormat[3].Flags = RDRIVER_PF_LIGHTMAP; + + PixelFormat[4].PixelFormat = GE_PIXELFORMAT_16BIT_1555_ARGB; + PixelFormat[4].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + // Then hand them off to the caller + for (i=0; i<5; i++) + { + if (!Cb(&PixelFormat[i], Context)) + return GE_TRUE; + } + + return TRUE; +} + +geBoolean DRIVERCC SetGamma(float Gamma) +{ + return GE_TRUE; +} + +geBoolean DRIVERCC GetGamma(float *Gamma) +{ + *Gamma = 1.0f; + + return GE_TRUE; +} + +BOOL DRIVERCC EnumSubDrivers2(DRV_ENUM_DRV_CB *Cb, void *Context); +BOOL DRIVERCC EnumModes2(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context); + +DRV_Driver D3DDRV = +{ + "D3D driver. v"DRV_VMAJS"."DRV_VMINS". Copyright 1999, WildTangent Inc.; All Rights Reserved.", + DRV_VERSION_MAJOR, + DRV_VERSION_MINOR, + + DRV_ERROR_NONE, + NULL, + + EnumSubDrivers2, + EnumModes2, + + EnumPixelFormats, + + DrvInit, + DrvShutdown, + DrvResetAll, + D3DMain_UpdateWindow, + D3DMain_SetActive, + + THandle_Create, + THandle_Destroy, + + THandle_Lock, + THandle_UnLock, + + NULL, // SetPal + NULL, // GetPal + + NULL, // SetAlpha + NULL, // GetAlpha + + THandle_GetInfo, + + BeginScene, + EndScene, + BeginWorld, + EndWorld, + BeginMeshes, + EndMeshes, + BeginModels, + EndModels, + + RenderGouraudPoly, + RenderWorldPoly, + RenderMiscTexturePoly, + + DrawDecal, + + 0,0,0, + + &CacheInfo, + + ScreenShot, + + SetGamma, + GetGamma, + + D3DMain_SetFogEnable, + + NULL, + NULL, // Init to NULL, engine SHOULD set this (SetupLightmap) + NULL +}; + +DRV_EngineSettings EngineSettings; + +DllExport BOOL DriverHook(DRV_Driver **Driver) +{ + + EngineSettings.CanSupportFlags = (DRV_SUPPORT_ALPHA | DRV_SUPPORT_COLORKEY); + EngineSettings.PreferenceFlags = 0;//DRV_PREFERENCE_NO_MIRRORS; + + D3DDRV.EngineSettings = &EngineSettings; + + *Driver = &D3DDRV; + + // Make sure the error string ptr is not null, or invalid!!! + D3DDRV.LastErrorStr = LastErrorStr; + + SetLastDrvError(DRV_ERROR_NONE, "D3DDrv: No error."); + + return TRUE; +} + +void SetLastDrvError(int32 Error, char *ErrorStr) +{ + LastError = Error; + + if (ErrorStr) + { + strcpy(LastErrorStr, ErrorStr); + } + else + LastErrorStr[0] = NULL; + + D3DDRV.LastErrorStr = LastErrorStr; + D3DDRV.LastError = LastError; +} + +//============================================================================================ +// ScreenShot +// +// Credits: Jeff K +//============================================================================================ +BOOL GENESISCC ScreenShot(const char *Name) +{ + DDSURFACEDESC2 ddsd; + BITMAPFILEHEADER bfh; + BITMAPINFOHEADER bih; + HRESULT result; + HDC surfDC = NULL; + HDC memDC = NULL; + HBITMAP bitmap = NULL; + HGDIOBJ oldbit = NULL; + FILE *file = NULL; + void *data= NULL; + int width, height, bpp; + int datasize; + BOOL success = FALSE; + + memset(&ddsd,0,sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + result = AppInfo.lpBackBuffer->GetSurfaceDesc(&ddsd); + + if (FAILED(result)) + goto cleanup; + + width = ddsd.dwWidth; + height= ddsd.dwHeight; + bpp = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + + if (bpp < 2) + bpp = 2; + + if (bpp > 3) + bpp = 3; + + datasize = width * bpp * height; + + if (width * bpp % 4) + datasize += height * (4 - width * bpp % 4); + + memset((void*)&bfh, 0, sizeof(bfh)); + + bfh.bfType = 'B'+('M'<<8); + bfh.bfSize = sizeof(bfh) + sizeof(bih) + datasize; + bfh.bfOffBits = sizeof(bfh) + sizeof(bih); + + memset((void*)&bih, 0, sizeof(bih)); + + bih.biSize = sizeof(bih); + bih.biWidth = ddsd.dwWidth; + bih.biHeight = ddsd.dwHeight; + bih.biPlanes = 1; + bih.biBitCount = (unsigned short)(bpp * 8); + bih.biCompression = BI_RGB; + + result = AppInfo.lpBackBuffer->GetDC(&surfDC); + + if (FAILED(result)) + goto cleanup; + + bitmap = CreateDIBSection(NULL, (BITMAPINFO *)&bih, DIB_RGB_COLORS, &data, NULL, 0); + + if (!bitmap) + goto cleanup; + + if (!data) + goto cleanup; + + memDC = CreateCompatibleDC(surfDC); + + if (!memDC) + goto cleanup; + + oldbit = SelectObject(memDC, bitmap); + + if (!oldbit || FAILED(oldbit)) + goto cleanup; + + result = BitBlt(memDC, 0, 0, width, height, surfDC, 0, 0, SRCCOPY); + + if (!result) + goto cleanup; + + AppInfo.lpBackBuffer->ReleaseDC(surfDC); + surfDC = NULL; + file = fopen(Name, "wb"); + + if (!file) + goto cleanup; + + fwrite((void*)&bfh, sizeof(bfh), 1, file); + fwrite((void*)&bih, sizeof(bih), 1, file); + fwrite((void*)data, 1, datasize, file); + + success = TRUE; + +cleanup: + + if (oldbit && !FAILED(oldbit)) + SelectObject(memDC, oldbit); + + if (memDC) + DeleteDC(memDC); + + if (surfDC) + AppInfo.lpBackBuffer->ReleaseDC(surfDC); + + if (bitmap) + DeleteObject(bitmap); + + if (file) + fclose(file); + + return success; +} + + diff --git a/G3D/Engine/Drivers/D3D8Drv/DDMemMgr.cpp b/G3D/Engine/Drivers/D3D8Drv/DDMemMgr.cpp new file mode 100644 index 0000000..97b5b03 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/DDMemMgr.cpp @@ -0,0 +1,174 @@ +/****************************************************************************************/ +/* DDMemMgr.c */ +/* */ +/* Author: John Pollard */ +/* Description: Mini D3D memory manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "BaseType.h" +#include "DDMemMgr.h" + + + + + + + + + + +#define DDMEMMGR_MAX_PARTITIONS 16 + +typedef struct DDMemMgr_Partition +{ + geBoolean Active; + uint32 FreeMem; + uint32 TotalMem; + +} DDMemMgr_Partition; + +typedef struct DDMemMgr +{ + uint32 TotalMem; + uint32 FreeMem; + DDMemMgr_Partition Partitions[DDMEMMGR_MAX_PARTITIONS]; +} DDMemMgr; + +//============================================================================ +// DDMemMgr_Create +//============================================================================ +DDMemMgr *DDMemMgr_Create(uint32 Size) +{ + DDMemMgr *MemMgr; + + MemMgr = (DDMemMgr*)malloc(sizeof(DDMemMgr)); + + if (!MemMgr) + return NULL; + + memset(MemMgr, 0, sizeof(DDMemMgr)); + + MemMgr->TotalMem = Size; + MemMgr->FreeMem = Size; + + return MemMgr; +} + +//============================================================================ +// DDMemMgr_Destroy +//============================================================================ +void DDMemMgr_Destroy(DDMemMgr *MemMgr) +{ + free(MemMgr); +} + +//============================================================================ +// DDMemMgr_Reset +//============================================================================ +void DDMemMgr_Reset(DDMemMgr *MemMgr) +{ + int32 i; + + MemMgr->FreeMem = MemMgr->TotalMem; + + for (i=0; iPartitions[i], 0, sizeof(DDMemMgr_Partition)); +} + +//============================================================================ +// DDMemMgr_GetFreeMem +//============================================================================ +uint32 DDMemMgr_GetFreeMem(DDMemMgr *MemMgr) +{ + return MemMgr->FreeMem; +} + +//============================================================================ +// DDMemMgr_PartitionCreate +//============================================================================ +DDMemMgr_Partition *DDMemMgr_PartitionCreate(DDMemMgr *MemMgr, uint32 Size) +{ + int32 i; + DDMemMgr_Partition *pPartition; + + if (Size > MemMgr->FreeMem) + return NULL; + + pPartition = MemMgr->Partitions; + + for (i=0; i< DDMEMMGR_MAX_PARTITIONS; i++, pPartition++) + { + if (!pPartition->Active) + { + pPartition->TotalMem = Size; + pPartition->FreeMem = Size; + pPartition->Active = GE_TRUE; + MemMgr->FreeMem -= Size; + + return pPartition; + } + } + + return NULL; +} + +//============================================================================ +// DDMemMgr_PartitionDestroy +//============================================================================ +void DDMemMgr_PartitionDestroy(DDMemMgr_Partition *Partition) +{ + memset(Partition, 0, sizeof(DDMemMgr_Partition)); +} + +//============================================================================ +// DDMemMgr_PartitionReset +//============================================================================ +void DDMemMgr_PartitionReset(DDMemMgr_Partition *Partition) +{ + Partition->FreeMem = Partition->TotalMem; +} + +//============================================================================ +// DDMemMgr_PArtitionGetTotalMem +//============================================================================ +uint32 DDMemMgr_PartitionGetTotalMem(DDMemMgr_Partition *Partition) +{ + return Partition->TotalMem; +} + +//============================================================================ +// DDMemMgr_PArtitionGetFreeMem +//============================================================================ +uint32 DDMemMgr_PartitionGetFreeMem(DDMemMgr_Partition *Partition) +{ + return Partition->FreeMem; +} + +//============================================================================ +// DDMemMgr_PartitionAllocMem +//============================================================================ +geBoolean DDMemMgr_PartitionAllocMem(DDMemMgr_Partition *Partition, uint32 Size) +{ + if (Partition->FreeMem < Size) + return GE_FALSE; + + Partition->FreeMem -= Size; + + return GE_TRUE; +} diff --git a/G3D/Engine/Drivers/D3D8Drv/DDMemMgr.h b/G3D/Engine/Drivers/D3D8Drv/DDMemMgr.h new file mode 100644 index 0000000..46c94c3 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/DDMemMgr.h @@ -0,0 +1,44 @@ +/****************************************************************************************/ +/* DDMemMgr.h */ +/* */ +/* Author: John Pollard */ +/* Description: Mini D3D memory manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DDMEMMGR_H +#define DDMEMMGR_H + +#include + +#include "BaseType.h" + + +typedef struct DDMemMgr DDMemMgr; +typedef struct DDMemMgr_Partition DDMemMgr_Partition; + +DDMemMgr *DDMemMgr_Create(uint32 Size); +void DDMemMgr_Destroy(DDMemMgr *MemMgr); +void DDMemMgr_Reset(DDMemMgr *MemMgr); +uint32 DDMemMgr_GetFreeMem(DDMemMgr *MemMgr); +DDMemMgr_Partition *DDMemMgr_PartitionCreate(DDMemMgr *MemMgr, uint32 Size); +void DDMemMgr_PartitionDestroy(DDMemMgr_Partition *Partition); +void DDMemMgr_PartitionReset(DDMemMgr_Partition *Partition); +uint32 DDMemMgr_PartitionGetTotalMem(DDMemMgr_Partition *Partition); +uint32 DDMemMgr_PartitionGetFreeMem(DDMemMgr_Partition *Partition); +geBoolean DDMemMgr_PartitionAllocMem(DDMemMgr_Partition *Partition, uint32 Size); + +#endif diff --git a/G3D/Engine/Drivers/D3D8Drv/GSPAN.CPP b/G3D/Engine/Drivers/D3D8Drv/GSPAN.CPP new file mode 100644 index 0000000..40c65fc --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/GSPAN.CPP @@ -0,0 +1,279 @@ +/****************************************************************************************/ +/* GSpan.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Front to back span code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "D3DDrv.h" +#include "GSpan.h" + + + + + + + +SPAN SpanLines[MAX_SPAN_LINES]; + +SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +SLIST ScanHash[MAX_SPANS]; // hash table for SList + +BOOL PolyVisible = FALSE; + +int32 NumWorldPixels = 0; +int32 NumSpans = 0; +int32 NumSpanPixels[MAX_SPAN_LINES]; +int32 PolysRendered = 0; + +int32 CurrentSList = 0; + +const int32 CEIL_FRACT = ( ( 1 << 16)-1); +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2) +{ + int32 Ctmp; + int32 y; + int32 x,m; + + int32 ydelta; + int32 Dir; + int32 Cx1, Cx2, Cy1, Cy2; + SPAN *pSpans; + + Cx1 = x1; + Cx2 = x2; + Cy1 = y1; + Cy2 = y2; + + if (Cy2 != Cy1) // This isn't a horizontal line + { + Dir =0; // Left side + + if (Cy2 < Cy1) // Make sure y2 is greater than y1 + { + Dir =1; // Right side + + Ctmp = Cx1; + Cx1 = Cx2; + Cx2 = Ctmp; + + Ctmp = Cy1; + Cy1 = Cy2; + Cy2 = Ctmp; + + } + + ydelta = (Cy2 - Cy1); + + x = (Cx1 << 16) + CEIL_FRACT; // Allign on int amounts + m = (((Cx2 - Cx1))<<16) / ydelta; // How much to increase x each iteration + + pSpans = &SpanLines[Cy1]; + + if (!Dir) + { + for (y = Cy1; y <= Cy2; y++, pSpans++) + { + pSpans->x1 = (x>>16); + x += m; // Add our constant to x + } + } + else + { + for (y = Cy1; y <= Cy2; y++, pSpans++) + { + pSpans->x2 = (x>>16); + x += m; // Add our constant to x + } + } + } +} + +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y) +{ + int32 i, xx2; + SLIST *LineStart; + SLIST *Current; + SPAN_MINMAX *pSList; + + if (NumSpanPixels[y] >= ClientWindow.Width) + return; + + if (x1 > x2) // Swap all the coordinates so x1 < x2 + { + i = x1; + x1 = x2; + x2 = i; + } + + Current = SMinMax[y].First; + + LineStart = NULL; + + pSList = &SMinMax[y]; + + // Check to see if there are spans + // in the list yet... + if (!pSList->First) + { + pSList->First = NewSList(); + pSList->First->Last = NULL; + pSList->First->Next = NULL; + pSList->First->Min = x1; + pSList->First->Max = x2; + } + else while (Current != NULL) + { + if (x1 >= Current->Min && x2 <= Current->Max) + return; // This line totally hidden... + + //if falls before the entire min, max + if (LineStart == NULL) + { + if (Current == pSList->First) + if (x2 < Current->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current; + NewMinMax->Last = NULL; + Current->Last = NewMinMax; + pSList->First = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if falls in the middle (but not touching) + if (Current->Next != NULL) + if (x1 > Current->Max && x2 < (Current->Next)->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current->Next; + NewMinMax->Last = Current; + Current->Next->Last = NewMinMax; + Current->Next = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if it falls to the right of all spans + if (Current->Next == NULL) + if (x1 > Current->Max) + { + SLIST *NewMinMax = NewSList(); + Current->Next = NewMinMax; + NewMinMax->Next = NULL; + NewMinMax->Last = Current; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + } + //if we have already started crossing spans, and we find out + // that we are in front of a span, then we can bail out... + if (LineStart != NULL) + if (x2 < Current->Min) + goto WasNull; + + + // We now know that we have not fallen into any empty holes. + // We must now check to see what spans, we've crossed... + + // if split by a min/max + if (x1 < Current->Min && x2 > Current->Max) + { + xx2 = Current->Min-1; + Current->Min = x1; + + NumWorldPixels += xx2 - x1 + 1; + NumSpanPixels[y] += xx2 - x1 + 1; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + x1 = Current->Max+1; + Current->Max = x2; + if (LineStart!=NULL) + LineStart->Max = x2; + else + LineStart = Current; + goto next; + } + + if (x1 <= Current->Max && x2 > Current->Max) + { + x1 = Current->Max+1; + Current->Max = x2; + LineStart = Current; + goto next; + } + if (x1 < Current->Min && x2 >= Current->Min) + { + x2 = Current->Min-1; + Current->Min = x1; + if (LineStart!=NULL) + LineStart->Max = Current->Max; + goto WasNull; + } + next:; + Current = Current->Next; + } + WasNull:; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + NumWorldPixels += x2 - x1 + 1; + NumSpanPixels[y] += x2 - x1 + 1; +} + +void ResetSList(void) +{ + CurrentSList = 0; + NumSpans = 0; +} + +SLIST *NewSList(void) +{ + + CurrentSList++; + NumSpans++; + + return &ScanHash[CurrentSList-1]; + + return NULL; +} + +void ResetSpans(int32 Rows) +{ + int32 i; + + for (i=0; i + +#define MAX_SPAN_LINES 1024 +#define MAX_SPANS 35000 + +typedef struct +{ + int32 x1; // Starting x on screen + int32 x2; // Ending x on screen +} SPAN; + +typedef struct _SList +{ + int32 Min, Max; + uint8 Used; + uint32 Flags; + _SList *Last; + _SList *Next; +} SLIST; + +typedef struct +{ + SLIST *First; + SLIST *Current; +} SPAN_MINMAX; + +extern SPAN SpanLines[MAX_SPAN_LINES]; + +extern SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +extern SLIST ScanHash[MAX_SPANS]; // hash table for SList + +extern int32 NumWorldPixels; +extern int32 NumSpans; +extern int32 NumSpanPixels[MAX_SPAN_LINES]; +extern int32 PolysRendered; + +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2); +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y); + +void ResetSList(void); +SLIST *NewSList(void); +void ResetSpans(int32 Rows); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D8Drv/Pcache.cpp b/G3D/Engine/Drivers/D3D8Drv/Pcache.cpp new file mode 100644 index 0000000..f78b704 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/Pcache.cpp @@ -0,0 +1,1273 @@ +/****************************************************************************************/ +/* PCache.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D poly cache */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DCache.h" +#include "D3D_Fx.h" + +#include "PCache.h" +#include "D3DDrv.h" +#include "THandle.h" +#include "D3D_Err.h" + + + + + + + +//==================================================================================== +// Local static variables +//==================================================================================== + +DRV_CacheInfo CacheInfo; + +// +// World Cache +// + + +#define MAX_WORLD_POLYS 256 +#define MAX_WORLD_POLY_VERTS 1024 + +#define MAX_MISC_POLYS 256 +#define MAX_MISC_POLY_VERTS 1024 + + +typedef struct +{ + float u; + float v; + uint32 Color; +} PCache_TVert; + +typedef struct +{ + geRDriver_THandle *THandle; + + DRV_LInfo *LInfo; // Original pointer to linfo + uint32 Flags; // Flags for this poly + float ShiftU; + float ShiftV; + float ScaleU; + float ScaleV; + int32 MipLevel; + uint32 SortKey; + int32 FirstVert; + int32 NumVerts; +} World_Poly; + +#define MAX_TEXTURE_STAGES 2 // Up to 2 tmu's (stages) + +// Verts we defined in the D3D flexible vertex format (FVF) +// This is a transformed and lit vertex definition, with up to 8 sets of uvs +typedef struct +{ + float u,v; +} PCache_UVSet; + +typedef struct +{ + float x,y,z; // Screen x, y, z + float rhw; // homogenous w + DWORD color; // color + DWORD specular; + PCache_UVSet uv[MAX_TEXTURE_STAGES]; // uv sets for each stage +} PCache_Vert; + +typedef struct +{ + World_Poly Polys[MAX_WORLD_POLYS]; + World_Poly *SortedPolys[MAX_WORLD_POLYS]; + World_Poly *SortedPolys2[MAX_WORLD_POLYS]; + PCache_Vert Verts[MAX_WORLD_POLY_VERTS]; + + PCache_TVert TVerts[MAX_WORLD_POLY_VERTS]; // Original uv + + int32 NumPolys; + int32 NumPolys2; + int32 NumVerts; +} World_Cache; + +static World_Cache WorldCache; + +#define PREP_WORLD_VERTS_NORMAL 1 // Prep verts as normal +#define PREP_WORLD_VERTS_LMAP 2 // Prep verts as lightmaps +#define PREP_WORLD_VERTS_SINGLE_PASS 3 // Prep verts for a single pass + +#define RENDER_WORLD_POLYS_NORMAL 1 // Render polys as normal +#define RENDER_WORLD_POLYS_LMAP 2 // Render polys as lightmaps +#define RENDER_WORLD_POLYS_SINGLE_PASS 3 + +// +// Misc cache +// + +typedef struct +{ + geRDriver_THandle *THandle; + uint32 Flags; // Flags for this poly + int32 MipLevel; + int32 FirstVert; + int32 NumVerts; + + uint32 SortKey; +} Misc_Poly; + +typedef struct +{ + Misc_Poly Polys[MAX_MISC_POLYS]; + Misc_Poly *SortedPolys[MAX_MISC_POLYS]; + PCache_Vert Verts[MAX_MISC_POLY_VERTS]; + //float ZVert[MAX_MISC_POLY_VERTS]; + + int32 NumPolys; + int32 NumVerts; +} Misc_Cache; + +static Misc_Cache MiscCache; + +//==================================================================================== +// Local static functions prototypes +//==================================================================================== +geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2); + +static BOOL RenderWorldPolys(int32 RenderMode); +static BOOL ClearWorldCache(void); +static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, float ScaleU, float ScaleV, int32 MaxMipLevel); + +#include + +//==================================================================================== +// PCache_InsertWorldPoly +//==================================================================================== +BOOL PCache_InsertWorldPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ + int32 Mip; + float ZRecip, DrawScaleU, DrawScaleV; + World_Poly *pCachePoly; + DRV_TLVertex *pVerts; + PCache_TVert *pTVerts; + PCache_Vert *pD3DVerts; + int32 i; + uint32 Alpha; + + + if ((WorldCache.NumVerts + NumVerts) >= MAX_WORLD_POLY_VERTS) + { + // If the cache is full, we must flush it before going on... + if (!PCache_FlushWorldPolys()) + return GE_FALSE; + } + else if (WorldCache.NumPolys+1 >= MAX_WORLD_POLYS) + { + // If the cache is full, we must flush it before going on... + if (!PCache_FlushWorldPolys()) + return GE_FALSE; + } + + DrawScaleU = 1.0f / TexInfo->DrawScaleU; + DrawScaleV = 1.0f / TexInfo->DrawScaleV; + + Mip = GetMipLevel(Verts, NumVerts, DrawScaleU, DrawScaleV, THandle->NumMipLevels-1); + + // Get a pointer to the original polys verts + pVerts = Verts; + + // Store info about this poly in the cache + pCachePoly = &WorldCache.Polys[WorldCache.NumPolys]; + + pCachePoly->THandle = THandle; + pCachePoly->LInfo = LInfo; + pCachePoly->Flags = Flags; + pCachePoly->FirstVert = WorldCache.NumVerts; + pCachePoly->NumVerts = NumVerts; + pCachePoly->ShiftU = TexInfo->ShiftU; + pCachePoly->ShiftV = TexInfo->ShiftV; + pCachePoly->ScaleU = DrawScaleU; + pCachePoly->ScaleV = DrawScaleV; + pCachePoly->MipLevel = Mip; + + // Don't forget the sort key: + pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip; + + // Get a pointer into the world verts + pD3DVerts = &WorldCache.Verts[WorldCache.NumVerts]; + pTVerts = &WorldCache.TVerts[WorldCache.NumVerts]; + + if (Flags & DRV_RENDER_ALPHA) + Alpha = (uint32)pVerts->a<<24; + else + Alpha = (uint32)(255<<24); + + for (i=0; i< NumVerts; i++) + { + ZRecip = 1.0f/(pVerts->z); + + pD3DVerts->x = pVerts->x; + pD3DVerts->y = pVerts->y; + + pD3DVerts->z = (1.0f - ZRecip); // ZBUFFER + pD3DVerts->rhw = ZRecip; + + if (AppInfo.FogEnable && !(Flags & DRV_RENDER_POLY_NO_FOG)) // poly fog + { + DWORD FogVal; + float Val; + + Val = pVerts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DVerts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DVerts->specular = 0; + + // Store the uv's so the prep pass can use them... + pTVerts->u = pVerts->u; + pTVerts->v = pVerts->v; + + pTVerts->Color = Alpha | ((uint32)pVerts->r<<16) | ((uint32)pVerts->g<<8) | (uint32)pVerts->b; + + pTVerts++; + pVerts++; + pD3DVerts++; + + } + + // Update globals about the world poly cache + WorldCache.NumVerts += NumVerts; + WorldCache.NumPolys++; + + return TRUE; +} + +//==================================================================================== +// PCache_FlushWorldPolys +//==================================================================================== +BOOL PCache_FlushWorldPolys(void) +{ + if (!WorldCache.NumPolys) + return TRUE; + + if (!THandle_CheckCache()) + return GE_FALSE; + + if (AppInfo.CanDoMultiTexture) + { + RenderWorldPolys(RENDER_WORLD_POLYS_SINGLE_PASS); + } + else + { + // Render them as normal + if (!RenderWorldPolys(RENDER_WORLD_POLYS_NORMAL)) + return GE_FALSE; + + // Render them as lmaps + RenderWorldPolys(RENDER_WORLD_POLYS_LMAP); + } + + ClearWorldCache(); + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +static int MiscBitmapHandleComp(const void *a, const void *b) +{ + uint32 Id1, Id2; + + Id1 = (uint32)(*(Misc_Poly**)a)->SortKey; + Id2 = (uint32)(*(Misc_Poly**)b)->SortKey; + + if ( Id1 == Id2) + return 0; + + if (Id1 < Id2) + return -1; + + return 1; +} + +//==================================================================================== +//==================================================================================== +static void SortMiscPolysByHandle(void) +{ + Misc_Poly *pPoly; + int32 i; + + pPoly = MiscCache.Polys; + + for (i=0; iTHandle; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + Size = 1<Log; + + Lut = &AppInfo.Lut1; + + THandle_Lock(THandle, 0, (void**)&pTempBits); + + Extra = Size - Width; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + U8 R, G, B; + U16 Color; + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + THandle_UnLock(THandle, 0); +} + + +//===================================================================================== +// LoadLMapFromSystem +//===================================================================================== +static void LoadLMapFromSystem(DRV_LInfo *LInfo, int32 Log, int32 LNum) +{ + U16 *pTempBits; + int32 w, h, Width, Height, Size, Extra; + U8 *pBitPtr; + LPDIRECTDRAWSURFACE4 Surface; + RGB_LUT *Lut; + DDSURFACEDESC2 ddsd; + HRESULT ddrval; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + Size = 1<Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + + pTempBits = (USHORT*)ddsd.lpSurface; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + U8 R, G, B; + U16 Color; + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + ddrval = Surface->Unlock(NULL); +} + +static BOOL IsKeyDown(int KeyCode) +{ + if (GetAsyncKeyState(KeyCode) & 0x8000) + return TRUE; + + return FALSE; +} + +extern uint32 CurrentLRU; + +//===================================================================================== +// SetupMipData +//===================================================================================== +geBoolean SetupMipData(THandle_MipData *MipData) +{ + if (!MipData->Slot || D3DCache_SlotGetUserData(MipData->Slot) != MipData) + { + MipData->Slot = D3DCache_TypeFindSlot(MipData->CacheType); + + D3DCache_SlotSetUserData(MipData->Slot, MipData); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// SetupLMap +//===================================================================================== +geBoolean SetupLMap(int32 Stage, DRV_LInfo *LInfo, int32 LNum, geBoolean Dynamic) +{ + geRDriver_THandle *THandle; + THandle_MipData *MipData; + + THandle = LInfo->THandle; + MipData = &THandle->MipData[0]; + + if (Dynamic) + MipData->Flags |= THANDLE_UPDATE; + + if (!SetupMipData(MipData)) + { + MipData->Flags |= THANDLE_UPDATE; // Force an upload + CacheInfo.LMapMisses++; + } + + if (MipData->Flags & THANDLE_UPDATE) + { + HRESULT Error; + LPDIRECTDRAWSURFACE4 Surface; + + Surface = D3DCache_SlotGetSurface(MipData->Slot); + + LoadLMapFromSystem(LInfo, THandle->Log, LNum); + + Error = Surface->BltFast(0, 0, SystemToVideo[THandle->Log].Surface, NULL, DDBLTFAST_WAIT); + + if (Error != DD_OK) + { + if(Error==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return GE_FALSE; + } + else + { + D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error)); + return GE_FALSE; + } + } + } + + if (Dynamic) // If it was dynmamic, force an update for one more frame + MipData->Flags |= THANDLE_UPDATE; + else + MipData->Flags &= ~THANDLE_UPDATE; + + D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU); + D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot)); + + return GE_TRUE; +} + +//===================================================================================== +// SetupTexture +//===================================================================================== +geBoolean SetupTexture(int32 Stage, geRDriver_THandle *THandle, int32 MipLevel) +{ + THandle_MipData *MipData; + + MipData = &THandle->MipData[MipLevel]; + + if (!SetupMipData(MipData)) + { + MipData->Flags |= THANDLE_UPDATE; // Force an upload + CacheInfo.TexMisses++; + } + + if (MipData->Flags & THANDLE_UPDATE) + { + HRESULT Error; + LPDIRECTDRAWSURFACE4 Surface; + + Surface = D3DCache_SlotGetSurface(MipData->Slot); + + Error = Surface->BltFast(0, 0, MipData->Surface, NULL, DDBLTFAST_WAIT); + + if (Error != DD_OK) + { + if(Error==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return FALSE; + } + else + { + D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error)); + return GE_FALSE; + } + } + } + + MipData->Flags &= ~THANDLE_UPDATE; + + D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU); + D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot)); + + return GE_TRUE; +} + +//==================================================================================== +// PCache_FlushMiscPolys +//==================================================================================== +BOOL PCache_FlushMiscPolys(void) +{ + int32 i; + Misc_Poly *pPoly; + + if (!MiscCache.NumPolys) + return TRUE; + + if (!THandle_CheckCache()) + return GE_FALSE; + + // Set the render states + if (AppInfo.CanDoMultiTexture) + { + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + D3DSetTexture(1, NULL); // Reset texture stage 1 + } + + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); + + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + D3DBlendEnable(TRUE); + + // Sort the polys by handle + SortMiscPolysByHandle(); + + for (i=0; i< MiscCache.NumPolys; i++) + { + pPoly = MiscCache.SortedPolys[i]; + + if (pPoly->Flags & DRV_RENDER_NO_ZMASK) // We are assuming that this is not going to change all that much + D3DZEnable(FALSE); + else + D3DZEnable(TRUE); + + if (pPoly->Flags & DRV_RENDER_NO_ZWRITE) // We are assuming that this is not going to change all that much + D3DZWriteEnable(FALSE); + else + D3DZWriteEnable(TRUE); + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(0, FALSE); + else + D3DTexWrap(0, TRUE); + + if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + + D3DTexturedPoly(&MiscCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + + // Turn z stuff back on... + D3DZWriteEnable (TRUE); + D3DZEnable(TRUE); + + MiscCache.NumPolys = 0; + MiscCache.NumVerts = 0; + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + + return TRUE; +} + +//==================================================================================== +// PCache_InsertMiscPoly +//==================================================================================== +BOOL PCache_InsertMiscPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, uint32 Flags) +{ + int32 Mip; + float ZRecip, u, v, ScaleU, ScaleV, InvScale; + Misc_Poly *pCachePoly; + DRV_TLVertex *pVerts; + PCache_Vert *pD3DVerts; + int32 i, SAlpha; + + if ((MiscCache.NumVerts + NumVerts) >= MAX_MISC_POLY_VERTS) + { + // If the cache is full, we must flush it before going on... + PCache_FlushMiscPolys(); + } + else if (MiscCache.NumPolys+1 >= MAX_MISC_POLYS) + { + // If the cache is full, we must flush it before going on... + PCache_FlushMiscPolys(); + } + + Mip = GetMipLevel(Verts, NumVerts, (float)THandle->Width, (float)THandle->Height, THandle->NumMipLevels-1); + + // Store info about this poly in the cache + pCachePoly = &MiscCache.Polys[MiscCache.NumPolys]; + + pCachePoly->THandle = THandle; + pCachePoly->Flags = Flags; + pCachePoly->FirstVert = MiscCache.NumVerts; + pCachePoly->NumVerts = NumVerts; + pCachePoly->MipLevel = Mip; + pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip; + + // Get scale value for vertices + //TCache_GetUVInvScale(Bitmap, Mip, &InvScale); + InvScale = 1.0f / (float)((1<Log)); + + // Convert them to take account that the vertices are allready from 0 to 1 + ScaleU = (float)THandle->Width * InvScale; + ScaleV = (float)THandle->Height * InvScale; + + // Precompute the alpha value... + SAlpha = ((int32)Verts->a)<<24; + + // Get a pointer to the original polys verts + pVerts = Verts; + // Get a pointer into the world verts + pD3DVerts = &MiscCache.Verts[MiscCache.NumVerts]; + + for (i=0; i< NumVerts; i++) + { + ZRecip = 1/(pVerts->z); + + pD3DVerts->x = pVerts->x; + pD3DVerts->y = pVerts->y; + + pD3DVerts->z = (1.0f - ZRecip); // ZBUFFER + pD3DVerts->rhw = ZRecip; + + u = pVerts->u * ScaleU; + v = pVerts->v * ScaleV; + + pD3DVerts->uv[0].u = u; + pD3DVerts->uv[0].v = v; + + pD3DVerts->color = SAlpha | ((int32)pVerts->r<<16) | ((int32)pVerts->g<<8) | (int32)pVerts->b; + + if (AppInfo.FogEnable && !(Flags & DRV_RENDER_POLY_NO_FOG) ) // poly fog + { + DWORD FogVal; + float Val; + + Val = pVerts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DVerts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DVerts->specular = 0; + + pVerts++; + pD3DVerts++; + } + + // Update globals about the misc poly cache + MiscCache.NumVerts += NumVerts; + MiscCache.NumPolys++; + + return TRUE; +} + +//==================================================================================== +// **** LOCAL STATIC FUNCTIONS ***** +//==================================================================================== + +//==================================================================================== +// World_PolyPrepVerts +//==================================================================================== +geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2) +{ + float InvScale, u, v; + PCache_TVert *pTVerts; + PCache_Vert *pVerts; + float ShiftU, ShiftV, ScaleU, ScaleV; + int32 j; + + switch (PrepMode) + { + case PREP_WORLD_VERTS_NORMAL: + { + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + + ShiftU = pPoly->ShiftU; + ShiftV = pPoly->ShiftV; + ScaleU = pPoly->ScaleU; + ScaleV = pPoly->ScaleV; + + // Get scale value for vertices + InvScale = 1.0f / (float)((1<THandle->Log)); + + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u*ScaleU+ShiftU; + v = pTVerts->v*ScaleV+ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + pVerts->color = pTVerts->Color; + + pTVerts++; + pVerts++; + } + + break; + } + + case PREP_WORLD_VERTS_LMAP: + { + if (!pPoly->LInfo) + return GE_TRUE; + + ShiftU = (float)-pPoly->LInfo->MinU + 8.0f; + ShiftV = (float)-pPoly->LInfo->MinV + 8.0f; + + // Get scale value for vertices + InvScale = 1.0f/(float)((1<LInfo->THandle->Log)<<4); + + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u + ShiftU; + v = pTVerts->v + ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + pVerts->color = 0xffffffff; + + pTVerts++; + pVerts++; + } + break; + } + + case PREP_WORLD_VERTS_SINGLE_PASS: + { + float InvScale2, ShiftU2, ShiftV2; + + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + + // Set up shifts and scaled for texture uv's + ShiftU = pPoly->ShiftU; + ShiftV = pPoly->ShiftV; + ScaleU = pPoly->ScaleU; + ScaleV = pPoly->ScaleV; + + // Get scale value for vertices + InvScale = 1.0f / (float)((1<THandle->Log)); + + // Set up shifts and scaled for lightmap uv's + ShiftU2 = (float)-pPoly->LInfo->MinU + 8.0f; + ShiftV2 = (float)-pPoly->LInfo->MinV + 8.0f; + InvScale2 = 1.0f/(float)((1<LInfo->THandle->Log)<<4); + + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u*ScaleU+ShiftU; + v = pTVerts->v*ScaleV+ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + u = pTVerts->u + ShiftU2; + v = pTVerts->v + ShiftV2; + + pVerts->uv[Stage2].u = u * InvScale2; + pVerts->uv[Stage2].v = v * InvScale2; + + pVerts->color = pTVerts->Color; + + pTVerts++; + pVerts++; + } + + break; + } + + default: + return FALSE; + } + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +static int BitmapHandleComp(const void *a, const void *b) +{ + int32 Id1, Id2; + + Id1 = (*(World_Poly**)a)->SortKey; + Id2 = (*(World_Poly**)b)->SortKey; + + if ( Id1 == Id2) + return 0; + + if (Id1 < Id2) + return -1; + + return 1; +} + +//==================================================================================== +//==================================================================================== +static void SortWorldPolysByHandle(void) +{ + World_Poly *pPoly; + int32 i; + + pPoly = WorldCache.Polys; + + for (i=0; iSetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); + + // Set the default state for the normal poly render mode for the world + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + // Get the first poly in the sorted list + SortWorldPolysByHandle(); + + for (i=0; i< WorldCache.NumPolys; i++) + { + pPoly = WorldCache.SortedPolys[i]; + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(0, FALSE); + else + D3DTexWrap(0, TRUE); + + if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, 0, 0); + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + } + + break; + } + + case RENDER_WORLD_POLYS_LMAP: + { + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); + + D3DTexWrap(0, FALSE); + + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO); + + pPoly = WorldCache.Polys; + + for (i=0; i< WorldCache.NumPolys; i++, pPoly++) + { + BOOL Dynamic = 0; + + if (!pPoly->LInfo) + continue; + + // Call the engine to set this sucker up, because it's visible... + D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic); + + if (!SetupLMap(0, pPoly->LInfo, 0, Dynamic)) + return GE_FALSE; + + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_LMAP, 0, 0); + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if (pPoly->LInfo->RGBLight[1]) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE); + + D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE); // Change to a fog state + + // For some reason, some cards can't upload data to the same texture twice, and have it take. + // So we force Fog maps to use a different slot than the lightmap was using... + pPoly->LInfo->THandle->MipData[0].Slot = NULL; + + if (!SetupLMap(0, pPoly->LInfo, 1, 1)) // Dynamic is 1, because fog is always dynamic + return GE_FALSE; + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO); // Restore state + + if (AppInfo.FogEnable) + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + } + break; + } + + case RENDER_WORLD_POLYS_SINGLE_PASS: + { + // Setup texture stage states + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT ); + //AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + + // Setup frame buffer blend modes + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + // Set the default state for the normal poly render mode for the world + D3DTexWrap(TSTAGE_0, TRUE); + D3DTexWrap(TSTAGE_1, FALSE); + + // Sort the list for front back operation to get the least number of world texture misses + SortWorldPolysByHandle(); + + // Reset non lightmaps faces to 0 + WorldCache.NumPolys2 = 0; + + for (i=0; i< WorldCache.NumPolys; i++) + { + BOOL Dynamic = 0; + + pPoly = WorldCache.SortedPolys[i]; + + if (!pPoly->LInfo) + { + // Put gouraud only polys in a seperate list, and render last + WorldCache.SortedPolys2[WorldCache.NumPolys2++] = pPoly; + continue; + } + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(TSTAGE_0, FALSE); + else + D3DTexWrap(TSTAGE_0, TRUE); + + if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + // Call the engine to set this sucker up, because it's visible... + D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic); + + if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 0, Dynamic)) + return GE_FALSE; + + // Prep the verts for a lightmap and texture map + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_SINGLE_PASS, TSTAGE_0, TSTAGE_1); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + + // Draw the texture + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + + // Render any fog maps + if (pPoly->LInfo->RGBLight[1]) + { + D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE); // Change to a fog state + + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + #endif + + // For some reason, some cards can't upload data to the same texture twice, and have it take. + // So we force Fog maps to use a different slot other than what the lightmap was using... + pPoly->LInfo->THandle->MipData[0].Slot = NULL; + + if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 1, 1)) // Dynamic is 1, because fog is always dynamic + return GE_FALSE; + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + // Restore states to the last state before fag map + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + #endif + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + } + + + } + + // Setup for any non-lightmaped faces faces, turn tmu1 off + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + #endif + + // Render all the faces without lightmaps + for (i=0; i< WorldCache.NumPolys2; i++) + { + BOOL Dynamic = 0; + + pPoly = WorldCache.SortedPolys2[i]; + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(TSTAGE_0, FALSE); + else + D3DTexWrap(TSTAGE_0, TRUE); + + if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + // Prep verts as if there was no lightmap + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, TSTAGE_0, TSTAGE_1); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + + // Draw the texture + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + + break; + } + + default: + return FALSE; + } + + + return TRUE; +} + +//==================================================================================== +// ClearWorldCache +//==================================================================================== +static BOOL ClearWorldCache(void) +{ + WorldCache.NumPolys = 0; + WorldCache.NumVerts = 0; + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +BOOL PCache_Reset(void) +{ + WorldCache.NumPolys = 0; + WorldCache.NumVerts = 0; + + MiscCache.NumPolys = 0; + MiscCache.NumVerts = 0; + + return TRUE; +} + +//==================================================================================== +// GetMipLevel +//==================================================================================== +static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, float ScaleU, float ScaleV, int32 MaxMipLevel) +{ + int32 Mip; + + if (MaxMipLevel == 0) + return 0; + + // + // Get the MipLevel + // + { + float du, dv, dx, dy, MipScale; + + int32 i; + + MipScale = 999999.0f; + + for (i=0; i< NumVerts; i++) + { + float MipScaleT; + DRV_TLVertex *pVert0, *pVert1; + int32 i2; + + i2 = i+1; + + if (i2 >= NumVerts) + i2=0; + + pVert0 = &Verts[i]; + pVert1 = &Verts[i2]; + + du = pVert1->u - pVert0->u; + dv = pVert1->v - pVert0->v; + dx = pVert1->x - pVert0->x; + dy = pVert1->y - pVert0->y; + + du *= ScaleU; + dv *= ScaleV; + + MipScaleT = ((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy)); + + if (MipScaleT < MipScale) + MipScale = MipScaleT; // Record the best MipScale (the one closest to the the eye) + } + + if (MipScale <= 4) // 2, 6, 12 + Mip = 0; + else if (MipScale <= 15) + Mip = 1; + else if (MipScale <= 40) + Mip = 2; + else + Mip = 3; + } + + if (Mip > MaxMipLevel) + Mip = MaxMipLevel; + + return Mip; +} \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D8Drv/Pcache.h b/G3D/Engine/Drivers/D3D8Drv/Pcache.h new file mode 100644 index 0000000..5e55574 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/Pcache.h @@ -0,0 +1,35 @@ +/****************************************************************************************/ +/* PCache.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D poly cache */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef PCACHE_H +#define PCACHE_H + +extern DRV_CacheInfo CacheInfo; + +BOOL PCache_InsertWorldPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +BOOL PCache_FlushWorldPolys(void); + +BOOL PCache_FlushMiscPolys(void); +BOOL PCache_InsertMiscPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, uint32 Flags); + +BOOL PCache_Reset(void); + +#endif diff --git a/G3D/Engine/Drivers/D3D8Drv/RENDER.H b/G3D/Engine/Drivers/D3D8Drv/RENDER.H new file mode 100644 index 0000000..f000b0a --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/RENDER.H @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* Render.h */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render polys under D3D */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef RENDER_H +#define RENDER_H + +#include + +#include "DCommon.h" + +geBoolean DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags); +geBoolean DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +geBoolean DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags); +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y); + +#endif diff --git a/G3D/Engine/Drivers/D3D8Drv/Render.cpp b/G3D/Engine/Drivers/D3D8Drv/Render.cpp new file mode 100644 index 0000000..56a1138 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/Render.cpp @@ -0,0 +1,246 @@ +/****************************************************************************************/ +/* Render.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render polys under D3D */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" +#include "Render.h" +#include "Scene.h" +#include "GSpan.h" +#include "D3D_Fx.h" +#include "D3DCache.h" +#include "D3D_Err.h" +#include "THandle.h" + +#include "PCache.h" + + + + + + + + + + +#define SNAP_VERT(v) ( ( v ) = ( float )( ( long )( ( v ) * 16 ) ) / 16.0f ) + +geBoolean DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags) +{ + int32 i; + DRV_TLVertex *pPnts; + D3DTLVERTEX D3DPnts[30], *pD3DPnts; + float ZRecip; + float Alpha; + + if(!AppInfo.RenderingIsOK) + return TRUE; + + if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + if (!PCache_FlushMiscPolys()) + return FALSE; + } + + Alpha = Pnts->a; + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + D3DSetTexture(0, NULL); + + int32 SAlpha = (int32)Alpha<<24; + pPnts = Pnts; + pD3DPnts = D3DPnts; + for (i=0; i< NumPoints; i++) + { + ZRecip = 1/pPnts->z; + + pD3DPnts->sx = pPnts->x; + pD3DPnts->sy = pPnts->y; + pD3DPnts->sz = (1.0f - ZRecip); // ZBUFFER + pD3DPnts->rhw = ZRecip; + pD3DPnts->color = SAlpha | ((int32)pPnts->r<<16) | ((int32)pPnts->g<<8) | (int32)pPnts->b; + + if (AppInfo.FogEnable && !(Flags & DRV_RENDER_POLY_NO_FOG)) // poly fog + { + DWORD FogVal; + float Val; + + Val = pPnts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DPnts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DPnts->specular = 0; + + pPnts++; + pD3DPnts++; + } + + D3DTexturedPolyOld(D3DPnts, NumPoints); + + if (Flags & DRV_RENDER_FLUSH) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + } + + return TRUE; +} + +geBoolean DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ + if(!AppInfo.RenderingIsOK) + { + return TRUE; + } + else if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + } + + + D3DDRV.NumRenderedPolys++; + + // Insert the poly into the world cache, for later rendering + PCache_InsertWorldPoly(Pnts, NumPoints, THandle, TexInfo, LInfo, Flags); + + if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + } + + return TRUE; +} + +geBoolean DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags) +{ + if(!AppInfo.RenderingIsOK) + { + return TRUE; + } + else if (Flags & DRV_RENDER_FLUSH) + { + PCache_FlushMiscPolys(); + } + + PCache_InsertMiscPoly(Pnts, NumPoints, THandle, Flags); + + if (Flags & DRV_RENDER_FLUSH) + { + PCache_FlushMiscPolys(); + } + + return TRUE; +} + +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) +{ + RECT SRect2, *pSRect; + int32 Width, Height; + HRESULT ddrval; + + if(!AppInfo.RenderingIsOK) + return TRUE; + + if (!SRect) + { + SRect2.left = 0; + SRect2.right = THandle->Width; + SRect2.top = 0; + SRect2.bottom = THandle->Height; + pSRect = &SRect2; + Width = (THandle->Width); + Height = (THandle->Height); + } + else + { + pSRect = SRect; + Width = (pSRect->right - pSRect->left)+1; + Height = (pSRect->bottom - pSRect->top)+1; + } + + if (x + Width <= 0) + return TRUE; + if (y + Height <= 0) + return TRUE; + + if (x >= ClientWindow.Width) + return TRUE; + + if (y >= ClientWindow.Height) + return TRUE; + + if (x + Width >= (ClientWindow.Width-1)) + pSRect->right -= ((x + Width) - (ClientWindow.Width-1)); + if (y + Height >= (ClientWindow.Height-1)) + pSRect->bottom -= ((y + Height) - (ClientWindow.Height-1)); + + if (x < 0) + { + pSRect->left += -x; + x=0; + } + if (y < 0) + { + pSRect->top += -y; + y=0; + } + + RECT DRect; + + Width = (pSRect->right - pSRect->left); + Height = (pSRect->bottom - pSRect->top); + + DRect.left = x; + DRect.right = x+Width; + DRect.top = y; + DRect.bottom = y+Height; + + ddrval= AppInfo.lpBackBuffer->Blt(&DRect, THandle->MipData[0].Surface, pSRect, + (DDBLT_KEYSRC | DDBLT_WAIT), NULL); + + if(ddrval==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return GE_FALSE; + } + + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/D3D8Drv/SCENE.H b/G3D/Engine/Drivers/D3D8Drv/SCENE.H new file mode 100644 index 0000000..624f9c6 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/SCENE.H @@ -0,0 +1,46 @@ +/****************************************************************************************/ +/* Scene.h */ +/* */ +/* Author: John Pollard */ +/* Description: Begin/EndScene code, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SCENE_H +#define SCENE_H + +#include + +#include "DCommon.h" + +#define RENDER_NONE 0 +#define RENDER_WORLD 1 +#define RENDER_MESHES 2 +#define RENDER_MODELS 3 + +extern int32 RenderMode; + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *WorldRect); +BOOL DRIVERCC EndScene(void); +BOOL DRIVERCC BeginWorld(void); +BOOL DRIVERCC EndWorld(void); +BOOL DRIVERCC BeginMeshes(void); +BOOL DRIVERCC EndMeshes(void); +BOOL DRIVERCC BeginModels(void); +BOOL DRIVERCC EndModels(void); + +#endif + diff --git a/G3D/Engine/Drivers/D3D8Drv/Scene.cpp b/G3D/Engine/Drivers/D3D8Drv/Scene.cpp new file mode 100644 index 0000000..707ad2e --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/Scene.cpp @@ -0,0 +1,205 @@ +/****************************************************************************************/ +/* Scene.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Begin/EndScene code, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" +#include "Scene.h" +#include "Render.h" +#include "GSpan.h" +#include "D3DCache.h" +#include "D3D_Fx.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "D3D_Err.h" +#include "THandle.h" + + + + + + + +int32 RenderMode; + +uint32 CurrentLRU; + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *WorldRect) +{ + HRESULT Result; + + CurrentLRU++; + + if (!AppInfo.lpD3DDevice) + { + D3DMain_Log("BeginScene: No D3D Device!."); + return FALSE; + } + + // Make sure we clear the cache info structure... + memset(&CacheInfo, 0, sizeof(DRV_CacheInfo)); + + if (!THandle_CheckCache()) + return GE_FALSE; + + // Watch for inactive app or minimize + if(AppInfo.RenderingIsOK) + { + if (!Main_ClearBackBuffer(Clear, ClearZ)) + { + D3DMain_Log("D3DClearBuffers failed."); + return FALSE; + } + + D3DDRV.NumRenderedPolys = 0; + + Result = AppInfo.lpD3DDevice->BeginScene(); + + if (Result != D3D_OK) + { + D3DMain_Log("BeginScene: D3D BeginScene Failed.\n%s.", D3DErrorToString(Result)); + return FALSE; + } + + D3DBilinearFilter(D3DFILTER_LINEAR, D3DFILTER_LINEAR); + D3DPolygonMode (D3DFILL_SOLID); + + D3DZWriteEnable (TRUE); + D3DZEnable(TRUE); + D3DZFunc(D3DCMP_LESSEQUAL); + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + D3DBlendEnable(TRUE); + + if (AppInfo.FogEnable) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR , ((DWORD)AppInfo.FogR<<16)|((DWORD)AppInfo.FogG<<8)|(DWORD)AppInfo.FogB); + } + else + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + } + } + + return TRUE; +} + +BOOL DRIVERCC EndScene(void) +{ + HRESULT Result; + + if (!AppInfo.lpD3DDevice) + return FALSE; + + if(AppInfo.RenderingIsOK) + { + // Flush everything one last time... + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + Result = AppInfo.lpD3DDevice->EndScene(); + + if (Result != D3D_OK) + { + D3DMain_Log("EndScene: D3D EndScene Failed.\n%s", D3DErrorToString(Result)); + return FALSE; + } + + if (!Main_ShowBackBuffer()) + return FALSE; + } + return TRUE; +} + +BOOL DRIVERCC BeginWorld(void) +{ + RenderMode = RENDER_WORLD; + return TRUE; +} + +BOOL DRIVERCC EndWorld(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + } + return TRUE; +} + +BOOL GlobalMeshHack; + +BOOL DRIVERCC BeginMeshes(void) +{ + GlobalMeshHack = TRUE; + RenderMode = RENDER_MESHES; + return TRUE; +} + +BOOL DRIVERCC EndMeshes(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushMiscPolys(); + PCache_FlushWorldPolys(); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + + GlobalMeshHack = FALSE; + } + return TRUE; +} + +BOOL DRIVERCC BeginModels(void) +{ + RenderMode = RENDER_MODELS; + return TRUE; +} + +BOOL DRIVERCC EndModels(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + + } + return TRUE; +} diff --git a/G3D/Engine/Drivers/D3D8Drv/THandle.cpp b/G3D/Engine/Drivers/D3D8Drv/THandle.cpp new file mode 100644 index 0000000..a932124 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/THandle.cpp @@ -0,0 +1,743 @@ +/****************************************************************************************/ +/* THandle.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for D3DDrv */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "THandle.h" +#include "BaseType.h" +#include "D3DDrv.h" +#include "DCommon.h" +#include "D3DCache.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "D3d_FX.h" + +#include "TPage.h" + + + + + + +#define MAX_TEXTURE_HANDLES 15000 +#define TEXTURE_CACHE_PERCENT 0.75f +#define LMAP_CACHE_PERCENT 0.25f +#define TSTAGE_0 0 +#define TSTAGE_1 1 + + + +geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; +DDMemMgr *MemMgr; +DDMemMgr_Partition *Partition[2]; +D3DCache *TextureCache; +D3DCache *LMapCache; +TPage_Mgr *TPageMgr; +DDSURFACEDESC2 CurrentSurfDesc; +THandle_MipData SystemToVideo[MAX_LMAP_LOG_SIZE]; +geBoolean CacheNeedsUpdate; + + + +//============================================================================================ +// FreeAllcaches +//============================================================================================ +void FreeAllCaches(void) +{ + if (LMapCache) + D3DCache_Destroy(LMapCache); + + if (TextureCache) + D3DCache_Destroy(TextureCache); + + LMapCache = NULL; + TextureCache = NULL; + + if (Partition[1]) + DDMemMgr_PartitionDestroy(Partition[1]); + if (Partition[0]) + DDMemMgr_PartitionDestroy(Partition[0]); + if (MemMgr) + DDMemMgr_Destroy(MemMgr); + + Partition[1] = NULL; + Partition[0] = NULL; + MemMgr = NULL; +} + +//============================================================================================ +// FindTextureHandle +//============================================================================================ +geRDriver_THandle *FindTextureHandle(void) +{ + int32 i; + geRDriver_THandle *pHandle; + + pHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pHandle++) + { + if (!pHandle->Active) + { + memset(pHandle, 0, sizeof(geRDriver_THandle)); + pHandle->Active = 1; + return pHandle; + } + } + + SetLastDrvError(DRV_ERROR_GENERIC, "D3D_FindTextureHandle: No more handles left.\n"); + + return NULL; +} + +//============================================================================================ +// FreeAllTextureHandles +//============================================================================================ +geBoolean FreeAllTextureHandles(void) +{ + int32 i; + geRDriver_THandle *pHandle; + + pHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pHandle++) + { + if (!pHandle->Active) + continue; + + if (!THandle_Destroy(pHandle)) + return GE_FALSE; + } + + return GE_TRUE; +} + +//============================================================================================ +//============================================================================================ +geBoolean THandle_Startup(void) +{ + // Create the main memory manager + MemMgr = DDMemMgr_Create(AppInfo.VidMemFree); + + if (!MemMgr) + goto ExitWithError; + + // Create partition 0 + Partition[0] = DDMemMgr_PartitionCreate(MemMgr, (uint32)((float)DDMemMgr_GetFreeMem(MemMgr)*TEXTURE_CACHE_PERCENT)); + + if (!Partition[0]) + goto ExitWithError; + + // Create partition 1 + Partition[1] = DDMemMgr_PartitionCreate(MemMgr, DDMemMgr_GetFreeMem(MemMgr)); + + if (!Partition[1]) + goto ExitWithError; + + // Create the texture cache from partition 0 + TextureCache = D3DCache_Create("Main Texture Cache", AppInfo.lpDD, Partition[0], AppInfo.CanDoMultiTexture); + + if (!TextureCache) + goto ExitWithError; + + // Create the lmap cache from partition 1 + LMapCache = D3DCache_Create("Lightmap Cache", AppInfo.lpDD, Partition[1], AppInfo.CanDoMultiTexture); + + if (!LMapCache) + goto ExitWithError; + + // Create all the system to video surfaces (for lmaps) + if (!CreateSystemToVideoSurfaces()) + goto ExitWithError; + + #ifdef USE_TPAGES + TPageMgr = TPage_MgrCreate(AppInfo.lpDD, &AppInfo.ddTexFormat, 512); + if (!TPageMgr) + goto ExitWithError; + #endif + + return GE_TRUE; + + ExitWithError: + { + THandle_Shutdown(); + return GE_FALSE; + } +} + +//============================================================================================ +//============================================================================================ +void THandle_Shutdown(void) +{ + FreeAllTextureHandles(); + FreeAllCaches(); + DestroySystemToVideoSurfaces(); + + CacheNeedsUpdate = GE_FALSE; +} + +//============================================================================================ +// Create3DTHandle +//============================================================================================ +geRDriver_THandle *Create3DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 Size, i; + + // Store width/height info + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = (1<Log); + + // Create the surfaces to hold all the mips + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + if (!THandle->MipData) + { + THandle_Destroy(THandle); + return NULL; + } + + Size = 1<Log; + + // Create all the surfaces for each mip level + for (i=0; i< NumMipLevels; i++) + { + int32 Stage; + + if (!THandle_CreateSurfaces(&THandle->MipData[i], Size, Size, &CurrentSurfDesc, GE_FALSE, 0)) + { + THandle_Destroy(THandle); + return NULL; + } + + // get a cache type for this surface since it is a 3d surface, and will need to be cached on the video card + //THandle->MipData[i].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, NumMipLevels, &CurrentSurfDesc); + // We can use 1 miplevel for the type, since we are createing types for each miplevel... + if (AppInfo.CanDoMultiTexture) + Stage = TSTAGE_0; + else + Stage = 0; + + THandle->MipData[i].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, 1, Stage, &CurrentSurfDesc); + + if (!THandle->MipData[i].CacheType) + { + THandle_Destroy(THandle); + return NULL; + } + + Size>>=1; + } + + return THandle; +} + +//============================================================================================ +// CreateLightmapTHandle +//============================================================================================ +geRDriver_THandle *CreateLightmapTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 Size, Stage; + + + // Save some info about the lightmap + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = 1<Log; + + + Size = 1<Log; + + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + THandle->MipData[0].Flags = THANDLE_UPDATE; + + if (AppInfo.CanDoMultiTexture) + Stage = TSTAGE_1; + else + Stage = 0; + + THandle->MipData[0].CacheType = D3DCache_TypeCreate(LMapCache, Size, Size, NumMipLevels, Stage, &CurrentSurfDesc); + + if (!THandle->MipData[0].CacheType) + { + THandle_Destroy(THandle); + return NULL; + } + + return THandle; +} + +//============================================================================================ +// Create2DTHandle +//============================================================================================ +geRDriver_THandle *Create2DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + + // Save some info about the lightmap + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = Width; + + // Create the surfaces to hold all the mips + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + if (!THandle->MipData) + { + THandle_Destroy(THandle); + return NULL; + } + + if (!THandle_CreateSurfaces(&THandle->MipData[0], Width, Height, &CurrentSurfDesc, GE_TRUE, 0)) + { + THandle_Destroy(THandle); + return NULL; + } + + return THandle; +} + +//============================================================================================ +// SetupCurrent3dDesc +//============================================================================================ +geBoolean SetupCurrent3dDesc(gePixelFormat PixelFormat) +{ + switch (PixelFormat) + { + case GE_PIXELFORMAT_16BIT_555_RGB: + case GE_PIXELFORMAT_16BIT_565_RGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddTexFormat, sizeof(DDSURFACEDESC2)); + break; + } + case GE_PIXELFORMAT_16BIT_4444_ARGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddFourBitAlphaSurfFormat, sizeof(DDSURFACEDESC2)); + break; + } + case GE_PIXELFORMAT_16BIT_1555_ARGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddOneBitAlphaSurfFormat, sizeof(DDSURFACEDESC2)); + break; + } + + default: + { + SetLastDrvError(DRV_ERROR_GENERIC, "SetupCurrent3dDesc: Invalid pixel format.\n"); + return GE_FALSE; + } + } + + return GE_TRUE; +} +//============================================================================================ +// THandle_Create +//============================================================================================ +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + geRDriver_THandle *THandle; + + THandle = FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "D3DDRV:THandle_Create: Out of texture handles.\n"); + return NULL; + } + + THandle->PixelFormat = *PixelFormat; + + if (PixelFormat->Flags & RDRIVER_PF_3D) + { + // Get the pixel format desc for this thandle + if (!SetupCurrent3dDesc(PixelFormat->PixelFormat)) + return NULL; + + if (!Create3DTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + + CacheNeedsUpdate = GE_TRUE; + } + else if (PixelFormat->Flags & RDRIVER_PF_LIGHTMAP) + { + // Get the pixel format desc for this thandle + if (!SetupCurrent3dDesc(PixelFormat->PixelFormat)) + return NULL; + + if (!CreateLightmapTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + + CacheNeedsUpdate = GE_TRUE; + } + else if (PixelFormat->Flags & RDRIVER_PF_2D) + { + // 2d surfaces are always this format for now + memcpy(&CurrentSurfDesc, &AppInfo.ddSurfFormat, sizeof(DDSURFACEDESC2)); + + if (!Create2DTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + } + + return THandle; +} + +//============================================================================================ +// THandle_Destroy +//============================================================================================ +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle) +{ + int32 i; + + + for (i=0; i< THandle->NumMipLevels; i++) + { + + if (THandle->MipData[i].CacheType) + { + D3DCache_TypeDestroy(THandle->MipData[i].CacheType); + CacheNeedsUpdate = GE_TRUE; + THandle->MipData[i].CacheType = NULL; + } + + if (THandle->MipData[i].Surface) + { + + THandle_DestroySurfaces(&THandle->MipData[i]); + THandle->MipData[i].Surface = NULL; + THandle->MipData[i].Texture = NULL; + } + } + + if (THandle->MipData) + free(THandle->MipData); + + memset(THandle, 0, sizeof(geRDriver_THandle)); + + return GE_TRUE; +} + +//===================================================================================== +//===================================================================================== +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Bits) +{ + DDSURFACEDESC2 SurfDesc; + HRESULT Result; + + + // Lock the surface so it can be filled with the data + memset(&SurfDesc, 0, sizeof(DDSURFACEDESC2)); + SurfDesc.dwSize = sizeof(DDSURFACEDESC2); + + Result = THandle->MipData[MipLevel].Surface->Lock(NULL, &SurfDesc, DDLOCK_WAIT, NULL); + + if (Result != DD_OK) + { + return GE_FALSE; + } + + THandle->MipData[MipLevel].Flags |= THANDLE_LOCKED; + + *Bits = (void*)SurfDesc.lpSurface; + + return GE_TRUE; +} + +//===================================================================================== +// THandle_UnLock +//===================================================================================== +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel) +{ + HRESULT Result; + + // Unlock the surface + Result = THandle->MipData[MipLevel].Surface->Unlock(NULL); + + if (Result != DD_OK) + { + return GE_FALSE; + } + + THandle->MipData[MipLevel].Flags |= THANDLE_UPDATE; + THandle->MipData[MipLevel].Flags &= ~THANDLE_LOCKED; + + return GE_TRUE; +} + + +//===================================================================================== +// THandle_GetInfo +//===================================================================================== +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info) +{ + Info->Width = THandle->Width>>MipLevel; + Info->Height = THandle->Height>>MipLevel; + Info->Stride = THandle->Stride>>MipLevel; + + if (THandle->PixelFormat.Flags & RDRIVER_PF_CAN_DO_COLORKEY) + { + Info->Flags = RDRIVER_THANDLE_HAS_COLORKEY; + Info->ColorKey = 1; + } + else + { + Info->Flags = 0; + Info->ColorKey = 0; + } + + Info->PixelFormat = THandle->PixelFormat; + + return GE_TRUE; +} + +//===================================================================================== +// CreateSystemToVideoSurfaces +// System surfaces to copy from system to video +//===================================================================================== +geBoolean CreateSystemToVideoSurfaces(void) +{ + int32 i; + DDSURFACEDESC2 SurfDesc; + + memcpy(&SurfDesc, &AppInfo.ddTexFormat, sizeof(DDSURFACEDESC2)); + + for (i=0; iCreateSurface(&ddsd, &Surface, NULL); + + if(Hr != DD_OK) + { + return FALSE; + } + + Surf->Surface = Surface; + + Surf->Texture = NULL; + + Hr = Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Surf->Texture); + + if(Hr != DD_OK) + { + Surface->Release(); + return GE_FALSE; + } + + if (ColorKey) + { + DDCOLORKEY CKey; + + // Create the color key for this surface + CKey.dwColorSpaceLowValue = 1; + CKey.dwColorSpaceHighValue = 1; + + if (Surf->Surface->SetColorKey(DDCKEY_SRCBLT , &CKey) != DD_OK) + { + SetLastDrvError(DRV_ERROR_GENERIC, "THandle_CreateSurfaces: SetColorKey failed for texture."); + Surf->Surface->Release(); + Surf->Surface = NULL; + Surf->Texture->Release(); + Surf->Texture = NULL; + return FALSE; + } + } + return GE_TRUE; // All good dude +} + +//===================================================================================== +// DestroySystemSurface +//===================================================================================== +void THandle_DestroySurfaces(THandle_MipData *Surf) +{ + if (Surf->Texture) + Surf->Texture->Release(); + if (Surf->Surface) + Surf->Surface->Release(); + + memset(Surf, 0, sizeof (THandle_MipData)); +} + +//===================================================================================== +// THandle_CheckCache +//===================================================================================== +geBoolean THandle_CheckCache(void) +{ + geRDriver_THandle *pTHandle; + int32 i, Stage0, Stage1; + int32 MaxTable1[9], MaxTable2[9]; + + if (!CacheNeedsUpdate) + return GE_TRUE; + + D3DMain_Log("THandle_CheckCache: Resetting texture cache...\n"); + + if (AppInfo.DeviceIdentifier.dwVendorId == 4634) // 3dfx series have a limit on the number of texture handles + { + D3DMain_Log(" 3dfx card detected, using smaller number of handles...\n"); + + // Texture cache + MaxTable1[0] = 24; // 1x1 + MaxTable1[1] = 24; // 2x2 + MaxTable1[2] = 24; // 4x4 + MaxTable1[3] = 24; // 8x8 + MaxTable1[4] = 24; // 16x16 + MaxTable1[5] = 128; // 32x32 + MaxTable1[6] = 128; // 64x64 + MaxTable1[7] = 128; //128x128 + MaxTable1[8] = 128; //256x256 + + // Lightmap cache + MaxTable2[0] = 128; // 1x1 + MaxTable2[1] = 128; // 2x2 + MaxTable2[2] = 256; // 4x4 + MaxTable2[3] = 256; // 8x8 + MaxTable2[4] = 256; // 16x16 + MaxTable2[5] = 128; // 32x32 + MaxTable2[6] = 128; // 64x64 + MaxTable2[7] = 128; //128x128 + MaxTable2[8] = 128; //256x256 + } + else + { + D3DMain_Log(" NO 3dfx card detected, using larger number of handles...\n"); + + // Texture cache + MaxTable1[0] = 32; // 1x1 + MaxTable1[1] = 32; // 2x2 + MaxTable1[2] = 32; // 4x4 + MaxTable1[3] = 32; // 8x8 + MaxTable1[4] = 32; // 16x16 + MaxTable1[5] = 32; // 32x32 + MaxTable1[6] = 128; // 64x64 + MaxTable1[7] = 128; //128x128 + MaxTable1[8] = 128; //256x256 + + MaxTable2[0] = 128; // 1x1 + MaxTable2[1] = 128; // 2x2 + MaxTable2[2] = 256; // 4x4 + MaxTable2[3] = 1024; // 8x8 + MaxTable2[4] = 1024; // 16x16 + MaxTable2[5] = 512; // 32x32 + MaxTable2[6] = 256; // 64x64 + MaxTable2[7] = 256; //128x128 + MaxTable2[8] = 256; //256x256 + } + + if (AppInfo.CanDoMultiTexture) + { + Stage0 = TSTAGE_0; + Stage1 = TSTAGE_1; + } + else + { + Stage0 = 0; + Stage1 = 0; + } + + if (!D3DCache_AdjustSlots(LMapCache, MaxTable2, GE_TRUE)) + { + D3DMain_Log("THandle_CheckCache: D3DCache_AdjustSlots failed for LMapCache.\n"); + return GE_FALSE; + } + + if (!D3DCache_AdjustSlots(TextureCache, MaxTable1, GE_FALSE)) + { + D3DMain_Log("THandle_CheckCache: D3DCache_AdjustSlots failed for TextureCache.\n"); + return GE_FALSE; + } + + + // Make sure no THandles reference any slots, because they mave have been moved around, or gotten destroyed... + // (Evict all textures in the cache) + pTHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pTHandle++) + { + int32 m; + + for (m=0; m< pTHandle->NumMipLevels; m++) + { + pTHandle->MipData[m].Slot = NULL; + } + } + + CacheNeedsUpdate = GE_FALSE; + + return GE_TRUE; +} diff --git a/G3D/Engine/Drivers/D3D8Drv/THandle.h b/G3D/Engine/Drivers/D3D8Drv/THandle.h new file mode 100644 index 0000000..16bafb8 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/THandle.h @@ -0,0 +1,101 @@ +/****************************************************************************************/ +/* THandle.h */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for D3DDrv */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef THANDLE_H +#define THANDLE_H + +#include + +#include "BaseType.h" +#include "DCommon.h" +#include "D3DCache.h" + +#include "TPage.h" + +//============================================================================================ +//============================================================================================ +#define THANDLE_MAX_MIP_LEVELS 255 +#define MAX_LMAP_LOG_SIZE 6 // Max lightmap size in pixels will be 32x32 + +typedef struct +{ + LPDIRECTDRAWSURFACE4 Surface; // The DD surface + D3DCache_Type *CacheType; + D3DCache_Slot *Slot; + + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface + + uint8 Flags; +} THandle_MipData; + +// THandle flags +#define THANDLE_LOCKED (1<<0) +#define THANDLE_UPDATE (1<<1) + +typedef struct geRDriver_THandle +{ + uint8 Active; + int32 Width; + int32 Height; + int32 Stride; + uint8 NumMipLevels; + uint8 Log; + + THandle_MipData *MipData; // A mipdata per miplevel + + geRDriver_PixelFormat PixelFormat; + + +} geRDriver_THandle; + +extern geRDriver_THandle TextureHandles[]; + +extern D3DCache *TextureCache; +extern D3DCache *LMapCache; + +extern TPage_Mgr *TPageMgr; + +extern THandle_MipData SystemToVideo[]; + +extern CacheNeedsUpdate; + +//============================================================================================ +//============================================================================================ +void FreeAllCaches(void); +geRDriver_THandle *FindTextureHandle(void); +geBoolean FreeAllTextureHandles(void); +geBoolean THandle_Startup(void); +void THandle_Shutdown(void); +geRDriver_THandle *Create3DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *CreateLightmapTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *Create2DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle); +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Bits); +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel); +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info); +geBoolean CreateSystemToVideoSurfaces(void); +void DestroySystemToVideoSurfaces(void); +geBoolean THandle_CreateSurfaces(THandle_MipData *MipData, int32 Width, int32 Height, DDSURFACEDESC2 *SurfDesc, geBoolean ColorKey, int32 Stage); +void THandle_DestroySurfaces(THandle_MipData *MipData); +geBoolean THandle_CheckCache(void); + +#endif diff --git a/G3D/Engine/Drivers/D3D8Drv/TPage.h b/G3D/Engine/Drivers/D3D8Drv/TPage.h new file mode 100644 index 0000000..b6db4d0 --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/TPage.h @@ -0,0 +1,69 @@ +/****************************************************************************************/ +/* TPage.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager using pages */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef TPAGE_H +#define TPAGE_H + +#include + +#include +#include + +typedef struct TPage_Mgr TPage_Mgr; +typedef struct TPage TPage; +typedef struct TPage_Block TPage_Block; + +// +// TPage_Mgr +// +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages); +void TPage_MgrDestroy(TPage_Mgr **TPageMgr); +geBoolean TPage_MgrHasTPage(TPage_Mgr *Mgr, TPage *Page); +geBoolean TPage_MgrAttachTPage(TPage_Mgr *Mgr, TPage *TPage); +void TPage_MgrDetachTPage(TPage_Mgr *Mgr, TPage *TPage); +TPage_Block *TPage_MgrFindOptimalBlock(TPage_Mgr *Mgr, uint32 LRU); + +// +// TPage +// +TPage *TPage_Create(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc); +void TPage_CreateRef(TPage *Page); +void TPage_Destroy(TPage **Page1); +geBoolean TPage_HasBlock(TPage *TPage, TPage_Block *Block); +geBoolean TPage_AttachBlock(TPage *Page, TPage_Block *Block); +void TPage_DetachBlock(TPage *TPage, TPage_Block *Block); +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc); +void TPage_DestroySurfaces(TPage *Page); + +// +//TPage_Block +// +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE4 Surface, LPDIRECT3DTEXTURE2 Texture, const RECT *Rect); +geBoolean TPage_BlockCreateRef(TPage_Block *Block); +void TPage_BlockDestroy(TPage_Block **Block); +LPDIRECT3DTEXTURE2 TPage_BlockGetTexture(TPage_Block *Block); +LPDIRECTDRAWSURFACE4 TPage_BlockGetSurface(TPage_Block *Block); +const RECT *TPage_BlockGetRect(TPage_Block *Block); +void TPage_BlockSetLRU(TPage_Block *Block, uint32 LRU); +void TPage_BlockSetUserData(TPage_Block *Block, void *UserData); +void *TPage_BlockGetUserData(TPage_Block *Block); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3D8Drv/tpage.cpp b/G3D/Engine/Drivers/D3D8Drv/tpage.cpp new file mode 100644 index 0000000..b473e0f --- /dev/null +++ b/G3D/Engine/Drivers/D3D8Drv/tpage.cpp @@ -0,0 +1,577 @@ +/****************************************************************************************/ +/* TPage.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager using pages */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "BaseType.h" +#include "TPage.h" + + + + + + + +// These must be a power of 2!!! +#define TPAGE_WIDTH 16 // Width of TPAges +#define TPAGE_HEIGHT 16 // Height of TPages + +#define TPAGE_GRID_X 16 // Must be <= TPAGE_WIDTH, and power of 2 +#define TPAGE_GRID_Y 16 // Must be <= TPAGE_HEIGHT, and power of 2 + +// NOTE - Blocks Width/Height that go into TPages MUST be <= AlignX/AlignY!!! + +typedef struct TPage_Block +{ + int32 RefCount; // Number of references to this object + + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this Block + LPDIRECT3DTEXTURE2 Texture; // The Texture interface to the surface + + RECT Rect; // The Rect into the surface that this block can use + + uint32 LRU; // Set to the TPage->TPageMgr->LRU when accesed... + + void *UserData; + + struct TPage_Block *Prev; + struct TPage_Block *Next; + +} TPage_Block; + +typedef struct TPage +{ + int32 RefCount; + + DDSURFACEDESC2 SurfaceDesc; // Surface description of this page (note all blocks must use this format!!!) + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this TPage + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface + + TPage_Block *Blocks; // Linked list of blocks + + uint32 LRU; + + struct TPage *Prev; + struct TPage *Next; +} TPage; + +typedef struct TPage_Mgr +{ + int32 NumPages; + + TPage *TPages; // Linked list of TPages + + LPDIRECTDRAW4 lpDD; // DD object used to create surfaces +} TPage_Mgr; + +//============================================================================ +// *** TPage_Mgr *** +//============================================================================ + +//============================================================================ +// TPage_MgrCreate +//============================================================================ +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages) +{ + TPage_Mgr *TPageMgr; + int32 i; + + TPageMgr = (TPage_Mgr*)malloc(sizeof(TPage_Mgr)); + + if (!TPageMgr) + return NULL; + + memset(TPageMgr, 0, sizeof(TPage_Mgr)); + + // Remeber the DD object + TPageMgr->lpDD = lpDD; + // Ref the dd object + lpDD->AddRef(); + + TPageMgr->NumPages = NumPages; + + // Create the pages + for (i=0; iTPages; Page; Page = Next) + { + Next = Page->Next; + + TPage_MgrDetachTPage(Mgr, Page); + TPage_Destroy(&Page); + } + + // Release our ref on the DD object + Mgr->lpDD->Release(); + + free(*TPageMgr); + + *TPageMgr = NULL; +} + +//============================================================================ +// TPage_MgrHasTPage +//============================================================================ +geBoolean TPage_MgrHasTPage(TPage_Mgr *Mgr, TPage *Page) +{ + TPage *Page2; + + for (Page2 = Mgr->TPages; Page2; Page2 = Page2->Next) + { + if (Page2 == Page) + { + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//============================================================================ +// TPage_MgrAttachTPage +// NOTE - A TPage can only attach to one TPage_Mgr, and only ONCE!! +//============================================================================ +geBoolean TPage_MgrAttachTPage(TPage_Mgr *Mgr, TPage *TPage) +{ + if (Mgr->TPages) + Mgr->TPages->Prev = TPage; + + TPage->Prev = NULL; + TPage->Next = Mgr->TPages; + Mgr->TPages = TPage; + + return GE_TRUE; +} + +//============================================================================ +// TPage_MgrDetachTPage +//============================================================================ +void TPage_MgrDetachTPage(TPage_Mgr *Mgr, TPage *TPage) +{ + if (TPage->Next) + TPage->Next->Prev = TPage->Prev; + + if (TPage->Prev) + TPage->Prev->Next = TPage->Prev; + else + { + // If we get here, this better be the first TPage in the list! + Mgr->TPages = TPage->Next; + } + + TPage->Next = NULL; + TPage->Prev = NULL; +} + +//============================================================================ +// TPage_MgrFindOptimalBlock +//============================================================================ +TPage_Block *TPage_MgrFindOptimalBlock(TPage_Mgr *Mgr, uint32 LRU) +{ + TPage *Page; + TPage_Block *Block, *BestBlock; + uint32 BestLRU; + + // We really should make a TPage_GetOptimalBlock... + BestBlock = NULL; + BestLRU = 0xffffffff; + + for (Page = Mgr->TPages; Page; Page = Page->Next) + { + for (Block = Page->Blocks; Block; Block = Block->Next) + { + if (Block->LRU < BestLRU) + { + BestBlock = Block; + BestLRU = Block->LRU; + } + } + } + + BestBlock->LRU = LRU; + + return BestBlock; +} + +//============================================================================ +// *** TPage *** +//============================================================================ + +//============================================================================ +// TPage_Create +//============================================================================ +TPage *TPage_Create(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc) +{ + TPage *Page; + int32 w, h; + + Page = (TPage*)malloc(sizeof(TPage)); + + if (!Page) + return NULL; + + memset(Page, 0, sizeof(TPage)); + + Page->SurfaceDesc = *SurfDesc; + + TPage_CreateRef(Page); // Create the very first ref + + if (!TPage_CreateSurfaces(Page, lpDD, SurfDesc)) + { + free(Page); + return NULL; + } + + // Create the blocks + for (h=0; hSurface, Page->Texture, &Rect); + + if (!Block) + goto ExitWithError; + + if (!TPage_AttachBlock(Page, Block)) + goto ExitWithError; + } + } + + return Page; + + ExitWithError: + { + if (Page) + TPage_Destroy(&Page); + + return NULL; + } +} + +//============================================================================ +// TPage_CreateRef +//============================================================================ +void TPage_CreateRef(TPage *Page) +{ + Page->RefCount++; +} + +//============================================================================ +// TPage_Destroy +//============================================================================ +void TPage_Destroy(TPage **Page1) +{ + TPage *Page; + TPage_Block *Block, *Next; + + Page = *Page1; + + Page->RefCount--; + + if (Page->RefCount > 0) + return; + + // Destroy any dd surfaces for this page + TPage_DestroySurfaces(Page); + + // Destroy all the blocks this page has + for (Block = Page->Blocks; Block; Block = Next) + { + Next = Block->Next; + + TPage_DetachBlock(Page, Block); + TPage_BlockDestroy(&Block); + } + + free(*Page1); + + *Page1 = NULL; +} + +//============================================================================ +// TPage_HasBlock +//============================================================================ +geBoolean TPage_HasBlock(TPage *TPage, TPage_Block *Block) +{ + TPage_Block *Block2; + + for (Block2 = TPage->Blocks; Block2; Block2 = Block2->Next) + { + if (Block2 == Block) + { + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//============================================================================ +// TPage_AttachBlock +// NOTE - A Block can only attach to one TPage, and only ONCE!! +//============================================================================ +geBoolean TPage_AttachBlock(TPage *Page, TPage_Block *Block) +{ + // Insert the block into the list of blocks for this Page + if (Page->Blocks) + Page->Blocks->Prev = Block; + + Block->Prev = NULL; + Block->Next = Page->Blocks; + + Page->Blocks = Block; + + return GE_TRUE; +} + +//============================================================================ +// TPage_DetachBlock +//============================================================================ +void TPage_DetachBlock(TPage *TPage, TPage_Block *Block) +{ + if (Block->Next) + Block->Next->Prev = Block->Prev; + + if (Block->Prev) + Block->Prev->Next = Block->Prev; + else + { + // If we get here, this better be the first Block in the list! + TPage->Blocks = Block->Next; + } + + // Reset the Block link + Block->Next = NULL; + Block->Prev = NULL; +} + +//===================================================================================== +// TPage_CreateSurfaces +//===================================================================================== +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc) +{ + HRESULT Hr; + DDSURFACEDESC2 ddsd; + + memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTDYNAMIC; + ddsd.ddsCaps.dwCaps3 = 0; + ddsd.ddsCaps.dwCaps4 = 0; + ddsd.dwWidth = TPAGE_WIDTH; + ddsd.dwHeight = TPAGE_HEIGHT; + + Hr = lpDD->CreateSurface(&ddsd, &Page->Surface, NULL); + + if (Hr != DD_OK) + return GE_FALSE; + + Hr = Page->Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Page->Texture); + + if(Hr != DD_OK) + { + Page->Surface->Release(); + Page->Surface = NULL; + Page->Texture = NULL; + return GE_FALSE; + } + + return GE_TRUE; // All good dude +} + + +//===================================================================================== +// TPage_DestroySurfaces +//===================================================================================== +void TPage_DestroySurfaces(TPage *Page) +{ + if (Page->Texture) + { + Page->Texture->Release(); + Page->Texture = NULL; + } + + if (Page->Surface) + { + Page->Surface->Release(); + Page->Surface = NULL; + } +} + +//============================================================================ +// *** TPage_Block *** +//============================================================================ + +//============================================================================ +// TPage_BlockCreate +//============================================================================ +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE4 Surface, LPDIRECT3DTEXTURE2 Texture, const RECT *Rect) +{ + TPage_Block *Block; + + Block = (TPage_Block*)malloc(sizeof(TPage_Block)); + + if (!Block) + return NULL; + + memset(Block, 0, sizeof(TPage_Block)); + + Surface->AddRef(); // Ref the surface + Texture->AddRef(); // Ditto... + + // Save off the surface, texture, and rect into the surface + Block->Surface = Surface; + Block->Texture = Texture; + Block->Rect = *Rect; + + TPage_BlockCreateRef(Block); // Create very first ref + + return Block; +} + +//============================================================================ +// TPage_BlockCreateRef +//============================================================================ +geBoolean TPage_BlockCreateRef(TPage_Block *Block) +{ + Block->RefCount++; + + return GE_TRUE; +} + +//============================================================================ +// TPage_BlockDestroy +//============================================================================ +void TPage_BlockDestroy(TPage_Block **Block) +{ + TPage_Block *Block2; + + Block2 = *Block; + + Block2->RefCount--; + + if (Block2->RefCount > 0) + return; + + // Destroy references to the surface and texture + if (Block2->Surface) + Block2->Surface->Release(); + + if (Block2->Texture) + Block2->Texture->Release(); + + // Free the block + free(Block2); + + *Block = NULL; +} + +//============================================================================ +// TPage_BlockGetTexture +//============================================================================ +LPDIRECT3DTEXTURE2 TPage_BlockGetTexture(TPage_Block *Block) +{ + return Block->Texture; +} + +//============================================================================ +// TPage_BlockGetSurface +//============================================================================ +LPDIRECTDRAWSURFACE4 TPage_BlockGetSurface(TPage_Block *Block) +{ + return Block->Surface; +} + +//============================================================================ +// TPage_BlockGetRect +//============================================================================ +const RECT *TPage_BlockGetRect(TPage_Block *Block) +{ + return &Block->Rect; +} + +//============================================================================ +// TPage_BlockSetLRU +//============================================================================ +void TPage_BlockSetLRU(TPage_Block *Block, uint32 LRU) +{ + Block->LRU = LRU; +} + +//============================================================================ +// TPage_BlockSetUserData +//============================================================================ +void TPage_BlockSetUserData(TPage_Block *Block, void *UserData) +{ + Block->UserData = UserData; +} + +//============================================================================ +// TPage_BlockGetUserData +//============================================================================ +void *TPage_BlockGetUserData(TPage_Block *Block) +{ + return Block->UserData; +} diff --git a/G3D/Engine/Drivers/D3DDrv/D3DDRV.H b/G3D/Engine/Drivers/D3DDrv/D3DDRV.H new file mode 100644 index 0000000..e18fdac --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3DDRV.H @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* D3DDrv.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3DDRV_H +#define D3DDRV_H + +#include "DCommon.h" + +extern DRV_Window ClientWindow; +extern DRV_Driver D3DDRV; + +void DRIVERCC ErrorBox(char *Str); +BOOL DRIVERCC DrvShutdown(void); +void SetLastDrvError(int32 Error, char *ErrorStr); + +#endif diff --git a/G3D/Engine/Drivers/D3DDrv/D3DDrv.dsp b/G3D/Engine/Drivers/D3DDrv/D3DDrv.dsp new file mode 100644 index 0000000..931f9f9 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3DDrv.dsp @@ -0,0 +1,207 @@ +# Microsoft Developer Studio Project File - Name="D3DDrv" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=D3DDrv - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "D3DDrv.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "D3DDrv.mak" CFG="D3DDrv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "D3DDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "D3DDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Source/Engine/Drivers/D3DDrv", DVPBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "D3DDrv - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W3 /GX /Ox /Ot /Ow /Og /Oi /Op /Ob2 /I "..\..\.." /I "..\\" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\Math" /I "..\..\..\Bitmap" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /FD /c +# SUBTRACT CPP /X /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /x /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib vfw32.lib dxguid.lib ddraw.lib d3dim.lib /nologo /dll /machine:I386 +# SUBTRACT LINK32 /nodefaultlib + +!ELSEIF "$(CFG)" == "D3DDrv - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /G5 /MTd /W3 /GX /Zi /Od /I "..\..\.." /I "..\..\..\Math" /I "..\\" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\Bitmap" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /YX /FD /GZ /c +# SUBTRACT CPP /X +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /x /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib vfw32.lib dxguid.lib ddraw.lib d3dim.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "D3DDrv - Win32 Release" +# Name "D3DDrv - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\D3d_err.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_err.h +# End Source File +# Begin Source File + +SOURCE=.\D3d_fx.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_fx.h +# End Source File +# Begin Source File + +SOURCE=.\D3d_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_main.h +# End Source File +# Begin Source File + +SOURCE=.\D3dcache.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3dcache.h +# End Source File +# Begin Source File + +SOURCE=.\D3ddrv.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3ddrv.h +# End Source File +# Begin Source File + +SOURCE=..\Dcommon.h +# End Source File +# Begin Source File + +SOURCE=.\DDMemMgr.c +# End Source File +# Begin Source File + +SOURCE=.\DDMemMgr.h +# End Source File +# Begin Source File + +SOURCE=.\Gspan.cpp +# End Source File +# Begin Source File + +SOURCE=.\Gspan.h +# End Source File +# Begin Source File + +SOURCE=.\Pcache.cpp +# End Source File +# Begin Source File + +SOURCE=.\Pcache.h +# End Source File +# Begin Source File + +SOURCE=.\Render.cpp +# End Source File +# Begin Source File + +SOURCE=.\Render.h +# End Source File +# Begin Source File + +SOURCE=.\Scene.cpp +# End Source File +# Begin Source File + +SOURCE=.\Scene.h +# End Source File +# Begin Source File + +SOURCE=.\THandle.cpp +# End Source File +# Begin Source File + +SOURCE=.\THandle.h +# End Source File +# Begin Source File + +SOURCE=.\tpage.cpp +# End Source File +# Begin Source File + +SOURCE=.\TPage.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# End Group +# End Target +# End Project diff --git a/G3D/Engine/Drivers/D3DDrv/D3DDrv.dsw b/G3D/Engine/Drivers/D3DDrv/D3DDrv.dsw new file mode 100644 index 0000000..262da56 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3DDrv.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "D3DDrv"=.\D3DDrv.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/G3D/Engine/Drivers/D3DDrv/D3DDrv.mak b/G3D/Engine/Drivers/D3DDrv/D3DDrv.mak new file mode 100644 index 0000000..454edfc --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3DDrv.mak @@ -0,0 +1,284 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on D3DDrv.dsp +!IF "$(CFG)" == "" +CFG=D3DDrv - Win32 Debug +!MESSAGE No configuration specified. Defaulting to D3DDrv - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "D3DDrv - Win32 Release" && "$(CFG)" != "D3DDrv - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "D3DDrv.mak" CFG="D3DDrv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "D3DDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "D3DDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "D3DDrv - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +ALL : "$(OUTDIR)\D3DDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\D3d_err.obj" + -@erase "$(INTDIR)\D3d_fx.obj" + -@erase "$(INTDIR)\D3d_main.obj" + -@erase "$(INTDIR)\D3dcache.obj" + -@erase "$(INTDIR)\D3ddrv.obj" + -@erase "$(INTDIR)\DDMemMgr.obj" + -@erase "$(INTDIR)\Gspan.obj" + -@erase "$(INTDIR)\Pcache.obj" + -@erase "$(INTDIR)\Render.obj" + -@erase "$(INTDIR)\Scene.obj" + -@erase "$(INTDIR)\THandle.obj" + -@erase "$(INTDIR)\tpage.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\D3DDrv.dll" + -@erase "$(OUTDIR)\D3DDrv.exp" + -@erase "$(OUTDIR)\D3DDrv.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MT /W3 /GX /O2 /X /I "..\..\.." /I "..\..\..\..\SdkDx6Sdk\Include" /I "..\\" /I "..\..\..\..\Sdk\Dx6Sdk\Include" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\Math" /I "..\..\..\Bitmap" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /Fp"$(INTDIR)\D3DDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\D3DDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:no /pdb:"$(OUTDIR)\D3DDrv.pdb" /machine:I386 /nodefaultlib /out:"$(OUTDIR)\D3DDrv.dll" /implib:"$(OUTDIR)\D3DDrv.lib" +LINK32_OBJS= \ + "$(INTDIR)\D3d_err.obj" \ + "$(INTDIR)\D3d_fx.obj" \ + "$(INTDIR)\D3d_main.obj" \ + "$(INTDIR)\D3dcache.obj" \ + "$(INTDIR)\D3ddrv.obj" \ + "$(INTDIR)\DDMemMgr.obj" \ + "$(INTDIR)\Gspan.obj" \ + "$(INTDIR)\Pcache.obj" \ + "$(INTDIR)\Render.obj" \ + "$(INTDIR)\Scene.obj" \ + "$(INTDIR)\THandle.obj" \ + "$(INTDIR)\tpage.obj" \ + "..\..\..\..\MSDev60\lib\Wininet.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmt.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\dxguid.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\ddraw.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\d3dim.lib" + +"$(OUTDIR)\D3DDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "D3DDrv - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\D3DDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\D3d_err.obj" + -@erase "$(INTDIR)\D3d_fx.obj" + -@erase "$(INTDIR)\D3d_main.obj" + -@erase "$(INTDIR)\D3dcache.obj" + -@erase "$(INTDIR)\D3ddrv.obj" + -@erase "$(INTDIR)\DDMemMgr.obj" + -@erase "$(INTDIR)\Gspan.obj" + -@erase "$(INTDIR)\Pcache.obj" + -@erase "$(INTDIR)\Render.obj" + -@erase "$(INTDIR)\Scene.obj" + -@erase "$(INTDIR)\THandle.obj" + -@erase "$(INTDIR)\tpage.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\D3DDrv.dll" + -@erase "$(OUTDIR)\D3DDrv.exp" + -@erase "$(OUTDIR)\D3DDrv.ilk" + -@erase "$(OUTDIR)\D3DDrv.lib" + -@erase "$(OUTDIR)\D3DDrv.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MTd /W3 /GX /Zi /Od /X /I "..\..\.." /I "..\..\..\Math" /I "..\\" /I "..\..\..\..\Sdk\Dx6Sdk\Include" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\Bitmap" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /Fp"$(INTDIR)\D3DDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\D3DDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:yes /pdb:"$(OUTDIR)\D3DDrv.pdb" /debug /machine:I386 /nodefaultlib /out:"$(OUTDIR)\D3DDrv.dll" /implib:"$(OUTDIR)\D3DDrv.lib" /pdbtype:sept +LINK32_OBJS= \ + "$(INTDIR)\D3d_err.obj" \ + "$(INTDIR)\D3d_fx.obj" \ + "$(INTDIR)\D3d_main.obj" \ + "$(INTDIR)\D3dcache.obj" \ + "$(INTDIR)\D3ddrv.obj" \ + "$(INTDIR)\DDMemMgr.obj" \ + "$(INTDIR)\Gspan.obj" \ + "$(INTDIR)\Pcache.obj" \ + "$(INTDIR)\Render.obj" \ + "$(INTDIR)\Scene.obj" \ + "$(INTDIR)\THandle.obj" \ + "$(INTDIR)\tpage.obj" \ + "..\..\..\..\MSDev60\lib\Wininet.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmtd.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\dxguid.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\ddraw.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\d3dim.lib" + +"$(OUTDIR)\D3DDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("D3DDrv.dep") +!INCLUDE "D3DDrv.dep" +!ELSE +!MESSAGE Warning: cannot find "D3DDrv.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "D3DDrv - Win32 Release" || "$(CFG)" == "D3DDrv - Win32 Debug" +SOURCE=.\D3d_err.cpp + +"$(INTDIR)\D3d_err.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3d_fx.cpp + +"$(INTDIR)\D3d_fx.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3d_main.cpp + +"$(INTDIR)\D3d_main.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3dcache.cpp + +"$(INTDIR)\D3dcache.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3ddrv.cpp + +"$(INTDIR)\D3ddrv.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\DDMemMgr.c + +"$(INTDIR)\DDMemMgr.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Gspan.cpp + +"$(INTDIR)\Gspan.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Pcache.cpp + +"$(INTDIR)\Pcache.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Render.cpp + +"$(INTDIR)\Render.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Scene.cpp + +"$(INTDIR)\Scene.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\THandle.cpp + +"$(INTDIR)\THandle.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\tpage.cpp + +"$(INTDIR)\tpage.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/G3D/Engine/Drivers/D3DDrv/D3DDrv.ncb b/G3D/Engine/Drivers/D3DDrv/D3DDrv.ncb new file mode 100644 index 0000000000000000000000000000000000000000..3ba92d06519085ceec183ad89c9fd09f22c08978 GIT binary patch literal 345088 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%0AwTrL6 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 literal 0 HcmV?d00001 diff --git a/G3D/Engine/Drivers/D3DDrv/D3DDrv.plg b/G3D/Engine/Drivers/D3DDrv/D3DDrv.plg new file mode 100644 index 0000000..08d3bef --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3DDrv.plg @@ -0,0 +1,44 @@ + + +
+

Build Log

+

+--------------------Configuration: D3DDrv - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP7C.tmp" with contents +[ +/nologo /G5 /MT /W3 /GX /Ox /Ot /Ow /Og /Oi /Op /Ob2 /I "..\..\.." /I "..\\" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\Math" /I "..\..\..\Bitmap" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /Fo"Release/" /Fd"Release/" /FD /c +"D:\Release\G3D\Engine\Drivers\D3DDrv\D3d_main.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP7C.tmp" +Creating temporary file "C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP7D.tmp" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib vfw32.lib dxguid.lib ddraw.lib d3dim.lib /nologo /dll /incremental:no /pdb:"Release/D3DDrv.pdb" /machine:I386 /out:"Release/D3DDrv.dll" /implib:"Release/D3DDrv.lib" +.\Release\D3d_err.obj +.\Release\D3d_fx.obj +.\Release\D3d_main.obj +.\Release\D3dcache.obj +.\Release\D3ddrv.obj +.\Release\DDMemMgr.obj +.\Release\Gspan.obj +.\Release\Pcache.obj +.\Release\Render.obj +.\Release\Scene.obj +.\Release\THandle.obj +.\Release\tpage.obj +] +Creating command line "link.exe @C:\DOCUME~1\RALPHD~1\LOCALS~1\Temp\RSP7D.tmp" +

Output Window

+Compiling... +D3d_main.cpp +Linking... + Creating library Release/D3DDrv.lib and object Release/D3DDrv.exp + + + +

Results

+D3DDrv.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/G3D/Engine/Drivers/D3DDrv/D3D_ERR.CPP b/G3D/Engine/Drivers/D3DDrv/D3D_ERR.CPP new file mode 100644 index 0000000..378c1fc --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3D_ERR.CPP @@ -0,0 +1,271 @@ +/****************************************************************************************/ +/* D3D_Err.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D Error code conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "D3D_Err.h" + +//================================================================================ +// D3DErrorToString +//================================================================================ +char *D3DErrorToString(HRESULT error) +{ + switch(error) { + case DD_OK: + return "No error.\0"; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized.\0"; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0"; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface.\0"; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface.\0"; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs.\0"; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0"; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0"; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation.\0"; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available.\0"; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process.\0"; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation.\0"; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive.\0"; + case DDERR_GENERIC: + return "Generic failure.\0"; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment.\0"; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created.\0"; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state.\0"; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface.\0"; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface.\0"; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect.\0"; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist.\0"; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0"; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode.\0"; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0"; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect.\0"; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified.\0"; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0"; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid.\0"; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked.\0"; + case DDERR_NO3D: + return "There is no 3D present.\0"; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0"; + case DDERR_NOBLTHW: + return "No blitter hardware present.\0"; + case DDERR_NOCLIPLIST: + return "No cliplist available.\0"; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object.\0"; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or available.\0"; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key\0"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color key.\0"; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0"; + case DDERR_NODC: + return "No DC was ever created for this surface.\0"; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware.\0"; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0"; + case DDERR_NOEMULATION: + return "Software emulation not available.\0"; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive mode.\0"; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported.\0"; + case DDERR_NOGDI: + return "There is no GDI present.\0"; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0"; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available.\0"; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination.\0"; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available.\0"; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface.\0"; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes.\0"; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0"; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available.\0"; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching.\0"; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0"; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0"; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0"; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface.\0"; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable.\0"; + case DDERR_NOTFOUND: + return "Requested item was not found.\0"; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, has been attempted.\0"; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface.\0"; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations.\0"; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0"; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated.\0"; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough video memory to perform the operation.\0"; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays.\0"; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays.\0"; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread.\0"; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface.\0"; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small.\0"; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to.\0"; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of.\0"; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread.\0"; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured.\0"; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.\0"; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached.\0"; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large.\0"; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large.\0"; + case DDERR_UNSUPPORTED: + return "Action not supported.\0"; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw.\0"; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress.\0"; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete.\0"; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode.\0"; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary.\0"; + case D3DERR_BADMAJORVERSION: + return "D3DERR_BADMAJORVERSION\0"; + case D3DERR_BADMINORVERSION: + return "D3DERR_BADMINORVERSION\0"; + case D3DERR_EXECUTE_LOCKED: + return "D3DERR_EXECUTE_LOCKED\0"; + case D3DERR_EXECUTE_NOT_LOCKED: + return "D3DERR_EXECUTE_NOT_LOCKED\0"; + case D3DERR_EXECUTE_CREATE_FAILED: + return "D3DERR_EXECUTE_CREATE_FAILED\0"; + case D3DERR_EXECUTE_DESTROY_FAILED: + return "D3DERR_EXECUTE_DESTROY_FAILED\0"; + case D3DERR_EXECUTE_LOCK_FAILED: + return "D3DERR_EXECUTE_LOCK_FAILED\0"; + case D3DERR_EXECUTE_UNLOCK_FAILED: + return "DDERR_EXECUTE_UNLOCK_FAILED\0"; + case D3DERR_EXECUTE_FAILED: + return "D3DERR_EXECUTE_FAILED\0"; + case D3DERR_EXECUTE_CLIPPED_FAILED: + return "D3DERR_EXECUTE_CLIPPED_FAILED\0"; + case D3DERR_TEXTURE_NO_SUPPORT: + return "D3DERR_TEXTURE_NO_SUPPORT\0"; + case D3DERR_TEXTURE_NOT_LOCKED: + return "D3DERR_TEXTURE_NOT_LOCKED\0"; + case D3DERR_TEXTURE_LOCKED: + return "D3DERR_TEXTURELOCKED\0"; + case D3DERR_TEXTURE_CREATE_FAILED: + return "D3DERR_TEXTURE_CREATE_FAILED\0"; + case D3DERR_TEXTURE_DESTROY_FAILED: + return "D3DERR_TEXTURE_DESTROY_FAILED\0"; + case D3DERR_TEXTURE_LOCK_FAILED: + return "D3DERR_TEXTURE_LOCK_FAILED\0"; + case D3DERR_TEXTURE_UNLOCK_FAILED: + return "D3DERR_TEXTURE_UNLOCK_FAILED\0"; + case D3DERR_TEXTURE_LOAD_FAILED: + return "D3DERR_TEXTURE_LOAD_FAILED\0"; + case D3DERR_MATRIX_CREATE_FAILED: + return "D3DERR_MATRIX_CREATE_FAILED\0"; + case D3DERR_MATRIX_DESTROY_FAILED: + return "D3DERR_MATRIX_DESTROY_FAILED\0"; + case D3DERR_MATRIX_SETDATA_FAILED: + return "D3DERR_MATRIX_SETDATA_FAILED\0"; + case D3DERR_SETVIEWPORTDATA_FAILED: + return "D3DERR_SETVIEWPORTDATA_FAILED\0"; + case D3DERR_MATERIAL_CREATE_FAILED: + return "D3DERR_MATERIAL_CREATE_FAILED\0"; + case D3DERR_MATERIAL_DESTROY_FAILED: + return "D3DERR_MATERIAL_DESTROY_FAILED\0"; + case D3DERR_MATERIAL_SETDATA_FAILED: + return "D3DERR_MATERIAL_SETDATA_FAILED\0"; + case D3DERR_LIGHT_SET_FAILED: + return "D3DERR_LIGHT_SET_FAILED\0"; + default: + return "Unrecognized error value.\0"; + } +} diff --git a/G3D/Engine/Drivers/D3DDrv/D3D_ERR.H b/G3D/Engine/Drivers/D3DDrv/D3D_ERR.H new file mode 100644 index 0000000..bc65c56 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3D_ERR.H @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* D3D_Err.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D Error code conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_ERR_H +#define D3D_ERR_H + +#include +#include +#include + +//================================================================================ +// Global functions +//================================================================================ +char *D3DErrorToString(HRESULT error); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3DDrv/D3d_fx.cpp b/G3D/Engine/Drivers/D3DDrv/D3d_fx.cpp new file mode 100644 index 0000000..1fecd28 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3d_fx.cpp @@ -0,0 +1,211 @@ +/****************************************************************************************/ +/* D3D_Fx.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D renderstate wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" +#include "Render.h" +#include "Scene.h" +#include "D3D_FX.h" +#include "D3D_Main.h" +#include "D3D_Err.h" + +static D3DTEXTUREHANDLE OldTexHandle = NULL; + +//====================================================================================================== +//====================================================================================================== +void D3DSetTexHandle(D3DTEXTUREHANDLE TexHandle) +{ + if (TexHandle == OldTexHandle) + return; + + OldTexHandle = TexHandle; + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, TexHandle); +} + +static LPDIRECT3DTEXTURE2 OldTexture[8]; + +//====================================================================================================== +//====================================================================================================== +void D3DSetTexture(int32 Stage, LPDIRECT3DTEXTURE2 Texture) +{ + if (Texture == OldTexture[Stage]) + return; + + OldTexture[Stage] = Texture; + + AppInfo.lpD3DDevice->SetTexture(Stage, Texture); +} + +//====================================================================================================== +//====================================================================================================== +void D3DBilinearFilter(D3DTEXTUREFILTER Min, D3DTEXTUREFILTER Mag) +{ + AppInfo.lpD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR); + AppInfo.lpD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + + if (AppInfo.CanDoMultiTexture) + { + AppInfo.lpD3DDevice->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFN_LINEAR); + AppInfo.lpD3DDevice->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + } +} + +//====================================================================================================== +// Old one uses D3DTLVERTEX vertex format +//====================================================================================================== +void D3DTexturedPolyOld(void *Pnts, int32 NumPoints) +{ + AppInfo.lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_TLVERTEX, Pnts, NumPoints, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT | D3DDP_DONOTCLIP); +} + +//====================================================================================================== +// D3DTexturedPoly +//====================================================================================================== +void D3DTexturedPoly(void *Pnts, int32 NumPoints) +{ + AppInfo.lpD3DDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, + //D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2, + Pnts, + NumPoints, + D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT | D3DDP_DONOTCLIP); + //D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTCLIP); +} + +//====================================================================================================== +// D3DViewport +//====================================================================================================== +void D3DViewport (int32 x, int32 y, int32 width, int32 height) +{ + D3DVIEWPORT2 vport; + + return; + + vport.dwSize = sizeof(D3DVIEWPORT2); + AppInfo.lpD3DViewport->GetViewport2(&vport); + vport.dwX = x; + vport.dwY = AppInfo.OldHeight - (y + height); + vport.dwWidth = width; + vport.dwHeight = height; + vport.dvClipX = -1.0f; + vport.dvClipY = 1.0f; + vport.dvClipWidth = (geFloat)width /2.0f; + vport.dvClipHeight = (geFloat)height/2.0f; + AppInfo.lpD3DViewport->SetViewport2(&vport); +} + +//====================================================================================================== +//====================================================================================================== +void D3DDepthRange (geFloat zNear, geFloat zFar) +{ + D3DVIEWPORT2 vport; + vport.dwSize = sizeof(D3DVIEWPORT2); + AppInfo.lpD3DViewport->GetViewport2(&vport); + vport.dvMinZ = (D3DVALUE)(((-1.0) * (zFar + zNear)) / (zFar - zNear)); + vport.dvMaxZ = (D3DVALUE)(((-1.0) * (zFar + zNear - 2.0)) / (zFar - zNear)); + AppInfo.lpD3DViewport->SetViewport2(&vport); +} + +static D3DBLEND OldSFunc = D3DBLEND_ONE; +static D3DBLEND OldDFunc = D3DBLEND_ONE; + +//====================================================================================================== +//====================================================================================================== +void D3DBlendFunc (D3DBLEND SFunc, D3DBLEND DFunc) +{ + if (SFunc != OldSFunc) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, SFunc); + OldSFunc = SFunc; + } + if (DFunc != OldDFunc) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, DFunc); + OldDFunc = DFunc; + } + +} + +static BOOL OldBlend = FALSE; + +//====================================================================================================== +//====================================================================================================== +void D3DBlendEnable(BOOL Enable) +{ + if (OldBlend == Enable) + return; + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, Enable); + + OldBlend = Enable; +} + +static BOOL OldWrap = FALSE; + +void D3DTexWrap(DWORD Stage, BOOL Wrap) +{ + if (OldWrap == Wrap) + return; + + OldWrap = Wrap; + + if (Wrap) + { + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); + } + else + { + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); + } +} + +void D3DZWriteEnable (BOOL Enable) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, Enable); +} + +void D3DZFunc (D3DCMPFUNC Func) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, Func); +} + +void D3DZEnable(BOOL Enable) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, Enable); +} + +void D3DPolygonMode (D3DFILLMODE Mode) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID); +} + + + diff --git a/G3D/Engine/Drivers/D3DDrv/D3d_fx.h b/G3D/Engine/Drivers/D3DDrv/D3d_fx.h new file mode 100644 index 0000000..939ea7c --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3d_fx.h @@ -0,0 +1,53 @@ +/****************************************************************************************/ +/* D3D_Fx.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D renderstate wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_FX_H +#define D3D_FX_H + +#include +#include +#include + +#include "D3D_Main.h" +#include "DCommon.h" + +void D3DSetTexHandle(D3DTEXTUREHANDLE TexHandle); +void D3DSetTexture(int32 Stage, LPDIRECT3DTEXTURE2 Texture); +void D3DTexturedPolyOld(void *Pnts, int32 NumPoints); +void D3DTexturedPoly(void *Pnts, int32 NumPoints); + +void D3DBilinearFilter(D3DTEXTUREFILTER Min, D3DTEXTUREFILTER Mag); +void D3DBlendEnable(BOOL Enable); + +void D3DBlendFunc (D3DBLEND SFunc, D3DBLEND DFunc); + +void D3DZWriteEnable (BOOL Enable); +void D3DZFunc (D3DCMPFUNC Func); +void D3DZEnable(BOOL Enable); + +void D3DTexWrap(DWORD Stage, BOOL Wrap); + +void D3DPolygonMode (D3DFILLMODE Mode); + +void D3DViewport (int32 x, int32 y, int32 width, int32 height); +void D3DDepthRange (geFloat zNear, geFloat zFar); + +#endif diff --git a/G3D/Engine/Drivers/D3DDrv/D3d_main.cpp b/G3D/Engine/Drivers/D3DDrv/D3d_main.cpp new file mode 100644 index 0000000..9ec15fb --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3d_main.cpp @@ -0,0 +1,2817 @@ +/****************************************************************************************/ +/* D3D_Main.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: DD/D3D wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + + +/****************************************************************************************/ +/* 32 BPP Supported */ +/* */ +/* 32 BPP Code Created by: Matthew Ellis */ +/* */ +/* This driver also support resolutions up 1280x960 */ +/****************************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "D3D_Main.h" +#include "D3D_Err.h" +#include "D3D_fx.h" +#include "d3dcache.h" + +#include "Render.h" +#include "D3DCache.h" +#include "THandle.h" +#include "PCache.h" + +#undef ATTEMPT +#define ATTEMPT(x) if (!(x)) goto exit_with_error + +#undef RELEASE +#define RELEASE(x) if (x) { x->Release(); x = NULL; } + +static BOOL bInitDone =FALSE; +#ifdef STRICT +WNDPROC pOldWndProc; +#else +FARPROC pOldWndProc; +#endif + +//================================================================================ +// Globals +//================================================================================ +App_Info AppInfo; // Our global structure that knows all... (once initialized) + +// start 32 bit changes +int BPP32 = 16; // Our bpp variable +int ZbufferD = 16; // our Z buffer depths +FILE *stream; // The variable we open our config file to +int gWidth, gHeight; // Global variables for our width and height +// end 32 bit changes + +#define MAX_DRIVERS 64 + +typedef struct +{ + geBoolean IsPrimary; + GUID Guid; + char Name[MAX_DRIVER_NAME]; +} D3D_DRIVER; + +typedef struct +{ + int32 NumDrivers; + D3D_DRIVER *Drivers; +} DDEnumInfo; + +//================================================================================ +// Local static functions +//================================================================================ +static BOOL D3DMain_CreateD3D(void); +static BOOL D3DMain_EnumDevices(void); +static BOOL D3DMain_CreateViewPort(int w, int h); +static BOOL D3DMain_ClearBuffers(void); +static BOOL OutputDriverInfo(const char *Filename, DDMain_D3DDriver *Driver); +static BOOL D3DMain_RememberOldMode(HWND hWnd); +static BOOL D3DMain_SetDisplayMode(HWND hWnd, int w, int h, int bpp, BOOL FullScreen); +static BOOL D3DMain_PickDevice(void); +static BOOL D3DMain_CreateDevice(void); +static BOOL D3DMain_CreateBuffers(void); +static void D3DMain_DestroyBuffers(void); +static BOOL D3DMain_CreateZBuffer(void); +static void D3DMain_DestroyZBuffer(void); +static BOOL D3DMain_RestoreDisplayMode(void); +static BOOL D3DMain_CreateDDFromName(const char *DriverName); +static geBoolean CreateDDFromDriver(D3D_DRIVER *pDriver); +static geBoolean CreateDDFromName(const char *DriverName, const DDEnumInfo *Info); + +BOOL D3DMain_RestoreAllSurfaces(void) +{ + HRESULT ddrval; + +#ifdef _DEBUG + OutputDebugString("--- D3DMain_RestoreAllSurfaces ---\n"); +#endif + + if (AppInfo.lpDD) + { + if (!D3DMain_SetDisplayMode(AppInfo.hWnd, AppInfo.CurrentWidth, AppInfo.CurrentHeight, AppInfo.CurrentBpp, AppInfo.FullScreen)) + return FALSE; + + // Restore all the surfaces + ddrval = AppInfo.lpDD->RestoreAllSurfaces(); + + if(ddrval!=DD_OK) + { + D3DMain_Log("D3DMain_RestoreAllSurfaces: AppInfo.lpDD->RestoreAllSurfaces() failed:\n %s\n", D3DErrorToString(ddrval)); + return FALSE; + } + } + + // Force an update in the cache system + if (TextureCache) + if (!D3DCache_EvictAllSurfaces(TextureCache)) + return FALSE; + + if (LMapCache) + if (!D3DCache_EvictAllSurfaces(LMapCache)) + return FALSE; + + return TRUE; +} + +//================================================================================ +// BPPToDDBD +// Convert an integer bit per pixel number to a DirectDraw bit depth flag +//================================================================================ +static DWORD BPPToDDBD(int bpp) +{ + switch(bpp) + { + case 1: + return DDBD_1; + case 2: + return DDBD_2; + case 4: + return DDBD_4; + case 8: + return DDBD_8; + case 16: + return DDBD_16; + case 24: + return DDBD_24; + case 32: + return DDBD_32; + default: + assert(!"BOGUS bpp"); + } + + return DDBD_1; // Shutup compiler warning +} + +//================================================================================ +// D3DMain_InitD3D +// Does all what is needed to get an app ready to go at a specified with height +// NOTE - It only makes 16 bit modes availible +//================================================================================ +BOOL D3DMain_InitD3D(HWND hWnd, const char *DriverName, int32 Width, int32 Height) +{ + HRESULT LastError; + SYSTEMTIME Time; + + memset(&AppInfo, 0, sizeof(App_Info)); + + GetSystemTime(&Time); + + unlink(D3DMAIN_LOG_FILENAME); + + D3DMain_Log("=================================================================\n"); + D3DMain_Log(" D3DDrv v%i.%i\n", DRV_VERSION_MAJOR, DRV_VERSION_MINOR); + D3DMain_Log(" Build Date: "__DATE__", Time: "__TIME__"\n"); + D3DMain_Log("=================================================================\n\n"); + + D3DMain_Log("Current Time: %2i:%2i:%2i\n", Time.wHour, Time.wMinute, Time.wSecond); + D3DMain_Log("Current Date: %2i-%2i-%4i\n", Time.wMonth, Time.wDay, Time.wYear); + D3DMain_Log("\n ** D3D Driver Initializing **\n\n"); + + AppInfo.hWnd = hWnd; + + // Create DD + ATTEMPT(D3DMain_CreateDDFromName(DriverName)); + + ATTEMPT(D3DMain_GetTextureMemory()); + + // We must do this after the DD object is created!!! + ATTEMPT(D3DMain_RememberOldMode(hWnd)); // Store old mode + + // Get available fullscreen display modes + ATTEMPT(D3DMain_EnumDisplayModes()); + + // Create D3D, and enum it's devices + ATTEMPT(D3DMain_CreateD3D()); + ATTEMPT(D3DMain_EnumDevices()); + +// start 32 bit changes + // Open the config file and read the bpp variable + stream = fopen("D3D24.ini","r"); + if(stream) + { + fscanf(stream,"%d",&BPP32); + fscanf(stream,"%d",&ZbufferD); + fclose(stream); + } + else + { + BPP32 = 16; + ZbufferD = 16; + } + + // Set our global width and height to the real width and height + gWidth = Width; + gHeight = Height; + + if (Width == -1 && Height == -1) // Window Mode + { + // Force Width/Height to client window area size + Width = AppInfo.OldWindowWidth; + Height = AppInfo.OldWindowHeight; + + ATTEMPT(D3DMain_SetDisplayMode(hWnd, Width, Height, AppInfo.OldBpp, FALSE)); + } + else + { + ATTEMPT(D3DMain_SetDisplayMode(hWnd, Width, Height, BPP32, TRUE)); + } +// end 32 bit changes + + // Pick a device we will be happy with + ATTEMPT(D3DMain_PickDevice()); + + // Create front/back buffer + ATTEMPT(D3DMain_CreateBuffers()); + + // For some reason, we have to create the zbuffer BEFORE the device??? Why??? + ATTEMPT(D3DMain_CreateZBuffer()); + + // Create the device and viewport + ATTEMPT(D3DMain_CreateDevice()); + ATTEMPT(D3DMain_CreateViewPort(Width, Height)); + + // Get the surface formats for textures, and 2d surfaces + ATTEMPT(D3DMain_GetSurfaceFormats()); + +#if 0 // For selective debugging + AppInfo.CanDoMultiTexture = GE_FALSE; +#else + AppInfo.CanDoMultiTexture = (AppInfo.Drivers[AppInfo.CurrentDriver].MaxSimultaneousTextures > 1) ? GE_TRUE : GE_FALSE; +#endif + + D3DMain_Log("--- D3DMain_SetRenderState --- \n"); + + // Set some defaults render states + LastError = AppInfo.lpD3DDevice->BeginScene(); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: BeginScene failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = AppInfo.lpD3DDevice->SetCurrentViewport(AppInfo.lpD3DViewport); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: SetViewport failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + //D3DMain_SetFogEnable(GE_TRUE, 255.0f, 0.0f, 0.0f, 500.0f, 1500.0f); + D3DMain_SetFogEnable(GE_FALSE, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL); + //AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE); + +#if 0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ANTIALIAS, D3DANTIALIAS_SORTINDEPENDENT); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_EDGEANTIALIAS, TRUE); +#endif + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, TRUE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPNEAREST); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_LINEAR); + + LastError = AppInfo.lpD3DDevice->EndScene(); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: EndScene failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.RenderingIsOK = TRUE; + + ATTEMPT(D3DMain_ClearBuffers()); + ATTEMPT(D3DMain_GetTextureMemory()); + + if (!THandle_Startup()) + return GE_FALSE; + + D3DViewport (0, 0, Width, Height); + D3DDepthRange (0.0f, 1.0f); + + D3DMain_Log("\n ** Initialization was successful **\n\n"); + + return TRUE; + + exit_with_error:; + D3DMain_Log(" ** Initialization was NOT successful **\n"); + D3DMain_ShutdownD3D(); + return FALSE; +} + +//================================================================================ +// D3DMain_ShutdownD3D +//================================================================================ +BOOL D3DMain_ShutdownD3D(void) +{ + D3DMain_Log("\n--- D3DMain_ShutdownD3D ---\n"); + + THandle_Shutdown(); + + // Destroys all objects including Direct Draw. + AppInfo.RenderingIsOK = FALSE; + + if (AppInfo.lpD3DViewport) + { + assert(AppInfo.lpD3DDevice); + AppInfo.lpD3DDevice->DeleteViewport(AppInfo.lpD3DViewport); + RELEASE(AppInfo.lpD3DViewport); + } + + RELEASE(AppInfo.lpD3DDevice); + + RELEASE(AppInfo.BackgroundMaterial); + + if (AppInfo.lpZBuffer) + { + assert(AppInfo.lpBackBuffer); + AppInfo.lpBackBuffer->DeleteAttachedSurface(0, AppInfo.lpZBuffer); + RELEASE(AppInfo.lpZBuffer); + } + + if (AppInfo.lpFrontBuffer) + AppInfo.lpFrontBuffer->SetClipper(NULL); + + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); + + D3DMain_RestoreDisplayMode(); + + RELEASE(AppInfo.lpD3D); + RELEASE(AppInfo.lpDD); + + memset(&AppInfo, 0, sizeof(App_Info)); + + D3DMain_Log(" Shutdown was successful...\n\n"); + + return TRUE; +} + +extern uint32 CurrentLRU; +//================================================================================ +//================================================================================ +geBoolean D3DMain_Reset(void) +{ + THandle_Shutdown(); + PCache_Reset(); + + if (!THandle_Startup()) + return GE_FALSE; + + CurrentLRU = 0; + + return GE_TRUE; +} + +//================================================================================ +// D3DMain_Log +//================================================================================ +void D3DMain_Log(LPSTR Str, ... ) +{ + char Buffer[2048]; + FILE *f; + + wvsprintf(Buffer, Str, (char*)(&Str+1)); + + f = fopen(D3DMAIN_LOG_FILENAME, "a+t"); + + if (!f) + return; + + fprintf(f, "%s", Buffer); + + fclose(f); +} + +//================================================================================ +// CompareModes +//================================================================================ +static int CompareModes(const void* element1, const void* element2) +{ + App_Mode *lpMode1, *lpMode2; + + lpMode1 = (App_Mode*)element1; + lpMode2 = (App_Mode*)element2; + + if (lpMode1->Bpp > lpMode2->Bpp) + return -1; + else if (lpMode2->Bpp > lpMode1->Bpp) + return 1; + else if (lpMode1->Width > lpMode2->Width) + return -1; + else if (lpMode2->Width > lpMode1->Width) + return 1; + else if (lpMode1->Height > lpMode2->Height) + return -1; + else if (lpMode2->Height > lpMode1->Height) + return 1; + else + return 0; +} + +//================================================================================ +// EnumDisplayModesCallback +//================================================================================ +static HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC2 pddsd, LPVOID lpContext) +{ + App_Mode *pMode; + + if (!pddsd) + return DDENUMRET_OK; + + if (pddsd->dwWidth > 1024 || pddsd->dwHeight > 768) + return DDENUMRET_OK; + + if (AppInfo.NumModes >= MAX_APP_MODES) + return DDENUMRET_CANCEL; + + pMode = &AppInfo.Modes[AppInfo.NumModes++]; + + // Save this mode at the end of the mode array and increment mode count + pMode->Width = pddsd->dwWidth; + pMode->Height = pddsd->dwHeight; + pMode->Bpp = pddsd->ddpfPixelFormat.dwRGBBitCount; + pMode->ThisDriverCanDo = FALSE; + + return DDENUMRET_OK; +} + +//================================================================================ +// D3DMain_EnumDisplayModes +//================================================================================ +BOOL D3DMain_EnumDisplayModes(void) +{ + HRESULT LastError; + + D3DMain_Log("--- D3DMain_EnumDisplayModes ---\n"); + + // Get a list of available display modes from DirectDraw + AppInfo.NumModes = 0; + + LastError = AppInfo.lpDD->EnumDisplayModes(0, NULL, 0, EnumDisplayModesCallback); + + if(LastError != DD_OK ) + { + D3DMain_Log("EnumDisplayModes failed.\n %s\n", D3DErrorToString(LastError)); + AppInfo.NumModes = 0; + return FALSE; + } + + // Sort the list of display modes + qsort((void *)&AppInfo.Modes[0], (size_t)AppInfo.NumModes, sizeof(App_Mode), CompareModes); + + return TRUE; +} + + + +//================================================================================ +// D3DMain_CreateD3D +//================================================================================ +static BOOL D3DMain_CreateD3D(void) +{ + HRESULT LastError; + + assert(AppInfo.lpDD); + + D3DMain_Log("--- D3DMain_CreateD3D ---\n"); + + LastError = AppInfo.lpDD->QueryInterface(IID_IDirect3D3, (LPVOID*)&AppInfo.lpD3D); + + if (LastError != DD_OK) + { + D3DMain_Log("Creation of IDirect3D failed.\n %s\n", D3DErrorToString(LastError)); + goto exit_with_error; + } + + return TRUE; + + exit_with_error: + return FALSE; +} +/* +#define MUST_BLEND (D3DPBLENDCAPS_BOTHINVSRCALPHA | \ + D3DPBLENDCAPS_BOTHSRCALPHA | \ + D3DPBLENDCAPS_DESTALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_INVDESTALPHA | \ + D3DPBLENDCAPS_INVDESTCOLOR | \ + D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_INVSRCCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_SRCALPHASAT | \ + D3DPBLENDCAPS_SRCCOLOR | \ + D3DPBLENDCAPS_ZERO) +*/ +#if 0 +#define MUST_BLEND_SRC (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#define MUST_BLEND_DEST (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_SRCCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#else +#define MUST_BLEND_SRC (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#define MUST_BLEND_DEST (D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) +#endif + +//================================================================================ +// EnumDeviceFunc +//================================================================================ +static HRESULT WINAPI EnumDeviceFunc(LPGUID lpGuid, LPSTR lpDeviceDescription, + LPSTR lpDeviceName, LPD3DDEVICEDESC lpHWDesc, + LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext) +{ + DDMain_D3DDriver *Driver; + BOOL Good; + + if (!lpGuid|| !lpDeviceDescription || !lpDeviceName || !lpHWDesc || !lpHELDesc) + return (D3DENUMRET_OK); + + if (strlen(lpDeviceDescription) >= MAX_DRIVER_NAME) + return (D3DENUMRET_OK); + + if (strlen(lpDeviceName) >= MAX_DRIVER_NAME) + return (D3DENUMRET_OK); + + lpContext = lpContext; + + Good = TRUE; + + AppInfo.CurrentDriver = AppInfo.NumDrivers; + + Driver = &AppInfo.Drivers[AppInfo.NumDrivers]; + + // Record the D3D driver's inforamation + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Guid, lpGuid, sizeof(GUID)); + lstrcpy(AppInfo.Drivers[AppInfo.NumDrivers].About, lpDeviceDescription); + lstrcpy(AppInfo.Drivers[AppInfo.NumDrivers].Name, lpDeviceName); + + // Is this a hardware device or software emulation? Checking the color + // model for a valid model works. + if (lpHWDesc->dcmColorModel) + { + AppInfo.Drivers[AppInfo.NumDrivers].IsHardware = TRUE; + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHWDesc, sizeof(D3DDEVICEDESC)); + } + else + { + // Skip if this is not a hardware driver + AppInfo.Drivers[AppInfo.NumDrivers].IsHardware = FALSE; + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHELDesc, sizeof(D3DDEVICEDESC)); + Good = FALSE; + } + + LPD3DDEVICEDESC Desc = &AppInfo.Drivers[AppInfo.NumDrivers].Desc; + + Driver->MaxTextureBlendStages = Desc->wMaxTextureBlendStages; + Driver->MaxSimultaneousTextures = Desc->wMaxSimultaneousTextures; + + if (!(Desc->dwDeviceZBufferBitDepth)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesZBuffer = TRUE; + + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesTextures = TRUE; + + // Skip if it does not support alpha blending + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHA)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesAlpha = TRUE; + + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_TRANSPARENCY)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesTransparency = TRUE; + + //if (!(lpHWDesc->dpcTriCaps.dwTextureAddressCaps & D3DPTADDRESSCAPS_CLAMP)) + // Good = FALSE; + //else + AppInfo.Drivers[AppInfo.NumDrivers].DoesClamping = TRUE; + + if ((Desc->dpcTriCaps.dwSrcBlendCaps & MUST_BLEND_SRC) != MUST_BLEND_SRC) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesSrcBlending = TRUE; + + if ((Desc->dpcTriCaps.dwDestBlendCaps & MUST_BLEND_DEST) != MUST_BLEND_DEST) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesDestBlending = TRUE; + + // Stop as soon as we find a driver that can render into a window + if ((Desc->dwDeviceRenderBitDepth & BPPToDDBD(AppInfo.OldBpp)) && AppInfo.IsPrimary && Good) + { + AppInfo.Drivers[AppInfo.NumDrivers].CanDoWindow = TRUE; + AppInfo.CanDoWindow = TRUE; + } + else + AppInfo.Drivers[AppInfo.NumDrivers].CanDoWindow = FALSE; + + // Store if we can use this driver + AppInfo.Drivers[AppInfo.NumDrivers].CanUse = Good; + + #if 0 + if (AppInfo.LogToFile) + OutputDriverInfo(D3DMAIN_LOG_FILENAME, &AppInfo.Drivers[AppInfo.NumDrivers]); + #endif + + if (!Good) + return (D3DENUMRET_OK); + + // Tell global structure that we found a good device + AppInfo.FoundGoodDevice = TRUE; + + // If all was good, increment the number of drivers + AppInfo.NumDrivers++; + + if (AppInfo.NumDrivers+1 >= DDMAIN_MAX_D3D_DRIVERS) + return (D3DENUMRET_CANCEL); + + return (D3DENUMRET_OK); +} + +//================================================================================ +// EnumDevices +//================================================================================ +static BOOL D3DMain_EnumDevices(void) +{ + HRESULT LastError; + + D3DMain_Log("--- D3DMain_EnumDevices ---\n"); + + AppInfo.NumDrivers = 0; + + LastError = AppInfo.lpD3D->EnumDevices(EnumDeviceFunc, NULL); + + if (LastError != DD_OK) + { + D3DMain_Log("Enumeration of drivers failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + + AppInfo.CurrentDriver = 0; + + return TRUE; +} + +//================================================================================ +// CreateSurface +//================================================================================ +static HRESULT CreateSurface(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE4 FAR *lpDDSurface) +{ + HRESULT Result; + + //if (AppInfo.OnlySystemMemory) + // lpDDSurfDesc->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + + Result = AppInfo.lpDD->CreateSurface(lpDDSurfDesc, lpDDSurface, NULL); + + return Result; +} + +//================================================================================ +// GetSurfDesc +//================================================================================ +static HRESULT GetSurfDesc(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE4 lpDDSurf) +{ + HRESULT Result; + + memset(lpDDSurfDesc, 0, sizeof(DDSURFACEDESC2)); + + lpDDSurfDesc->dwSize = sizeof(DDSURFACEDESC2); + + Result = lpDDSurf->GetSurfaceDesc(lpDDSurfDesc); + + return Result; +} + +//================================================================================ +// D3DMain_CreateViewPort +//================================================================================ +static BOOL D3DMain_CreateViewPort(int w, int h) +{ + LPDIRECT3DVIEWPORT3 lpD3DViewport; + HRESULT rval; + + D3DMain_Log("--- D3DMain_CreateViewPort ---\n"); + + // Create the D3D viewport object + rval = AppInfo.lpD3D->CreateViewport(&lpD3DViewport, NULL); + + if (rval != D3D_OK) + { + D3DMain_Log("Create D3D viewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Add the viewport to the D3D device + rval = AppInfo.lpD3DDevice->AddViewport(lpD3DViewport); + if (rval != D3D_OK) + { + D3DMain_Log("Add D3D viewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Setup the viewport for a reasonable viewing area + D3DVIEWPORT2 viewData; + + memset(&viewData, 0, sizeof(D3DVIEWPORT2)); + viewData.dwSize = sizeof(D3DVIEWPORT2); + viewData.dwX = viewData.dwY = 0; + viewData.dwWidth = w; + viewData.dwHeight = h; + viewData.dvClipX = -1.0f; + viewData.dvClipWidth = 2.0f; + viewData.dvClipHeight = h * 2.0f / w; + viewData.dvClipY = viewData.dvClipHeight / 2.0f; + viewData.dvMinZ = 0.0f; + viewData.dvMaxZ = 1.0f; + + rval = lpD3DViewport->SetViewport2(&viewData); + if (rval != D3D_OK) + { + D3DMain_Log("SetViewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + AppInfo.lpD3DViewport = lpD3DViewport; + + // Create the material that will be used for the background + { + D3DMATERIAL Material; + D3DMATERIALHANDLE MatHandle; + + // Create the material + rval = AppInfo.lpD3D->CreateMaterial(&AppInfo.BackgroundMaterial, NULL ); + + if (rval != D3D_OK) + { + D3DMain_Log("D3DMain_CreateViewPort: CreateMaterial failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Fill in the material with the data + memset(&Material, 0, sizeof(D3DMATERIAL)); + + Material.dwSize = sizeof(D3DMATERIAL); + Material.dcvDiffuse.r = Material.dcvAmbient.r = 255.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = 255.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = 255.0f; + Material.dwRampSize = 16L; // A default ramp size + + AppInfo.BackgroundMaterial->SetMaterial(&Material); + + // Attach the material to the viewport + AppInfo.BackgroundMaterial->GetHandle( AppInfo.lpD3DDevice, &MatHandle); + AppInfo.lpD3DViewport->SetBackground(MatHandle); + } + + return TRUE; +} + +//================================================================================ +// EnumTextureFormatsCallback +// Record information about each texture format the current D3D driver can +// support. Choose one as the default format and return it through lpContext. +//================================================================================ +static HRESULT CALLBACK EnumTextureFormatsCallback(LPDDPIXELFORMAT lpddpfPixelFormat, LPVOID lpContext) +{ + DDMain_SurfFormat *pTexFormat; + + if(!lpddpfPixelFormat) + return DDENUMRET_OK; + + if (AppInfo.NumTextureFormats+1 >= DDMAIN_MAX_TEXTURE_FORMATS ) + { + return DDENUMRET_CANCEL; + } + + pTexFormat = &AppInfo.TextureFormats[AppInfo.NumTextureFormats]; + + // Clear out this texture format slot + memset(pTexFormat, 0, sizeof(DDMain_SurfFormat)); + + if(lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + { + if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0x8000) + { + if(lpddpfPixelFormat->dwRBitMask != 0x7c00 || + lpddpfPixelFormat->dwGBitMask != 0x3e0 || + lpddpfPixelFormat->dwBBitMask != 0x1f) + return DDENUMRET_OK; + + pTexFormat->HasOneBitAlpha = TRUE; + pTexFormat->HasFourBitAlpha = FALSE; + } + else if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0xf000) + { + if(lpddpfPixelFormat->dwRBitMask != 0xf00 || + lpddpfPixelFormat->dwGBitMask != 0xf0 || + lpddpfPixelFormat->dwBBitMask != 0xf) + return DDENUMRET_OK; + + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = TRUE; + } + else + { + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = FALSE; + } + } + else + { + if(!(lpddpfPixelFormat->dwFlags & DDPF_RGB)) + return DDENUMRET_OK; + + #if 0 + if(lpddpfPixelFormat->dwRGBBitCount != 16) + return DDENUMRET_OK; + + if( (lpddpfPixelFormat->dwRBitMask != 0xf800 && lpddpfPixelFormat->dwRBitMask != 0x7c00) || + (lpddpfPixelFormat->dwGBitMask != 0x7e0 && lpddpfPixelFormat->dwGBitMask != 0x3e0) || + (lpddpfPixelFormat->dwBBitMask != 0x1f)) + return DDENUMRET_OK; + #endif + + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = FALSE; + } + + // Record the PixelFormat of this texture + memcpy(&pTexFormat->ddsd.ddpfPixelFormat, lpddpfPixelFormat, sizeof(DDPIXELFORMAT)); + + AppInfo.NumTextureFormats++; + + return DDENUMRET_OK; +} + +//================================================================================ +// Main_EnumTextureFormats +// Get a list of available texture map formats from the Direct3D driver by +// enumeration. Choose a default format. +//================================================================================ +BOOL Main_EnumTextureFormats(void) +{ + HRESULT LastError; + + assert(AppInfo.lpD3DDevice); + + AppInfo.NumTextureFormats = 0; + + LastError = AppInfo.lpD3DDevice->EnumTextureFormats(EnumTextureFormatsCallback, NULL); + + if (LastError != DD_OK) + { + D3DMain_Log("Main_EnumTextureFormats: Enumeration of texture formats failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + + +//================================================================================ +// EnumSurfaceFormatsCallback +//================================================================================ +HRESULT WINAPI EnumSurfaceFormatsCallback(LPDIRECTDRAWSURFACE4 lpDDSurface, LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext) +{ + LPDDPIXELFORMAT lpddpfPixelFormat; + DDMain_SurfFormat *pSurfFormat; + + // Don't need this. + RELEASE(lpDDSurface); + + lpddpfPixelFormat = &lpDDSurfaceDesc->ddpfPixelFormat; + + if(!lpddpfPixelFormat) + return DDENUMRET_OK; + + if (AppInfo.NumSurfFormats+1 >= DDMAIN_MAX_SURFACE_FORMATS ) + return DDENUMRET_CANCEL; + + pSurfFormat = &AppInfo.SurfFormats[AppInfo.NumSurfFormats]; + + // Clear out this texture format slot + memset(pSurfFormat, 0, sizeof(DDMain_SurfFormat)); + + if(lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + { + if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0x8000) + { + // 1555 + if(lpddpfPixelFormat->dwRBitMask != 0x7c00 || + lpddpfPixelFormat->dwGBitMask != 0x3e0 || + lpddpfPixelFormat->dwBBitMask != 0x1f) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = TRUE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + else if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0xf000) + { + // 4444 + if(lpddpfPixelFormat->dwRBitMask != 0xf00 || + lpddpfPixelFormat->dwGBitMask != 0xf0 || + lpddpfPixelFormat->dwBBitMask != 0xf) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = TRUE; + } + else + { + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + } + else + { + if(!(lpddpfPixelFormat->dwFlags & DDPF_RGB)) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + + // Record the PixelFormat of this texture + memcpy(&pSurfFormat->ddsd.ddpfPixelFormat, lpddpfPixelFormat,sizeof(DDPIXELFORMAT)); + + AppInfo.NumSurfFormats++; + + return DDENUMRET_OK; +} + +//================================================================================ +// Main_EnumSurfaceFormats +//================================================================================ +BOOL Main_EnumSurfaceFormats(void) +{ + HRESULT LastError; + + assert(AppInfo.lpDD); + + AppInfo.NumSurfFormats = 0; + + LastError = AppInfo.lpDD->EnumSurfaces(DDENUMSURFACES_DOESEXIST|DDENUMSURFACES_ALL, + NULL, NULL, EnumSurfaceFormatsCallback); + + if (LastError != DD_OK) + { + D3DMain_Log("Main_EnumSurfaceFormats: Enumeration of texture formats failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + + +//----------------------------------------------------------------------------- +// Name: EnumZBufferFormatsCallback() +// Desc: Enumeration function to report valid pixel formats for z-buffers. +//----------------------------------------------------------------------------- +static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf, + VOID* pddpfDesired ) +{ + if( NULL==pddpf || NULL==pddpfDesired ) + return D3DENUMRET_CANCEL; + + // If the current pixel format's match the desired ones (DDPF_ZBUFFER and + // possibly DDPF_STENCILBUFFER), lets copy it and return. This function is + // not choosy...it accepts the first valid format that comes along. + if( pddpf->dwFlags == ((DDPIXELFORMAT*)pddpfDesired)->dwFlags ) + { + memcpy( pddpfDesired, pddpf, sizeof(DDPIXELFORMAT) ); + + // We're happy with a 16-bit z-buffer. Otherwise, keep looking. + if( pddpf->dwZBufferBitDepth == 16 ) + return D3DENUMRET_CANCEL; + } + + return D3DENUMRET_OK; +} + +//================================================================================ +// D3DMain_ClearBuffers +//================================================================================ +static BOOL D3DMain_ClearBuffers(void) +{ + DDSURFACEDESC2 ddsd; + RECT dst; + DDBLTFX ddbltfx; + HRESULT LastError; + + // Find the width and height of the front buffer by getting its + // DDSURFACEDESC2 + if (AppInfo.lpFrontBuffer) + { + LastError = GetSurfDesc(&ddsd, AppInfo.lpFrontBuffer); + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_ClearBuffers: Failure getting the surface description of the front buffer before clearing.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + // Clear the front buffer to black + memset(&ddbltfx, 0, sizeof(ddbltfx)); + //memset(&ddbltfx, 0xffffff, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(DDBLTFX); + SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight); + + LastError = AppInfo.lpFrontBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, + &ddbltfx); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("D3DMain_ClearBuffers: D3DMain_RestoreAllSurfaces failed...\n"); + return FALSE; + } + } + else + { + D3DMain_Log("D3DMain_ClearBuffers: Clearing the front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + } + + if (AppInfo.lpBackBuffer) + { + // Find the width and height of the back buffer by getting its + // DDSURFACEDESC2 + + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_ClearBuffers: Failure while getting the surface description of the back buffer before clearing.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + // Clear the back buffer to black + memset(&ddbltfx, 0, sizeof(ddbltfx)); + //memset(&ddbltfx, 0xffffff, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(DDBLTFX); + SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight); + LastError = AppInfo.lpBackBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, + &ddbltfx); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("D3DMain_ClearBuffers: D3DMain_RestoreAllSurfaces failed.\n"); + return FALSE; + } + } + else + { + D3DMain_Log("D3DMain_ClearBuffers: Clearing the back buffer failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + } + + return TRUE; +} + +//================================================================================ +// Main_ShowBackBuffer +//================================================================================ +BOOL Main_ShowBackBuffer(void) +{ + HRESULT LastError; + + if (!AppInfo.RenderingIsOK) + return TRUE; + + if (AppInfo.FullScreen) + { + // Flip the back and front buffers + #if 1 + LastError = AppInfo.lpFrontBuffer->Flip(AppInfo.lpBackBuffer, DDFLIP_WAIT); + #else + LastError = AppInfo.lpFrontBuffer->Flip(AppInfo.lpBackBuffer, DDFLIP_NOVSYNC); + #endif + + if (LastError == DDERR_SURFACELOST) + { + D3DMain_RestoreAllSurfaces(); + //AppInfo.lpFrontBuffer->Restore(); + //AppInfo.lpBackBuffer->Restore(); + + D3DMain_ClearBuffers(); + + } + else if (LastError == DDERR_WASSTILLDRAWING) + { + } + else if (LastError != DD_OK) + { + D3DMain_Log("Flipping complex display surface failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + } + else + { + RECT FRect, BRect; + + FRect.left = AppInfo.WindowXOffset; + FRect.right = FRect.left + AppInfo.CurrentWidth; + FRect.top = AppInfo.WindowYOffset; + FRect.bottom = FRect.top + AppInfo.CurrentHeight; + + BRect.left = 0; + BRect.right = AppInfo.CurrentWidth; + BRect.top = 0; + BRect.bottom = AppInfo.CurrentHeight; + + LastError = AppInfo.lpFrontBuffer->Blt(&FRect, AppInfo.lpBackBuffer, + &BRect, DDBLT_WAIT, NULL); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("Main_ShowBackBuffer: D3DMain_RestoreAllSurfaces.\n"); + return FALSE; + } + } + else + { + D3DMain_Log("Main_ShowBackBuffer: Blt of back buffer to front buffer failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + } + } + + return TRUE; +} + +//================================================================================ +// Main_ClearBackBuffer +//================================================================================ +BOOL Main_ClearBackBuffer(BOOL Clear, BOOL ClearZ) +{ + int ClearFlags; + D3DRECT Dummy; + HRESULT LastError; + + if (!AppInfo.RenderingIsOK) + return TRUE; + + // Default to clear nothing + ClearFlags = 0; + + // Then set in what callers wants to clear + if (Clear) + ClearFlags |= D3DCLEAR_TARGET; + + if (ClearZ) + ClearFlags |= D3DCLEAR_ZBUFFER; + + Dummy.x1 = Dummy.y1 = 0; + Dummy.x2 = AppInfo.CurrentWidth; + Dummy.y2 = AppInfo.CurrentHeight; + + LastError = AppInfo.lpD3DViewport->Clear(1, &Dummy, ClearFlags); + + if (LastError != D3D_OK) + { + D3DMain_Log("Viewport clear failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + +//================================================================================ +// Surface manipulation +//================================================================================ + +typedef struct +{ + unsigned char r, g, b; +} MY_D3D_RGB; + +typedef struct +{ + DWORD R_Shift; + DWORD G_Shift; + DWORD B_Shift; + DWORD A_Shift; + + DWORD R_Mask; + DWORD G_Mask; + DWORD B_Mask; + DWORD A_Mask; + + DWORD R_Width; + DWORD G_Width; + DWORD B_Width; + DWORD A_Width; +} D3D_PixelMask; + +//================================================================================ +// GetSurfacePixelMask +//================================================================================ +static void GetSurfacePixelMask(DDSURFACEDESC2 *ddsd, D3D_PixelMask *PixelMask) +{ + DWORD red_mask, grn_mask, blu_mask, a_mask; + DWORD red_shift, grn_shift, blu_shift, a_shift; + DWORD red_width, grn_width, blu_width, a_width; + int i; + + red_mask = ddsd->ddpfPixelFormat.dwRBitMask; + grn_mask = ddsd->ddpfPixelFormat.dwGBitMask; + blu_mask = ddsd->ddpfPixelFormat.dwBBitMask; + a_mask = ddsd->ddpfPixelFormat.dwRGBAlphaBitMask; + + // + // Derive shift, width values from masks + // + + for (i=31; i >= 0; i--) + { + if (red_mask & (1 << i)) + red_shift = i; + + if (grn_mask & (1 << i)) + grn_shift = i; + + if (blu_mask & (1 << i)) + blu_shift = i; + + if (a_mask & (1 << i)) + a_shift = i; + } + + for (i=0; i <= 31; i++) + { + if (red_mask & (1 << i)) + red_width = i - red_shift + 1; + + if (grn_mask & (1 << i)) + grn_width = i - grn_shift + 1; + + if (blu_mask & (1 << i)) + blu_width = i - blu_shift + 1; + + if (a_mask & (1 << i)) + a_width = i - a_shift + 1; + } + // + // Pass all requested values back to the caller + // + + PixelMask->R_Shift = red_shift; + PixelMask->G_Shift = grn_shift; + PixelMask->B_Shift = blu_shift; + PixelMask->A_Shift = a_shift; + + PixelMask->R_Mask = red_mask; + PixelMask->G_Mask = grn_mask; + PixelMask->B_Mask = blu_mask; + PixelMask->A_Mask = a_mask; + + PixelMask->R_Width = red_width; + PixelMask->G_Width = grn_width; + PixelMask->B_Width = blu_width; + PixelMask->A_Width = a_width; +} + +//================================================================================ +// MyRGB +//================================================================================ +static unsigned int MyRGB(DWORD R, DWORD G, DWORD B, D3D_PixelMask *PixelMask) +{ + DWORD R_Left, G_Left, B_Left; + DWORD R_Right, G_Right, B_Right; + + + // Get shift constants for current video mode + R_Left = PixelMask->R_Shift; + G_Left = PixelMask->G_Shift; + B_Left = PixelMask->B_Shift; + + R_Right = 8 - PixelMask->R_Width; + G_Right = 8 - PixelMask->G_Width; + B_Right = 8 - PixelMask->B_Width; + // Shift R,G, and B into one value + return( + (((((unsigned int) R) >> R_Right) << R_Left) & PixelMask->R_Mask) | + (((((unsigned int) G) >> G_Right) << G_Left) & PixelMask->G_Mask) | + (((((unsigned int) B) >> B_Right) << B_Left) & PixelMask->B_Mask) + ); +} + +//========================================================================================== +// D3DMain_GetSurfaceFormats +//========================================================================================== +BOOL D3DMain_GetSurfaceFormats(void) +{ + int32 i; + + D3DMain_Log("--- D3DMain_GetSurfaceFormats ---\n"); + + if (!Main_EnumTextureFormats()) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Main_EnumTextureFormats failed.\n"); + return FALSE; + } + + if (!Main_EnumSurfaceFormats()) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Main_EnumSurfaceFormats failed.\n"); + return FALSE; + } + +#if 1 + for(i = 0; i < AppInfo.NumSurfFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + lpddpfPixelFormat = &AppInfo.SurfFormats[i].ddsd.ddpfPixelFormat; + + if(lpddpfPixelFormat->dwRGBBitCount != AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount) + continue; + + if (lpddpfPixelFormat->dwRGBAlphaBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask) + continue; + if (lpddpfPixelFormat->dwRBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRBitMask) + continue; + if (lpddpfPixelFormat->dwGBitMask != AppInfo.ddsd.ddpfPixelFormat.dwGBitMask) + continue; + if (lpddpfPixelFormat->dwBBitMask != AppInfo.ddsd.ddpfPixelFormat.dwBBitMask) + continue; + + #if 0 // For debugging (This is the surface it is going to use for 2d decals) + D3DMain_Log("Bits: %i, A:%x, R:%x, G:%x, B:%x\n", AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount, + AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwRBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwGBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwBBitMask); + return FALSE; + #endif + + + AppInfo.ddSurfFormat = AppInfo.SurfFormats[i].ddsd; + + break; + } + + if(i == AppInfo.NumSurfFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find a 2d surface format that matches current bit depth.\n"); + return FALSE; + } + +#else + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + lpddpfPixelFormat = &AppInfo.TextureFormats[i].ddsd.ddpfPixelFormat; + + if(lpddpfPixelFormat->dwRGBBitCount != AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount) + continue; + + if (lpddpfPixelFormat->dwRGBAlphaBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask) + continue; + if (lpddpfPixelFormat->dwRBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRBitMask) + continue; + if (lpddpfPixelFormat->dwGBitMask != AppInfo.ddsd.ddpfPixelFormat.dwGBitMask) + continue; + if (lpddpfPixelFormat->dwBBitMask != AppInfo.ddsd.ddpfPixelFormat.dwBBitMask) + continue; + + #if 0 // For debugging (This is the surface it is going to use for 2d decals) + D3DMain_Log("Bits: %i, A:%x, R:%x, G:%x, B:%x\n", AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount, + AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwRBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwGBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwBBitMask); + return FALSE; + #endif + + + AppInfo.ddSurfFormat = AppInfo.TextureFormats[i].ddsd; + + break; + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find a 2d surface format that matches current bit depth.\n"); + return FALSE; + } +#endif + + // Now get the 3d surface formats + + // Get 1555 + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + if(AppInfo.TextureFormats[i].HasOneBitAlpha == TRUE) + { + AppInfo.ddOneBitAlphaSurfFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 1555 texture support.\n"); + return FALSE; + } + + // Get 4444 + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + if(AppInfo.TextureFormats[i].HasFourBitAlpha == TRUE) + { + AppInfo.ddFourBitAlphaSurfFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 4444 texture support.\n"); + return FALSE; + } + + // Get either 555, or 565. + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + if(AppInfo.TextureFormats[i].HasOneBitAlpha == TRUE) + continue; + + if (AppInfo.TextureFormats[i].HasFourBitAlpha == TRUE) + continue; + + lpddpfPixelFormat = &AppInfo.TextureFormats[i].ddsd.ddpfPixelFormat; + + // For now, force 3d textures with RGB only info to be either 565 or 555 + // We could enum all formats and let the caller pick between several different RGB formats... + if (lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + continue; // We don't want any surface that has alpha, just pure RGB... + + if(lpddpfPixelFormat->dwRGBBitCount != 16) + continue; + + if( (lpddpfPixelFormat->dwRBitMask != 0xf800 && lpddpfPixelFormat->dwRBitMask != 0x7c00) || + (lpddpfPixelFormat->dwGBitMask != 0x7e0 && lpddpfPixelFormat->dwGBitMask != 0x3e0) || + (lpddpfPixelFormat->dwBBitMask != 0x1f)) + continue; + + + // This is it + AppInfo.ddTexFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 555 or 565 texture support.\n"); + return FALSE; + } + + Main_BuildRGBGammaTables(1.0f); + + return TRUE; +} + +//========================================================================================== +// Main_CheckDD +// Checks to see if current DD driver has any usable D3D Devices... +//========================================================================================== +BOOL Main_CheckDD(void) +{ + AppInfo.NumDrivers = 0; + AppInfo.CurrentDriver = 0; + AppInfo.FoundGoodDevice = FALSE; + AppInfo.CanDoWindow = FALSE; + + assert(AppInfo.lpDD); + + if (!D3DMain_RememberOldMode(GetDesktopWindow())) + return FALSE; + + memset(AppInfo.Drivers, 0, sizeof(DDMain_D3DDriver)*DDMAIN_MAX_D3D_DRIVERS); + + if (!D3DMain_CreateD3D()) + return FALSE; + + if (!D3DMain_EnumDevices()) // See if we can enumerate at least one good device for this DD Driver + return FALSE; + + if (!AppInfo.FoundGoodDevice) // Return FALSE if not... + return FALSE; + + return TRUE; // Found at least one!!! +} + +//========================================================================================== +// OutputDriverInfo +//========================================================================================== +static BOOL OutputDriverInfo(const char *FileName, DDMain_D3DDriver *Driver) +{ + FILE *f; + SYSTEMTIME Time; + char YesNo[2][10]; + + f = fopen(FileName, "a+t"); + + if (!f) + return FALSE; + + GetSystemTime(&Time); + + strcpy(YesNo[0], "No\n"); + strcpy(YesNo[1], "Yes\n"); + + fprintf(f,"=================================================================\n"); + fprintf(f,"Time: %2i:%2i:%2i\n", Time.wHour, Time.wMinute, Time.wSecond); + fprintf(f,"Date: %2i-%2i-%4i\n", Time.wMonth, Time.wDay, Time.wYear); + + fprintf(f, "DirectDraw Name: \n"); + fprintf(f, " %s\n", AppInfo.DDName); + + fprintf(f, "D3D Driver Name: \n"); + fprintf(f, " %s\n", Driver->Name); + + fprintf(f, "D3D Driver Description: \n"); + fprintf(f, " %s\n", Driver->About); + + fprintf(f, "3D Acceleration : %s", YesNo[Driver->IsHardware]); + fprintf(f, "Texture Support : %s", YesNo[Driver->DoesTextures]); + fprintf(f, "Transparency Support : %s", YesNo[Driver->DoesTransparency]); + fprintf(f, "Alpha Support : %s", YesNo[Driver->DoesAlpha]); + fprintf(f, "UV Clamping Support : %s", YesNo[Driver->DoesClamping]); + fprintf(f, "Src Blending Support : %s", YesNo[Driver->DoesSrcBlending]); + fprintf(f, "Dest Blending Support : %s", YesNo[Driver->DoesDestBlending]); + fprintf(f, "Window Support : %s", YesNo[Driver->CanDoWindow]); + fprintf(f, "Can Use : %s", YesNo[Driver->CanUse]); + + fclose(f); + + return TRUE; +} + +//========================================================================================== +// D3DMain_GetTextureMemory +//========================================================================================== +BOOL D3DMain_GetTextureMemory(void) +{ + + DDSCAPS2 ddsCaps; + DWORD dwTotal; + DWORD dwFree; + HRESULT Error; + + D3DMain_Log("--- D3DMain_GetTextureMemory ---\n"); + + memset(&ddsCaps, 0, sizeof(ddsCaps)); + + //ddsCaps.dwSize = sizeof(DDSCAPS2); + ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + + Error = AppInfo.lpDD->GetAvailableVidMem(&ddsCaps, &dwTotal, &dwFree); + + if(Error !=DD_OK) + { + D3DMain_Log("Getting DD capabilities failed while checking total video memory.\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + AppInfo.VidMemFree = dwFree; + + D3DMain_Log(" Ram free: %i\n", AppInfo.VidMemFree); + + return TRUE; +} + + +//========================================================================================== +//========================================================================================== +void Main_BuildRGBGammaTables(geFloat Gamma) +{ + int32 i, Val; + int32 GammaTable[256]; + D3D_PixelMask PixelMask; + DWORD R_Left, G_Left, B_Left, A_Left; + DWORD R_Right, G_Right, B_Right, A_Right; + + + AppInfo.Gamma = Gamma; + + if (Gamma == 1.0) + { + for (i=0 ; i<256 ; i++) + GammaTable[i] = i; + } + else for (i=0 ; i<256 ; i++) + { + geFloat Ratio = (i+0.5f)/255.5f; + + geFloat RGB = (geFloat)(255.0 * pow((double)Ratio, 1.0/(double)Gamma) + 0.5); + + if (RGB < 0.0f) + RGB = 0.0f; + if (RGB > 255.0f) + RGB = 255.0f; + + GammaTable[i] = (int32)RGB; + } + + GetSurfacePixelMask(&AppInfo.ddTexFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut1.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut1.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut1.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut1.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } + GetSurfacePixelMask(&AppInfo.ddFourBitAlphaSurfFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut2.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut2.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut2.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut2.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } + GetSurfacePixelMask(&AppInfo.ddOneBitAlphaSurfFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut3.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut3.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut3.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut3.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } +} + +//==================================================================================================== +// D3DMain_UpdateWindow +//==================================================================================================== +geBoolean DRIVERCC D3DMain_UpdateWindow(void) +{ + D3DMain_GetClientWindowOffset(AppInfo.hWnd); + return GE_TRUE; +} + +//==================================================================================================== +// D3DMain_SetActive +//==================================================================================================== +geBoolean DRIVERCC D3DMain_SetActive(geBoolean wParam) +{ + if (AppInfo.lpFrontBuffer) + AppInfo.RenderingIsOK = wParam; + + if(AppInfo.RenderingIsOK) // Regaining focus + { + HRESULT Result; + + if (AppInfo.lpFrontBuffer) + { + Result = AppInfo.lpFrontBuffer->IsLost(); + + if(Result == DDERR_SURFACELOST) + { + if(!D3DMain_RestoreAllSurfaces()) + { + OutputDebugString("Couldn't restore surfaces!\n"); + return GE_FALSE; + } + + OutputDebugString("D3DMain_SetActive: Regained Focus...\n"); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); // Dx doesn't restore it + } + else + OutputDebugString("D3DMain_SetActive: No surfaces lost...\n"); + } + } + + return GE_TRUE; +} + +//======================================================================================================== +// D3DMain_SetFogEnable +//======================================================================================================== +geBoolean DRIVERCC D3DMain_SetFogEnable(geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End) +{ + D3DMATERIAL Material; + + AppInfo.FogEnable = Enable; + AppInfo.FogR = r; + AppInfo.FogG = g; + AppInfo.FogB = b; + AppInfo.FogStart = Start; + AppInfo.FogEnd = End; + + // Fill in the material with the data + memset(&Material, 0, sizeof(D3DMATERIAL)); + + Material.dwSize = sizeof(D3DMATERIAL); + + if (Enable) + { + Material.dcvDiffuse.r = Material.dcvAmbient.r = r/255.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = g/255.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = b/255.0f; + } + else + { + Material.dcvDiffuse.r = Material.dcvAmbient.r = 0.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = 0.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = 0.0f; + } + + Material.dwRampSize = 16L; // A default ramp size + + AppInfo.BackgroundMaterial->SetMaterial(&Material); + + return GE_TRUE; +} + +//================================================================================ +// D3DMain_GetClientWindowOffset +//================================================================================ +BOOL D3DMain_GetClientWindowOffset(HWND hWnd) +{ + POINT CPoint; + + CPoint.x = CPoint.y = 0; + + ClientToScreen(hWnd, &CPoint); + + AppInfo.WindowXOffset = CPoint.x; + AppInfo.WindowYOffset = CPoint.y; + + return TRUE; +} + +//================================================================================ +// D3DMain_RememberOldMode +//================================================================================ +static BOOL D3DMain_RememberOldMode(HWND hWnd) +{ + DDSURFACEDESC2 ddsd; + HRESULT LastError; + RECT CRect; + + D3DMain_Log("--- D3DMain_RememberOldMode ---\n"); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + + LastError = AppInfo.lpDD->GetDisplayMode(&ddsd); + + if (LastError != DD_OK) + { + D3DMain_Log("Getting the current display mode failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + + GetClientRect(hWnd, &CRect); + + // Get old fulscreen width/height/bpp + AppInfo.OldWidth = ddsd.dwWidth; + AppInfo.OldHeight = ddsd.dwHeight; + AppInfo.OldBpp = ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Get old window width/pos + AppInfo.OldWindowWidth = CRect.right; + AppInfo.OldWindowHeight = CRect.bottom; + + GetWindowRect(hWnd, &CRect); + AppInfo.OldWindowRect = CRect; + + AppInfo.OldGWL_STYLE = GetWindowLong(hWnd, GWL_STYLE); + + D3DMain_GetClientWindowOffset(hWnd); + + return TRUE; +} + +//========================================================================================== +// D3DMain_SetDisplayMode +//========================================================================================== +static BOOL D3DMain_SetDisplayMode(HWND hWnd, int w, int h, int bpp, BOOL FullScreen) +{ + HRESULT LastError; + int DWidth, DHeight; + char YN[2][32]; + + strcpy(YN[0], "NO"); + strcpy(YN[1], "YES"); + + D3DMain_Log("--- D3DMain_SetDisplayMode ---\n"); + D3DMain_Log(" W: %i, H: %i, Bpp: %i, FullScreen: %s\n", w, h, bpp, YN[FullScreen]); + + if (FullScreen) + { + LastError = AppInfo.lpDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);// | DDSCL_ALLOWREBOOT); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to fullscreen failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + LastError = AppInfo.lpDD->SetDisplayMode(w, h, bpp,0,0); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetFullScreenDisplayMode: Mode %dx%dx%d failed\n %s\n", w, h, bpp, D3DErrorToString(LastError)); + return FALSE; + } + + DWidth = GetSystemMetrics(SM_CXSCREEN); + DHeight = GetSystemMetrics(SM_CYSCREEN); + + // + // Set window boundaries to cover entire desktop, and show it + // + SetWindowLong(hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE | WS_POPUP); + + SetWindowLong(hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE & + ~(WS_OVERLAPPED | + WS_CAPTION | + WS_SYSMENU | + WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | + WS_THICKFRAME)); + + + SetWindowPos(AppInfo.hWnd, + HWND_TOP, + 0, + 0, + DWidth, + DHeight, + SWP_NOCOPYBITS | SWP_NOZORDER); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); + } + else + { + LastError = AppInfo.lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to normal failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + + AppInfo.hWnd = hWnd; + AppInfo.CurrentWidth = w; + AppInfo.CurrentHeight = h; + AppInfo.CurrentBpp = bpp; + AppInfo.FullScreen = FullScreen; + + AppInfo.ModeSet = GE_TRUE; + + return TRUE; +} + +//================================================================================ +// D3DMain_PickDevice +//================================================================================ +static BOOL D3DMain_PickDevice(void) +{ + int32 i; + DWORD Depths; + + D3DMain_Log("--- D3DMain_PickDevice ---\n"); + + // Find a device with the same bpp as the mode set + +// start 32 bit change + if (gWidth == -1 && gHeight == -1) + { + // Find a device with the same bpp as the mode set + Depths = BPPToDDBD(AppInfo.CurrentBpp); + } + else + { + // Find a device with the same bpp as the mode set + Depths = BPPToDDBD(BPP32); + } + + //Depths = BPPToDDBD(AppInfo.CurrentBpp); +// end 32 bit change + + for (i = 0; i < AppInfo.NumDrivers; i++) + { + if (!(AppInfo.Drivers[i].IsHardware)) // ONLY hardware + continue; + + // Only choose drivers that can support our draw buffer bpp + if (!(AppInfo.Drivers[i].Desc.dwDeviceRenderBitDepth & Depths)) + continue; + + // Only choose drivers that can create the zbuffer we need + +// start 32 bit changes + // Get the Z buffer depth + if ( ZbufferD == 24) + { + // Only choose drivers that can create the zbuffer we need + if (!(AppInfo.Drivers[i].Desc.dwDeviceZBufferBitDepth & DDBD_24)) + continue; + } + else + { + // Only choose drivers that can create the zbuffer we need + if (!(AppInfo.Drivers[i].Desc.dwDeviceZBufferBitDepth & DDBD_16)) + continue; + } + //if (!(AppInfo.Drivers[i].Desc.dwDeviceZBufferBitDepth & DDBD_16)) + //continue; +// end 32 bit changes + + if (!(AppInfo.Drivers[i].Desc.dcmColorModel & D3DCOLOR_RGB)) + continue; + + if (!AppInfo.Drivers[i].CanDoWindow && !AppInfo.FullScreen) + continue; + + // Remember the current driver + AppInfo.CurrentDriver = i; + + return TRUE; + } + + return FALSE; +} + +//================================================================================ +// D3DMain_CreateDevice +//================================================================================ +static BOOL D3DMain_CreateDevice(void) +{ + HRESULT Error; + + D3DMain_Log("--- D3DMain_CreateDevice ---\n"); + + // Release old device + RELEASE(AppInfo.lpD3DDevice); + + Error = AppInfo.lpD3D->CreateDevice(AppInfo.Drivers[AppInfo.CurrentDriver].Guid, + AppInfo.lpBackBuffer, + &AppInfo.lpD3DDevice,NULL); + + if (Error != DD_OK) + { + D3DMain_Log("D3DMain_CreateDevice: lpD3D->CreateDevice failed:\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + #if 0 + { + // Get some info from the device + D3DDEVICEDESC hw, sw; + + hw.dwSize = sw.dwSize = D3DDEVICEDESCSIZE; + + AppInfo.lpD3DDevice->GetCaps(&hw, &sw); + } + #endif + + // Get Device Identifier + Error = AppInfo.lpDD->GetDeviceIdentifier(&AppInfo.DeviceIdentifier, 0); + + if (Error != DD_OK) + { + D3DMain_Log("D3DMain_CreateDevice: lpDD->GetDeviceIdentifier failed:\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + // Print the debug ID + D3DMain_Log(" Vender ID = %6i\n", AppInfo.DeviceIdentifier.dwVendorId); + D3DMain_Log(" Device ID = %6i\n", AppInfo.DeviceIdentifier.dwDeviceId); + + return TRUE; +} + +//================================================================================ +// D3DMain_CreateBuffers +//================================================================================ +static BOOL D3DMain_CreateBuffers(void) +{ + DDSURFACEDESC2 ddsd; + DDSCAPS2 ddscaps; + HRESULT LastError; + + D3DMain_Log("--- D3DMain_CreateBuffers ---\n"); + + // Release any old objects that might be lying around. This should have + // already been taken care of, but just in case... + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); + + if (AppInfo.FullScreen) + { + // Create a complex flipping surface for fullscreen mode with one + // back buffer. + memset(&ddsd,0,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | + DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX; + ddsd.dwBackBufferCount = 1; + + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + + LastError = CreateSurface(&ddsd, &AppInfo.lpFrontBuffer); + + if(LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n Please restart the program and try another fullscreen mode with less resolution or lower bit depth.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for fullscreen flipping surface failed.\n %s\n", + D3DErrorToString(LastError)); + } + + goto exit_with_error; + } + + // Obtain a pointer to the back buffer surface created above so we + // can use it later. For now, just check to see if it ended up in + // video memory (FYI). + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + LastError = AppInfo.lpFrontBuffer->GetAttachedSurface(&ddscaps, &AppInfo.lpBackBuffer); + + if(LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: GetAttachedSurface failed to get back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: Failed to get surface description of back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.BackBufferInVideo = + (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + AppInfo.ddsd = ddsd; // Save the format of the back buffer + } + else + { + // In the window case, create a front buffer which is the primary + // surface and a back buffer which is an offscreen plane surface. + + memset(&ddsd,0,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + + LastError = AppInfo.lpDD->CreateSurface(&ddsd, &AppInfo.lpFrontBuffer, NULL); + + if(LastError != DD_OK ) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n To run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for window front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + goto exit_with_error; + } + + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwWidth = AppInfo.CurrentWidth; + ddsd.dwHeight = AppInfo.CurrentHeight; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + + LastError = CreateSurface(&ddsd, &AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n To run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for window back buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + goto exit_with_error; + } + + // Check to see if the back buffer is in video memory (FYI). + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: Failed to get surface description for back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.BackBufferInVideo = (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + // Create the DirectDraw Clipper object and attach it to the window + // and front buffer. + LastError = AppInfo.lpDD->CreateClipper(0, &AppInfo.lpClipper, NULL); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: CreateClipper failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = AppInfo.lpClipper->SetHWnd(0, AppInfo.hWnd); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: Attaching clipper to window failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + + LastError = AppInfo.lpFrontBuffer->SetClipper(AppInfo.lpClipper); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: Attaching clipper to front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.ddsd = ddsd; // Save the format of the back buffer + } + + D3DMain_ClearBuffers(); + + return TRUE; + + exit_with_error: + + RELEASE(AppInfo.lpFrontBuffer); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpClipper); + return FALSE; +} + +//================================================================================ +// D3DMain_DestroyBuffers +//================================================================================ +static void D3DMain_DestroyBuffers(void) +{ + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); +} + +//================================================================================ +// D3DMain_CreateZBuffer +// Create a Z-Buffer of the appropriate depth and attach it to the back buffer. +//================================================================================ +static BOOL D3DMain_CreateZBuffer(void) +{ + DDSURFACEDESC2 ddsd; + HRESULT LastError; + + assert(AppInfo.lpBackBuffer); + + D3DMain_Log("--- D3DMain_CreateZBuffer ---\n"); + + // Release any Z-Buffer that might be around just in case. + RELEASE(AppInfo.lpZBuffer); + + memset(&ddsd, 0 ,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;//DDSD_ZBUFFERBITDEPTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; + ddsd.dwWidth = AppInfo.CurrentWidth; + ddsd.dwHeight = AppInfo.CurrentHeight; + + ddsd.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER; + + // Find a valid zbuffer, from the current device + AppInfo.lpD3D->EnumZBufferFormats(AppInfo.Drivers[AppInfo.CurrentDriver].Guid, EnumZBufferFormatsCallback, + (VOID*)&ddsd.ddpfPixelFormat); + + + if( sizeof(DDPIXELFORMAT) != ddsd.ddpfPixelFormat.dwSize ) + { + D3DMain_Log("CreateZBuffer: No zbuffer found for 3d device.\n"); + return FALSE; + } + + LastError = AppInfo.lpDD->CreateSurface(&ddsd, &AppInfo.lpZBuffer, NULL); + + if(LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + if (AppInfo.FullScreen) + { + D3DMain_Log("CreateZBuffer: There was not enough video memory to create the Z-buffer surface.\n Please try another mode with less resolution.\n"); + } + else + { + D3DMain_Log("CreateZBuffer: There was not enough video memory to create the Z-buffer surface.\n Please try another mode with less resolution.\n"); + } + } + else + { + D3DMain_Log("CreateZBuffer: CreateSurface for Z-buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + + goto exit_with_error; + } + + // Attach the Z-buffer to the back buffer so D3D will find it + LastError = AppInfo.lpBackBuffer->AddAttachedSurface(AppInfo.lpZBuffer); + + if(LastError != DD_OK) + { + D3DMain_Log("CreateZBuffer: AddAttachedBuffer failed for Z-Buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + // Find out if it ended up in video memory. + LastError = GetSurfDesc(&ddsd, AppInfo.lpZBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateZBuffer: Failed to get surface description of Z buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.ZBufferInVideo = (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + return TRUE; + + exit_with_error: + RELEASE(AppInfo.lpZBuffer); + return FALSE; +} + +//================================================================================ +// D3DMain_DestroyZBuffer +//================================================================================ +static void D3DMain_DestroyZBuffer(void) +{ + RELEASE(AppInfo.lpZBuffer) +} + +//================================================================================ +// D3DMain_RestoreDisplayMode +// Does nothing if mode has not been set yet +//================================================================================ +static BOOL D3DMain_RestoreDisplayMode(void) +{ + HRESULT LastError; + + if (!AppInfo.ModeSet) + return TRUE; + + AppInfo.ModeSet = GE_FALSE; + + assert(AppInfo.lpDD); + + if (AppInfo.FullScreen) + { + LastError = AppInfo.lpDD->RestoreDisplayMode(); + + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_RestoreDisplayMode: RestoreDisplayMode failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + LastError = AppInfo.lpDD->SetCooperativeLevel(AppInfo.hWnd, DDSCL_NORMAL); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to normal failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + + // Restore window width/height + SetWindowLong(AppInfo.hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE); + + SetWindowPos(AppInfo.hWnd, + HWND_TOP, + AppInfo.OldWindowRect.left, + AppInfo.OldWindowRect.top, + (AppInfo.OldWindowRect.right - AppInfo.OldWindowRect.left), + (AppInfo.OldWindowRect.bottom - AppInfo.OldWindowRect.top), + SWP_NOCOPYBITS | SWP_NOZORDER); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); + + return TRUE; +} + + +// +// Enum drivers +// + +D3D_DRIVER Drivers[MAX_DRIVERS]; + +//======================================================================================================== +// EnumDriversCB2 +//======================================================================================================== +BOOL FAR PASCAL EnumDriversCB2(GUID FAR *lpGUID, LPSTR lpDriverDesc, LPSTR lpDriverName, LPVOID lpContext) +{ + DDEnumInfo *Info; + D3D_DRIVER *pDriver; + + if (!lpDriverDesc || !lpDriverName) + return (D3DENUMRET_OK); + + if (strlen(lpDriverDesc) + 5 >= MAX_DRIVER_NAME) + return DDENUMRET_OK; + + Info = (DDEnumInfo*)lpContext; + + if (Info->NumDrivers >= MAX_DRIVERS) + return DDENUMRET_CANCEL; + + pDriver = &Info->Drivers[Info->NumDrivers++]; + + if (lpGUID) + { + pDriver->IsPrimary = GE_FALSE; + memcpy(&pDriver->Guid, lpGUID, sizeof(GUID)); + } + else + { + pDriver->IsPrimary = GE_TRUE; + } + + // Save name + sprintf(pDriver->Name, "(D3D)%s", lpDriverDesc); + + return DDENUMRET_OK; +} + +//======================================================================================================== +// EnumSubDrivers2 +//======================================================================================================== +BOOL DRIVERCC EnumSubDrivers2(DRV_ENUM_DRV_CB *Cb, void *Context) +{ + HRESULT hr; + int32 i; + DDEnumInfo Info; + + unlink(D3DMAIN_LOG_FILENAME); + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_EnumSubDrivers: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + for (i=0; i< Info.NumDrivers; i++) + { + // Create the DD object for this driver + if (!CreateDDFromDriver(&Info.Drivers[i])) + return GE_FALSE; + + if (Main_CheckDD()) + { + if (!Cb(i, Info.Drivers[i].Name, Context)) + { + RELEASE(AppInfo.lpD3D); + AppInfo.lpD3D = NULL; + + //D3DMain_ShutdownD3D(); + RELEASE(AppInfo.lpDD); + AppInfo.lpDD = NULL; + memset(&AppInfo, 0, sizeof(AppInfo)); + break; + } + } + + RELEASE(AppInfo.lpD3D); + AppInfo.lpD3D = NULL; + + //D3DMain_ShutdownD3D(); + RELEASE(AppInfo.lpDD); + AppInfo.lpDD = NULL; + memset(&AppInfo, 0, sizeof(AppInfo)); + } + + //Cb(i, "(D3D)HackDriver", Context); + + return TRUE; +} + +//======================================================================================================== +// EnumModes2 +//======================================================================================================== +BOOL DRIVERCC EnumModes2(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context) +{ + HRESULT hr; + int32 i, Width, Height; + char ModeName[MAX_DRIVER_NAME]; + DDEnumInfo Info; + + //Cb(0, "HackMode 2", 640, 480, Context); + //return GE_TRUE; + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_EnumModes: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + + if (!CreateDDFromName(DriverName, &Info)) + return GE_FALSE; + + if (!D3DMain_EnumDisplayModes()) + { + D3DMain_ShutdownD3D(); + + D3DMain_Log("D3DMain_EnumModes: D3DMain_EnumDisplayModes failed.\n"); + return FALSE; + } + + for (i=0; i< AppInfo.NumModes; i++) + { + if (AppInfo.Modes[i].Bpp != 16) + continue; + + // Get the width/height of mode + Width = AppInfo.Modes[i].Width; + Height = AppInfo.Modes[i].Height; + + // Make a unique name + sprintf(ModeName, "%ix%i", Width, Height); + + // Call their callback with this driver mode + if (!Cb(i, ModeName, Width, Height, Context)) + { + D3DMain_ShutdownD3D(); + return GE_TRUE; + } + } + + if (AppInfo.CanDoWindow) + { + if (!Cb(i, "WindowMode", -1, -1, Context)) + { + D3DMain_ShutdownD3D(); + return GE_TRUE; + } + } + + D3DMain_ShutdownD3D(); + + return TRUE; +} + +//================================================================================ +// DDEnumCallback +//================================================================================ +static BOOL FAR PASCAL DDEnumCallback( GUID FAR* lpGUID, + LPSTR lpDriverDesc, + LPSTR lpDriverName, + LPVOID lpContext) +{ + LPDIRECTDRAW4 pDD6; + DDCAPS DriverCaps, HELCaps; + DD_Enum *DDEnum; + LPDIRECTDRAW pDD1; + HRESULT hr; + + DDEnum = (DD_Enum*)lpContext; + + if(strncmp(lpDriverDesc, DDEnum->DriverName, strlen(DDEnum->DriverName))) + return DDENUMRET_OK; // Next... This is not the one they wanted + + pDD1 = NULL; + hr = DirectDrawCreate( lpGUID, &pDD1, NULL ); + + if(FAILED( hr )) + return DDENUMRET_CANCEL; // Assume this is bad, and stop + + assert(pDD1); + + // Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw + // represents the DX6 version of the API. + hr = pDD1->QueryInterface( IID_IDirectDraw4, (VOID**)&pDD6); + + // Don't need this anymore + RELEASE(pDD1); + + if( FAILED( hr ) ) + return DDENUMRET_CANCEL; + + memset(&DriverCaps, 0, sizeof(DDCAPS)); + DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + if (FAILED(pDD6->GetCaps(&DriverCaps, &HELCaps))) + { + RELEASE(pDD6); + return DDENUMRET_CANCEL; + } + + // Make sure it's a 3d compatible device + if (!(DriverCaps.dwCaps & DDCAPS_3D)) + { + RELEASE(pDD6); + return DDENUMRET_CANCEL; + } + + if (!lpGUID) + AppInfo.IsPrimary = TRUE; + else + AppInfo.IsPrimary = FALSE; + + DDEnum->lpDD = pDD6; + DDEnum->FoundDD = TRUE; + + return DDENUMRET_CANCEL; // We are done +} + +//================================================================================ +// D3DMain_CreateDDFromName +// Creates DD, searching for the specified DD name using DriverName +//================================================================================ +static BOOL D3DMain_CreateDDFromName(const char *DriverName) +{ + HRESULT hr; + DDCAPS DriverCaps, HELCaps; + DDEnumInfo Info; + + D3DMain_Log("--- D3DMain_CreateDDFromName ---\n"); + + if (strlen(DriverName) >= MAX_DRIVER_NAME) + return GE_FALSE; + + D3DMain_Log(" Name: %s\n", DriverName); + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_CreateDDFromName: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + { + char TempName[1024]; + + sprintf(TempName, "(D3D)%s", DriverName); + + if (!CreateDDFromName(TempName, &Info)) + return GE_FALSE; + } + + assert(AppInfo.lpDD); + + memset(&DriverCaps, 0, sizeof(DDCAPS)); + DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + if (FAILED(AppInfo.lpDD->GetCaps(&DriverCaps, &HELCaps))) + { + D3DMain_Log("D3DMain_CreateDDFromName: GetCaps failed.\n"); + D3DMain_ShutdownD3D(); + return FALSE; + } + + if (DriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED) + D3DMain_Log(" DDCAPS2_CANRENDERWINDOWED : YES\n"); + else + D3DMain_Log(" DDCAPS2_CANRENDERWINDOWED : NO\n"); + + if (DriverCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) + D3DMain_Log(" DDCAPS2_NO2DDURING3DSCENE : YES\n"); + else + D3DMain_Log(" DDCAPS2_NO2DDURING3DSCENE : NO\n"); + + // Save the DD object + strcpy(AppInfo.DDName, DriverName); + + return TRUE; +} + +//======================================================================================================== +// CreateDDFromDriver +//======================================================================================================== +static geBoolean CreateDDFromDriver(D3D_DRIVER *pDriver) +{ + LPDIRECTDRAW pDD1; + HRESULT hr; + + AppInfo.IsPrimary = pDriver->IsPrimary; + + if (pDriver->IsPrimary) + hr = DirectDrawCreate(NULL, &pDD1, NULL ); + else + hr = DirectDrawCreate(&pDriver->Guid, &pDD1, NULL ); + + if( FAILED( hr ) ) + return GE_FALSE; + + // Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw + // represents the DX6 version of the API. + hr = pDD1->QueryInterface(IID_IDirectDraw4, (VOID**)&AppInfo.lpDD); + + // Don't need this guy anymore + RELEASE(pDD1); + + if(FAILED(hr)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +// CreateDDFromName +//======================================================================================================== +static geBoolean CreateDDFromName(const char *DriverName, const DDEnumInfo *Info) +{ + int32 i; + + for (i=0; i < Info->NumDrivers; i++) + { + if (!strcmp(Info->Drivers[i].Name, DriverName)) + break; + } + + if (i == Info->NumDrivers) + return GE_FALSE; + + // Create the DD object for this driver + if (!CreateDDFromDriver(&Info->Drivers[i])) + return GE_FALSE; + + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/D3DDrv/D3d_main.h b/G3D/Engine/Drivers/D3DDrv/D3d_main.h new file mode 100644 index 0000000..bae9427 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3d_main.h @@ -0,0 +1,227 @@ +/****************************************************************************************/ +/* D3D_Main.h */ +/* */ +/* Author: John Pollard */ +/* Description: DD/D3D wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_MAIN_H +#define D3D_MAIN_H + +#include +#include +#include + +#define INITGUID + +#include "DCommon.h" + +#define MAX_APP_MODES 50 +#define DDMAIN_MAX_D3D_DRIVERS 10 +#define DDMAIN_MAX_TEXTURE_FORMATS 128 +#define DDMAIN_MAX_SURFACE_FORMATS 128 + +#define D3DMAIN_LOG_FILENAME "D3DDrv.Log" + +#define MAX_DRIVER_NAME 1024 + +//================================================================================ +// Structure defs +//================================================================================ + +typedef struct +{ + char Name[MAX_DRIVER_NAME]; // Short name of the driver + char About[MAX_DRIVER_NAME]; // Short string about the driver + D3DDEVICEDESC Desc; // D3DDEVICEDESC for complete information + GUID Guid; // it's GUID + BOOL IsHardware; // does this driver represent a hardware device? + BOOL DoesTextures; // does this driver do texture mapping? + BOOL DoesZBuffer; // can this driver use a z-buffer? + BOOL CanDoWindow; // can it render to Window's display depth? + BOOL DoesTransparency; + BOOL DoesAlpha; + BOOL DoesClamping; + BOOL DoesSrcBlending; + BOOL DoesDestBlending; + + WORD MaxTextureBlendStages; + WORD MaxSimultaneousTextures; + + BOOL CanUse; // We can use this driver +} DDMain_D3DDriver; + +typedef struct +{ + int32 Width; // width + int32 Height; // height + int32 Bpp; // bits per pixel + BOOL ThisDriverCanDo; // == TRUE if d3d driver can render into +} App_Mode; + +typedef struct +{ + DDSURFACEDESC2 ddsd; // DDSURFACEDESC for complete information + BOOL HasOneBitAlpha; + BOOL HasFourBitAlpha; +} DDMain_SurfFormat; + +typedef struct +{ + uint32 R[256]; + uint32 G[256]; + uint32 B[256]; + uint32 A[256]; +} RGB_LUT; + +// App_Info, used for everything global. +typedef struct +{ + // Window info + HWND hWnd; // Handle to parent Window + + DDSURFACEDESC2 ddsd; + + // Mode that we were in before initializing + int32 OldWidth; // Old screen width + int32 OldHeight; + int32 OldBpp; + + int32 CurrentWidth; + int32 CurrentHeight; + int32 CurrentBpp; + + int32 OldWindowWidth; // Old client width + int32 OldWindowHeight; + int32 WindowXOffset; + int32 WindowYOffset; + + RECT OldWindowRect; + ULONG OldGWL_STYLE; + + geBoolean ModeSet; + + char DDName[MAX_DRIVER_NAME]; // Have no idea how big to make this. Anyone? + + LPDIRECTDRAW4 lpDD; // The current initialized DD object + LPDIRECT3D3 lpD3D; // The current initialized D3D object + + LPDIRECTDRAWSURFACE4 lpFrontBuffer; // front buffer surface + LPDIRECTDRAWSURFACE4 lpBackBuffer; // back buffer surface + LPDIRECTDRAWSURFACE4 lpZBuffer; // z-buffer surface + LPDIRECTDRAWCLIPPER lpClipper; // Clipper in windowed case + BOOL BackBufferInVideo; // back buf in video mem? + BOOL ZBufferInVideo; // is Z-buf in video mem? + LPDIRECT3DDEVICE3 lpD3DDevice; // D3D device + LPDIRECT3DVIEWPORT3 lpD3DViewport; // D3D viewport + + LPDIRECT3DMATERIAL3 BackgroundMaterial; + + // 2d surface format (for blt'ing to the display) + DDSURFACEDESC2 ddSurfFormat; // 555 or 565 surface desc + + // Texture formats (for the D3D device) + DDSURFACEDESC2 ddTexFormat; // 555 or 565 surface desc + DDSURFACEDESC2 ddFourBitAlphaSurfFormat; // 4444 surface desc + DDSURFACEDESC2 ddOneBitAlphaSurfFormat; // 1555 surface desc + + RGB_LUT Lut1; + RGB_LUT Lut2; + RGB_LUT Lut3; + + BOOL IsPrimary; // + BOOL FullScreen; + + int32 NumModes; + App_Mode Modes[MAX_APP_MODES]; + + int32 NumDrivers; + DDMain_D3DDriver Drivers[DDMAIN_MAX_D3D_DRIVERS]; + int32 CurrentDriver; + DDDEVICEIDENTIFIER DeviceIdentifier; + + // Surface formats + int32 NumSurfFormats; // Num 2D texture formats avail (from DD4 object) + DDMain_SurfFormat SurfFormats[DDMAIN_MAX_SURFACE_FORMATS]; + + // Texture formats + int32 NumTextureFormats; // Num 3D texture formats avail (from device) + DDMain_SurfFormat TextureFormats[DDMAIN_MAX_TEXTURE_FORMATS]; + + BOOL LogToFile; + BOOL FoundGoodDevice; + BOOL CanDoWindow; + + BOOL RenderingIsOK; + + DWORD VidMemFree; + + geFloat Gamma; + BOOL GammaChanged; + + geBoolean CanDoMultiTexture; + + geBoolean FogEnable; + geFloat FogStart; + geFloat FogEnd; + geFloat FogR; + geFloat FogG; + geFloat FogB; + + // DD / D3D Flags + uint32 Flags; +} App_Info; + +// DD enum strcuture. Used when enuming dd +typedef struct +{ + LPDIRECTDRAW4 lpDD; + char DriverName[MAX_DRIVER_NAME]; + BOOL FoundDD; +} DD_Enum; + +//================================================================================ +// Globals +//================================================================================ +extern App_Info AppInfo; // Our global structure that knows all... (once initialized) + +//================================================================================ +// Global functions +//================================================================================ +BOOL D3DMain_InitD3D(HWND hWnd, const char *DriverName, int32 Width, int32 Height); +BOOL D3DMain_ShutdownD3D(void); +geBoolean D3DMain_Reset(void); +void D3DMain_Log(LPSTR Str, ... ); +BOOL D3DMain_RestoreAllSurfaces(void); + +BOOL Main_EnumTextureFormats(void); +BOOL D3DMain_EnumDisplayModes(void); +BOOL Main_ClearBackBuffer(BOOL Clear, BOOL ClearZ); +BOOL Main_ShowBackBuffer(void); + +BOOL D3DMain_GetSurfaceFormats(void); + +BOOL Main_CheckDD(void); +BOOL D3DMain_GetTextureMemory(void); +void Main_BuildRGBGammaTables(geFloat Gamma); + +BOOL D3DMain_GetClientWindowOffset(HWND hWnd); +geBoolean DRIVERCC D3DMain_UpdateWindow(void); +geBoolean DRIVERCC D3DMain_SetActive(geBoolean wParam); +geBoolean DRIVERCC D3DMain_SetFogEnable(geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3DDrv/D3dcache.cpp b/G3D/Engine/Drivers/D3DDrv/D3dcache.cpp new file mode 100644 index 0000000..769300d --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3dcache.cpp @@ -0,0 +1,785 @@ +/****************************************************************************************/ +/* D3DCache.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include +#include + +#include "D3DCache.h" + +// Cache types are just the different types of textures +// Texutres may vary from width/height/num miplevels/etc... +// Cache types is just a way to combine them to similar types... +#define D3DCACHE_MAX_CACHE_TYPES 128 + +//======================================================================================================== +//======================================================================================================== +typedef struct D3DCache_Type +{ + int32 Log; + int32 Width; // Width/Height + int32 Height; + int32 NumMipLevels; + int32 Stage; + int32 RefCount; // How many references to this cache_type + + DDSURFACEDESC2 ddsd; // DD surface description + + D3DCache_Slot *Slots; // Cache slots for this Cache type + int32 NumUsedSlots; // Number of slots being used + + D3DCache_Type *SelfCheck; + D3DCache *Cache; +} D3DCache_Type; + +typedef struct D3DCache +{ + struct D3DCache *SelfCheck; + + char Name[D3DCACHE_MAX_NAME]; + + LPDIRECTDRAW4 lpDD; // DD object for the cache manager + + DDMemMgr_Partition *Partition; + + geBoolean UseStages; + + D3DCache_Type CacheTypes[D3DCACHE_MAX_CACHE_TYPES]; // CacheTypes +} D3DCache; + +typedef struct D3DCache_Slot +{ + struct D3DCache_Slot *SelfCheck; + + D3DCache_Type *CacheType; + + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this slot + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface + + uint32 LRU; // Current LRU for cache slot + + void *UserData; + +} D3DCache_Slot; + +//======================================================================================================== +//======================================================================================================== + +//======================================================================================================== +// D3DCache_Create +//======================================================================================================== +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW4 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages) +{ + D3DCache *Cache; + + assert(strlen(Name) < D3DCACHE_MAX_NAME); + + Cache = (D3DCache*)malloc(sizeof(D3DCache)); + + if (!Cache) + return NULL; + + memset(Cache, 0, sizeof(D3DCache)); + + Cache->lpDD = lpDD; + + Cache->Partition = Partition; + + Cache->UseStages = UseStages; + + Cache->SelfCheck = Cache; + + strcpy(Cache->Name, Name); + + return Cache; +} + +//======================================================================================================== +// D3DCache_Destroy +//======================================================================================================== +void D3DCache_Destroy(D3DCache *Cache) +{ + assert(Cache); + + D3DCache_FreeAllSlots(Cache); + + free(Cache); +} + +//======================================================================================================== +// D3DCache_IsValid +//======================================================================================================== +geBoolean D3DCache_IsValid(D3DCache *Cache) +{ + if (!Cache) + return GE_FALSE; + + if (Cache->SelfCheck != Cache) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +geBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + int32 s; + + if (!pCacheType->RefCount) + continue; + + assert(D3DCache_TypeIsValid(pCacheType)); + + for (pSlot = pCacheType->Slots, s=0; sNumUsedSlots; s++, pSlot++) + { + D3DCache_SlotSetUserData(pSlot, NULL); + } + } + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + continue; + + assert(D3DCache_TypeIsValid(pCacheType)); + + if (pCacheType->Width != Width) + continue; + if (pCacheType->Height != Height) + continue; + + if (pCacheType->NumMipLevels != NumMipLevels) + continue; + + if (pCacheType->Stage != Stage) + continue; + + if (memcmp(&pCacheType->ddsd, ddsd, sizeof(DDSURFACEDESC2))) + continue; + + return pCacheType; // Found a match + } + + return NULL; // Cache Type not found!!! +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + break; + } + + if (i == D3DCACHE_MAX_CACHE_TYPES) // No types left + return NULL; + + assert(pCacheType->Slots == NULL); + assert(pCacheType->NumUsedSlots == 0); + + pCacheType->Width = Width; + pCacheType->Height = Height; + pCacheType->NumMipLevels = NumMipLevels; + pCacheType->Stage = Stage; + pCacheType->ddsd = *ddsd; + + pCacheType->SelfCheck = pCacheType; + pCacheType->Cache = Cache; + + pCacheType->Log = GetLog(Width, Height); + + // Found one + pCacheType->RefCount++; + + return pCacheType; +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + D3DCache_Type *CacheType; + + assert(D3DCache_IsValid(Cache)); + + CacheType = D3DCache_FindCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd); + + if (CacheType) + { + CacheType->RefCount++; + return CacheType; + } + + // Could not find one allready in the list, so add a new one... + return D3DCache_InsertCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd); +} + +//======================================================================================================== +// D3DCache_TypeDestroy +//======================================================================================================== +void D3DCache_TypeDestroy(D3DCache_Type *CacheType) +{ + assert(CacheType->RefCount > 0); + assert(D3DCache_TypeIsValid(CacheType)); + + CacheType->RefCount--; + + if (CacheType->RefCount == 0) + { + if (CacheType->Slots) + { + D3DCache_Slot *pSlot; + int32 k; + + // Go through each slot, and free all the surfaces on them + for (pSlot = CacheType->Slots, k=0; k< CacheType->NumUsedSlots; k++, pSlot++) + { + assert(D3DCache_SlotIsValid(pSlot)); + assert(pSlot->Surface); + assert(pSlot->Texture); + + if (pSlot->Texture) + pSlot->Texture->Release(); + if (pSlot->Surface) + pSlot->Surface->Release(); + } + + free(CacheType->Slots); + CacheType->Slots = NULL; + CacheType->NumUsedSlots = 0; + } + } +} + +//======================================================================================================== +// D3DCache_TypeIsValid +//======================================================================================================== +geBoolean D3DCache_TypeIsValid(D3DCache_Type *Type) +{ + if (!Type) + return GE_FALSE; + + if (Type->SelfCheck != Type) + return GE_FALSE; + + if (!D3DCache_IsValid(Type->Cache)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_FreeAllSlots +//======================================================================================================== +geBoolean D3DCache_FreeAllSlots(D3DCache *Cache) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + int32 k; + + assert(pCacheType->RefCount >= 0); + + if (pCacheType->RefCount == 0) + { + assert(pCacheType->Slots == NULL); + continue; + } + + assert(D3DCache_TypeIsValid(pCacheType)); + + // Go through each slot, and free all the surfaces on them + for (pSlot = pCacheType->Slots, k=0; k< pCacheType->NumUsedSlots; k++, pSlot++) + { + assert(D3DCache_SlotIsValid(pSlot)); + assert(pSlot->Surface); + assert(pSlot->Texture); + + if (pSlot->Texture) + pSlot->Texture->Release(); + if (pSlot->Surface) + pSlot->Surface->Release(); + } + + if (pCacheType->Slots) + free(pCacheType->Slots); + + pCacheType->Slots = NULL; + pCacheType->NumUsedSlots = 0; + } + + DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_WriteToFile +//======================================================================================================== +geBoolean D3DCache_WriteToFile(D3DCache *Cache, const char *FileName, geBoolean Append) +{ + int32 i; + D3DCache_Type *pCacheType; + int32 TotalRef, TotalUsed; + SYSTEMTIME Time; + FILE *f; + + if (Append) + f = fopen(FileName, "a+t"); + else + f = fopen(FileName, "w"); + + if (!f) + return GE_FALSE; + + GetSystemTime(&Time); + + fprintf(f, "=======================================================\n"); + fprintf(f, "Date: %i/%i/%i, Time: %i:%i\n", Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute); + fprintf(f, "Cache Name: %s\n", Cache->Name); + fprintf(f, "Total Mem: %5i\n", DDMemMgr_PartitionGetTotalMem(Cache->Partition)); + fprintf(f, "Free Mem: %5i\n", DDMemMgr_PartitionGetFreeMem(Cache->Partition)); + fprintf(f, " --- Slots ---\n"); + + TotalRef = TotalUsed = 0; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (!pCacheType->RefCount) + continue; + + fprintf(f, "Width: %3i, Height %3i, Mips: %2i, Stage: %2i, Ref: %4i, Used: %4i\n", + pCacheType->Width, pCacheType->Height, pCacheType->NumMipLevels, pCacheType->Stage, pCacheType->RefCount, pCacheType->NumUsedSlots); + + TotalRef += pCacheType->RefCount; + TotalUsed += pCacheType->NumUsedSlots; + } + + fprintf(f, "Total Ref: %4i, Total Used: %4i\n", TotalRef, TotalUsed); + + fclose(f); + + return GE_TRUE; +} + +static geBoolean AppendHack = GE_FALSE; + +// HACK!!!! +void D3DMain_Log(LPSTR Str, ... ); +//======================================================================================================== +// D3DCache_AdjustSlots +//======================================================================================================== +geBoolean D3DCache_AdjustSlots(D3DCache *Cache, const int32 *MaxTable, geBoolean UsePartition) +{ + D3DCache_Type *pCacheType; + int32 i, Total, NumPasses; + + assert(D3DCache_IsValid(Cache)); + + D3DCache_FreeAllSlots(Cache); // Just get rid of everything for now... + DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager + + Total = 0; + NumPasses = 0; + + while(1) + { + D3DCache_Slot *LastSlot; + + LastSlot = NULL; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + uint32 Size, Width, Height, Result; + + if (pCacheType->RefCount <= 0) + { + assert(pCacheType->Slots == NULL); + continue; + } + + if (pCacheType->NumUsedSlots >= pCacheType->RefCount) + continue; // This is all we need for this slot... + + if (pCacheType->NumUsedSlots >= MaxTable[pCacheType->Log]) + continue; + + if (!pCacheType->Slots) // If no slots have been allocated, allocate them now... + { + pCacheType->Slots = (D3DCache_Slot*)malloc(sizeof(D3DCache_Type)*pCacheType->RefCount); + memset(pCacheType->Slots, 0, sizeof(D3DCache_Type)*pCacheType->RefCount); + } + + Width = pCacheType->Width; + Height = pCacheType->Height; + + Size = Width*Height*(pCacheType->ddsd.ddpfPixelFormat.dwRGBBitCount>>3); // (BitCount/8) + + if (UsePartition) + { + if (!DDMemMgr_PartitionAllocMem(Cache->Partition, Size)) + { + LastSlot = NULL; // Make a complete stop + break; // No more memory in the partition, stop now... + } + } + + pSlot = &pCacheType->Slots[pCacheType->NumUsedSlots]; + pSlot->SelfCheck = pSlot; + + pSlot->CacheType = pCacheType; + + // Allocate surfaces now + Result = D3DCache_SetupSlot(Cache, pSlot, Width, Height, &pCacheType->ddsd, Cache->UseStages, pCacheType->Stage); + + if (!Result) + { + memset(pSlot, 0, sizeof(D3DCache_Slot)); + break; + } + else if (Result == -1) + { + D3DMain_Log("D3DCache_AdjustSlots: D3DCache_SetupSlot failed.\n"); + return GE_FALSE; + } + + pCacheType->NumUsedSlots++; + Total++; + + LastSlot = pSlot; + } + + NumPasses++; + + if (!LastSlot) // Nothing was allocated on that pass, so assume we are out of memory + break; + } + + pCacheType = Cache->CacheTypes; + + // Go through one last time, and make sure all got allocated + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (pCacheType->RefCount <= 0) + { + assert(pCacheType->Slots == NULL); + continue; + } + + if (pCacheType->NumUsedSlots <= 0) + { + D3DMain_Log("D3DCache_AdjustSlots: Out of ram creating surfaces for cache.\n"); + D3DMain_Log("D3DCache_AdjustSlots: Pick a display mode with a smaller resolution.\n"); + return GE_FALSE; // Not all slots with refs got a texture + } + + assert(pCacheType->Slots != NULL); + } + + D3DCache_WriteToFile(Cache, "D3DCache.Log", AppendHack); + AppendHack = GE_TRUE; + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_SlotIsValid +//======================================================================================================== +geBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot) +{ + if (!Slot) + return GE_FALSE; + + if (Slot->SelfCheck != Slot) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// D3DCache_SetupSlot +// +// Returns -1 on failure +// Returns 0 on out of memory +// Returns 1 on success +//===================================================================================== +int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, geBoolean UseStage, int32 Stage) +{ + LPDIRECTDRAWSURFACE4 Surface; + DDSURFACEDESC2 ddsd; + HRESULT Hr; + + assert(D3DCache_IsValid(Cache)); + assert(D3DCache_SlotIsValid(Slot)); + + memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + + if (UseStage) + ddsd.dwFlags |= DDSD_TEXTURESTAGE; + + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_HINTDYNAMIC; + ddsd.ddsCaps.dwCaps3 = 0; + ddsd.ddsCaps.dwCaps4 = 0; + ddsd.dwHeight = Width; + ddsd.dwWidth = Height; + + ddsd.dwTextureStage = Stage; + + Hr = Cache->lpDD->CreateSurface(&ddsd, &Surface, NULL); + + if(Hr != DD_OK) + { + if (Hr == DDERR_OUTOFVIDEOMEMORY) + { + return 0; + } + + return -1; + } + + Slot->Surface = Surface; + + // Set the color key +#if 0 + { + DDCOLORKEY CKey; + + // Create the color key for this surface + CKey.dwColorSpaceLowValue = 1; + CKey.dwColorSpaceHighValue = 1; + + if (Slot->Surface->SetColorKey(DDCKEY_SRCBLT , &CKey) != DD_OK) + { + Slot->Surface->Release(); + Slot->Surface = NULL; + return -1; + } + } + #endif + + Hr = Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Slot->Texture); + + if(Hr != DD_OK) + { + Surface->Release(); + return -1; + } + + return 1; // All good dude +} + + +//======================================================================================================== +// D3DCache_TypeFindSlot +//======================================================================================================== +D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType) +{ + D3DCache_Slot *pBestSlot, *pSlot; + uint32 BestLRU; + int32 i; + + assert(D3DCache_TypeIsValid(CacheType)); + + assert(CacheType->Slots); + + pSlot = CacheType->Slots; + pBestSlot = pSlot; + BestLRU = pBestSlot->LRU; + + for (i=0; i< CacheType->NumUsedSlots; i++, pSlot++) + { + assert(D3DCache_SlotIsValid(pSlot)); + + if (pSlot->LRU < BestLRU) + { + pBestSlot = pSlot; + BestLRU = pSlot->LRU; + } + } + + pBestSlot->LRU = 0; + pBestSlot->UserData = NULL; + + return pBestSlot; +} + +//======================================================================================================== +// D3DCache_SlotSetUserData +//======================================================================================================== +void D3DCache_SlotSetUserData(D3DCache_Slot *Slot, void *UserData) +{ + assert(D3DCache_SlotIsValid(Slot)); + + Slot->UserData = UserData; +} + +//======================================================================================================== +// D3DCache_SlotGetUserData +//======================================================================================================== +void *D3DCache_SlotGetUserData(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->UserData; +} + +//======================================================================================================== +// D3DCache_SlotSetLRU +//======================================================================================================== +void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU) +{ + assert(D3DCache_SlotIsValid(Slot)); + + Slot->LRU = LRU; +} + +//======================================================================================================== +// D3DCache_SlotGetLRU +//======================================================================================================== +uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->LRU; +} + +LPDIRECT3DTEXTURE2 D3DCache_SlotGetTexture(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->Texture; +} + +LPDIRECTDRAWSURFACE4 D3DCache_SlotGetSurface(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->Surface; +} + +//===================================================================================== +// Log2 +// Return the log of a size +//===================================================================================== +uint32 Log2(uint32 P2) +{ + uint32 p = 0; + int32 i = 0; + + for (i = P2; i > 0; i>>=1) + p++; + + return (p-1); +} + +//===================================================================================== +// SnapToPower2 +// Snaps a number to a power of 2 +//===================================================================================== +int32 SnapToPower2(int32 Width) +{ +#if 1 + if (Width > 0 && Width <= 1) Width = 1; + else if (Width > 1 && Width <= 2) Width = 2; + else if (Width > 2 && Width <= 4) Width = 4; + else if (Width > 4 && Width <= 8) Width = 8; + else if (Width > 8 && Width <= 16) Width =16; + else if (Width > 16 && Width <= 32) Width = 32; + else if (Width > 32 && Width <= 64) Width = 64; + else if (Width > 64 && Width <= 128) Width = 128; + else if (Width > 128 && Width <= 256) Width = 256; + else + return -1; +#else + + if (Width > 1 && Width <= 8) Width = 8; + else if (Width > 8 && Width <= 16) Width =16; + else if (Width > 16 && Width <= 32) Width = 32; + else if (Width > 32 && Width <= 64) Width = 64; + else if (Width > 64 && Width <= 128) Width = 128; + else if (Width > 128 && Width <= 256) Width = 256; + else + return -1; +#endif + + return Width; +} + +//===================================================================================== +// Return the max log of a (power of 2) width and height +//===================================================================================== +int32 GetLog(int32 Width, int32 Height) +{ + int32 LWidth = SnapToPower2(max(Width, Height)); + + return Log2(LWidth); +} + diff --git a/G3D/Engine/Drivers/D3DDrv/D3dcache.h b/G3D/Engine/Drivers/D3DDrv/D3dcache.h new file mode 100644 index 0000000..f7a1481 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3dcache.h @@ -0,0 +1,64 @@ +/****************************************************************************************/ +/* D3DCache.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3DCache_H +#define D3DCache_H + +#include +#include +#include + +#include "BaseType.h" +#include "DDMemMgr.h" + +#define D3DCACHE_MAX_NAME 256 + +typedef struct D3DCache D3DCache; +typedef struct D3DCache_Type D3DCache_Type; +typedef struct D3DCache_Slot D3DCache_Slot; + +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW4 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages); +void D3DCache_Destroy(D3DCache *Cache); +geBoolean D3DCache_IsValid(D3DCache *Cache); +geBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache); +D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +void D3DCache_TypeDestroy(D3DCache_Type *CacheType); +geBoolean D3DCache_TypeIsValid(D3DCache_Type *Type); +geBoolean D3DCache_FreeAllSlots(D3DCache *Cache); +geBoolean D3DCache_AdjustSlots(D3DCache *Cache, const int32 *MaxTable, geBoolean UsePartition); +geBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot); +int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, geBoolean UseStage, int32 Stage); +D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType); +void D3DCache_SlotSetUserData(D3DCache_Slot *Slot, void *UserData); +void *D3DCache_SlotGetUserData(D3DCache_Slot *Slot); +void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU); +uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot); +LPDIRECT3DTEXTURE2 D3DCache_SlotGetTexture(D3DCache_Slot *Slot); +LPDIRECTDRAWSURFACE4 D3DCache_SlotGetSurface(D3DCache_Slot *Slot); + +uint32 Log2(uint32 P2); +int32 SnapToPower2(int32 Width); +int32 GetLog(int32 Width, int32 Height); + +#endif + diff --git a/G3D/Engine/Drivers/D3DDrv/D3ddrv.cpp b/G3D/Engine/Drivers/D3DDrv/D3ddrv.cpp new file mode 100644 index 0000000..2c78242 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/D3ddrv.cpp @@ -0,0 +1,368 @@ +/****************************************************************************************/ +/* D3DDrv.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" + +#include "Scene.h" +#include "Render.h" +#include "D3DCache.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "THandle.h" + + +DRV_Window ClientWindow; +BOOL ExitHandlerActive = FALSE; + +int32 LastError; +char LastErrorStr[200]; + +geBoolean DRIVERCC DrvShutdown(void); +geBoolean DRIVERCC ScreenShot(const char *Name); + +BOOL DRIVERCC DrvInit(DRV_DriverHook *Hook) +{ + RECT WRect; + + // Start up + if (!D3DMain_InitD3D(Hook->hWnd, Hook->DriverName+5, Hook->Width, Hook->Height)) + { + //SetLastDrvError(DRV_ERROR_INIT_ERROR, "D3D_DrvInit: Could not init driver.\n"); + return FALSE; + } + + // If they are asking for a window mode, use there hWnd for the size + if (Hook->Width ==-1 && Hook->Height == -1) + { + GetClientRect(Hook->hWnd, &WRect); + + Hook->Width = (WRect.right - WRect.left); + Hook->Height = (WRect.bottom - WRect.top); + } + + ClientWindow.Width = Hook->Width; + ClientWindow.Height = Hook->Height; + ClientWindow.hWnd = Hook->hWnd; + + return TRUE; +} + +//============================================================================================ +//============================================================================================ +BOOL DRIVERCC DrvShutdown(void) +{ + D3DMain_ShutdownD3D(); + return TRUE; +} + +//============================================================================================ +// DrvResetAll +//============================================================================================ +geBoolean DRIVERCC DrvResetAll(void) +{ + return D3DMain_Reset(); +} + +geRDriver_PixelFormat PixelFormat[10]; + +#define NUM_PIXEL_FORMATS (sizeof(PixelFormats)/sizeof(geRDriver_PixelFormat)) + +geBoolean DRIVERCC EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context) +{ + int32 i; + gePixelFormat Format3d, Format2d; + uint32 CurrentBpp; + + CurrentBpp = AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Setup the 2d surface format + if (CurrentBpp == 32 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwRGBAlphaBitMask == 0xff000000) + Format2d = GE_PIXELFORMAT_32BIT_ARGB; + else if (CurrentBpp == 32 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwBBitMask == 0xff) + Format2d = GE_PIXELFORMAT_32BIT_XRGB; + else if (CurrentBpp == 24 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwBBitMask == 0xff) + Format2d = GE_PIXELFORMAT_24BIT_RGB; + else if (AppInfo.ddSurfFormat.ddpfPixelFormat.dwGBitMask == (31<<5)) + Format2d = GE_PIXELFORMAT_16BIT_555_RGB; + else + Format2d = GE_PIXELFORMAT_16BIT_565_RGB; + + // Setup the 3d (Texture) format + if (AppInfo.ddTexFormat.ddpfPixelFormat.dwGBitMask == (31<<5)) + Format3d = GE_PIXELFORMAT_16BIT_555_RGB; + else + Format3d = GE_PIXELFORMAT_16BIT_565_RGB; + + + // Create the surface formats now + PixelFormat[0].PixelFormat = Format3d; // 3d 565/555 surface + PixelFormat[0].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + PixelFormat[1].PixelFormat = GE_PIXELFORMAT_16BIT_4444_ARGB; // 3d 4444 surface + PixelFormat[1].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + PixelFormat[2].PixelFormat = Format2d; // 2d 565/555 surface + PixelFormat[2].Flags = RDRIVER_PF_2D | RDRIVER_PF_CAN_DO_COLORKEY; + + PixelFormat[3].PixelFormat = Format3d; // Lightmap 565/555 surface + PixelFormat[3].Flags = RDRIVER_PF_LIGHTMAP; + + PixelFormat[4].PixelFormat = GE_PIXELFORMAT_16BIT_1555_ARGB; + PixelFormat[4].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + // Then hand them off to the caller + for (i=0; i<5; i++) + { + if (!Cb(&PixelFormat[i], Context)) + return GE_TRUE; + } + + return TRUE; +} + +geBoolean DRIVERCC SetGamma(geFloat Gamma) +{ + return GE_TRUE; +} + +geBoolean DRIVERCC GetGamma(geFloat *Gamma) +{ + *Gamma = 1.0f; + + return GE_TRUE; +} + +BOOL DRIVERCC EnumSubDrivers2(DRV_ENUM_DRV_CB *Cb, void *Context); +BOOL DRIVERCC EnumModes2(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context); + +DRV_Driver D3DDRV = +{ + "D3D driver. v"DRV_VMAJS"."DRV_VMINS". Copyright 1999, WildTangent Inc.; All Rights Reserved.", + DRV_VERSION_MAJOR, + DRV_VERSION_MINOR, + + DRV_ERROR_NONE, + NULL, + + EnumSubDrivers2, + EnumModes2, + + EnumPixelFormats, + + DrvInit, + DrvShutdown, + DrvResetAll, + D3DMain_UpdateWindow, + D3DMain_SetActive, + + THandle_Create, + THandle_Destroy, + + THandle_Lock, + THandle_UnLock, + + NULL, // SetPal + NULL, // GetPal + + NULL, // SetAlpha + NULL, // GetAlpha + + THandle_GetInfo, + + BeginScene, + EndScene, + BeginWorld, + EndWorld, + BeginMeshes, + EndMeshes, + BeginModels, + EndModels, + + RenderGouraudPoly, + RenderWorldPoly, + RenderMiscTexturePoly, + + DrawDecal, + + 0,0,0, + + &CacheInfo, + + ScreenShot, + + SetGamma, + GetGamma, + + D3DMain_SetFogEnable, + + NULL, + NULL, // Init to NULL, engine SHOULD set this (SetupLightmap) + NULL +}; + +DRV_EngineSettings EngineSettings; + +DllExport BOOL DriverHook(DRV_Driver **Driver) +{ + EngineSettings.CanSupportFlags = (DRV_SUPPORT_ALPHA | DRV_SUPPORT_COLORKEY); + EngineSettings.PreferenceFlags = 0;//DRV_PREFERENCE_NO_MIRRORS; + + D3DDRV.EngineSettings = &EngineSettings; + + *Driver = &D3DDRV; + + // Make sure the error string ptr is not null, or invalid!!! + D3DDRV.LastErrorStr = LastErrorStr; + + SetLastDrvError(DRV_ERROR_NONE, "D3DDrv: No error."); + + return TRUE; +} + +void SetLastDrvError(int32 Error, char *ErrorStr) +{ + LastError = Error; + + if (ErrorStr) + { + strcpy(LastErrorStr, ErrorStr); + } + else + LastErrorStr[0] = NULL; + + D3DDRV.LastErrorStr = LastErrorStr; + D3DDRV.LastError = LastError; +} + +// eaa3 05/31/2000 Added Orf's Direct3D screenshot code to the driver +// ..so we can get SCREENSHOTS out of both Glide and D3d. + +BOOL DRIVERCC ScreenShot(const char *Name) +{ + DDSURFACEDESC2 ddsd; + BITMAPFILEHEADER bfh; + BITMAPINFOHEADER bih; + HRESULT result; + HDC surfDC = NULL; + HDC memDC = NULL; + HBITMAP bitmap = NULL; + HBITMAP oldbit = NULL; + FILE *file = NULL; + void *data= NULL; + int width, height, bpp; + int datasize; + BOOL success = FALSE; + + memset(&ddsd,0,sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + result = AppInfo.lpBackBuffer->GetSurfaceDesc(&ddsd); + if(FAILED(result)) + goto cleanup; + + width = ddsd.dwWidth; + height= ddsd.dwHeight; + bpp = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + + if(bpp < 2) + bpp = 2; + if(bpp > 3) + bpp = 3; + + datasize = width * bpp * height; + if(width * bpp % 4) + datasize += height * (4 - width * bpp % 4); + + memset((void*)&bfh, 0, sizeof(bfh)); + bfh.bfType = 'B'+('M'<<8); + bfh.bfSize = sizeof(bfh) + sizeof(bih) + datasize; + bfh.bfOffBits = sizeof(bfh) + sizeof(bih); + memset((void*)&bih, 0, sizeof(bih)); + bih.biSize = sizeof(bih); + bih.biWidth = ddsd.dwWidth; + bih.biHeight = ddsd.dwHeight; + bih.biPlanes = 1; + bih.biBitCount = bpp * 8; + bih.biCompression = BI_RGB; + result = AppInfo.lpBackBuffer->GetDC(&surfDC); + + if(FAILED(result)) + goto cleanup; + + bitmap = CreateDIBSection(NULL, (BITMAPINFO *)&bih, DIB_RGB_COLORS, + &data, NULL, 0); + + if(!bitmap) + goto cleanup; + if(!data) + goto cleanup; + + memDC = CreateCompatibleDC(surfDC); + if(!memDC) + goto cleanup; + + oldbit = (HBITMAP)SelectObject(memDC, bitmap); + if(!oldbit || FAILED(oldbit)) + goto cleanup; + + result = BitBlt(memDC, 0, 0, width, height, surfDC, 0, 0, SRCCOPY); + if(!result) + goto cleanup; + + AppInfo.lpBackBuffer->ReleaseDC(surfDC); + surfDC = NULL; + + file = fopen(Name, "wb"); + + if(!file) + goto cleanup; + + fwrite((void*)&bfh, sizeof(bfh), 1, file); + fwrite((void*)&bih, sizeof(bih), 1, file); + fwrite((void*)data, 1, datasize, file); + + success = TRUE; + +cleanup: + + if(oldbit && !FAILED(oldbit)) + SelectObject(memDC, oldbit); + + if(memDC) + DeleteDC(memDC); + + if(surfDC) + AppInfo.lpBackBuffer->ReleaseDC(surfDC); + + if(bitmap) + DeleteObject(bitmap); + + if(file) + fclose(file); + + return success; + +} + + diff --git a/G3D/Engine/Drivers/D3DDrv/DDMemMgr.c b/G3D/Engine/Drivers/D3DDrv/DDMemMgr.c new file mode 100644 index 0000000..d5979e6 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/DDMemMgr.c @@ -0,0 +1,195 @@ +/****************************************************************************************/ +/* DDMemMgr.c */ +/* */ +/* Author: John Pollard */ +/* Description: Mini D3D memory manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "BaseType.h" +#include "DDMemMgr.h" + +#define DDMEMMGR_MAX_PARTITIONS 16 + +typedef struct DDMemMgr_Partition +{ + geBoolean Active; + uint32 FreeMem; + uint32 TotalMem; + +} DDMemMgr_Partition; + +typedef struct DDMemMgr +{ + uint32 TotalMem; + uint32 FreeMem; + DDMemMgr_Partition Partitions[DDMEMMGR_MAX_PARTITIONS]; +} DDMemMgr; + +//============================================================================ +// DDMemMgr_Create +//============================================================================ +DDMemMgr *DDMemMgr_Create(uint32 Size) +{ + DDMemMgr *MemMgr; + + MemMgr = (DDMemMgr*)malloc(sizeof(DDMemMgr)); + + if (!MemMgr) + return NULL; + + memset(MemMgr, 0, sizeof(DDMemMgr)); + + MemMgr->TotalMem = Size; + MemMgr->FreeMem = Size; + + return MemMgr; +} + +//============================================================================ +// DDMemMgr_Destroy +//============================================================================ +void DDMemMgr_Destroy(DDMemMgr *MemMgr) +{ + assert(MemMgr); + + free(MemMgr); +} + +//============================================================================ +// DDMemMgr_Reset +//============================================================================ +void DDMemMgr_Reset(DDMemMgr *MemMgr) +{ + int32 i; + + assert(MemMgr); + + MemMgr->FreeMem = MemMgr->TotalMem; + + for (i=0; iPartitions[i], 0, sizeof(DDMemMgr_Partition)); +} + +//============================================================================ +// DDMemMgr_GetFreeMem +//============================================================================ +uint32 DDMemMgr_GetFreeMem(DDMemMgr *MemMgr) +{ + assert(MemMgr); + return MemMgr->FreeMem; +} + +//============================================================================ +// DDMemMgr_PartitionCreate +//============================================================================ +DDMemMgr_Partition *DDMemMgr_PartitionCreate(DDMemMgr *MemMgr, uint32 Size) +{ + int32 i; + DDMemMgr_Partition *pPartition; + + assert(MemMgr); + + if (Size > MemMgr->FreeMem) + return NULL; + + pPartition = MemMgr->Partitions; + + for (i=0; i< DDMEMMGR_MAX_PARTITIONS; i++, pPartition++) + { + if (!pPartition->Active) + { + assert(pPartition->TotalMem == 0); + assert(pPartition->FreeMem == 0); + + pPartition->TotalMem = Size; + pPartition->FreeMem = Size; + pPartition->Active = GE_TRUE; + + MemMgr->FreeMem -= Size; + + assert(MemMgr->FreeMem >= 0); + + return pPartition; + } + } + + return NULL; +} + +//============================================================================ +// DDMemMgr_PartitionDestroy +//============================================================================ +void DDMemMgr_PartitionDestroy(DDMemMgr_Partition *Partition) +{ + assert(Partition); + assert(Partition->Active); + + memset(Partition, 0, sizeof(DDMemMgr_Partition)); +} + +//============================================================================ +// DDMemMgr_PartitionReset +//============================================================================ +void DDMemMgr_PartitionReset(DDMemMgr_Partition *Partition) +{ + assert(Partition->Active); + assert(Partition->FreeMem >= 0); + + Partition->FreeMem = Partition->TotalMem; +} + +//============================================================================ +// DDMemMgr_PArtitionGetTotalMem +//============================================================================ +uint32 DDMemMgr_PartitionGetTotalMem(DDMemMgr_Partition *Partition) +{ + assert(Partition); + assert(Partition->TotalMem >= 0); + + return Partition->TotalMem; +} + +//============================================================================ +// DDMemMgr_PArtitionGetFreeMem +//============================================================================ +uint32 DDMemMgr_PartitionGetFreeMem(DDMemMgr_Partition *Partition) +{ + assert(Partition); + assert(Partition->FreeMem >= 0); + + return Partition->FreeMem; +} + +//============================================================================ +// DDMemMgr_PartitionAllocMem +//============================================================================ +geBoolean DDMemMgr_PartitionAllocMem(DDMemMgr_Partition *Partition, uint32 Size) +{ + assert(Partition->Active); + + if (Partition->FreeMem < Size) + return GE_FALSE; + + Partition->FreeMem -= Size; + + assert(Partition->FreeMem >= 0); + + return GE_TRUE; +} diff --git a/G3D/Engine/Drivers/D3DDrv/DDMemMgr.h b/G3D/Engine/Drivers/D3DDrv/DDMemMgr.h new file mode 100644 index 0000000..a575f73 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/DDMemMgr.h @@ -0,0 +1,51 @@ +/****************************************************************************************/ +/* DDMemMgr.h */ +/* */ +/* Author: John Pollard */ +/* Description: Mini D3D memory manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DDMEMMGR_H +#define DDMEMMGR_H + +#include +#include + +#include "BaseType.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DDMemMgr DDMemMgr; +typedef struct DDMemMgr_Partition DDMemMgr_Partition; + +DDMemMgr *DDMemMgr_Create(uint32 Size); +void DDMemMgr_Destroy(DDMemMgr *MemMgr); +void DDMemMgr_Reset(DDMemMgr *MemMgr); +uint32 DDMemMgr_GetFreeMem(DDMemMgr *MemMgr); +DDMemMgr_Partition *DDMemMgr_PartitionCreate(DDMemMgr *MemMgr, uint32 Size); +void DDMemMgr_PartitionDestroy(DDMemMgr_Partition *Partition); +void DDMemMgr_PartitionReset(DDMemMgr_Partition *Partition); +uint32 DDMemMgr_PartitionGetTotalMem(DDMemMgr_Partition *Partition); +uint32 DDMemMgr_PartitionGetFreeMem(DDMemMgr_Partition *Partition); +geBoolean DDMemMgr_PartitionAllocMem(DDMemMgr_Partition *Partition, uint32 Size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/G3D/Engine/Drivers/D3DDrv/GSPAN.CPP b/G3D/Engine/Drivers/D3DDrv/GSPAN.CPP new file mode 100644 index 0000000..c4eda43 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/GSPAN.CPP @@ -0,0 +1,281 @@ +/****************************************************************************************/ +/* GSpan.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Front to back span code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "GSpan.h" + +SPAN SpanLines[MAX_SPAN_LINES]; + +SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +SLIST ScanHash[MAX_SPANS]; // hash table for SList + +BOOL PolyVisible = FALSE; + +int32 NumWorldPixels = 0; +int32 NumSpans = 0; +int32 NumSpanPixels[MAX_SPAN_LINES]; +int32 PolysRendered = 0; + +int32 CurrentSList = 0; + +const int32 CEIL_FRACT = ( ( 1 << 16)-1); +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2) +{ + int32 Ctmp; + int32 y; + int32 x,m; + + int32 ydelta; + int32 Dir; + int32 Cx1, Cx2, Cy1, Cy2; + SPAN *pSpans; + + Cx1 = x1; + Cx2 = x2; + Cy1 = y1; + Cy2 = y2; + + if (Cy2 != Cy1) // This isn't a horizontal line + { + Dir =0; // Left side + + if (Cy2 < Cy1) // Make sure y2 is greater than y1 + { + Dir =1; // Right side + + Ctmp = Cx1; + Cx1 = Cx2; + Cx2 = Ctmp; + + Ctmp = Cy1; + Cy1 = Cy2; + Cy2 = Ctmp; + + } + + ydelta = (Cy2 - Cy1); + + x = (Cx1 << 16) + CEIL_FRACT; // Allign on int amounts + m = (((Cx2 - Cx1))<<16) / ydelta; // How much to increase x each iteration + + pSpans = &SpanLines[Cy1]; + + if (!Dir) + { + for (y = Cy1; y <= Cy2; y++, pSpans++) + { + pSpans->x1 = (x>>16); + x += m; // Add our constant to x + } + } + else + { + for (y = Cy1; y <= Cy2; y++, pSpans++) + { + pSpans->x2 = (x>>16); + x += m; // Add our constant to x + } + } + } +} + +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y) +{ + int32 i, xx2; + SLIST *LineStart; + SLIST *Current; + SPAN_MINMAX *pSList; + + assert(y >=0 && y < MAX_SPAN_LINES); + + if (NumSpanPixels[y] >= ClientWindow.Width) + return; + + if (x1 > x2) // Swap all the coordinates so x1 < x2 + { + i = x1; + x1 = x2; + x2 = i; + } + + //if ( (x2 - x1) < 0) + // return; // Invalid line + + Current = SMinMax[y].First; + + LineStart = NULL; + + pSList = &SMinMax[y]; + + // Check to see if there are spans + // in the list yet... + if (!pSList->First) + { + pSList->First = NewSList(); + pSList->First->Last = NULL; + pSList->First->Next = NULL; + pSList->First->Min = x1; + pSList->First->Max = x2; + } + else while (Current != NULL) + { + if (x1 >= Current->Min && x2 <= Current->Max) + return; // This line totally hidden... + + //if falls before the entire min, max + if (LineStart == NULL) + { + if (Current == pSList->First) + if (x2 < Current->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current; + NewMinMax->Last = NULL; + Current->Last = NewMinMax; + pSList->First = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if falls in the middle (but not touching) + if (Current->Next != NULL) + if (x1 > Current->Max && x2 < (Current->Next)->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current->Next; + NewMinMax->Last = Current; + Current->Next->Last = NewMinMax; + Current->Next = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if it falls to the right of all spans + if (Current->Next == NULL) + if (x1 > Current->Max) + { + SLIST *NewMinMax = NewSList(); + Current->Next = NewMinMax; + NewMinMax->Next = NULL; + NewMinMax->Last = Current; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + } + //if we have already started crossing spans, and we find out + // that we are in front of a span, then we can bail out... + if (LineStart != NULL) + if (x2 < Current->Min) + goto WasNull; + + + // We now know that we have not fallen into any empty holes. + // We must now check to see what spans, we've crossed... + + // if split by a min/max + if (x1 < Current->Min && x2 > Current->Max) + { + xx2 = Current->Min-1; + Current->Min = x1; + + NumWorldPixels += xx2 - x1 + 1; + NumSpanPixels[y] += xx2 - x1 + 1; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + x1 = Current->Max+1; + Current->Max = x2; + if (LineStart!=NULL) + LineStart->Max = x2; + else + LineStart = Current; + goto next; + } + + if (x1 <= Current->Max && x2 > Current->Max) + { + x1 = Current->Max+1; + Current->Max = x2; + LineStart = Current; + goto next; + } + if (x1 < Current->Min && x2 >= Current->Min) + { + x2 = Current->Min-1; + Current->Min = x1; + if (LineStart!=NULL) + LineStart->Max = Current->Max; + goto WasNull; + } + next:; + Current = Current->Next; + } + WasNull:; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + NumWorldPixels += x2 - x1 + 1; + NumSpanPixels[y] += x2 - x1 + 1; +} + +void ResetSList(void) +{ + CurrentSList = 0; + NumSpans = 0; +} + +SLIST *NewSList(void) +{ + + CurrentSList++; + NumSpans++; + + assert(CurrentSList < MAX_SPANS); + + return &ScanHash[CurrentSList-1]; + + return NULL; +} + +void ResetSpans(int32 Rows) +{ + int32 i; + + for (i=0; i + +#define MAX_SPAN_LINES 1024 +#define MAX_SPANS 35000 + +typedef struct +{ + int32 x1; // Starting x on screen + int32 x2; // Ending x on screen +} SPAN; + +typedef struct _SList +{ + int32 Min, Max; + uint8 Used; + uint32 Flags; + _SList *Last; + _SList *Next; +} SLIST; + +typedef struct +{ + SLIST *First; + SLIST *Current; +} SPAN_MINMAX; + +extern SPAN SpanLines[MAX_SPAN_LINES]; + +extern SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +extern SLIST ScanHash[MAX_SPANS]; // hash table for SList + +extern int32 NumWorldPixels; +extern int32 NumSpans; +extern int32 NumSpanPixels[MAX_SPAN_LINES]; +extern int32 PolysRendered; + +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2); +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y); + +void ResetSList(void); +SLIST *NewSList(void); +void ResetSpans(int32 Rows); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3DDrv/Pcache.cpp b/G3D/Engine/Drivers/D3DDrv/Pcache.cpp new file mode 100644 index 0000000..ad3dc8b --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/Pcache.cpp @@ -0,0 +1,1463 @@ +/****************************************************************************************/ +/* PCache.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D poly cache */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DCache.h" +#include "D3D_Fx.h" + +#include "PCache.h" +#include "D3DDrv.h" +#include "THandle.h" +#include "D3D_Err.h" + + +//#define D3D_MANAGE_TEXTURES +//#define SUPER_FLUSH + +//==================================================================================== +// Local static variables +//==================================================================================== + +DRV_CacheInfo CacheInfo; + +// +// World Cache +// + +#if 1 + +#define MAX_WORLD_POLYS 512 +#define MAX_WORLD_POLY_VERTS 2048 + +#define MAX_MISC_POLYS 512 +#define MAX_MISC_POLY_VERTS 2048 + +#else + +#define MAX_WORLD_POLYS 256 +#define MAX_WORLD_POLY_VERTS 4096 + +#define MAX_MISC_POLYS 256 +#define MAX_MISC_POLY_VERTS 4096 + +#endif + +typedef struct +{ + geFloat u; + geFloat v; + //geFloat a; + uint32 Color; +} PCache_TVert; + +typedef struct +{ + geRDriver_THandle *THandle; + + DRV_LInfo *LInfo; // Original pointer to linfo + uint32 Flags; // Flags for this poly + geFloat ShiftU; + geFloat ShiftV; + geFloat ScaleU; + geFloat ScaleV; + int32 MipLevel; + uint32 SortKey; + int32 FirstVert; + int32 NumVerts; +} World_Poly; + +#define MAX_TEXTURE_STAGES 2 // Up to 2 tmu's (stages) + +// Verts we defined in the D3D flexible vertex format (FVF) +// This is a transformed and lit vertex definition, with up to 8 sets of uvs +typedef struct +{ + geFloat u,v; +} PCache_UVSet; + +typedef struct +{ + geFloat x,y,z; // Screen x, y, z + geFloat rhw; // homogenous w + DWORD color; // color + DWORD specular; + PCache_UVSet uv[MAX_TEXTURE_STAGES]; // uv sets for each stage +} PCache_Vert; + +typedef struct +{ + World_Poly Polys[MAX_WORLD_POLYS]; + World_Poly *SortedPolys[MAX_WORLD_POLYS]; + World_Poly *SortedPolys2[MAX_WORLD_POLYS]; + PCache_Vert Verts[MAX_WORLD_POLY_VERTS]; + + PCache_TVert TVerts[MAX_WORLD_POLY_VERTS]; // Original uv + + int32 NumPolys; + int32 NumPolys2; + int32 NumVerts; +} World_Cache; + +static World_Cache WorldCache; + +#define PREP_WORLD_VERTS_NORMAL 1 // Prep verts as normal +#define PREP_WORLD_VERTS_LMAP 2 // Prep verts as lightmaps +#define PREP_WORLD_VERTS_SINGLE_PASS 3 // Prep verts for a single pass + +#define RENDER_WORLD_POLYS_NORMAL 1 // Render polys as normal +#define RENDER_WORLD_POLYS_LMAP 2 // Render polys as lightmaps +#define RENDER_WORLD_POLYS_SINGLE_PASS 3 + +// +// Misc cache +// + +typedef struct +{ + geRDriver_THandle *THandle; + uint32 Flags; // Flags for this poly + int32 MipLevel; + int32 FirstVert; + int32 NumVerts; + + uint32 SortKey; +} Misc_Poly; + +typedef struct +{ + Misc_Poly Polys[MAX_MISC_POLYS]; + Misc_Poly *SortedPolys[MAX_MISC_POLYS]; + PCache_Vert Verts[MAX_MISC_POLY_VERTS]; + //geFloat ZVert[MAX_MISC_POLY_VERTS]; + + int32 NumPolys; + int32 NumVerts; +} Misc_Cache; + +static Misc_Cache MiscCache; + +//==================================================================================== +// Local static functions prototypes +//==================================================================================== +geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2); + +static BOOL RenderWorldPolys(int32 RenderMode); +static BOOL ClearWorldCache(void); +static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, geFloat ScaleU, geFloat ScaleV, int32 MaxMipLevel); + +#include + +//==================================================================================== +// PCache_InsertWorldPoly +//==================================================================================== +BOOL PCache_InsertWorldPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ + int32 Mip; + geFloat ZRecip, DrawScaleU, DrawScaleV; + World_Poly *pCachePoly; + DRV_TLVertex *pVerts; + PCache_TVert *pTVerts; + PCache_Vert *pD3DVerts; + int32 i; + uint32 Alpha; + + #ifdef _DEBUG + if (LInfo) + { + assert(LInfo->THandle); + } + #endif + + if ((WorldCache.NumVerts + NumVerts) >= MAX_WORLD_POLY_VERTS) + { + // If the cache is full, we must flush it before going on... + if (!PCache_FlushWorldPolys()) + return GE_FALSE; + } + else if (WorldCache.NumPolys+1 >= MAX_WORLD_POLYS) + { + // If the cache is full, we must flush it before going on... + if (!PCache_FlushWorldPolys()) + return GE_FALSE; + } + + DrawScaleU = 1.0f / TexInfo->DrawScaleU; + DrawScaleV = 1.0f / TexInfo->DrawScaleV; + + Mip = GetMipLevel(Verts, NumVerts, DrawScaleU, DrawScaleV, THandle->NumMipLevels-1); + + // Get a pointer to the original polys verts + pVerts = Verts; + + // Store info about this poly in the cache + pCachePoly = &WorldCache.Polys[WorldCache.NumPolys]; + + pCachePoly->THandle = THandle; + pCachePoly->LInfo = LInfo; + pCachePoly->Flags = Flags; + pCachePoly->FirstVert = WorldCache.NumVerts; + pCachePoly->NumVerts = NumVerts; + pCachePoly->ShiftU = TexInfo->ShiftU; + pCachePoly->ShiftV = TexInfo->ShiftV; + pCachePoly->ScaleU = DrawScaleU; + pCachePoly->ScaleV = DrawScaleV; + pCachePoly->MipLevel = Mip; + + // Don't forget the sort key: + pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip; + + // Get a pointer into the world verts + pD3DVerts = &WorldCache.Verts[WorldCache.NumVerts]; + pTVerts = &WorldCache.TVerts[WorldCache.NumVerts]; + + if (Flags & DRV_RENDER_ALPHA) + Alpha = (uint32)pVerts->a<<24; + else + Alpha = (uint32)(255<<24); + + for (i=0; i< NumVerts; i++) + { + ZRecip = 1.0f/(pVerts->z); + + pD3DVerts->x = pVerts->x; + pD3DVerts->y = pVerts->y; + + pD3DVerts->z = (1.0f - ZRecip); // ZBUFFER + pD3DVerts->rhw = ZRecip; + + if (AppInfo.FogEnable && !(Flags & DRV_RENDER_POLY_NO_FOG)) // poly fog + { + DWORD FogVal; + geFloat Val; + + Val = pVerts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DVerts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DVerts->specular = 0; + + // Store the uv's so the prep pass can use them... + pTVerts->u = pVerts->u; + pTVerts->v = pVerts->v; + + pTVerts->Color = Alpha | ((uint32)pVerts->r<<16) | ((uint32)pVerts->g<<8) | (uint32)pVerts->b; + + pTVerts++; + pVerts++; + pD3DVerts++; + + } + + // Update globals about the world poly cache + WorldCache.NumVerts += NumVerts; + WorldCache.NumPolys++; + + return TRUE; +} + +//==================================================================================== +// PCache_FlushWorldPolys +//==================================================================================== +BOOL PCache_FlushWorldPolys(void) +{ + if (!WorldCache.NumPolys) + return TRUE; + + if (!THandle_CheckCache()) + return GE_FALSE; + + if (AppInfo.CanDoMultiTexture) + { + RenderWorldPolys(RENDER_WORLD_POLYS_SINGLE_PASS); + } + else + { + // Render them as normal + if (!RenderWorldPolys(RENDER_WORLD_POLYS_NORMAL)) + return GE_FALSE; + + // Render them as lmaps + RenderWorldPolys(RENDER_WORLD_POLYS_LMAP); + } + + ClearWorldCache(); + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +static int MiscBitmapHandleComp(const void *a, const void *b) +{ + uint32 Id1, Id2; + + Id1 = (uint32)(*(Misc_Poly**)a)->SortKey; + Id2 = (uint32)(*(Misc_Poly**)b)->SortKey; + + if ( Id1 == Id2) + return 0; + + if (Id1 < Id2) + return -1; + + return 1; +} + +//==================================================================================== +//==================================================================================== +static void SortMiscPolysByHandle(void) +{ + Misc_Poly *pPoly; + int32 i; + + pPoly = MiscCache.Polys; + + for (i=0; iTHandle; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + Size = 1<Log; + + Lut = &AppInfo.Lut1; + + THandle_Lock(THandle, 0, (void**)&pTempBits); + + Extra = Size - Width; + U8 R, G, B; + U16 Color; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + THandle_UnLock(THandle, 0); +} + +#ifdef USE_TPAGES +//===================================================================================== +// FillLMapSurface +//===================================================================================== +static void FillLMapSurface2(DRV_LInfo *LInfo, int32 LNum) +{ + U16 *pTempBits; + int32 w, h, Width, Height, Stride; + U8 *pBitPtr; + RGB_LUT *Lut; + geRDriver_THandle *THandle; + HRESULT Result; + const RECT *pRect; + DDSURFACEDESC2 SurfDesc; + LPDIRECTDRAWSURFACE4 Surface; + int32 Extra; + + THandle = LInfo->THandle; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + + Lut = &AppInfo.Lut1; + + pRect = TPage_BlockGetRect(THandle->Block); + Surface = TPage_BlockGetSurface(THandle->Block); + + memset(&SurfDesc, 0, sizeof(DDSURFACEDESC2)); + SurfDesc.dwSize = sizeof(DDSURFACEDESC2); + + Result = Surface->Lock((RECT*)pRect, &SurfDesc, DDLOCK_WAIT, NULL); + + assert(Result == DD_OK); + + Stride = SurfDesc.dwWidth; + + pTempBits = (U16*)SurfDesc.lpSurface; + + Extra = Stride - Width; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + U8 R, G, B; + U16 Color; + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + Result = Surface->Unlock((RECT*)pRect); + + assert(Result == DD_OK); +} +#endif + +//===================================================================================== +// LoadLMapFromSystem +//===================================================================================== +static void LoadLMapFromSystem(DRV_LInfo *LInfo, int32 Log, int32 LNum) +{ + U16 *pTempBits; + int32 w, h, Width, Height, Size, Extra; + U8 *pBitPtr; + LPDIRECTDRAWSURFACE4 Surface; + RGB_LUT *Lut; + DDSURFACEDESC2 ddsd; + HRESULT ddrval; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + Size = 1<Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + + assert(ddrval == DD_OK); + U8 R, G, B; + U16 Color; + + pTempBits = (USHORT*)ddsd.lpSurface; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + ddrval = Surface->Unlock(NULL); + assert(ddrval == DD_OK); +} + +static BOOL IsKeyDown(int KeyCode) +{ + if (GetAsyncKeyState(KeyCode) & 0x8000) + return TRUE; + + return FALSE; +} + +extern uint32 CurrentLRU; + +//===================================================================================== +// SetupMipData +//===================================================================================== +geBoolean SetupMipData(THandle_MipData *MipData) +{ + if (!MipData->Slot || D3DCache_SlotGetUserData(MipData->Slot) != MipData) + { + MipData->Slot = D3DCache_TypeFindSlot(MipData->CacheType); + assert(MipData->Slot); + + D3DCache_SlotSetUserData(MipData->Slot, MipData); + + #ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + #endif + + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// SetupLMap +//===================================================================================== +geBoolean SetupLMap(int32 Stage, DRV_LInfo *LInfo, int32 LNum, geBoolean Dynamic) +{ +#ifdef D3D_MANAGE_TEXTURES + #ifdef USE_TPAGES + { + geRDriver_THandle *THandle; + + THandle = LInfo->THandle; + + if (Dynamic) + THandle->Flags |= THANDLE_UPDATE; + + if (!THandle->Block) + { + THandle->Block = TPage_MgrFindOptimalBlock(TPageMgr, CurrentLRU); + THandle->Flags |= THANDLE_UPDATE; + TPage_BlockSetUserData(THandle->Block, THandle); + assert(THandle->Block); + } + else if (TPage_BlockGetUserData(THandle->Block) != THandle) + { + // Find another block + THandle->Block = TPage_MgrFindOptimalBlock(TPageMgr, CurrentLRU); + assert(THandle->Block); + + THandle->Flags |= THANDLE_UPDATE; + TPage_BlockSetUserData(THandle->Block, THandle); + } + + if (THandle->Flags & THANDLE_UPDATE) + FillLMapSurface2(LInfo, LNum); + + TPage_BlockSetLRU(THandle->Block, CurrentLRU); + D3DSetTexture(Stage, TPage_BlockGetTexture(THandle->Block)); + + if (Dynamic) + THandle->Flags |= THANDLE_UPDATE; + else + THandle->Flags &= ~THANDLE_UPDATE; + + return GE_TRUE; + } + #else + { + geRDriver_THandle *THandle; + + THandle = LInfo->THandle; + + if (Dynamic) + THandle->MipData[0].Flags |= THANDLE_UPDATE; + + if (THandle->MipData[0].Flags & THANDLE_UPDATE) + FillLMapSurface(LInfo, LNum); + + D3DSetTexture(Stage, THandle->MipData[0].Texture); + + if (Dynamic) + THandle->MipData[0].Flags |= THANDLE_UPDATE; + else + THandle->MipData[0].Flags &= ~THANDLE_UPDATE; + + return GE_TRUE; + } + #endif + +#else + geRDriver_THandle *THandle; + THandle_MipData *MipData; + + THandle = LInfo->THandle; + MipData = &THandle->MipData[0]; + + if (Dynamic) + MipData->Flags |= THANDLE_UPDATE; + + if (!SetupMipData(MipData)) + { + MipData->Flags |= THANDLE_UPDATE; // Force an upload + CacheInfo.LMapMisses++; + } + + if (MipData->Flags & THANDLE_UPDATE) + { + HRESULT Error; + LPDIRECTDRAWSURFACE4 Surface; + + assert(MipData->Slot); + + Surface = D3DCache_SlotGetSurface(MipData->Slot); + + assert(Surface); + assert(THandle->Log < MAX_LMAP_LOG_SIZE); + assert(SystemToVideo[THandle->Log].Surface); + + LoadLMapFromSystem(LInfo, THandle->Log, LNum); + + Error = Surface->BltFast(0, 0, SystemToVideo[THandle->Log].Surface, NULL, DDBLTFAST_WAIT); + //Error = Surface->BltFast(0, 0, SystemToVideo[THandle->Log].Surface, NULL, 0); + //Error = Surface->Blt(NULL, SystemToVideo[THandle->Log].Surface, NULL, DDBLT_WAIT, NULL); + //Error = Surface->Blt(NULL, SystemToVideo[THandle->Log].Surface, NULL, 0, NULL); + + if (Error != DD_OK) + { + if(Error==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return GE_FALSE; + } + else + { + D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error)); + return GE_FALSE; + } + } + } + + if (Dynamic) // If it was dynmamic, force an update for one more frame + MipData->Flags |= THANDLE_UPDATE; + else + MipData->Flags &= ~THANDLE_UPDATE; + + D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU); + D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot)); + + return GE_TRUE; +#endif +} + +//===================================================================================== +// SetupTexture +//===================================================================================== +geBoolean SetupTexture(int32 Stage, geRDriver_THandle *THandle, int32 MipLevel) +{ +#ifdef D3D_MANAGE_TEXTURES + D3DSetTexture(Stage, THandle->MipData[MipLevel].Texture); + return GE_TRUE; +#else + THandle_MipData *MipData; + + MipData = &THandle->MipData[MipLevel]; + + if (!SetupMipData(MipData)) + { + MipData->Flags |= THANDLE_UPDATE; // Force an upload + CacheInfo.TexMisses++; + } + + if (MipData->Flags & THANDLE_UPDATE) + { + HRESULT Error; + LPDIRECTDRAWSURFACE4 Surface; + + Surface = D3DCache_SlotGetSurface(MipData->Slot); + + Error = Surface->BltFast(0, 0, MipData->Surface, NULL, DDBLTFAST_WAIT); + + if (Error != DD_OK) + { + if(Error==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return FALSE; + } + else + { + D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error)); + return GE_FALSE; + } + } + } + + MipData->Flags &= ~THANDLE_UPDATE; + + D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU); + D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot)); + + return GE_TRUE; +#endif +} + +//==================================================================================== +// PCache_FlushMiscPolys +//==================================================================================== +BOOL PCache_FlushMiscPolys(void) +{ + int32 i; + Misc_Poly *pPoly; + + if (!MiscCache.NumPolys) + return TRUE; + + if (!THandle_CheckCache()) + return GE_FALSE; + + // Set the render states + if (AppInfo.CanDoMultiTexture) + { + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + D3DSetTexture(1, NULL); // Reset texture stage 1 + } + + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + D3DBlendEnable(TRUE); + + // Sort the polys by handle + SortMiscPolysByHandle(); + + for (i=0; i< MiscCache.NumPolys; i++) + { + pPoly = MiscCache.SortedPolys[i]; + + if (pPoly->Flags & DRV_RENDER_NO_ZMASK) // We are assuming that this is not going to change all that much + D3DZEnable(FALSE); + else + D3DZEnable(TRUE); + + if (pPoly->Flags & DRV_RENDER_NO_ZWRITE) // We are assuming that this is not going to change all that much + D3DZWriteEnable(FALSE); + else + D3DZWriteEnable(TRUE); + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(0, FALSE); + else + D3DTexWrap(0, TRUE); + + if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + + D3DTexturedPoly(&MiscCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + + // Turn z stuff back on... + D3DZWriteEnable (TRUE); + D3DZEnable(TRUE); + + MiscCache.NumPolys = 0; + MiscCache.NumVerts = 0; + +#ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); +#endif + + return TRUE; +} + +//==================================================================================== +// PCache_InsertMiscPoly +//==================================================================================== +BOOL PCache_InsertMiscPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, uint32 Flags) +{ + int32 Mip; + geFloat ZRecip, u, v, ScaleU, ScaleV, InvScale; + Misc_Poly *pCachePoly; + DRV_TLVertex *pVerts; + PCache_Vert *pD3DVerts; + int32 i, SAlpha; + + if ((MiscCache.NumVerts + NumVerts) >= MAX_MISC_POLY_VERTS) + { + // If the cache is full, we must flush it before going on... + PCache_FlushMiscPolys(); + } + else if (MiscCache.NumPolys+1 >= MAX_MISC_POLYS) + { + // If the cache is full, we must flush it before going on... + PCache_FlushMiscPolys(); + } + + Mip = GetMipLevel(Verts, NumVerts, (geFloat)THandle->Width, (geFloat)THandle->Height, THandle->NumMipLevels-1); + + // Store info about this poly in the cache + pCachePoly = &MiscCache.Polys[MiscCache.NumPolys]; + + pCachePoly->THandle = THandle; + pCachePoly->Flags = Flags; + pCachePoly->FirstVert = MiscCache.NumVerts; + pCachePoly->NumVerts = NumVerts; + pCachePoly->MipLevel = Mip; + pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip; + + // Get scale value for vertices + //TCache_GetUVInvScale(Bitmap, Mip, &InvScale); + InvScale = 1.0f / (geFloat)((1<Log)); + + // Convert them to take account that the vertices are allready from 0 to 1 + ScaleU = (geFloat)THandle->Width * InvScale; + ScaleV = (geFloat)THandle->Height * InvScale; + + // Precompute the alpha value... + SAlpha = ((int32)Verts->a)<<24; + + // Get a pointer to the original polys verts + pVerts = Verts; + // Get a pointer into the world verts + pD3DVerts = &MiscCache.Verts[MiscCache.NumVerts]; + + for (i=0; i< NumVerts; i++) + { + ZRecip = 1/(pVerts->z); + + pD3DVerts->x = pVerts->x; + pD3DVerts->y = pVerts->y; + + pD3DVerts->z = (1.0f - ZRecip); // ZBUFFER + pD3DVerts->rhw = ZRecip; + + u = pVerts->u * ScaleU; + v = pVerts->v * ScaleV; + + pD3DVerts->uv[0].u = u; + pD3DVerts->uv[0].v = v; + + pD3DVerts->color = SAlpha | ((int32)pVerts->r<<16) | ((int32)pVerts->g<<8) | (int32)pVerts->b; + + if (AppInfo.FogEnable && !(Flags & DRV_RENDER_POLY_NO_FOG) ) // poly fog + { + DWORD FogVal; + geFloat Val; + + Val = pVerts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DVerts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DVerts->specular = 0; + + pVerts++; + pD3DVerts++; + } + + // Update globals about the misc poly cache + MiscCache.NumVerts += NumVerts; + MiscCache.NumPolys++; + + return TRUE; +} + +//==================================================================================== +// **** LOCAL STATIC FUNCTIONS ***** +//==================================================================================== + +//==================================================================================== +// World_PolyPrepVerts +//==================================================================================== +geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2) +{ + geFloat InvScale, u, v; + PCache_TVert *pTVerts; + PCache_Vert *pVerts; + geFloat ShiftU, ShiftV, ScaleU, ScaleV; + geFloat InvScale2, ShiftU2, ShiftV2; + int32 j; + + switch (PrepMode) + { + case PREP_WORLD_VERTS_NORMAL: + { + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + + ShiftU = pPoly->ShiftU; + ShiftV = pPoly->ShiftV; + ScaleU = pPoly->ScaleU; + ScaleV = pPoly->ScaleV; + + // Get scale value for vertices + InvScale = 1.0f / (geFloat)((1<THandle->Log)); + + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u*ScaleU+ShiftU; + v = pTVerts->v*ScaleV+ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + pVerts->color = pTVerts->Color; + + pTVerts++; + pVerts++; + } + + break; + } + + case PREP_WORLD_VERTS_LMAP: + { + if (!pPoly->LInfo) + return GE_TRUE; + + ShiftU = (geFloat)-pPoly->LInfo->MinU + 8.0f; + ShiftV = (geFloat)-pPoly->LInfo->MinV + 8.0f; + + // Get scale value for vertices + InvScale = 1.0f/(geFloat)((1<LInfo->THandle->Log)<<4); + + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u + ShiftU; + v = pTVerts->v + ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + pVerts->color = 0xffffffff; + + pTVerts++; + pVerts++; + } + break; + } + + case PREP_WORLD_VERTS_SINGLE_PASS: + { + + assert(pPoly->LInfo); + + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + + // Set up shifts and scaled for texture uv's + ShiftU = pPoly->ShiftU; + ShiftV = pPoly->ShiftV; + ScaleU = pPoly->ScaleU; + ScaleV = pPoly->ScaleV; + + // Get scale value for vertices + InvScale = 1.0f / (geFloat)((1<THandle->Log)); + + // Set up shifts and scaled for lightmap uv's + ShiftU2 = (geFloat)-pPoly->LInfo->MinU + 8.0f; + ShiftV2 = (geFloat)-pPoly->LInfo->MinV + 8.0f; + InvScale2 = 1.0f/(geFloat)((1<LInfo->THandle->Log)<<4); + + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u*ScaleU+ShiftU; + v = pTVerts->v*ScaleV+ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + u = pTVerts->u + ShiftU2; + v = pTVerts->v + ShiftV2; + + pVerts->uv[Stage2].u = u * InvScale2; + pVerts->uv[Stage2].v = v * InvScale2; + + pVerts->color = pTVerts->Color; + + pTVerts++; + pVerts++; + } + + break; + } + + default: + return FALSE; + } + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +static int BitmapHandleComp(const void *a, const void *b) +{ + int32 Id1, Id2; + + Id1 = (*(World_Poly**)a)->SortKey; + Id2 = (*(World_Poly**)b)->SortKey; + + if ( Id1 == Id2) + return 0; + + if (Id1 < Id2) + return -1; + + return 1; +} + +//==================================================================================== +//==================================================================================== +static void SortWorldPolysByHandle(void) +{ + World_Poly *pPoly; + int32 i; + + pPoly = WorldCache.Polys; + + for (i=0; iSetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); + + // Set the default state for the normal poly render mode for the world + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + // Get the first poly in the sorted list + SortWorldPolysByHandle(); + + for (i=0; i< WorldCache.NumPolys; i++) + { + pPoly = WorldCache.SortedPolys[i]; + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(0, FALSE); + else + D3DTexWrap(0, TRUE); + + if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, 0, 0); + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + } + + break; + } + + case RENDER_WORLD_POLYS_LMAP: + { + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); + + D3DTexWrap(0, FALSE); + + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO); + + pPoly = WorldCache.Polys; + BOOL Dynamic = 0; + + for (i=0; i< WorldCache.NumPolys; i++, pPoly++) + { + + if (!pPoly->LInfo) + continue; + + // Call the engine to set this sucker up, because it's visible... + D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic); + + if (!SetupLMap(0, pPoly->LInfo, 0, Dynamic)) + return GE_FALSE; + + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_LMAP, 0, 0); + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if (pPoly->LInfo->RGBLight[1]) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE); + + D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE); // Change to a fog state + + // For some reason, some cards can't upload data to the same texture twice, and have it take. + // So we force Fog maps to use a different slot than the lightmap was using... + pPoly->LInfo->THandle->MipData[0].Slot = NULL; + + if (!SetupLMap(0, pPoly->LInfo, 1, 1)) // Dynamic is 1, because fog is always dynamic + return GE_FALSE; + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO); // Restore state + + if (AppInfo.FogEnable) + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + } + break; + } + + case RENDER_WORLD_POLYS_SINGLE_PASS: + { + // Setup texture stage states + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT ); + //AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + + // Setup frame buffer blend modes + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + // Set the default state for the normal poly render mode for the world + D3DTexWrap(TSTAGE_0, TRUE); + D3DTexWrap(TSTAGE_1, FALSE); + + // Sort the list for front back operation to get the least number of world texture misses + SortWorldPolysByHandle(); + + // Reset non lightmaps faces to 0 + WorldCache.NumPolys2 = 0; + + for (i=0; i< WorldCache.NumPolys; i++) + { + BOOL Dynamic = 0; + + pPoly = WorldCache.SortedPolys[i]; + + if (!pPoly->LInfo) + { + // Put gouraud only polys in a seperate list, and render last + WorldCache.SortedPolys2[WorldCache.NumPolys2++] = pPoly; + continue; + } + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(TSTAGE_0, FALSE); + else + D3DTexWrap(TSTAGE_0, TRUE); + + if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + // Call the engine to set this sucker up, because it's visible... + D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic); + + if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 0, Dynamic)) + return GE_FALSE; + + // Prep the verts for a lightmap and texture map + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_SINGLE_PASS, TSTAGE_0, TSTAGE_1); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + + // Draw the texture + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + + // Render any fog maps + if (pPoly->LInfo->RGBLight[1]) + { + D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE); // Change to a fog state + + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + #endif + + // For some reason, some cards can't upload data to the same texture twice, and have it take. + // So we force Fog maps to use a different slot other than what the lightmap was using... + pPoly->LInfo->THandle->MipData[0].Slot = NULL; + + if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 1, 1)) // Dynamic is 1, because fog is always dynamic + return GE_FALSE; + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + // Restore states to the last state before fag map + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + #endif + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + } + + + } + + // Setup for any non-lightmaped faces faces, turn tmu1 off + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + #endif + + // Render all the faces without lightmaps + for (i=0; i< WorldCache.NumPolys2; i++) + { + BOOL Dynamic = 0; + + pPoly = WorldCache.SortedPolys2[i]; + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(TSTAGE_0, FALSE); + else + D3DTexWrap(TSTAGE_0, TRUE); + + if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + // Prep verts as if there was no lightmap + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, TSTAGE_0, TSTAGE_1); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + + // Draw the texture + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if ( (pPoly->Flags & DRV_RENDER_POLY_NO_FOG) && AppInfo.FogEnable) // poly fog + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + + break; + } + + default: + return FALSE; + } + + + return TRUE; +} + +//==================================================================================== +// ClearWorldCache +//==================================================================================== +static BOOL ClearWorldCache(void) +{ + WorldCache.NumPolys = 0; + WorldCache.NumVerts = 0; + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +BOOL PCache_Reset(void) +{ + WorldCache.NumPolys = 0; + WorldCache.NumVerts = 0; + + MiscCache.NumPolys = 0; + MiscCache.NumVerts = 0; + + return TRUE; +} + +//==================================================================================== +// GetMipLevel +//==================================================================================== +static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, geFloat ScaleU, geFloat ScaleV, int32 MaxMipLevel) +{ + int32 Mip; + + if (MaxMipLevel == 0) + return 0; + + // + // Get the MipLevel + // + { + geFloat du, dv, dx, dy, MipScale; + + #if 1 // WAY slower, but more accurate + int32 i; + + MipScale = 999999.0f; + + geFloat MipScaleT; + DRV_TLVertex *pVert0, *pVert1; + int32 i2; + + for (i=0; i< NumVerts; i++) + { + + i2 = i+1; + + if (i2 >= NumVerts) + i2=0; + + pVert0 = &Verts[i]; + pVert1 = &Verts[i2]; + + du = pVert1->u - pVert0->u; + dv = pVert1->v - pVert0->v; + dx = pVert1->x - pVert0->x; + dy = pVert1->y - pVert0->y; + + du *= ScaleU; + dv *= ScaleV; + + MipScaleT = ((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy)); + + if (MipScaleT < MipScale) + MipScale = MipScaleT; // Record the best MipScale (the one closest to the the eye) + } + #else // Faster, less accurate + du = Verts[1].u - Verts[0].u; + dv = Verts[1].v - Verts[0].v; + dx = Verts[1].x - Verts[0].x; + dy = Verts[1].y - Verts[0].y; + + du *= ScaleU; + dv *= ScaleV; + + MipScale = ((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy)); + #endif + + #if 0 + if (MipScale <= 5) // 2, 6, 12 + Mip = 0; + else if (MipScale <= 20) + Mip = 1; + else if (MipScale <= 45) + Mip = 2; + else + Mip = 3; + #else + if (MipScale <= 4) // 2, 6, 12 + Mip = 0; + else if (MipScale <= 15) + Mip = 1; + else if (MipScale <= 40) + Mip = 2; + else + Mip = 3; + #endif + } + + if (Mip > MaxMipLevel) + Mip = MaxMipLevel; + + return Mip; +} \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3DDrv/Pcache.h b/G3D/Engine/Drivers/D3DDrv/Pcache.h new file mode 100644 index 0000000..5e55574 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/Pcache.h @@ -0,0 +1,35 @@ +/****************************************************************************************/ +/* PCache.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D poly cache */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef PCACHE_H +#define PCACHE_H + +extern DRV_CacheInfo CacheInfo; + +BOOL PCache_InsertWorldPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +BOOL PCache_FlushWorldPolys(void); + +BOOL PCache_FlushMiscPolys(void); +BOOL PCache_InsertMiscPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, uint32 Flags); + +BOOL PCache_Reset(void); + +#endif diff --git a/G3D/Engine/Drivers/D3DDrv/README.NOW b/G3D/Engine/Drivers/D3DDrv/README.NOW new file mode 100644 index 0000000..735c1fc --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/README.NOW @@ -0,0 +1,22 @@ +D3DDRV.DLL MIPMAP SELECTION MODIFICATION +by Ed Averill, Rabid Games +11/03/1999 + + Here is the modified PCACHE.CPP and the release-compiled +D3DDRV.DLL. This driver has a modification to take the AVERAGE +of all polygon edges and perform MIP selection computation on +this average, instead of the shipping drivers computation based +on only the first edge in the list. This driver appears to +remove most MIP artifacts, at least in the levels I've tested +it with. + + BE SURE TO BACK UP YOUR OLD DRIVER IN CASE THIS ONE +DOESN'T WORK FOR YOU!!!! There may be a small loss in frame +rate as more detailed MIPS are selected more often than with +the original driver. Note that my bias is in favor of visual +accuracy at the cost of frame-rate, your mileage may vary, +this offer void where prohibited by law, all the usual +disclaimers apply. When in doubt, Use the Source, Luke. + +Ed Averill, Rabid Games +http://www.rabidgames.com diff --git a/G3D/Engine/Drivers/D3DDrv/RENDER.H b/G3D/Engine/Drivers/D3DDrv/RENDER.H new file mode 100644 index 0000000..f000b0a --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/RENDER.H @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* Render.h */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render polys under D3D */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef RENDER_H +#define RENDER_H + +#include + +#include "DCommon.h" + +geBoolean DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags); +geBoolean DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +geBoolean DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags); +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y); + +#endif diff --git a/G3D/Engine/Drivers/D3DDrv/Render.cpp b/G3D/Engine/Drivers/D3DDrv/Render.cpp new file mode 100644 index 0000000..60deb90 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/Render.cpp @@ -0,0 +1,316 @@ +/****************************************************************************************/ +/* Render.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render polys under D3D */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" +#include "Render.h" +#include "Scene.h" +#include "GSpan.h" +#include "D3D_Fx.h" +#include "D3DCache.h" +#include "D3D_Err.h" +#include "THandle.h" + +#include "PCache.h" + +#define SNAP_VERT(v) ( ( v ) = ( geFloat )( ( long )( ( v ) * 16 ) ) / 16.0f ) + +geBoolean DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags) +{ + int32 i; + DRV_TLVertex *pPnts; + D3DTLVERTEX D3DPnts[30], *pD3DPnts; + geFloat ZRecip; + geFloat Alpha; + + if(!AppInfo.RenderingIsOK) + return TRUE; + + if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + if (!PCache_FlushMiscPolys()) + return FALSE; + } + + Alpha = Pnts->a; + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + D3DSetTexture(0, NULL); + + int32 SAlpha = (int32)Alpha<<24; + pPnts = Pnts; + pD3DPnts = D3DPnts; + for (i=0; i< NumPoints; i++) + { + ZRecip = 1/pPnts->z; + + pD3DPnts->sx = pPnts->x; + pD3DPnts->sy = pPnts->y; + pD3DPnts->sz = (1.0f - ZRecip); // ZBUFFER + pD3DPnts->rhw = ZRecip; + pD3DPnts->color = SAlpha | ((int32)pPnts->r<<16) | ((int32)pPnts->g<<8) | (int32)pPnts->b; + + if (AppInfo.FogEnable && !(Flags & DRV_RENDER_POLY_NO_FOG)) // poly fog + { + DWORD FogVal; + geFloat Val; + + Val = pPnts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DPnts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DPnts->specular = 0; + + pPnts++; + pD3DPnts++; + } + + D3DTexturedPolyOld(D3DPnts, NumPoints); + + if (Flags & DRV_RENDER_FLUSH) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + } + + return TRUE; +} + +geBoolean DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ +#ifdef USE_SPANS + int32 i; + DRV_TLVertex *CPnt; + int32 OldPixels; + int32 Mip = 0; + int32 MinY, MaxY, MinX, MaxX; + int32 FirstX, FirstY, x1, y1, x2, y2; + SPAN *pSpans; + int32 WidthHeight; +#endif + + if(!AppInfo.RenderingIsOK) + { + return TRUE; + } + else if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + } + +#ifdef USE_SPANS + if (RenderMode != RENDER_WORLD) + goto NotWorld; + + CPnt = Pnts; // Set to the first points in the array + + x1 = (int32)CPnt->x; + y1 = (int32)CPnt->y; + + FirstX = MinX = MaxX = x1; + FirstY = MinY = MaxY = y1; + + for (i = 1; i < NumPoints; i++) + { + CPnt++; + + x2 = (int32)CPnt->x; + y2 = (int32)CPnt->y; + + EdgeOutNoUV (x1, y1, x2, y2); + + if (x2 > MaxX) + MaxX = x2; + else if (x2 < MinX) + MinX = x2; + + if (y2 > MaxY) + MaxY = y2; + else if (y2 < MinY) + MinY = y2; + + // Swap + x1 = x2; + y1 = y2; + } + + // Close the poly + EdgeOutNoUV (x1, y1, FirstX, FirstY); + + OldPixels = NumWorldPixels; + + pSpans = &SpanLines[MinY]; + + WidthHeight = ClientWindow.Width*ClientWindow.Height; + for (i = MinY; i <= MaxY; i++, pSpans++) + { + AddSpanNoUV(pSpans->x1, pSpans->x2, i); + + if (NumWorldPixels >= WidthHeight) + break; + } + + if ((MaxY - MinY) < 3) + goto NotWorld; + + if ((MaxX - MinX) < 3) + goto NotWorld; + + if (NumWorldPixels == OldPixels) + return TRUE; + + NotWorld:; +#endif + + D3DDRV.NumRenderedPolys++; + + // Insert the poly into the world cache, for later rendering + PCache_InsertWorldPoly(Pnts, NumPoints, THandle, TexInfo, LInfo, Flags); + + if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + } + + return TRUE; +} + +geBoolean DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags) +{ + if(!AppInfo.RenderingIsOK) + { + return TRUE; + } + else if (Flags & DRV_RENDER_FLUSH) + { + PCache_FlushMiscPolys(); + } + + PCache_InsertMiscPoly(Pnts, NumPoints, THandle, Flags); + + if (Flags & DRV_RENDER_FLUSH) + { + PCache_FlushMiscPolys(); + } + + return TRUE; +} + +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) +{ + RECT SRect2, *pSRect; + int32 Width, Height; + HRESULT ddrval; + + if(!AppInfo.RenderingIsOK) + return TRUE; + + if (!SRect) + { + SRect2.left = 0; + SRect2.right = THandle->Width; + SRect2.top = 0; + SRect2.bottom = THandle->Height; + pSRect = &SRect2; + Width = (THandle->Width); + Height = (THandle->Height); + } + else + { + pSRect = SRect; + Width = (pSRect->right - pSRect->left)+1; + Height = (pSRect->bottom - pSRect->top)+1; + } + + if (x + Width <= 0) + return TRUE; + if (y + Height <= 0) + return TRUE; + + if (x >= ClientWindow.Width) + return TRUE; + + if (y >= ClientWindow.Height) + return TRUE; + + if (x + Width >= (ClientWindow.Width-1)) + pSRect->right -= ((x + Width) - (ClientWindow.Width-1)); + if (y + Height >= (ClientWindow.Height-1)) + pSRect->bottom -= ((y + Height) - (ClientWindow.Height-1)); + + if (x < 0) + { + pSRect->left += -x; + x=0; + } + if (y < 0) + { + pSRect->top += -y; + y=0; + } + +#if 0 + AppInfo.lpBackBuffer->BltFast(x, y, THandle->MipData[0].Surface, pSRect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); +#else + RECT DRect; + + Width = (pSRect->right - pSRect->left); + Height = (pSRect->bottom - pSRect->top); + + DRect.left = x; + DRect.right = x+Width; + DRect.top = y; + DRect.bottom = y+Height; + + ddrval= AppInfo.lpBackBuffer->Blt(&DRect, THandle->MipData[0].Surface, pSRect, + (DDBLT_KEYSRC | DDBLT_WAIT), NULL); + + if(ddrval==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return GE_FALSE; + } + //AppInfo.lpBackBuffer->Blt(&DRect, Decals[Handle].Surface, pSRect, (DDBLT_WAIT), NULL); +#endif + + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/D3DDrv/SCENE.H b/G3D/Engine/Drivers/D3DDrv/SCENE.H new file mode 100644 index 0000000..624f9c6 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/SCENE.H @@ -0,0 +1,46 @@ +/****************************************************************************************/ +/* Scene.h */ +/* */ +/* Author: John Pollard */ +/* Description: Begin/EndScene code, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SCENE_H +#define SCENE_H + +#include + +#include "DCommon.h" + +#define RENDER_NONE 0 +#define RENDER_WORLD 1 +#define RENDER_MESHES 2 +#define RENDER_MODELS 3 + +extern int32 RenderMode; + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *WorldRect); +BOOL DRIVERCC EndScene(void); +BOOL DRIVERCC BeginWorld(void); +BOOL DRIVERCC EndWorld(void); +BOOL DRIVERCC BeginMeshes(void); +BOOL DRIVERCC EndMeshes(void); +BOOL DRIVERCC BeginModels(void); +BOOL DRIVERCC EndModels(void); + +#endif + diff --git a/G3D/Engine/Drivers/D3DDrv/Scene.cpp b/G3D/Engine/Drivers/D3DDrv/Scene.cpp new file mode 100644 index 0000000..5922f3e --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/Scene.cpp @@ -0,0 +1,217 @@ +/****************************************************************************************/ +/* Scene.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Begin/EndScene code, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" +#include "Scene.h" +#include "Render.h" +#include "GSpan.h" +#include "D3DCache.h" +#include "D3D_Fx.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "D3D_Err.h" +#include "THandle.h" + +//#define D3D_MANAGE_TEXTURES +#define SUPER_FLUSH + +int32 RenderMode; + +uint32 CurrentLRU; + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *WorldRect) +{ + HRESULT Result; + + CurrentLRU++; + + if (!AppInfo.lpD3DDevice) + { + D3DMain_Log("BeginScene: No D3D Device!."); + return FALSE; + } + + // Make sure we clear the cache info structure... + memset(&CacheInfo, 0, sizeof(DRV_CacheInfo)); + + if (!THandle_CheckCache()) + return GE_FALSE; + + // Watch for inactive app or minimize + if(AppInfo.RenderingIsOK) + { + if (!Main_ClearBackBuffer(Clear, ClearZ)) + { + D3DMain_Log("D3DClearBuffers failed."); + return FALSE; + } + + D3DDRV.NumRenderedPolys = 0; + + Result = AppInfo.lpD3DDevice->BeginScene(); + + if (Result != D3D_OK) + { + D3DMain_Log("BeginScene: D3D BeginScene Failed.\n%s.", D3DErrorToString(Result)); + return FALSE; + } + + D3DBilinearFilter(D3DFILTER_LINEAR, D3DFILTER_LINEAR); + D3DPolygonMode (D3DFILL_SOLID); + + D3DZWriteEnable (TRUE); + D3DZEnable(TRUE); + D3DZFunc(D3DCMP_LESSEQUAL); + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + D3DBlendEnable(TRUE); + + if (AppInfo.FogEnable) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR , ((DWORD)AppInfo.FogR<<16)|((DWORD)AppInfo.FogG<<8)|(DWORD)AppInfo.FogB); + } + else + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + } + } + + return TRUE; +} + +BOOL DRIVERCC EndScene(void) +{ + HRESULT Result; + + if (!AppInfo.lpD3DDevice) + return FALSE; + + if(AppInfo.RenderingIsOK) + { + // Flush everything one last time... + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + Result = AppInfo.lpD3DDevice->EndScene(); + + if (Result != D3D_OK) + { + D3DMain_Log("EndScene: D3D EndScene Failed.\n%s", D3DErrorToString(Result)); + return FALSE; + } + + if (!Main_ShowBackBuffer()) + return FALSE; + } + return TRUE; +} + +BOOL DRIVERCC BeginWorld(void) +{ + #ifdef USE_SPANS + if(AppInfo.RenderingIsOK) + { + ResetSpans(ClientWindow.Height); + } + #endif + + RenderMode = RENDER_WORLD; + return TRUE; +} + +BOOL DRIVERCC EndWorld(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + assert(AppInfo.lpD3DDevice); + #ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + #endif + + } + return TRUE; +} + +BOOL GlobalMeshHack; + +BOOL DRIVERCC BeginMeshes(void) +{ + GlobalMeshHack = TRUE; + RenderMode = RENDER_MESHES; + return TRUE; +} + +BOOL DRIVERCC EndMeshes(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushMiscPolys(); + PCache_FlushWorldPolys(); + + #ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + #endif + + GlobalMeshHack = FALSE; + } + return TRUE; +} + +BOOL DRIVERCC BeginModels(void) +{ + RenderMode = RENDER_MODELS; + return TRUE; +} + +BOOL DRIVERCC EndModels(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + #ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + #endif + + } + return TRUE; +} diff --git a/G3D/Engine/Drivers/D3DDrv/THandle.cpp b/G3D/Engine/Drivers/D3DDrv/THandle.cpp new file mode 100644 index 0000000..f20f66b --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/THandle.cpp @@ -0,0 +1,846 @@ +/****************************************************************************************/ +/* THandle.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for D3DDrv */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "THandle.h" +#include "BaseType.h" +#include "D3DDrv.h" +#include "DCommon.h" +#include "D3DCache.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "D3d_FX.h" + +#include "TPage.h" + +//#define D3D_MANAGE_TEXTURES + +#define USE_ONE_CACHE + +#define MAX_TEXTURE_HANDLES 132000 + +#define TEXTURE_CACHE_PERCENT 0.70f +#define LMAP_CACHE_PERCENT 0.30f + +#define TSTAGE_0 0 +#define TSTAGE_1 1 + +//============================================================================================ +//============================================================================================ + +geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; + +DDMemMgr *MemMgr; +DDMemMgr_Partition *Partition[2]; + +D3DCache *TextureCache; +D3DCache *LMapCache; + +TPage_Mgr *TPageMgr; + +DDSURFACEDESC2 CurrentSurfDesc; + +THandle_MipData SystemToVideo[MAX_LMAP_LOG_SIZE]; + +geBoolean CacheNeedsUpdate; +/* +#ifdef D3D_MANAGE_TEXTURES + #define NUM_LMAP_VIDEO_SURFACES 10; + THandle_MipData SystemToVideo[MAX_LMAP_LOG_SIZE]; +#endif +*/ + +//============================================================================================ +//============================================================================================ + +//============================================================================================ +// FreeAllcaches +//============================================================================================ +void FreeAllCaches(void) +{ + if (LMapCache) + D3DCache_Destroy(LMapCache); + + if (TextureCache) + D3DCache_Destroy(TextureCache); + + LMapCache = NULL; + TextureCache = NULL; + + if (Partition[1]) + DDMemMgr_PartitionDestroy(Partition[1]); + if (Partition[0]) + DDMemMgr_PartitionDestroy(Partition[0]); + if (MemMgr) + DDMemMgr_Destroy(MemMgr); + + +#ifdef USE_TPAGES + if (TPageMgr) + { + TPage_MgrDestroy(&TPageMgr); + TPageMgr = NULL; + } +#endif + + Partition[1] = NULL; + Partition[0] = NULL; + MemMgr = NULL; +} + +//============================================================================================ +// FindTextureHandle +//============================================================================================ +geRDriver_THandle *FindTextureHandle(void) +{ + int32 i; + geRDriver_THandle *pHandle; + + pHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pHandle++) + { + if (!pHandle->Active) + { + memset(pHandle, 0, sizeof(geRDriver_THandle)); + pHandle->Active = 1; + return pHandle; + } + } + + SetLastDrvError(DRV_ERROR_GENERIC, "D3D_FindTextureHandle: No more handles left.\n"); + + return NULL; +} + +//============================================================================================ +// FreeAllTextureHandles +//============================================================================================ +geBoolean FreeAllTextureHandles(void) +{ + int32 i; + geRDriver_THandle *pHandle; + + pHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pHandle++) + { + if (!pHandle->Active) + continue; + + if (!THandle_Destroy(pHandle)) + return GE_FALSE; + } + + return GE_TRUE; +} + +//============================================================================================ +//============================================================================================ +geBoolean THandle_Startup(void) +{ + // Create the main memory manager + MemMgr = DDMemMgr_Create(AppInfo.VidMemFree); + + if (!MemMgr) + goto ExitWithError; + + // Create partition 0 + Partition[0] = DDMemMgr_PartitionCreate(MemMgr, (uint32)((geFloat)DDMemMgr_GetFreeMem(MemMgr)*TEXTURE_CACHE_PERCENT)); + + if (!Partition[0]) + goto ExitWithError; + + // Create partition 1 + Partition[1] = DDMemMgr_PartitionCreate(MemMgr, DDMemMgr_GetFreeMem(MemMgr)); + + if (!Partition[1]) + goto ExitWithError; + + // Create the texture cache from partition 0 + TextureCache = D3DCache_Create("Main Texture Cache", AppInfo.lpDD, Partition[0], AppInfo.CanDoMultiTexture); + + if (!TextureCache) + goto ExitWithError; + +#ifndef USE_ONE_CACHE + // Create the lmap cache from partition 1 + LMapCache = D3DCache_Create("Lightmap Cache", AppInfo.lpDD, Partition[1], AppInfo.CanDoMultiTexture); + + if (!LMapCache) + goto ExitWithError; +#endif + + // Create all the system to video surfaces (for lmaps) + if (!CreateSystemToVideoSurfaces()) + goto ExitWithError; + + #ifdef USE_TPAGES + TPageMgr = TPage_MgrCreate(AppInfo.lpDD, &AppInfo.ddTexFormat, 512); + if (!TPageMgr) + goto ExitWithError; + #endif + + return GE_TRUE; + + ExitWithError: + { + THandle_Shutdown(); + return GE_FALSE; + } +} + +//============================================================================================ +//============================================================================================ +void THandle_Shutdown(void) +{ + FreeAllTextureHandles(); + FreeAllCaches(); + DestroySystemToVideoSurfaces(); + + CacheNeedsUpdate = GE_FALSE; +} + +//============================================================================================ +// Create3DTHandle +//============================================================================================ +geRDriver_THandle *Create3DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 Size, i; + + assert(NumMipLevels < THANDLE_MAX_MIP_LEVELS); + assert(NumMipLevels <= 4); + + // Store width/height info + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = (1<Log); + + // Create the surfaces to hold all the mips + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + if (!THandle->MipData) + { + THandle_Destroy(THandle); + return NULL; + } + + Size = 1<Log; + + // Create all the surfaces for each mip level + for (i=0; i< NumMipLevels; i++) + { + int32 Stage; + + if (!THandle_CreateSurfaces(&THandle->MipData[i], Size, Size, &CurrentSurfDesc, GE_FALSE, 0)) + { + THandle_Destroy(THandle); + return NULL; + } + + // get a cache type for this surface since it is a 3d surface, and will need to be cached on the video card + //THandle->MipData[i].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, NumMipLevels, &CurrentSurfDesc); + // We can use 1 miplevel for the type, since we are createing types for each miplevel... + if (AppInfo.CanDoMultiTexture) + Stage = TSTAGE_0; + else + Stage = 0; + + THandle->MipData[i].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, 1, Stage, &CurrentSurfDesc); + + if (!THandle->MipData[i].CacheType) + { + THandle_Destroy(THandle); + return NULL; + } + + Size>>=1; + } + + return THandle; +} + +//============================================================================================ +// CreateLightmapTHandle +//============================================================================================ +geRDriver_THandle *CreateLightmapTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 Size, Stage; + + assert(NumMipLevels < THANDLE_MAX_MIP_LEVELS); + + assert(NumMipLevels == 1); + + // Save some info about the lightmap + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = 1<Log; + + assert(THandle->Log < MAX_LMAP_LOG_SIZE); + + Size = 1<Log; + + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + THandle->MipData[0].Flags = THANDLE_UPDATE; + +#ifdef D3D_MANAGE_TEXTURES + #ifndef USE_TPAGES + { + int32 Stage; + + if (AppInfo.CanDoMultiTexture) + Stage = STAGE_1; + else + Stage = 0; + + if (!THandle_CreateSurfaces(&THandle->MipData[0], Size, Size, &CurrentSurfDesc, GE_FALSE, Stage)) + { + THandle_Destroy(THandle); + return NULL; + } + + D3DSetTexture(0, THandle->MipData[0].Texture); + } + #endif +#endif + + if (AppInfo.CanDoMultiTexture) + Stage = TSTAGE_1; + else + Stage = 0; + +#ifdef USE_ONE_CACHE + THandle->MipData[0].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, NumMipLevels, Stage, &CurrentSurfDesc); +#else + THandle->MipData[0].CacheType = D3DCache_TypeCreate(LMapCache, Size, Size, NumMipLevels, Stage, &CurrentSurfDesc); +#endif + + if (!THandle->MipData[0].CacheType) + { + THandle_Destroy(THandle); + return NULL; + } + + return THandle; +} + +//============================================================================================ +// Create2DTHandle +//============================================================================================ +geRDriver_THandle *Create2DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + assert(NumMipLevels < THANDLE_MAX_MIP_LEVELS); + assert(NumMipLevels == 1); + + // Save some info about the lightmap + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = Width; + + // Create the surfaces to hold all the mips + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + if (!THandle->MipData) + { + THandle_Destroy(THandle); + return NULL; + } + + if (!THandle_CreateSurfaces(&THandle->MipData[0], Width, Height, &CurrentSurfDesc, GE_TRUE, 0)) + { + THandle_Destroy(THandle); + return NULL; + } + + return THandle; +} + +//============================================================================================ +// SetupCurrent3dDesc +//============================================================================================ +geBoolean SetupCurrent3dDesc(gePixelFormat PixelFormat) +{ + switch (PixelFormat) + { + case GE_PIXELFORMAT_16BIT_555_RGB: + case GE_PIXELFORMAT_16BIT_565_RGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddTexFormat, sizeof(DDSURFACEDESC2)); + break; + } + case GE_PIXELFORMAT_16BIT_4444_ARGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddFourBitAlphaSurfFormat, sizeof(DDSURFACEDESC2)); + break; + } + case GE_PIXELFORMAT_16BIT_1555_ARGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddOneBitAlphaSurfFormat, sizeof(DDSURFACEDESC2)); + break; + } + + default: + { + SetLastDrvError(DRV_ERROR_GENERIC, "SetupCurrent3dDesc: Invalid pixel format.\n"); + return GE_FALSE; + } + } + + return GE_TRUE; +} +//============================================================================================ +// THandle_Create +//============================================================================================ +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + geRDriver_THandle *THandle; + + THandle = FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "D3DDRV:THandle_Create: Out of texture handles.\n"); + return NULL; + } + + THandle->PixelFormat = *PixelFormat; + + if (PixelFormat->Flags & RDRIVER_PF_3D) + { + // Get the pixel format desc for this thandle + if (!SetupCurrent3dDesc(PixelFormat->PixelFormat)) + return NULL; + + if (!Create3DTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + + CacheNeedsUpdate = GE_TRUE; + } + else if (PixelFormat->Flags & RDRIVER_PF_LIGHTMAP) + { + // Get the pixel format desc for this thandle + if (!SetupCurrent3dDesc(PixelFormat->PixelFormat)) + return NULL; + + if (!CreateLightmapTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + + CacheNeedsUpdate = GE_TRUE; + } + else if (PixelFormat->Flags & RDRIVER_PF_2D) + { + // 2d surfaces are always this format for now + memcpy(&CurrentSurfDesc, &AppInfo.ddSurfFormat, sizeof(DDSURFACEDESC2)); + + if (!Create2DTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + } + + return THandle; +} + +//============================================================================================ +// THandle_Destroy +//============================================================================================ +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle) +{ + int32 i; + + assert(THandle); + assert(THandle->Active); + + for (i=0; i< THandle->NumMipLevels; i++) + { + assert(THandle->MipData); + + if (THandle->MipData[i].CacheType) + { + D3DCache_TypeDestroy(THandle->MipData[i].CacheType); + CacheNeedsUpdate = GE_TRUE; + THandle->MipData[i].CacheType = NULL; + } + + if (THandle->MipData[i].Surface) + { + assert(THandle->MipData[i].Texture); + + THandle_DestroySurfaces(&THandle->MipData[i]); + THandle->MipData[i].Surface = NULL; + THandle->MipData[i].Texture = NULL; + } + } + + if (THandle->MipData) + free(THandle->MipData); + + memset(THandle, 0, sizeof(geRDriver_THandle)); + + return GE_TRUE; +} + +//===================================================================================== +//===================================================================================== +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Bits) +{ + DDSURFACEDESC2 SurfDesc; + HRESULT Result; + + assert(!(THandle->MipData[MipLevel].Flags & THANDLE_LOCKED)); + + // Lock the surface so it can be filled with the data + memset(&SurfDesc, 0, sizeof(DDSURFACEDESC2)); + SurfDesc.dwSize = sizeof(DDSURFACEDESC2); + + Result = THandle->MipData[MipLevel].Surface->Lock(NULL, &SurfDesc, DDLOCK_WAIT, NULL); + + if (Result != DD_OK) + { + return GE_FALSE; + } + + THandle->MipData[MipLevel].Flags |= THANDLE_LOCKED; + + *Bits = (void*)SurfDesc.lpSurface; + + return GE_TRUE; +} + +//===================================================================================== +// THandle_UnLock +//===================================================================================== +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel) +{ + HRESULT Result; + + assert(MipLevel <= THandle->NumMipLevels); + assert(THandle->MipData[MipLevel].Flags & THANDLE_LOCKED); + + // Unlock the surface + Result = THandle->MipData[MipLevel].Surface->Unlock(NULL); + + if (Result != DD_OK) + { + return GE_FALSE; + } + + THandle->MipData[MipLevel].Flags |= THANDLE_UPDATE; + THandle->MipData[MipLevel].Flags &= ~THANDLE_LOCKED; + + return GE_TRUE; +} + +#ifndef NDEBUG +#define DebugIf(a, b) if (a) b +#else +#define DebugIf(a, b) +#endif + +//===================================================================================== +// THandle_GetInfo +//===================================================================================== +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info) +{ + DebugIf (MipLevel > THandle->Log, return GE_FALSE); + + Info->Width = THandle->Width>>MipLevel; + Info->Height = THandle->Height>>MipLevel; + Info->Stride = THandle->Stride>>MipLevel; + + if (THandle->PixelFormat.Flags & RDRIVER_PF_CAN_DO_COLORKEY) + { + Info->Flags = RDRIVER_THANDLE_HAS_COLORKEY; + Info->ColorKey = 1; + } + else + { + Info->Flags = 0; + Info->ColorKey = 0; + } + + Info->PixelFormat = THandle->PixelFormat; + + return GE_TRUE; +} + +//===================================================================================== +// CreateSystemToVideoSurfaces +// System surfaces to copy from system to video +//===================================================================================== +geBoolean CreateSystemToVideoSurfaces(void) +{ + int32 i; + DDSURFACEDESC2 SurfDesc; + + memcpy(&SurfDesc, &AppInfo.ddTexFormat, sizeof(DDSURFACEDESC2)); + + for (i=0; iCreateSurface(&ddsd, &Surface, NULL); + + if(Hr != DD_OK) + { + return FALSE; + } + + Surf->Surface = Surface; + + Surf->Texture = NULL; + + Hr = Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Surf->Texture); + + if(Hr != DD_OK) + { + Surface->Release(); + return GE_FALSE; + } + + if (ColorKey) + { + DDCOLORKEY CKey; + + // Create the color key for this surface + CKey.dwColorSpaceLowValue = 1; + CKey.dwColorSpaceHighValue = 1; + + if (Surf->Surface->SetColorKey(DDCKEY_SRCBLT , &CKey) != DD_OK) + { + SetLastDrvError(DRV_ERROR_GENERIC, "THandle_CreateSurfaces: SetColorKey failed for texture."); + Surf->Surface->Release(); + Surf->Surface = NULL; + Surf->Texture->Release(); + Surf->Texture = NULL; + return FALSE; + } + } + return GE_TRUE; // All good dude +} + +//===================================================================================== +// DestroySystemSurface +//===================================================================================== +void THandle_DestroySurfaces(THandle_MipData *Surf) +{ + if (Surf->Texture) + Surf->Texture->Release(); + if (Surf->Surface) + Surf->Surface->Release(); + + memset(Surf, 0, sizeof (THandle_MipData)); +} + +//===================================================================================== +// THandle_CheckCache +//===================================================================================== +geBoolean THandle_CheckCache(void) +{ + geRDriver_THandle *pTHandle; + int32 i, Stage0, Stage1; + int32 MaxTable1[9], MaxTable2[9]; + + if (!CacheNeedsUpdate) + return GE_TRUE; + +#ifndef D3D_MANAGE_TEXTURES // If D3D is managing textures, then we don't ned to do any of this... + D3DMain_Log("THandle_CheckCache: Resetting texture cache...\n"); + +#ifdef USE_ONE_CACHE + #pragma message ("There numbers ARE NOT DONE. So if USE_ONE_CACHE is defined, please finish this...") + // Texture cache & Lightmap cache (we are only using one cache, so the combine into the TextureCache) + MaxTable1[0] = 256; // 1x1 + MaxTable1[1] = 256; // 2x2 + MaxTable1[2] = 256; // 4x4 + MaxTable1[3] = 512; // 8x8 + MaxTable1[4] = 512; // 16x16 + MaxTable1[5] = 512; // 32x32 + MaxTable1[6] = 512; // 64x64 + MaxTable1[7] = 256; //128x128 + MaxTable1[8] = 256; //256x256 +#else + if (AppInfo.DeviceIdentifier.dwVendorId == 4634) // 3dfx series have a limit on the number of texture handles + { + D3DMain_Log(" 3dfx card detected, using smaller number of handles...\n"); + + // Texture cache + MaxTable1[0] = 24; // 1x1 + MaxTable1[1] = 24; // 2x2 + MaxTable1[2] = 24; // 4x4 + MaxTable1[3] = 24; // 8x8 + MaxTable1[4] = 24; // 16x16 + MaxTable1[5] = 128; // 32x32 + MaxTable1[6] = 128; // 64x64 + MaxTable1[7] = 128; //128x128 + MaxTable1[8] = 128; //256x256 + + // Lightmap cache + MaxTable2[0] = 128; // 1x1 + MaxTable2[1] = 128; // 2x2 + MaxTable2[2] = 256; // 4x4 + MaxTable2[3] = 256; // 8x8 + MaxTable2[4] = 256; // 16x16 + MaxTable2[5] = 128; // 32x32 + MaxTable2[6] = 128; // 64x64 + MaxTable2[7] = 128; //128x128 + MaxTable2[8] = 128; //256x256 + } + else + { + D3DMain_Log(" NO 3dfx card detected, using larger number of handles...\n"); + + // Texture cache + MaxTable1[0] = 32; // 1x1 + MaxTable1[1] = 32; // 2x2 + MaxTable1[2] = 32; // 4x4 + MaxTable1[3] = 32; // 8x8 + MaxTable1[4] = 32; // 16x16 + MaxTable1[5] = 32; // 32x32 + MaxTable1[6] = 128; // 64x64 + MaxTable1[7] = 128; //128x128 + MaxTable1[8] = 128; //256x256 + + MaxTable2[0] = 128; // 1x1 + MaxTable2[1] = 128; // 2x2 + MaxTable2[2] = 256; // 4x4 + MaxTable2[3] = 1024; // 8x8 + MaxTable2[4] = 1024; // 16x16 + MaxTable2[5] = 512; // 32x32 + MaxTable2[6] = 256; // 64x64 + MaxTable2[7] = 256; //128x128 + MaxTable2[8] = 256; //256x256 + } +#endif + + if (AppInfo.CanDoMultiTexture) + { + Stage0 = TSTAGE_0; + Stage1 = TSTAGE_1; + } + else + { + Stage0 = 0; + Stage1 = 0; + } + + #ifndef USE_ONE_CACHE + if (!D3DCache_AdjustSlots(LMapCache, MaxTable2, GE_TRUE)) + { + D3DMain_Log("THandle_CheckCache: D3DCache_AdjustSlots failed for LMapCache.\n"); + return GE_FALSE; + } + #endif + + if (!D3DCache_AdjustSlots(TextureCache, MaxTable1, GE_FALSE)) + { + D3DMain_Log("THandle_CheckCache: D3DCache_AdjustSlots failed for TextureCache.\n"); + return GE_FALSE; + } + +#endif + + // Make sure no THandles reference any slots, because they mave have been moved around, or gotten destroyed... + // (Evict all textures in the cache) + pTHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pTHandle++) + { + int32 m; + + for (m=0; m< pTHandle->NumMipLevels; m++) + { + pTHandle->MipData[m].Slot = NULL; + } + } + + CacheNeedsUpdate = GE_FALSE; + + return GE_TRUE; +} diff --git a/G3D/Engine/Drivers/D3DDrv/THandle.h b/G3D/Engine/Drivers/D3DDrv/THandle.h new file mode 100644 index 0000000..9569a9a --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/THandle.h @@ -0,0 +1,106 @@ +/****************************************************************************************/ +/* THandle.h */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for D3DDrv */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef THANDLE_H +#define THANDLE_H + +#include + +#include "BaseType.h" +#include "DCommon.h" +#include "D3DCache.h" + +#include "TPage.h" + +//============================================================================================ +//============================================================================================ +#define THANDLE_MAX_MIP_LEVELS 255 +//#define MAX_LMAP_LOG_SIZE 8 // Max lightmap size in pixels will be 128x128 +//#define MAX_LMAP_LOG_SIZE 7 // Max lightmap size in pixels will be 64x64 +#define MAX_LMAP_LOG_SIZE 6 // Max lightmap size in pixels will be 32x32 + +typedef struct +{ + LPDIRECTDRAWSURFACE4 Surface; // The DD surface + D3DCache_Type *CacheType; + D3DCache_Slot *Slot; + + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface + + uint8 Flags; +} THandle_MipData; + +// THandle flags +#define THANDLE_LOCKED (1<<0) +#define THANDLE_UPDATE (1<<1) + +typedef struct geRDriver_THandle +{ + uint8 Active; + int32 Width; + int32 Height; + int32 Stride; + uint8 NumMipLevels; + uint8 Log; + + THandle_MipData *MipData; // A mipdata per miplevel + + geRDriver_PixelFormat PixelFormat; + +#ifdef USE_TPAGES + TPage_Block *Block; +#endif + +} geRDriver_THandle; + +extern geRDriver_THandle TextureHandles[]; + +extern D3DCache *TextureCache; +extern D3DCache *LMapCache; + +extern TPage_Mgr *TPageMgr; + +extern THandle_MipData SystemToVideo[]; + +extern CacheNeedsUpdate; + +//============================================================================================ +//============================================================================================ +void FreeAllCaches(void); +geRDriver_THandle *FindTextureHandle(void); +geBoolean FreeAllTextureHandles(void); +geBoolean THandle_Startup(void); +void THandle_Shutdown(void); +geRDriver_THandle *Create3DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *CreateLightmapTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *Create2DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle); +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Bits); +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel); +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info); +geBoolean CreateSystemToVideoSurfaces(void); +void DestroySystemToVideoSurfaces(void); +geBoolean THandle_CreateSurfaces(THandle_MipData *MipData, int32 Width, int32 Height, DDSURFACEDESC2 *SurfDesc, geBoolean ColorKey, int32 Stage); +void THandle_DestroySurfaces(THandle_MipData *MipData); +geBoolean THandle_CheckCache(void); + +#endif diff --git a/G3D/Engine/Drivers/D3DDrv/TPage.h b/G3D/Engine/Drivers/D3DDrv/TPage.h new file mode 100644 index 0000000..b6db4d0 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/TPage.h @@ -0,0 +1,69 @@ +/****************************************************************************************/ +/* TPage.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager using pages */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef TPAGE_H +#define TPAGE_H + +#include + +#include +#include + +typedef struct TPage_Mgr TPage_Mgr; +typedef struct TPage TPage; +typedef struct TPage_Block TPage_Block; + +// +// TPage_Mgr +// +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages); +void TPage_MgrDestroy(TPage_Mgr **TPageMgr); +geBoolean TPage_MgrHasTPage(TPage_Mgr *Mgr, TPage *Page); +geBoolean TPage_MgrAttachTPage(TPage_Mgr *Mgr, TPage *TPage); +void TPage_MgrDetachTPage(TPage_Mgr *Mgr, TPage *TPage); +TPage_Block *TPage_MgrFindOptimalBlock(TPage_Mgr *Mgr, uint32 LRU); + +// +// TPage +// +TPage *TPage_Create(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc); +void TPage_CreateRef(TPage *Page); +void TPage_Destroy(TPage **Page1); +geBoolean TPage_HasBlock(TPage *TPage, TPage_Block *Block); +geBoolean TPage_AttachBlock(TPage *Page, TPage_Block *Block); +void TPage_DetachBlock(TPage *TPage, TPage_Block *Block); +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc); +void TPage_DestroySurfaces(TPage *Page); + +// +//TPage_Block +// +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE4 Surface, LPDIRECT3DTEXTURE2 Texture, const RECT *Rect); +geBoolean TPage_BlockCreateRef(TPage_Block *Block); +void TPage_BlockDestroy(TPage_Block **Block); +LPDIRECT3DTEXTURE2 TPage_BlockGetTexture(TPage_Block *Block); +LPDIRECTDRAWSURFACE4 TPage_BlockGetSurface(TPage_Block *Block); +const RECT *TPage_BlockGetRect(TPage_Block *Block); +void TPage_BlockSetLRU(TPage_Block *Block, uint32 LRU); +void TPage_BlockSetUserData(TPage_Block *Block, void *UserData); +void *TPage_BlockGetUserData(TPage_Block *Block); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/D3DDrv/mssccprj.scc b/G3D/Engine/Drivers/D3DDrv/mssccprj.scc new file mode 100644 index 0000000..848e217 --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/mssccprj.scc @@ -0,0 +1,4 @@ +SCC = This is a Source Code Control file + +[D3DDrv.mak] +SCC_Project_Name = "$/Genesis10/Source/Engine/Drivers/D3DDrv", LQQBAAAA diff --git a/G3D/Engine/Drivers/D3DDrv/tpage.cpp b/G3D/Engine/Drivers/D3DDrv/tpage.cpp new file mode 100644 index 0000000..4a9cb3b --- /dev/null +++ b/G3D/Engine/Drivers/D3DDrv/tpage.cpp @@ -0,0 +1,677 @@ +/****************************************************************************************/ +/* TPage.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager using pages */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "BaseType.h" +#include "TPage.h" + +// These must be a power of 2!!! +#define TPAGE_WIDTH 16 // Width of TPAges +#define TPAGE_HEIGHT 16 // Height of TPages + +#define TPAGE_GRID_X 16 // Must be <= TPAGE_WIDTH, and power of 2 +#define TPAGE_GRID_Y 16 // Must be <= TPAGE_HEIGHT, and power of 2 + +// NOTE - Blocks Width/Height that go into TPages MUST be <= AlignX/AlignY!!! + +typedef struct TPage_Block +{ + int32 RefCount; // Number of references to this object + + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this Block + LPDIRECT3DTEXTURE2 Texture; // The Texture interface to the surface + + RECT Rect; // The Rect into the surface that this block can use + + uint32 LRU; // Set to the TPage->TPageMgr->LRU when accesed... + + void *UserData; + + struct TPage_Block *Prev; + struct TPage_Block *Next; + +} TPage_Block; + +typedef struct TPage +{ + int32 RefCount; + + DDSURFACEDESC2 SurfaceDesc; // Surface description of this page (note all blocks must use this format!!!) + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this TPage + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface + + TPage_Block *Blocks; // Linked list of blocks + + uint32 LRU; + + struct TPage *Prev; + struct TPage *Next; +} TPage; + +typedef struct TPage_Mgr +{ + int32 NumPages; + + TPage *TPages; // Linked list of TPages + + LPDIRECTDRAW4 lpDD; // DD object used to create surfaces +} TPage_Mgr; + +//============================================================================ +// *** TPage_Mgr *** +//============================================================================ + +//============================================================================ +// TPage_MgrCreate +//============================================================================ +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages) +{ + TPage_Mgr *TPageMgr; + int32 i; + + TPageMgr = (TPage_Mgr*)malloc(sizeof(TPage_Mgr)); + + if (!TPageMgr) + return NULL; + + memset(TPageMgr, 0, sizeof(TPage_Mgr)); + + // Remeber the DD object + TPageMgr->lpDD = lpDD; + // Ref the dd object + lpDD->AddRef(); + + TPageMgr->NumPages = NumPages; + + // Create the pages + for (i=0; iTPages; Page; Page = Next) + { + Next = Page->Next; + + TPage_MgrDetachTPage(Mgr, Page); + TPage_Destroy(&Page); + } + + assert(Mgr->TPages == NULL); + + // Release our ref on the DD object + Mgr->lpDD->Release(); + + free(*TPageMgr); + + *TPageMgr = NULL; +} + +//============================================================================ +// TPage_MgrHasTPage +//============================================================================ +geBoolean TPage_MgrHasTPage(TPage_Mgr *Mgr, TPage *Page) +{ + TPage *Page2; + + assert(Mgr); + assert(Page); + + for (Page2 = Mgr->TPages; Page2; Page2 = Page2->Next) + { + if (Page2 == Page) + { + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//============================================================================ +// TPage_MgrAttachTPage +// NOTE - A TPage can only attach to one TPage_Mgr, and only ONCE!! +//============================================================================ +geBoolean TPage_MgrAttachTPage(TPage_Mgr *Mgr, TPage *TPage) +{ + assert(TPage_MgrHasTPage(Mgr, TPage) == GE_FALSE); + assert(TPage->Prev == NULL); + assert(TPage->Next == NULL); + + if (Mgr->TPages) + Mgr->TPages->Prev = TPage; + + TPage->Prev = NULL; + TPage->Next = Mgr->TPages; + Mgr->TPages = TPage; + + return GE_TRUE; +} + +//============================================================================ +// TPage_MgrDetachTPage +//============================================================================ +void TPage_MgrDetachTPage(TPage_Mgr *Mgr, TPage *TPage) +{ + assert(Mgr); + assert(TPage); + assert(TPage_MgrHasTPage(Mgr, TPage) == GE_TRUE); + + if (TPage->Next) + TPage->Next->Prev = TPage->Prev; + + if (TPage->Prev) + TPage->Prev->Next = TPage->Prev; + else + { + // If we get here, this better be the first TPage in the list! + assert(Mgr->TPages == TPage); + Mgr->TPages = TPage->Next; + } + + TPage->Next = NULL; + TPage->Prev = NULL; +} + +//============================================================================ +// TPage_MgrFindOptimalBlock +//============================================================================ +TPage_Block *TPage_MgrFindOptimalBlock(TPage_Mgr *Mgr, uint32 LRU) +{ +#if 0 + TPage *Page, *BestPage; + TPage_Block *Block, *BestBlock; + uint32 BestLRU; + + // We really should make a TPage_GetOptimalBlock... + + // First, find the page that has the highest LRU + BestLRU = 0; + BestPage = Mgr->TPages; + + for (Page = Mgr->TPages; Page; Page = Page->Next) + { + if (Page->LRU > BestLRU && Page->NumFull) + { + BestPage = Page; + BestLRU = Page->LRU; + } + } + + // Now, find the block with the lowest LRU in this page + BestBlock = BestPage->Blocks; + BestLRU = 0xffffffff; + + for (Block = BestPage->Blocks; Block; Block = Block->Next) + { + if (Block->LRU < BestLRU) + { + BestBlock = Block; + BestLRU = Block->LRU; + } + } + /* + if (BestBlock->LRU == LRU) + BestPage->NumFull++; + else + */ + BestBlock->LRU = LRU; + BestPage->LRU = LRU; +#else + TPage *Page; + TPage_Block *Block, *BestBlock; + uint32 BestLRU; + + // We really should make a TPage_GetOptimalBlock... + BestBlock = NULL; + BestLRU = 0xffffffff; + + for (Page = Mgr->TPages; Page; Page = Page->Next) + { + for (Block = Page->Blocks; Block; Block = Block->Next) + { + if (Block->LRU < BestLRU) + { + BestBlock = Block; + BestLRU = Block->LRU; + } + } + } + + BestBlock->LRU = LRU; +#endif + + return BestBlock; +} + +//============================================================================ +// *** TPage *** +//============================================================================ + +//============================================================================ +// TPage_Create +//============================================================================ +TPage *TPage_Create(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc) +{ + TPage *Page; + int32 w, h; + + Page = (TPage*)malloc(sizeof(TPage)); + + if (!Page) + return NULL; + + memset(Page, 0, sizeof(TPage)); + + Page->SurfaceDesc = *SurfDesc; + + TPage_CreateRef(Page); // Create the very first ref + + if (!TPage_CreateSurfaces(Page, lpDD, SurfDesc)) + { + free(Page); + return NULL; + } + + // Create the blocks + for (h=0; hSurface, Page->Texture, &Rect); + + if (!Block) + goto ExitWithError; + + if (!TPage_AttachBlock(Page, Block)) + goto ExitWithError; + } + } + + return Page; + + ExitWithError: + { + if (Page) + TPage_Destroy(&Page); + + return NULL; + } +} + +//============================================================================ +// TPage_CreateRef +//============================================================================ +void TPage_CreateRef(TPage *Page) +{ + assert(Page->RefCount >= 0); // Refs can == 0, because thats what they are when TPages are first created + + Page->RefCount++; +} + +//============================================================================ +// TPage_Destroy +//============================================================================ +void TPage_Destroy(TPage **Page1) +{ + TPage *Page; + TPage_Block *Block, *Next; + + assert(Page1); + Page = *Page1; + + assert(Page); + assert(Page->RefCount > 0); + + Page->RefCount--; + + if (Page->RefCount > 0) + return; + + // Destroy any dd surfaces for this page + TPage_DestroySurfaces(Page); + + // Destroy all the blocks this page has + for (Block = Page->Blocks; Block; Block = Next) + { + Next = Block->Next; + + TPage_DetachBlock(Page, Block); + TPage_BlockDestroy(&Block); + } + + assert(Page->Blocks == NULL); + + free(*Page1); + + *Page1 = NULL; +} + +//============================================================================ +// TPage_HasBlock +//============================================================================ +geBoolean TPage_HasBlock(TPage *TPage, TPage_Block *Block) +{ + TPage_Block *Block2; + + assert(TPage); + assert(Block); + + for (Block2 = TPage->Blocks; Block2; Block2 = Block2->Next) + { + if (Block2 == Block) + { + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//============================================================================ +// TPage_AttachBlock +// NOTE - A Block can only attach to one TPage, and only ONCE!! +//============================================================================ +geBoolean TPage_AttachBlock(TPage *Page, TPage_Block *Block) +{ + assert(TPage_HasBlock(Page, Block) == GE_FALSE); + assert(Block->Prev == NULL); + assert(Block->Next == NULL); + + // Insert the block into the list of blocks for this Page + if (Page->Blocks) + Page->Blocks->Prev = Block; + + Block->Prev = NULL; + Block->Next = Page->Blocks; + + Page->Blocks = Block; + + return GE_TRUE; +} + +//============================================================================ +// TPage_DetachBlock +//============================================================================ +void TPage_DetachBlock(TPage *TPage, TPage_Block *Block) +{ + assert(TPage); + assert(Block); + assert(TPage_HasBlock(TPage, Block) == GE_TRUE); + + if (Block->Next) + Block->Next->Prev = Block->Prev; + + if (Block->Prev) + Block->Prev->Next = Block->Prev; + else + { + // If we get here, this better be the first Block in the list! + assert(TPage->Blocks == Block); + TPage->Blocks = Block->Next; + } + + // Reset the Block link + Block->Next = NULL; + Block->Prev = NULL; +} + +//===================================================================================== +// TPage_CreateSurfaces +//===================================================================================== +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc) +{ + HRESULT Hr; + DDSURFACEDESC2 ddsd; + + assert(Page); + + memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTDYNAMIC; + + ddsd.ddsCaps.dwCaps3 = 0; + ddsd.ddsCaps.dwCaps4 = 0; + + ddsd.dwWidth = TPAGE_WIDTH; + ddsd.dwHeight = TPAGE_HEIGHT; + + Hr = lpDD->CreateSurface(&ddsd, &Page->Surface, NULL); + + if (Hr != DD_OK) + return GE_FALSE; + + Hr = Page->Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Page->Texture); + + if(Hr != DD_OK) + { + Page->Surface->Release(); + Page->Surface = NULL; + Page->Texture = NULL; + return GE_FALSE; + } + + return GE_TRUE; // All good dude +} + + +//===================================================================================== +// TPage_DestroySurfaces +//===================================================================================== +void TPage_DestroySurfaces(TPage *Page) +{ + assert(Page); + + if (Page->Texture) + { + Page->Texture->Release(); + Page->Texture = NULL; + } + + if (Page->Surface) + { + Page->Surface->Release(); + Page->Surface = NULL; + } +} + +//============================================================================ +// *** TPage_Block *** +//============================================================================ + +//============================================================================ +// TPage_BlockCreate +//============================================================================ +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE4 Surface, LPDIRECT3DTEXTURE2 Texture, const RECT *Rect) +{ + TPage_Block *Block; + + Block = (TPage_Block*)malloc(sizeof(TPage_Block)); + + if (!Block) + return NULL; + + memset(Block, 0, sizeof(TPage_Block)); + + Surface->AddRef(); // Ref the surface + Texture->AddRef(); // Ditto... + + // Save off the surface, texture, and rect into the surface + Block->Surface = Surface; + Block->Texture = Texture; + Block->Rect = *Rect; + + TPage_BlockCreateRef(Block); // Create very first ref + + return Block; +} + +//============================================================================ +// TPage_BlockCreateRef +//============================================================================ +geBoolean TPage_BlockCreateRef(TPage_Block *Block) +{ + assert(Block); + + Block->RefCount++; + + return GE_TRUE; +} + +//============================================================================ +// TPage_BlockDestroy +//============================================================================ +void TPage_BlockDestroy(TPage_Block **Block) +{ + TPage_Block *Block2; + + assert(Block); + + Block2 = *Block; + + assert(Block2); + assert(Block2->RefCount > 0); + + Block2->RefCount--; + + if (Block2->RefCount > 0) + return; + + // Destroy references to the surface and texture + if (Block2->Surface) + Block2->Surface->Release(); + + if (Block2->Texture) + Block2->Texture->Release(); + + // Free the block + free(Block2); + + *Block = NULL; +} + +//============================================================================ +// TPage_BlockGetTexture +//============================================================================ +LPDIRECT3DTEXTURE2 TPage_BlockGetTexture(TPage_Block *Block) +{ + assert(Block); + + return Block->Texture; +} + +//============================================================================ +// TPage_BlockGetSurface +//============================================================================ +LPDIRECTDRAWSURFACE4 TPage_BlockGetSurface(TPage_Block *Block) +{ + assert(Block); + + return Block->Surface; +} + +//============================================================================ +// TPage_BlockGetRect +//============================================================================ +const RECT *TPage_BlockGetRect(TPage_Block *Block) +{ + assert(Block); + + return &Block->Rect; +} + +//============================================================================ +// TPage_BlockSetLRU +//============================================================================ +void TPage_BlockSetLRU(TPage_Block *Block, uint32 LRU) +{ + assert(Block); + + Block->LRU = LRU; +} + +//============================================================================ +// TPage_BlockSetUserData +//============================================================================ +void TPage_BlockSetUserData(TPage_Block *Block, void *UserData) +{ + assert(Block); + + Block->UserData = UserData; +} + +//============================================================================ +// TPage_BlockGetUserData +//============================================================================ +void *TPage_BlockGetUserData(TPage_Block *Block) +{ + assert(Block); + + return Block->UserData; +} diff --git a/G3D/Engine/Drivers/Dcommon.h b/G3D/Engine/Drivers/Dcommon.h new file mode 100644 index 0000000..f9f42ca --- /dev/null +++ b/G3D/Engine/Drivers/Dcommon.h @@ -0,0 +1,502 @@ +/****************************************************************************************/ +/* DCommon.h */ +/* */ +/* Author: John Pollard */ +/* Description: Header file for all driver modules. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DCOMMON_H +#define DCOMMON_H + +//#include // {} CB commented out windows +// If you include Windows it MUST be before dcommon! + +// FIXME: What should we do with these? +#include "XForm3d.h" +#include "Vec3d.h" +#include "PixelFormat.h" +#include "geTypes.h" // This is a no no + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(push) +#pragma pack(8) + +#ifndef WINVER +#ifdef STRICT +typedef struct HWND__ * HWND; +typedef struct HBITMAP__ * HBITMAP; +#else // STRICT +typedef void * HWND; +typedef void * HBITMAP; +#endif // STRICT + +#ifndef VOID +#define VOID void +typedef char CHAR; +typedef short SHORT; +typedef long LONG; +#endif + +#ifndef BASETYPES +#define BASETYPES +typedef unsigned long ULONG; +typedef ULONG *PULONG; +typedef unsigned short USHORT; +typedef USHORT *PUSHORT; +typedef unsigned char UCHAR; +typedef UCHAR *PUCHAR; +typedef char *PSZ; +#endif /* !BASETYPES */ + +typedef unsigned long DWORD; +typedef int geBoolean; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef geFloat FLOAT; + +typedef struct tagRECT +{ + LONG left; + LONG top; + LONG right; + LONG bottom; +} RECT; + +#endif // WINVER + +#define DRIVERCC _fastcall + +#ifndef __cplusplus + #define DllImport __declspec( dllimport ) + #define DllExport __declspec( dllexport ) +#else + #define DllImport extern "C" __declspec( dllimport ) + #define DllExport extern "C" __declspec( dllexport ) +#endif + +#define DRV_VERSION_MAJOR 100 // Genesis 1.0 +#define DRV_VERSION_MINOR 3 // >= 3.0 added fog +#define DRV_VMAJS "100" +#define DRV_VMINS "3" + +#ifndef US_TYPEDEFS +#define US_TYPEDEFS + + typedef uint8 U8; + typedef uint16 U16; + typedef uint32 U32; + typedef char C8; + typedef int8 S8; + typedef int16 S16; + typedef int32 S32; +#endif + +//=== +typedef struct geRDriver_THandle geRDriver_THandle; + +// DriverFormat flags +#define RDRIVER_PF_2D_SHIFT (0) // Supports being used as a 2d decal surface +#define RDRIVER_PF_3D_SHIFT (1) // Supports being used as a 3d poly surface +#define RDRIVER_PF_LIGHTMAP_SHIFT (2) // Surface is a lightmap surface +#define RDRIVER_PF_PALETTE_SHIFT (3) // Surface is a palette +#define RDRIVER_PF_ALPHA_SHIFT (4) // Surface is an alpha map +#define RDRIVER_PF_OPTIONAL_SHIFT (16) +#define RDRIVER_PF_HAS_ALPHA_SHIFT (RDRIVER_PF_OPTIONAL_SHIFT + 0) // Surface can take an alpha map +#define RDRIVER_PF_CAN_DO_COLORKEY_SHIFT (RDRIVER_PF_OPTIONAL_SHIFT + 1) // Surface supports colorkeying +#define RDRIVER_PF_COMBINE_LIGHTMAP_SHIFT (RDRIVER_PF_OPTIONAL_SHIFT + 2) // Supports being rendered with a lightmap (3d will be set as well) + +#define RDRIVER_PF_2D (1< +#include +#include + +#include "GCache.h" +#include "GMemMGr.h" +#include "DCommon.h" +#include "Glide.h" + +#define GCACHE_WRITELOG +//#define DYNAMIC_CACHE + + +#define GCACHE_MAX_CACHE_TYPES 128 + +//======================================================================================================== +//======================================================================================================== +typedef struct GCache_Type +{ + GrTexInfo Info; + int32 Log; + int32 Width; // Width/Height + int32 Height; + uint8 NumMipLevels; + uint32 Size; + + geFloat OneOverWidth_255; + geFloat OneOverHeight_255; + + GCache_Slot *Slots; // Cache slots for this Cache type + int32 RefCount; // How many slots are allocated + int32 UsedSlots; // How many slots were used + +#ifdef DYNAMIC_CACHE + struct GCache_Type *PrevNext[2]; // NextPrev cache type in list +#endif + +} GCache_Type; + +typedef struct GCache +{ + char Name[GCACHE_MAX_NAME]; + + GMemMgr *MemMgr; // Memory manager + + GCache_Type CacheTypes[GCACHE_MAX_CACHE_TYPES]; // CacheTypes + + uint32 LastMemAddr; + + struct GCache *SelfCheck; +} GCache; + +typedef struct GCache_Slot +{ + + GCache_Type *Type; + + uint32 MemAddr; // Points to the tex mem where mem is + uint32 LRU; // Current LRU for cache slot + + void *UserData; + + struct GCache_Slot *SelfCheck; + +} GCache_Slot; + +//======================================================================================================== +//======================================================================================================== + +//======================================================================================================== +// GCache_Create +//======================================================================================================== +GCache *GCache_Create(const char *Name, GMemMgr *MemMgr) +{ + GCache *Cache; + + assert(Name); + assert(strlen(Name) < GCACHE_MAX_NAME); + assert(MemMgr); + + Cache = malloc(sizeof(GCache)); + + if (!Cache) + return NULL; + + memset(Cache, 0, sizeof(GCache)); + + strcpy(Cache->Name, Name); + + Cache->MemMgr = MemMgr; + + Cache->LastMemAddr = 0xffffffff; + + Cache->SelfCheck = Cache; + + if (!GCache_Reset(Cache)) + goto ExitWithError; + + return Cache; + + ExitWithError: + { + if (Cache) + free(Cache); + + return NULL; + } +} + +//======================================================================================================== +// GCache_Destroy +//======================================================================================================== +void GCache_Destroy(GCache *Cache) +{ + assert(Cache); + + free(Cache); +} + +//======================================================================================================== +//======================================================================================================== +geBoolean GCache_Reset(GCache *Cache) +{ + int32 i; + GCache_Type *pCacheType; + + GCache_FreeAllSlots(Cache); + + for (pCacheType = Cache->CacheTypes, i=0; i 0) + pCacheType->PrevNext[0] = (pCacheType-1); + if (i < GCACHE_MAX_CACHE_TYPES-1) + pCacheType->PrevNext[1] = (pCacheType+1); + #endif + } + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +GCache_Type *GCache_FindCacheTypeByInfo(GCache *Cache, const GrTexInfo *Info) +{ + int32 i; + GCache_Type *pCacheType; + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + continue; + + if (Info->smallLod != pCacheType->Info.smallLod) + continue; + if (Info->largeLod != pCacheType->Info.largeLod) + continue; + if (Info->aspectRatio != pCacheType->Info.aspectRatio) + continue; + + if (Info->format != pCacheType->Info.format) + continue; + + #if 0 + // Check to see if the size required to create the surface matches + Size = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, (GrTexInfo*)Info); + + //if (Size != pCacheType->Size) + continue; + #endif + + return pCacheType; // Found a match + } + + return NULL; // Cache Type not found!!! +} + +//======================================================================================================== +//======================================================================================================== +GCache_Type *GCache_InsertCacheTypeByInfo(GCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, const GrTexInfo *Info) +{ + int32 i; + GCache_Type *pCacheType; + + assert(NumMipLevels <= 255); + assert(NumMipLevels >= 0); + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + { + assert(pCacheType->Slots == NULL); + assert(pCacheType->UsedSlots == 0); + break; + } + } + + if (i == GCACHE_MAX_CACHE_TYPES) // No types left + return NULL; + + pCacheType->Info = *Info; + pCacheType->Info.data = NULL; + pCacheType->Width = Width; + pCacheType->Height = Height; + pCacheType->NumMipLevels = (uint8)NumMipLevels; + pCacheType->Size = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, (GrTexInfo*)Info); + + // Found one + pCacheType->RefCount++; + + return pCacheType; +} + +//======================================================================================================== +// GCache_UpdateSlot +//======================================================================================================== +geBoolean GCache_UpdateSlot(GCache *Cache, GCache_Slot *Slot, GrTexInfo *Info) +{ + assert(GCache_SlotIsValid(Slot)); + + grTexDownloadMipMap(GMemMgr_GetTmu(Cache->MemMgr), Slot->MemAddr, GR_MIPMAPLEVELMASK_BOTH, Info); + + return GE_TRUE; +} + +//======================================================================================================== +// GCache_SetTexture +//======================================================================================================== +geBoolean GCache_SetTexture(GCache *Cache, GCache_Slot *Slot) +{ + assert(GCache_SlotIsValid(Slot)); + + if (Cache->LastMemAddr == Slot->MemAddr) + return GE_TRUE; + + grTexSource(GMemMgr_GetTmu(Cache->MemMgr), Slot->MemAddr, GR_MIPMAPLEVELMASK_BOTH, &Slot->Type->Info); + + Cache->LastMemAddr = Slot->MemAddr; + + Slot->LRU++; + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +GCache_Type *GCache_TypeCreate(GCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, const GrTexInfo *Info) +{ + GCache_Type *CacheType; + + CacheType = GCache_FindCacheTypeByInfo(Cache, Info); + + if (CacheType) + { + CacheType->RefCount++; + return CacheType; + } + + // Could not find one allready in the list, so add a new one... + return GCache_InsertCacheTypeByInfo(Cache, Width, Height, NumMipLevels, Info); +} + +//======================================================================================================== +// GCache_TypeDestroy +//======================================================================================================== +void GCache_TypeDestroy(GCache_Type *CacheType) +{ + assert(CacheType->RefCount > 0); + + CacheType->RefCount--; + + if (CacheType->RefCount == 0) + { + if (CacheType->Slots) + { + assert(CacheType->UsedSlots > 0); + free(CacheType->Slots); + } + else + { + assert(CacheType->UsedSlots == 0); + } + + CacheType->UsedSlots = 0; + CacheType->Slots = NULL; + } +} + +//======================================================================================================== +// GCache_FreeAllSlots +//======================================================================================================== +geBoolean GCache_FreeAllSlots(GCache *Cache) +{ + int32 i; + GCache_Type *pCacheType; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< GCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + assert(pCacheType->RefCount >= 0); + + if (pCacheType->RefCount == 0) + { + assert(pCacheType->Slots == NULL); + assert(pCacheType->UsedSlots == 0); + continue; + } + + if (pCacheType->Slots) + { + assert(pCacheType->UsedSlots > 0); + free(pCacheType->Slots); + } + else + assert(pCacheType->UsedSlots == 0); + + pCacheType->Slots = NULL; + pCacheType->UsedSlots = 0; + } + + return GE_TRUE; +} + +//======================================================================================================== +// GCache_WriteToFile +//======================================================================================================== +geBoolean GCache_WriteToFile(GCache *Cache, const char *FileName, geBoolean Append) +{ + int32 i; + GCache_Type *pCacheType; + int32 TotalRef, TotalUsed; + SYSTEMTIME Time; + FILE *f; + + if (Append) + f = fopen(FileName, "a+t"); + else + f = fopen(FileName, "w"); + + if (!f) + return GE_FALSE; + + pCacheType = Cache->CacheTypes; + + TotalRef = TotalUsed = 0; + + GetSystemTime(&Time); + + fprintf(f, "=======================================================\n"); + fprintf(f, "Date: %i/%i/%i, Time: %i:%i\n", Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute); + fprintf(f, "Cache Name: %s\n", Cache->Name); + fprintf(f, "Total Memory for Cache: %6i\n", GMemMgr_GetTotalMemory(Cache->MemMgr)); + fprintf(f, "Free Memory for Cache: %6i\n", GMemMgr_GetFreeMemory(Cache->MemMgr)); + fprintf(f, "--- Slots ---\n"); + + for (i=0; i< GCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (!pCacheType->RefCount) + continue; + + fprintf(f, "Width: %3i, Height %3i, Mips: %2i, Ref: %4i, Used: %4i\n", + pCacheType->Width, pCacheType->Height, pCacheType->NumMipLevels, pCacheType->RefCount, pCacheType->UsedSlots); + + TotalRef += pCacheType->RefCount; + TotalUsed += pCacheType->UsedSlots; + } + + fprintf(f, "Total Ref: %4i, Total Used: %4i\n", TotalRef, TotalUsed); + + fclose(f); + + return GE_TRUE; +} + +static geBoolean AppendHack = GE_FALSE; + +//======================================================================================================== +// GCache_AdjustSlots +//======================================================================================================== +geBoolean GCache_AdjustSlots(GCache *Cache) +{ + GCache_Type *pCacheType; + int32 i; + + GCache_FreeAllSlots(Cache); + + GMemMgr_Reset(Cache->MemMgr); // Reset the caches memory manager + + while(1) + { + GCache_Slot *LastSlot; + + LastSlot = NULL; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< GCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + GCache_Slot *pSlot; + uint32 Size; + + if (pCacheType->RefCount <= 0) + { + assert(pCacheType->Slots == NULL); + assert(pCacheType->UsedSlots == 0); + continue; + } + + if (pCacheType->UsedSlots >= pCacheType->RefCount) + continue; // This is all we need for this slot... + + if (!pCacheType->Slots) // If no slots have been allocated, allocate them now... + { + assert(pCacheType->UsedSlots == 0); + + pCacheType->Slots = malloc(sizeof(GCache_Type)*pCacheType->RefCount); + + if (!pCacheType->Slots) + return GE_FALSE; + + memset(pCacheType->Slots, 0, sizeof(GCache_Type)*pCacheType->RefCount); + } + + Size = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &pCacheType->Info); + + if (GMemMgr_GetFreeMemory(Cache->MemMgr) < Size) + break; // Took all available ram from memmgr. No choice, but to stop + + pSlot = &pCacheType->Slots[pCacheType->UsedSlots++]; + pSlot->SelfCheck = pSlot; + + pSlot->Type = pCacheType; + + if (!GMemMgr_AllocMem(Cache->MemMgr, Size, &pSlot->MemAddr)) + { + pCacheType->UsedSlots--; // Cancel last operation + break; + } + + LastSlot = pSlot; + } + + if (!LastSlot) // Nothing was allocated on that pass, so assume we are out of memory + break; + } + + pCacheType = Cache->CacheTypes; + + // Go through one last time, and make sure all got allocated + for (i=0; i< GCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (pCacheType->RefCount <= 0) + { + assert(pCacheType->Slots == NULL); + assert(pCacheType->UsedSlots == 0); + continue; + } + + if (pCacheType->UsedSlots <= 0) // Oops... + return GE_FALSE; + + assert(pCacheType->Slots != NULL); + } + +#ifdef GCACHE_WRITELOG + GCache_WriteToFile(Cache, "GCache.Log", AppendHack); + + AppendHack = GE_TRUE; +#endif + + return GE_TRUE; +} + +//======================================================================================================== +// GCache_SlotGetMemAddress +//======================================================================================================== +uint32 GCache_SlotGetMemAddress(GCache_Slot *Slot) +{ + assert(GCache_SlotIsValid(Slot)); + + return Slot->MemAddr; +} + +//======================================================================================================== +// GCache_SlotIsValid +//======================================================================================================== +geBoolean GCache_SlotIsValid(GCache_Slot *Slot) +{ + if (!Slot) + return GE_FALSE; + + if (Slot->SelfCheck != Slot) + return GE_FALSE; + + return GE_TRUE; +} + +#ifdef DYNAMIC_CACHE + +#define GROW_DIR_LEFT 0 +#define GROW_DIR_RIGHT 1 + +#define MAX_STACK 64 + +typedef struct +{ + GCache_Type *Type; + int32 UsedSlots; +} GCache_TypeStack; + +//======================================================================================================== +// GCache_TypeGrowDir +//======================================================================================================== +GCache_Slot *GCache_TypeGrowDir(GCache_Type *CacheType, GCache_Type *Current, int32 Dir) +{ + uint32 Size; + int32 UsedSlots; + GCache_Type *Original; + GCache_TypeStack Stack[MAX_STACK], *pStack; + + assert(CacheType); + assert(Current); + + Original = Current; + + Size = Current->Size; + UsedSlots = Current->UsedSlots; + + pStack = Stack; + + // Do a test run, to see if we can make a new slot + while (CacheType->Size > Size) + { + // CacheType does not have enough memory, need to take more + + if (pStack >= &Stack[MAX_STACK]) + return NULL; // No more stack space, oh well... + + if (UsedSlots <= 1) // Keep at least one slot used + { + pStack->Type = Current; + pStack->UsedSlots = UsedSlots; + pStack++; + + Current = Current->PrevNext[Dir]; + + if (!Current) + return NULL; // Can't do it + + UsedSlots = Current->UsedSlots; + continue; + } + + UsedSlots--; + Size += Current->Size; + + pStack->Type = Current; + pStack->UsedSlots = UsedSlots; + pStack++; + } + + // Go back up the stack, fixing up slots in the types we are gonna grow into... + while (pStack-- > Stack) + { + pStack->Type->UsedSlots = pStack->UsedSlots; + } + + return &Original->Slots[Original->UsedSlots++]; +} + +//======================================================================================================== +// GCache_TypeGrow +// Trys to grow to the left or to the right by stealing one of it's neigbors +//======================================================================================================== +GCache_Slot *GCache_TypeGrow(GCache_Type *CacheType) +{ + GCache_Type **PrevNext; + GCache_Slot *Slot; + int32 Dir; + + PrevNext = CacheType->PrevNext; + + assert(PrevNext[0] || PrevNext[1]); // At least one must be initialized + + if (!PrevNext[0]) + return GCache_TypeGrowDir(CacheType, PrevNext[1], GROW_DIR_RIGHT); + if (!PrevNext[1]) + return GCache_TypeGrowDir(CacheType, PrevNext[0], GROW_DIR_LEFT); + + // Pick the best side first (the one with the biggest texture size) + if (PrevNext[GROW_DIR_LEFT]->Size > PrevNext[GROW_DIR_RIGHT]->Size) + Dir = GROW_DIR_LEFT; + else + Dir = GROW_DIR_RIGHT; + + Slot = GCache_TypeGrowDir(CacheType, PrevNext[Dir], Dir); + + if (!Slot) // Try opposite direction + Slot = GCache_TypeGrowDir(CacheType, PrevNext[!Dir], !Dir); + + return Slot; +} + +#endif + +//======================================================================================================== +// GCache_TypeFindSlot +//======================================================================================================== +GCache_Slot *GCache_TypeFindSlot(GCache_Type *CacheType) +{ + GCache_Slot *pBestSlot, *pSlot; + uint32 BestLRU; + int32 i; + + assert(CacheType->Slots); + +#ifdef DYNAMIC_CACHE + // First, try to steal a slot from one of our neigbors... + // Try the biggest side first + if (pBestSlot = GCache_TypeGrow(CacheType)) + goto GotIt; +#endif + + pSlot = CacheType->Slots; + pBestSlot = pSlot; + BestLRU = pBestSlot->LRU; + + for (i=0; i< CacheType->UsedSlots; i++, pSlot++) + { + if (pSlot->LRU < BestLRU) + { + pBestSlot = pSlot; + BestLRU = pSlot->LRU; + } + } + +#ifdef DYNAMIC_CACHE + GotIt: +#endif + + pBestSlot->LRU = 0; + pBestSlot->UserData = NULL; + + return pBestSlot; +} + +//======================================================================================================== +// GCache_SlotSetUserData +//======================================================================================================== +void GCache_SlotSetUserData(GCache_Slot *Slot, void *UserData) +{ + assert(GCache_SlotIsValid(Slot)); + + Slot->UserData = UserData; +} + +//======================================================================================================== +// GCache_SlotGetUserData +//======================================================================================================== +void *GCache_SlotGetUserData(GCache_Slot *Slot) +{ + assert(GCache_SlotIsValid(Slot)); + + return Slot->UserData; +} + +//======================================================================================================== +// GCache_SlotGetInfo +//======================================================================================================== +GrTexInfo *GCache_SlotGetInfo(GCache_Slot *Slot) +{ + assert(GCache_SlotIsValid(Slot)); + + return &Slot->Type->Info; +} + +//======================================================================================================== +// GCache_SlotSetLRU +//======================================================================================================== +void GCache_SlotSetLRU(GCache_Slot *Slot, uint32 LRU) +{ + assert(GCache_SlotIsValid(Slot)); + + Slot->LRU = LRU; +} diff --git a/G3D/Engine/Drivers/GlideDrv/GCache.h b/G3D/Engine/Drivers/GlideDrv/GCache.h new file mode 100644 index 0000000..939c027 --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GCache.h @@ -0,0 +1,66 @@ +/****************************************************************************************/ +/* GCache.h */ +/* */ +/* Author: John Pollard */ +/* Description: Texture cache manager for glide */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GCACHE_H +#define GCACHE_H + +#include +#include "Glide.h" + +#include "BaseType.h" +#include "GMemMGr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GCACHE_MAX_NAME 256 + +typedef struct GCache GCache; +typedef struct GCache_Type GCache_Type; +typedef struct GCache_Slot GCache_Slot; + + +GCache *GCache_Create(const char *Name, GMemMgr *MemMgr); +void GCache_Destroy(GCache *Cache); +geBoolean GCache_Reset(GCache *Cache); +GCache_Type *GCache_FindCacheTypeByInfo(GCache *Cache, const GrTexInfo *Info); +GCache_Type *GCache_InsertCacheTypeByInfo(GCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, const GrTexInfo *Info); +geBoolean GCache_UpdateSlot(GCache *Cache, GCache_Slot *Slot, GrTexInfo *Info); +geBoolean GCache_SetTexture(GCache *Cache, GCache_Slot *Slot); +GCache_Type *GCache_TypeCreate(GCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, const GrTexInfo *Info); +void GCache_TypeDestroy(GCache_Type *CacheType); +geBoolean GCache_FreeAllSlots(GCache *Cache); +geBoolean GCache_AdjustSlots(GCache *Cache); +uint32 GCache_SlotGetMemAddress(GCache_Slot *Slot); +uint32 GCache_SlotGetMemAddress(GCache_Slot *Slot); +geBoolean GCache_SlotIsValid(GCache_Slot *Slot); +GCache_Slot *GCache_TypeFindSlot(GCache_Type *CacheType); +void GCache_SlotSetUserData(GCache_Slot *Slot, void *UserData); +void *GCache_SlotGetUserData(GCache_Slot *Slot); +GrTexInfo *GCache_SlotGetInfo(GCache_Slot *Slot); +void GCache_SlotSetLRU(GCache_Slot *Slot, uint32 LRU); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/GlideDrv/GLIDEDRV.H b/G3D/Engine/Drivers/GlideDrv/GLIDEDRV.H new file mode 100644 index 0000000..e7a6c34 --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GLIDEDRV.H @@ -0,0 +1,33 @@ +/****************************************************************************************/ +/* GlideDrv.h */ +/* */ +/* Author: John Pollard */ +/* Description: Distributes work to other modules. This is the main GlideDrv file. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GLIDEDRV_H +#define GLIDEDRV_H + +#include "BaseType.h" + +#include "DCommon.h" + +extern DRV_Driver GLIDEDRV; + +void SetLastDrvError(int32 Error, char *ErrorStr); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/GlideDrv/GMain.c b/G3D/Engine/Drivers/GlideDrv/GMain.c new file mode 100644 index 0000000..2ea4546 --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GMain.c @@ -0,0 +1,405 @@ +/****************************************************************************************/ +/* GMain.c */ +/* */ +/* Author: John Pollard */ +/* Description: Glide initialization code, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "GlideDrv.h" +#include "GMain.h" +#include "GCache.h" +#include "Glide.h" +#include "GTHandle.h" + +int WriteBMP(unsigned short *ScreenBuffer, const char *Name); + +GrChipID_t TMU[3]; // TMU map number table + +DRV_Window ClientWindow; + +static RECT OldWindow; + +GMain_BoardInfo g_BoardInfo; // Global board info for current hardware + +geBoolean g_FogEnable = GE_TRUE; +geFloat g_FogR; +geFloat g_FogG; +geFloat g_FogB; + +//============================================================================== +//============================================================================== +geBoolean GMain_Startup(DRV_DriverHook *Hook) +{ + + int32 VidMode; + + //SetEnvironmentVariable("SST_GAMMA", "1.0"); + + switch(Hook->Mode) + { + case 0: + { + ClientWindow.Width = 512; + ClientWindow.Height = 384; + VidMode = GR_RESOLUTION_512x384; + break; + } + case 1: + { + ClientWindow.Width = 640; + ClientWindow.Height = 480; + VidMode = GR_RESOLUTION_640x480; + break; + } + case 2: + { + ClientWindow.Width = 800; + ClientWindow.Height = 600; + VidMode = GR_RESOLUTION_800x600; + break; + } + case 3: + { + ClientWindow.Width = 1024; + ClientWindow.Height = 768; + VidMode = GR_RESOLUTION_1024x768; + break; + } + default: + { + SetLastDrvError(DRV_ERROR_NULL_WINDOW, "GLIDE_DrvInit: Invalid display mode."); + return FALSE; + } + } + + ClientWindow.hWnd = Hook->hWnd; + + // Go full-screen so we won't lose the mouse + { + RECT DeskTop; + + // Save the old window size + GetWindowRect(ClientWindow.hWnd, &OldWindow); + + // Get the size of the desktop + GetWindowRect(GetDesktopWindow(), &DeskTop); + + // Resize the window to the size of the desktop + MoveWindow(ClientWindow.hWnd, DeskTop.left-4, DeskTop.top-40, DeskTop.right+20, DeskTop.bottom+20, TRUE); + + // Center the mouse + SetCursorPos(ClientWindow.Width / 2, ClientWindow.Height / 2); + } + + // initialize the Glide library + grGlideInit(); + + // Get the info about this board + if (!GMain_GetBoardInfo(&g_BoardInfo)) + return FALSE; + + if (g_BoardInfo.NumTMU <= 0) + { + SetLastDrvError(DRV_ERROR_INIT_ERROR, "GLIDE_DrvInit: Not enough texture mapping units."); + return GE_FALSE; + } + + // select the current graphics system + grSstSelect(0); + + // initialize and open the graphics system + if (!grSstWinOpen( (U32)ClientWindow.hWnd, + VidMode, + GR_REFRESH_60Hz, + GR_COLORFORMAT_ABGR, + GR_ORIGIN_UPPER_LEFT, + 2, 1 )) + { + SetLastDrvError(DRV_ERROR_INIT_ERROR, "GLIDE_DrvInit: grSstWinOpen failed."); + return GE_FALSE; + } + + // We know that GLIDE will be in 5-6-5 mode... + ClientWindow.R_shift = 5+6; + ClientWindow.G_shift = 5; + ClientWindow.B_shift = 0; + + ClientWindow.R_mask = 0xf800; + ClientWindow.G_mask = 0x07e0; + ClientWindow.B_mask = 0x001f; + + ClientWindow.R_width = 5; + ClientWindow.G_width = 6; + ClientWindow.B_width = 5; + + SetLastDrvError(DRV_ERROR_NONE, "GMain_Startup: No error."); + + if (!GTHandle_Startup()) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GMain_Startup: GTHandle_Startup failed...\n"); + return GE_FALSE; + } + + if (!GMain_InitGlideRegisters()) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GMain_Startup: GMain_InitGlideRegisters failed...\n"); + return GE_FALSE; + } + + // Init the 3d display + //grSstControl(GR_CONTROL_ACTIVATE); + grGammaCorrectionValue(1.0f); + + return GE_TRUE; +} + +//================================================================================== +// GMain_Shutdown +//================================================================================== +void GMain_Shutdown(void) +{ + GTHandle_Shutdown(); + + // Resize the window to the size of the original size + MoveWindow(ClientWindow.hWnd, OldWindow.left, OldWindow.top, OldWindow.right, OldWindow.bottom, TRUE); + + grGlideShutdown(); +} + +//================================================================================== +// GMain_GetBoardInfo +// Glide is assumed to be initialized before this function is called... +//================================================================================== +geBoolean GMain_GetBoardInfo(GMain_BoardInfo *Info) +{ + GrHwConfiguration GlideHwConfig; + + // detect the Voodoo Graphics hardware in the host system + if (!grSstQueryHardware(&GlideHwConfig)) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GMain_GetBoardInfo: grSstQueryHardware failed."); + return GE_FALSE; + } + + memset(Info, 0, sizeof(*Info)); + + switch (GlideHwConfig.SSTs[0].type) + { + case GR_SSTTYPE_VOODOO: + + Info->MainRam = GlideHwConfig.SSTs[0].sstBoard.VoodooConfig.fbRam; + Info->NumTMU = GlideHwConfig.SSTs[0].sstBoard.VoodooConfig.nTexelfx; + break; + + case GR_SSTTYPE_SST96: + Info->MainRam = GlideHwConfig.SSTs[0].sstBoard.SST96Config.fbRam; + Info->NumTMU = GlideHwConfig.SSTs[0].sstBoard.SST96Config.nTexelfx; + break; + + case GR_SSTTYPE_AT3D: + SetLastDrvError(DRV_ERROR_GENERIC, "GMain_GetBoardInfo: GR_SSTTYPE_AT3D not supported."); + return GE_FALSE; + + case GR_SSTTYPE_Voodoo2: + Info->MainRam = GlideHwConfig.SSTs[0].sstBoard.Voodoo2Config.fbRam; + Info->NumTMU = GlideHwConfig.SSTs[0].sstBoard.Voodoo2Config.nTexelfx; + break; + } + +#if 0 + Info->NumTMU = 1; +#endif + + return GE_TRUE; +} + +static GrFog_t FogTable[GR_FOG_TABLE_SIZE]; + +//================================================================================== +// GMain_InitGlideRegisters +//================================================================================== +geBoolean GMain_InitGlideRegisters(void) +{ + // + // Setup card register states + // + + // fix up the z-buffer + grDepthBufferMode( GR_DEPTHBUFFER_ZBUFFER ); + grDepthBufferFunction( GR_CMP_GEQUAL ); + grDepthMask( FXTRUE ); + + // Fixup the transparent color + grChromakeyMode(GR_CHROMAKEY_DISABLE); // Off by default, on for decals though... + grChromakeyValue(1); + + // Fixup the Mipmapping + // TMU + // Bias -32...+31 + // Detail scale 0...7 + // Detail Max 0...1.0 + grTexDetailControl(TMU[0], 0, 1, 1.0f); + + // -8... 7.75 + grTexLodBiasValue(TMU[0], -1.0f); + //grTexLodBiasValue(TMU[0], 7.0f); + + // Tell it how we like it... + guColorCombineFunction( GR_COLORCOMBINE_DECAL_TEXTURE ); + + guTexCombineFunction( TMU[0], GR_TEXTURECOMBINE_DECAL ); + + //rTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); + //grTexMipMapMode( TMU[0], GR_MIPMAP_DISABLE, FXFALSE ); + + //grTexFilterMode( TMU[0], GR_TEXTUREFILTER_POINT_SAMPLED,GR_TEXTUREFILTER_BILINEAR); + //grTexFilterMode( TMU[0], GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_POINT_SAMPLED); + grTexFilterMode( TMU[0], GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR); + grTexClampMode( TMU[0], GR_TEXTURECLAMP_WRAP,GR_TEXTURECLAMP_WRAP); + + grTexCombine( TMU[0], + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE ); + + + // turn on gouraud shading + grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_TEXTURE, + FXFALSE ); + + + grAlphaCombine( GR_COMBINE_FUNCTION_BLEND_OTHER, + GR_COMBINE_FACTOR_LOCAL_ALPHA, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_TEXTURE, + FXFALSE ); + + /* + grAlphaCombine( GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_LOCAL, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_TEXTURE, + FXFALSE ); + */ + + //grAlphaControlsITRGBLighting(FXTRUE); + //grGlideShamelessPlug(FXTRUE); + + if (g_BoardInfo.NumTMU >= 2) + { + grTexDetailControl(TMU[1], 0, 1, 0.3f); + grTexLodBiasValue(TMU[1], 0.3f); + + guTexCombineFunction( TMU[1], GR_TEXTURECOMBINE_DECAL ); + + grTexFilterMode( TMU[1], GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR); + grTexClampMode( TMU[1], GR_TEXTURECLAMP_CLAMP,GR_TEXTURECLAMP_CLAMP); + + grTexCombine( TMU[1], + GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + FXFALSE, FXFALSE ); + + // Always texture clamp on second TMU (it only uses lightmaps for now) + grTexClampMode(TMU[1], GR_TEXTURECLAMP_CLAMP,GR_TEXTURECLAMP_CLAMP); + + grHints(GR_HINT_STWHINT, GR_STWHINT_ST_DIFF_TMU0 | GR_STWHINT_ST_DIFF_TMU1); + } + + //GMain_SetFogEnable(GE_TRUE, 0.0f, 255.0f, 0.0f, 500.0f, 1500.0f); + GMain_SetFogEnable(GE_FALSE, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + + return GE_TRUE; +} + +extern uint32 CurrentLRU; // Shame!!! + +//================================================================================== +// Reset the 3dfx, and free all allocated ram +//================================================================================== +geBoolean GMain_ResetAll(void) +{ + GTHandle_Shutdown(); + + if (!GTHandle_Startup()) + return GE_FALSE; + + if (!GMain_InitGlideRegisters()) + return GE_FALSE; + + CurrentLRU = 0; + + return GE_TRUE; +} + +//================================================================================== +//================================================================================== +geBoolean DRIVERCC GMain_ScreenShot(const char *Name) +{ + uint16 *Buffer; + + Buffer = (uint16*)malloc(sizeof(uint16*)*ClientWindow.Width*ClientWindow.Height); + + if (!grLfbReadRegion(GR_BUFFER_FRONTBUFFER,0,0,ClientWindow.Width,ClientWindow.Height, + ClientWindow.Width*2, (void*)Buffer)) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE: Could not save BMP."); + return FALSE; + } + + WriteBMP(Buffer, Name, ClientWindow.Width, ClientWindow.Height); + + free(Buffer); + + return GE_TRUE; +} + +//================================================================================== +// GMain_SetFogEnable +//================================================================================== +geBoolean DRIVERCC GMain_SetFogEnable(geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End) +{ + g_FogEnable = Enable; + g_FogR = r; + g_FogG = g; + g_FogB = b; + + if (g_FogEnable) + { + grFogMode(GR_FOG_WITH_TABLE); + grFogColorValue(((uint32)b<<16)|((uint32)g<<8)|(uint32)r); + guFogGenerateLinear(FogTable, Start, End); + grFogTable(FogTable); + } + else + { + grFogMode(GR_FOG_DISABLE); + } + + return GE_TRUE; +} diff --git a/G3D/Engine/Drivers/GlideDrv/GMain.h b/G3D/Engine/Drivers/GlideDrv/GMain.h new file mode 100644 index 0000000..00c77ed --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GMain.h @@ -0,0 +1,68 @@ +/****************************************************************************************/ +/* GMain.h */ +/* */ +/* Author: John Pollard */ +/* Description: Glide initialization code, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GMAIN_H +#define GMAIN_H + +#include + +#include "GTHandle.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GMAIN_MAX_TMU_SUPPORT 8 + +typedef struct +{ + uint32 MainRam; + int32 NumTMU; + uint32 TmuRam[GMAIN_MAX_TMU_SUPPORT]; +} GMain_BoardInfo; + +extern GrChipID_t TMU[3]; // TMU number table + +extern DRV_Window ClientWindow; +extern GrHwConfiguration GlideHwConfig; +extern GMain_BoardInfo g_BoardInfo; // Global board info for current hardware + +extern geBoolean g_FogEnable; +extern geFloat g_FogR; +extern geFloat g_FogG; +extern geFloat g_FogB; + +//============================================================================================ +//============================================================================================ + +geBoolean GMain_Startup(DRV_DriverHook *Hook); +void GMain_Shutdown(void); +geBoolean GMain_GetBoardInfo(GMain_BoardInfo *Info); +geBoolean GMain_InitGlideRegisters(void); +geBoolean GMain_ResetAll(void); +geBoolean DRIVERCC GMain_ScreenShot(const char *Name); +geBoolean DRIVERCC GMain_SetFogEnable(geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/GlideDrv/GMemMgr.c b/G3D/Engine/Drivers/GlideDrv/GMemMgr.c new file mode 100644 index 0000000..835bc12 --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GMemMgr.c @@ -0,0 +1,148 @@ +/****************************************************************************************/ +/* GMemMgr.c */ +/* */ +/* Author: John Pollard */ +/* Description: Mini memory manager for glide */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "GMemMgr.h" +#include "BaseType.h" +#include "Glide.h" + +//======================================================================================================== +//======================================================================================================== +typedef struct GMemMgr +{ + GrChipID_t Tmu; // Tmu that this memory manager is in charge of + + uint32 MinAddress; // Min address allowed to use for this mgr + uint32 MaxAddress; // Max address allowed to use for this mgr + + uint32 CurrentAddress; +} GMemMgr; + +//======================================================================================================== +// GMemMgr_Create +// Create a memmgr on a tmu, and assumes it has all the data available to it... +//======================================================================================================== +GMemMgr *GMemMgr_Create(GrChipID_t Tmu, uint32 MinAddress, uint32 MaxAddress) +{ + GMemMgr *MemMgr; + + MemMgr = malloc(sizeof(GMemMgr)); + + if (!MemMgr) + return NULL; + + // Clear the memmgr + memset(MemMgr, 0, sizeof(GMemMgr)); + + // Set the default values... + MemMgr->Tmu = Tmu; + + MemMgr->MinAddress = MinAddress; + MemMgr->MaxAddress = MaxAddress; + + MemMgr->CurrentAddress = MinAddress; + + return MemMgr; +} + +//======================================================================================================== +// GMemMgr_Destroy +//======================================================================================================== +void GMemMgr_Destroy(GMemMgr *MemMgr) +{ + assert(MemMgr); + + free(MemMgr); +} + +//======================================================================================================== +// GMemMgr_GetTotalMemory +//======================================================================================================== +uint32 GMemMgr_GetTotalMemory(GMemMgr *MemMgr) +{ + return (MemMgr->MaxAddress - MemMgr->MinAddress); +} + +//======================================================================================================== +// GMemMgr_GetFreeMemory +//======================================================================================================== +uint32 GMemMgr_GetFreeMemory(GMemMgr *MemMgr) +{ + return (MemMgr->MaxAddress - MemMgr->CurrentAddress); +} + +//======================================================================================================== +// GMemMgr_AllocMem +//======================================================================================================== +geBoolean GMemMgr_AllocMem(GMemMgr *MemMgr, uint32 Size, uint32 *Address) +{ + #define TWO_MEG (1024*1024*2) + + uint32 StartAddr; + + assert(MemMgr); + assert(GMemMgr_GetFreeMemory(MemMgr) >= Size); + + if (GMemMgr_GetFreeMemory(MemMgr) < Size) + return GE_FALSE; + + if (((MemMgr->CurrentAddress+Size)%TWO_MEG) < Size) // Align on 2 meg boundry... + { + MemMgr->CurrentAddress = ((MemMgr->CurrentAddress / TWO_MEG)+1) * TWO_MEG; + if (MemMgr->CurrentAddress+Size >= MemMgr->MaxAddress) + return GE_FALSE; + } + + while ((MemMgr->CurrentAddress & 7) != 0) + { + MemMgr->CurrentAddress++; + if (MemMgr->CurrentAddress+Size >= MemMgr->MaxAddress) + return GE_FALSE; + } + + StartAddr = MemMgr->CurrentAddress; + + MemMgr->CurrentAddress += Size; + + *Address = StartAddr; + + return GE_TRUE; +} + +//======================================================================================================== +// GMemMgr_GetTmu +//======================================================================================================== +GrChipID_t GMemMgr_GetTmu(GMemMgr *MemMgr) +{ + assert(MemMgr); + + return MemMgr->Tmu; +} + +//======================================================================================================== +// GMemMgr_Reset +//======================================================================================================== +void GMemMgr_Reset(GMemMgr *MemMgr) +{ + MemMgr->CurrentAddress = MemMgr->MinAddress; +} diff --git a/G3D/Engine/Drivers/GlideDrv/GMemMgr.h b/G3D/Engine/Drivers/GlideDrv/GMemMgr.h new file mode 100644 index 0000000..ff32117 --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GMemMgr.h @@ -0,0 +1,47 @@ +/****************************************************************************************/ +/* GMemMgr.h */ +/* */ +/* Author: John Pollard */ +/* Description: Mini memory manager for glide */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GMEMMGR_H +#define GMEMMGR_H + +#include +#include "Glide.h" +#include "BaseType.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GMemMgr GMemMgr; + +GMemMgr *GMemMgr_Create(GrChipID_t Tmu, uint32 MinAddress, uint32 MaxAddress); +void GMemMgr_Destroy(GMemMgr *MemMgr); +uint32 GMemMgr_GetTotalMemory(GMemMgr *MemMgr); +uint32 GMemMgr_GetFreeMemory(GMemMgr *MemMgr); +geBoolean GMemMgr_AllocMem(GMemMgr *MemMgr, uint32 Size, uint32 *Address); +GrChipID_t GMemMgr_GetTmu(GMemMgr *MemMgr); +void GMemMgr_Reset(GMemMgr *MemMgr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Engine/Drivers/GlideDrv/GSpan.cpp b/G3D/Engine/Drivers/GlideDrv/GSpan.cpp new file mode 100644 index 0000000..ac15c7a --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GSpan.cpp @@ -0,0 +1,278 @@ +/****************************************************************************************/ +/* GSpan.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Front to back span code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "GSpan.h" +#include "GlideDrv.h" +#include "GMain.h" + +SPAN SpanLines[MAX_SPAN_LINES]; + +SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +SLIST ScanHash[MAX_SPANS]; // hash table for SList + +BOOL PolyVisible = FALSE; + +int32 NumWorldPixels = 0; +int32 NumSpans = 0; +int32 NumSpanPixels[MAX_SPAN_LINES]; +int32 PolysRendered = 0; + +int32 CurrentSList = 0; + +const int32 CEIL_FRACT = ( ( 1 << 16)-1); +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2) +{ + int32 Ctmp; + int32 y; + int32 x,m; + + int32 Ydelta; + int32 Dir; + int32 Cx1, Cx2, Cy1, Cy2; + SPAN *pSpans; + + Cx1 = x1; + Cx2 = x2; + Cy1 = y1; + Cy2 = y2; + + if (Cy2 != Cy1) // This isn't a horizontal line + { + Dir =0; // Left side + + if (Cy2 < Cy1) // Make sure y2 is greater than y1 + { + Dir =1; // Right side + + Ctmp = Cx1; + Cx1 = Cx2; + Cx2 = Ctmp; + + Ctmp = Cy1; + Cy1 = Cy2; + Cy2 = Ctmp; + + } + + Ydelta = (Cy2 - Cy1); + + x = (Cx1 << 16) + CEIL_FRACT; // Allign on int amounts + m = (((Cx2 - Cx1))<<16) / Ydelta; // How much to increase x each iteration + + pSpans = &SpanLines[Cy1]; + + if (Dir == 0) + { + for (y = Cy1; y <= Cy2; y++) // Go through each row + { + pSpans->x1 = (x>>16); + pSpans++; + x += m; // Add our constant to x + } + } + else + { + for (y = Cy1; y <= Cy2; y++) // Go through each row + { + pSpans->x2 = (x>>16); + pSpans++; + x += m; // Add our constant to x + } + } + } +} + +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y) +{ + int32 i, xx2; + SLIST *LineStart = NULL; + SLIST *Current; + + assert(y >=0 && y < MAX_SPAN_LINES); + + // FIXME: Make set ClientWindow.VWidth + if (NumSpanPixels[y] >= ClientWindow.Width) + return; + + if (x1 > x2) // Swap all the coordinates so x1 < x2 + { + i = x1; + x1 = x2; + x2 = i; + } + + //if ( (x2 - x1) < 0) + // return; // Invalid line + + Current = SMinMax[y].First; + + // Check to see if there are spans + // in the list yet... + if (SMinMax[y].First == NULL) + { + SMinMax[y].First = NewSList(); + (SMinMax[y].First)->Last = NULL; + (SMinMax[y].First)->Next = NULL; + (SMinMax[y].First)->Min = x1; + (SMinMax[y].First)->Max = x2; + } + else while (Current != NULL) + { + if (x1 >= Current->Min && x2 <= Current->Max) + return; // This line totally hidden... + + //if falls before the entire min, max + if (LineStart == NULL) + { + if (Current == SMinMax[y].First) + if (x2 < Current->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current; + NewMinMax->Last = NULL; + Current->Last = NewMinMax; + SMinMax[y].First = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if falls in the middle (but not touching) + if (Current->Next != NULL) + if (x1 > Current->Max && x2 < (Current->Next)->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current->Next; + NewMinMax->Last = Current; + (Current->Next)->Last = NewMinMax; + Current->Next = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if it falls to the right of all spans + if (Current->Next == NULL) + if (x1 > Current->Max) + { + SLIST *NewMinMax = NewSList(); + Current->Next = NewMinMax; + NewMinMax->Next = NULL; + NewMinMax->Last = Current; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + } + //if we have already started crossing spans, and we find out + // that we are in front of a span, then we can bail out... + if (LineStart != NULL) + if (x2 < Current->Min) + goto WasNull; + + + // We now know that we have not fallen into any empty holes. + // We must now check to see what spans, we've crossed... + + // if split by a min/max + if (x1 < Current->Min && x2 > Current->Max) + { + xx2 = Current->Min-1; + Current->Min = x1; + + NumWorldPixels += xx2 - x1 + 1; + NumSpanPixels[y] += xx2 - x1 + 1; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + x1 = Current->Max+1; + Current->Max = x2; + if (LineStart!=NULL) + LineStart->Max = x2; + else + LineStart = Current; + goto next; + } + + if (x1 <= Current->Max && x2 > Current->Max) + { + x1 = Current->Max+1; + Current->Max = x2; + LineStart = Current; + goto next; + } + if (x1 < Current->Min && x2 >= Current->Min) + { + x2 = Current->Min-1; + Current->Min = x1; + if (LineStart!=NULL) + LineStart->Max = Current->Max; + goto WasNull; + } + next:; + Current = Current->Next; + } + WasNull:; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + NumWorldPixels += x2 - x1 + 1; + NumSpanPixels[y] += x2 - x1 + 1; +} + +void ResetSList(void) +{ + CurrentSList = 0; + NumSpans = 0; +} + +SLIST *NewSList(void) +{ + + CurrentSList++; + NumSpans++; + + assert(CurrentSList < MAX_SPANS); + + return &ScanHash[CurrentSList-1]; + + return NULL; +} + +void ResetSpans(int32 Rows) +{ + int32 i; + + for (i=0; i + +#include "DCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_SPAN_LINES 1024 +#define MAX_SPANS 35000 + +typedef struct +{ + int32 x1; // Starting x on screen + int32 x2; // Ending x on screen +} SPAN; + +typedef struct SLIST +{ + uint8 Used; + int32 Min, Max; + uint32 Flags; + struct SLIST *Last; + struct SLIST *Next; +} SLIST; + +typedef struct +{ + SLIST *First; + SLIST *Current; +} SPAN_MINMAX; + +extern SPAN SpanLines[MAX_SPAN_LINES]; + +extern SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +extern SLIST ScanHash[MAX_SPANS]; // hash table for SList + +extern int32 NumWorldPixels; +extern int32 NumSpans; +extern int32 NumSpanPixels[MAX_SPAN_LINES]; +extern int32 PolysRendered; + +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2); +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y); + +void ResetSList(void); +SLIST *NewSList(void); +void ResetSpans(int32 Rows); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/GlideDrv/GTHandle.h b/G3D/Engine/Drivers/GlideDrv/GTHandle.h new file mode 100644 index 0000000..56015ae --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GTHandle.h @@ -0,0 +1,125 @@ +/****************************************************************************************/ +/* GTHandle.h */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for glide */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef THANDLE_H +#define THANDLE_H + +#include + +#include "DCommon.h" +#include "BaseType.h" +#include "GCache.h" +#include "Glide.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_TEXTURE_HANDLES 20000 + +// THandle flags +#define THANDLE_UPDATE (1<<0) // Force a thandle to be uploaded to the card +#define THANDLE_LOCKED (1<<1) // THandle is currently locked (invalid for rendering etc) + +#define THANDLE_PALETTE_FORMAT (GE_PIXELFORMAT_32BIT_XRGB) + +//============================================================================================ +//============================================================================================ +typedef struct +{ + int32 RefCount; + int32 Width; + int32 Height; + int32 LogSize; + uint8 NumMipLevels; + geRDriver_PixelFormat PixelFormat; + + uint8 Log; + geFloat OneOverLogSize_255; +} THandle_Info; + +typedef struct geRDriver_THandle +{ + uint8 Active; + struct geRDriver_THandle *PalHandle; + int32 Width; // Original width/height + int32 Height; + int32 LogSize; // Square width/height in cache + uint8 NumMipLevels; + geFloat OneOverLogSize_255; + uint8 Log; + geRDriver_PixelFormat PixelFormat; + //GrTexInfo Info; + //uint16 InfoIndex; // Use this ASAP!!! + + void *Data; // Actual data bits of LogSize*LogSize + + GCache_Type *CacheType; + GCache_Slot *Slot; // Current slot this handle is being textured with + + uint8 Flags; +} geRDriver_THandle; + +extern geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; + +// Memory managers +extern GMemMgr *MemMgr[2]; + +// Texture caches +extern GCache *TextureCache; // Texture cache +extern GCache *LMapCache; // Lightmap texture cache + +extern geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; // Contain Texture/Decal/Lightmap handles + +extern geBoolean TexturesChanged; +extern geBoolean LMapsChanged; + +//============================================================================================ +//============================================================================================ +geBoolean GTHandle_Startup(void); +void GTHandle_Shutdown(void); +void GTHandle_FreeAllCaches(void); +geRDriver_THandle *GTHandle_FindTextureHandle(); +void GTHandle_FreeTextureHandle(geRDriver_THandle *THandle); +void GTHandle_FreeAllTextureHandles(void); +geBoolean GTHandle_SetupInfo(GrTexInfo *Info, int32 Width, int32 Height, int32 NumMipLevels, GrTextureFormat_t Format, int32 *Size); +geBoolean GlideFormatFromGenesisFormat(gePixelFormat Format, GrTextureFormat_t *Out); +geRDriver_THandle *Create3DTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *CreateLightmapTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *Create2DTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *DRIVERCC GTHandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geBoolean DRIVERCC GTHandle_Destroy(geRDriver_THandle *THandle); +geBoolean DRIVERCC GTHandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Data); +geBoolean DRIVERCC GTHandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel); +geBoolean DRIVERCC GThandle_SetPal(geRDriver_THandle *THandle, geRDriver_THandle *PalHandle); +geRDriver_THandle *DRIVERCC GThandle_GetPal(geRDriver_THandle *THandle); +geBoolean DRIVERCC GTHandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info); +geBoolean GTHandle_CheckTextures(void); +geBoolean GetLod(S32 Width, GrLOD_t *Lod); +geBoolean GetAspectRatio(int32 Width, int32 Height, GrAspectRatio_t *Aspect); +uint32 GetLog(uint32 P2); +int32 SnapToPower2(int32 Width); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/GlideDrv/GThandle.c b/G3D/Engine/Drivers/GlideDrv/GThandle.c new file mode 100644 index 0000000..55382fc --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GThandle.c @@ -0,0 +1,843 @@ +/****************************************************************************************/ +/* GTHandle.c */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for glide */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "GTHandle.h" +#include "GCache.h" +#include "GMain.h" +#include "GlideDrv.h" + + +#define TEXTURE_CACHE_PERCENT 0.75f +#define LMAP_CACHE_PERCENT 0.25f + +// Memory managers +GMemMgr *MemMgr[2]; + +// Texture caches +GCache *TextureCache; // Texture cache +GCache *LMapCache; // Lightmap texture cache + +geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; // Contain Texture/Decal/Lightmap handles + +geBoolean TexturesChanged; +geBoolean LMapsChanged; + +//================================================================================== +// GTHandle_Startup +//================================================================================== +geBoolean GTHandle_Startup(void) +{ + if (g_BoardInfo.NumTMU >= 2) + { + TMU[0] = GR_TMU0; + TMU[1] = GR_TMU1; + + MemMgr[0] = GMemMgr_Create(GR_TMU0, grTexMinAddress(GR_TMU0), grTexMaxAddress(GR_TMU0)); + if (!MemMgr[0]) + goto ExitWithError; + MemMgr[1] = GMemMgr_Create(GR_TMU1, grTexMinAddress(GR_TMU1), grTexMaxAddress(GR_TMU1)); + if (!MemMgr[1]) + goto ExitWithError; + + } + else + { + uint32 MinAddress, MaxAddress, MidAddress; + + TMU[0] = GR_TMU0; + TMU[1] = GR_TMU0; + + MinAddress = grTexMinAddress(GR_TMU0); + MaxAddress = grTexMaxAddress(GR_TMU0); + MidAddress = MinAddress + (uint32)((geFloat)(MaxAddress - MinAddress)*TEXTURE_CACHE_PERCENT); + + MemMgr[0] = GMemMgr_Create(GR_TMU0, MinAddress, MidAddress); + if (!MemMgr[0]) + goto ExitWithError; + MemMgr[1] = GMemMgr_Create(GR_TMU0, MidAddress+1, MaxAddress); + if (!MemMgr[1]) + goto ExitWithError; + } + + TextureCache = GCache_Create("Texture Cache", MemMgr[0]); + + if (!TextureCache) + goto ExitWithError; + + LMapCache = GCache_Create("Lightmap Cache", MemMgr[1]); + + if (!LMapCache) + goto ExitWithError; + + return GE_TRUE; + + ExitWithError: + { + GTHandle_FreeAllTextureHandles(); + GTHandle_FreeAllCaches(); + + return GE_FALSE; + } +} + +//================================================================================== +// GTHandle_Shutdown +//================================================================================== +void GTHandle_Shutdown(void) +{ + // Free all the texture handles first!!! + GTHandle_FreeAllTextureHandles(); + // Then free all the caches + GTHandle_FreeAllCaches(); + + TexturesChanged = GE_FALSE; + LMapsChanged = GE_FALSE; +} + +//================================================================================== +//================================================================================== +void GTHandle_FreeAllCaches(void) +{ + if (LMapCache) + GCache_Destroy(LMapCache); + if (TextureCache) + GCache_Destroy(TextureCache); + + TextureCache = NULL; + LMapCache = NULL; + + if (MemMgr[1]) + GMemMgr_Destroy(MemMgr[1]); + if (MemMgr[0]) + GMemMgr_Destroy(MemMgr[0]); + + MemMgr[0] = NULL; + MemMgr[1] = NULL; +} + +//======================================================================================== +// FindTextureHandle +//======================================================================================== +geRDriver_THandle *GTHandle_FindTextureHandle() +{ + int32 i; + geRDriver_THandle *THandle; + + THandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, THandle++) + { + if (!THandle->Active) + { + assert(THandle->Data == NULL); + + memset(THandle, 0, sizeof(geRDriver_THandle)); + + THandle->Active = GE_TRUE; + + return THandle; + } + } + + return NULL; +} + +//======================================================================================== +// GTHandle_FreeTextureHandle +//======================================================================================== +void GTHandle_FreeTextureHandle(geRDriver_THandle *THandle) +{ + assert(THandle); + assert(THandle->Active == GE_TRUE); + + if (THandle->Data) + free(THandle->Data); + + if (THandle->CacheType) + { + GCache_TypeDestroy(THandle->CacheType); + TexturesChanged = GE_TRUE; + } + + memset(THandle, 0, sizeof(geRDriver_THandle)); +} + +//================================================================================== +// GTHandle_FreeAllTextureHandles +//================================================================================== +void GTHandle_FreeAllTextureHandles(void) +{ + int32 i; + geRDriver_THandle *pTHandle; + + pTHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pTHandle++) + { + if (!pTHandle->Active) + { + assert(pTHandle->Data == NULL); + continue; + } + + GTHandle_FreeTextureHandle(pTHandle); + } +} + +//======================================================================================== +// GTHandle_SetupInfo +//======================================================================================== +geBoolean GTHandle_SetupInfo(GrTexInfo *Info, int32 Width, int32 Height, int32 NumMipLevels, GrTextureFormat_t Format, int32 *Size) +{ + GrLOD_t LLod, SLod; + GrAspectRatio_t Ratio; + int32 SquareSize; + + SquareSize = max(Width, Height); + SquareSize = SnapToPower2(SquareSize); + + if (!GetLod(SquareSize, &LLod)) + return GE_FALSE; + + if (!GetLod((SquareSize>>(NumMipLevels-1)), &SLod)) + return GE_FALSE; + +#if 1 + Ratio = GR_ASPECT_1x1; +#else + if (!GetAspectRatio(SquareSize, SquareSize, &Ratio)) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_SetupInfo: Invalid aspect ratio."); + return GE_FALSE; + } +#endif + + *Size = SquareSize; + + Info->largeLod = LLod; + Info->smallLod = SLod; + Info->aspectRatio = Ratio; + Info->format = Format; + + return GE_TRUE; +} + +//============================================================================================ +// GlideFormatFromGenesisFormat +//============================================================================================ +geBoolean GlideFormatFromGenesisFormat(gePixelFormat Format, GrTextureFormat_t *Out) +{ + switch(Format) + { + case GE_PIXELFORMAT_16BIT_565_RGB: + { + *Out = GR_TEXFMT_RGB_565; + break; + } + case GE_PIXELFORMAT_16BIT_4444_ARGB: + { + *Out = GR_TEXFMT_ARGB_4444; + break; + + } + case GE_PIXELFORMAT_16BIT_1555_ARGB: + { + *Out = GR_TEXFMT_ARGB_1555; + break; + + } + case GE_PIXELFORMAT_8BIT: + { + #ifdef ALPHA_PALETTE + *Out = GR_TEXFMT_AP_88; + #else + *Out = GR_TEXFMT_P_8; + #endif + break; + } + + default: + { + assert(!"GlideFormatFromGenesisFormat: Invalid Pixel format."); + *Out = GE_PIXELFORMAT_8BIT; + return GE_FALSE; + } + } + + return GE_TRUE; +} + +//======================================================================================== +// GTHandle_Create3DTexture +// Creates a 3d texture surface +//======================================================================================== +geRDriver_THandle *Create3DTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 SWidth, SHeight; // Snapped to power of 2 width/height + GrTexInfo Info; + int32 DataSize; + uint8 *Data; + geRDriver_THandle *THandle; + GrTextureFormat_t Format; + + assert(PixelFormat); + + Data = NULL; + + THandle = GTHandle_FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_Create3DTexture: No more handles left."); + goto ExitWithError; + } + + if (Width > 256) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_Create3DTexture: Width > 256."); + goto ExitWithError; + } + + if (Height > 256) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_Create3DTexture: Height > 256."); + goto ExitWithError; + } + + SWidth = SnapToPower2(Width); + SHeight = SnapToPower2(Height); + + if (Width != SWidth) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_Create3DTexture: Not a power of 2."); + goto ExitWithError; + } + + if (Height != SHeight) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_Create3DTexture: Not a power of 2."); + goto ExitWithError; + } + + if (!GlideFormatFromGenesisFormat(PixelFormat->PixelFormat, &Format)) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_RegisterMiscTexture: GlideFormatFromGenesisFormat failed..."); + goto ExitWithError; + } + + if (!GTHandle_SetupInfo(&Info, Width, Height, NumMipLevels, Format, &THandle->LogSize)) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_RegisterMiscTexture: SetupInfo failed..."); + goto ExitWithError; + } + + THandle->Log = (uint8)GetLog(THandle->LogSize); + + // Get the size of the data so we can create a block of memory for it + DataSize = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &Info); + + // Allocate the data + Data = (uint8*)malloc(sizeof(uint8)*DataSize); + + if (!Data) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_RegisterMiscTexture: out of memory for data."); + goto ExitWithError; + } + +#if 0 + memset(Data, 0xff, DataSize); // For debugging +#endif + + // Save the data pointer... + Info.data = (void*)Data; + + // Save the data + THandle->Data = Data; + THandle->Active = GE_TRUE; + THandle->NumMipLevels = (uint8)NumMipLevels; + //THandle->Info = Info; + + // Save off some other goot info + THandle->Width = Width; // Original Width + THandle->Height = Height; + + THandle->OneOverLogSize_255 = 255.0f / (geFloat)THandle->LogSize; + + THandle->CacheType = GCache_TypeCreate(TextureCache, THandle->LogSize, THandle->LogSize, NumMipLevels, &Info); + + THandle->PixelFormat = *PixelFormat; + + TexturesChanged = GE_TRUE; + + return THandle; + + ExitWithError: + { + if (Data) + free(Data); + + return NULL; + } +} + +//********************************************************************************** +// Loads a lightmap texture +//********************************************************************************** +geRDriver_THandle *CreateLightmapTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + geRDriver_THandle *THandle; + geFloat Size; + + THandle = GTHandle_FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_CreateLightmapTexture: Max texture handles."); + return NULL; + } + + if ( ! (PixelFormat->Flags&RDRIVER_PF_LIGHTMAP) ) // This should be the only bit set (except for Can_Do_ColorKey) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_CreateLightmapTexture: Invalid pixel format."); + return NULL; + } + + if (PixelFormat->PixelFormat != GE_PIXELFORMAT_16BIT_565_RGB) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_CreateLightmapTexture: PixelFormat != GE_PIXELFORMAT_16BIT_565_RGB."); + return NULL; + } + + THandle->Width = Width; + THandle->Height = Height; + + { + GrTexInfo Info; + + if (!GTHandle_SetupInfo(&Info, Width, Height, 1, GR_TEXFMT_RGB_565, &THandle->LogSize)) + return GE_FALSE; + THandle->Log = (uint8)GetLog(THandle->LogSize); + + THandle->CacheType = GCache_TypeCreate(LMapCache, THandle->LogSize, THandle->LogSize, NumMipLevels, &Info); + } + + Size = (geFloat)(THandle->LogSize<<4); + + THandle->OneOverLogSize_255 = 255.0f / Size; + + TexturesChanged = GE_TRUE; + + return THandle; +} + +//================================================================================== +// Create2DTexture +//================================================================================== +geRDriver_THandle *Create2DTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + geRDriver_THandle *THandle; + int32 Size; + + THandle = GTHandle_FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_CreateTexture: No more handles left."); + return NULL; + } + + THandle->Width = Width; + THandle->Height = Height; + THandle->LogSize = Width; + THandle->NumMipLevels = (uint8)NumMipLevels; + + Size = Width*Height; + + THandle->Data = (uint16*)malloc(sizeof(uint16)*Size); + THandle->PixelFormat = *PixelFormat; + + return THandle; +} + +//======================================================================================== +// GTHandle_CreatePalTexture +//======================================================================================== +geRDriver_THandle *CreatePalTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 DataSize; + uint32 *Data; + geRDriver_THandle *THandle; + GrTextureFormat_t Format; + + assert(PixelFormat); + + Data = NULL; + + THandle = GTHandle_FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_CreatePalTexture: No more handles left."); + goto ExitWithError; + } + + assert(Width == 256); + assert(Height == 1); + assert(NumMipLevels == 1); + + switch (PixelFormat->PixelFormat) + { + case THANDLE_PALETTE_FORMAT: + { + Format = GR_TEXFMT_P_8; + break; + } + + default: + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_CreatePalTexture: Invalid pixel format."); + goto ExitWithError; + } + } + + // Allocate the data + DataSize = sizeof(uint32)*256; + + Data = (uint32*)malloc(DataSize); + + if (!Data) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_RegisterMiscTexture: out of memory for data."); + goto ExitWithError; + } + +#if 0 + memset(Data, 0xff, DataSize); // For debugging +#endif + + // Save the data + THandle->Data = Data; + THandle->Active = GE_TRUE; + THandle->NumMipLevels = (uint8)NumMipLevels; + + THandle->Width = Width; // Original Width + THandle->Height = Height; + THandle->LogSize = Width; + THandle->PixelFormat = *PixelFormat; + + return THandle; + + ExitWithError: + { + if (Data) + free(Data); + + return NULL; + } +} + +//================================================================================== +// GTHandle_Create +//================================================================================== +geRDriver_THandle *DRIVERCC GTHandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + if (PixelFormat->Flags & RDRIVER_PF_2D) + return Create2DTexture(Width, Height, NumMipLevels, PixelFormat); + else if (PixelFormat->Flags & RDRIVER_PF_3D) + return Create3DTexture(Width, Height, NumMipLevels, PixelFormat); + else if (PixelFormat->Flags & RDRIVER_PF_LIGHTMAP) + return CreateLightmapTexture(Width, Height, NumMipLevels, PixelFormat); + else if (PixelFormat->Flags & RDRIVER_PF_PALETTE) + return CreatePalTexture(Width, Height, NumMipLevels, PixelFormat); + else + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_CreateTexture: Invalid pixelformat."); + return GE_FALSE; + } +} + +//================================================================================== +// GTHandle_Destroy +//================================================================================== +geBoolean DRIVERCC GTHandle_Destroy(geRDriver_THandle *THandle) +{ + GTHandle_FreeTextureHandle(THandle); + + return GE_TRUE; +} + +//================================================================================== +// GTHandle_Lock +//================================================================================== +geBoolean DRIVERCC GTHandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Data) +{ + int32 i, Size; + uint16 *pData; + uint8 *pData8; + + assert(MipLevel <= THandle->NumMipLevels); + + if (THandle->PixelFormat.Flags & RDRIVER_PF_LIGHTMAP) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_LockTextureHandle: Attempt to lock a lightmap texture."); + return GE_FALSE; + } + + THandle->Flags |= THANDLE_LOCKED; // This texture is now locked + + Size = THandle->LogSize*THandle->LogSize; + + if (THandle->PixelFormat.PixelFormat == GE_PIXELFORMAT_8BIT) + { + pData8 = (uint8*)THandle->Data; + + for (i=0; i>=2; + } + + *Data = pData8; + } + else + { + pData = (uint16*)THandle->Data; + + for (i=0; i>=2; + } + + *Data = pData; + } + + return GE_TRUE; +} + +//================================================================================== +// GTHandle_UnLock +//================================================================================== +geBoolean DRIVERCC GTHandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel) +{ + #pragma message ("FIXME: Flags needs to be per-mip!!!") + + //if (!(THandle->Flags & THANDLE_LOCKED)) + // return GE_FALSE; + + THandle->Flags &= ~THANDLE_LOCKED; // This handle is now unlocked + THandle->Flags |= THANDLE_UPDATE; // Mark it for updating... + + return GE_TRUE; +} + +//================================================================================== +// GThandle_SetPal +//================================================================================== +geBoolean DRIVERCC GThandle_SetPal(geRDriver_THandle *THandle, geRDriver_THandle *PalHandle) +{ + assert(PalHandle->PixelFormat.PixelFormat == THANDLE_PALETTE_FORMAT); + assert(PalHandle->PixelFormat.Flags & RDRIVER_PF_PALETTE); + assert(PalHandle->Width = 256); + assert(PalHandle->LogSize = 256); + assert(PalHandle->Height = 1); + + THandle->PalHandle = PalHandle; + + return GE_TRUE; +} + +//================================================================================== +// GThandle_GetPal +//================================================================================== +geRDriver_THandle *DRIVERCC GThandle_GetPal(geRDriver_THandle *THandle) +{ + return THandle->PalHandle; +} + +//================================================================================== +// GTHandle_GetInfo +//================================================================================== +geBoolean DRIVERCC GTHandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info) +{ + Info->Width = THandle->Width>>MipLevel; + Info->Height = THandle->Height>>MipLevel; + Info->Stride = THandle->LogSize>>MipLevel; + Info->PixelFormat = THandle->PixelFormat; + + if (THandle->PixelFormat.Flags & RDRIVER_PF_CAN_DO_COLORKEY) + { + // Color keys are allways on for surfaces that support it for now... + Info->Flags = RDRIVER_THANDLE_HAS_COLORKEY; // Color keys are allways on for surfaces that support it for now... + + if (THandle->PixelFormat.Flags & RDRIVER_PF_PALETTE) + Info->ColorKey = (1<<16); + else + Info->ColorKey = 1; + } + else + { + Info->Flags = 0; + Info->ColorKey = 0; + } + + return GE_TRUE; +} + +//================================================================================== +// GTHandle_CheckTextures +//================================================================================== +geBoolean GTHandle_CheckTextures(void) +{ + int32 i; + geRDriver_THandle *pTHandle; + + if (!TexturesChanged) + return GE_TRUE; + + if (!GCache_AdjustSlots(TextureCache)) + { + SetLastDrvError(DRV_ERROR_INVALID_REGISTER_MODE, "GTHandle_CheckTextures: GCache_AdjustSlots for textures."); + return GE_FALSE; + } + + if (!GCache_AdjustSlots(LMapCache)) + { + SetLastDrvError(DRV_ERROR_INVALID_REGISTER_MODE, "GTHandle_CheckTextures: GCache_AdjustSlots for lightmaps."); + return GE_FALSE; + } + + // Make sure no THandles reference any slots, because they mave have been moved around, or gotten destroyed... + // (Evict all textures in the cache) + pTHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pTHandle++) + pTHandle->Slot = NULL; + + // Reset the tedxture handle changed boolean + TexturesChanged = GE_FALSE; + + return GE_TRUE; +} + +//********************************************************************************** +// Return the LOD of a mip-map +//********************************************************************************** +geBoolean GetLod(S32 Width, GrLOD_t *Lod) +{ + if (Width == 1) + *Lod = GR_LOD_1; + else if (Width == 2) + *Lod = GR_LOD_2; + else if (Width == 4) + *Lod = GR_LOD_4; + else if (Width == 8) + *Lod = GR_LOD_8; + else if (Width == 16) + *Lod = GR_LOD_16; + else if (Width == 32) + *Lod = GR_LOD_32; + else if (Width == 64) + *Lod = GR_LOD_64; + else if (Width == 128) + *Lod = GR_LOD_128; + else if (Width == 256) + *Lod = GR_LOD_256; + else + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_GetLod: Invalid texture width."); + return GE_FALSE; + } + + return GE_TRUE; +} + +//********************************************************************************** +// Returns the aspect ratio of a texture mip-map +//********************************************************************************** +geBoolean GetAspectRatio(int32 Width, int32 Height, GrAspectRatio_t *Aspect) +{ + int Aspect2; + + Aspect2 = ( 8 * Width ) / Height; + + switch( Aspect2) + { + case 64: + *Aspect = GR_ASPECT_8x1; + break; + case 32: + *Aspect = GR_ASPECT_4x1; + break; + case 16: + *Aspect = GR_ASPECT_2x1; + break; + case 8: + *Aspect = GR_ASPECT_1x1; + break; + case 4: + *Aspect = GR_ASPECT_1x2; + break; + case 2: + *Aspect = GR_ASPECT_1x4; + break; + case 1: + *Aspect = GR_ASPECT_1x8; + break; + + default: + return GE_FALSE; + } + + return GE_TRUE; +} + +//********************************************************************************** +// Returns the log of a number (number must be a power of 2) +//********************************************************************************** +uint32 GetLog(uint32 P2) +{ + U32 p = 0; + S32 i = 0; + + for (i = P2; i > 0; i>>=1) + p++; + + return (p-1); +} + +//********************************************************************************** +// Snaps a number to a power of 2 +//********************************************************************************** +int32 SnapToPower2(int32 Width) +{ +int RetWidth; + // CB : I couldn't stand that big branch of if's ! + for ( RetWidth = 1; RetWidth < Width; RetWidth <<= 1 ) ; + assert( RetWidth <= 256 ); +return RetWidth; +} + + diff --git a/G3D/Engine/Drivers/GlideDrv/GlideDrv.c b/G3D/Engine/Drivers/GlideDrv/GlideDrv.c new file mode 100644 index 0000000..e780a93 --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GlideDrv.c @@ -0,0 +1,299 @@ +/****************************************************************************************/ +/* GlideDrv.c */ +/* */ +/* Author: John Pollard */ +/* Description: Distributes work to other modules. This is the main GlideDrv file. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "DCommon.h" +#include "GlideDrv.h" +#include "GMain.h" +#include "Glide.h" +#include "GTHandle.h" +#include "Render.h" + +int32 LastError; +char LastErrorStr[255]; + +static geFloat CurrentGamma; + +DRV_EngineSettings EngineSettings; +#define ENABLE_WIREFRAME + +//================================================================================================ +//================================================================================================ +geBoolean DRIVERCC DrvInit(DRV_DriverHook *Hook) +{ + #ifdef ENABLE_WIREFRAME + { + // reset key states (compensate for windows bug) + uint32 KeyState1, KeyState2; + #pragma message("Glide : WireFrame enabled!") + KeyState1 = GetAsyncKeyState(VK_CONTROL); + KeyState2 = GetAsyncKeyState(VK_F8); + } + #endif + + return GMain_Startup(Hook); +} + +//================================================================================================ +//================================================================================================ +geBoolean DRIVERCC DrvShutdown(void) +{ + GMain_Shutdown(); + + return TRUE; +} + +//================================================================================================ +//================================================================================================ +geBoolean DRIVERCC DrvResetAll(void) +{ + return GMain_ResetAll(); +} + +//================================================================================================ +//================================================================================================ +geBoolean DRIVERCC SetGamma(geFloat Gamma) +{ + CurrentGamma = Gamma; + + //grGammaCorrectionValue(CurrentGamma); + return TRUE; +} + +//================================================================================================ +//================================================================================================ +geBoolean DRIVERCC GetGamma(geFloat *Gamma) +{ + //*Gamma = CurrentGamma; + *Gamma = 1.0f; + + return TRUE; +} + +//================================================================================================ +//================================================================================================ +geBoolean DRIVERCC EnumModes(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context) +{ + //if (!GMain_GetBoardInfo(&g_BoardInfo)) + // return GE_TRUE; + + if (g_BoardInfo.MainRam == 0) + return GE_TRUE; // No modes + + if (g_BoardInfo.MainRam >= 1) + { + if (!Cb(0, "512x384", 512, 384, Context)) + return GE_TRUE; + } + + if (g_BoardInfo.MainRam >= 2) + { + if (!Cb(1, "640x480", 640, 480, Context)) + return GE_TRUE; + } + + if (g_BoardInfo.MainRam >= 4) + { + if (!Cb(2, "800x600", 800, 600, Context)) + return GE_TRUE; + } + + if (g_BoardInfo.MainRam > 4) + { + if (!Cb(3, "1024x768", 1024, 768, Context)) + return GE_TRUE; + } + + return GE_TRUE; +} + +//================================================================================================ +//================================================================================================ +geBoolean DRIVERCC EnumSubDrivers(DRV_ENUM_DRV_CB *Cb, void *Context) +{ + // Initialize the Glide library + grGlideInit(); + + // Get the info about this board + if (!GMain_GetBoardInfo(&g_BoardInfo)) + return GE_TRUE; + + if (g_BoardInfo.MainRam == 0) + return GE_TRUE; // No modes, so don't return any drivers + + if (!Cb(0, "Glide Driver v"DRV_VMAJS"."DRV_VMINS".", Context)) + return GE_TRUE; + + // Shutdown Glide library + grGlideShutdown(); + + return GE_TRUE; +} + +geRDriver_PixelFormat PixelFormats[] = +{ + {GE_PIXELFORMAT_8BIT , RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP}, + {GE_PIXELFORMAT_16BIT_4444_ARGB , RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP}, + {GE_PIXELFORMAT_16BIT_565_RGB , RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP}, + {GE_PIXELFORMAT_8BIT , RDRIVER_PF_3D}, + {GE_PIXELFORMAT_16BIT_565_RGB , RDRIVER_PF_2D | RDRIVER_PF_CAN_DO_COLORKEY}, + {GE_PIXELFORMAT_16BIT_565_RGB , RDRIVER_PF_LIGHTMAP}, + {THANDLE_PALETTE_FORMAT , RDRIVER_PF_PALETTE}, + {GE_PIXELFORMAT_16BIT_1555_ARGB , RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP}, +}; + +#define NUM_PIXEL_FORMATS (sizeof(PixelFormats)/sizeof(geRDriver_PixelFormat)) + +//================================================================================================ +//================================================================================================ +geBoolean DRIVERCC EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context) +{ + int32 i; + + // Then hand them off to the caller + for (i=0; i +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GlideDrv - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GlideDrv.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GlideDrv.mak" CFG="GlideDrv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GlideDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GlideDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Source/Engine/Drivers/GlideDrv", CVPBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GlideDrv - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GLIDEDRV_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /X /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\..\Sdk\Glide\Include" /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GLIDEDRV_EXPORTS" /D "__MSC__" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 /nologo /dll /machine:I386 /nodefaultlib + +!ELSEIF "$(CFG)" == "GlideDrv - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GLIDEDRV_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /X /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\..\Sdk\Glide\Include" /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GLIDEDRV_EXPORTS" /D "__MSC__" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "GlideDrv - Win32 Release" +# Name "GlideDrv - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\Bmp.c +# End Source File +# Begin Source File + +SOURCE=..\Dcommon.h +# End Source File +# Begin Source File + +SOURCE=.\GCache.c +# End Source File +# Begin Source File + +SOURCE=.\GCache.h +# End Source File +# Begin Source File + +SOURCE=.\GlideDrv.c +# End Source File +# Begin Source File + +SOURCE=.\Glidedrv.h +# End Source File +# Begin Source File + +SOURCE=.\GMain.c +# End Source File +# Begin Source File + +SOURCE=.\GMain.h +# End Source File +# Begin Source File + +SOURCE=.\GMemMgr.c +# End Source File +# Begin Source File + +SOURCE=.\GMemMgr.h +# End Source File +# Begin Source File + +SOURCE=.\GSpan.cpp +# End Source File +# Begin Source File + +SOURCE=.\GSpan.h +# End Source File +# Begin Source File + +SOURCE=.\GThandle.c +# End Source File +# Begin Source File + +SOURCE=.\GTHandle.h +# End Source File +# Begin Source File + +SOURCE=.\Render.c +# End Source File +# Begin Source File + +SOURCE=.\Render.h +# End Source File +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\Sdk\Glide\Lib\glide2x.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Libcmt.lib + +!IF "$(CFG)" == "GlideDrv - Win32 Release" + +!ELSEIF "$(CFG)" == "GlideDrv - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Libcmtd.lib + +!IF "$(CFG)" == "GlideDrv - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "GlideDrv - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Winspool.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Uuid.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Comdlg32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Gdi32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Kernel32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Oldnames.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Shell32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\User32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Advapi32.lib +# End Source File +# End Group +# End Target +# End Project diff --git a/G3D/Engine/Drivers/GlideDrv/GlideDrv.dsw b/G3D/Engine/Drivers/GlideDrv/GlideDrv.dsw new file mode 100644 index 0000000..5b1db9a --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GlideDrv.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "GlideDrv"=.\GlideDrv.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/G3D/Engine/Drivers/GlideDrv/GlideDrv.mak b/G3D/Engine/Drivers/GlideDrv/GlideDrv.mak new file mode 100644 index 0000000..d7eb271 --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/GlideDrv.mak @@ -0,0 +1,245 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on GlideDrv.dsp +!IF "$(CFG)" == "" +CFG=GlideDrv - Win32 Debug +!MESSAGE No configuration specified. Defaulting to GlideDrv - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "GlideDrv - Win32 Release" && "$(CFG)" != "GlideDrv - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GlideDrv.mak" CFG="GlideDrv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GlideDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GlideDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GlideDrv - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +ALL : "$(OUTDIR)\GlideDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\Bmp.obj" + -@erase "$(INTDIR)\GCache.obj" + -@erase "$(INTDIR)\GlideDrv.obj" + -@erase "$(INTDIR)\GMain.obj" + -@erase "$(INTDIR)\GMemMgr.obj" + -@erase "$(INTDIR)\GSpan.obj" + -@erase "$(INTDIR)\GThandle.obj" + -@erase "$(INTDIR)\Render.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\GlideDrv.dll" + -@erase "$(OUTDIR)\GlideDrv.exp" + -@erase "$(OUTDIR)\GlideDrv.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MT /W3 /GX /O2 /X /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\..\Sdk\Glide\Include" /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GLIDEDRV_EXPORTS" /D "__MSC__" /Fp"$(INTDIR)\GlideDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\GlideDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:no /pdb:"$(OUTDIR)\GlideDrv.pdb" /machine:I386 /nodefaultlib /out:"$(OUTDIR)\GlideDrv.dll" /implib:"$(OUTDIR)\GlideDrv.lib" +LINK32_OBJS= \ + "$(INTDIR)\Bmp.obj" \ + "$(INTDIR)\GCache.obj" \ + "$(INTDIR)\GlideDrv.obj" \ + "$(INTDIR)\GMain.obj" \ + "$(INTDIR)\GMemMgr.obj" \ + "$(INTDIR)\GSpan.obj" \ + "$(INTDIR)\GThandle.obj" \ + "$(INTDIR)\Render.obj" \ + "..\..\..\..\Sdk\Glide\Lib\glide2x.lib" \ + "..\..\..\..\MSDev60\lib\Libcmt.lib" \ + "..\..\..\..\MSDev60\lib\Winspool.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" + +"$(OUTDIR)\GlideDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "GlideDrv - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\GlideDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\Bmp.obj" + -@erase "$(INTDIR)\GCache.obj" + -@erase "$(INTDIR)\GlideDrv.obj" + -@erase "$(INTDIR)\GMain.obj" + -@erase "$(INTDIR)\GMemMgr.obj" + -@erase "$(INTDIR)\GSpan.obj" + -@erase "$(INTDIR)\GThandle.obj" + -@erase "$(INTDIR)\Render.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\GlideDrv.dll" + -@erase "$(OUTDIR)\GlideDrv.exp" + -@erase "$(OUTDIR)\GlideDrv.ilk" + -@erase "$(OUTDIR)\GlideDrv.lib" + -@erase "$(OUTDIR)\GlideDrv.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /X /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\..\Sdk\Glide\Include" /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GLIDEDRV_EXPORTS" /D "__MSC__" /Fp"$(INTDIR)\GlideDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\GlideDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:yes /pdb:"$(OUTDIR)\GlideDrv.pdb" /debug /machine:I386 /nodefaultlib /out:"$(OUTDIR)\GlideDrv.dll" /implib:"$(OUTDIR)\GlideDrv.lib" /pdbtype:sept +LINK32_OBJS= \ + "$(INTDIR)\Bmp.obj" \ + "$(INTDIR)\GCache.obj" \ + "$(INTDIR)\GlideDrv.obj" \ + "$(INTDIR)\GMain.obj" \ + "$(INTDIR)\GMemMgr.obj" \ + "$(INTDIR)\GSpan.obj" \ + "$(INTDIR)\GThandle.obj" \ + "$(INTDIR)\Render.obj" \ + "..\..\..\..\Sdk\Glide\Lib\glide2x.lib" \ + "..\..\..\..\MSDev60\lib\Libcmtd.lib" \ + "..\..\..\..\MSDev60\lib\Winspool.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" + +"$(OUTDIR)\GlideDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("GlideDrv.dep") +!INCLUDE "GlideDrv.dep" +!ELSE +!MESSAGE Warning: cannot find "GlideDrv.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "GlideDrv - Win32 Release" || "$(CFG)" == "GlideDrv - Win32 Debug" +SOURCE=..\Bmp.c + +"$(INTDIR)\Bmp.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\GCache.c + +"$(INTDIR)\GCache.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\GlideDrv.c + +"$(INTDIR)\GlideDrv.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\GMain.c + +"$(INTDIR)\GMain.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\GMemMgr.c + +"$(INTDIR)\GMemMgr.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\GSpan.cpp + +"$(INTDIR)\GSpan.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\GThandle.c + +"$(INTDIR)\GThandle.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Render.c + +"$(INTDIR)\Render.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/G3D/Engine/Drivers/GlideDrv/GlideDrv.ncb b/G3D/Engine/Drivers/GlideDrv/GlideDrv.ncb new file mode 100644 index 0000000000000000000000000000000000000000..44d5199feff33793929a766182d3e6bb47fdbf58 GIT binary patch literal 107520 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
+

Build Log

+

+--------------------Configuration: D3DDrv - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\WINDOWS\TEMP\RSP2390.TMP" with contents +[ +/nologo /G5 /MT /W3 /GX /Ox /Ot /Ow /Og /Oi /Op /Ob2 /I "..\..\.." /I "..\\" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\Math" /I "..\..\..\Bitmap" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /Fo"Release/" /Fd"Release/" /FD /c +"D:\Release\G3D\Engine\Drivers\WireFrame\D3d_main.cpp" +] +Creating command line "cl.exe @C:\WINDOWS\TEMP\RSP2390.TMP" +Creating temporary file "C:\WINDOWS\TEMP\RSP2391.TMP" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib vfw32.lib dxguid.lib ddraw.lib d3dim.lib /nologo /dll /incremental:no /pdb:"Release/WireDrv.pdb" /machine:I386 /out:"Release/WireDrv.dll" /implib:"Release/WireDrv.lib" +.\Release\D3d_err.obj +.\Release\D3d_fx.obj +.\Release\D3d_main.obj +.\Release\D3dcache.obj +.\Release\D3ddrv.obj +.\Release\DDMemMgr.obj +.\Release\Gspan.obj +.\Release\Pcache.obj +.\Release\Render.obj +.\Release\Scene.obj +.\Release\THandle.obj +.\Release\tpage.obj +] +Creating command line "link.exe @C:\WINDOWS\TEMP\RSP2391.TMP" +

Output Window

+Compiling... +D3d_main.cpp +Linking... + Creating library Release/WireDrv.lib and object Release/WireDrv.exp + + + +

Results

+WireDrv.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/G3D/Engine/Drivers/WireFrame/D3d_err.cpp b/G3D/Engine/Drivers/WireFrame/D3d_err.cpp new file mode 100644 index 0000000..378c1fc --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3d_err.cpp @@ -0,0 +1,271 @@ +/****************************************************************************************/ +/* D3D_Err.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D Error code conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "D3D_Err.h" + +//================================================================================ +// D3DErrorToString +//================================================================================ +char *D3DErrorToString(HRESULT error) +{ + switch(error) { + case DD_OK: + return "No error.\0"; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized.\0"; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0"; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface.\0"; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface.\0"; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs.\0"; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0"; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0"; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation.\0"; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available.\0"; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process.\0"; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation.\0"; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive.\0"; + case DDERR_GENERIC: + return "Generic failure.\0"; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment.\0"; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created.\0"; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state.\0"; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface.\0"; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface.\0"; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect.\0"; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist.\0"; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0"; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode.\0"; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0"; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect.\0"; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified.\0"; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0"; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid.\0"; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked.\0"; + case DDERR_NO3D: + return "There is no 3D present.\0"; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0"; + case DDERR_NOBLTHW: + return "No blitter hardware present.\0"; + case DDERR_NOCLIPLIST: + return "No cliplist available.\0"; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object.\0"; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or available.\0"; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key\0"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color key.\0"; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0"; + case DDERR_NODC: + return "No DC was ever created for this surface.\0"; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware.\0"; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0"; + case DDERR_NOEMULATION: + return "Software emulation not available.\0"; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive mode.\0"; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported.\0"; + case DDERR_NOGDI: + return "There is no GDI present.\0"; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0"; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available.\0"; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination.\0"; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available.\0"; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface.\0"; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes.\0"; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0"; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available.\0"; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching.\0"; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0"; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0"; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0"; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface.\0"; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable.\0"; + case DDERR_NOTFOUND: + return "Requested item was not found.\0"; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, has been attempted.\0"; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface.\0"; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations.\0"; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0"; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated.\0"; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough video memory to perform the operation.\0"; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays.\0"; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays.\0"; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread.\0"; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface.\0"; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small.\0"; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to.\0"; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of.\0"; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread.\0"; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured.\0"; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.\0"; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached.\0"; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large.\0"; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large.\0"; + case DDERR_UNSUPPORTED: + return "Action not supported.\0"; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw.\0"; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress.\0"; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete.\0"; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode.\0"; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary.\0"; + case D3DERR_BADMAJORVERSION: + return "D3DERR_BADMAJORVERSION\0"; + case D3DERR_BADMINORVERSION: + return "D3DERR_BADMINORVERSION\0"; + case D3DERR_EXECUTE_LOCKED: + return "D3DERR_EXECUTE_LOCKED\0"; + case D3DERR_EXECUTE_NOT_LOCKED: + return "D3DERR_EXECUTE_NOT_LOCKED\0"; + case D3DERR_EXECUTE_CREATE_FAILED: + return "D3DERR_EXECUTE_CREATE_FAILED\0"; + case D3DERR_EXECUTE_DESTROY_FAILED: + return "D3DERR_EXECUTE_DESTROY_FAILED\0"; + case D3DERR_EXECUTE_LOCK_FAILED: + return "D3DERR_EXECUTE_LOCK_FAILED\0"; + case D3DERR_EXECUTE_UNLOCK_FAILED: + return "DDERR_EXECUTE_UNLOCK_FAILED\0"; + case D3DERR_EXECUTE_FAILED: + return "D3DERR_EXECUTE_FAILED\0"; + case D3DERR_EXECUTE_CLIPPED_FAILED: + return "D3DERR_EXECUTE_CLIPPED_FAILED\0"; + case D3DERR_TEXTURE_NO_SUPPORT: + return "D3DERR_TEXTURE_NO_SUPPORT\0"; + case D3DERR_TEXTURE_NOT_LOCKED: + return "D3DERR_TEXTURE_NOT_LOCKED\0"; + case D3DERR_TEXTURE_LOCKED: + return "D3DERR_TEXTURELOCKED\0"; + case D3DERR_TEXTURE_CREATE_FAILED: + return "D3DERR_TEXTURE_CREATE_FAILED\0"; + case D3DERR_TEXTURE_DESTROY_FAILED: + return "D3DERR_TEXTURE_DESTROY_FAILED\0"; + case D3DERR_TEXTURE_LOCK_FAILED: + return "D3DERR_TEXTURE_LOCK_FAILED\0"; + case D3DERR_TEXTURE_UNLOCK_FAILED: + return "D3DERR_TEXTURE_UNLOCK_FAILED\0"; + case D3DERR_TEXTURE_LOAD_FAILED: + return "D3DERR_TEXTURE_LOAD_FAILED\0"; + case D3DERR_MATRIX_CREATE_FAILED: + return "D3DERR_MATRIX_CREATE_FAILED\0"; + case D3DERR_MATRIX_DESTROY_FAILED: + return "D3DERR_MATRIX_DESTROY_FAILED\0"; + case D3DERR_MATRIX_SETDATA_FAILED: + return "D3DERR_MATRIX_SETDATA_FAILED\0"; + case D3DERR_SETVIEWPORTDATA_FAILED: + return "D3DERR_SETVIEWPORTDATA_FAILED\0"; + case D3DERR_MATERIAL_CREATE_FAILED: + return "D3DERR_MATERIAL_CREATE_FAILED\0"; + case D3DERR_MATERIAL_DESTROY_FAILED: + return "D3DERR_MATERIAL_DESTROY_FAILED\0"; + case D3DERR_MATERIAL_SETDATA_FAILED: + return "D3DERR_MATERIAL_SETDATA_FAILED\0"; + case D3DERR_LIGHT_SET_FAILED: + return "D3DERR_LIGHT_SET_FAILED\0"; + default: + return "Unrecognized error value.\0"; + } +} diff --git a/G3D/Engine/Drivers/WireFrame/D3d_err.h b/G3D/Engine/Drivers/WireFrame/D3d_err.h new file mode 100644 index 0000000..bc65c56 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3d_err.h @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* D3D_Err.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D Error code conversions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_ERR_H +#define D3D_ERR_H + +#include +#include +#include + +//================================================================================ +// Global functions +//================================================================================ +char *D3DErrorToString(HRESULT error); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/WireFrame/D3d_fx.cpp b/G3D/Engine/Drivers/WireFrame/D3d_fx.cpp new file mode 100644 index 0000000..73fd6a0 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3d_fx.cpp @@ -0,0 +1,211 @@ +/****************************************************************************************/ +/* D3D_Fx.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D renderstate wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" +#include "Render.h" +#include "Scene.h" +#include "D3D_FX.h" +#include "D3D_Main.h" +#include "D3D_Err.h" + +static D3DTEXTUREHANDLE OldTexHandle = NULL; + +//====================================================================================================== +//====================================================================================================== +void D3DSetTexHandle(D3DTEXTUREHANDLE TexHandle) +{ + if (TexHandle == OldTexHandle) + return; + + OldTexHandle = TexHandle; + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, TexHandle); +} + +static LPDIRECT3DTEXTURE2 OldTexture[8]; + +//====================================================================================================== +//====================================================================================================== +void D3DSetTexture(int32 Stage, LPDIRECT3DTEXTURE2 Texture) +{ + if (Texture == OldTexture[Stage]) + return; + + OldTexture[Stage] = Texture; + + AppInfo.lpD3DDevice->SetTexture(Stage, Texture); +} + +//====================================================================================================== +//====================================================================================================== +void D3DBilinearFilter(D3DTEXTUREFILTER Min, D3DTEXTUREFILTER Mag) +{ + AppInfo.lpD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR); + AppInfo.lpD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + + if (AppInfo.CanDoMultiTexture) + { + AppInfo.lpD3DDevice->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFN_LINEAR); + AppInfo.lpD3DDevice->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + } +} + +//====================================================================================================== +// Old one uses D3DTLVERTEX vertex format +//====================================================================================================== +void D3DTexturedPolyOld(void *Pnts, int32 NumPoints) +{ + AppInfo.lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_TLVERTEX, Pnts, NumPoints, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT | D3DDP_DONOTCLIP); +} + +//====================================================================================================== +// D3DTexturedPoly +//====================================================================================================== +void D3DTexturedPoly(void *Pnts, int32 NumPoints) +{ + AppInfo.lpD3DDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, + //D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2, + Pnts, + NumPoints, + D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT | D3DDP_DONOTCLIP); + //D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTCLIP); +} + +//====================================================================================================== +// D3DViewport +//====================================================================================================== +void D3DViewport (int32 x, int32 y, int32 width, int32 height) +{ + D3DVIEWPORT2 vport; + + return; + + vport.dwSize = sizeof(D3DVIEWPORT2); + AppInfo.lpD3DViewport->GetViewport2(&vport); + vport.dwX = x; + vport.dwY = AppInfo.OldHeight - (y + height); + vport.dwWidth = width; + vport.dwHeight = height; + vport.dvClipX = -1.0f; + vport.dvClipY = 1.0f; + vport.dvClipWidth = (geFloat)width /2.0f; + vport.dvClipHeight = (geFloat)height/2.0f; + AppInfo.lpD3DViewport->SetViewport2(&vport); +} + +//====================================================================================================== +//====================================================================================================== +void D3DDepthRange (geFloat zNear, geFloat zFar) +{ + D3DVIEWPORT2 vport; + vport.dwSize = sizeof(D3DVIEWPORT2); + AppInfo.lpD3DViewport->GetViewport2(&vport); + vport.dvMinZ = (D3DVALUE)(((-1.0) * (zFar + zNear)) / (zFar - zNear)); + vport.dvMaxZ = (D3DVALUE)(((-1.0) * (zFar + zNear - 2.0)) / (zFar - zNear)); + AppInfo.lpD3DViewport->SetViewport2(&vport); +} + +static D3DBLEND OldSFunc = D3DBLEND_ONE; +static D3DBLEND OldDFunc = D3DBLEND_ONE; + +//====================================================================================================== +//====================================================================================================== +void D3DBlendFunc (D3DBLEND SFunc, D3DBLEND DFunc) +{ + if (SFunc != OldSFunc) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, SFunc); + OldSFunc = SFunc; + } + if (DFunc != OldDFunc) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, DFunc); + OldDFunc = DFunc; + } + +} + +static BOOL OldBlend = FALSE; + +//====================================================================================================== +//====================================================================================================== +void D3DBlendEnable(BOOL Enable) +{ + if (OldBlend == Enable) + return; + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, Enable); + + OldBlend = Enable; +} + +static BOOL OldWrap = FALSE; + +void D3DTexWrap(DWORD Stage, BOOL Wrap) +{ + if (OldWrap == Wrap) + return; + + OldWrap = Wrap; + + if (Wrap) + { + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); + } + else + { + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); + AppInfo.lpD3DDevice->SetTextureStageState(Stage, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); + } +} + +void D3DZWriteEnable (BOOL Enable) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, Enable); +} + +void D3DZFunc (D3DCMPFUNC Func) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, Func); +} + +void D3DZEnable(BOOL Enable) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, Enable); +} + +void D3DPolygonMode (D3DFILLMODE Mode) +{ + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, Mode); +} + + + diff --git a/G3D/Engine/Drivers/WireFrame/D3d_fx.h b/G3D/Engine/Drivers/WireFrame/D3d_fx.h new file mode 100644 index 0000000..939ea7c --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3d_fx.h @@ -0,0 +1,53 @@ +/****************************************************************************************/ +/* D3D_Fx.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D renderstate wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_FX_H +#define D3D_FX_H + +#include +#include +#include + +#include "D3D_Main.h" +#include "DCommon.h" + +void D3DSetTexHandle(D3DTEXTUREHANDLE TexHandle); +void D3DSetTexture(int32 Stage, LPDIRECT3DTEXTURE2 Texture); +void D3DTexturedPolyOld(void *Pnts, int32 NumPoints); +void D3DTexturedPoly(void *Pnts, int32 NumPoints); + +void D3DBilinearFilter(D3DTEXTUREFILTER Min, D3DTEXTUREFILTER Mag); +void D3DBlendEnable(BOOL Enable); + +void D3DBlendFunc (D3DBLEND SFunc, D3DBLEND DFunc); + +void D3DZWriteEnable (BOOL Enable); +void D3DZFunc (D3DCMPFUNC Func); +void D3DZEnable(BOOL Enable); + +void D3DTexWrap(DWORD Stage, BOOL Wrap); + +void D3DPolygonMode (D3DFILLMODE Mode); + +void D3DViewport (int32 x, int32 y, int32 width, int32 height); +void D3DDepthRange (geFloat zNear, geFloat zFar); + +#endif diff --git a/G3D/Engine/Drivers/WireFrame/D3d_main.cpp b/G3D/Engine/Drivers/WireFrame/D3d_main.cpp new file mode 100644 index 0000000..93791d1 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3d_main.cpp @@ -0,0 +1,2749 @@ +/****************************************************************************************/ +/* D3D_Main.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: DD/D3D wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "D3D_Main.h" +#include "D3D_Err.h" +#include "D3D_fx.h" +#include "d3dcache.h" + +#include "Render.h" +#include "D3DCache.h" +#include "THandle.h" +#include "PCache.h" + +#undef ATTEMPT +#define ATTEMPT(x) if (!(x)) goto exit_with_error + +#undef RELEASE +#define RELEASE(x) if (x) { x->Release(); x = NULL; } + +static BOOL bInitDone =FALSE; +#ifdef STRICT +WNDPROC pOldWndProc; +#else +FARPROC pOldWndProc; +#endif + +//================================================================================ +// Globals +//================================================================================ +App_Info AppInfo; // Our global structure that knows all... (once initialized) + +#define MAX_DRIVERS 64 + +typedef struct +{ + geBoolean IsPrimary; + GUID Guid; + char Name[MAX_DRIVER_NAME]; +} D3D_DRIVER; + +typedef struct +{ + int32 NumDrivers; + D3D_DRIVER *Drivers; +} DDEnumInfo; + +//================================================================================ +// Local static functions +//================================================================================ +static BOOL D3DMain_CreateD3D(void); +static BOOL D3DMain_EnumDevices(void); +static BOOL D3DMain_CreateViewPort(int w, int h); +static BOOL D3DMain_ClearBuffers(void); +static BOOL OutputDriverInfo(const char *Filename, DDMain_D3DDriver *Driver); +static BOOL D3DMain_RememberOldMode(HWND hWnd); +static BOOL D3DMain_SetDisplayMode(HWND hWnd, int w, int h, int bpp, BOOL FullScreen); +static BOOL D3DMain_PickDevice(void); +static BOOL D3DMain_CreateDevice(void); +static BOOL D3DMain_CreateBuffers(void); +static void D3DMain_DestroyBuffers(void); +static BOOL D3DMain_CreateZBuffer(void); +static void D3DMain_DestroyZBuffer(void); +static BOOL D3DMain_RestoreDisplayMode(void); +static BOOL D3DMain_CreateDDFromName(const char *DriverName); +static geBoolean CreateDDFromDriver(D3D_DRIVER *pDriver); +static geBoolean CreateDDFromName(const char *DriverName, const DDEnumInfo *Info); + +BOOL D3DMain_RestoreAllSurfaces(void) +{ + HRESULT ddrval; + +#ifdef _DEBUG + OutputDebugString("--- D3DMain_RestoreAllSurfaces ---\n"); +#endif + + if (AppInfo.lpDD) + { + if (!D3DMain_SetDisplayMode(AppInfo.hWnd, AppInfo.CurrentWidth, AppInfo.CurrentHeight, AppInfo.CurrentBpp, AppInfo.FullScreen)) + return FALSE; + + // Restore all the surfaces + ddrval = AppInfo.lpDD->RestoreAllSurfaces(); + + if(ddrval!=DD_OK) + { + D3DMain_Log("D3DMain_RestoreAllSurfaces: AppInfo.lpDD->RestoreAllSurfaces() failed:\n %s\n", D3DErrorToString(ddrval)); + return FALSE; + } + } + + // Force an update in the cache system + if (TextureCache) + if (!D3DCache_EvictAllSurfaces(TextureCache)) + return FALSE; + + if (LMapCache) + if (!D3DCache_EvictAllSurfaces(LMapCache)) + return FALSE; + + return TRUE; +} + +//================================================================================ +// BPPToDDBD +// Convert an integer bit per pixel number to a DirectDraw bit depth flag +//================================================================================ +static DWORD BPPToDDBD(int bpp) +{ + switch(bpp) + { + case 1: + return DDBD_1; + case 2: + return DDBD_2; + case 4: + return DDBD_4; + case 8: + return DDBD_8; + case 16: + return DDBD_16; + case 24: + return DDBD_24; + case 32: + return DDBD_32; + default: + assert(!"BOGUS bpp"); + } + + return DDBD_1; // Shutup compiler warning +} + +//================================================================================ +// D3DMain_InitD3D +// Does all what is needed to get an app ready to go at a specified with height +// NOTE - It only makes 16 bit modes availible +//================================================================================ +BOOL D3DMain_InitD3D(HWND hWnd, const char *DriverName, int32 Width, int32 Height) +{ + HRESULT LastError; + SYSTEMTIME Time; + + memset(&AppInfo, 0, sizeof(App_Info)); + + GetSystemTime(&Time); + + unlink(D3DMAIN_LOG_FILENAME); + + D3DMain_Log("=================================================================\n"); + D3DMain_Log(" D3DDrv v%i.%i\n", DRV_VERSION_MAJOR, DRV_VERSION_MINOR); + D3DMain_Log(" Build Date: "__DATE__", Time: "__TIME__"\n"); + D3DMain_Log("=================================================================\n\n"); + + D3DMain_Log("Current Time: %2i:%2i:%2i\n", Time.wHour, Time.wMinute, Time.wSecond); + D3DMain_Log("Current Date: %2i-%2i-%4i\n", Time.wMonth, Time.wDay, Time.wYear); + D3DMain_Log("\n ** D3D Driver Initializing **\n\n"); + + AppInfo.hWnd = hWnd; + + // Create DD + ATTEMPT(D3DMain_CreateDDFromName(DriverName)); + + ATTEMPT(D3DMain_GetTextureMemory()); + + // We must do this after the DD object is created!!! + ATTEMPT(D3DMain_RememberOldMode(hWnd)); // Store old mode + + // Get available fullscreen display modes + ATTEMPT(D3DMain_EnumDisplayModes()); + + // Create D3D, and enum it's devices + ATTEMPT(D3DMain_CreateD3D()); + ATTEMPT(D3DMain_EnumDevices()); + + if (Width == -1 && Height == -1) // Window Mode + { + // Force Width/Height to client window area size + Width = AppInfo.OldWindowWidth; + Height = AppInfo.OldWindowHeight; + + ATTEMPT(D3DMain_SetDisplayMode(hWnd, Width, Height, AppInfo.OldBpp, FALSE)); + } + else + { + ATTEMPT(D3DMain_SetDisplayMode(hWnd, Width, Height, 16, TRUE)); + } + + // Pick a device we will be happy with + ATTEMPT(D3DMain_PickDevice()); + + // Create front/back buffer + ATTEMPT(D3DMain_CreateBuffers()); + + // For some reason, we have to create the zbuffer BEFORE the device??? Why??? + ATTEMPT(D3DMain_CreateZBuffer()); + + // Create the device and viewport + ATTEMPT(D3DMain_CreateDevice()); + ATTEMPT(D3DMain_CreateViewPort(Width, Height)); + + // Get the surface formats for textures, and 2d surfaces + ATTEMPT(D3DMain_GetSurfaceFormats()); + +#if 0 // For selective debugging + AppInfo.CanDoMultiTexture = GE_FALSE; +#else + AppInfo.CanDoMultiTexture = (AppInfo.Drivers[AppInfo.CurrentDriver].MaxSimultaneousTextures > 1) ? GE_TRUE : GE_FALSE; +#endif + + D3DMain_Log("--- D3DMain_SetRenderState --- \n"); + + // Set some defaults render states + LastError = AppInfo.lpD3DDevice->BeginScene(); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: BeginScene failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = AppInfo.lpD3DDevice->SetCurrentViewport(AppInfo.lpD3DViewport); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: SetViewport failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + //D3DMain_SetFogEnable(GE_TRUE, 255.0f, 0.0f, 0.0f, 500.0f, 1500.0f); + D3DMain_SetFogEnable(GE_FALSE, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL); + //AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE); + +#if 0 + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_ANTIALIAS, D3DANTIALIAS_SORTINDEPENDENT); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_EDGEANTIALIAS, TRUE); +#endif + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, TRUE); + + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEARMIPNEAREST); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_LINEAR); + + LastError = AppInfo.lpD3DDevice->EndScene(); + + if (LastError != D3D_OK) + { + D3DMain_Log("D3DMain_InitD3D: EndScene failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.RenderingIsOK = TRUE; + + ATTEMPT(D3DMain_ClearBuffers()); + ATTEMPT(D3DMain_GetTextureMemory()); + + if (!THandle_Startup()) + return GE_FALSE; + + D3DViewport (0, 0, Width, Height); + D3DDepthRange (0.0f, 1.0f); + + D3DMain_Log("\n ** Initialization was successful **\n\n"); + + return TRUE; + + exit_with_error:; + D3DMain_Log(" ** Initialization was NOT successful **\n"); + D3DMain_ShutdownD3D(); + return FALSE; +} + +//================================================================================ +// D3DMain_ShutdownD3D +//================================================================================ +BOOL D3DMain_ShutdownD3D(void) +{ + D3DMain_Log("\n--- D3DMain_ShutdownD3D ---\n"); + + THandle_Shutdown(); + + // Destroys all objects including Direct Draw. + AppInfo.RenderingIsOK = FALSE; + + if (AppInfo.lpD3DViewport) + { + assert(AppInfo.lpD3DDevice); + AppInfo.lpD3DDevice->DeleteViewport(AppInfo.lpD3DViewport); + RELEASE(AppInfo.lpD3DViewport); + } + + RELEASE(AppInfo.lpD3DDevice); + + RELEASE(AppInfo.BackgroundMaterial); + + if (AppInfo.lpZBuffer) + { + assert(AppInfo.lpBackBuffer); + AppInfo.lpBackBuffer->DeleteAttachedSurface(0, AppInfo.lpZBuffer); + RELEASE(AppInfo.lpZBuffer); + } + + if (AppInfo.lpFrontBuffer) + AppInfo.lpFrontBuffer->SetClipper(NULL); + + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); + + D3DMain_RestoreDisplayMode(); + + RELEASE(AppInfo.lpD3D); + RELEASE(AppInfo.lpDD); + + memset(&AppInfo, 0, sizeof(App_Info)); + + D3DMain_Log(" Shutdown was successful...\n\n"); + + return TRUE; +} + +extern uint32 CurrentLRU; +//================================================================================ +//================================================================================ +geBoolean D3DMain_Reset(void) +{ + THandle_Shutdown(); + PCache_Reset(); + + if (!THandle_Startup()) + return GE_FALSE; + + CurrentLRU = 0; + + return GE_TRUE; +} + +//================================================================================ +// D3DMain_Log +//================================================================================ +void D3DMain_Log(LPSTR Str, ... ) +{ + char Buffer[2048]; + FILE *f; + + wvsprintf(Buffer, Str, (char*)(&Str+1)); + + f = fopen(D3DMAIN_LOG_FILENAME, "a+t"); + + if (!f) + return; + + fprintf(f, "%s", Buffer); + + fclose(f); +} + +//================================================================================ +// CompareModes +//================================================================================ +static int CompareModes(const void* element1, const void* element2) +{ + App_Mode *lpMode1, *lpMode2; + + lpMode1 = (App_Mode*)element1; + lpMode2 = (App_Mode*)element2; + + if (lpMode1->Bpp > lpMode2->Bpp) + return -1; + else if (lpMode2->Bpp > lpMode1->Bpp) + return 1; + else if (lpMode1->Width > lpMode2->Width) + return -1; + else if (lpMode2->Width > lpMode1->Width) + return 1; + else if (lpMode1->Height > lpMode2->Height) + return -1; + else if (lpMode2->Height > lpMode1->Height) + return 1; + else + return 0; +} + +//================================================================================ +// EnumDisplayModesCallback +//================================================================================ +static HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC2 pddsd, LPVOID lpContext) +{ + App_Mode *pMode; + + if (!pddsd) + return DDENUMRET_OK; + + if (pddsd->dwWidth > 1024 || pddsd->dwHeight > 768) + return DDENUMRET_OK; + + if (AppInfo.NumModes >= MAX_APP_MODES) + return DDENUMRET_CANCEL; + + pMode = &AppInfo.Modes[AppInfo.NumModes++]; + + // Save this mode at the end of the mode array and increment mode count + pMode->Width = pddsd->dwWidth; + pMode->Height = pddsd->dwHeight; + pMode->Bpp = pddsd->ddpfPixelFormat.dwRGBBitCount; + pMode->ThisDriverCanDo = FALSE; + + return DDENUMRET_OK; +} + +//================================================================================ +// D3DMain_EnumDisplayModes +//================================================================================ +BOOL D3DMain_EnumDisplayModes(void) +{ + HRESULT LastError; + + D3DMain_Log("--- D3DMain_EnumDisplayModes ---\n"); + + // Get a list of available display modes from DirectDraw + AppInfo.NumModes = 0; + + LastError = AppInfo.lpDD->EnumDisplayModes(0, NULL, 0, EnumDisplayModesCallback); + + if(LastError != DD_OK ) + { + D3DMain_Log("EnumDisplayModes failed.\n %s\n", D3DErrorToString(LastError)); + AppInfo.NumModes = 0; + return FALSE; + } + + // Sort the list of display modes + qsort((void *)&AppInfo.Modes[0], (size_t)AppInfo.NumModes, sizeof(App_Mode), CompareModes); + + return TRUE; +} + + + +//================================================================================ +// D3DMain_CreateD3D +//================================================================================ +static BOOL D3DMain_CreateD3D(void) +{ + HRESULT LastError; + + assert(AppInfo.lpDD); + + D3DMain_Log("--- D3DMain_CreateD3D ---\n"); + + LastError = AppInfo.lpDD->QueryInterface(IID_IDirect3D3, (LPVOID*)&AppInfo.lpD3D); + + if (LastError != DD_OK) + { + D3DMain_Log("Creation of IDirect3D failed.\n %s\n", D3DErrorToString(LastError)); + goto exit_with_error; + } + + return TRUE; + + exit_with_error: + return FALSE; +} +/* +#define MUST_BLEND (D3DPBLENDCAPS_BOTHINVSRCALPHA | \ + D3DPBLENDCAPS_BOTHSRCALPHA | \ + D3DPBLENDCAPS_DESTALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_INVDESTALPHA | \ + D3DPBLENDCAPS_INVDESTCOLOR | \ + D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_INVSRCCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_SRCALPHASAT | \ + D3DPBLENDCAPS_SRCCOLOR | \ + D3DPBLENDCAPS_ZERO) +*/ +#if 0 +#define MUST_BLEND_SRC (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#define MUST_BLEND_DEST (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_SRCCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#else +#define MUST_BLEND_SRC (D3DPBLENDCAPS_SRCALPHA | \ + D3DPBLENDCAPS_DESTCOLOR | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) + +#define MUST_BLEND_DEST (D3DPBLENDCAPS_INVSRCALPHA | \ + D3DPBLENDCAPS_ONE | \ + D3DPBLENDCAPS_ZERO) +#endif + +//================================================================================ +// EnumDeviceFunc +//================================================================================ +static HRESULT WINAPI EnumDeviceFunc(LPGUID lpGuid, LPSTR lpDeviceDescription, + LPSTR lpDeviceName, LPD3DDEVICEDESC lpHWDesc, + LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext) +{ + DDMain_D3DDriver *Driver; + BOOL Good; + + if (!lpGuid|| !lpDeviceDescription || !lpDeviceName || !lpHWDesc || !lpHELDesc) + return (D3DENUMRET_OK); + + if (strlen(lpDeviceDescription) >= MAX_DRIVER_NAME) + return (D3DENUMRET_OK); + + if (strlen(lpDeviceName) >= MAX_DRIVER_NAME) + return (D3DENUMRET_OK); + + lpContext = lpContext; + + Good = TRUE; + + AppInfo.CurrentDriver = AppInfo.NumDrivers; + + Driver = &AppInfo.Drivers[AppInfo.NumDrivers]; + + // Record the D3D driver's inforamation + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Guid, lpGuid, sizeof(GUID)); + lstrcpy(AppInfo.Drivers[AppInfo.NumDrivers].About, lpDeviceDescription); + lstrcpy(AppInfo.Drivers[AppInfo.NumDrivers].Name, lpDeviceName); + + // Is this a hardware device or software emulation? Checking the color + // model for a valid model works. + if (lpHWDesc->dcmColorModel) + { + AppInfo.Drivers[AppInfo.NumDrivers].IsHardware = TRUE; + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHWDesc, sizeof(D3DDEVICEDESC)); + } + else + { + // Skip if this is not a hardware driver + AppInfo.Drivers[AppInfo.NumDrivers].IsHardware = FALSE; + memcpy(&AppInfo.Drivers[AppInfo.NumDrivers].Desc, lpHELDesc, sizeof(D3DDEVICEDESC)); + Good = FALSE; + } + + LPD3DDEVICEDESC Desc = &AppInfo.Drivers[AppInfo.NumDrivers].Desc; + + Driver->MaxTextureBlendStages = Desc->wMaxTextureBlendStages; + Driver->MaxSimultaneousTextures = Desc->wMaxSimultaneousTextures; + + if (!(Desc->dwDeviceZBufferBitDepth)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesZBuffer = TRUE; + + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesTextures = TRUE; + + // Skip if it does not support alpha blending + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHA)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesAlpha = TRUE; + + if (!(Desc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_TRANSPARENCY)) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesTransparency = TRUE; + + //if (!(lpHWDesc->dpcTriCaps.dwTextureAddressCaps & D3DPTADDRESSCAPS_CLAMP)) + // Good = FALSE; + //else + AppInfo.Drivers[AppInfo.NumDrivers].DoesClamping = TRUE; + + if ((Desc->dpcTriCaps.dwSrcBlendCaps & MUST_BLEND_SRC) != MUST_BLEND_SRC) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesSrcBlending = TRUE; + + if ((Desc->dpcTriCaps.dwDestBlendCaps & MUST_BLEND_DEST) != MUST_BLEND_DEST) + Good = FALSE; + else + AppInfo.Drivers[AppInfo.NumDrivers].DoesDestBlending = TRUE; + + // Stop as soon as we find a driver that can render into a window + if ((Desc->dwDeviceRenderBitDepth & BPPToDDBD(AppInfo.OldBpp)) && AppInfo.IsPrimary && Good) + { + AppInfo.Drivers[AppInfo.NumDrivers].CanDoWindow = TRUE; + AppInfo.CanDoWindow = TRUE; + } + else + AppInfo.Drivers[AppInfo.NumDrivers].CanDoWindow = FALSE; + + // Store if we can use this driver + AppInfo.Drivers[AppInfo.NumDrivers].CanUse = Good; + + #if 0 + if (AppInfo.LogToFile) + OutputDriverInfo(D3DMAIN_LOG_FILENAME, &AppInfo.Drivers[AppInfo.NumDrivers]); + #endif + + if (!Good) + return (D3DENUMRET_OK); + + // Tell global structure that we found a good device + AppInfo.FoundGoodDevice = TRUE; + + // If all was good, increment the number of drivers + AppInfo.NumDrivers++; + + if (AppInfo.NumDrivers+1 >= DDMAIN_MAX_D3D_DRIVERS) + return (D3DENUMRET_CANCEL); + + return (D3DENUMRET_OK); +} + +//================================================================================ +// EnumDevices +//================================================================================ +static BOOL D3DMain_EnumDevices(void) +{ + HRESULT LastError; + + D3DMain_Log("--- D3DMain_EnumDevices ---\n"); + + AppInfo.NumDrivers = 0; + + LastError = AppInfo.lpD3D->EnumDevices(EnumDeviceFunc, NULL); + + if (LastError != DD_OK) + { + D3DMain_Log("Enumeration of drivers failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + + AppInfo.CurrentDriver = 0; + + return TRUE; +} + +//================================================================================ +// CreateSurface +//================================================================================ +static HRESULT CreateSurface(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE4 FAR *lpDDSurface) +{ + HRESULT Result; + + //if (AppInfo.OnlySystemMemory) + // lpDDSurfDesc->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + + Result = AppInfo.lpDD->CreateSurface(lpDDSurfDesc, lpDDSurface, NULL); + + return Result; +} + +//================================================================================ +// GetSurfDesc +//================================================================================ +static HRESULT GetSurfDesc(LPDDSURFACEDESC2 lpDDSurfDesc, LPDIRECTDRAWSURFACE4 lpDDSurf) +{ + HRESULT Result; + + memset(lpDDSurfDesc, 0, sizeof(DDSURFACEDESC2)); + + lpDDSurfDesc->dwSize = sizeof(DDSURFACEDESC2); + + Result = lpDDSurf->GetSurfaceDesc(lpDDSurfDesc); + + return Result; +} + +//================================================================================ +// D3DMain_CreateViewPort +//================================================================================ +static BOOL D3DMain_CreateViewPort(int w, int h) +{ + LPDIRECT3DVIEWPORT3 lpD3DViewport; + HRESULT rval; + + D3DMain_Log("--- D3DMain_CreateViewPort ---\n"); + + // Create the D3D viewport object + rval = AppInfo.lpD3D->CreateViewport(&lpD3DViewport, NULL); + + if (rval != D3D_OK) + { + D3DMain_Log("Create D3D viewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Add the viewport to the D3D device + rval = AppInfo.lpD3DDevice->AddViewport(lpD3DViewport); + if (rval != D3D_OK) + { + D3DMain_Log("Add D3D viewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Setup the viewport for a reasonable viewing area + D3DVIEWPORT2 viewData; + + memset(&viewData, 0, sizeof(D3DVIEWPORT2)); + viewData.dwSize = sizeof(D3DVIEWPORT2); + viewData.dwX = viewData.dwY = 0; + viewData.dwWidth = w; + viewData.dwHeight = h; + viewData.dvClipX = -1.0f; + viewData.dvClipWidth = 2.0f; + viewData.dvClipHeight = h * 2.0f / w; + viewData.dvClipY = viewData.dvClipHeight / 2.0f; + viewData.dvMinZ = 0.0f; + viewData.dvMaxZ = 1.0f; + + rval = lpD3DViewport->SetViewport2(&viewData); + if (rval != D3D_OK) + { + D3DMain_Log("SetViewport failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + AppInfo.lpD3DViewport = lpD3DViewport; + + // Create the material that will be used for the background + { + D3DMATERIAL Material; + D3DMATERIALHANDLE MatHandle; + + // Create the material + rval = AppInfo.lpD3D->CreateMaterial(&AppInfo.BackgroundMaterial, NULL ); + + if (rval != D3D_OK) + { + D3DMain_Log("D3DMain_CreateViewPort: CreateMaterial failed.\n %s\n", D3DErrorToString(rval)); + return FALSE; + } + + // Fill in the material with the data + memset(&Material, 0, sizeof(D3DMATERIAL)); + + Material.dwSize = sizeof(D3DMATERIAL); + Material.dcvDiffuse.r = Material.dcvAmbient.r = 0.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = 0.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = 0.0f; + Material.dwRampSize = 16L; // A default ramp size + + AppInfo.BackgroundMaterial->SetMaterial(&Material); + + // Attach the material to the viewport + AppInfo.BackgroundMaterial->GetHandle( AppInfo.lpD3DDevice, &MatHandle); + AppInfo.lpD3DViewport->SetBackground(MatHandle); + } + + return TRUE; +} + +//================================================================================ +// EnumTextureFormatsCallback +// Record information about each texture format the current D3D driver can +// support. Choose one as the default format and return it through lpContext. +//================================================================================ +static HRESULT CALLBACK EnumTextureFormatsCallback(LPDDPIXELFORMAT lpddpfPixelFormat, LPVOID lpContext) +{ + DDMain_SurfFormat *pTexFormat; + + if(!lpddpfPixelFormat) + return DDENUMRET_OK; + + if (AppInfo.NumTextureFormats+1 >= DDMAIN_MAX_TEXTURE_FORMATS ) + { + return DDENUMRET_CANCEL; + } + + pTexFormat = &AppInfo.TextureFormats[AppInfo.NumTextureFormats]; + + // Clear out this texture format slot + memset(pTexFormat, 0, sizeof(DDMain_SurfFormat)); + + if(lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + { + if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0x8000) + { + if(lpddpfPixelFormat->dwRBitMask != 0x7c00 || + lpddpfPixelFormat->dwGBitMask != 0x3e0 || + lpddpfPixelFormat->dwBBitMask != 0x1f) + return DDENUMRET_OK; + + pTexFormat->HasOneBitAlpha = TRUE; + pTexFormat->HasFourBitAlpha = FALSE; + } + else if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0xf000) + { + if(lpddpfPixelFormat->dwRBitMask != 0xf00 || + lpddpfPixelFormat->dwGBitMask != 0xf0 || + lpddpfPixelFormat->dwBBitMask != 0xf) + return DDENUMRET_OK; + + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = TRUE; + } + else + { + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = FALSE; + } + } + else + { + if(!(lpddpfPixelFormat->dwFlags & DDPF_RGB)) + return DDENUMRET_OK; + + #if 0 + if(lpddpfPixelFormat->dwRGBBitCount != 16) + return DDENUMRET_OK; + + if( (lpddpfPixelFormat->dwRBitMask != 0xf800 && lpddpfPixelFormat->dwRBitMask != 0x7c00) || + (lpddpfPixelFormat->dwGBitMask != 0x7e0 && lpddpfPixelFormat->dwGBitMask != 0x3e0) || + (lpddpfPixelFormat->dwBBitMask != 0x1f)) + return DDENUMRET_OK; + #endif + + pTexFormat->HasOneBitAlpha = FALSE; + pTexFormat->HasFourBitAlpha = FALSE; + } + + // Record the PixelFormat of this texture + memcpy(&pTexFormat->ddsd.ddpfPixelFormat, lpddpfPixelFormat, sizeof(DDPIXELFORMAT)); + + AppInfo.NumTextureFormats++; + + return DDENUMRET_OK; +} + +//================================================================================ +// Main_EnumTextureFormats +// Get a list of available texture map formats from the Direct3D driver by +// enumeration. Choose a default format. +//================================================================================ +BOOL Main_EnumTextureFormats(void) +{ + HRESULT LastError; + + assert(AppInfo.lpD3DDevice); + + AppInfo.NumTextureFormats = 0; + + LastError = AppInfo.lpD3DDevice->EnumTextureFormats(EnumTextureFormatsCallback, NULL); + + if (LastError != DD_OK) + { + D3DMain_Log("Main_EnumTextureFormats: Enumeration of texture formats failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + + +//================================================================================ +// EnumSurfaceFormatsCallback +//================================================================================ +HRESULT WINAPI EnumSurfaceFormatsCallback(LPDIRECTDRAWSURFACE4 lpDDSurface, LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext) +{ + LPDDPIXELFORMAT lpddpfPixelFormat; + DDMain_SurfFormat *pSurfFormat; + + // Don't need this. + RELEASE(lpDDSurface); + + lpddpfPixelFormat = &lpDDSurfaceDesc->ddpfPixelFormat; + + if(!lpddpfPixelFormat) + return DDENUMRET_OK; + + if (AppInfo.NumSurfFormats+1 >= DDMAIN_MAX_SURFACE_FORMATS ) + return DDENUMRET_CANCEL; + + pSurfFormat = &AppInfo.SurfFormats[AppInfo.NumSurfFormats]; + + // Clear out this texture format slot + memset(pSurfFormat, 0, sizeof(DDMain_SurfFormat)); + + if(lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + { + if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0x8000) + { + // 1555 + if(lpddpfPixelFormat->dwRBitMask != 0x7c00 || + lpddpfPixelFormat->dwGBitMask != 0x3e0 || + lpddpfPixelFormat->dwBBitMask != 0x1f) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = TRUE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + else if(lpddpfPixelFormat->dwRGBAlphaBitMask == 0xf000) + { + // 4444 + if(lpddpfPixelFormat->dwRBitMask != 0xf00 || + lpddpfPixelFormat->dwGBitMask != 0xf0 || + lpddpfPixelFormat->dwBBitMask != 0xf) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = TRUE; + } + else + { + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + } + else + { + if(!(lpddpfPixelFormat->dwFlags & DDPF_RGB)) + return DDENUMRET_OK; + + pSurfFormat->HasOneBitAlpha = FALSE; + pSurfFormat->HasFourBitAlpha = FALSE; + } + + // Record the PixelFormat of this texture + memcpy(&pSurfFormat->ddsd.ddpfPixelFormat, lpddpfPixelFormat,sizeof(DDPIXELFORMAT)); + + AppInfo.NumSurfFormats++; + + return DDENUMRET_OK; +} + +//================================================================================ +// Main_EnumSurfaceFormats +//================================================================================ +BOOL Main_EnumSurfaceFormats(void) +{ + HRESULT LastError; + + assert(AppInfo.lpDD); + + AppInfo.NumSurfFormats = 0; + + LastError = AppInfo.lpDD->EnumSurfaces(DDENUMSURFACES_DOESEXIST|DDENUMSURFACES_ALL, + NULL, NULL, EnumSurfaceFormatsCallback); + + if (LastError != DD_OK) + { + D3DMain_Log("Main_EnumSurfaceFormats: Enumeration of texture formats failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + + +//----------------------------------------------------------------------------- +// Name: EnumZBufferFormatsCallback() +// Desc: Enumeration function to report valid pixel formats for z-buffers. +//----------------------------------------------------------------------------- +static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf, + VOID* pddpfDesired ) +{ + if( NULL==pddpf || NULL==pddpfDesired ) + return D3DENUMRET_CANCEL; + + // If the current pixel format's match the desired ones (DDPF_ZBUFFER and + // possibly DDPF_STENCILBUFFER), lets copy it and return. This function is + // not choosy...it accepts the first valid format that comes along. + if( pddpf->dwFlags == ((DDPIXELFORMAT*)pddpfDesired)->dwFlags ) + { + memcpy( pddpfDesired, pddpf, sizeof(DDPIXELFORMAT) ); + + // We're happy with a 16-bit z-buffer. Otherwise, keep looking. + if( pddpf->dwZBufferBitDepth == 16 ) + return D3DENUMRET_CANCEL; + } + + return D3DENUMRET_OK; +} + +//================================================================================ +// D3DMain_ClearBuffers +//================================================================================ +static BOOL D3DMain_ClearBuffers(void) +{ + DDSURFACEDESC2 ddsd; + RECT dst; + DDBLTFX ddbltfx; + HRESULT LastError; + + // Find the width and height of the front buffer by getting its + // DDSURFACEDESC2 + if (AppInfo.lpFrontBuffer) + { + LastError = GetSurfDesc(&ddsd, AppInfo.lpFrontBuffer); + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_ClearBuffers: Failure getting the surface description of the front buffer before clearing.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + // Clear the front buffer to black + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(DDBLTFX); + SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight); + + LastError = AppInfo.lpFrontBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, + &ddbltfx); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("D3DMain_ClearBuffers: D3DMain_RestoreAllSurfaces failed...\n"); + return FALSE; + } + } + else + { + D3DMain_Log("D3DMain_ClearBuffers: Clearing the front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + } + + if (AppInfo.lpBackBuffer) + { + // Find the width and height of the back buffer by getting its + // DDSURFACEDESC2 + + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_ClearBuffers: Failure while getting the surface description of the back buffer before clearing.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + // Clear the back buffer to black + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(DDBLTFX); + SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight); + LastError = AppInfo.lpBackBuffer->Blt(&dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, + &ddbltfx); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("D3DMain_ClearBuffers: D3DMain_RestoreAllSurfaces failed.\n"); + return FALSE; + } + } + else + { + D3DMain_Log("D3DMain_ClearBuffers: Clearing the back buffer failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + } + + return TRUE; +} + +//================================================================================ +// Main_ShowBackBuffer +//================================================================================ +BOOL Main_ShowBackBuffer(void) +{ + HRESULT LastError; + + if (!AppInfo.RenderingIsOK) + return TRUE; + + if (AppInfo.FullScreen) + { + // Flip the back and front buffers + #if 1 + LastError = AppInfo.lpFrontBuffer->Flip(AppInfo.lpBackBuffer, DDFLIP_WAIT); + #else + LastError = AppInfo.lpFrontBuffer->Flip(AppInfo.lpBackBuffer, DDFLIP_NOVSYNC); + #endif + + if (LastError == DDERR_SURFACELOST) + { + D3DMain_RestoreAllSurfaces(); + //AppInfo.lpFrontBuffer->Restore(); + //AppInfo.lpBackBuffer->Restore(); + + D3DMain_ClearBuffers(); + + } + else if (LastError == DDERR_WASSTILLDRAWING) + { + } + else if (LastError != DD_OK) + { + D3DMain_Log("Flipping complex display surface failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + } + else + { + RECT FRect, BRect; + + FRect.left = AppInfo.WindowXOffset; + FRect.right = FRect.left + AppInfo.CurrentWidth; + FRect.top = AppInfo.WindowYOffset; + FRect.bottom = FRect.top + AppInfo.CurrentHeight; + + BRect.left = 0; + BRect.right = AppInfo.CurrentWidth; + BRect.top = 0; + BRect.bottom = AppInfo.CurrentHeight; + + LastError = AppInfo.lpFrontBuffer->Blt(&FRect, AppInfo.lpBackBuffer, + &BRect, DDBLT_WAIT, NULL); + + if (LastError != DD_OK) + { + if(LastError==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + { + D3DMain_Log("Main_ShowBackBuffer: D3DMain_RestoreAllSurfaces.\n"); + return FALSE; + } + } + else + { + D3DMain_Log("Main_ShowBackBuffer: Blt of back buffer to front buffer failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + } + } + + return TRUE; +} + +//================================================================================ +// Main_ClearBackBuffer +//================================================================================ +BOOL Main_ClearBackBuffer(BOOL Clear, BOOL ClearZ) +{ + int ClearFlags; + D3DRECT Dummy; + HRESULT LastError; + + if (!AppInfo.RenderingIsOK) + return TRUE; + + // Default to clear nothing + ClearFlags = 0; + + // Then set in what callers wants to clear + if (Clear) + ClearFlags |= D3DCLEAR_TARGET; + + if (ClearZ) + ClearFlags |= D3DCLEAR_ZBUFFER; + + Dummy.x1 = Dummy.y1 = 0; + Dummy.x2 = AppInfo.CurrentWidth; + Dummy.y2 = AppInfo.CurrentHeight; + + LastError = AppInfo.lpD3DViewport->Clear(1, &Dummy, ClearFlags); + + if (LastError != D3D_OK) + { + D3DMain_Log("Viewport clear failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + return TRUE; +} + +//================================================================================ +// Surface manipulation +//================================================================================ + +typedef struct +{ + unsigned char r, g, b; +} MY_D3D_RGB; + +typedef struct +{ + DWORD R_Shift; + DWORD G_Shift; + DWORD B_Shift; + DWORD A_Shift; + + DWORD R_Mask; + DWORD G_Mask; + DWORD B_Mask; + DWORD A_Mask; + + DWORD R_Width; + DWORD G_Width; + DWORD B_Width; + DWORD A_Width; +} D3D_PixelMask; + +//================================================================================ +// GetSurfacePixelMask +//================================================================================ +static void GetSurfacePixelMask(DDSURFACEDESC2 *ddsd, D3D_PixelMask *PixelMask) +{ + DWORD red_mask, grn_mask, blu_mask, a_mask; + DWORD red_shift, grn_shift, blu_shift, a_shift; + DWORD red_width, grn_width, blu_width, a_width; + int i; + + red_mask = ddsd->ddpfPixelFormat.dwRBitMask; + grn_mask = ddsd->ddpfPixelFormat.dwGBitMask; + blu_mask = ddsd->ddpfPixelFormat.dwBBitMask; + a_mask = ddsd->ddpfPixelFormat.dwRGBAlphaBitMask; + + // + // Derive shift, width values from masks + // + + for (i=31; i >= 0; i--) + { + if (red_mask & (1 << i)) + red_shift = i; + + if (grn_mask & (1 << i)) + grn_shift = i; + + if (blu_mask & (1 << i)) + blu_shift = i; + + if (a_mask & (1 << i)) + a_shift = i; + } + + for (i=0; i <= 31; i++) + { + if (red_mask & (1 << i)) + red_width = i - red_shift + 1; + + if (grn_mask & (1 << i)) + grn_width = i - grn_shift + 1; + + if (blu_mask & (1 << i)) + blu_width = i - blu_shift + 1; + + if (a_mask & (1 << i)) + a_width = i - a_shift + 1; + } + // + // Pass all requested values back to the caller + // + + PixelMask->R_Shift = red_shift; + PixelMask->G_Shift = grn_shift; + PixelMask->B_Shift = blu_shift; + PixelMask->A_Shift = a_shift; + + PixelMask->R_Mask = red_mask; + PixelMask->G_Mask = grn_mask; + PixelMask->B_Mask = blu_mask; + PixelMask->A_Mask = a_mask; + + PixelMask->R_Width = red_width; + PixelMask->G_Width = grn_width; + PixelMask->B_Width = blu_width; + PixelMask->A_Width = a_width; +} + +//================================================================================ +// MyRGB +//================================================================================ +static unsigned int MyRGB(DWORD R, DWORD G, DWORD B, D3D_PixelMask *PixelMask) +{ + DWORD R_Left, G_Left, B_Left; + DWORD R_Right, G_Right, B_Right; + + + // Get shift constants for current video mode + R_Left = PixelMask->R_Shift; + G_Left = PixelMask->G_Shift; + B_Left = PixelMask->B_Shift; + + R_Right = 8 - PixelMask->R_Width; + G_Right = 8 - PixelMask->G_Width; + B_Right = 8 - PixelMask->B_Width; + // Shift R,G, and B into one value + return( + (((((unsigned int) R) >> R_Right) << R_Left) & PixelMask->R_Mask) | + (((((unsigned int) G) >> G_Right) << G_Left) & PixelMask->G_Mask) | + (((((unsigned int) B) >> B_Right) << B_Left) & PixelMask->B_Mask) + ); +} + +//========================================================================================== +// D3DMain_GetSurfaceFormats +//========================================================================================== +BOOL D3DMain_GetSurfaceFormats(void) +{ + int32 i; + + D3DMain_Log("--- D3DMain_GetSurfaceFormats ---\n"); + + if (!Main_EnumTextureFormats()) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Main_EnumTextureFormats failed.\n"); + return FALSE; + } + + if (!Main_EnumSurfaceFormats()) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Main_EnumSurfaceFormats failed.\n"); + return FALSE; + } + +#if 1 + for(i = 0; i < AppInfo.NumSurfFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + lpddpfPixelFormat = &AppInfo.SurfFormats[i].ddsd.ddpfPixelFormat; + + if(lpddpfPixelFormat->dwRGBBitCount != AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount) + continue; + + if (lpddpfPixelFormat->dwRGBAlphaBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask) + continue; + if (lpddpfPixelFormat->dwRBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRBitMask) + continue; + if (lpddpfPixelFormat->dwGBitMask != AppInfo.ddsd.ddpfPixelFormat.dwGBitMask) + continue; + if (lpddpfPixelFormat->dwBBitMask != AppInfo.ddsd.ddpfPixelFormat.dwBBitMask) + continue; + + #if 0 // For debugging (This is the surface it is going to use for 2d decals) + D3DMain_Log("Bits: %i, A:%x, R:%x, G:%x, B:%x\n", AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount, + AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwRBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwGBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwBBitMask); + return FALSE; + #endif + + + AppInfo.ddSurfFormat = AppInfo.SurfFormats[i].ddsd; + + break; + } + + if(i == AppInfo.NumSurfFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find a 2d surface format that matches current bit depth.\n"); + return FALSE; + } + +#else + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + lpddpfPixelFormat = &AppInfo.TextureFormats[i].ddsd.ddpfPixelFormat; + + if(lpddpfPixelFormat->dwRGBBitCount != AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount) + continue; + + if (lpddpfPixelFormat->dwRGBAlphaBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask) + continue; + if (lpddpfPixelFormat->dwRBitMask != AppInfo.ddsd.ddpfPixelFormat.dwRBitMask) + continue; + if (lpddpfPixelFormat->dwGBitMask != AppInfo.ddsd.ddpfPixelFormat.dwGBitMask) + continue; + if (lpddpfPixelFormat->dwBBitMask != AppInfo.ddsd.ddpfPixelFormat.dwBBitMask) + continue; + + #if 0 // For debugging (This is the surface it is going to use for 2d decals) + D3DMain_Log("Bits: %i, A:%x, R:%x, G:%x, B:%x\n", AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount, + AppInfo.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwRBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwGBitMask, + AppInfo.ddsd.ddpfPixelFormat.dwBBitMask); + return FALSE; + #endif + + + AppInfo.ddSurfFormat = AppInfo.TextureFormats[i].ddsd; + + break; + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find a 2d surface format that matches current bit depth.\n"); + return FALSE; + } +#endif + + // Now get the 3d surface formats + + // Get 1555 + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + if(AppInfo.TextureFormats[i].HasOneBitAlpha == TRUE) + { + AppInfo.ddOneBitAlphaSurfFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 1555 texture support.\n"); + return FALSE; + } + + // Get 4444 + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + if(AppInfo.TextureFormats[i].HasFourBitAlpha == TRUE) + { + AppInfo.ddFourBitAlphaSurfFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 4444 texture support.\n"); + return FALSE; + } + + // Get either 555, or 565. + for(i = 0; i < AppInfo.NumTextureFormats; i++) + { + LPDDPIXELFORMAT lpddpfPixelFormat; + + if(AppInfo.TextureFormats[i].HasOneBitAlpha == TRUE) + continue; + + if (AppInfo.TextureFormats[i].HasFourBitAlpha == TRUE) + continue; + + lpddpfPixelFormat = &AppInfo.TextureFormats[i].ddsd.ddpfPixelFormat; + + // For now, force 3d textures with RGB only info to be either 565 or 555 + // We could enum all formats and let the caller pick between several different RGB formats... + if (lpddpfPixelFormat->dwFlags & DDPF_ALPHAPIXELS) + continue; // We don't want any surface that has alpha, just pure RGB... + + if(lpddpfPixelFormat->dwRGBBitCount != 16) + continue; + + if( (lpddpfPixelFormat->dwRBitMask != 0xf800 && lpddpfPixelFormat->dwRBitMask != 0x7c00) || + (lpddpfPixelFormat->dwGBitMask != 0x7e0 && lpddpfPixelFormat->dwGBitMask != 0x3e0) || + (lpddpfPixelFormat->dwBBitMask != 0x1f)) + continue; + + + // This is it + AppInfo.ddTexFormat = AppInfo.TextureFormats[i].ddsd; + break; + } + + if(i == AppInfo.NumTextureFormats) + { + D3DMain_Log("D3DMain_GetSurfaceFormats: Unable to find 555 or 565 texture support.\n"); + return FALSE; + } + + Main_BuildRGBGammaTables(1.0f); + + return TRUE; +} + +//========================================================================================== +// Main_CheckDD +// Checks to see if current DD driver has any usable D3D Devices... +//========================================================================================== +BOOL Main_CheckDD(void) +{ + AppInfo.NumDrivers = 0; + AppInfo.CurrentDriver = 0; + AppInfo.FoundGoodDevice = FALSE; + AppInfo.CanDoWindow = FALSE; + + assert(AppInfo.lpDD); + + if (!D3DMain_RememberOldMode(GetDesktopWindow())) + return FALSE; + + memset(AppInfo.Drivers, 0, sizeof(DDMain_D3DDriver)*DDMAIN_MAX_D3D_DRIVERS); + + if (!D3DMain_CreateD3D()) + return FALSE; + + if (!D3DMain_EnumDevices()) // See if we can enumerate at least one good device for this DD Driver + return FALSE; + + if (!AppInfo.FoundGoodDevice) // Return FALSE if not... + return FALSE; + + return TRUE; // Found at least one!!! +} + +//========================================================================================== +// OutputDriverInfo +//========================================================================================== +static BOOL OutputDriverInfo(const char *FileName, DDMain_D3DDriver *Driver) +{ + FILE *f; + SYSTEMTIME Time; + char YesNo[2][10]; + + f = fopen(FileName, "a+t"); + + if (!f) + return FALSE; + + GetSystemTime(&Time); + + strcpy(YesNo[0], "No\n"); + strcpy(YesNo[1], "Yes\n"); + + fprintf(f,"=================================================================\n"); + fprintf(f,"Time: %2i:%2i:%2i\n", Time.wHour, Time.wMinute, Time.wSecond); + fprintf(f,"Date: %2i-%2i-%4i\n", Time.wMonth, Time.wDay, Time.wYear); + + fprintf(f, "DirectDraw Name: \n"); + fprintf(f, " %s\n", AppInfo.DDName); + + fprintf(f, "D3D Driver Name: \n"); + fprintf(f, " %s\n", Driver->Name); + + fprintf(f, "D3D Driver Description: \n"); + fprintf(f, " %s\n", Driver->About); + + fprintf(f, "3D Acceleration : %s", YesNo[Driver->IsHardware]); + fprintf(f, "Texture Support : %s", YesNo[Driver->DoesTextures]); + fprintf(f, "Transparency Support : %s", YesNo[Driver->DoesTransparency]); + fprintf(f, "Alpha Support : %s", YesNo[Driver->DoesAlpha]); + fprintf(f, "UV Clamping Support : %s", YesNo[Driver->DoesClamping]); + fprintf(f, "Src Blending Support : %s", YesNo[Driver->DoesSrcBlending]); + fprintf(f, "Dest Blending Support : %s", YesNo[Driver->DoesDestBlending]); + fprintf(f, "Window Support : %s", YesNo[Driver->CanDoWindow]); + fprintf(f, "Can Use : %s", YesNo[Driver->CanUse]); + + fclose(f); + + return TRUE; +} + +//========================================================================================== +// D3DMain_GetTextureMemory +//========================================================================================== +BOOL D3DMain_GetTextureMemory(void) +{ + + DDSCAPS2 ddsCaps; + DWORD dwTotal; + DWORD dwFree; + HRESULT Error; + + D3DMain_Log("--- D3DMain_GetTextureMemory ---\n"); + + memset(&ddsCaps, 0, sizeof(ddsCaps)); + + //ddsCaps.dwSize = sizeof(DDSCAPS2); + ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + + Error = AppInfo.lpDD->GetAvailableVidMem(&ddsCaps, &dwTotal, &dwFree); + + if(Error !=DD_OK) + { + D3DMain_Log("Getting DD capabilities failed while checking total video memory.\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + AppInfo.VidMemFree = dwFree; + + D3DMain_Log(" Ram free: %i\n", AppInfo.VidMemFree); + + return TRUE; +} + + +//========================================================================================== +//========================================================================================== +void Main_BuildRGBGammaTables(geFloat Gamma) +{ + int32 i, Val; + int32 GammaTable[256]; + D3D_PixelMask PixelMask; + DWORD R_Left, G_Left, B_Left, A_Left; + DWORD R_Right, G_Right, B_Right, A_Right; + + + AppInfo.Gamma = Gamma; + + if (Gamma == 1.0) + { + for (i=0 ; i<256 ; i++) + GammaTable[i] = i; + } + else for (i=0 ; i<256 ; i++) + { + geFloat Ratio = (i+0.5f)/255.5f; + + geFloat RGB = (geFloat)(255.0 * pow((double)Ratio, 1.0/(double)Gamma) + 0.5); + + if (RGB < 0.0f) + RGB = 0.0f; + if (RGB > 255.0f) + RGB = 255.0f; + + GammaTable[i] = (int32)RGB; + } + + GetSurfacePixelMask(&AppInfo.ddTexFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut1.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut1.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut1.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut1.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } + GetSurfacePixelMask(&AppInfo.ddFourBitAlphaSurfFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut2.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut2.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut2.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut2.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } + GetSurfacePixelMask(&AppInfo.ddOneBitAlphaSurfFormat, &PixelMask); + for (i=0; i< 256; i++) + { + // Get shift constants for current video mode/pixel format + R_Left = PixelMask.R_Shift; + G_Left = PixelMask.G_Shift; + B_Left = PixelMask.B_Shift; + A_Left = PixelMask.A_Shift; + + R_Right = 8 - PixelMask.R_Width; + G_Right = 8 - PixelMask.G_Width; + B_Right = 8 - PixelMask.B_Width; + A_Right = 8 - PixelMask.A_Width; + + Val = GammaTable[i]; + + AppInfo.Lut3.R[i] = (((uint32)Val >> R_Right) << R_Left) & PixelMask.R_Mask; + AppInfo.Lut3.G[i] = (((uint32)Val >> G_Right) << G_Left) & PixelMask.G_Mask; + AppInfo.Lut3.B[i] = (((uint32)Val >> B_Right) << B_Left) & PixelMask.B_Mask; + AppInfo.Lut3.A[i] = (((uint32) i >> A_Right) << A_Left) & PixelMask.A_Mask; + } +} + +//==================================================================================================== +// D3DMain_UpdateWindow +//==================================================================================================== +geBoolean DRIVERCC D3DMain_UpdateWindow(void) +{ + D3DMain_GetClientWindowOffset(AppInfo.hWnd); + return GE_TRUE; +} + +//==================================================================================================== +// D3DMain_SetActive +//==================================================================================================== +geBoolean DRIVERCC D3DMain_SetActive(geBoolean wParam) +{ + if (AppInfo.lpFrontBuffer) + AppInfo.RenderingIsOK = wParam; + + if(AppInfo.RenderingIsOK) // Regaining focus + { + HRESULT Result; + + if (AppInfo.lpFrontBuffer) + { + Result = AppInfo.lpFrontBuffer->IsLost(); + + if(Result == DDERR_SURFACELOST) + { + if(!D3DMain_RestoreAllSurfaces()) + { + OutputDebugString("Couldn't restore surfaces!\n"); + return GE_FALSE; + } + + OutputDebugString("D3DMain_SetActive: Regained Focus...\n"); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); // Dx doesn't restore it + } + else + OutputDebugString("D3DMain_SetActive: No surfaces lost...\n"); + } + } + + return GE_TRUE; +} + +//======================================================================================================== +// D3DMain_SetFogEnable +//======================================================================================================== +geBoolean DRIVERCC D3DMain_SetFogEnable(geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End) +{ + D3DMATERIAL Material; + + AppInfo.FogEnable = Enable; + AppInfo.FogR = r; + AppInfo.FogG = g; + AppInfo.FogB = b; + AppInfo.FogStart = Start; + AppInfo.FogEnd = End; + + // Fill in the material with the data + memset(&Material, 0, sizeof(D3DMATERIAL)); + + Material.dwSize = sizeof(D3DMATERIAL); + + if (Enable) + { + Material.dcvDiffuse.r = Material.dcvAmbient.r = r/255.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = g/255.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = b/255.0f; + } + else + { + Material.dcvDiffuse.r = Material.dcvAmbient.r = 0.0f; + Material.dcvDiffuse.g = Material.dcvAmbient.g = 0.0f; + Material.dcvDiffuse.b = Material.dcvAmbient.b = 0.0f; + } + + Material.dwRampSize = 16L; // A default ramp size + + AppInfo.BackgroundMaterial->SetMaterial(&Material); + + return GE_TRUE; +} + +//================================================================================ +// D3DMain_GetClientWindowOffset +//================================================================================ +BOOL D3DMain_GetClientWindowOffset(HWND hWnd) +{ + POINT CPoint; + + CPoint.x = CPoint.y = 0; + + ClientToScreen(hWnd, &CPoint); + + AppInfo.WindowXOffset = CPoint.x; + AppInfo.WindowYOffset = CPoint.y; + + return TRUE; +} + +//================================================================================ +// D3DMain_RememberOldMode +//================================================================================ +static BOOL D3DMain_RememberOldMode(HWND hWnd) +{ + DDSURFACEDESC2 ddsd; + HRESULT LastError; + RECT CRect; + + D3DMain_Log("--- D3DMain_RememberOldMode ---\n"); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + + LastError = AppInfo.lpDD->GetDisplayMode(&ddsd); + + if (LastError != DD_OK) + { + D3DMain_Log("Getting the current display mode failed.\n %s\n", D3DErrorToString(LastError)); + return FALSE; + } + + GetClientRect(hWnd, &CRect); + + // Get old fulscreen width/height/bpp + AppInfo.OldWidth = ddsd.dwWidth; + AppInfo.OldHeight = ddsd.dwHeight; + AppInfo.OldBpp = ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Get old window width/pos + AppInfo.OldWindowWidth = CRect.right; + AppInfo.OldWindowHeight = CRect.bottom; + + GetWindowRect(hWnd, &CRect); + AppInfo.OldWindowRect = CRect; + + AppInfo.OldGWL_STYLE = GetWindowLong(hWnd, GWL_STYLE); + + D3DMain_GetClientWindowOffset(hWnd); + + return TRUE; +} + +//========================================================================================== +// D3DMain_SetDisplayMode +//========================================================================================== +static BOOL D3DMain_SetDisplayMode(HWND hWnd, int w, int h, int bpp, BOOL FullScreen) +{ + HRESULT LastError; + int DWidth, DHeight; + char YN[2][32]; + + strcpy(YN[0], "NO"); + strcpy(YN[1], "YES"); + + D3DMain_Log("--- D3DMain_SetDisplayMode ---\n"); + D3DMain_Log(" W: %i, H: %i, Bpp: %i, FullScreen: %s\n", w, h, bpp, YN[FullScreen]); + + if (FullScreen) + { + LastError = AppInfo.lpDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);// | DDSCL_ALLOWREBOOT); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to fullscreen failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + LastError = AppInfo.lpDD->SetDisplayMode(w, h, bpp,0,0); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetFullScreenDisplayMode: Mode %dx%dx%d failed\n %s\n", w, h, bpp, D3DErrorToString(LastError)); + return FALSE; + } + + DWidth = GetSystemMetrics(SM_CXSCREEN); + DHeight = GetSystemMetrics(SM_CYSCREEN); + + // + // Set window boundaries to cover entire desktop, and show it + // + SetWindowLong(hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE | WS_POPUP); + + SetWindowLong(hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE & + ~(WS_OVERLAPPED | + WS_CAPTION | + WS_SYSMENU | + WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | + WS_THICKFRAME)); + + + SetWindowPos(AppInfo.hWnd, + HWND_TOP, + 0, + 0, + DWidth, + DHeight, + SWP_NOCOPYBITS | SWP_NOZORDER); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); + } + else + { + LastError = AppInfo.lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to normal failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + + AppInfo.hWnd = hWnd; + AppInfo.CurrentWidth = w; + AppInfo.CurrentHeight = h; + AppInfo.CurrentBpp = bpp; + AppInfo.FullScreen = FullScreen; + + AppInfo.ModeSet = GE_TRUE; + + return TRUE; +} + +//================================================================================ +// D3DMain_PickDevice +//================================================================================ +static BOOL D3DMain_PickDevice(void) +{ + int32 i; + DWORD Depths; + + D3DMain_Log("--- D3DMain_PickDevice ---\n"); + + // Find a device with the same bpp as the mode set + Depths = BPPToDDBD(AppInfo.CurrentBpp); + + for (i = 0; i < AppInfo.NumDrivers; i++) + { + if (!(AppInfo.Drivers[i].IsHardware)) // ONLY hardware + continue; + + // Only choose drivers that can support our draw buffer bpp + if (!(AppInfo.Drivers[i].Desc.dwDeviceRenderBitDepth & Depths)) + continue; + + // Only choose drivers that can create the zbuffer we need + if (!(AppInfo.Drivers[i].Desc.dwDeviceZBufferBitDepth & DDBD_16)) + continue; + + if (!(AppInfo.Drivers[i].Desc.dcmColorModel & D3DCOLOR_RGB)) + continue; + + if (!AppInfo.Drivers[i].CanDoWindow && !AppInfo.FullScreen) + continue; + + // Remember the current driver + AppInfo.CurrentDriver = i; + + return TRUE; + } + + return FALSE; +} + +//================================================================================ +// D3DMain_CreateDevice +//================================================================================ +static BOOL D3DMain_CreateDevice(void) +{ + HRESULT Error; + + D3DMain_Log("--- D3DMain_CreateDevice ---\n"); + + // Release old device + RELEASE(AppInfo.lpD3DDevice); + + Error = AppInfo.lpD3D->CreateDevice(AppInfo.Drivers[AppInfo.CurrentDriver].Guid, + AppInfo.lpBackBuffer, + &AppInfo.lpD3DDevice,NULL); + + if (Error != DD_OK) + { + D3DMain_Log("D3DMain_CreateDevice: lpD3D->CreateDevice failed:\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + #if 0 + { + // Get some info from the device + D3DDEVICEDESC hw, sw; + + hw.dwSize = sw.dwSize = D3DDEVICEDESCSIZE; + + AppInfo.lpD3DDevice->GetCaps(&hw, &sw); + } + #endif + + // Get Device Identifier + Error = AppInfo.lpDD->GetDeviceIdentifier(&AppInfo.DeviceIdentifier, 0); + + if (Error != DD_OK) + { + D3DMain_Log("D3DMain_CreateDevice: lpDD->GetDeviceIdentifier failed:\n %s\n", D3DErrorToString(Error)); + return FALSE; + } + + // Print the debug ID + D3DMain_Log(" Vender ID = %6i\n", AppInfo.DeviceIdentifier.dwVendorId); + D3DMain_Log(" Device ID = %6i\n", AppInfo.DeviceIdentifier.dwDeviceId); + + return TRUE; +} + +//================================================================================ +// D3DMain_CreateBuffers +//================================================================================ +static BOOL D3DMain_CreateBuffers(void) +{ + DDSURFACEDESC2 ddsd; + DDSCAPS2 ddscaps; + HRESULT LastError; + + D3DMain_Log("--- D3DMain_CreateBuffers ---\n"); + + // Release any old objects that might be lying around. This should have + // already been taken care of, but just in case... + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); + + if (AppInfo.FullScreen) + { + // Create a complex flipping surface for fullscreen mode with one + // back buffer. + memset(&ddsd,0,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | + DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX; + ddsd.dwBackBufferCount = 1; + + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + + LastError = CreateSurface(&ddsd, &AppInfo.lpFrontBuffer); + + if(LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n Please restart the program and try another fullscreen mode with less resolution or lower bit depth.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for fullscreen flipping surface failed.\n %s\n", + D3DErrorToString(LastError)); + } + + goto exit_with_error; + } + + // Obtain a pointer to the back buffer surface created above so we + // can use it later. For now, just check to see if it ended up in + // video memory (FYI). + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + LastError = AppInfo.lpFrontBuffer->GetAttachedSurface(&ddscaps, &AppInfo.lpBackBuffer); + + if(LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: GetAttachedSurface failed to get back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: Failed to get surface description of back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.BackBufferInVideo = + (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + AppInfo.ddsd = ddsd; // Save the format of the back buffer + } + else + { + // In the window case, create a front buffer which is the primary + // surface and a back buffer which is an offscreen plane surface. + + memset(&ddsd,0,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + + LastError = AppInfo.lpDD->CreateSurface(&ddsd, &AppInfo.lpFrontBuffer, NULL); + + if(LastError != DD_OK ) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n To run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for window front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + goto exit_with_error; + } + + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwWidth = AppInfo.CurrentWidth; + ddsd.dwHeight = AppInfo.CurrentHeight; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + + LastError = CreateSurface(&ddsd, &AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + D3DMain_Log("CreateBuffers: There was not enough video memory to create the rendering surface.\n To run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.\n"); + } + else + { + D3DMain_Log("CreateBuffers: CreateSurface for window back buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + goto exit_with_error; + } + + // Check to see if the back buffer is in video memory (FYI). + LastError = GetSurfDesc(&ddsd, AppInfo.lpBackBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateBuffers: Failed to get surface description for back buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.BackBufferInVideo = (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + // Create the DirectDraw Clipper object and attach it to the window + // and front buffer. + LastError = AppInfo.lpDD->CreateClipper(0, &AppInfo.lpClipper, NULL); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: CreateClipper failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + LastError = AppInfo.lpClipper->SetHWnd(0, AppInfo.hWnd); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: Attaching clipper to window failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + + LastError = AppInfo.lpFrontBuffer->SetClipper(AppInfo.lpClipper); + + if(LastError != DD_OK ) + { + D3DMain_Log("CreateBuffers: Attaching clipper to front buffer failed.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.ddsd = ddsd; // Save the format of the back buffer + } + + D3DMain_ClearBuffers(); + + return TRUE; + + exit_with_error: + + RELEASE(AppInfo.lpFrontBuffer); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpClipper); + return FALSE; +} + +//================================================================================ +// D3DMain_DestroyBuffers +//================================================================================ +static void D3DMain_DestroyBuffers(void) +{ + RELEASE(AppInfo.lpClipper); + RELEASE(AppInfo.lpBackBuffer); + RELEASE(AppInfo.lpFrontBuffer); +} + +//================================================================================ +// D3DMain_CreateZBuffer +// Create a Z-Buffer of the appropriate depth and attach it to the back buffer. +//================================================================================ +static BOOL D3DMain_CreateZBuffer(void) +{ + DDSURFACEDESC2 ddsd; + HRESULT LastError; + + assert(AppInfo.lpBackBuffer); + + D3DMain_Log("--- D3DMain_CreateZBuffer ---\n"); + + // Release any Z-Buffer that might be around just in case. + RELEASE(AppInfo.lpZBuffer); + + memset(&ddsd, 0 ,sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;//DDSD_ZBUFFERBITDEPTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; + ddsd.dwWidth = AppInfo.CurrentWidth; + ddsd.dwHeight = AppInfo.CurrentHeight; + + ddsd.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER; + + // Find a valid zbuffer, from the current device + AppInfo.lpD3D->EnumZBufferFormats(AppInfo.Drivers[AppInfo.CurrentDriver].Guid, EnumZBufferFormatsCallback, + (VOID*)&ddsd.ddpfPixelFormat); + + + if( sizeof(DDPIXELFORMAT) != ddsd.ddpfPixelFormat.dwSize ) + { + D3DMain_Log("CreateZBuffer: No zbuffer found for 3d device.\n"); + return FALSE; + } + + LastError = AppInfo.lpDD->CreateSurface(&ddsd, &AppInfo.lpZBuffer, NULL); + + if(LastError != DD_OK) + { + if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) + { + if (AppInfo.FullScreen) + { + D3DMain_Log("CreateZBuffer: There was not enough video memory to create the Z-buffer surface.\n Please try another mode with less resolution.\n"); + } + else + { + D3DMain_Log("CreateZBuffer: There was not enough video memory to create the Z-buffer surface.\n Please try another mode with less resolution.\n"); + } + } + else + { + D3DMain_Log("CreateZBuffer: CreateSurface for Z-buffer failed.\n %s\n", + D3DErrorToString(LastError)); + } + + goto exit_with_error; + } + + // Attach the Z-buffer to the back buffer so D3D will find it + LastError = AppInfo.lpBackBuffer->AddAttachedSurface(AppInfo.lpZBuffer); + + if(LastError != DD_OK) + { + D3DMain_Log("CreateZBuffer: AddAttachedBuffer failed for Z-Buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + // Find out if it ended up in video memory. + LastError = GetSurfDesc(&ddsd, AppInfo.lpZBuffer); + + if (LastError != DD_OK) + { + D3DMain_Log("CreateZBuffer: Failed to get surface description of Z buffer.\n %s\n", + D3DErrorToString(LastError)); + goto exit_with_error; + } + + AppInfo.ZBufferInVideo = (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + + return TRUE; + + exit_with_error: + RELEASE(AppInfo.lpZBuffer); + return FALSE; +} + +//================================================================================ +// D3DMain_DestroyZBuffer +//================================================================================ +static void D3DMain_DestroyZBuffer(void) +{ + RELEASE(AppInfo.lpZBuffer) +} + +//================================================================================ +// D3DMain_RestoreDisplayMode +// Does nothing if mode has not been set yet +//================================================================================ +static BOOL D3DMain_RestoreDisplayMode(void) +{ + HRESULT LastError; + + if (!AppInfo.ModeSet) + return TRUE; + + AppInfo.ModeSet = GE_FALSE; + + assert(AppInfo.lpDD); + + if (AppInfo.FullScreen) + { + LastError = AppInfo.lpDD->RestoreDisplayMode(); + + if (LastError != DD_OK) + { + D3DMain_Log("D3DMain_RestoreDisplayMode: RestoreDisplayMode failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + + LastError = AppInfo.lpDD->SetCooperativeLevel(AppInfo.hWnd, DDSCL_NORMAL); + + if(LastError != DD_OK ) + { + D3DMain_Log("SetCooperativeLevel to normal failed.\n %s\n", + D3DErrorToString(LastError)); + return FALSE; + } + } + + // Restore window width/height + SetWindowLong(AppInfo.hWnd, GWL_STYLE, AppInfo.OldGWL_STYLE); + + SetWindowPos(AppInfo.hWnd, + HWND_TOP, + AppInfo.OldWindowRect.left, + AppInfo.OldWindowRect.top, + (AppInfo.OldWindowRect.right - AppInfo.OldWindowRect.left), + (AppInfo.OldWindowRect.bottom - AppInfo.OldWindowRect.top), + SWP_NOCOPYBITS | SWP_NOZORDER); + + ShowWindow(AppInfo.hWnd, SW_SHOWNORMAL); + + return TRUE; +} + + +// +// Enum drivers +// + +D3D_DRIVER Drivers[MAX_DRIVERS]; + +//======================================================================================================== +// EnumDriversCB2 +//======================================================================================================== +BOOL FAR PASCAL EnumDriversCB2(GUID FAR *lpGUID, LPSTR lpDriverDesc, LPSTR lpDriverName, LPVOID lpContext) +{ + DDEnumInfo *Info; + D3D_DRIVER *pDriver; + + if (!lpDriverDesc || !lpDriverName) + return (D3DENUMRET_OK); + + if (strlen(lpDriverDesc) + 5 >= MAX_DRIVER_NAME) + return DDENUMRET_OK; + + Info = (DDEnumInfo*)lpContext; + + if (Info->NumDrivers >= MAX_DRIVERS) + return DDENUMRET_CANCEL; + + pDriver = &Info->Drivers[Info->NumDrivers++]; + + if (lpGUID) + { + pDriver->IsPrimary = GE_FALSE; + memcpy(&pDriver->Guid, lpGUID, sizeof(GUID)); + } + else + { + pDriver->IsPrimary = GE_TRUE; + } + + // Save name + //sprintf(pDriver->Name, "(D3D)%s", lpDriverDesc); + sprintf(pDriver->Name, "WireFrame (D3D)"); + + return DDENUMRET_OK; +} + +//======================================================================================================== +// EnumSubDrivers2 +//======================================================================================================== +BOOL DRIVERCC EnumSubDrivers2(DRV_ENUM_DRV_CB *Cb, void *Context) +{ + HRESULT hr; + int32 i; + DDEnumInfo Info; + + unlink(D3DMAIN_LOG_FILENAME); + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_EnumSubDrivers: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + for (i=0; i< Info.NumDrivers; i++) + { + // Create the DD object for this driver + if (!CreateDDFromDriver(&Info.Drivers[i])) + return GE_FALSE; + + if (Main_CheckDD()) + { + if (!Cb(i, Info.Drivers[i].Name, Context)) + { + RELEASE(AppInfo.lpD3D); + AppInfo.lpD3D = NULL; + + //D3DMain_ShutdownD3D(); + RELEASE(AppInfo.lpDD); + AppInfo.lpDD = NULL; + memset(&AppInfo, 0, sizeof(AppInfo)); + break; + } + } + + RELEASE(AppInfo.lpD3D); + AppInfo.lpD3D = NULL; + + //D3DMain_ShutdownD3D(); + RELEASE(AppInfo.lpDD); + AppInfo.lpDD = NULL; + memset(&AppInfo, 0, sizeof(AppInfo)); + } + + //Cb(i, "(D3D)HackDriver", Context); + + return TRUE; +} + +//======================================================================================================== +// EnumModes2 +//======================================================================================================== +BOOL DRIVERCC EnumModes2(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context) +{ + HRESULT hr; + int32 i, Width, Height; + char ModeName[MAX_DRIVER_NAME]; + DDEnumInfo Info; + + //Cb(0, "HackMode 2", 640, 480, Context); + //return GE_TRUE; + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_EnumModes: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + + if (!CreateDDFromName(DriverName, &Info)) + return GE_FALSE; + + if (!D3DMain_EnumDisplayModes()) + { + D3DMain_ShutdownD3D(); + + D3DMain_Log("D3DMain_EnumModes: D3DMain_EnumDisplayModes failed.\n"); + return FALSE; + } + + for (i=0; i< AppInfo.NumModes; i++) + { + if (AppInfo.Modes[i].Bpp != 16) + continue; + + // Get the width/height of mode + Width = AppInfo.Modes[i].Width; + Height = AppInfo.Modes[i].Height; + + // Make a unique name + sprintf(ModeName, "%ix%i", Width, Height); + + // Call their callback with this driver mode + if (!Cb(i, ModeName, Width, Height, Context)) + { + D3DMain_ShutdownD3D(); + return GE_TRUE; + } + } + + if (AppInfo.CanDoWindow) + { + if (!Cb(i, "WindowMode", -1, -1, Context)) + { + D3DMain_ShutdownD3D(); + return GE_TRUE; + } + } + + D3DMain_ShutdownD3D(); + + return TRUE; +} + +//================================================================================ +// DDEnumCallback +//================================================================================ +static BOOL FAR PASCAL DDEnumCallback( GUID FAR* lpGUID, + LPSTR lpDriverDesc, + LPSTR lpDriverName, + LPVOID lpContext) +{ + LPDIRECTDRAW4 pDD6; + DDCAPS DriverCaps, HELCaps; + DD_Enum *DDEnum; + LPDIRECTDRAW pDD1; + HRESULT hr; + + DDEnum = (DD_Enum*)lpContext; + + if(strncmp(lpDriverDesc, DDEnum->DriverName, strlen(DDEnum->DriverName))) + return DDENUMRET_OK; // Next... This is not the one they wanted + + pDD1 = NULL; + hr = DirectDrawCreate( lpGUID, &pDD1, NULL ); + + if(FAILED( hr )) + return DDENUMRET_CANCEL; // Assume this is bad, and stop + + assert(pDD1); + + // Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw + // represents the DX6 version of the API. + hr = pDD1->QueryInterface( IID_IDirectDraw4, (VOID**)&pDD6); + + // Don't need this anymore + RELEASE(pDD1); + + if( FAILED( hr ) ) + return DDENUMRET_CANCEL; + + memset(&DriverCaps, 0, sizeof(DDCAPS)); + DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + if (FAILED(pDD6->GetCaps(&DriverCaps, &HELCaps))) + { + RELEASE(pDD6); + return DDENUMRET_CANCEL; + } + + // Make sure it's a 3d compatible device + if (!(DriverCaps.dwCaps & DDCAPS_3D)) + { + RELEASE(pDD6); + return DDENUMRET_CANCEL; + } + + if (!lpGUID) + AppInfo.IsPrimary = TRUE; + else + AppInfo.IsPrimary = FALSE; + + DDEnum->lpDD = pDD6; + DDEnum->FoundDD = TRUE; + + return DDENUMRET_CANCEL; // We are done +} + +//================================================================================ +// D3DMain_CreateDDFromName +// Creates DD, searching for the specified DD name using DriverName +//================================================================================ +static BOOL D3DMain_CreateDDFromName(const char *DriverName) +{ + HRESULT hr; + DDCAPS DriverCaps, HELCaps; + DDEnumInfo Info; + + D3DMain_Log("--- D3DMain_CreateDDFromName ---\n"); + + if (strlen(DriverName) >= MAX_DRIVER_NAME) + return GE_FALSE; + + D3DMain_Log(" Name: %s\n", DriverName); + + Info.Drivers = Drivers; + Info.NumDrivers = 0; + + hr = DirectDrawEnumerate(EnumDriversCB2, &Info); + + if (hr != DD_OK) + { + D3DMain_Log("D3DMain_CreateDDFromName: DirectDrawEnumerate failed.\n"); + return FALSE; + } + + { + char TempName[1024]; + + sprintf(TempName, "WireFrame (D3D)"); + + if (!CreateDDFromName(TempName, &Info)) + return GE_FALSE; + } + + assert(AppInfo.lpDD); + + memset(&DriverCaps, 0, sizeof(DDCAPS)); + DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + if (FAILED(AppInfo.lpDD->GetCaps(&DriverCaps, &HELCaps))) + { + D3DMain_Log("D3DMain_CreateDDFromName: GetCaps failed.\n"); + D3DMain_ShutdownD3D(); + return FALSE; + } + + if (DriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED) + D3DMain_Log(" DDCAPS2_CANRENDERWINDOWED : YES\n"); + else + D3DMain_Log(" DDCAPS2_CANRENDERWINDOWED : NO\n"); + + if (DriverCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) + D3DMain_Log(" DDCAPS2_NO2DDURING3DSCENE : YES\n"); + else + D3DMain_Log(" DDCAPS2_NO2DDURING3DSCENE : NO\n"); + + // Save the DD object + strcpy(AppInfo.DDName, DriverName); + + return TRUE; +} + +//======================================================================================================== +// CreateDDFromDriver +//======================================================================================================== +static geBoolean CreateDDFromDriver(D3D_DRIVER *pDriver) +{ + LPDIRECTDRAW pDD1; + HRESULT hr; + + AppInfo.IsPrimary = pDriver->IsPrimary; + + if (pDriver->IsPrimary) + hr = DirectDrawCreate(NULL, &pDD1, NULL ); + else + hr = DirectDrawCreate(&pDriver->Guid, &pDD1, NULL ); + + if( FAILED( hr ) ) + return GE_FALSE; + + // Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw + // represents the DX6 version of the API. + hr = pDD1->QueryInterface(IID_IDirectDraw4, (VOID**)&AppInfo.lpDD); + + // Don't need this guy anymore + RELEASE(pDD1); + + if(FAILED(hr)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +// CreateDDFromName +//======================================================================================================== +static geBoolean CreateDDFromName(const char *DriverName, const DDEnumInfo *Info) +{ + int32 i; + + for (i=0; i < Info->NumDrivers; i++) + { + if (!strcmp(Info->Drivers[i].Name, DriverName)) + break; + } + + if (i == Info->NumDrivers) + return GE_FALSE; + + // Create the DD object for this driver + if (!CreateDDFromDriver(&Info->Drivers[i])) + return GE_FALSE; + + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/WireFrame/D3d_main.h b/G3D/Engine/Drivers/WireFrame/D3d_main.h new file mode 100644 index 0000000..bae9427 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3d_main.h @@ -0,0 +1,227 @@ +/****************************************************************************************/ +/* D3D_Main.h */ +/* */ +/* Author: John Pollard */ +/* Description: DD/D3D wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3D_MAIN_H +#define D3D_MAIN_H + +#include +#include +#include + +#define INITGUID + +#include "DCommon.h" + +#define MAX_APP_MODES 50 +#define DDMAIN_MAX_D3D_DRIVERS 10 +#define DDMAIN_MAX_TEXTURE_FORMATS 128 +#define DDMAIN_MAX_SURFACE_FORMATS 128 + +#define D3DMAIN_LOG_FILENAME "D3DDrv.Log" + +#define MAX_DRIVER_NAME 1024 + +//================================================================================ +// Structure defs +//================================================================================ + +typedef struct +{ + char Name[MAX_DRIVER_NAME]; // Short name of the driver + char About[MAX_DRIVER_NAME]; // Short string about the driver + D3DDEVICEDESC Desc; // D3DDEVICEDESC for complete information + GUID Guid; // it's GUID + BOOL IsHardware; // does this driver represent a hardware device? + BOOL DoesTextures; // does this driver do texture mapping? + BOOL DoesZBuffer; // can this driver use a z-buffer? + BOOL CanDoWindow; // can it render to Window's display depth? + BOOL DoesTransparency; + BOOL DoesAlpha; + BOOL DoesClamping; + BOOL DoesSrcBlending; + BOOL DoesDestBlending; + + WORD MaxTextureBlendStages; + WORD MaxSimultaneousTextures; + + BOOL CanUse; // We can use this driver +} DDMain_D3DDriver; + +typedef struct +{ + int32 Width; // width + int32 Height; // height + int32 Bpp; // bits per pixel + BOOL ThisDriverCanDo; // == TRUE if d3d driver can render into +} App_Mode; + +typedef struct +{ + DDSURFACEDESC2 ddsd; // DDSURFACEDESC for complete information + BOOL HasOneBitAlpha; + BOOL HasFourBitAlpha; +} DDMain_SurfFormat; + +typedef struct +{ + uint32 R[256]; + uint32 G[256]; + uint32 B[256]; + uint32 A[256]; +} RGB_LUT; + +// App_Info, used for everything global. +typedef struct +{ + // Window info + HWND hWnd; // Handle to parent Window + + DDSURFACEDESC2 ddsd; + + // Mode that we were in before initializing + int32 OldWidth; // Old screen width + int32 OldHeight; + int32 OldBpp; + + int32 CurrentWidth; + int32 CurrentHeight; + int32 CurrentBpp; + + int32 OldWindowWidth; // Old client width + int32 OldWindowHeight; + int32 WindowXOffset; + int32 WindowYOffset; + + RECT OldWindowRect; + ULONG OldGWL_STYLE; + + geBoolean ModeSet; + + char DDName[MAX_DRIVER_NAME]; // Have no idea how big to make this. Anyone? + + LPDIRECTDRAW4 lpDD; // The current initialized DD object + LPDIRECT3D3 lpD3D; // The current initialized D3D object + + LPDIRECTDRAWSURFACE4 lpFrontBuffer; // front buffer surface + LPDIRECTDRAWSURFACE4 lpBackBuffer; // back buffer surface + LPDIRECTDRAWSURFACE4 lpZBuffer; // z-buffer surface + LPDIRECTDRAWCLIPPER lpClipper; // Clipper in windowed case + BOOL BackBufferInVideo; // back buf in video mem? + BOOL ZBufferInVideo; // is Z-buf in video mem? + LPDIRECT3DDEVICE3 lpD3DDevice; // D3D device + LPDIRECT3DVIEWPORT3 lpD3DViewport; // D3D viewport + + LPDIRECT3DMATERIAL3 BackgroundMaterial; + + // 2d surface format (for blt'ing to the display) + DDSURFACEDESC2 ddSurfFormat; // 555 or 565 surface desc + + // Texture formats (for the D3D device) + DDSURFACEDESC2 ddTexFormat; // 555 or 565 surface desc + DDSURFACEDESC2 ddFourBitAlphaSurfFormat; // 4444 surface desc + DDSURFACEDESC2 ddOneBitAlphaSurfFormat; // 1555 surface desc + + RGB_LUT Lut1; + RGB_LUT Lut2; + RGB_LUT Lut3; + + BOOL IsPrimary; // + BOOL FullScreen; + + int32 NumModes; + App_Mode Modes[MAX_APP_MODES]; + + int32 NumDrivers; + DDMain_D3DDriver Drivers[DDMAIN_MAX_D3D_DRIVERS]; + int32 CurrentDriver; + DDDEVICEIDENTIFIER DeviceIdentifier; + + // Surface formats + int32 NumSurfFormats; // Num 2D texture formats avail (from DD4 object) + DDMain_SurfFormat SurfFormats[DDMAIN_MAX_SURFACE_FORMATS]; + + // Texture formats + int32 NumTextureFormats; // Num 3D texture formats avail (from device) + DDMain_SurfFormat TextureFormats[DDMAIN_MAX_TEXTURE_FORMATS]; + + BOOL LogToFile; + BOOL FoundGoodDevice; + BOOL CanDoWindow; + + BOOL RenderingIsOK; + + DWORD VidMemFree; + + geFloat Gamma; + BOOL GammaChanged; + + geBoolean CanDoMultiTexture; + + geBoolean FogEnable; + geFloat FogStart; + geFloat FogEnd; + geFloat FogR; + geFloat FogG; + geFloat FogB; + + // DD / D3D Flags + uint32 Flags; +} App_Info; + +// DD enum strcuture. Used when enuming dd +typedef struct +{ + LPDIRECTDRAW4 lpDD; + char DriverName[MAX_DRIVER_NAME]; + BOOL FoundDD; +} DD_Enum; + +//================================================================================ +// Globals +//================================================================================ +extern App_Info AppInfo; // Our global structure that knows all... (once initialized) + +//================================================================================ +// Global functions +//================================================================================ +BOOL D3DMain_InitD3D(HWND hWnd, const char *DriverName, int32 Width, int32 Height); +BOOL D3DMain_ShutdownD3D(void); +geBoolean D3DMain_Reset(void); +void D3DMain_Log(LPSTR Str, ... ); +BOOL D3DMain_RestoreAllSurfaces(void); + +BOOL Main_EnumTextureFormats(void); +BOOL D3DMain_EnumDisplayModes(void); +BOOL Main_ClearBackBuffer(BOOL Clear, BOOL ClearZ); +BOOL Main_ShowBackBuffer(void); + +BOOL D3DMain_GetSurfaceFormats(void); + +BOOL Main_CheckDD(void); +BOOL D3DMain_GetTextureMemory(void); +void Main_BuildRGBGammaTables(geFloat Gamma); + +BOOL D3DMain_GetClientWindowOffset(HWND hWnd); +geBoolean DRIVERCC D3DMain_UpdateWindow(void); +geBoolean DRIVERCC D3DMain_SetActive(geBoolean wParam); +geBoolean DRIVERCC D3DMain_SetFogEnable(geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/WireFrame/D3dcache.cpp b/G3D/Engine/Drivers/WireFrame/D3dcache.cpp new file mode 100644 index 0000000..769300d --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3dcache.cpp @@ -0,0 +1,785 @@ +/****************************************************************************************/ +/* D3DCache.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include +#include + +#include "D3DCache.h" + +// Cache types are just the different types of textures +// Texutres may vary from width/height/num miplevels/etc... +// Cache types is just a way to combine them to similar types... +#define D3DCACHE_MAX_CACHE_TYPES 128 + +//======================================================================================================== +//======================================================================================================== +typedef struct D3DCache_Type +{ + int32 Log; + int32 Width; // Width/Height + int32 Height; + int32 NumMipLevels; + int32 Stage; + int32 RefCount; // How many references to this cache_type + + DDSURFACEDESC2 ddsd; // DD surface description + + D3DCache_Slot *Slots; // Cache slots for this Cache type + int32 NumUsedSlots; // Number of slots being used + + D3DCache_Type *SelfCheck; + D3DCache *Cache; +} D3DCache_Type; + +typedef struct D3DCache +{ + struct D3DCache *SelfCheck; + + char Name[D3DCACHE_MAX_NAME]; + + LPDIRECTDRAW4 lpDD; // DD object for the cache manager + + DDMemMgr_Partition *Partition; + + geBoolean UseStages; + + D3DCache_Type CacheTypes[D3DCACHE_MAX_CACHE_TYPES]; // CacheTypes +} D3DCache; + +typedef struct D3DCache_Slot +{ + struct D3DCache_Slot *SelfCheck; + + D3DCache_Type *CacheType; + + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this slot + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface + + uint32 LRU; // Current LRU for cache slot + + void *UserData; + +} D3DCache_Slot; + +//======================================================================================================== +//======================================================================================================== + +//======================================================================================================== +// D3DCache_Create +//======================================================================================================== +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW4 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages) +{ + D3DCache *Cache; + + assert(strlen(Name) < D3DCACHE_MAX_NAME); + + Cache = (D3DCache*)malloc(sizeof(D3DCache)); + + if (!Cache) + return NULL; + + memset(Cache, 0, sizeof(D3DCache)); + + Cache->lpDD = lpDD; + + Cache->Partition = Partition; + + Cache->UseStages = UseStages; + + Cache->SelfCheck = Cache; + + strcpy(Cache->Name, Name); + + return Cache; +} + +//======================================================================================================== +// D3DCache_Destroy +//======================================================================================================== +void D3DCache_Destroy(D3DCache *Cache) +{ + assert(Cache); + + D3DCache_FreeAllSlots(Cache); + + free(Cache); +} + +//======================================================================================================== +// D3DCache_IsValid +//======================================================================================================== +geBoolean D3DCache_IsValid(D3DCache *Cache) +{ + if (!Cache) + return GE_FALSE; + + if (Cache->SelfCheck != Cache) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +geBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + for (pCacheType = Cache->CacheTypes, i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + int32 s; + + if (!pCacheType->RefCount) + continue; + + assert(D3DCache_TypeIsValid(pCacheType)); + + for (pSlot = pCacheType->Slots, s=0; sNumUsedSlots; s++, pSlot++) + { + D3DCache_SlotSetUserData(pSlot, NULL); + } + } + + return GE_TRUE; +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + continue; + + assert(D3DCache_TypeIsValid(pCacheType)); + + if (pCacheType->Width != Width) + continue; + if (pCacheType->Height != Height) + continue; + + if (pCacheType->NumMipLevels != NumMipLevels) + continue; + + if (pCacheType->Stage != Stage) + continue; + + if (memcmp(&pCacheType->ddsd, ddsd, sizeof(DDSURFACEDESC2))) + continue; + + return pCacheType; // Found a match + } + + return NULL; // Cache Type not found!!! +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + pCacheType = Cache->CacheTypes; + + for (i=0; iRefCount == 0) // Nobody is using this slot yet + break; + } + + if (i == D3DCACHE_MAX_CACHE_TYPES) // No types left + return NULL; + + assert(pCacheType->Slots == NULL); + assert(pCacheType->NumUsedSlots == 0); + + pCacheType->Width = Width; + pCacheType->Height = Height; + pCacheType->NumMipLevels = NumMipLevels; + pCacheType->Stage = Stage; + pCacheType->ddsd = *ddsd; + + pCacheType->SelfCheck = pCacheType; + pCacheType->Cache = Cache; + + pCacheType->Log = GetLog(Width, Height); + + // Found one + pCacheType->RefCount++; + + return pCacheType; +} + +//======================================================================================================== +//======================================================================================================== +D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd) +{ + D3DCache_Type *CacheType; + + assert(D3DCache_IsValid(Cache)); + + CacheType = D3DCache_FindCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd); + + if (CacheType) + { + CacheType->RefCount++; + return CacheType; + } + + // Could not find one allready in the list, so add a new one... + return D3DCache_InsertCacheType(Cache, Width, Height, NumMipLevels, Stage, ddsd); +} + +//======================================================================================================== +// D3DCache_TypeDestroy +//======================================================================================================== +void D3DCache_TypeDestroy(D3DCache_Type *CacheType) +{ + assert(CacheType->RefCount > 0); + assert(D3DCache_TypeIsValid(CacheType)); + + CacheType->RefCount--; + + if (CacheType->RefCount == 0) + { + if (CacheType->Slots) + { + D3DCache_Slot *pSlot; + int32 k; + + // Go through each slot, and free all the surfaces on them + for (pSlot = CacheType->Slots, k=0; k< CacheType->NumUsedSlots; k++, pSlot++) + { + assert(D3DCache_SlotIsValid(pSlot)); + assert(pSlot->Surface); + assert(pSlot->Texture); + + if (pSlot->Texture) + pSlot->Texture->Release(); + if (pSlot->Surface) + pSlot->Surface->Release(); + } + + free(CacheType->Slots); + CacheType->Slots = NULL; + CacheType->NumUsedSlots = 0; + } + } +} + +//======================================================================================================== +// D3DCache_TypeIsValid +//======================================================================================================== +geBoolean D3DCache_TypeIsValid(D3DCache_Type *Type) +{ + if (!Type) + return GE_FALSE; + + if (Type->SelfCheck != Type) + return GE_FALSE; + + if (!D3DCache_IsValid(Type->Cache)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_FreeAllSlots +//======================================================================================================== +geBoolean D3DCache_FreeAllSlots(D3DCache *Cache) +{ + int32 i; + D3DCache_Type *pCacheType; + + assert(D3DCache_IsValid(Cache)); + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + int32 k; + + assert(pCacheType->RefCount >= 0); + + if (pCacheType->RefCount == 0) + { + assert(pCacheType->Slots == NULL); + continue; + } + + assert(D3DCache_TypeIsValid(pCacheType)); + + // Go through each slot, and free all the surfaces on them + for (pSlot = pCacheType->Slots, k=0; k< pCacheType->NumUsedSlots; k++, pSlot++) + { + assert(D3DCache_SlotIsValid(pSlot)); + assert(pSlot->Surface); + assert(pSlot->Texture); + + if (pSlot->Texture) + pSlot->Texture->Release(); + if (pSlot->Surface) + pSlot->Surface->Release(); + } + + if (pCacheType->Slots) + free(pCacheType->Slots); + + pCacheType->Slots = NULL; + pCacheType->NumUsedSlots = 0; + } + + DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_WriteToFile +//======================================================================================================== +geBoolean D3DCache_WriteToFile(D3DCache *Cache, const char *FileName, geBoolean Append) +{ + int32 i; + D3DCache_Type *pCacheType; + int32 TotalRef, TotalUsed; + SYSTEMTIME Time; + FILE *f; + + if (Append) + f = fopen(FileName, "a+t"); + else + f = fopen(FileName, "w"); + + if (!f) + return GE_FALSE; + + GetSystemTime(&Time); + + fprintf(f, "=======================================================\n"); + fprintf(f, "Date: %i/%i/%i, Time: %i:%i\n", Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute); + fprintf(f, "Cache Name: %s\n", Cache->Name); + fprintf(f, "Total Mem: %5i\n", DDMemMgr_PartitionGetTotalMem(Cache->Partition)); + fprintf(f, "Free Mem: %5i\n", DDMemMgr_PartitionGetFreeMem(Cache->Partition)); + fprintf(f, " --- Slots ---\n"); + + TotalRef = TotalUsed = 0; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (!pCacheType->RefCount) + continue; + + fprintf(f, "Width: %3i, Height %3i, Mips: %2i, Stage: %2i, Ref: %4i, Used: %4i\n", + pCacheType->Width, pCacheType->Height, pCacheType->NumMipLevels, pCacheType->Stage, pCacheType->RefCount, pCacheType->NumUsedSlots); + + TotalRef += pCacheType->RefCount; + TotalUsed += pCacheType->NumUsedSlots; + } + + fprintf(f, "Total Ref: %4i, Total Used: %4i\n", TotalRef, TotalUsed); + + fclose(f); + + return GE_TRUE; +} + +static geBoolean AppendHack = GE_FALSE; + +// HACK!!!! +void D3DMain_Log(LPSTR Str, ... ); +//======================================================================================================== +// D3DCache_AdjustSlots +//======================================================================================================== +geBoolean D3DCache_AdjustSlots(D3DCache *Cache, const int32 *MaxTable, geBoolean UsePartition) +{ + D3DCache_Type *pCacheType; + int32 i, Total, NumPasses; + + assert(D3DCache_IsValid(Cache)); + + D3DCache_FreeAllSlots(Cache); // Just get rid of everything for now... + DDMemMgr_PartitionReset(Cache->Partition); // Reset the caches memory manager + + Total = 0; + NumPasses = 0; + + while(1) + { + D3DCache_Slot *LastSlot; + + LastSlot = NULL; + + pCacheType = Cache->CacheTypes; + + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + D3DCache_Slot *pSlot; + uint32 Size, Width, Height, Result; + + if (pCacheType->RefCount <= 0) + { + assert(pCacheType->Slots == NULL); + continue; + } + + if (pCacheType->NumUsedSlots >= pCacheType->RefCount) + continue; // This is all we need for this slot... + + if (pCacheType->NumUsedSlots >= MaxTable[pCacheType->Log]) + continue; + + if (!pCacheType->Slots) // If no slots have been allocated, allocate them now... + { + pCacheType->Slots = (D3DCache_Slot*)malloc(sizeof(D3DCache_Type)*pCacheType->RefCount); + memset(pCacheType->Slots, 0, sizeof(D3DCache_Type)*pCacheType->RefCount); + } + + Width = pCacheType->Width; + Height = pCacheType->Height; + + Size = Width*Height*(pCacheType->ddsd.ddpfPixelFormat.dwRGBBitCount>>3); // (BitCount/8) + + if (UsePartition) + { + if (!DDMemMgr_PartitionAllocMem(Cache->Partition, Size)) + { + LastSlot = NULL; // Make a complete stop + break; // No more memory in the partition, stop now... + } + } + + pSlot = &pCacheType->Slots[pCacheType->NumUsedSlots]; + pSlot->SelfCheck = pSlot; + + pSlot->CacheType = pCacheType; + + // Allocate surfaces now + Result = D3DCache_SetupSlot(Cache, pSlot, Width, Height, &pCacheType->ddsd, Cache->UseStages, pCacheType->Stage); + + if (!Result) + { + memset(pSlot, 0, sizeof(D3DCache_Slot)); + break; + } + else if (Result == -1) + { + D3DMain_Log("D3DCache_AdjustSlots: D3DCache_SetupSlot failed.\n"); + return GE_FALSE; + } + + pCacheType->NumUsedSlots++; + Total++; + + LastSlot = pSlot; + } + + NumPasses++; + + if (!LastSlot) // Nothing was allocated on that pass, so assume we are out of memory + break; + } + + pCacheType = Cache->CacheTypes; + + // Go through one last time, and make sure all got allocated + for (i=0; i< D3DCACHE_MAX_CACHE_TYPES; i++, pCacheType++) + { + if (pCacheType->RefCount <= 0) + { + assert(pCacheType->Slots == NULL); + continue; + } + + if (pCacheType->NumUsedSlots <= 0) + { + D3DMain_Log("D3DCache_AdjustSlots: Out of ram creating surfaces for cache.\n"); + D3DMain_Log("D3DCache_AdjustSlots: Pick a display mode with a smaller resolution.\n"); + return GE_FALSE; // Not all slots with refs got a texture + } + + assert(pCacheType->Slots != NULL); + } + + D3DCache_WriteToFile(Cache, "D3DCache.Log", AppendHack); + AppendHack = GE_TRUE; + + return GE_TRUE; +} + +//======================================================================================================== +// D3DCache_SlotIsValid +//======================================================================================================== +geBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot) +{ + if (!Slot) + return GE_FALSE; + + if (Slot->SelfCheck != Slot) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// D3DCache_SetupSlot +// +// Returns -1 on failure +// Returns 0 on out of memory +// Returns 1 on success +//===================================================================================== +int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, geBoolean UseStage, int32 Stage) +{ + LPDIRECTDRAWSURFACE4 Surface; + DDSURFACEDESC2 ddsd; + HRESULT Hr; + + assert(D3DCache_IsValid(Cache)); + assert(D3DCache_SlotIsValid(Slot)); + + memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + + if (UseStage) + ddsd.dwFlags |= DDSD_TEXTURESTAGE; + + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_HINTDYNAMIC; + ddsd.ddsCaps.dwCaps3 = 0; + ddsd.ddsCaps.dwCaps4 = 0; + ddsd.dwHeight = Width; + ddsd.dwWidth = Height; + + ddsd.dwTextureStage = Stage; + + Hr = Cache->lpDD->CreateSurface(&ddsd, &Surface, NULL); + + if(Hr != DD_OK) + { + if (Hr == DDERR_OUTOFVIDEOMEMORY) + { + return 0; + } + + return -1; + } + + Slot->Surface = Surface; + + // Set the color key +#if 0 + { + DDCOLORKEY CKey; + + // Create the color key for this surface + CKey.dwColorSpaceLowValue = 1; + CKey.dwColorSpaceHighValue = 1; + + if (Slot->Surface->SetColorKey(DDCKEY_SRCBLT , &CKey) != DD_OK) + { + Slot->Surface->Release(); + Slot->Surface = NULL; + return -1; + } + } + #endif + + Hr = Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Slot->Texture); + + if(Hr != DD_OK) + { + Surface->Release(); + return -1; + } + + return 1; // All good dude +} + + +//======================================================================================================== +// D3DCache_TypeFindSlot +//======================================================================================================== +D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType) +{ + D3DCache_Slot *pBestSlot, *pSlot; + uint32 BestLRU; + int32 i; + + assert(D3DCache_TypeIsValid(CacheType)); + + assert(CacheType->Slots); + + pSlot = CacheType->Slots; + pBestSlot = pSlot; + BestLRU = pBestSlot->LRU; + + for (i=0; i< CacheType->NumUsedSlots; i++, pSlot++) + { + assert(D3DCache_SlotIsValid(pSlot)); + + if (pSlot->LRU < BestLRU) + { + pBestSlot = pSlot; + BestLRU = pSlot->LRU; + } + } + + pBestSlot->LRU = 0; + pBestSlot->UserData = NULL; + + return pBestSlot; +} + +//======================================================================================================== +// D3DCache_SlotSetUserData +//======================================================================================================== +void D3DCache_SlotSetUserData(D3DCache_Slot *Slot, void *UserData) +{ + assert(D3DCache_SlotIsValid(Slot)); + + Slot->UserData = UserData; +} + +//======================================================================================================== +// D3DCache_SlotGetUserData +//======================================================================================================== +void *D3DCache_SlotGetUserData(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->UserData; +} + +//======================================================================================================== +// D3DCache_SlotSetLRU +//======================================================================================================== +void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU) +{ + assert(D3DCache_SlotIsValid(Slot)); + + Slot->LRU = LRU; +} + +//======================================================================================================== +// D3DCache_SlotGetLRU +//======================================================================================================== +uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->LRU; +} + +LPDIRECT3DTEXTURE2 D3DCache_SlotGetTexture(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->Texture; +} + +LPDIRECTDRAWSURFACE4 D3DCache_SlotGetSurface(D3DCache_Slot *Slot) +{ + assert(D3DCache_SlotIsValid(Slot)); + + return Slot->Surface; +} + +//===================================================================================== +// Log2 +// Return the log of a size +//===================================================================================== +uint32 Log2(uint32 P2) +{ + uint32 p = 0; + int32 i = 0; + + for (i = P2; i > 0; i>>=1) + p++; + + return (p-1); +} + +//===================================================================================== +// SnapToPower2 +// Snaps a number to a power of 2 +//===================================================================================== +int32 SnapToPower2(int32 Width) +{ +#if 1 + if (Width > 0 && Width <= 1) Width = 1; + else if (Width > 1 && Width <= 2) Width = 2; + else if (Width > 2 && Width <= 4) Width = 4; + else if (Width > 4 && Width <= 8) Width = 8; + else if (Width > 8 && Width <= 16) Width =16; + else if (Width > 16 && Width <= 32) Width = 32; + else if (Width > 32 && Width <= 64) Width = 64; + else if (Width > 64 && Width <= 128) Width = 128; + else if (Width > 128 && Width <= 256) Width = 256; + else + return -1; +#else + + if (Width > 1 && Width <= 8) Width = 8; + else if (Width > 8 && Width <= 16) Width =16; + else if (Width > 16 && Width <= 32) Width = 32; + else if (Width > 32 && Width <= 64) Width = 64; + else if (Width > 64 && Width <= 128) Width = 128; + else if (Width > 128 && Width <= 256) Width = 256; + else + return -1; +#endif + + return Width; +} + +//===================================================================================== +// Return the max log of a (power of 2) width and height +//===================================================================================== +int32 GetLog(int32 Width, int32 Height) +{ + int32 LWidth = SnapToPower2(max(Width, Height)); + + return Log2(LWidth); +} + diff --git a/G3D/Engine/Drivers/WireFrame/D3dcache.h b/G3D/Engine/Drivers/WireFrame/D3dcache.h new file mode 100644 index 0000000..f7a1481 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3dcache.h @@ -0,0 +1,64 @@ +/****************************************************************************************/ +/* D3DCache.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3DCache_H +#define D3DCache_H + +#include +#include +#include + +#include "BaseType.h" +#include "DDMemMgr.h" + +#define D3DCACHE_MAX_NAME 256 + +typedef struct D3DCache D3DCache; +typedef struct D3DCache_Type D3DCache_Type; +typedef struct D3DCache_Slot D3DCache_Slot; + +D3DCache *D3DCache_Create(const char *Name, LPDIRECTDRAW4 lpDD, DDMemMgr_Partition *Partition, geBoolean UseStages); +void D3DCache_Destroy(D3DCache *Cache); +geBoolean D3DCache_IsValid(D3DCache *Cache); +geBoolean D3DCache_EvictAllSurfaces(D3DCache *Cache); +D3DCache_Type *D3DCache_FindCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +D3DCache_Type *D3DCache_InsertCacheType(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +D3DCache_Type *D3DCache_TypeCreate(D3DCache *Cache, int32 Width, int32 Height, int32 NumMipLevels, int32 Stage, const DDSURFACEDESC2 *ddsd); +void D3DCache_TypeDestroy(D3DCache_Type *CacheType); +geBoolean D3DCache_TypeIsValid(D3DCache_Type *Type); +geBoolean D3DCache_FreeAllSlots(D3DCache *Cache); +geBoolean D3DCache_AdjustSlots(D3DCache *Cache, const int32 *MaxTable, geBoolean UsePartition); +geBoolean D3DCache_SlotIsValid(D3DCache_Slot *Slot); +int32 D3DCache_SetupSlot(D3DCache *Cache, D3DCache_Slot *Slot, int32 Width, int32 Height, const DDSURFACEDESC2 *SurfDesc, geBoolean UseStage, int32 Stage); +D3DCache_Slot *D3DCache_TypeFindSlot(D3DCache_Type *CacheType); +void D3DCache_SlotSetUserData(D3DCache_Slot *Slot, void *UserData); +void *D3DCache_SlotGetUserData(D3DCache_Slot *Slot); +void D3DCache_SlotSetLRU(D3DCache_Slot *Slot, uint32 LRU); +uint32 D3DCache_SlotGetLRU(D3DCache_Slot *Slot); +LPDIRECT3DTEXTURE2 D3DCache_SlotGetTexture(D3DCache_Slot *Slot); +LPDIRECTDRAWSURFACE4 D3DCache_SlotGetSurface(D3DCache_Slot *Slot); + +uint32 Log2(uint32 P2); +int32 SnapToPower2(int32 Width); +int32 GetLog(int32 Width, int32 Height); + +#endif + diff --git a/G3D/Engine/Drivers/WireFrame/D3ddrv.cpp b/G3D/Engine/Drivers/WireFrame/D3ddrv.cpp new file mode 100644 index 0000000..2c78242 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3ddrv.cpp @@ -0,0 +1,368 @@ +/****************************************************************************************/ +/* D3DDrv.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" + +#include "Scene.h" +#include "Render.h" +#include "D3DCache.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "THandle.h" + + +DRV_Window ClientWindow; +BOOL ExitHandlerActive = FALSE; + +int32 LastError; +char LastErrorStr[200]; + +geBoolean DRIVERCC DrvShutdown(void); +geBoolean DRIVERCC ScreenShot(const char *Name); + +BOOL DRIVERCC DrvInit(DRV_DriverHook *Hook) +{ + RECT WRect; + + // Start up + if (!D3DMain_InitD3D(Hook->hWnd, Hook->DriverName+5, Hook->Width, Hook->Height)) + { + //SetLastDrvError(DRV_ERROR_INIT_ERROR, "D3D_DrvInit: Could not init driver.\n"); + return FALSE; + } + + // If they are asking for a window mode, use there hWnd for the size + if (Hook->Width ==-1 && Hook->Height == -1) + { + GetClientRect(Hook->hWnd, &WRect); + + Hook->Width = (WRect.right - WRect.left); + Hook->Height = (WRect.bottom - WRect.top); + } + + ClientWindow.Width = Hook->Width; + ClientWindow.Height = Hook->Height; + ClientWindow.hWnd = Hook->hWnd; + + return TRUE; +} + +//============================================================================================ +//============================================================================================ +BOOL DRIVERCC DrvShutdown(void) +{ + D3DMain_ShutdownD3D(); + return TRUE; +} + +//============================================================================================ +// DrvResetAll +//============================================================================================ +geBoolean DRIVERCC DrvResetAll(void) +{ + return D3DMain_Reset(); +} + +geRDriver_PixelFormat PixelFormat[10]; + +#define NUM_PIXEL_FORMATS (sizeof(PixelFormats)/sizeof(geRDriver_PixelFormat)) + +geBoolean DRIVERCC EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context) +{ + int32 i; + gePixelFormat Format3d, Format2d; + uint32 CurrentBpp; + + CurrentBpp = AppInfo.ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Setup the 2d surface format + if (CurrentBpp == 32 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwRGBAlphaBitMask == 0xff000000) + Format2d = GE_PIXELFORMAT_32BIT_ARGB; + else if (CurrentBpp == 32 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwBBitMask == 0xff) + Format2d = GE_PIXELFORMAT_32BIT_XRGB; + else if (CurrentBpp == 24 && AppInfo.ddSurfFormat.ddpfPixelFormat.dwBBitMask == 0xff) + Format2d = GE_PIXELFORMAT_24BIT_RGB; + else if (AppInfo.ddSurfFormat.ddpfPixelFormat.dwGBitMask == (31<<5)) + Format2d = GE_PIXELFORMAT_16BIT_555_RGB; + else + Format2d = GE_PIXELFORMAT_16BIT_565_RGB; + + // Setup the 3d (Texture) format + if (AppInfo.ddTexFormat.ddpfPixelFormat.dwGBitMask == (31<<5)) + Format3d = GE_PIXELFORMAT_16BIT_555_RGB; + else + Format3d = GE_PIXELFORMAT_16BIT_565_RGB; + + + // Create the surface formats now + PixelFormat[0].PixelFormat = Format3d; // 3d 565/555 surface + PixelFormat[0].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + PixelFormat[1].PixelFormat = GE_PIXELFORMAT_16BIT_4444_ARGB; // 3d 4444 surface + PixelFormat[1].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + PixelFormat[2].PixelFormat = Format2d; // 2d 565/555 surface + PixelFormat[2].Flags = RDRIVER_PF_2D | RDRIVER_PF_CAN_DO_COLORKEY; + + PixelFormat[3].PixelFormat = Format3d; // Lightmap 565/555 surface + PixelFormat[3].Flags = RDRIVER_PF_LIGHTMAP; + + PixelFormat[4].PixelFormat = GE_PIXELFORMAT_16BIT_1555_ARGB; + PixelFormat[4].Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + + // Then hand them off to the caller + for (i=0; i<5; i++) + { + if (!Cb(&PixelFormat[i], Context)) + return GE_TRUE; + } + + return TRUE; +} + +geBoolean DRIVERCC SetGamma(geFloat Gamma) +{ + return GE_TRUE; +} + +geBoolean DRIVERCC GetGamma(geFloat *Gamma) +{ + *Gamma = 1.0f; + + return GE_TRUE; +} + +BOOL DRIVERCC EnumSubDrivers2(DRV_ENUM_DRV_CB *Cb, void *Context); +BOOL DRIVERCC EnumModes2(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context); + +DRV_Driver D3DDRV = +{ + "D3D driver. v"DRV_VMAJS"."DRV_VMINS". Copyright 1999, WildTangent Inc.; All Rights Reserved.", + DRV_VERSION_MAJOR, + DRV_VERSION_MINOR, + + DRV_ERROR_NONE, + NULL, + + EnumSubDrivers2, + EnumModes2, + + EnumPixelFormats, + + DrvInit, + DrvShutdown, + DrvResetAll, + D3DMain_UpdateWindow, + D3DMain_SetActive, + + THandle_Create, + THandle_Destroy, + + THandle_Lock, + THandle_UnLock, + + NULL, // SetPal + NULL, // GetPal + + NULL, // SetAlpha + NULL, // GetAlpha + + THandle_GetInfo, + + BeginScene, + EndScene, + BeginWorld, + EndWorld, + BeginMeshes, + EndMeshes, + BeginModels, + EndModels, + + RenderGouraudPoly, + RenderWorldPoly, + RenderMiscTexturePoly, + + DrawDecal, + + 0,0,0, + + &CacheInfo, + + ScreenShot, + + SetGamma, + GetGamma, + + D3DMain_SetFogEnable, + + NULL, + NULL, // Init to NULL, engine SHOULD set this (SetupLightmap) + NULL +}; + +DRV_EngineSettings EngineSettings; + +DllExport BOOL DriverHook(DRV_Driver **Driver) +{ + EngineSettings.CanSupportFlags = (DRV_SUPPORT_ALPHA | DRV_SUPPORT_COLORKEY); + EngineSettings.PreferenceFlags = 0;//DRV_PREFERENCE_NO_MIRRORS; + + D3DDRV.EngineSettings = &EngineSettings; + + *Driver = &D3DDRV; + + // Make sure the error string ptr is not null, or invalid!!! + D3DDRV.LastErrorStr = LastErrorStr; + + SetLastDrvError(DRV_ERROR_NONE, "D3DDrv: No error."); + + return TRUE; +} + +void SetLastDrvError(int32 Error, char *ErrorStr) +{ + LastError = Error; + + if (ErrorStr) + { + strcpy(LastErrorStr, ErrorStr); + } + else + LastErrorStr[0] = NULL; + + D3DDRV.LastErrorStr = LastErrorStr; + D3DDRV.LastError = LastError; +} + +// eaa3 05/31/2000 Added Orf's Direct3D screenshot code to the driver +// ..so we can get SCREENSHOTS out of both Glide and D3d. + +BOOL DRIVERCC ScreenShot(const char *Name) +{ + DDSURFACEDESC2 ddsd; + BITMAPFILEHEADER bfh; + BITMAPINFOHEADER bih; + HRESULT result; + HDC surfDC = NULL; + HDC memDC = NULL; + HBITMAP bitmap = NULL; + HBITMAP oldbit = NULL; + FILE *file = NULL; + void *data= NULL; + int width, height, bpp; + int datasize; + BOOL success = FALSE; + + memset(&ddsd,0,sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + result = AppInfo.lpBackBuffer->GetSurfaceDesc(&ddsd); + if(FAILED(result)) + goto cleanup; + + width = ddsd.dwWidth; + height= ddsd.dwHeight; + bpp = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + + if(bpp < 2) + bpp = 2; + if(bpp > 3) + bpp = 3; + + datasize = width * bpp * height; + if(width * bpp % 4) + datasize += height * (4 - width * bpp % 4); + + memset((void*)&bfh, 0, sizeof(bfh)); + bfh.bfType = 'B'+('M'<<8); + bfh.bfSize = sizeof(bfh) + sizeof(bih) + datasize; + bfh.bfOffBits = sizeof(bfh) + sizeof(bih); + memset((void*)&bih, 0, sizeof(bih)); + bih.biSize = sizeof(bih); + bih.biWidth = ddsd.dwWidth; + bih.biHeight = ddsd.dwHeight; + bih.biPlanes = 1; + bih.biBitCount = bpp * 8; + bih.biCompression = BI_RGB; + result = AppInfo.lpBackBuffer->GetDC(&surfDC); + + if(FAILED(result)) + goto cleanup; + + bitmap = CreateDIBSection(NULL, (BITMAPINFO *)&bih, DIB_RGB_COLORS, + &data, NULL, 0); + + if(!bitmap) + goto cleanup; + if(!data) + goto cleanup; + + memDC = CreateCompatibleDC(surfDC); + if(!memDC) + goto cleanup; + + oldbit = (HBITMAP)SelectObject(memDC, bitmap); + if(!oldbit || FAILED(oldbit)) + goto cleanup; + + result = BitBlt(memDC, 0, 0, width, height, surfDC, 0, 0, SRCCOPY); + if(!result) + goto cleanup; + + AppInfo.lpBackBuffer->ReleaseDC(surfDC); + surfDC = NULL; + + file = fopen(Name, "wb"); + + if(!file) + goto cleanup; + + fwrite((void*)&bfh, sizeof(bfh), 1, file); + fwrite((void*)&bih, sizeof(bih), 1, file); + fwrite((void*)data, 1, datasize, file); + + success = TRUE; + +cleanup: + + if(oldbit && !FAILED(oldbit)) + SelectObject(memDC, oldbit); + + if(memDC) + DeleteDC(memDC); + + if(surfDC) + AppInfo.lpBackBuffer->ReleaseDC(surfDC); + + if(bitmap) + DeleteObject(bitmap); + + if(file) + fclose(file); + + return success; + +} + + diff --git a/G3D/Engine/Drivers/WireFrame/D3ddrv.h b/G3D/Engine/Drivers/WireFrame/D3ddrv.h new file mode 100644 index 0000000..e18fdac --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3ddrv.h @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* D3DDrv.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef D3DDRV_H +#define D3DDRV_H + +#include "DCommon.h" + +extern DRV_Window ClientWindow; +extern DRV_Driver D3DDRV; + +void DRIVERCC ErrorBox(char *Str); +BOOL DRIVERCC DrvShutdown(void); +void SetLastDrvError(int32 Error, char *ErrorStr); + +#endif diff --git a/G3D/Engine/Drivers/WireFrame/DDMemMgr.c b/G3D/Engine/Drivers/WireFrame/DDMemMgr.c new file mode 100644 index 0000000..d5979e6 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/DDMemMgr.c @@ -0,0 +1,195 @@ +/****************************************************************************************/ +/* DDMemMgr.c */ +/* */ +/* Author: John Pollard */ +/* Description: Mini D3D memory manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "BaseType.h" +#include "DDMemMgr.h" + +#define DDMEMMGR_MAX_PARTITIONS 16 + +typedef struct DDMemMgr_Partition +{ + geBoolean Active; + uint32 FreeMem; + uint32 TotalMem; + +} DDMemMgr_Partition; + +typedef struct DDMemMgr +{ + uint32 TotalMem; + uint32 FreeMem; + DDMemMgr_Partition Partitions[DDMEMMGR_MAX_PARTITIONS]; +} DDMemMgr; + +//============================================================================ +// DDMemMgr_Create +//============================================================================ +DDMemMgr *DDMemMgr_Create(uint32 Size) +{ + DDMemMgr *MemMgr; + + MemMgr = (DDMemMgr*)malloc(sizeof(DDMemMgr)); + + if (!MemMgr) + return NULL; + + memset(MemMgr, 0, sizeof(DDMemMgr)); + + MemMgr->TotalMem = Size; + MemMgr->FreeMem = Size; + + return MemMgr; +} + +//============================================================================ +// DDMemMgr_Destroy +//============================================================================ +void DDMemMgr_Destroy(DDMemMgr *MemMgr) +{ + assert(MemMgr); + + free(MemMgr); +} + +//============================================================================ +// DDMemMgr_Reset +//============================================================================ +void DDMemMgr_Reset(DDMemMgr *MemMgr) +{ + int32 i; + + assert(MemMgr); + + MemMgr->FreeMem = MemMgr->TotalMem; + + for (i=0; iPartitions[i], 0, sizeof(DDMemMgr_Partition)); +} + +//============================================================================ +// DDMemMgr_GetFreeMem +//============================================================================ +uint32 DDMemMgr_GetFreeMem(DDMemMgr *MemMgr) +{ + assert(MemMgr); + return MemMgr->FreeMem; +} + +//============================================================================ +// DDMemMgr_PartitionCreate +//============================================================================ +DDMemMgr_Partition *DDMemMgr_PartitionCreate(DDMemMgr *MemMgr, uint32 Size) +{ + int32 i; + DDMemMgr_Partition *pPartition; + + assert(MemMgr); + + if (Size > MemMgr->FreeMem) + return NULL; + + pPartition = MemMgr->Partitions; + + for (i=0; i< DDMEMMGR_MAX_PARTITIONS; i++, pPartition++) + { + if (!pPartition->Active) + { + assert(pPartition->TotalMem == 0); + assert(pPartition->FreeMem == 0); + + pPartition->TotalMem = Size; + pPartition->FreeMem = Size; + pPartition->Active = GE_TRUE; + + MemMgr->FreeMem -= Size; + + assert(MemMgr->FreeMem >= 0); + + return pPartition; + } + } + + return NULL; +} + +//============================================================================ +// DDMemMgr_PartitionDestroy +//============================================================================ +void DDMemMgr_PartitionDestroy(DDMemMgr_Partition *Partition) +{ + assert(Partition); + assert(Partition->Active); + + memset(Partition, 0, sizeof(DDMemMgr_Partition)); +} + +//============================================================================ +// DDMemMgr_PartitionReset +//============================================================================ +void DDMemMgr_PartitionReset(DDMemMgr_Partition *Partition) +{ + assert(Partition->Active); + assert(Partition->FreeMem >= 0); + + Partition->FreeMem = Partition->TotalMem; +} + +//============================================================================ +// DDMemMgr_PArtitionGetTotalMem +//============================================================================ +uint32 DDMemMgr_PartitionGetTotalMem(DDMemMgr_Partition *Partition) +{ + assert(Partition); + assert(Partition->TotalMem >= 0); + + return Partition->TotalMem; +} + +//============================================================================ +// DDMemMgr_PArtitionGetFreeMem +//============================================================================ +uint32 DDMemMgr_PartitionGetFreeMem(DDMemMgr_Partition *Partition) +{ + assert(Partition); + assert(Partition->FreeMem >= 0); + + return Partition->FreeMem; +} + +//============================================================================ +// DDMemMgr_PartitionAllocMem +//============================================================================ +geBoolean DDMemMgr_PartitionAllocMem(DDMemMgr_Partition *Partition, uint32 Size) +{ + assert(Partition->Active); + + if (Partition->FreeMem < Size) + return GE_FALSE; + + Partition->FreeMem -= Size; + + assert(Partition->FreeMem >= 0); + + return GE_TRUE; +} diff --git a/G3D/Engine/Drivers/WireFrame/DDMemMgr.h b/G3D/Engine/Drivers/WireFrame/DDMemMgr.h new file mode 100644 index 0000000..a575f73 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/DDMemMgr.h @@ -0,0 +1,51 @@ +/****************************************************************************************/ +/* DDMemMgr.h */ +/* */ +/* Author: John Pollard */ +/* Description: Mini D3D memory manager */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DDMEMMGR_H +#define DDMEMMGR_H + +#include +#include + +#include "BaseType.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DDMemMgr DDMemMgr; +typedef struct DDMemMgr_Partition DDMemMgr_Partition; + +DDMemMgr *DDMemMgr_Create(uint32 Size); +void DDMemMgr_Destroy(DDMemMgr *MemMgr); +void DDMemMgr_Reset(DDMemMgr *MemMgr); +uint32 DDMemMgr_GetFreeMem(DDMemMgr *MemMgr); +DDMemMgr_Partition *DDMemMgr_PartitionCreate(DDMemMgr *MemMgr, uint32 Size); +void DDMemMgr_PartitionDestroy(DDMemMgr_Partition *Partition); +void DDMemMgr_PartitionReset(DDMemMgr_Partition *Partition); +uint32 DDMemMgr_PartitionGetTotalMem(DDMemMgr_Partition *Partition); +uint32 DDMemMgr_PartitionGetFreeMem(DDMemMgr_Partition *Partition); +geBoolean DDMemMgr_PartitionAllocMem(DDMemMgr_Partition *Partition, uint32 Size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/G3D/Engine/Drivers/WireFrame/Gspan.cpp b/G3D/Engine/Drivers/WireFrame/Gspan.cpp new file mode 100644 index 0000000..c4eda43 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/Gspan.cpp @@ -0,0 +1,281 @@ +/****************************************************************************************/ +/* GSpan.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Front to back span code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "GSpan.h" + +SPAN SpanLines[MAX_SPAN_LINES]; + +SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +SLIST ScanHash[MAX_SPANS]; // hash table for SList + +BOOL PolyVisible = FALSE; + +int32 NumWorldPixels = 0; +int32 NumSpans = 0; +int32 NumSpanPixels[MAX_SPAN_LINES]; +int32 PolysRendered = 0; + +int32 CurrentSList = 0; + +const int32 CEIL_FRACT = ( ( 1 << 16)-1); +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2) +{ + int32 Ctmp; + int32 y; + int32 x,m; + + int32 ydelta; + int32 Dir; + int32 Cx1, Cx2, Cy1, Cy2; + SPAN *pSpans; + + Cx1 = x1; + Cx2 = x2; + Cy1 = y1; + Cy2 = y2; + + if (Cy2 != Cy1) // This isn't a horizontal line + { + Dir =0; // Left side + + if (Cy2 < Cy1) // Make sure y2 is greater than y1 + { + Dir =1; // Right side + + Ctmp = Cx1; + Cx1 = Cx2; + Cx2 = Ctmp; + + Ctmp = Cy1; + Cy1 = Cy2; + Cy2 = Ctmp; + + } + + ydelta = (Cy2 - Cy1); + + x = (Cx1 << 16) + CEIL_FRACT; // Allign on int amounts + m = (((Cx2 - Cx1))<<16) / ydelta; // How much to increase x each iteration + + pSpans = &SpanLines[Cy1]; + + if (!Dir) + { + for (y = Cy1; y <= Cy2; y++, pSpans++) + { + pSpans->x1 = (x>>16); + x += m; // Add our constant to x + } + } + else + { + for (y = Cy1; y <= Cy2; y++, pSpans++) + { + pSpans->x2 = (x>>16); + x += m; // Add our constant to x + } + } + } +} + +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y) +{ + int32 i, xx2; + SLIST *LineStart; + SLIST *Current; + SPAN_MINMAX *pSList; + + assert(y >=0 && y < MAX_SPAN_LINES); + + if (NumSpanPixels[y] >= ClientWindow.Width) + return; + + if (x1 > x2) // Swap all the coordinates so x1 < x2 + { + i = x1; + x1 = x2; + x2 = i; + } + + //if ( (x2 - x1) < 0) + // return; // Invalid line + + Current = SMinMax[y].First; + + LineStart = NULL; + + pSList = &SMinMax[y]; + + // Check to see if there are spans + // in the list yet... + if (!pSList->First) + { + pSList->First = NewSList(); + pSList->First->Last = NULL; + pSList->First->Next = NULL; + pSList->First->Min = x1; + pSList->First->Max = x2; + } + else while (Current != NULL) + { + if (x1 >= Current->Min && x2 <= Current->Max) + return; // This line totally hidden... + + //if falls before the entire min, max + if (LineStart == NULL) + { + if (Current == pSList->First) + if (x2 < Current->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current; + NewMinMax->Last = NULL; + Current->Last = NewMinMax; + pSList->First = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if falls in the middle (but not touching) + if (Current->Next != NULL) + if (x1 > Current->Max && x2 < (Current->Next)->Min) + { + SLIST *NewMinMax = NewSList(); + NewMinMax->Next = Current->Next; + NewMinMax->Last = Current; + Current->Next->Last = NewMinMax; + Current->Next = NewMinMax; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + // if it falls to the right of all spans + if (Current->Next == NULL) + if (x1 > Current->Max) + { + SLIST *NewMinMax = NewSList(); + Current->Next = NewMinMax; + NewMinMax->Next = NULL; + NewMinMax->Last = Current; + NewMinMax->Min = x1; + NewMinMax->Max = x2; + goto WasNull; + } + } + //if we have already started crossing spans, and we find out + // that we are in front of a span, then we can bail out... + if (LineStart != NULL) + if (x2 < Current->Min) + goto WasNull; + + + // We now know that we have not fallen into any empty holes. + // We must now check to see what spans, we've crossed... + + // if split by a min/max + if (x1 < Current->Min && x2 > Current->Max) + { + xx2 = Current->Min-1; + Current->Min = x1; + + NumWorldPixels += xx2 - x1 + 1; + NumSpanPixels[y] += xx2 - x1 + 1; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + x1 = Current->Max+1; + Current->Max = x2; + if (LineStart!=NULL) + LineStart->Max = x2; + else + LineStart = Current; + goto next; + } + + if (x1 <= Current->Max && x2 > Current->Max) + { + x1 = Current->Max+1; + Current->Max = x2; + LineStart = Current; + goto next; + } + if (x1 < Current->Min && x2 >= Current->Min) + { + x2 = Current->Min-1; + Current->Min = x1; + if (LineStart!=NULL) + LineStart->Max = Current->Max; + goto WasNull; + } + next:; + Current = Current->Next; + } + WasNull:; + + if (!PolyVisible) + { + PolysRendered++; + PolyVisible = 1; + } + + NumWorldPixels += x2 - x1 + 1; + NumSpanPixels[y] += x2 - x1 + 1; +} + +void ResetSList(void) +{ + CurrentSList = 0; + NumSpans = 0; +} + +SLIST *NewSList(void) +{ + + CurrentSList++; + NumSpans++; + + assert(CurrentSList < MAX_SPANS); + + return &ScanHash[CurrentSList-1]; + + return NULL; +} + +void ResetSpans(int32 Rows) +{ + int32 i; + + for (i=0; i + +#define MAX_SPAN_LINES 1024 +#define MAX_SPANS 35000 + +typedef struct +{ + int32 x1; // Starting x on screen + int32 x2; // Ending x on screen +} SPAN; + +typedef struct _SList +{ + int32 Min, Max; + uint8 Used; + uint32 Flags; + _SList *Last; + _SList *Next; +} SLIST; + +typedef struct +{ + SLIST *First; + SLIST *Current; +} SPAN_MINMAX; + +extern SPAN SpanLines[MAX_SPAN_LINES]; + +extern SPAN_MINMAX SMinMax[MAX_SPAN_LINES]; // Linked list of spans for each scanline... +extern SLIST ScanHash[MAX_SPANS]; // hash table for SList + +extern int32 NumWorldPixels; +extern int32 NumSpans; +extern int32 NumSpanPixels[MAX_SPAN_LINES]; +extern int32 PolysRendered; + +void DRIVERCC EdgeOutNoUV (int32 x1, int32 y1, int32 x2, int32 y2); +void DRIVERCC AddSpanNoUV(int32 x1, int32 x2, int32 y); + +void ResetSList(void); +SLIST *NewSList(void); +void ResetSpans(int32 Rows); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/WireFrame/Pcache.cpp b/G3D/Engine/Drivers/WireFrame/Pcache.cpp new file mode 100644 index 0000000..11c269e --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/Pcache.cpp @@ -0,0 +1,1445 @@ +/****************************************************************************************/ +/* PCache.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D poly cache */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DCache.h" +#include "D3D_Fx.h" + +#include "PCache.h" +#include "D3DDrv.h" +#include "THandle.h" +#include "D3D_Err.h" + + +//#define D3D_MANAGE_TEXTURES +//#define SUPER_FLUSH + +//==================================================================================== +// Local static variables +//==================================================================================== + +DRV_CacheInfo CacheInfo; + +// +// World Cache +// + +#if 1 + +#define MAX_WORLD_POLYS 512 +#define MAX_WORLD_POLY_VERTS 2048 + +#define MAX_MISC_POLYS 512 +#define MAX_MISC_POLY_VERTS 2048 + +#else + +#define MAX_WORLD_POLYS 256 +#define MAX_WORLD_POLY_VERTS 4096 + +#define MAX_MISC_POLYS 256 +#define MAX_MISC_POLY_VERTS 4096 + +#endif + +typedef struct +{ + geFloat u; + geFloat v; + //geFloat a; + uint32 Color; +} PCache_TVert; + +typedef struct +{ + geRDriver_THandle *THandle; + + DRV_LInfo *LInfo; // Original pointer to linfo + uint32 Flags; // Flags for this poly + geFloat ShiftU; + geFloat ShiftV; + geFloat ScaleU; + geFloat ScaleV; + int32 MipLevel; + uint32 SortKey; + int32 FirstVert; + int32 NumVerts; +} World_Poly; + +#define MAX_TEXTURE_STAGES 2 // Up to 2 tmu's (stages) + +// Verts we defined in the D3D flexible vertex format (FVF) +// This is a transformed and lit vertex definition, with up to 8 sets of uvs +typedef struct +{ + geFloat u,v; +} PCache_UVSet; + +typedef struct +{ + geFloat x,y,z; // Screen x, y, z + geFloat rhw; // homogenous w + DWORD color; // color + DWORD specular; + PCache_UVSet uv[MAX_TEXTURE_STAGES]; // uv sets for each stage +} PCache_Vert; + +typedef struct +{ + World_Poly Polys[MAX_WORLD_POLYS]; + World_Poly *SortedPolys[MAX_WORLD_POLYS]; + World_Poly *SortedPolys2[MAX_WORLD_POLYS]; + PCache_Vert Verts[MAX_WORLD_POLY_VERTS]; + + PCache_TVert TVerts[MAX_WORLD_POLY_VERTS]; // Original uv + + int32 NumPolys; + int32 NumPolys2; + int32 NumVerts; +} World_Cache; + +static World_Cache WorldCache; + +#define PREP_WORLD_VERTS_NORMAL 1 // Prep verts as normal +#define PREP_WORLD_VERTS_LMAP 2 // Prep verts as lightmaps +#define PREP_WORLD_VERTS_SINGLE_PASS 3 // Prep verts for a single pass + +#define RENDER_WORLD_POLYS_NORMAL 1 // Render polys as normal +#define RENDER_WORLD_POLYS_LMAP 2 // Render polys as lightmaps +#define RENDER_WORLD_POLYS_SINGLE_PASS 3 + +// +// Misc cache +// + +typedef struct +{ + geRDriver_THandle *THandle; + uint32 Flags; // Flags for this poly + int32 MipLevel; + int32 FirstVert; + int32 NumVerts; + + uint32 SortKey; +} Misc_Poly; + +typedef struct +{ + Misc_Poly Polys[MAX_MISC_POLYS]; + Misc_Poly *SortedPolys[MAX_MISC_POLYS]; + PCache_Vert Verts[MAX_MISC_POLY_VERTS]; + //geFloat ZVert[MAX_MISC_POLY_VERTS]; + + int32 NumPolys; + int32 NumVerts; +} Misc_Cache; + +static Misc_Cache MiscCache; + +//==================================================================================== +// Local static functions prototypes +//==================================================================================== +geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2); + +static BOOL RenderWorldPolys(int32 RenderMode); +static BOOL ClearWorldCache(void); +static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, geFloat ScaleU, geFloat ScaleV, int32 MaxMipLevel); + +#include + +//==================================================================================== +// PCache_InsertWorldPoly +//==================================================================================== +BOOL PCache_InsertWorldPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ + int32 Mip; + geFloat ZRecip, DrawScaleU, DrawScaleV; + World_Poly *pCachePoly; + DRV_TLVertex *pVerts; + PCache_TVert *pTVerts; + PCache_Vert *pD3DVerts; + int32 i; + uint32 Alpha; + + #ifdef _DEBUG + if (LInfo) + { + assert(LInfo->THandle); + } + #endif + + if ((WorldCache.NumVerts + NumVerts) >= MAX_WORLD_POLY_VERTS) + { + // If the cache is full, we must flush it before going on... + if (!PCache_FlushWorldPolys()) + return GE_FALSE; + } + else if (WorldCache.NumPolys+1 >= MAX_WORLD_POLYS) + { + // If the cache is full, we must flush it before going on... + if (!PCache_FlushWorldPolys()) + return GE_FALSE; + } + + DrawScaleU = 1.0f / TexInfo->DrawScaleU; + DrawScaleV = 1.0f / TexInfo->DrawScaleV; + + Mip = GetMipLevel(Verts, NumVerts, DrawScaleU, DrawScaleV, THandle->NumMipLevels-1); + + // Get a pointer to the original polys verts + pVerts = Verts; + + // Store info about this poly in the cache + pCachePoly = &WorldCache.Polys[WorldCache.NumPolys]; + + pCachePoly->THandle = THandle; + pCachePoly->LInfo = LInfo; + pCachePoly->Flags = Flags; + pCachePoly->FirstVert = WorldCache.NumVerts; + pCachePoly->NumVerts = NumVerts; + pCachePoly->ShiftU = TexInfo->ShiftU; + pCachePoly->ShiftV = TexInfo->ShiftV; + pCachePoly->ScaleU = DrawScaleU; + pCachePoly->ScaleV = DrawScaleV; + pCachePoly->MipLevel = Mip; + + // Don't forget the sort key: + pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip; + + // Get a pointer into the world verts + pD3DVerts = &WorldCache.Verts[WorldCache.NumVerts]; + pTVerts = &WorldCache.TVerts[WorldCache.NumVerts]; + + if (Flags & DRV_RENDER_ALPHA) + Alpha = (uint32)pVerts->a<<24; + else + Alpha = (uint32)(255<<24); + + for (i=0; i< NumVerts; i++) + { + ZRecip = 1.0f/(pVerts->z); + + pD3DVerts->x = pVerts->x; + pD3DVerts->y = pVerts->y; + + pD3DVerts->z = (1.0f - ZRecip); // ZBUFFER + pD3DVerts->rhw = ZRecip; + + if (AppInfo.FogEnable) + { + DWORD FogVal; + geFloat Val; + + Val = pVerts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DVerts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DVerts->specular = 0; + + // Store the uv's so the prep pass can use them... + pTVerts->u = pVerts->u; + pTVerts->v = pVerts->v; + + pTVerts->Color = Alpha | ((uint32)pVerts->r<<16) | ((uint32)pVerts->g<<8) | (uint32)pVerts->b; + + pTVerts++; + pVerts++; + pD3DVerts++; + + } + + // Update globals about the world poly cache + WorldCache.NumVerts += NumVerts; + WorldCache.NumPolys++; + + return TRUE; +} + +//==================================================================================== +// PCache_FlushWorldPolys +//==================================================================================== +BOOL PCache_FlushWorldPolys(void) +{ + if (!WorldCache.NumPolys) + return TRUE; + + if (!THandle_CheckCache()) + return GE_FALSE; + + if (AppInfo.CanDoMultiTexture) + { + RenderWorldPolys(RENDER_WORLD_POLYS_SINGLE_PASS); + } + else + { + // Render them as normal + if (!RenderWorldPolys(RENDER_WORLD_POLYS_NORMAL)) + return GE_FALSE; + + // Render them as lmaps + RenderWorldPolys(RENDER_WORLD_POLYS_LMAP); + } + + ClearWorldCache(); + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +static int MiscBitmapHandleComp(const void *a, const void *b) +{ + uint32 Id1, Id2; + + Id1 = (uint32)(*(Misc_Poly**)a)->SortKey; + Id2 = (uint32)(*(Misc_Poly**)b)->SortKey; + + if ( Id1 == Id2) + return 0; + + if (Id1 < Id2) + return -1; + + return 1; +} + +//==================================================================================== +//==================================================================================== +static void SortMiscPolysByHandle(void) +{ + Misc_Poly *pPoly; + int32 i; + + pPoly = MiscCache.Polys; + + for (i=0; iTHandle; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + Size = 1<Log; + + Lut = &AppInfo.Lut1; + + THandle_Lock(THandle, 0, (void**)&pTempBits); + + Extra = Size - Width; + U8 R, G, B; + U16 Color; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + THandle_UnLock(THandle, 0); +} + +#ifdef USE_TPAGES +//===================================================================================== +// FillLMapSurface +//===================================================================================== +static void FillLMapSurface2(DRV_LInfo *LInfo, int32 LNum) +{ + U16 *pTempBits; + int32 w, h, Width, Height, Stride; + U8 *pBitPtr; + RGB_LUT *Lut; + geRDriver_THandle *THandle; + HRESULT Result; + const RECT *pRect; + DDSURFACEDESC2 SurfDesc; + LPDIRECTDRAWSURFACE4 Surface; + int32 Extra; + + THandle = LInfo->THandle; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + + Lut = &AppInfo.Lut1; + + pRect = TPage_BlockGetRect(THandle->Block); + Surface = TPage_BlockGetSurface(THandle->Block); + + memset(&SurfDesc, 0, sizeof(DDSURFACEDESC2)); + SurfDesc.dwSize = sizeof(DDSURFACEDESC2); + + Result = Surface->Lock((RECT*)pRect, &SurfDesc, DDLOCK_WAIT, NULL); + + assert(Result == DD_OK); + + Stride = SurfDesc.dwWidth; + + pTempBits = (U16*)SurfDesc.lpSurface; + + Extra = Stride - Width; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + U8 R, G, B; + U16 Color; + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + Result = Surface->Unlock((RECT*)pRect); + + assert(Result == DD_OK); +} +#endif + +//===================================================================================== +// LoadLMapFromSystem +//===================================================================================== +static void LoadLMapFromSystem(DRV_LInfo *LInfo, int32 Log, int32 LNum) +{ + U16 *pTempBits; + int32 w, h, Width, Height, Size, Extra; + U8 *pBitPtr; + LPDIRECTDRAWSURFACE4 Surface; + RGB_LUT *Lut; + DDSURFACEDESC2 ddsd; + HRESULT ddrval; + + pBitPtr = (U8*)LInfo->RGBLight[LNum]; + + Width = LInfo->Width; + Height = LInfo->Height; + Size = 1<Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + + assert(ddrval == DD_OK); + U8 R, G, B; + U16 Color; + + pTempBits = (USHORT*)ddsd.lpSurface; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + R = *pBitPtr++; + G = *pBitPtr++; + B = *pBitPtr++; + + Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]); + + *pTempBits++ = Color; + } + pTempBits += Extra; + } + + ddrval = Surface->Unlock(NULL); + assert(ddrval == DD_OK); +} + +static BOOL IsKeyDown(int KeyCode) +{ + if (GetAsyncKeyState(KeyCode) & 0x8000) + return TRUE; + + return FALSE; +} + +extern uint32 CurrentLRU; + +//===================================================================================== +// SetupMipData +//===================================================================================== +geBoolean SetupMipData(THandle_MipData *MipData) +{ + if (!MipData->Slot || D3DCache_SlotGetUserData(MipData->Slot) != MipData) + { + MipData->Slot = D3DCache_TypeFindSlot(MipData->CacheType); + assert(MipData->Slot); + + D3DCache_SlotSetUserData(MipData->Slot, MipData); + + #ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + #endif + + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// SetupLMap +//===================================================================================== +geBoolean SetupLMap(int32 Stage, DRV_LInfo *LInfo, int32 LNum, geBoolean Dynamic) +{ +#ifdef D3D_MANAGE_TEXTURES + #ifdef USE_TPAGES + { + geRDriver_THandle *THandle; + + THandle = LInfo->THandle; + + if (Dynamic) + THandle->Flags |= THANDLE_UPDATE; + + if (!THandle->Block) + { + THandle->Block = TPage_MgrFindOptimalBlock(TPageMgr, CurrentLRU); + THandle->Flags |= THANDLE_UPDATE; + TPage_BlockSetUserData(THandle->Block, THandle); + assert(THandle->Block); + } + else if (TPage_BlockGetUserData(THandle->Block) != THandle) + { + // Find another block + THandle->Block = TPage_MgrFindOptimalBlock(TPageMgr, CurrentLRU); + assert(THandle->Block); + + THandle->Flags |= THANDLE_UPDATE; + TPage_BlockSetUserData(THandle->Block, THandle); + } + + if (THandle->Flags & THANDLE_UPDATE) + FillLMapSurface2(LInfo, LNum); + + TPage_BlockSetLRU(THandle->Block, CurrentLRU); + D3DSetTexture(Stage, TPage_BlockGetTexture(THandle->Block)); + + if (Dynamic) + THandle->Flags |= THANDLE_UPDATE; + else + THandle->Flags &= ~THANDLE_UPDATE; + + return GE_TRUE; + } + #else + { + geRDriver_THandle *THandle; + + THandle = LInfo->THandle; + + if (Dynamic) + THandle->MipData[0].Flags |= THANDLE_UPDATE; + + if (THandle->MipData[0].Flags & THANDLE_UPDATE) + FillLMapSurface(LInfo, LNum); + + D3DSetTexture(Stage, THandle->MipData[0].Texture); + + if (Dynamic) + THandle->MipData[0].Flags |= THANDLE_UPDATE; + else + THandle->MipData[0].Flags &= ~THANDLE_UPDATE; + + return GE_TRUE; + } + #endif + +#else + geRDriver_THandle *THandle; + THandle_MipData *MipData; + + THandle = LInfo->THandle; + MipData = &THandle->MipData[0]; + + if (Dynamic) + MipData->Flags |= THANDLE_UPDATE; + + if (!SetupMipData(MipData)) + { + MipData->Flags |= THANDLE_UPDATE; // Force an upload + CacheInfo.LMapMisses++; + } + + if (MipData->Flags & THANDLE_UPDATE) + { + HRESULT Error; + LPDIRECTDRAWSURFACE4 Surface; + + assert(MipData->Slot); + + Surface = D3DCache_SlotGetSurface(MipData->Slot); + + assert(Surface); + assert(THandle->Log < MAX_LMAP_LOG_SIZE); + assert(SystemToVideo[THandle->Log].Surface); + + LoadLMapFromSystem(LInfo, THandle->Log, LNum); + + Error = Surface->BltFast(0, 0, SystemToVideo[THandle->Log].Surface, NULL, DDBLTFAST_WAIT); + //Error = Surface->BltFast(0, 0, SystemToVideo[THandle->Log].Surface, NULL, 0); + //Error = Surface->Blt(NULL, SystemToVideo[THandle->Log].Surface, NULL, DDBLT_WAIT, NULL); + //Error = Surface->Blt(NULL, SystemToVideo[THandle->Log].Surface, NULL, 0, NULL); + + if (Error != DD_OK) + { + if(Error==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return GE_FALSE; + } + else + { + D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error)); + return GE_FALSE; + } + } + } + + if (Dynamic) // If it was dynmamic, force an update for one more frame + MipData->Flags |= THANDLE_UPDATE; + else + MipData->Flags &= ~THANDLE_UPDATE; + + D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU); + D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot)); + + return GE_TRUE; +#endif +} + +//===================================================================================== +// SetupTexture +//===================================================================================== +geBoolean SetupTexture(int32 Stage, geRDriver_THandle *THandle, int32 MipLevel) +{ +#ifdef D3D_MANAGE_TEXTURES + D3DSetTexture(Stage, THandle->MipData[MipLevel].Texture); + return GE_TRUE; +#else + THandle_MipData *MipData; + + MipData = &THandle->MipData[MipLevel]; + + if (!SetupMipData(MipData)) + { + MipData->Flags |= THANDLE_UPDATE; // Force an upload + CacheInfo.TexMisses++; + } + + if (MipData->Flags & THANDLE_UPDATE) + { + HRESULT Error; + LPDIRECTDRAWSURFACE4 Surface; + + Surface = D3DCache_SlotGetSurface(MipData->Slot); + + Error = Surface->BltFast(0, 0, MipData->Surface, NULL, DDBLTFAST_WAIT); + + if (Error != DD_OK) + { + if(Error==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return FALSE; + } + else + { + D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error)); + return GE_FALSE; + } + } + } + + MipData->Flags &= ~THANDLE_UPDATE; + + D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU); + D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot)); + + return GE_TRUE; +#endif +} + +//==================================================================================== +// PCache_FlushMiscPolys +//==================================================================================== +BOOL PCache_FlushMiscPolys(void) +{ + int32 i; + Misc_Poly *pPoly; + + if (!MiscCache.NumPolys) + return TRUE; + + if (!THandle_CheckCache()) + return GE_FALSE; + + // Set the render states + if (AppInfo.CanDoMultiTexture) + { + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + D3DSetTexture(1, NULL); // Reset texture stage 1 + } + + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + D3DBlendEnable(TRUE); + + // Sort the polys by handle + SortMiscPolysByHandle(); + + for (i=0; i< MiscCache.NumPolys; i++) + { + pPoly = MiscCache.SortedPolys[i]; + + if (pPoly->Flags & DRV_RENDER_NO_ZMASK) // We are assuming that this is not going to change all that much + D3DZEnable(FALSE); + else + D3DZEnable(TRUE); + + if (pPoly->Flags & DRV_RENDER_NO_ZWRITE) // We are assuming that this is not going to change all that much + D3DZWriteEnable(FALSE); + else + D3DZWriteEnable(TRUE); + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(0, FALSE); + else + D3DTexWrap(0, TRUE); + + if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + D3DTexturedPoly(&MiscCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + } + + // Turn z stuff back on... + D3DZWriteEnable (TRUE); + D3DZEnable(TRUE); + + MiscCache.NumPolys = 0; + MiscCache.NumVerts = 0; + +#ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); +#endif + + return TRUE; +} + +//==================================================================================== +// PCache_InsertMiscPoly +//==================================================================================== +BOOL PCache_InsertMiscPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, uint32 Flags) +{ + int32 Mip; + geFloat ZRecip, u, v, ScaleU, ScaleV, InvScale; + Misc_Poly *pCachePoly; + DRV_TLVertex *pVerts; + PCache_Vert *pD3DVerts; + int32 i, SAlpha; + + if ((MiscCache.NumVerts + NumVerts) >= MAX_MISC_POLY_VERTS) + { + // If the cache is full, we must flush it before going on... + PCache_FlushMiscPolys(); + } + else if (MiscCache.NumPolys+1 >= MAX_MISC_POLYS) + { + // If the cache is full, we must flush it before going on... + PCache_FlushMiscPolys(); + } + + Mip = GetMipLevel(Verts, NumVerts, (geFloat)THandle->Width, (geFloat)THandle->Height, THandle->NumMipLevels-1); + + // Store info about this poly in the cache + pCachePoly = &MiscCache.Polys[MiscCache.NumPolys]; + + pCachePoly->THandle = THandle; + pCachePoly->Flags = Flags; + pCachePoly->FirstVert = MiscCache.NumVerts; + pCachePoly->NumVerts = NumVerts; + pCachePoly->MipLevel = Mip; + pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip; + + // Get scale value for vertices + //TCache_GetUVInvScale(Bitmap, Mip, &InvScale); + InvScale = 1.0f / (geFloat)((1<Log)); + + // Convert them to take account that the vertices are allready from 0 to 1 + ScaleU = (geFloat)THandle->Width * InvScale; + ScaleV = (geFloat)THandle->Height * InvScale; + + // Precompute the alpha value... + SAlpha = ((int32)Verts->a)<<24; + + // Get a pointer to the original polys verts + pVerts = Verts; + // Get a pointer into the world verts + pD3DVerts = &MiscCache.Verts[MiscCache.NumVerts]; + + for (i=0; i< NumVerts; i++) + { + ZRecip = 1/(pVerts->z); + + pD3DVerts->x = pVerts->x; + pD3DVerts->y = pVerts->y; + + pD3DVerts->z = (1.0f - ZRecip); // ZBUFFER + pD3DVerts->rhw = ZRecip; + + u = pVerts->u * ScaleU; + v = pVerts->v * ScaleV; + + pD3DVerts->uv[0].u = u; + pD3DVerts->uv[0].v = v; + + pD3DVerts->color = SAlpha | ((int32)pVerts->r<<16) | ((int32)pVerts->g<<8) | (int32)pVerts->b; + + if (AppInfo.FogEnable) // We might get hit on this first "if" but it should predict pretty well in the rest of the tight loop + { + DWORD FogVal; + geFloat Val; + + Val = pVerts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DVerts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DVerts->specular = 0; + + pVerts++; + pD3DVerts++; + } + + // Update globals about the misc poly cache + MiscCache.NumVerts += NumVerts; + MiscCache.NumPolys++; + + return TRUE; +} + +//==================================================================================== +// **** LOCAL STATIC FUNCTIONS ***** +//==================================================================================== + +//==================================================================================== +// World_PolyPrepVerts +//==================================================================================== +geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2) +{ + geFloat InvScale, u, v; + PCache_TVert *pTVerts; + PCache_Vert *pVerts; + geFloat ShiftU, ShiftV, ScaleU, ScaleV; + geFloat InvScale2, ShiftU2, ShiftV2; + int32 j; + + switch (PrepMode) + { + case PREP_WORLD_VERTS_NORMAL: + { + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + + ShiftU = pPoly->ShiftU; + ShiftV = pPoly->ShiftV; + ScaleU = pPoly->ScaleU; + ScaleV = pPoly->ScaleV; + + // Get scale value for vertices + InvScale = 1.0f / (geFloat)((1<THandle->Log)); + + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u*ScaleU+ShiftU; + v = pTVerts->v*ScaleV+ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + pVerts->color = pTVerts->Color; + + pTVerts++; + pVerts++; + } + + break; + } + + case PREP_WORLD_VERTS_LMAP: + { + if (!pPoly->LInfo) + return GE_TRUE; + + ShiftU = (geFloat)-pPoly->LInfo->MinU + 8.0f; + ShiftV = (geFloat)-pPoly->LInfo->MinV + 8.0f; + + // Get scale value for vertices + InvScale = 1.0f/(geFloat)((1<LInfo->THandle->Log)<<4); + + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u + ShiftU; + v = pTVerts->v + ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + pVerts->color = 0xffffffff; + + pTVerts++; + pVerts++; + } + break; + } + + case PREP_WORLD_VERTS_SINGLE_PASS: + { + + assert(pPoly->LInfo); + + pTVerts = &WorldCache.TVerts[pPoly->FirstVert]; + + // Set up shifts and scaled for texture uv's + ShiftU = pPoly->ShiftU; + ShiftV = pPoly->ShiftV; + ScaleU = pPoly->ScaleU; + ScaleV = pPoly->ScaleV; + + // Get scale value for vertices + InvScale = 1.0f / (geFloat)((1<THandle->Log)); + + // Set up shifts and scaled for lightmap uv's + ShiftU2 = (geFloat)-pPoly->LInfo->MinU + 8.0f; + ShiftV2 = (geFloat)-pPoly->LInfo->MinV + 8.0f; + InvScale2 = 1.0f/(geFloat)((1<LInfo->THandle->Log)<<4); + + pVerts = &WorldCache.Verts[pPoly->FirstVert]; + + for (j=0; j< pPoly->NumVerts; j++) + { + u = pTVerts->u*ScaleU+ShiftU; + v = pTVerts->v*ScaleV+ShiftV; + + pVerts->uv[Stage1].u = u * InvScale; + pVerts->uv[Stage1].v = v * InvScale; + + u = pTVerts->u + ShiftU2; + v = pTVerts->v + ShiftV2; + + pVerts->uv[Stage2].u = u * InvScale2; + pVerts->uv[Stage2].v = v * InvScale2; + + pVerts->color = pTVerts->Color; + + pTVerts++; + pVerts++; + } + + break; + } + + default: + return FALSE; + } + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +static int BitmapHandleComp(const void *a, const void *b) +{ + int32 Id1, Id2; + + Id1 = (*(World_Poly**)a)->SortKey; + Id2 = (*(World_Poly**)b)->SortKey; + + if ( Id1 == Id2) + return 0; + + if (Id1 < Id2) + return -1; + + return 1; +} + +//==================================================================================== +//==================================================================================== +static void SortWorldPolysByHandle(void) +{ + World_Poly *pPoly; + int32 i; + + pPoly = WorldCache.Polys; + + for (i=0; iSetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); + + // Set the default state for the normal poly render mode for the world + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + // Get the first poly in the sorted list + SortWorldPolysByHandle(); + + for (i=0; i< WorldCache.NumPolys; i++) + { + pPoly = WorldCache.SortedPolys[i]; + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(0, FALSE); + else + D3DTexWrap(0, TRUE); + + if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, 0, 0); + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + } + + break; + } + + case RENDER_WORLD_POLYS_LMAP: + { + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); + + D3DTexWrap(0, FALSE); + + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO); + + pPoly = WorldCache.Polys; + BOOL Dynamic = 0; + + for (i=0; i< WorldCache.NumPolys; i++, pPoly++) + { + + if (!pPoly->LInfo) + continue; + + // Call the engine to set this sucker up, because it's visible... + D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic); + + if (!SetupLMap(0, pPoly->LInfo, 0, Dynamic)) + return GE_FALSE; + + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_LMAP, 0, 0); + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + if (pPoly->LInfo->RGBLight[1]) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE); + + D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE); // Change to a fog state + + // For some reason, some cards can't upload data to the same texture twice, and have it take. + // So we force Fog maps to use a different slot than the lightmap was using... + pPoly->LInfo->THandle->MipData[0].Slot = NULL; + + if (!SetupLMap(0, pPoly->LInfo, 1, 1)) // Dynamic is 1, because fog is always dynamic + return GE_FALSE; + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO); // Restore state + + if (AppInfo.FogEnable) + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + } + } + break; + } + + case RENDER_WORLD_POLYS_SINGLE_PASS: + { + // Setup texture stage states + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT ); + //AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + + // Setup frame buffer blend modes + D3DBlendEnable(TRUE); + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + // Set the default state for the normal poly render mode for the world + D3DTexWrap(TSTAGE_0, TRUE); + D3DTexWrap(TSTAGE_1, FALSE); + + // Sort the list for front back operation to get the least number of world texture misses + SortWorldPolysByHandle(); + + // Reset non lightmaps faces to 0 + WorldCache.NumPolys2 = 0; + + for (i=0; i< WorldCache.NumPolys; i++) + { + BOOL Dynamic = 0; + + pPoly = WorldCache.SortedPolys[i]; + + if (!pPoly->LInfo) + { + // Put gouraud only polys in a seperate list, and render last + WorldCache.SortedPolys2[WorldCache.NumPolys2++] = pPoly; + continue; + } + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(TSTAGE_0, FALSE); + else + D3DTexWrap(TSTAGE_0, TRUE); + + if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + // Call the engine to set this sucker up, because it's visible... + D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic); + + if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 0, Dynamic)) + return GE_FALSE; + + // Prep the verts for a lightmap and texture map + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_SINGLE_PASS, TSTAGE_0, TSTAGE_1); + + // Draw the texture + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + // Render any fog maps + if (pPoly->LInfo->RGBLight[1]) + { + D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE); // Change to a fog state + + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + #endif + + // For some reason, some cards can't upload data to the same texture twice, and have it take. + // So we force Fog maps to use a different slot other than what the lightmap was using... + pPoly->LInfo->THandle->MipData[0].Slot = NULL; + + if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 1, 1)) // Dynamic is 1, because fog is always dynamic + return GE_FALSE; + + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + + // Restore states to the last state before fag map + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + #endif + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + } + + + } + + // Setup for any non-lightmaped faces faces, turn tmu1 off + #if (TSTAGE_0 == 0) + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE); + AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + #else + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + #endif + + // Render all the faces without lightmaps + for (i=0; i< WorldCache.NumPolys2; i++) + { + BOOL Dynamic = 0; + + pPoly = WorldCache.SortedPolys2[i]; + + if (pPoly->Flags & DRV_RENDER_CLAMP_UV) + D3DTexWrap(TSTAGE_0, FALSE); + else + D3DTexWrap(TSTAGE_0, TRUE); + + if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel)) + return GE_FALSE; + + // Prep verts as if there was no lightmap + World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, TSTAGE_0, TSTAGE_1); + + // Draw the texture + D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts); + } + + break; + } + + default: + return FALSE; + } + + + return TRUE; +} + +//==================================================================================== +// ClearWorldCache +//==================================================================================== +static BOOL ClearWorldCache(void) +{ + WorldCache.NumPolys = 0; + WorldCache.NumVerts = 0; + + return TRUE; +} + +//==================================================================================== +//==================================================================================== +BOOL PCache_Reset(void) +{ + WorldCache.NumPolys = 0; + WorldCache.NumVerts = 0; + + MiscCache.NumPolys = 0; + MiscCache.NumVerts = 0; + + return TRUE; +} + +//==================================================================================== +// GetMipLevel +//==================================================================================== +static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, geFloat ScaleU, geFloat ScaleV, int32 MaxMipLevel) +{ + int32 Mip; + + if (MaxMipLevel == 0) + return 0; + + // + // Get the MipLevel + // + { + geFloat du, dv, dx, dy, MipScale; + + #if 1 // WAY slower, but more accurate + int32 i; + + MipScale = 999999.0f; + + geFloat MipScaleT; + DRV_TLVertex *pVert0, *pVert1; + int32 i2; + + for (i=0; i< NumVerts; i++) + { + + i2 = i+1; + + if (i2 >= NumVerts) + i2=0; + + pVert0 = &Verts[i]; + pVert1 = &Verts[i2]; + + du = pVert1->u - pVert0->u; + dv = pVert1->v - pVert0->v; + dx = pVert1->x - pVert0->x; + dy = pVert1->y - pVert0->y; + + du *= ScaleU; + dv *= ScaleV; + + MipScaleT = ((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy)); + + if (MipScaleT < MipScale) + MipScale = MipScaleT; // Record the best MipScale (the one closest to the the eye) + } + #else // Faster, less accurate + du = Verts[1].u - Verts[0].u; + dv = Verts[1].v - Verts[0].v; + dx = Verts[1].x - Verts[0].x; + dy = Verts[1].y - Verts[0].y; + + du *= ScaleU; + dv *= ScaleV; + + MipScale = ((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy)); + #endif + + #if 0 + if (MipScale <= 5) // 2, 6, 12 + Mip = 0; + else if (MipScale <= 20) + Mip = 1; + else if (MipScale <= 45) + Mip = 2; + else + Mip = 3; + #else + if (MipScale <= 4) // 2, 6, 12 + Mip = 0; + else if (MipScale <= 15) + Mip = 1; + else if (MipScale <= 40) + Mip = 2; + else + Mip = 3; + #endif + } + + if (Mip > MaxMipLevel) + Mip = MaxMipLevel; + + return Mip; +} \ No newline at end of file diff --git a/G3D/Engine/Drivers/WireFrame/Pcache.h b/G3D/Engine/Drivers/WireFrame/Pcache.h new file mode 100644 index 0000000..5e55574 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/Pcache.h @@ -0,0 +1,35 @@ +/****************************************************************************************/ +/* PCache.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D poly cache */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef PCACHE_H +#define PCACHE_H + +extern DRV_CacheInfo CacheInfo; + +BOOL PCache_InsertWorldPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +BOOL PCache_FlushWorldPolys(void); + +BOOL PCache_FlushMiscPolys(void); +BOOL PCache_InsertMiscPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, uint32 Flags); + +BOOL PCache_Reset(void); + +#endif diff --git a/G3D/Engine/Drivers/WireFrame/Readme.now b/G3D/Engine/Drivers/WireFrame/Readme.now new file mode 100644 index 0000000..735c1fc --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/Readme.now @@ -0,0 +1,22 @@ +D3DDRV.DLL MIPMAP SELECTION MODIFICATION +by Ed Averill, Rabid Games +11/03/1999 + + Here is the modified PCACHE.CPP and the release-compiled +D3DDRV.DLL. This driver has a modification to take the AVERAGE +of all polygon edges and perform MIP selection computation on +this average, instead of the shipping drivers computation based +on only the first edge in the list. This driver appears to +remove most MIP artifacts, at least in the levels I've tested +it with. + + BE SURE TO BACK UP YOUR OLD DRIVER IN CASE THIS ONE +DOESN'T WORK FOR YOU!!!! There may be a small loss in frame +rate as more detailed MIPS are selected more often than with +the original driver. Note that my bias is in favor of visual +accuracy at the cost of frame-rate, your mileage may vary, +this offer void where prohibited by law, all the usual +disclaimers apply. When in doubt, Use the Source, Luke. + +Ed Averill, Rabid Games +http://www.rabidgames.com diff --git a/G3D/Engine/Drivers/WireFrame/Render.cpp b/G3D/Engine/Drivers/WireFrame/Render.cpp new file mode 100644 index 0000000..cf1621f --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/Render.cpp @@ -0,0 +1,316 @@ +/****************************************************************************************/ +/* Render.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render polys under D3D */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" +#include "Render.h" +#include "Scene.h" +#include "GSpan.h" +#include "D3D_Fx.h" +#include "D3DCache.h" +#include "D3D_Err.h" +#include "THandle.h" + +#include "PCache.h" + +#define SNAP_VERT(v) ( ( v ) = ( geFloat )( ( long )( ( v ) * 16 ) ) / 16.0f ) + +geBoolean DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags) +{ + int32 i; + DRV_TLVertex *pPnts; + D3DTLVERTEX D3DPnts[30], *pD3DPnts; + geFloat ZRecip; + geFloat Alpha; + + if(!AppInfo.RenderingIsOK) + return TRUE; + + if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + if (!PCache_FlushMiscPolys()) + return FALSE; + } + + Alpha = Pnts->a; + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + D3DSetTexture(0, NULL); + + int32 SAlpha = (int32)Alpha<<24; + pPnts = Pnts; + pD3DPnts = D3DPnts; + for (i=0; i< NumPoints; i++) + { + ZRecip = 1/pPnts->z; + + pD3DPnts->sx = pPnts->x; + pD3DPnts->sy = pPnts->y; + pD3DPnts->sz = (1.0f - ZRecip); // ZBUFFER + pD3DPnts->rhw = ZRecip; + pD3DPnts->color = SAlpha | ((int32)pPnts->r<<16) | ((int32)pPnts->g<<8) | (int32)pPnts->b; + + if (AppInfo.FogEnable) + { + DWORD FogVal; + geFloat Val; + + Val = pPnts->z; + + if (Val > AppInfo.FogEnd) + Val = AppInfo.FogEnd; + + FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f); + + if (FogVal < 0) + FogVal = 0; + else if (FogVal > 255) + FogVal = 255; + + pD3DPnts->specular = (FogVal<<24); // Alpha component in specular is the fog value (0...255) + } + else + pD3DPnts->specular = 0; + + pPnts++; + pD3DPnts++; + } + + D3DTexturedPolyOld(D3DPnts, NumPoints); + + if (Flags & DRV_RENDER_FLUSH) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + } + + return TRUE; +} + +geBoolean DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ +#ifdef USE_SPANS + int32 i; + DRV_TLVertex *CPnt; + int32 OldPixels; + int32 Mip = 0; + int32 MinY, MaxY, MinX, MaxX; + int32 FirstX, FirstY, x1, y1, x2, y2; + SPAN *pSpans; + int32 WidthHeight; +#endif + + if(!AppInfo.RenderingIsOK) + { + return TRUE; + } + else if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + } + +#ifdef USE_SPANS + if (RenderMode != RENDER_WORLD) + goto NotWorld; + + CPnt = Pnts; // Set to the first points in the array + + x1 = (int32)CPnt->x; + y1 = (int32)CPnt->y; + + FirstX = MinX = MaxX = x1; + FirstY = MinY = MaxY = y1; + + for (i = 1; i < NumPoints; i++) + { + CPnt++; + + x2 = (int32)CPnt->x; + y2 = (int32)CPnt->y; + + EdgeOutNoUV (x1, y1, x2, y2); + + if (x2 > MaxX) + MaxX = x2; + else if (x2 < MinX) + MinX = x2; + + if (y2 > MaxY) + MaxY = y2; + else if (y2 < MinY) + MinY = y2; + + // Swap + x1 = x2; + y1 = y2; + } + + // Close the poly + EdgeOutNoUV (x1, y1, FirstX, FirstY); + + OldPixels = NumWorldPixels; + + pSpans = &SpanLines[MinY]; + + WidthHeight = ClientWindow.Width*ClientWindow.Height; + for (i = MinY; i <= MaxY; i++, pSpans++) + { + AddSpanNoUV(pSpans->x1, pSpans->x2, i); + + if (NumWorldPixels >= WidthHeight) + break; + } + + if ((MaxY - MinY) < 3) + goto NotWorld; + + if ((MaxX - MinX) < 3) + goto NotWorld; + + if (NumWorldPixels == OldPixels) + return TRUE; + + NotWorld:; +#endif + + D3DDRV.NumRenderedPolys++; + + // Insert the poly into the world cache, for later rendering + PCache_InsertWorldPoly(Pnts, NumPoints, THandle, TexInfo, LInfo, Flags); + + if (Flags & DRV_RENDER_FLUSH) + { + if (!PCache_FlushWorldPolys()) + return FALSE; + } + + return TRUE; +} + +geBoolean DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags) +{ + if(!AppInfo.RenderingIsOK) + { + return TRUE; + } + else if (Flags & DRV_RENDER_FLUSH) + { + PCache_FlushMiscPolys(); + } + + PCache_InsertMiscPoly(Pnts, NumPoints, THandle, Flags); + + if (Flags & DRV_RENDER_FLUSH) + { + PCache_FlushMiscPolys(); + } + + return TRUE; +} + +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) +{ + RECT SRect2, *pSRect; + int32 Width, Height; + HRESULT ddrval; + + if(!AppInfo.RenderingIsOK) + return TRUE; + + if (!SRect) + { + SRect2.left = 0; + SRect2.right = THandle->Width; + SRect2.top = 0; + SRect2.bottom = THandle->Height; + pSRect = &SRect2; + Width = (THandle->Width); + Height = (THandle->Height); + } + else + { + pSRect = SRect; + Width = (pSRect->right - pSRect->left)+1; + Height = (pSRect->bottom - pSRect->top)+1; + } + + if (x + Width <= 0) + return TRUE; + if (y + Height <= 0) + return TRUE; + + if (x >= ClientWindow.Width) + return TRUE; + + if (y >= ClientWindow.Height) + return TRUE; + + if (x + Width >= (ClientWindow.Width-1)) + pSRect->right -= ((x + Width) - (ClientWindow.Width-1)); + if (y + Height >= (ClientWindow.Height-1)) + pSRect->bottom -= ((y + Height) - (ClientWindow.Height-1)); + + if (x < 0) + { + pSRect->left += -x; + x=0; + } + if (y < 0) + { + pSRect->top += -y; + y=0; + } + +#if 0 + AppInfo.lpBackBuffer->BltFast(x, y, THandle->MipData[0].Surface, pSRect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); +#else + RECT DRect; + + Width = (pSRect->right - pSRect->left); + Height = (pSRect->bottom - pSRect->top); + + DRect.left = x; + DRect.right = x+Width; + DRect.top = y; + DRect.bottom = y+Height; + + ddrval= AppInfo.lpBackBuffer->Blt(&DRect, THandle->MipData[0].Surface, pSRect, + (DDBLT_KEYSRC | DDBLT_WAIT), NULL); + + if(ddrval==DDERR_SURFACELOST) + { + if (!D3DMain_RestoreAllSurfaces()) + return GE_FALSE; + } + //AppInfo.lpBackBuffer->Blt(&DRect, Decals[Handle].Surface, pSRect, (DDBLT_WAIT), NULL); +#endif + + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/WireFrame/Render.h b/G3D/Engine/Drivers/WireFrame/Render.h new file mode 100644 index 0000000..f000b0a --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/Render.h @@ -0,0 +1,34 @@ +/****************************************************************************************/ +/* Render.h */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render polys under D3D */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef RENDER_H +#define RENDER_H + +#include + +#include "DCommon.h" + +geBoolean DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags); +geBoolean DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +geBoolean DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags); +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y); + +#endif diff --git a/G3D/Engine/Drivers/WireFrame/Scene.cpp b/G3D/Engine/Drivers/WireFrame/Scene.cpp new file mode 100644 index 0000000..cdeaaa4 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/Scene.cpp @@ -0,0 +1,217 @@ +/****************************************************************************************/ +/* Scene.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Begin/EndScene code, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "D3DDrv.h" +#include "DCommon.h" +#include "Scene.h" +#include "Render.h" +#include "GSpan.h" +#include "D3DCache.h" +#include "D3D_Fx.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "D3D_Err.h" +#include "THandle.h" + +//#define D3D_MANAGE_TEXTURES +#define SUPER_FLUSH + +int32 RenderMode; + +uint32 CurrentLRU; + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *WorldRect) +{ + HRESULT Result; + + CurrentLRU++; + + if (!AppInfo.lpD3DDevice) + { + D3DMain_Log("BeginScene: No D3D Device!."); + return FALSE; + } + + // Make sure we clear the cache info structure... + memset(&CacheInfo, 0, sizeof(DRV_CacheInfo)); + + if (!THandle_CheckCache()) + return GE_FALSE; + + // Watch for inactive app or minimize + if(AppInfo.RenderingIsOK) + { + if (!Main_ClearBackBuffer(Clear, ClearZ)) + { + D3DMain_Log("D3DClearBuffers failed."); + return FALSE; + } + + D3DDRV.NumRenderedPolys = 0; + + Result = AppInfo.lpD3DDevice->BeginScene(); + + if (Result != D3D_OK) + { + D3DMain_Log("BeginScene: D3D BeginScene Failed.\n%s.", D3DErrorToString(Result)); + return FALSE; + } + + D3DBilinearFilter(D3DFILTER_LINEAR, D3DFILTER_LINEAR); + D3DPolygonMode (D3DFILL_WIREFRAME); + + D3DZWriteEnable (TRUE); + D3DZEnable(TRUE); + D3DZFunc(D3DCMP_LESSEQUAL); + + D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + D3DBlendEnable(TRUE); + + if (AppInfo.FogEnable) + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE); + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR , ((DWORD)AppInfo.FogR<<16)|((DWORD)AppInfo.FogG<<8)|(DWORD)AppInfo.FogB); + } + else + { + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , FALSE); + } + } + + return TRUE; +} + +BOOL DRIVERCC EndScene(void) +{ + HRESULT Result; + + if (!AppInfo.lpD3DDevice) + return FALSE; + + if(AppInfo.RenderingIsOK) + { + // Flush everything one last time... + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + Result = AppInfo.lpD3DDevice->EndScene(); + + if (Result != D3D_OK) + { + D3DMain_Log("EndScene: D3D EndScene Failed.\n%s", D3DErrorToString(Result)); + return FALSE; + } + + if (!Main_ShowBackBuffer()) + return FALSE; + } + return TRUE; +} + +BOOL DRIVERCC BeginWorld(void) +{ + #ifdef USE_SPANS + if(AppInfo.RenderingIsOK) + { + ResetSpans(ClientWindow.Height); + } + #endif + + RenderMode = RENDER_WORLD; + return TRUE; +} + +BOOL DRIVERCC EndWorld(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + assert(AppInfo.lpD3DDevice); + #ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + #endif + + } + return TRUE; +} + +BOOL GlobalMeshHack; + +BOOL DRIVERCC BeginMeshes(void) +{ + GlobalMeshHack = TRUE; + RenderMode = RENDER_MESHES; + return TRUE; +} + +BOOL DRIVERCC EndMeshes(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushMiscPolys(); + PCache_FlushWorldPolys(); + + #ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + #endif + + GlobalMeshHack = FALSE; + } + return TRUE; +} + +BOOL DRIVERCC BeginModels(void) +{ + RenderMode = RENDER_MODELS; + return TRUE; +} + +BOOL DRIVERCC EndModels(void) +{ + RenderMode = RENDER_NONE; + + if(AppInfo.RenderingIsOK) + { + PCache_FlushWorldPolys(); + PCache_FlushMiscPolys(); + + #ifdef SUPER_FLUSH + AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0); + AppInfo.lpD3DDevice->EndScene(); + AppInfo.lpD3DDevice->BeginScene(); + #endif + + } + return TRUE; +} diff --git a/G3D/Engine/Drivers/WireFrame/Scene.h b/G3D/Engine/Drivers/WireFrame/Scene.h new file mode 100644 index 0000000..624f9c6 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/Scene.h @@ -0,0 +1,46 @@ +/****************************************************************************************/ +/* Scene.h */ +/* */ +/* Author: John Pollard */ +/* Description: Begin/EndScene code, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SCENE_H +#define SCENE_H + +#include + +#include "DCommon.h" + +#define RENDER_NONE 0 +#define RENDER_WORLD 1 +#define RENDER_MESHES 2 +#define RENDER_MODELS 3 + +extern int32 RenderMode; + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *WorldRect); +BOOL DRIVERCC EndScene(void); +BOOL DRIVERCC BeginWorld(void); +BOOL DRIVERCC EndWorld(void); +BOOL DRIVERCC BeginMeshes(void); +BOOL DRIVERCC EndMeshes(void); +BOOL DRIVERCC BeginModels(void); +BOOL DRIVERCC EndModels(void); + +#endif + diff --git a/G3D/Engine/Drivers/WireFrame/THandle.cpp b/G3D/Engine/Drivers/WireFrame/THandle.cpp new file mode 100644 index 0000000..f20f66b --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/THandle.cpp @@ -0,0 +1,846 @@ +/****************************************************************************************/ +/* THandle.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for D3DDrv */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "THandle.h" +#include "BaseType.h" +#include "D3DDrv.h" +#include "DCommon.h" +#include "D3DCache.h" +#include "D3D_Main.h" +#include "PCache.h" +#include "D3d_FX.h" + +#include "TPage.h" + +//#define D3D_MANAGE_TEXTURES + +#define USE_ONE_CACHE + +#define MAX_TEXTURE_HANDLES 132000 + +#define TEXTURE_CACHE_PERCENT 0.70f +#define LMAP_CACHE_PERCENT 0.30f + +#define TSTAGE_0 0 +#define TSTAGE_1 1 + +//============================================================================================ +//============================================================================================ + +geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; + +DDMemMgr *MemMgr; +DDMemMgr_Partition *Partition[2]; + +D3DCache *TextureCache; +D3DCache *LMapCache; + +TPage_Mgr *TPageMgr; + +DDSURFACEDESC2 CurrentSurfDesc; + +THandle_MipData SystemToVideo[MAX_LMAP_LOG_SIZE]; + +geBoolean CacheNeedsUpdate; +/* +#ifdef D3D_MANAGE_TEXTURES + #define NUM_LMAP_VIDEO_SURFACES 10; + THandle_MipData SystemToVideo[MAX_LMAP_LOG_SIZE]; +#endif +*/ + +//============================================================================================ +//============================================================================================ + +//============================================================================================ +// FreeAllcaches +//============================================================================================ +void FreeAllCaches(void) +{ + if (LMapCache) + D3DCache_Destroy(LMapCache); + + if (TextureCache) + D3DCache_Destroy(TextureCache); + + LMapCache = NULL; + TextureCache = NULL; + + if (Partition[1]) + DDMemMgr_PartitionDestroy(Partition[1]); + if (Partition[0]) + DDMemMgr_PartitionDestroy(Partition[0]); + if (MemMgr) + DDMemMgr_Destroy(MemMgr); + + +#ifdef USE_TPAGES + if (TPageMgr) + { + TPage_MgrDestroy(&TPageMgr); + TPageMgr = NULL; + } +#endif + + Partition[1] = NULL; + Partition[0] = NULL; + MemMgr = NULL; +} + +//============================================================================================ +// FindTextureHandle +//============================================================================================ +geRDriver_THandle *FindTextureHandle(void) +{ + int32 i; + geRDriver_THandle *pHandle; + + pHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pHandle++) + { + if (!pHandle->Active) + { + memset(pHandle, 0, sizeof(geRDriver_THandle)); + pHandle->Active = 1; + return pHandle; + } + } + + SetLastDrvError(DRV_ERROR_GENERIC, "D3D_FindTextureHandle: No more handles left.\n"); + + return NULL; +} + +//============================================================================================ +// FreeAllTextureHandles +//============================================================================================ +geBoolean FreeAllTextureHandles(void) +{ + int32 i; + geRDriver_THandle *pHandle; + + pHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pHandle++) + { + if (!pHandle->Active) + continue; + + if (!THandle_Destroy(pHandle)) + return GE_FALSE; + } + + return GE_TRUE; +} + +//============================================================================================ +//============================================================================================ +geBoolean THandle_Startup(void) +{ + // Create the main memory manager + MemMgr = DDMemMgr_Create(AppInfo.VidMemFree); + + if (!MemMgr) + goto ExitWithError; + + // Create partition 0 + Partition[0] = DDMemMgr_PartitionCreate(MemMgr, (uint32)((geFloat)DDMemMgr_GetFreeMem(MemMgr)*TEXTURE_CACHE_PERCENT)); + + if (!Partition[0]) + goto ExitWithError; + + // Create partition 1 + Partition[1] = DDMemMgr_PartitionCreate(MemMgr, DDMemMgr_GetFreeMem(MemMgr)); + + if (!Partition[1]) + goto ExitWithError; + + // Create the texture cache from partition 0 + TextureCache = D3DCache_Create("Main Texture Cache", AppInfo.lpDD, Partition[0], AppInfo.CanDoMultiTexture); + + if (!TextureCache) + goto ExitWithError; + +#ifndef USE_ONE_CACHE + // Create the lmap cache from partition 1 + LMapCache = D3DCache_Create("Lightmap Cache", AppInfo.lpDD, Partition[1], AppInfo.CanDoMultiTexture); + + if (!LMapCache) + goto ExitWithError; +#endif + + // Create all the system to video surfaces (for lmaps) + if (!CreateSystemToVideoSurfaces()) + goto ExitWithError; + + #ifdef USE_TPAGES + TPageMgr = TPage_MgrCreate(AppInfo.lpDD, &AppInfo.ddTexFormat, 512); + if (!TPageMgr) + goto ExitWithError; + #endif + + return GE_TRUE; + + ExitWithError: + { + THandle_Shutdown(); + return GE_FALSE; + } +} + +//============================================================================================ +//============================================================================================ +void THandle_Shutdown(void) +{ + FreeAllTextureHandles(); + FreeAllCaches(); + DestroySystemToVideoSurfaces(); + + CacheNeedsUpdate = GE_FALSE; +} + +//============================================================================================ +// Create3DTHandle +//============================================================================================ +geRDriver_THandle *Create3DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 Size, i; + + assert(NumMipLevels < THANDLE_MAX_MIP_LEVELS); + assert(NumMipLevels <= 4); + + // Store width/height info + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = (1<Log); + + // Create the surfaces to hold all the mips + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + if (!THandle->MipData) + { + THandle_Destroy(THandle); + return NULL; + } + + Size = 1<Log; + + // Create all the surfaces for each mip level + for (i=0; i< NumMipLevels; i++) + { + int32 Stage; + + if (!THandle_CreateSurfaces(&THandle->MipData[i], Size, Size, &CurrentSurfDesc, GE_FALSE, 0)) + { + THandle_Destroy(THandle); + return NULL; + } + + // get a cache type for this surface since it is a 3d surface, and will need to be cached on the video card + //THandle->MipData[i].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, NumMipLevels, &CurrentSurfDesc); + // We can use 1 miplevel for the type, since we are createing types for each miplevel... + if (AppInfo.CanDoMultiTexture) + Stage = TSTAGE_0; + else + Stage = 0; + + THandle->MipData[i].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, 1, Stage, &CurrentSurfDesc); + + if (!THandle->MipData[i].CacheType) + { + THandle_Destroy(THandle); + return NULL; + } + + Size>>=1; + } + + return THandle; +} + +//============================================================================================ +// CreateLightmapTHandle +//============================================================================================ +geRDriver_THandle *CreateLightmapTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 Size, Stage; + + assert(NumMipLevels < THANDLE_MAX_MIP_LEVELS); + + assert(NumMipLevels == 1); + + // Save some info about the lightmap + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = 1<Log; + + assert(THandle->Log < MAX_LMAP_LOG_SIZE); + + Size = 1<Log; + + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + THandle->MipData[0].Flags = THANDLE_UPDATE; + +#ifdef D3D_MANAGE_TEXTURES + #ifndef USE_TPAGES + { + int32 Stage; + + if (AppInfo.CanDoMultiTexture) + Stage = STAGE_1; + else + Stage = 0; + + if (!THandle_CreateSurfaces(&THandle->MipData[0], Size, Size, &CurrentSurfDesc, GE_FALSE, Stage)) + { + THandle_Destroy(THandle); + return NULL; + } + + D3DSetTexture(0, THandle->MipData[0].Texture); + } + #endif +#endif + + if (AppInfo.CanDoMultiTexture) + Stage = TSTAGE_1; + else + Stage = 0; + +#ifdef USE_ONE_CACHE + THandle->MipData[0].CacheType = D3DCache_TypeCreate(TextureCache, Size, Size, NumMipLevels, Stage, &CurrentSurfDesc); +#else + THandle->MipData[0].CacheType = D3DCache_TypeCreate(LMapCache, Size, Size, NumMipLevels, Stage, &CurrentSurfDesc); +#endif + + if (!THandle->MipData[0].CacheType) + { + THandle_Destroy(THandle); + return NULL; + } + + return THandle; +} + +//============================================================================================ +// Create2DTHandle +//============================================================================================ +geRDriver_THandle *Create2DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + assert(NumMipLevels < THANDLE_MAX_MIP_LEVELS); + assert(NumMipLevels == 1); + + // Save some info about the lightmap + THandle->Width = Width; + THandle->Height = Height; + THandle->NumMipLevels = (uint8)NumMipLevels; + THandle->Log = (uint8)GetLog(Width, Height); + THandle->Stride = Width; + + // Create the surfaces to hold all the mips + THandle->MipData = (THandle_MipData*)malloc(sizeof(THandle_MipData)*NumMipLevels); + memset(THandle->MipData, 0, sizeof(THandle_MipData)*NumMipLevels); + + if (!THandle->MipData) + { + THandle_Destroy(THandle); + return NULL; + } + + if (!THandle_CreateSurfaces(&THandle->MipData[0], Width, Height, &CurrentSurfDesc, GE_TRUE, 0)) + { + THandle_Destroy(THandle); + return NULL; + } + + return THandle; +} + +//============================================================================================ +// SetupCurrent3dDesc +//============================================================================================ +geBoolean SetupCurrent3dDesc(gePixelFormat PixelFormat) +{ + switch (PixelFormat) + { + case GE_PIXELFORMAT_16BIT_555_RGB: + case GE_PIXELFORMAT_16BIT_565_RGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddTexFormat, sizeof(DDSURFACEDESC2)); + break; + } + case GE_PIXELFORMAT_16BIT_4444_ARGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddFourBitAlphaSurfFormat, sizeof(DDSURFACEDESC2)); + break; + } + case GE_PIXELFORMAT_16BIT_1555_ARGB: + { + memcpy(&CurrentSurfDesc, &AppInfo.ddOneBitAlphaSurfFormat, sizeof(DDSURFACEDESC2)); + break; + } + + default: + { + SetLastDrvError(DRV_ERROR_GENERIC, "SetupCurrent3dDesc: Invalid pixel format.\n"); + return GE_FALSE; + } + } + + return GE_TRUE; +} +//============================================================================================ +// THandle_Create +//============================================================================================ +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + geRDriver_THandle *THandle; + + THandle = FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "D3DDRV:THandle_Create: Out of texture handles.\n"); + return NULL; + } + + THandle->PixelFormat = *PixelFormat; + + if (PixelFormat->Flags & RDRIVER_PF_3D) + { + // Get the pixel format desc for this thandle + if (!SetupCurrent3dDesc(PixelFormat->PixelFormat)) + return NULL; + + if (!Create3DTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + + CacheNeedsUpdate = GE_TRUE; + } + else if (PixelFormat->Flags & RDRIVER_PF_LIGHTMAP) + { + // Get the pixel format desc for this thandle + if (!SetupCurrent3dDesc(PixelFormat->PixelFormat)) + return NULL; + + if (!CreateLightmapTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + + CacheNeedsUpdate = GE_TRUE; + } + else if (PixelFormat->Flags & RDRIVER_PF_2D) + { + // 2d surfaces are always this format for now + memcpy(&CurrentSurfDesc, &AppInfo.ddSurfFormat, sizeof(DDSURFACEDESC2)); + + if (!Create2DTHandle(THandle, Width, Height, NumMipLevels, PixelFormat)) + return NULL; + } + + return THandle; +} + +//============================================================================================ +// THandle_Destroy +//============================================================================================ +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle) +{ + int32 i; + + assert(THandle); + assert(THandle->Active); + + for (i=0; i< THandle->NumMipLevels; i++) + { + assert(THandle->MipData); + + if (THandle->MipData[i].CacheType) + { + D3DCache_TypeDestroy(THandle->MipData[i].CacheType); + CacheNeedsUpdate = GE_TRUE; + THandle->MipData[i].CacheType = NULL; + } + + if (THandle->MipData[i].Surface) + { + assert(THandle->MipData[i].Texture); + + THandle_DestroySurfaces(&THandle->MipData[i]); + THandle->MipData[i].Surface = NULL; + THandle->MipData[i].Texture = NULL; + } + } + + if (THandle->MipData) + free(THandle->MipData); + + memset(THandle, 0, sizeof(geRDriver_THandle)); + + return GE_TRUE; +} + +//===================================================================================== +//===================================================================================== +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Bits) +{ + DDSURFACEDESC2 SurfDesc; + HRESULT Result; + + assert(!(THandle->MipData[MipLevel].Flags & THANDLE_LOCKED)); + + // Lock the surface so it can be filled with the data + memset(&SurfDesc, 0, sizeof(DDSURFACEDESC2)); + SurfDesc.dwSize = sizeof(DDSURFACEDESC2); + + Result = THandle->MipData[MipLevel].Surface->Lock(NULL, &SurfDesc, DDLOCK_WAIT, NULL); + + if (Result != DD_OK) + { + return GE_FALSE; + } + + THandle->MipData[MipLevel].Flags |= THANDLE_LOCKED; + + *Bits = (void*)SurfDesc.lpSurface; + + return GE_TRUE; +} + +//===================================================================================== +// THandle_UnLock +//===================================================================================== +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel) +{ + HRESULT Result; + + assert(MipLevel <= THandle->NumMipLevels); + assert(THandle->MipData[MipLevel].Flags & THANDLE_LOCKED); + + // Unlock the surface + Result = THandle->MipData[MipLevel].Surface->Unlock(NULL); + + if (Result != DD_OK) + { + return GE_FALSE; + } + + THandle->MipData[MipLevel].Flags |= THANDLE_UPDATE; + THandle->MipData[MipLevel].Flags &= ~THANDLE_LOCKED; + + return GE_TRUE; +} + +#ifndef NDEBUG +#define DebugIf(a, b) if (a) b +#else +#define DebugIf(a, b) +#endif + +//===================================================================================== +// THandle_GetInfo +//===================================================================================== +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info) +{ + DebugIf (MipLevel > THandle->Log, return GE_FALSE); + + Info->Width = THandle->Width>>MipLevel; + Info->Height = THandle->Height>>MipLevel; + Info->Stride = THandle->Stride>>MipLevel; + + if (THandle->PixelFormat.Flags & RDRIVER_PF_CAN_DO_COLORKEY) + { + Info->Flags = RDRIVER_THANDLE_HAS_COLORKEY; + Info->ColorKey = 1; + } + else + { + Info->Flags = 0; + Info->ColorKey = 0; + } + + Info->PixelFormat = THandle->PixelFormat; + + return GE_TRUE; +} + +//===================================================================================== +// CreateSystemToVideoSurfaces +// System surfaces to copy from system to video +//===================================================================================== +geBoolean CreateSystemToVideoSurfaces(void) +{ + int32 i; + DDSURFACEDESC2 SurfDesc; + + memcpy(&SurfDesc, &AppInfo.ddTexFormat, sizeof(DDSURFACEDESC2)); + + for (i=0; iCreateSurface(&ddsd, &Surface, NULL); + + if(Hr != DD_OK) + { + return FALSE; + } + + Surf->Surface = Surface; + + Surf->Texture = NULL; + + Hr = Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Surf->Texture); + + if(Hr != DD_OK) + { + Surface->Release(); + return GE_FALSE; + } + + if (ColorKey) + { + DDCOLORKEY CKey; + + // Create the color key for this surface + CKey.dwColorSpaceLowValue = 1; + CKey.dwColorSpaceHighValue = 1; + + if (Surf->Surface->SetColorKey(DDCKEY_SRCBLT , &CKey) != DD_OK) + { + SetLastDrvError(DRV_ERROR_GENERIC, "THandle_CreateSurfaces: SetColorKey failed for texture."); + Surf->Surface->Release(); + Surf->Surface = NULL; + Surf->Texture->Release(); + Surf->Texture = NULL; + return FALSE; + } + } + return GE_TRUE; // All good dude +} + +//===================================================================================== +// DestroySystemSurface +//===================================================================================== +void THandle_DestroySurfaces(THandle_MipData *Surf) +{ + if (Surf->Texture) + Surf->Texture->Release(); + if (Surf->Surface) + Surf->Surface->Release(); + + memset(Surf, 0, sizeof (THandle_MipData)); +} + +//===================================================================================== +// THandle_CheckCache +//===================================================================================== +geBoolean THandle_CheckCache(void) +{ + geRDriver_THandle *pTHandle; + int32 i, Stage0, Stage1; + int32 MaxTable1[9], MaxTable2[9]; + + if (!CacheNeedsUpdate) + return GE_TRUE; + +#ifndef D3D_MANAGE_TEXTURES // If D3D is managing textures, then we don't ned to do any of this... + D3DMain_Log("THandle_CheckCache: Resetting texture cache...\n"); + +#ifdef USE_ONE_CACHE + #pragma message ("There numbers ARE NOT DONE. So if USE_ONE_CACHE is defined, please finish this...") + // Texture cache & Lightmap cache (we are only using one cache, so the combine into the TextureCache) + MaxTable1[0] = 256; // 1x1 + MaxTable1[1] = 256; // 2x2 + MaxTable1[2] = 256; // 4x4 + MaxTable1[3] = 512; // 8x8 + MaxTable1[4] = 512; // 16x16 + MaxTable1[5] = 512; // 32x32 + MaxTable1[6] = 512; // 64x64 + MaxTable1[7] = 256; //128x128 + MaxTable1[8] = 256; //256x256 +#else + if (AppInfo.DeviceIdentifier.dwVendorId == 4634) // 3dfx series have a limit on the number of texture handles + { + D3DMain_Log(" 3dfx card detected, using smaller number of handles...\n"); + + // Texture cache + MaxTable1[0] = 24; // 1x1 + MaxTable1[1] = 24; // 2x2 + MaxTable1[2] = 24; // 4x4 + MaxTable1[3] = 24; // 8x8 + MaxTable1[4] = 24; // 16x16 + MaxTable1[5] = 128; // 32x32 + MaxTable1[6] = 128; // 64x64 + MaxTable1[7] = 128; //128x128 + MaxTable1[8] = 128; //256x256 + + // Lightmap cache + MaxTable2[0] = 128; // 1x1 + MaxTable2[1] = 128; // 2x2 + MaxTable2[2] = 256; // 4x4 + MaxTable2[3] = 256; // 8x8 + MaxTable2[4] = 256; // 16x16 + MaxTable2[5] = 128; // 32x32 + MaxTable2[6] = 128; // 64x64 + MaxTable2[7] = 128; //128x128 + MaxTable2[8] = 128; //256x256 + } + else + { + D3DMain_Log(" NO 3dfx card detected, using larger number of handles...\n"); + + // Texture cache + MaxTable1[0] = 32; // 1x1 + MaxTable1[1] = 32; // 2x2 + MaxTable1[2] = 32; // 4x4 + MaxTable1[3] = 32; // 8x8 + MaxTable1[4] = 32; // 16x16 + MaxTable1[5] = 32; // 32x32 + MaxTable1[6] = 128; // 64x64 + MaxTable1[7] = 128; //128x128 + MaxTable1[8] = 128; //256x256 + + MaxTable2[0] = 128; // 1x1 + MaxTable2[1] = 128; // 2x2 + MaxTable2[2] = 256; // 4x4 + MaxTable2[3] = 1024; // 8x8 + MaxTable2[4] = 1024; // 16x16 + MaxTable2[5] = 512; // 32x32 + MaxTable2[6] = 256; // 64x64 + MaxTable2[7] = 256; //128x128 + MaxTable2[8] = 256; //256x256 + } +#endif + + if (AppInfo.CanDoMultiTexture) + { + Stage0 = TSTAGE_0; + Stage1 = TSTAGE_1; + } + else + { + Stage0 = 0; + Stage1 = 0; + } + + #ifndef USE_ONE_CACHE + if (!D3DCache_AdjustSlots(LMapCache, MaxTable2, GE_TRUE)) + { + D3DMain_Log("THandle_CheckCache: D3DCache_AdjustSlots failed for LMapCache.\n"); + return GE_FALSE; + } + #endif + + if (!D3DCache_AdjustSlots(TextureCache, MaxTable1, GE_FALSE)) + { + D3DMain_Log("THandle_CheckCache: D3DCache_AdjustSlots failed for TextureCache.\n"); + return GE_FALSE; + } + +#endif + + // Make sure no THandles reference any slots, because they mave have been moved around, or gotten destroyed... + // (Evict all textures in the cache) + pTHandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pTHandle++) + { + int32 m; + + for (m=0; m< pTHandle->NumMipLevels; m++) + { + pTHandle->MipData[m].Slot = NULL; + } + } + + CacheNeedsUpdate = GE_FALSE; + + return GE_TRUE; +} diff --git a/G3D/Engine/Drivers/WireFrame/THandle.h b/G3D/Engine/Drivers/WireFrame/THandle.h new file mode 100644 index 0000000..9569a9a --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/THandle.h @@ -0,0 +1,106 @@ +/****************************************************************************************/ +/* THandle.h */ +/* */ +/* Author: John Pollard */ +/* Description: THandle manager for D3DDrv */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef THANDLE_H +#define THANDLE_H + +#include + +#include "BaseType.h" +#include "DCommon.h" +#include "D3DCache.h" + +#include "TPage.h" + +//============================================================================================ +//============================================================================================ +#define THANDLE_MAX_MIP_LEVELS 255 +//#define MAX_LMAP_LOG_SIZE 8 // Max lightmap size in pixels will be 128x128 +//#define MAX_LMAP_LOG_SIZE 7 // Max lightmap size in pixels will be 64x64 +#define MAX_LMAP_LOG_SIZE 6 // Max lightmap size in pixels will be 32x32 + +typedef struct +{ + LPDIRECTDRAWSURFACE4 Surface; // The DD surface + D3DCache_Type *CacheType; + D3DCache_Slot *Slot; + + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface + + uint8 Flags; +} THandle_MipData; + +// THandle flags +#define THANDLE_LOCKED (1<<0) +#define THANDLE_UPDATE (1<<1) + +typedef struct geRDriver_THandle +{ + uint8 Active; + int32 Width; + int32 Height; + int32 Stride; + uint8 NumMipLevels; + uint8 Log; + + THandle_MipData *MipData; // A mipdata per miplevel + + geRDriver_PixelFormat PixelFormat; + +#ifdef USE_TPAGES + TPage_Block *Block; +#endif + +} geRDriver_THandle; + +extern geRDriver_THandle TextureHandles[]; + +extern D3DCache *TextureCache; +extern D3DCache *LMapCache; + +extern TPage_Mgr *TPageMgr; + +extern THandle_MipData SystemToVideo[]; + +extern CacheNeedsUpdate; + +//============================================================================================ +//============================================================================================ +void FreeAllCaches(void); +geRDriver_THandle *FindTextureHandle(void); +geBoolean FreeAllTextureHandles(void); +geBoolean THandle_Startup(void); +void THandle_Shutdown(void); +geRDriver_THandle *Create3DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *CreateLightmapTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *Create2DTHandle(geRDriver_THandle *THandle, int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle); +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Bits); +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel); +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info); +geBoolean CreateSystemToVideoSurfaces(void); +void DestroySystemToVideoSurfaces(void); +geBoolean THandle_CreateSurfaces(THandle_MipData *MipData, int32 Width, int32 Height, DDSURFACEDESC2 *SurfDesc, geBoolean ColorKey, int32 Stage); +void THandle_DestroySurfaces(THandle_MipData *MipData); +geBoolean THandle_CheckCache(void); + +#endif diff --git a/G3D/Engine/Drivers/WireFrame/TPage.h b/G3D/Engine/Drivers/WireFrame/TPage.h new file mode 100644 index 0000000..b6db4d0 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/TPage.h @@ -0,0 +1,69 @@ +/****************************************************************************************/ +/* TPage.h */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager using pages */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef TPAGE_H +#define TPAGE_H + +#include + +#include +#include + +typedef struct TPage_Mgr TPage_Mgr; +typedef struct TPage TPage; +typedef struct TPage_Block TPage_Block; + +// +// TPage_Mgr +// +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages); +void TPage_MgrDestroy(TPage_Mgr **TPageMgr); +geBoolean TPage_MgrHasTPage(TPage_Mgr *Mgr, TPage *Page); +geBoolean TPage_MgrAttachTPage(TPage_Mgr *Mgr, TPage *TPage); +void TPage_MgrDetachTPage(TPage_Mgr *Mgr, TPage *TPage); +TPage_Block *TPage_MgrFindOptimalBlock(TPage_Mgr *Mgr, uint32 LRU); + +// +// TPage +// +TPage *TPage_Create(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc); +void TPage_CreateRef(TPage *Page); +void TPage_Destroy(TPage **Page1); +geBoolean TPage_HasBlock(TPage *TPage, TPage_Block *Block); +geBoolean TPage_AttachBlock(TPage *Page, TPage_Block *Block); +void TPage_DetachBlock(TPage *TPage, TPage_Block *Block); +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc); +void TPage_DestroySurfaces(TPage *Page); + +// +//TPage_Block +// +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE4 Surface, LPDIRECT3DTEXTURE2 Texture, const RECT *Rect); +geBoolean TPage_BlockCreateRef(TPage_Block *Block); +void TPage_BlockDestroy(TPage_Block **Block); +LPDIRECT3DTEXTURE2 TPage_BlockGetTexture(TPage_Block *Block); +LPDIRECTDRAWSURFACE4 TPage_BlockGetSurface(TPage_Block *Block); +const RECT *TPage_BlockGetRect(TPage_Block *Block); +void TPage_BlockSetLRU(TPage_Block *Block, uint32 LRU); +void TPage_BlockSetUserData(TPage_Block *Block, void *UserData); +void *TPage_BlockGetUserData(TPage_Block *Block); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/WireFrame/mssccprj.scc b/G3D/Engine/Drivers/WireFrame/mssccprj.scc new file mode 100644 index 0000000..848e217 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/mssccprj.scc @@ -0,0 +1,4 @@ +SCC = This is a Source Code Control file + +[D3DDrv.mak] +SCC_Project_Name = "$/Genesis10/Source/Engine/Drivers/D3DDrv", LQQBAAAA diff --git a/G3D/Engine/Drivers/WireFrame/tpage.cpp b/G3D/Engine/Drivers/WireFrame/tpage.cpp new file mode 100644 index 0000000..4a9cb3b --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/tpage.cpp @@ -0,0 +1,677 @@ +/****************************************************************************************/ +/* TPage.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: D3D cache manager using pages */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "BaseType.h" +#include "TPage.h" + +// These must be a power of 2!!! +#define TPAGE_WIDTH 16 // Width of TPAges +#define TPAGE_HEIGHT 16 // Height of TPages + +#define TPAGE_GRID_X 16 // Must be <= TPAGE_WIDTH, and power of 2 +#define TPAGE_GRID_Y 16 // Must be <= TPAGE_HEIGHT, and power of 2 + +// NOTE - Blocks Width/Height that go into TPages MUST be <= AlignX/AlignY!!! + +typedef struct TPage_Block +{ + int32 RefCount; // Number of references to this object + + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this Block + LPDIRECT3DTEXTURE2 Texture; // The Texture interface to the surface + + RECT Rect; // The Rect into the surface that this block can use + + uint32 LRU; // Set to the TPage->TPageMgr->LRU when accesed... + + void *UserData; + + struct TPage_Block *Prev; + struct TPage_Block *Next; + +} TPage_Block; + +typedef struct TPage +{ + int32 RefCount; + + DDSURFACEDESC2 SurfaceDesc; // Surface description of this page (note all blocks must use this format!!!) + LPDIRECTDRAWSURFACE4 Surface; // The DD surface for this TPage + LPDIRECT3DTEXTURE2 Texture; // The texture interface to the surface + + TPage_Block *Blocks; // Linked list of blocks + + uint32 LRU; + + struct TPage *Prev; + struct TPage *Next; +} TPage; + +typedef struct TPage_Mgr +{ + int32 NumPages; + + TPage *TPages; // Linked list of TPages + + LPDIRECTDRAW4 lpDD; // DD object used to create surfaces +} TPage_Mgr; + +//============================================================================ +// *** TPage_Mgr *** +//============================================================================ + +//============================================================================ +// TPage_MgrCreate +//============================================================================ +TPage_Mgr *TPage_MgrCreate(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfaceDesc, int32 NumPages) +{ + TPage_Mgr *TPageMgr; + int32 i; + + TPageMgr = (TPage_Mgr*)malloc(sizeof(TPage_Mgr)); + + if (!TPageMgr) + return NULL; + + memset(TPageMgr, 0, sizeof(TPage_Mgr)); + + // Remeber the DD object + TPageMgr->lpDD = lpDD; + // Ref the dd object + lpDD->AddRef(); + + TPageMgr->NumPages = NumPages; + + // Create the pages + for (i=0; iTPages; Page; Page = Next) + { + Next = Page->Next; + + TPage_MgrDetachTPage(Mgr, Page); + TPage_Destroy(&Page); + } + + assert(Mgr->TPages == NULL); + + // Release our ref on the DD object + Mgr->lpDD->Release(); + + free(*TPageMgr); + + *TPageMgr = NULL; +} + +//============================================================================ +// TPage_MgrHasTPage +//============================================================================ +geBoolean TPage_MgrHasTPage(TPage_Mgr *Mgr, TPage *Page) +{ + TPage *Page2; + + assert(Mgr); + assert(Page); + + for (Page2 = Mgr->TPages; Page2; Page2 = Page2->Next) + { + if (Page2 == Page) + { + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//============================================================================ +// TPage_MgrAttachTPage +// NOTE - A TPage can only attach to one TPage_Mgr, and only ONCE!! +//============================================================================ +geBoolean TPage_MgrAttachTPage(TPage_Mgr *Mgr, TPage *TPage) +{ + assert(TPage_MgrHasTPage(Mgr, TPage) == GE_FALSE); + assert(TPage->Prev == NULL); + assert(TPage->Next == NULL); + + if (Mgr->TPages) + Mgr->TPages->Prev = TPage; + + TPage->Prev = NULL; + TPage->Next = Mgr->TPages; + Mgr->TPages = TPage; + + return GE_TRUE; +} + +//============================================================================ +// TPage_MgrDetachTPage +//============================================================================ +void TPage_MgrDetachTPage(TPage_Mgr *Mgr, TPage *TPage) +{ + assert(Mgr); + assert(TPage); + assert(TPage_MgrHasTPage(Mgr, TPage) == GE_TRUE); + + if (TPage->Next) + TPage->Next->Prev = TPage->Prev; + + if (TPage->Prev) + TPage->Prev->Next = TPage->Prev; + else + { + // If we get here, this better be the first TPage in the list! + assert(Mgr->TPages == TPage); + Mgr->TPages = TPage->Next; + } + + TPage->Next = NULL; + TPage->Prev = NULL; +} + +//============================================================================ +// TPage_MgrFindOptimalBlock +//============================================================================ +TPage_Block *TPage_MgrFindOptimalBlock(TPage_Mgr *Mgr, uint32 LRU) +{ +#if 0 + TPage *Page, *BestPage; + TPage_Block *Block, *BestBlock; + uint32 BestLRU; + + // We really should make a TPage_GetOptimalBlock... + + // First, find the page that has the highest LRU + BestLRU = 0; + BestPage = Mgr->TPages; + + for (Page = Mgr->TPages; Page; Page = Page->Next) + { + if (Page->LRU > BestLRU && Page->NumFull) + { + BestPage = Page; + BestLRU = Page->LRU; + } + } + + // Now, find the block with the lowest LRU in this page + BestBlock = BestPage->Blocks; + BestLRU = 0xffffffff; + + for (Block = BestPage->Blocks; Block; Block = Block->Next) + { + if (Block->LRU < BestLRU) + { + BestBlock = Block; + BestLRU = Block->LRU; + } + } + /* + if (BestBlock->LRU == LRU) + BestPage->NumFull++; + else + */ + BestBlock->LRU = LRU; + BestPage->LRU = LRU; +#else + TPage *Page; + TPage_Block *Block, *BestBlock; + uint32 BestLRU; + + // We really should make a TPage_GetOptimalBlock... + BestBlock = NULL; + BestLRU = 0xffffffff; + + for (Page = Mgr->TPages; Page; Page = Page->Next) + { + for (Block = Page->Blocks; Block; Block = Block->Next) + { + if (Block->LRU < BestLRU) + { + BestBlock = Block; + BestLRU = Block->LRU; + } + } + } + + BestBlock->LRU = LRU; +#endif + + return BestBlock; +} + +//============================================================================ +// *** TPage *** +//============================================================================ + +//============================================================================ +// TPage_Create +//============================================================================ +TPage *TPage_Create(LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc) +{ + TPage *Page; + int32 w, h; + + Page = (TPage*)malloc(sizeof(TPage)); + + if (!Page) + return NULL; + + memset(Page, 0, sizeof(TPage)); + + Page->SurfaceDesc = *SurfDesc; + + TPage_CreateRef(Page); // Create the very first ref + + if (!TPage_CreateSurfaces(Page, lpDD, SurfDesc)) + { + free(Page); + return NULL; + } + + // Create the blocks + for (h=0; hSurface, Page->Texture, &Rect); + + if (!Block) + goto ExitWithError; + + if (!TPage_AttachBlock(Page, Block)) + goto ExitWithError; + } + } + + return Page; + + ExitWithError: + { + if (Page) + TPage_Destroy(&Page); + + return NULL; + } +} + +//============================================================================ +// TPage_CreateRef +//============================================================================ +void TPage_CreateRef(TPage *Page) +{ + assert(Page->RefCount >= 0); // Refs can == 0, because thats what they are when TPages are first created + + Page->RefCount++; +} + +//============================================================================ +// TPage_Destroy +//============================================================================ +void TPage_Destroy(TPage **Page1) +{ + TPage *Page; + TPage_Block *Block, *Next; + + assert(Page1); + Page = *Page1; + + assert(Page); + assert(Page->RefCount > 0); + + Page->RefCount--; + + if (Page->RefCount > 0) + return; + + // Destroy any dd surfaces for this page + TPage_DestroySurfaces(Page); + + // Destroy all the blocks this page has + for (Block = Page->Blocks; Block; Block = Next) + { + Next = Block->Next; + + TPage_DetachBlock(Page, Block); + TPage_BlockDestroy(&Block); + } + + assert(Page->Blocks == NULL); + + free(*Page1); + + *Page1 = NULL; +} + +//============================================================================ +// TPage_HasBlock +//============================================================================ +geBoolean TPage_HasBlock(TPage *TPage, TPage_Block *Block) +{ + TPage_Block *Block2; + + assert(TPage); + assert(Block); + + for (Block2 = TPage->Blocks; Block2; Block2 = Block2->Next) + { + if (Block2 == Block) + { + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//============================================================================ +// TPage_AttachBlock +// NOTE - A Block can only attach to one TPage, and only ONCE!! +//============================================================================ +geBoolean TPage_AttachBlock(TPage *Page, TPage_Block *Block) +{ + assert(TPage_HasBlock(Page, Block) == GE_FALSE); + assert(Block->Prev == NULL); + assert(Block->Next == NULL); + + // Insert the block into the list of blocks for this Page + if (Page->Blocks) + Page->Blocks->Prev = Block; + + Block->Prev = NULL; + Block->Next = Page->Blocks; + + Page->Blocks = Block; + + return GE_TRUE; +} + +//============================================================================ +// TPage_DetachBlock +//============================================================================ +void TPage_DetachBlock(TPage *TPage, TPage_Block *Block) +{ + assert(TPage); + assert(Block); + assert(TPage_HasBlock(TPage, Block) == GE_TRUE); + + if (Block->Next) + Block->Next->Prev = Block->Prev; + + if (Block->Prev) + Block->Prev->Next = Block->Prev; + else + { + // If we get here, this better be the first Block in the list! + assert(TPage->Blocks == Block); + TPage->Blocks = Block->Next; + } + + // Reset the Block link + Block->Next = NULL; + Block->Prev = NULL; +} + +//===================================================================================== +// TPage_CreateSurfaces +//===================================================================================== +geBoolean TPage_CreateSurfaces(TPage *Page, LPDIRECTDRAW4 lpDD, const DDSURFACEDESC2 *SurfDesc) +{ + HRESULT Hr; + DDSURFACEDESC2 ddsd; + + assert(Page); + + memcpy(&ddsd, SurfDesc, sizeof(DDSURFACEDESC2)); + + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTDYNAMIC; + + ddsd.ddsCaps.dwCaps3 = 0; + ddsd.ddsCaps.dwCaps4 = 0; + + ddsd.dwWidth = TPAGE_WIDTH; + ddsd.dwHeight = TPAGE_HEIGHT; + + Hr = lpDD->CreateSurface(&ddsd, &Page->Surface, NULL); + + if (Hr != DD_OK) + return GE_FALSE; + + Hr = Page->Surface->QueryInterface(IID_IDirect3DTexture2, (void**)&Page->Texture); + + if(Hr != DD_OK) + { + Page->Surface->Release(); + Page->Surface = NULL; + Page->Texture = NULL; + return GE_FALSE; + } + + return GE_TRUE; // All good dude +} + + +//===================================================================================== +// TPage_DestroySurfaces +//===================================================================================== +void TPage_DestroySurfaces(TPage *Page) +{ + assert(Page); + + if (Page->Texture) + { + Page->Texture->Release(); + Page->Texture = NULL; + } + + if (Page->Surface) + { + Page->Surface->Release(); + Page->Surface = NULL; + } +} + +//============================================================================ +// *** TPage_Block *** +//============================================================================ + +//============================================================================ +// TPage_BlockCreate +//============================================================================ +TPage_Block *TPage_BlockCreate(LPDIRECTDRAWSURFACE4 Surface, LPDIRECT3DTEXTURE2 Texture, const RECT *Rect) +{ + TPage_Block *Block; + + Block = (TPage_Block*)malloc(sizeof(TPage_Block)); + + if (!Block) + return NULL; + + memset(Block, 0, sizeof(TPage_Block)); + + Surface->AddRef(); // Ref the surface + Texture->AddRef(); // Ditto... + + // Save off the surface, texture, and rect into the surface + Block->Surface = Surface; + Block->Texture = Texture; + Block->Rect = *Rect; + + TPage_BlockCreateRef(Block); // Create very first ref + + return Block; +} + +//============================================================================ +// TPage_BlockCreateRef +//============================================================================ +geBoolean TPage_BlockCreateRef(TPage_Block *Block) +{ + assert(Block); + + Block->RefCount++; + + return GE_TRUE; +} + +//============================================================================ +// TPage_BlockDestroy +//============================================================================ +void TPage_BlockDestroy(TPage_Block **Block) +{ + TPage_Block *Block2; + + assert(Block); + + Block2 = *Block; + + assert(Block2); + assert(Block2->RefCount > 0); + + Block2->RefCount--; + + if (Block2->RefCount > 0) + return; + + // Destroy references to the surface and texture + if (Block2->Surface) + Block2->Surface->Release(); + + if (Block2->Texture) + Block2->Texture->Release(); + + // Free the block + free(Block2); + + *Block = NULL; +} + +//============================================================================ +// TPage_BlockGetTexture +//============================================================================ +LPDIRECT3DTEXTURE2 TPage_BlockGetTexture(TPage_Block *Block) +{ + assert(Block); + + return Block->Texture; +} + +//============================================================================ +// TPage_BlockGetSurface +//============================================================================ +LPDIRECTDRAWSURFACE4 TPage_BlockGetSurface(TPage_Block *Block) +{ + assert(Block); + + return Block->Surface; +} + +//============================================================================ +// TPage_BlockGetRect +//============================================================================ +const RECT *TPage_BlockGetRect(TPage_Block *Block) +{ + assert(Block); + + return &Block->Rect; +} + +//============================================================================ +// TPage_BlockSetLRU +//============================================================================ +void TPage_BlockSetLRU(TPage_Block *Block, uint32 LRU) +{ + assert(Block); + + Block->LRU = LRU; +} + +//============================================================================ +// TPage_BlockSetUserData +//============================================================================ +void TPage_BlockSetUserData(TPage_Block *Block, void *UserData) +{ + assert(Block); + + Block->UserData = UserData; +} + +//============================================================================ +// TPage_BlockGetUserData +//============================================================================ +void *TPage_BlockGetUserData(TPage_Block *Block) +{ + assert(Block); + + return Block->UserData; +} diff --git a/G3D/Engine/Logo/A_CORONA.c b/G3D/Engine/Logo/A_CORONA.c new file mode 100644 index 0000000..2b52804 --- /dev/null +++ b/G3D/Engine/Logo/A_CORONA.c @@ -0,0 +1,899 @@ +/****************************************************************************************/ +/* A_CORONA.C */ +/* */ +/* Author: */ +/* Description: Embedded alpha mask Corona bitmap */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +unsigned char A_Corona_bmp[] = { +0x42, 0x4d, 0x38, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x4, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x80, +0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x1, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, +0xb, 0x0, 0x0, 0x12, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, +0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, +0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, +0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, +0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, +0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, +0xff, 0xff, 0x0, 0xf8, 0xf8, 0xf8, 0x0, 0xf3, 0xf3, 0xf3, 0x0, 0xec, 0xec, 0xec, 0x0, 0xe5, 0xe5, 0xe5, 0x0, 0xde, +0xde, 0xde, 0x0, 0xd6, 0xd6, 0xd6, 0x0, 0xd1, 0xd1, 0xd1, 0x0, 0xca, 0xca, 0xca, 0x0, 0xc3, 0xc3, 0xc3, 0x0, 0xbc, +0xbc, 0xbc, 0x0, 0xb5, 0xb5, 0xb5, 0x0, 0xaf, 0xaf, 0xaf, 0x0, 0xa8, 0xa8, 0xa8, 0x0, 0xa1, 0xa1, 0xa1, 0x0, 0x9a, +0x9a, 0x9a, 0x0, 0x93, 0x93, 0x93, 0x0, 0x8d, 0x8d, 0x8d, 0x0, 0x86, 0x86, 0x86, 0x0, 0x7f, 0x7f, 0x7f, 0x0, 0x78, +0x78, 0x78, 0x0, 0x71, 0x71, 0x71, 0x0, 0x6a, 0x6a, 0x6a, 0x0, 0x64, 0x64, 0x64, 0x0, 0x5d, 0x5d, 0x5d, 0x0, 0x56, +0x56, 0x56, 0x0, 0x4f, 0x4f, 0x4f, 0x0, 0x48, 0x48, 0x48, 0x0, 0x42, 0x42, 0x42, 0x0, 0x3b, 0x3b, 0x3b, 0x0, 0x34, +0x34, 0x34, 0x0, 0x2d, 0x2d, 0x2d, 0x0, 0x26, 0x26, 0x26, 0x0, 0x21, 0x21, 0x21, 0x0, 0x19, 0x19, 0x19, 0x0, 0x12, +0x12, 0x12, 0x0, 0xb, 0xb, 0xb, 0x0, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x43, 0x42, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x41, 0x43, 0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x43, 0x42, 0x42, 0x42, 0x43, 0x43, +0x43, 0x42, 0x42, 0x42, 0x42, 0x43, 0x42, 0x43, 0x42, 0x42, 0x43, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x43, 0x42, +0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x42, 0x42, 0x42, 0x42, 0x41, +0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x43, 0x43, 0x43, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, +0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x41, 0x40, 0x41, 0x41, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, +0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x40, 0x40, 0x40, 0x40, 0x3f, 0x40, 0x40, 0x41, 0x42, 0x41, 0x42, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, +0x42, 0x42, 0x42, 0x42, 0x41, 0x40, 0x41, 0x41, 0x42, 0x43, 0x42, 0x42, 0x42, 0x42, 0x41, 0x40, 0x40, 0x40, 0x3e, 0x3d, +0x3d, 0x3e, 0x3f, 0x3e, 0x3d, 0x3d, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3d, 0x3d, 0x3c, 0x3d, 0x3d, 0x3e, +0x3e, 0x3f, 0x40, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x42, 0x42, +0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x40, 0x41, 0x40, 0x40, 0x41, 0x40, 0x40, 0x3e, +0x3d, 0x3c, 0x3c, 0x3a, 0x39, 0x38, 0x38, 0x38, 0x38, 0x39, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x39, +0x39, 0x39, 0x39, 0x38, 0x38, 0x37, 0x36, 0x36, 0x37, 0x3a, 0x3b, 0x3d, 0x3e, 0x3f, 0x41, 0x41, 0x42, 0x42, 0x41, 0x42, +0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x41, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x40, +0x3f, 0x3c, 0x3b, 0x3a, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x37, 0x38, 0x38, 0x39, +0x39, 0x39, 0x38, 0x39, 0x38, 0x39, 0x39, 0x38, 0x39, 0x39, 0x37, 0x37, 0x36, 0x35, 0x35, 0x35, 0x37, 0x38, 0x38, 0x39, +0x39, 0x3a, 0x3a, 0x3a, 0x3c, 0x3d, 0x3e, 0x3f, 0x41, 0x41, 0x41, 0x42, 0x41, 0x40, 0x41, 0x42, 0x42, 0x43, 0x42, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, +0x42, 0x42, 0x41, 0x3f, 0x3d, 0x3b, 0x3b, 0x39, 0x38, 0x37, 0x37, 0x37, 0x37, 0x38, 0x39, 0x3a, 0x39, 0x38, 0x38, 0x39, +0x38, 0x37, 0x36, 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x38, 0x37, 0x37, 0x38, 0x38, 0x39, 0x38, 0x37, 0x38, 0x37, 0x37, +0x34, 0x34, 0x34, 0x34, 0x36, 0x37, 0x37, 0x38, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x3a, 0x3a, 0x3c, 0x3d, 0x3f, +0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x42, 0x43, 0x42, 0x42, 0x43, 0x43, 0x42, 0x40, 0x3f, 0x3d, 0x3a, 0x38, 0x38, 0x38, 0x38, 0x38, 0x37, 0x36, 0x35, +0x36, 0x37, 0x38, 0x39, 0x39, 0x39, 0x37, 0x38, 0x37, 0x37, 0x36, 0x35, 0x35, 0x35, 0x37, 0x37, 0x37, 0x38, 0x37, 0x37, +0x37, 0x38, 0x38, 0x37, 0x37, 0x37, 0x35, 0x34, 0x34, 0x32, 0x32, 0x33, 0x35, 0x37, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, +0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3b, 0x3d, 0x3f, 0x41, 0x41, 0x40, 0x41, 0x41, 0x41, 0x41, 0x42, +0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x40, 0x3d, 0x3c, 0x3a, 0x3b, 0x3b, 0x3a, +0x39, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x35, 0x35, 0x35, 0x36, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x37, 0x38, +0x38, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x39, 0x38, 0x37, 0x34, 0x32, 0x33, 0x35, +0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x38, 0x38, 0x39, 0x39, 0x37, 0x38, 0x39, +0x3a, 0x3d, 0x3e, 0x41, 0x40, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x41, 0x3e, +0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x38, 0x38, 0x39, 0x3c, +0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3b, 0x3a, 0x3a, 0x39, 0x3b, 0x3c, 0x3d, 0x3c, 0x3b, 0x3c, 0x3b, 0x3c, 0x3c, 0x3c, +0x3b, 0x3b, 0x3a, 0x38, 0x37, 0x36, 0x37, 0x39, 0x3b, 0x3d, 0x3e, 0x3d, 0x3d, 0x3c, 0x3b, 0x3b, 0x39, 0x38, 0x37, 0x38, +0x38, 0x38, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x3a, 0x3d, 0x40, 0x42, 0x43, 0x42, 0x42, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x42, 0x43, 0x42, 0x42, 0x40, 0x3c, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x3a, 0x39, 0x3a, 0x39, 0x3b, 0x3a, 0x3b, +0x3d, 0x3b, 0x3b, 0x3a, 0x39, 0x39, 0x39, 0x3b, 0x3c, 0x3d, 0x3d, 0x3c, 0x3c, 0x3b, 0x3a, 0x3a, 0x39, 0x39, 0x3a, 0x3b, +0x3c, 0x3b, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x39, 0x39, 0x37, 0x35, 0x34, 0x36, 0x39, 0x3b, 0x3d, 0x3d, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3b, 0x38, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x38, 0x39, 0x39, +0x3a, 0x3a, 0x3d, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x43, 0x42, 0x3f, 0x3d, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, +0x39, 0x39, 0x3c, 0x3f, 0x40, 0x40, 0x3f, 0x3e, 0x3c, 0x3c, 0x3a, 0x39, 0x39, 0x38, 0x38, 0x39, 0x3a, 0x3c, 0x3d, 0x3c, +0x3b, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x38, 0x3a, 0x3a, 0x3b, 0x3a, 0x39, 0x3a, 0x3b, 0x3a, 0x3b, 0x3a, 0x38, 0x37, 0x34, +0x33, 0x34, 0x37, 0x39, 0x3a, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3b, 0x3d, 0x3d, 0x3c, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, +0x39, 0x38, 0x35, 0x35, 0x36, 0x38, 0x38, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3d, 0x40, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x40, 0x3c, 0x3b, 0x3a, +0x3a, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x3a, 0x3c, 0x3e, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3f, 0x3e, 0x3d, 0x3b, 0x3b, 0x3a, +0x38, 0x37, 0x36, 0x36, 0x38, 0x3a, 0x3c, 0x3c, 0x3a, 0x3a, 0x39, 0x37, 0x36, 0x36, 0x36, 0x38, 0x3a, 0x39, 0x39, 0x38, +0x39, 0x3a, 0x39, 0x39, 0x38, 0x36, 0x34, 0x32, 0x32, 0x33, 0x36, 0x38, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, +0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x39, 0x39, 0x39, 0x3a, 0x3b, 0x3b, 0x3b, +0x3b, 0x3b, 0x3d, 0x41, 0x43, 0x43, 0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x41, 0x41, 0x41, 0x41, 0x41, +0x41, 0x41, 0x3f, 0x3c, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x39, 0x3d, 0x3f, 0x3f, 0x3f, 0x3e, 0x3d, 0x3d, 0x3d, +0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3c, 0x3b, 0x39, 0x38, 0x37, 0x36, 0x35, 0x36, 0x37, 0x39, 0x3b, 0x3a, 0x39, 0x38, 0x37, +0x35, 0x34, 0x35, 0x36, 0x37, 0x38, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x37, 0x34, 0x32, 0x2f, 0x2f, 0x33, 0x37, 0x38, +0x3a, 0x3a, 0x3a, 0x39, 0x3a, 0x3a, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x38, 0x39, 0x39, 0x39, 0x3b, 0x3c, 0x3d, +0x3e, 0x3e, 0x3f, 0x3c, 0x3a, 0x3a, 0x3a, 0x3b, 0x3a, 0x3a, 0x3b, 0x3c, 0x3c, 0x41, 0x43, 0x43, 0x42, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x42, 0x43, 0x42, 0x41, 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3b, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, +0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x39, 0x39, 0x37, 0x36, 0x35, +0x33, 0x35, 0x37, 0x3a, 0x39, 0x38, 0x37, 0x37, 0x35, 0x33, 0x33, 0x34, 0x36, 0x37, 0x36, 0x37, 0x36, 0x37, 0x37, 0x36, +0x35, 0x33, 0x30, 0x2e, 0x2f, 0x33, 0x36, 0x38, 0x39, 0x38, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x39, 0x39, 0x3a, 0x38, 0x38, +0x38, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3c, 0x3d, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x3e, 0x3b, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, +0x3a, 0x3b, 0x3e, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, 0x40, 0x3f, 0x3d, 0x38, 0x38, 0x38, 0x38, +0x38, 0x37, 0x38, 0x3a, 0x3e, 0x3f, 0x3f, 0x3f, 0x3e, 0x3f, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, +0x3c, 0x3c, 0x3c, 0x3a, 0x38, 0x37, 0x36, 0x34, 0x33, 0x33, 0x34, 0x36, 0x39, 0x38, 0x36, 0x35, 0x33, 0x31, 0x30, 0x31, +0x32, 0x32, 0x32, 0x31, 0x32, 0x32, 0x33, 0x33, 0x32, 0x30, 0x2d, 0x2d, 0x30, 0x33, 0x36, 0x38, 0x38, 0x38, 0x37, 0x38, +0x38, 0x38, 0x38, 0x38, 0x38, 0x37, 0x37, 0x36, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3c, 0x3d, 0x3d, 0x3f, 0x3f, 0x3f, 0x3f, +0x40, 0x40, 0x40, 0x3f, 0x3b, 0x3a, 0x3a, 0x3a, 0x3b, 0x3a, 0x3b, 0x3c, 0x40, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, +0x41, 0x3f, 0x3b, 0x38, 0x37, 0x37, 0x36, 0x36, 0x36, 0x38, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, +0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x37, 0x36, 0x34, 0x33, 0x31, 0x31, 0x31, +0x32, 0x31, 0x2e, 0x2b, 0x27, 0x24, 0x23, 0x23, 0x24, 0x25, 0x25, 0x24, 0x25, 0x26, 0x26, 0x26, 0x24, 0x22, 0x20, 0x23, +0x27, 0x2d, 0x31, 0x34, 0x36, 0x37, 0x36, 0x36, 0x37, 0x37, 0x38, 0x37, 0x36, 0x35, 0x33, 0x35, 0x36, 0x36, 0x38, 0x39, +0x3c, 0x3d, 0x3d, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, +0x3b, 0x3e, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, +0x42, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x40, 0x3f, 0x3b, 0x38, 0x38, 0x37, 0x37, 0x35, 0x36, 0x3a, 0x3b, 0x3b, 0x3b, +0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3a, 0x3a, 0x39, 0x39, 0x3a, 0x3a, 0x3a, +0x3a, 0x38, 0x35, 0x31, 0x2c, 0x28, 0x24, 0x23, 0x24, 0x24, 0x22, 0x21, 0x1f, 0x1c, 0x1b, 0x1b, 0x1e, 0x1f, 0x20, 0x20, +0x20, 0x21, 0x21, 0x1f, 0x1c, 0x19, 0x17, 0x19, 0x1d, 0x23, 0x26, 0x27, 0x28, 0x2b, 0x2e, 0x31, 0x35, 0x36, 0x35, 0x35, +0x33, 0x33, 0x34, 0x35, 0x36, 0x37, 0x39, 0x3b, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3f, 0x3e, 0x3e, 0x3f, 0x3f, 0x3e, 0x3f, +0x40, 0x40, 0x40, 0x3e, 0x39, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3d, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x3e, 0x39, 0x3a, 0x39, 0x38, +0x38, 0x36, 0x38, 0x3c, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x3a, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3c, 0x3c, 0x3b, 0x3b, 0x3a, +0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x39, 0x38, 0x34, 0x31, 0x2c, 0x28, 0x22, 0x1e, 0x1c, 0x1c, 0x1e, 0x20, 0x24, 0x23, +0x22, 0x21, 0x21, 0x22, 0x25, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x26, 0x21, 0x1c, 0x1a, 0x1c, 0x20, 0x22, 0x23, 0x20, +0x21, 0x21, 0x24, 0x26, 0x29, 0x2c, 0x2d, 0x2f, 0x32, 0x33, 0x33, 0x35, 0x37, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3d, 0x3e, +0x3e, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40, 0x3c, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, +0x40, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, +0x42, 0x41, 0x3e, 0x39, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x3c, 0x3c, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x37, 0x37, 0x38, +0x37, 0x38, 0x39, 0x39, 0x3a, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x38, 0x38, 0x37, 0x33, 0x2f, 0x2c, 0x28, 0x27, 0x25, 0x23, +0x22, 0x22, 0x20, 0x21, 0x25, 0x2b, 0x30, 0x32, 0x30, 0x2c, 0x2a, 0x29, 0x2a, 0x2c, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2b, +0x28, 0x24, 0x27, 0x2b, 0x30, 0x2e, 0x2b, 0x26, 0x23, 0x22, 0x22, 0x21, 0x20, 0x1f, 0x21, 0x25, 0x29, 0x2d, 0x33, 0x36, +0x38, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3d, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, +0x3f, 0x40, 0x3e, 0x39, 0x39, 0x3a, 0x39, 0x3a, 0x3b, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x42, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x3f, 0x3a, 0x3b, 0x3a, 0x39, 0x39, 0x3a, 0x3e, 0x3e, 0x3e, 0x3d, +0x3c, 0x3b, 0x3a, 0x38, 0x38, 0x36, 0x36, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x38, 0x39, 0x39, 0x3a, 0x39, 0x37, 0x32, +0x2e, 0x29, 0x25, 0x22, 0x23, 0x24, 0x25, 0x29, 0x2e, 0x30, 0x31, 0x2e, 0x2b, 0x2c, 0x2d, 0x2f, 0x2c, 0x27, 0x23, 0x20, +0x20, 0x22, 0x23, 0x24, 0x24, 0x25, 0x25, 0x23, 0x1f, 0x1f, 0x24, 0x2a, 0x2f, 0x2f, 0x2f, 0x30, 0x31, 0x30, 0x2b, 0x26, +0x20, 0x1e, 0x1d, 0x1e, 0x20, 0x26, 0x2b, 0x32, 0x36, 0x3a, 0x3b, 0x3b, 0x3c, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3f, 0x41, +0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x40, 0x3b, 0x3c, 0x3b, +0x3b, 0x3a, 0x3c, 0x40, 0x3f, 0x3e, 0x3f, 0x3e, 0x3e, 0x3d, 0x3b, 0x3a, 0x3a, 0x38, 0x36, 0x36, 0x34, 0x33, 0x33, 0x33, +0x34, 0x34, 0x35, 0x36, 0x37, 0x32, 0x2f, 0x2a, 0x25, 0x23, 0x23, 0x23, 0x25, 0x2c, 0x32, 0x34, 0x35, 0x33, 0x31, 0x2c, +0x27, 0x21, 0x21, 0x22, 0x21, 0x1d, 0x1a, 0x16, 0x16, 0x17, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x18, 0x14, 0x14, 0x1a, 0x20, +0x24, 0x25, 0x28, 0x2b, 0x2e, 0x30, 0x2f, 0x2e, 0x2d, 0x28, 0x23, 0x21, 0x22, 0x23, 0x25, 0x2a, 0x2f, 0x33, 0x38, 0x3b, +0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3d, 0x3e, 0x3f, 0x3f, 0x3f, +0x3f, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x39, 0x3f, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x41, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x41, 0x41, 0x40, 0x40, 0x3f, 0x3e, 0x3e, 0x3d, 0x3c, 0x3c, +0x3a, 0x3a, 0x38, 0x36, 0x35, 0x34, 0x32, 0x31, 0x30, 0x31, 0x32, 0x2e, 0x2a, 0x27, 0x24, 0x23, 0x24, 0x25, 0x27, 0x2e, +0x33, 0x32, 0x32, 0x31, 0x2e, 0x2c, 0x28, 0x23, 0x1f, 0x1c, 0x19, 0x1b, 0x1d, 0x1c, 0x17, 0x13, 0x11, 0x12, 0x14, 0x16, +0x16, 0x16, 0x15, 0x11, 0xf, 0x12, 0x17, 0x1b, 0x1c, 0x1d, 0x1f, 0x20, 0x22, 0x26, 0x27, 0x2a, 0x2d, 0x2e, 0x30, 0x30, +0x2b, 0x27, 0x26, 0x26, 0x26, 0x2b, 0x30, 0x34, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3a, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, +0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3f, 0x3e, 0x3e, 0x3f, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x40, 0x41, 0x41, 0x42, +0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x3d, 0x3c, 0x3b, 0x3b, 0x3b, 0x3c, 0x40, 0x40, 0x40, +0x41, 0x40, 0x40, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x36, 0x34, 0x32, 0x31, 0x2f, 0x29, 0x24, +0x20, 0x1d, 0x1e, 0x20, 0x26, 0x2e, 0x34, 0x33, 0x31, 0x2d, 0x2a, 0x26, 0x23, 0x22, 0x23, 0x22, 0x20, 0x1d, 0x1a, 0x17, +0x19, 0x1a, 0x14, 0x10, 0xc, 0xc, 0xe, 0x10, 0x10, 0x10, 0xf, 0xb, 0x9, 0xf, 0x15, 0x18, 0x18, 0x1a, 0x1b, 0x1b, +0x1c, 0x1b, 0x1d, 0x20, 0x26, 0x2b, 0x32, 0x35, 0x36, 0x33, 0x2c, 0x27, 0x26, 0x25, 0x27, 0x2c, 0x31, 0x36, 0x39, 0x39, +0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x38, +0x38, 0x38, 0x38, 0x39, 0x3b, 0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x43, 0x3e, 0x3b, +0x3b, 0x3b, 0x3a, 0x3a, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x40, 0x3f, 0x40, 0x3f, 0x3e, 0x3e, 0x3d, 0x3c, 0x3c, 0x3a, +0x3a, 0x38, 0x37, 0x36, 0x31, 0x2b, 0x24, 0x1e, 0x1b, 0x1b, 0x1c, 0x26, 0x2d, 0x2f, 0x2f, 0x2d, 0x2a, 0x26, 0x22, 0x20, +0x1f, 0x1f, 0x20, 0x20, 0x20, 0x1f, 0x19, 0x15, 0x12, 0x14, 0x11, 0x9, 0x4, 0x2, 0x4, 0x6, 0x7, 0x7, 0x5, 0x3, +0x5, 0xb, 0x11, 0x12, 0x14, 0x15, 0x17, 0x17, 0x16, 0x18, 0x1a, 0x1e, 0x22, 0x26, 0x2c, 0x30, 0x34, 0x36, 0x36, 0x31, +0x28, 0x25, 0x24, 0x24, 0x2a, 0x2f, 0x34, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, +0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x37, 0x38, 0x39, 0x38, 0x39, 0x3d, 0x41, 0x41, 0x41, 0x42, 0x42, 0x43, +0x43, 0x43, 0x43, 0x42, 0x42, 0x40, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3f, 0x40, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3f, +0x3f, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3c, 0x3b, 0x3a, 0x35, 0x2f, 0x28, 0x21, 0x1f, 0x1f, 0x20, 0x28, 0x2a, +0x2a, 0x29, 0x26, 0x21, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, 0x1c, 0x1c, 0x17, 0x11, 0xa, 0x6, 0x5, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6, 0xa, 0xe, 0x10, 0x10, 0x11, 0x14, 0x17, 0x1b, 0x1e, +0x20, 0x23, 0x26, 0x28, 0x2d, 0x31, 0x35, 0x34, 0x33, 0x2a, 0x25, 0x24, 0x24, 0x28, 0x2e, 0x34, 0x38, 0x39, 0x38, 0x39, +0x38, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x39, 0x3a, 0x3b, 0x3a, 0x3a, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3b, 0x37, 0x38, 0x38, +0x38, 0x39, 0x3f, 0x40, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x42, 0x41, 0x3d, 0x3a, 0x3b, 0x3a, 0x3a, 0x3d, 0x40, +0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x39, 0x32, +0x2c, 0x25, 0x24, 0x25, 0x28, 0x30, 0x30, 0x2e, 0x28, 0x22, 0x1b, 0x1a, 0x1a, 0x1b, 0x1c, 0x1e, 0x1e, 0x1c, 0x1b, 0x18, +0x15, 0x10, 0xe, 0x8, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x1, 0x3, 0x7, 0xd, 0x12, 0x16, 0x1b, 0x1d, 0x1f, 0x20, 0x21, 0x23, 0x25, 0x2a, 0x2e, 0x33, 0x33, 0x35, 0x2c, 0x24, +0x24, 0x23, 0x26, 0x2c, 0x32, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x37, 0x38, 0x39, 0x39, 0x3b, 0x3a, +0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x38, 0x38, 0x37, 0x38, 0x39, 0x3b, 0x40, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x42, 0x42, +0x40, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x3f, 0x40, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, +0x3c, 0x3d, 0x3c, 0x3c, 0x3c, 0x39, 0x34, 0x2e, 0x28, 0x27, 0x29, 0x2d, 0x35, 0x36, 0x34, 0x2e, 0x27, 0x20, 0x1e, 0x1b, +0x18, 0x18, 0x18, 0x17, 0x19, 0x16, 0x12, 0xe, 0x9, 0x5, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xd, 0x11, 0x17, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, +0x22, 0x24, 0x28, 0x2e, 0x32, 0x33, 0x33, 0x2b, 0x23, 0x22, 0x22, 0x26, 0x2c, 0x31, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, +0x37, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3a, 0x3a, 0x3a, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3f, +0x42, 0x41, 0x42, 0x43, 0x43, 0x42, 0x42, 0x42, 0x3d, 0x3b, 0x3a, 0x3a, 0x3a, 0x3e, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, +0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x35, 0x2f, 0x29, 0x26, 0x28, 0x2c, 0x36, +0x38, 0x38, 0x33, 0x2e, 0x27, 0x24, 0x22, 0x1f, 0x1e, 0x1b, 0x18, 0x14, 0xf, 0xb, 0x7, 0x1, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x6, 0xa, 0x10, 0x15, 0x17, 0x1a, 0x1c, 0x1e, 0x1f, 0x21, 0x22, 0x25, 0x2b, 0x31, 0x31, 0x31, 0x28, 0x21, 0x20, 0x20, +0x26, 0x2b, 0x30, 0x33, 0x33, 0x35, 0x34, 0x35, 0x37, 0x37, 0x38, 0x39, 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3e, +0x3e, 0x3f, 0x3a, 0x39, 0x39, 0x3a, 0x3a, 0x3d, 0x42, 0x43, 0x42, 0x43, 0x43, 0x43, 0x42, 0x41, 0x3b, 0x3b, 0x3a, 0x3a, +0x3a, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, +0x35, 0x2f, 0x29, 0x25, 0x26, 0x28, 0x32, 0x37, 0x37, 0x33, 0x2e, 0x28, 0x28, 0x27, 0x26, 0x24, 0x23, 0x20, 0x1c, 0x15, +0xd, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x8, 0xd, 0x13, 0x17, 0x19, 0x1a, 0x1c, 0x1d, 0x20, 0x20, +0x25, 0x2a, 0x2f, 0x2e, 0x2d, 0x23, 0x1f, 0x1f, 0x22, 0x28, 0x2e, 0x34, 0x35, 0x35, 0x37, 0x37, 0x38, 0x38, 0x38, 0x3a, +0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3e, 0x3e, 0x3e, 0x3f, 0x40, 0x3f, 0x3a, 0x3a, 0x3a, 0x3b, 0x3c, 0x42, 0x43, 0x42, 0x43, +0x43, 0x43, 0x43, 0x3f, 0x3b, 0x3b, 0x3a, 0x3b, 0x3c, 0x41, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3d, 0x3e, 0x3c, +0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x39, 0x3a, 0x38, 0x32, 0x2b, 0x26, 0x25, 0x26, 0x2b, 0x35, 0x36, 0x33, 0x2e, 0x29, 0x27, +0x25, 0x25, 0x26, 0x26, 0x24, 0x23, 0x1c, 0x16, 0xd, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, +0xb, 0x10, 0x14, 0x17, 0x19, 0x1a, 0x1b, 0x1d, 0x20, 0x26, 0x2b, 0x30, 0x30, 0x2a, 0x21, 0x21, 0x21, 0x26, 0x2d, 0x33, +0x37, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3e, 0x3f, 0x3e, 0x3f, 0x40, 0x40, 0x40, 0x3b, +0x3b, 0x3a, 0x3b, 0x3b, 0x40, 0x42, 0x43, 0x43, 0x43, 0x43, 0x42, 0x3d, 0x3b, 0x3a, 0x3a, 0x3a, 0x3e, 0x40, 0x40, 0x40, +0x3f, 0x3f, 0x3f, 0x3e, 0x3f, 0x3e, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3c, 0x3b, 0x3a, 0x3a, 0x36, 0x30, 0x29, 0x25, 0x25, +0x26, 0x30, 0x35, 0x34, 0x2f, 0x2a, 0x25, 0x24, 0x24, 0x24, 0x24, 0x22, 0x22, 0x1e, 0x18, 0x13, 0xb, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0xa, 0x11, 0x15, 0x17, 0x1b, 0x1d, 0x1f, 0x21, 0x25, 0x2b, 0x31, +0x32, 0x31, 0x27, 0x23, 0x23, 0x26, 0x2d, 0x34, 0x39, 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3e, 0x3e, 0x3f, +0x3e, 0x3f, 0x3f, 0x40, 0x40, 0x41, 0x41, 0x3d, 0x3a, 0x3b, 0x3a, 0x3b, 0x3f, 0x43, 0x42, 0x43, 0x43, 0x42, 0x42, 0x3c, +0x3b, 0x3a, 0x3a, 0x39, 0x3f, 0x41, 0x3f, 0x40, 0x3f, 0x3e, 0x3f, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3d, 0x3b, 0x3b, +0x3b, 0x3a, 0x39, 0x35, 0x2f, 0x28, 0x24, 0x26, 0x29, 0x33, 0x35, 0x33, 0x2e, 0x27, 0x24, 0x22, 0x22, 0x22, 0x21, 0x21, +0x1e, 0x1a, 0x14, 0xc, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x9, 0x10, 0x16, +0x19, 0x1c, 0x1f, 0x20, 0x22, 0x25, 0x2b, 0x32, 0x35, 0x35, 0x2d, 0x26, 0x26, 0x27, 0x2d, 0x34, 0x39, 0x3a, 0x3b, 0x3c, +0x3c, 0x3c, 0x3c, 0x3c, 0x3e, 0x3d, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x41, 0x3e, 0x3a, 0x3a, 0x3a, 0x3b, +0x3d, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3e, 0x3f, 0x3e, +0x3e, 0x3e, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x34, 0x2d, 0x27, 0x25, 0x25, 0x2c, 0x35, 0x35, 0x32, +0x2d, 0x26, 0x24, 0x22, 0x22, 0x22, 0x21, 0x20, 0x1c, 0x17, 0x10, 0x8, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xe, 0x15, 0x19, 0x1b, 0x1e, 0x20, 0x22, 0x23, 0x2a, 0x2f, 0x34, 0x35, 0x2e, 0x26, +0x24, 0x24, 0x2b, 0x31, 0x37, 0x3a, 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, +0x3f, 0x3f, 0x40, 0x3f, 0x3a, 0x3a, 0x3a, 0x3b, 0x3d, 0x42, 0x42, 0x43, 0x43, 0x42, 0x42, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, +0x40, 0x41, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x33, +0x2d, 0x27, 0x25, 0x26, 0x2d, 0x35, 0x35, 0x31, 0x2c, 0x26, 0x24, 0x23, 0x23, 0x23, 0x21, 0x20, 0x1b, 0x16, 0xf, 0x7, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xa, 0x11, 0x15, 0x18, 0x1b, 0x1d, +0x1e, 0x20, 0x26, 0x2c, 0x31, 0x32, 0x2c, 0x23, 0x22, 0x22, 0x27, 0x2f, 0x35, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3a, 0x3a, +0x3b, 0x3c, 0x3c, 0x3d, 0x3c, 0x3d, 0x3d, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x39, 0x39, 0x3a, 0x3a, 0x3c, 0x41, 0x42, 0x43, +0x42, 0x43, 0x41, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x40, 0x40, 0x40, 0x3f, 0x3e, 0x3e, 0x3f, 0x3e, 0x3d, 0x3d, 0x3d, 0x3d, +0x3c, 0x3c, 0x3b, 0x3a, 0x3b, 0x3a, 0x39, 0x33, 0x2e, 0x26, 0x25, 0x27, 0x2c, 0x35, 0x35, 0x32, 0x2d, 0x26, 0x25, 0x23, +0x23, 0x23, 0x22, 0x21, 0x1c, 0x17, 0x10, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x7, 0xd, 0x12, 0x13, 0x18, 0x19, 0x1a, 0x1d, 0x24, 0x29, 0x2e, 0x2f, 0x2a, 0x21, 0x20, 0x1f, 0x26, 0x2c, +0x33, 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3f, 0x3e, +0x39, 0x39, 0x3a, 0x3a, 0x3c, 0x41, 0x42, 0x43, 0x43, 0x42, 0x41, 0x3b, 0x3b, 0x3a, 0x3a, 0x39, 0x40, 0x40, 0x40, 0x3f, +0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x35, 0x2f, 0x28, 0x26, 0x27, +0x2b, 0x35, 0x36, 0x35, 0x2f, 0x29, 0x25, 0x22, 0x22, 0x22, 0x20, 0x1f, 0x1a, 0x15, 0xe, 0x6, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xd, 0x12, 0x13, 0x17, 0x18, 0x1b, 0x1d, 0x23, 0x2a, +0x2d, 0x2e, 0x27, 0x20, 0x1e, 0x20, 0x26, 0x2d, 0x33, 0x35, 0x36, 0x37, 0x37, 0x38, 0x38, 0x38, 0x3a, 0x39, 0x3a, 0x3b, +0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3e, 0x3e, 0x3d, 0x38, 0x38, 0x38, 0x39, 0x3b, 0x42, 0x42, 0x43, 0x43, 0x43, 0x41, 0x3d, +0x3b, 0x3a, 0x3b, 0x3a, 0x40, 0x41, 0x40, 0x3f, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3d, 0x3d, 0x3c, 0x3d, 0x3c, 0x3c, +0x3c, 0x3b, 0x3b, 0x36, 0x30, 0x29, 0x25, 0x25, 0x27, 0x31, 0x35, 0x34, 0x2e, 0x28, 0x23, 0x20, 0x1f, 0x1f, 0x1c, 0x1b, +0x16, 0x11, 0xb, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xd, 0x12, +0x15, 0x18, 0x19, 0x1a, 0x1d, 0x20, 0x27, 0x2d, 0x2f, 0x30, 0x25, 0x20, 0x20, 0x22, 0x28, 0x2f, 0x35, 0x36, 0x36, 0x37, +0x38, 0x38, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3f, 0x3c, 0x39, 0x39, 0x39, 0x3a, +0x3c, 0x41, 0x42, 0x43, 0x43, 0x43, 0x43, 0x3d, 0x3b, 0x3b, 0x3b, 0x3a, 0x3e, 0x41, 0x40, 0x40, 0x40, 0x40, 0x3f, 0x3e, +0x3f, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x3a, 0x3a, 0x39, 0x39, 0x36, 0x2f, 0x29, 0x23, 0x23, 0x24, 0x2b, 0x31, 0x31, +0x2c, 0x27, 0x1f, 0x1d, 0x1a, 0x19, 0x17, 0x17, 0x15, 0x10, 0xb, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x6, 0xd, 0x13, 0x17, 0x18, 0x1b, 0x1d, 0x1d, 0x20, 0x26, 0x2b, 0x30, 0x31, 0x2d, 0x23, 0x21, +0x21, 0x25, 0x2c, 0x32, 0x37, 0x37, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3e, 0x3e, +0x3e, 0x3f, 0x3f, 0x3c, 0x39, 0x39, 0x39, 0x3a, 0x3e, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x40, 0x3c, 0x3b, 0x3b, 0x3b, +0x3b, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3b, 0x3a, 0x3a, 0x39, 0x39, 0x38, 0x37, 0x37, 0x36, +0x30, 0x2a, 0x22, 0x1f, 0x1f, 0x22, 0x2b, 0x2d, 0x2b, 0x26, 0x20, 0x1b, 0x19, 0x18, 0x18, 0x17, 0x14, 0x13, 0x10, 0xd, +0x8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xa, 0x11, 0x16, 0x19, 0x1d, 0x1d, 0x1e, 0x21, +0x25, 0x2a, 0x31, 0x31, 0x33, 0x29, 0x23, 0x23, 0x24, 0x29, 0x30, 0x36, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, +0x3b, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3f, 0x3e, 0x40, 0x40, 0x3b, 0x39, 0x3a, 0x3a, 0x3a, 0x3f, 0x42, 0x42, 0x43, +0x43, 0x43, 0x42, 0x41, 0x3b, 0x3b, 0x3a, 0x3a, 0x39, 0x40, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3c, 0x3b, 0x3b, 0x3a, +0x39, 0x39, 0x37, 0x37, 0x36, 0x35, 0x34, 0x33, 0x30, 0x2a, 0x23, 0x1d, 0x1c, 0x1e, 0x24, 0x2d, 0x2c, 0x2a, 0x25, 0x1e, +0x1b, 0x19, 0x18, 0x19, 0x18, 0x17, 0x16, 0x13, 0xf, 0xb, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x9, 0xd, +0xf, 0x13, 0x17, 0x19, 0x1b, 0x1c, 0x1f, 0x23, 0x29, 0x2f, 0x33, 0x34, 0x2d, 0x25, 0x23, 0x23, 0x27, 0x2e, 0x34, 0x39, +0x38, 0x38, 0x39, 0x39, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x39, +0x39, 0x39, 0x3a, 0x3b, 0x41, 0x42, 0x42, 0x43, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x3a, 0x3a, 0x39, 0x39, 0x3c, 0x3e, 0x3d, +0x3e, 0x3c, 0x3c, 0x3b, 0x3a, 0x3a, 0x39, 0x38, 0x37, 0x37, 0x36, 0x35, 0x34, 0x33, 0x33, 0x32, 0x31, 0x2d, 0x27, 0x22, +0x1d, 0x1d, 0x1d, 0x26, 0x2d, 0x2c, 0x2a, 0x26, 0x21, 0x1e, 0x1c, 0x1b, 0x1b, 0x1b, 0x1a, 0x19, 0x17, 0x14, 0xf, 0xa, +0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x6, 0xd, 0x12, 0x16, 0x18, 0x18, 0x19, 0x19, 0x18, 0x19, 0x1c, 0x1f, 0x25, 0x2b, 0x30, 0x32, 0x2f, +0x26, 0x25, 0x24, 0x27, 0x2d, 0x32, 0x37, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3d, 0x3d, 0x3d, +0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x40, 0x3b, 0x39, 0x3a, 0x3a, 0x3b, 0x3d, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x42, 0x42, +0x3e, 0x3a, 0x39, 0x39, 0x38, 0x37, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x37, 0x37, 0x37, 0x35, 0x35, +0x35, 0x34, 0x34, 0x32, 0x33, 0x32, 0x2c, 0x27, 0x20, 0x1d, 0x1f, 0x1f, 0x28, 0x30, 0x2f, 0x2e, 0x28, 0x23, 0x20, 0x1f, +0x1e, 0x1e, 0x1e, 0x1d, 0x1b, 0x19, 0x15, 0x11, 0xb, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0xa, 0x10, 0x15, 0x1a, 0x1e, 0x20, 0x1f, 0x1f, 0x1c, 0x1d, +0x1d, 0x1f, 0x23, 0x2a, 0x2d, 0x2e, 0x2c, 0x24, 0x20, 0x22, 0x24, 0x2a, 0x31, 0x37, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, +0x3c, 0x3b, 0x3c, 0x3c, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x40, 0x3f, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x40, +0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x41, 0x42, 0x41, 0x3b, 0x39, 0x38, 0x38, 0x38, 0x3a, 0x3d, 0x3c, 0x3b, 0x3c, 0x3b, +0x3a, 0x38, 0x38, 0x37, 0x38, 0x37, 0x37, 0x36, 0x35, 0x34, 0x35, 0x34, 0x33, 0x34, 0x33, 0x2e, 0x29, 0x23, 0x21, 0x21, +0x21, 0x2a, 0x31, 0x31, 0x30, 0x2c, 0x29, 0x23, 0x22, 0x20, 0x1f, 0x1d, 0x1b, 0x1b, 0x17, 0x15, 0x11, 0xc, 0xa, 0xb, +0xb, 0x7, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x4, 0x6, 0x6, 0x6, 0x9, 0x10, 0x14, 0x17, +0x1a, 0x1c, 0x1e, 0x21, 0x22, 0x22, 0x23, 0x22, 0x26, 0x29, 0x2d, 0x2d, 0x2d, 0x29, 0x20, 0x1e, 0x1f, 0x21, 0x27, 0x2d, +0x34, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3c, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, +0x40, 0x3b, 0x39, 0x3a, 0x3a, 0x3a, 0x3d, 0x42, 0x42, 0x42, 0x43, 0x43, 0x42, 0x43, 0x42, 0x41, 0x41, 0x3e, 0x39, 0x39, +0x38, 0x37, 0x37, 0x3b, 0x3d, 0x3c, 0x3c, 0x3a, 0x3b, 0x39, 0x39, 0x39, 0x39, 0x38, 0x37, 0x36, 0x36, 0x37, 0x36, 0x36, +0x36, 0x36, 0x36, 0x35, 0x30, 0x2b, 0x26, 0x22, 0x22, 0x24, 0x29, 0x31, 0x34, 0x34, 0x30, 0x2c, 0x27, 0x22, 0x20, 0x1d, +0x1c, 0x19, 0x17, 0x14, 0x12, 0x13, 0x15, 0x16, 0x15, 0x10, 0xb, 0x3, 0x0, 0x0, 0x4, 0x8, 0xd, 0xf, 0x10, 0x10, +0x11, 0x13, 0x14, 0x12, 0x11, 0x13, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f, 0x23, 0x24, 0x29, 0x2d, 0x31, 0x33, 0x32, 0x31, +0x29, 0x20, 0x1e, 0x1d, 0x1f, 0x25, 0x2c, 0x31, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3e, +0x3d, 0x3e, 0x3f, 0x3f, 0x3f, 0x40, 0x3f, 0x3f, 0x3d, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x40, 0x42, 0x42, 0x42, 0x43, 0x43, +0x43, 0x42, 0x42, 0x41, 0x41, 0x41, 0x3b, 0x39, 0x38, 0x38, 0x37, 0x37, 0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x39, +0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, 0x37, 0x33, 0x2e, 0x29, 0x24, 0x24, 0x25, 0x26, +0x2e, 0x35, 0x33, 0x33, 0x2e, 0x2a, 0x24, 0x1f, 0x1c, 0x19, 0x17, 0x15, 0x16, 0x19, 0x1a, 0x1b, 0x18, 0x14, 0xe, 0x9, +0x5, 0xa, 0xf, 0x13, 0x17, 0x19, 0x1a, 0x18, 0x17, 0x19, 0x19, 0x18, 0x16, 0x15, 0x18, 0x1a, 0x1c, 0x1d, 0x1f, 0x21, +0x25, 0x2a, 0x30, 0x35, 0x37, 0x36, 0x32, 0x29, 0x23, 0x21, 0x20, 0x23, 0x28, 0x2c, 0x30, 0x33, 0x33, 0x34, 0x35, 0x36, +0x37, 0x38, 0x39, 0x39, 0x3a, 0x3b, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x40, 0x40, 0x40, 0x39, 0x3a, 0x3a, 0x3b, +0x3b, 0x3f, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41, 0x3f, 0x3a, 0x38, 0x38, 0x38, 0x37, +0x39, 0x3c, 0x3d, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x39, +0x39, 0x39, 0x36, 0x31, 0x2c, 0x28, 0x24, 0x25, 0x25, 0x27, 0x2e, 0x32, 0x31, 0x2f, 0x2c, 0x27, 0x22, 0x1d, 0x19, 0x1a, +0x1b, 0x1c, 0x1d, 0x1c, 0x19, 0x16, 0x10, 0xb, 0xa, 0x10, 0x13, 0x16, 0x1a, 0x1c, 0x1d, 0x1c, 0x1b, 0x1c, 0x1c, 0x1c, +0x1a, 0x19, 0x18, 0x1b, 0x1d, 0x22, 0x26, 0x28, 0x2d, 0x31, 0x33, 0x35, 0x32, 0x2c, 0x28, 0x26, 0x25, 0x26, 0x29, 0x2e, +0x30, 0x35, 0x34, 0x33, 0x33, 0x33, 0x34, 0x35, 0x37, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3e, 0x3f, +0x3f, 0x3f, 0x40, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3d, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x41, +0x41, 0x40, 0x40, 0x3d, 0x38, 0x38, 0x37, 0x37, 0x36, 0x39, 0x3d, 0x3e, 0x3d, 0x3d, 0x3d, 0x3e, 0x3c, 0x3c, 0x3d, 0x3c, +0x3c, 0x3b, 0x3b, 0x3a, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x3a, 0x39, 0x34, 0x30, 0x2b, 0x25, 0x23, 0x23, 0x22, 0x24, +0x2a, 0x2f, 0x2e, 0x2c, 0x2a, 0x28, 0x25, 0x24, 0x25, 0x23, 0x20, 0x1f, 0x1b, 0x16, 0x11, 0xd, 0xe, 0x15, 0x17, 0x1a, +0x1d, 0x1f, 0x1f, 0x1e, 0x1d, 0x1d, 0x1f, 0x1f, 0x1e, 0x1f, 0x20, 0x21, 0x26, 0x2b, 0x30, 0x31, 0x31, 0x32, 0x2d, 0x28, +0x25, 0x25, 0x26, 0x27, 0x2c, 0x30, 0x34, 0x37, 0x38, 0x37, 0x36, 0x36, 0x36, 0x35, 0x34, 0x36, 0x35, 0x37, 0x38, 0x38, +0x39, 0x3a, 0x3a, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3f, 0x3e, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3c, 0x41, 0x43, 0x42, 0x43, +0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x40, 0x41, 0x40, 0x40, 0x3f, 0x3d, 0x38, 0x39, 0x38, 0x38, 0x38, 0x3a, 0x3f, +0x3f, 0x3e, 0x3e, 0x3d, 0x3d, 0x3e, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, +0x3a, 0x38, 0x32, 0x2d, 0x29, 0x24, 0x21, 0x20, 0x20, 0x1f, 0x23, 0x26, 0x2b, 0x2c, 0x2e, 0x31, 0x31, 0x2f, 0x2b, 0x27, +0x21, 0x1d, 0x17, 0x14, 0x17, 0x1b, 0x1c, 0x1f, 0x22, 0x25, 0x25, 0x24, 0x24, 0x26, 0x27, 0x28, 0x2b, 0x2c, 0x2c, 0x2c, +0x2c, 0x2e, 0x30, 0x2f, 0x2a, 0x24, 0x23, 0x22, 0x23, 0x24, 0x29, 0x2f, 0x34, 0x39, 0x3b, 0x3b, 0x3b, 0x3a, 0x39, 0x39, +0x37, 0x38, 0x38, 0x37, 0x37, 0x37, 0x37, 0x38, 0x39, 0x39, 0x3a, 0x3b, 0x3b, 0x3d, 0x3e, 0x3e, 0x3d, 0x38, 0x38, 0x39, +0x39, 0x3a, 0x3a, 0x40, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x40, +0x41, 0x3e, 0x3a, 0x3a, 0x3a, 0x39, 0x38, 0x3a, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, +0x3d, 0x3c, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x31, 0x2c, 0x27, 0x22, 0x1e, 0x1c, 0x1b, 0x1c, +0x1d, 0x23, 0x2a, 0x30, 0x33, 0x32, 0x30, 0x2e, 0x2a, 0x26, 0x23, 0x22, 0x26, 0x29, 0x2a, 0x2c, 0x2f, 0x31, 0x31, 0x31, +0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x2f, 0x2c, 0x27, 0x23, 0x20, 0x21, 0x23, 0x23, 0x22, 0x25, 0x28, 0x2d, 0x31, 0x36, +0x39, 0x3b, 0x3c, 0x3b, 0x3c, 0x3c, 0x3c, 0x3a, 0x3b, 0x39, 0x3a, 0x3a, 0x39, 0x39, 0x38, 0x3a, 0x39, 0x3a, 0x3a, 0x3b, +0x3c, 0x3d, 0x3d, 0x3c, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x3f, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x3f, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x3f, 0x3f, 0x3f, +0x3f, 0x3f, 0x3e, 0x3e, 0x3d, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3a, 0x3a, 0x39, 0x38, 0x38, 0x36, +0x36, 0x34, 0x30, 0x2c, 0x27, 0x23, 0x20, 0x1e, 0x1f, 0x21, 0x24, 0x23, 0x24, 0x24, 0x25, 0x25, 0x24, 0x24, 0x23, 0x26, +0x2a, 0x2d, 0x2e, 0x30, 0x32, 0x35, 0x34, 0x34, 0x31, 0x2f, 0x2e, 0x2c, 0x29, 0x25, 0x22, 0x20, 0x1e, 0x1c, 0x1d, 0x1e, +0x23, 0x28, 0x2d, 0x30, 0x33, 0x36, 0x37, 0x38, 0x38, 0x3a, 0x3b, 0x3c, 0x3d, 0x3d, 0x3e, 0x3d, 0x3c, 0x3d, 0x3b, 0x3b, +0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, 0x3a, 0x37, 0x38, 0x38, 0x38, 0x39, 0x3a, 0x3d, 0x41, 0x40, +0x40, 0x41, 0x41, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x3f, +0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3c, 0x3f, 0x40, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3c, +0x3c, 0x3b, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x34, 0x32, 0x30, 0x2e, 0x2c, 0x2b, 0x2a, 0x2a, 0x27, 0x25, +0x23, 0x21, 0x1f, 0x1c, 0x1a, 0x17, 0x16, 0x18, 0x1d, 0x20, 0x21, 0x22, 0x24, 0x26, 0x26, 0x25, 0x23, 0x22, 0x22, 0x23, +0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x24, 0x27, 0x2c, 0x31, 0x36, 0x38, 0x39, 0x38, 0x38, 0x38, 0x38, 0x39, 0x3a, 0x3c, +0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3d, 0x3e, 0x3d, 0x3c, 0x3d, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x39, 0x37, 0x37, +0x38, 0x38, 0x39, 0x3a, 0x3f, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x40, 0x3c, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x3f, 0x40, 0x3f, 0x3f, +0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3a, 0x3a, 0x39, 0x39, 0x37, 0x36, 0x36, 0x35, 0x33, 0x32, +0x32, 0x33, 0x35, 0x37, 0x38, 0x35, 0x33, 0x30, 0x2d, 0x29, 0x24, 0x20, 0x1d, 0x19, 0x18, 0x1a, 0x1e, 0x1f, 0x20, 0x21, +0x23, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x28, 0x29, 0x2b, 0x2c, 0x2e, 0x2e, 0x30, 0x32, 0x31, 0x32, 0x34, 0x35, 0x37, +0x39, 0x3a, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3e, 0x3f, 0x3e, 0x3e, 0x3e, +0x3d, 0x3e, 0x3d, 0x3b, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x3b, 0x40, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x43, 0x43, 0x42, 0x41, 0x3d, 0x3b, +0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x3b, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3f, 0x3d, 0x3e, 0x3c, 0x3c, 0x3c, 0x3b, 0x3a, +0x39, 0x38, 0x38, 0x37, 0x35, 0x34, 0x34, 0x33, 0x34, 0x36, 0x37, 0x39, 0x39, 0x39, 0x39, 0x38, 0x36, 0x33, 0x30, 0x2c, +0x29, 0x26, 0x26, 0x28, 0x2c, 0x2b, 0x2c, 0x2d, 0x2f, 0x30, 0x31, 0x31, 0x31, 0x31, 0x32, 0x33, 0x36, 0x37, 0x37, 0x37, +0x36, 0x35, 0x35, 0x34, 0x33, 0x33, 0x35, 0x36, 0x39, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3f, +0x3f, 0x3f, 0x40, 0x3f, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x39, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x3c, 0x40, 0x41, +0x41, 0x42, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x43, 0x40, 0x3b, 0x3b, 0x3a, 0x3b, 0x3a, 0x3a, 0x3a, 0x3b, 0x3f, 0x3f, 0x40, 0x3e, +0x3e, 0x3e, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3a, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x35, 0x36, 0x37, 0x39, 0x3a, 0x3a, +0x3b, 0x3a, 0x39, 0x39, 0x37, 0x34, 0x32, 0x30, 0x2e, 0x2d, 0x2f, 0x31, 0x35, 0x36, 0x36, 0x36, 0x38, 0x39, 0x3a, 0x3a, +0x39, 0x39, 0x37, 0x38, 0x38, 0x39, 0x39, 0x39, 0x37, 0x36, 0x36, 0x35, 0x34, 0x35, 0x36, 0x36, 0x38, 0x3a, 0x3c, 0x3b, +0x3c, 0x3b, 0x3c, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3f, 0x3f, 0x40, 0x3f, 0x40, 0x40, 0x41, 0x3f, 0x3b, 0x39, 0x39, 0x39, +0x39, 0x39, 0x39, 0x3b, 0x3f, 0x41, 0x40, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x3d, 0x3b, 0x3b, +0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x3b, 0x3e, 0x3f, 0x3f, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x39, 0x38, 0x37, +0x36, 0x37, 0x38, 0x38, 0x39, 0x3c, 0x3b, 0x3b, 0x3a, 0x3b, 0x3a, 0x38, 0x36, 0x35, 0x33, 0x31, 0x2f, 0x2f, 0x30, 0x33, +0x36, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x38, 0x37, 0x37, +0x36, 0x36, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3d, 0x3d, 0x3f, 0x3e, 0x40, 0x40, +0x40, 0x3f, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3d, 0x41, 0x42, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x40, 0x3c, 0x3b, 0x3a, 0x3b, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x3c, 0x3e, 0x3d, 0x3e, +0x3d, 0x3d, 0x3c, 0x3c, 0x3a, 0x39, 0x38, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x39, +0x37, 0x35, 0x33, 0x32, 0x31, 0x31, 0x33, 0x37, 0x38, 0x38, 0x38, 0x38, 0x3a, 0x3b, 0x3c, 0x3c, 0x3b, 0x3a, 0x39, 0x39, +0x39, 0x3a, 0x3b, 0x3b, 0x3b, 0x3a, 0x38, 0x38, 0x38, 0x37, 0x38, 0x37, 0x38, 0x39, 0x3a, 0x3c, 0x3d, 0x3e, 0x3d, 0x3e, +0x3d, 0x3e, 0x3d, 0x3e, 0x3f, 0x3f, 0x3f, 0x3c, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3d, 0x41, 0x42, 0x42, +0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x40, 0x3c, 0x3a, 0x3b, +0x39, 0x3a, 0x3a, 0x38, 0x38, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x3c, 0x3b, 0x3b, 0x3a, 0x39, 0x39, 0x3a, 0x3a, 0x3c, 0x3c, +0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x39, 0x37, 0x36, 0x35, 0x33, 0x32, 0x33, 0x35, 0x38, 0x39, 0x39, 0x39, 0x3a, +0x3b, 0x3c, 0x3d, 0x3d, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3b, 0x39, 0x39, 0x39, 0x39, 0x38, +0x38, 0x3a, 0x3a, 0x3b, 0x3d, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3b, 0x3a, 0x38, 0x39, 0x39, 0x3a, 0x3b, 0x3b, +0x3b, 0x3b, 0x3d, 0x40, 0x42, 0x42, 0x43, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x40, 0x3c, 0x3b, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, 0x39, 0x3b, +0x3b, 0x3b, 0x3a, 0x3b, 0x3c, 0x3c, 0x3e, 0x3d, 0x3e, 0x3d, 0x3d, 0x3e, 0x3d, 0x3c, 0x3b, 0x39, 0x38, 0x37, 0x35, 0x35, +0x34, 0x35, 0x37, 0x3a, 0x3b, 0x3a, 0x3a, 0x3a, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, +0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x39, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3d, 0x3f, 0x3f, 0x3d, 0x3b, 0x39, 0x39, +0x39, 0x38, 0x38, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3c, 0x41, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x42, 0x42, 0x40, 0x3c, 0x3a, 0x39, +0x39, 0x39, 0x39, 0x38, 0x37, 0x37, 0x36, 0x36, 0x35, 0x37, 0x38, 0x3a, 0x3d, 0x3e, 0x3e, 0x3f, 0x3f, 0x3e, 0x3f, 0x3e, +0x3d, 0x3c, 0x3b, 0x3a, 0x38, 0x38, 0x37, 0x36, 0x35, 0x37, 0x39, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3d, 0x3e, 0x3d, 0x3e, 0x3d, 0x3d, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, +0x3a, 0x39, 0x37, 0x38, 0x3a, 0x3a, 0x39, 0x3a, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3c, 0x40, 0x43, 0x42, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x42, 0x43, 0x42, 0x42, 0x41, 0x41, 0x41, 0x3e, 0x3b, 0x39, 0x39, 0x38, 0x38, 0x37, 0x37, 0x36, 0x37, 0x37, 0x36, 0x37, +0x38, 0x38, 0x3a, 0x3a, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3a, 0x3a, 0x39, 0x38, 0x37, 0x37, 0x38, 0x3a, 0x3c, +0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, +0x3d, 0x3a, 0x3a, 0x3a, 0x37, 0x36, 0x35, 0x35, 0x36, 0x38, 0x37, 0x37, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3c, +0x3f, 0x41, 0x41, 0x42, 0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x41, 0x41, 0x42, 0x42, 0x41, 0x3f, 0x3b, 0x39, +0x39, 0x37, 0x37, 0x38, 0x37, 0x38, 0x38, 0x39, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, +0x36, 0x35, 0x35, 0x35, 0x36, 0x38, 0x39, 0x3b, 0x3b, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, +0x3a, 0x3a, 0x39, 0x39, 0x3a, 0x39, 0x39, 0x38, 0x38, 0x37, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x37, 0x37, 0x38, 0x38, +0x38, 0x39, 0x3a, 0x3a, 0x3c, 0x3d, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, +0x42, 0x42, 0x42, 0x42, 0x41, 0x42, 0x41, 0x40, 0x3f, 0x3b, 0x39, 0x38, 0x38, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, +0x39, 0x39, 0x39, 0x39, 0x38, 0x36, 0x36, 0x35, 0x35, 0x34, 0x33, 0x33, 0x34, 0x35, 0x36, 0x38, 0x37, 0x37, 0x37, 0x37, +0x38, 0x39, 0x39, 0x39, 0x39, 0x38, 0x39, 0x39, 0x37, 0x38, 0x38, 0x39, 0x38, 0x38, 0x39, 0x39, 0x38, 0x38, 0x38, 0x37, +0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3e, 0x40, 0x42, 0x43, 0x42, 0x43, 0x42, 0x42, 0x43, 0x42, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x41, 0x41, 0x41, 0x40, 0x40, 0x3f, 0x3f, +0x3e, 0x3d, 0x3d, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x38, 0x37, 0x37, 0x37, 0x37, 0x36, 0x35, 0x35, 0x34, +0x36, 0x36, 0x38, 0x39, 0x38, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x39, 0x39, 0x38, 0x39, 0x39, +0x3a, 0x3a, 0x39, 0x3a, 0x39, 0x39, 0x39, 0x39, 0x38, 0x39, 0x38, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x3f, 0x40, 0x42, +0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x42, 0x42, 0x41, 0x41, 0x40, 0x40, 0x40, 0x42, 0x42, 0x42, 0x41, 0x40, 0x3e, 0x3d, 0x3b, 0x3b, 0x3a, 0x3a, 0x39, +0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x39, 0x39, 0x39, 0x38, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, +0x39, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x3a, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3f, +0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x40, 0x41, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41, 0x41, 0x41, 0x42, 0x43, 0x43, 0x43, 0x43, +0x42, 0x43, 0x43, 0x42, 0x41, 0x40, 0x3f, 0x3e, 0x3b, 0x3a, 0x3a, 0x39, 0x37, 0x37, 0x36, 0x37, 0x37, 0x38, 0x3a, 0x39, +0x3a, 0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3a, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x39, 0x3b, 0x3c, 0x3d, 0x3d, +0x3f, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x42, 0x41, 0x41, 0x41, 0x42, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x41, 0x42, +0x41, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x42, 0x42, 0x42, 0x42, 0x41, 0x40, 0x40, 0x41, 0x3f, +0x3e, 0x3e, 0x3c, 0x3d, 0x3c, 0x3d, 0x3e, 0x3d, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, +0x3f, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x42, 0x41, 0x42, 0x42, 0x42, 0x43, 0x42, 0x42, 0x43, +0x43, 0x43, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x41, 0x40, 0x41, 0x40, 0x40, 0x3f, 0x40, 0x41, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, +0x42, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, +0x43, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x41, +0x40, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, +0x42, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, +0x43, 0x43, 0x43, 0x0, 0x0, +}; + +int A_Corona_bmp_Length = sizeof(A_Corona_bmp); diff --git a/G3D/Engine/Logo/A_STREAK.c b/G3D/Engine/Logo/A_STREAK.c new file mode 100644 index 0000000..487690f --- /dev/null +++ b/G3D/Engine/Logo/A_STREAK.c @@ -0,0 +1,899 @@ +/****************************************************************************************/ +/* A_STREAK.C */ +/* */ +/* Author: */ +/* Description: Embedded alpha mask streak bitmap */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +unsigned char A_Streak_bmp[] = { +0x42, 0x4d, 0x38, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x4, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x80, +0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x1, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, +0xb, 0x0, 0x0, 0x12, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0xf7, +0xf7, 0xf7, 0x0, 0xf4, 0xf4, 0xf4, 0x0, 0xf0, 0xf0, 0xf0, 0x0, 0xec, 0xec, 0xec, 0x0, 0xe8, 0xe8, 0xe8, 0x0, 0xe4, +0xe4, 0xe4, 0x0, 0xde, 0xde, 0xde, 0x0, 0xdb, 0xdb, 0xdb, 0x0, 0xd9, 0xd9, 0xd9, 0x0, 0xd2, 0xd2, 0xd2, 0x0, 0xd1, +0xd1, 0xd1, 0x0, 0xcb, 0xcb, 0xcb, 0x0, 0xc8, 0xc8, 0xc8, 0x0, 0xc6, 0xc6, 0xc6, 0x0, 0xc0, 0xc0, 0xc0, 0x0, 0xbf, +0xbf, 0xbf, 0x0, 0xbc, 0xbc, 0xbc, 0x0, 0xbb, 0xbb, 0xbb, 0x0, 0xb9, 0xb9, 0xb9, 0x0, 0xb3, 0xb3, 0xb3, 0x0, 0xb1, +0xb1, 0xb1, 0x0, 0xae, 0xae, 0xae, 0x0, 0xad, 0xad, 0xad, 0x0, 0xaa, 0xaa, 0xaa, 0x0, 0xa8, 0xa8, 0xa8, 0x0, 0xa5, +0xa5, 0xa5, 0x0, 0x9e, 0x9e, 0x9e, 0x0, 0x9a, 0x9a, 0x9a, 0x0, 0x99, 0x99, 0x99, 0x0, 0x97, 0x97, 0x97, 0x0, 0x95, +0x95, 0x95, 0x0, 0x93, 0x93, 0x93, 0x0, 0x8f, 0x8f, 0x8f, 0x0, 0x8c, 0x8c, 0x8c, 0x0, 0x8b, 0x8b, 0x8b, 0x0, 0x88, +0x88, 0x88, 0x0, 0x86, 0x86, 0x86, 0x0, 0x84, 0x84, 0x84, 0x0, 0x81, 0x81, 0x81, 0x0, 0x7f, 0x7f, 0x7f, 0x0, 0x7c, +0x7c, 0x7c, 0x0, 0x7b, 0x7b, 0x7b, 0x0, 0x79, 0x79, 0x79, 0x0, 0x77, 0x77, 0x77, 0x0, 0x75, 0x75, 0x75, 0x0, 0x72, +0x72, 0x72, 0x0, 0x70, 0x70, 0x70, 0x0, 0x6e, 0x6e, 0x6e, 0x0, 0x6d, 0x6d, 0x6d, 0x0, 0x6a, 0x6a, 0x6a, 0x0, 0x69, +0x69, 0x69, 0x0, 0x66, 0x66, 0x66, 0x0, 0x65, 0x65, 0x65, 0x0, 0x63, 0x63, 0x63, 0x0, 0x61, 0x61, 0x61, 0x0, 0x5e, +0x5e, 0x5e, 0x0, 0x5d, 0x5d, 0x5d, 0x0, 0x5a, 0x5a, 0x5a, 0x0, 0x59, 0x59, 0x59, 0x0, 0x57, 0x57, 0x57, 0x0, 0x54, +0x54, 0x54, 0x0, 0x52, 0x52, 0x52, 0x0, 0x50, 0x50, 0x50, 0x0, 0x4f, 0x4f, 0x4f, 0x0, 0x4c, 0x4c, 0x4c, 0x0, 0x4a, +0x4a, 0x4a, 0x0, 0x48, 0x48, 0x48, 0x0, 0x47, 0x47, 0x47, 0x0, 0x45, 0x45, 0x45, 0x0, 0x43, 0x43, 0x43, 0x0, 0x40, +0x40, 0x40, 0x0, 0x3f, 0x3f, 0x3f, 0x0, 0x3d, 0x3d, 0x3d, 0x0, 0x3b, 0x3b, 0x3b, 0x0, 0x39, 0x39, 0x39, 0x0, 0x36, +0x36, 0x36, 0x0, 0x35, 0x35, 0x35, 0x0, 0x32, 0x32, 0x32, 0x0, 0x31, 0x31, 0x31, 0x0, 0x2e, 0x2e, 0x2e, 0x0, 0x2c, +0x2c, 0x2c, 0x0, 0x2a, 0x2a, 0x2a, 0x0, 0x29, 0x29, 0x29, 0x0, 0x26, 0x26, 0x26, 0x0, 0x25, 0x25, 0x25, 0x0, 0x22, +0x22, 0x22, 0x0, 0x21, 0x21, 0x21, 0x0, 0x1e, 0x1e, 0x1e, 0x0, 0x1d, 0x1d, 0x1d, 0x0, 0x1a, 0x1a, 0x1a, 0x0, 0x18, +0x18, 0x18, 0x0, 0x16, 0x16, 0x16, 0x0, 0x14, 0x14, 0x14, 0x0, 0x12, 0x12, 0x12, 0x0, 0x10, 0x10, 0x10, 0x0, 0xf, +0xf, 0xf, 0x0, 0xc, 0xc, 0xc, 0x0, 0xb, 0xb, 0xb, 0x0, 0x8, 0x8, 0x8, 0x0, 0x7, 0x7, 0x7, 0x0, 0x4, +0x4, 0x4, 0x0, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x66, 0x67, 0x67, +0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x66, 0x67, 0x67, 0x66, 0x66, 0x66, +0x66, 0x67, 0x66, 0x66, 0x67, 0x66, 0x67, 0x66, 0x66, 0x66, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, +0x65, 0x65, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x67, 0x66, 0x66, 0x65, 0x65, 0x66, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x64, 0x65, 0x65, 0x66, 0x66, 0x66, 0x65, 0x65, 0x66, 0x66, 0x66, 0x65, +0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, 0x64, 0x63, 0x64, 0x64, 0x65, +0x66, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x65, 0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x67, 0x67, 0x66, 0x66, +0x66, 0x67, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x67, 0x66, +0x65, 0x65, 0x65, 0x64, 0x63, 0x63, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, +0x64, 0x65, 0x65, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x67, 0x66, 0x65, 0x65, 0x65, 0x63, 0x63, 0x63, 0x63, 0x64, 0x65, 0x65, 0x65, 0x65, +0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x64, 0x65, 0x65, 0x66, 0x66, 0x65, 0x66, 0x66, 0x65, 0x65, 0x65, 0x66, +0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x66, 0x66, 0x66, 0x66, 0x65, 0x65, 0x63, +0x63, 0x62, 0x62, 0x63, 0x64, 0x65, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x63, 0x64, 0x64, 0x65, 0x66, +0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x66, +0x66, 0x66, 0x65, 0x66, 0x66, 0x65, 0x64, 0x63, 0x63, 0x61, 0x62, 0x62, 0x64, 0x64, 0x64, 0x63, 0x64, 0x64, 0x64, 0x64, +0x64, 0x64, 0x63, 0x63, 0x63, 0x65, 0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x66, 0x66, 0x65, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, +0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x66, 0x67, 0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x64, 0x63, 0x62, 0x60, 0x60, 0x61, +0x63, 0x63, 0x63, 0x63, 0x64, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x65, +0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x66, 0x66, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, +0x65, 0x65, 0x65, 0x63, 0x62, 0x60, 0x60, 0x60, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x62, 0x62, 0x62, +0x64, 0x64, 0x65, 0x65, 0x64, 0x64, 0x64, 0x64, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x66, +0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, +0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x63, 0x62, 0x60, 0x5f, 0x5f, 0x60, 0x62, 0x62, 0x62, +0x62, 0x63, 0x63, 0x62, 0x62, 0x61, 0x61, 0x62, 0x63, 0x64, 0x65, 0x64, 0x63, 0x63, 0x63, 0x65, 0x65, 0x66, 0x67, 0x67, +0x67, 0x66, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, +0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x64, 0x65, 0x64, 0x63, +0x62, 0x60, 0x5d, 0x5d, 0x5f, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x60, 0x60, 0x60, 0x62, 0x63, 0x63, 0x63, 0x63, +0x63, 0x63, 0x64, 0x65, 0x66, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +0x67, 0x66, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, +0x65, 0x65, 0x65, 0x64, 0x64, 0x64, 0x63, 0x63, 0x61, 0x5f, 0x5d, 0x5d, 0x5d, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x60, 0x60, +0x5f, 0x5f, 0x60, 0x62, 0x63, 0x63, 0x62, 0x62, 0x62, 0x63, 0x64, 0x66, 0x66, 0x67, 0x66, 0x65, 0x65, 0x64, 0x65, 0x65, +0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, +0x65, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x63, 0x64, 0x63, 0x63, 0x61, 0x5f, 0x5c, 0x5b, +0x5c, 0x5d, 0x5e, 0x60, 0x5f, 0x5f, 0x5f, 0x5e, 0x5e, 0x5e, 0x60, 0x61, 0x62, 0x61, 0x61, 0x62, 0x62, 0x64, 0x65, 0x66, +0x66, 0x65, 0x65, 0x64, 0x64, 0x64, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x65, 0x65, 0x65, 0x65, 0x65, +0x65, 0x65, 0x65, 0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x64, 0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x65, 0x64, +0x64, 0x63, 0x63, 0x62, 0x61, 0x5f, 0x5c, 0x5a, 0x5a, 0x5b, 0x5d, 0x5d, 0x5f, 0x5e, 0x5d, 0x5d, 0x5d, 0x5d, 0x60, 0x60, +0x60, 0x60, 0x60, 0x61, 0x63, 0x65, 0x65, 0x65, 0x65, 0x64, 0x64, 0x63, 0x64, 0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, +0x66, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x64, 0x64, +0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x63, 0x64, 0x63, 0x62, 0x62, 0x60, 0x5e, 0x5b, 0x5a, 0x59, 0x5a, 0x5b, 0x5c, +0x5d, 0x5d, 0x5c, 0x5b, 0x5c, 0x5d, 0x5e, 0x60, 0x60, 0x5f, 0x60, 0x62, 0x64, 0x65, 0x65, 0x64, 0x63, 0x63, 0x63, 0x64, +0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x66, 0x66, 0x67, 0x66, 0x67, 0x66, +0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x64, +0x64, 0x64, 0x65, 0x65, 0x64, 0x64, 0x64, 0x63, 0x63, 0x63, 0x63, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x61, 0x61, +0x60, 0x5e, 0x5b, 0x58, 0x57, 0x57, 0x59, 0x5a, 0x5b, 0x5b, 0x5a, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x63, +0x64, 0x64, 0x63, 0x63, 0x63, 0x63, 0x63, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x65, 0x66, 0x65, 0x66, 0x66, 0x66, 0x65, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, 0x65, 0x64, 0x64, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x62, 0x61, +0x61, 0x62, 0x61, 0x62, 0x63, 0x62, 0x62, 0x61, 0x60, 0x5d, 0x5b, 0x58, 0x56, 0x54, 0x56, 0x58, 0x59, 0x58, 0x58, 0x58, +0x5a, 0x5b, 0x5c, 0x5d, 0x5d, 0x5f, 0x61, 0x63, 0x63, 0x63, 0x62, 0x62, 0x63, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, +0x65, 0x65, 0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, 0x65, 0x64, 0x63, +0x63, 0x63, 0x62, 0x63, 0x62, 0x63, 0x62, 0x61, 0x61, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x5e, 0x5d, 0x5b, 0x57, +0x54, 0x52, 0x54, 0x55, 0x56, 0x56, 0x56, 0x56, 0x58, 0x5a, 0x5b, 0x5c, 0x5d, 0x60, 0x61, 0x62, 0x61, 0x61, 0x62, 0x63, +0x63, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, 0x63, 0x63, 0x63, 0x62, 0x62, 0x61, 0x61, 0x61, 0x60, 0x5f, 0x5f, 0x5f, +0x5f, 0x5f, 0x5f, 0x5f, 0x5d, 0x5d, 0x5a, 0x56, 0x52, 0x4f, 0x50, 0x51, 0x53, 0x53, 0x53, 0x54, 0x56, 0x58, 0x5a, 0x5c, +0x5d, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, +0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x65, 0x65, 0x64, 0x63, 0x63, +0x61, 0x61, 0x60, 0x60, 0x60, 0x5f, 0x5e, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5b, 0x5a, 0x56, 0x50, 0x4b, 0x4b, 0x4d, +0x4d, 0x4f, 0x4f, 0x51, 0x54, 0x57, 0x59, 0x5b, 0x5d, 0x5e, 0x5e, 0x60, 0x60, 0x61, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, +0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5d, 0x5b, 0x5b, 0x5b, 0x5a, +0x5a, 0x5a, 0x58, 0x54, 0x4f, 0x49, 0x46, 0x47, 0x48, 0x49, 0x4b, 0x4f, 0x52, 0x56, 0x58, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, +0x60, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x64, 0x65, 0x65, 0x65, 0x66, 0x65, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x65, 0x65, 0x64, 0x63, 0x62, +0x60, 0x60, 0x5d, 0x5d, 0x5b, 0x5a, 0x58, 0x58, 0x57, 0x57, 0x55, 0x51, 0x4c, 0x45, 0x40, 0x3e, 0x40, 0x42, 0x47, 0x4b, +0x50, 0x54, 0x58, 0x5a, 0x5b, 0x5c, 0x5e, 0x5e, 0x60, 0x60, 0x61, 0x61, 0x62, 0x63, 0x63, 0x63, 0x64, 0x65, 0x65, 0x65, +0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, +0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x64, 0x63, 0x62, 0x61, 0x5f, 0x5d, 0x5b, 0x5a, 0x58, 0x57, 0x55, 0x53, 0x51, 0x4e, +0x47, 0x3e, 0x37, 0x33, 0x34, 0x39, 0x40, 0x47, 0x4d, 0x53, 0x56, 0x58, 0x5a, 0x5c, 0x5d, 0x5e, 0x60, 0x60, 0x61, 0x61, +0x62, 0x63, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, +0x65, 0x65, 0x65, 0x65, 0x64, 0x65, 0x64, 0x64, 0x64, 0x64, 0x63, 0x64, 0x63, 0x63, 0x63, 0x63, 0x62, 0x61, 0x60, 0x5f, +0x5d, 0x5b, 0x59, 0x56, 0x53, 0x50, 0x4d, 0x49, 0x40, 0x35, 0x27, 0x1c, 0x1c, 0x24, 0x2f, 0x3a, 0x44, 0x49, 0x4d, 0x50, +0x53, 0x55, 0x56, 0x58, 0x5a, 0x5a, 0x5b, 0x5d, 0x5e, 0x5e, 0x60, 0x60, 0x61, 0x62, 0x62, 0x63, 0x63, 0x63, 0x64, 0x65, +0x65, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, +0x66, 0x65, 0x65, 0x65, 0x65, 0x64, 0x64, 0x63, 0x63, 0x63, 0x63, 0x63, 0x61, 0x61, 0x60, 0x60, 0x60, 0x5f, 0x5f, 0x5e, +0x5e, 0x5d, 0x5d, 0x5c, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 0x56, 0x53, 0x50, 0x4d, 0x49, 0x44, 0x3c, 0x31, 0x23, 0x13, 0x5, +0x5, 0xd, 0x1a, 0x26, 0x30, 0x37, 0x3c, 0x3f, 0x41, 0x45, 0x46, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x51, 0x52, 0x53, +0x54, 0x56, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x60, 0x62, 0x62, 0x63, +0x63, 0x63, 0x64, 0x65, 0x64, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, 0x64, +0x64, 0x63, 0x63, 0x62, 0x61, 0x60, 0x60, 0x60, 0x5e, 0x5d, 0x5d, 0x5c, 0x5b, 0x5b, 0x5a, 0x59, 0x59, 0x58, 0x57, 0x56, +0x55, 0x54, 0x52, 0x51, 0x4f, 0x4e, 0x4d, 0x4b, 0x4b, 0x49, 0x47, 0x47, 0x44, 0x42, 0x40, 0x3d, 0x3b, 0x38, 0x34, 0x30, +0x2b, 0x25, 0x1e, 0x18, 0xc, 0x1, 0x0, 0x0, 0x0, 0x0, 0x5, 0xf, 0x1a, 0x1e, 0x24, 0x28, 0x2b, 0x2e, 0x31, 0x33, +0x36, 0x37, 0x3a, 0x3a, 0x3c, 0x3c, 0x3f, 0x3f, 0x40, 0x41, 0x43, 0x45, 0x46, 0x47, 0x49, 0x49, 0x4b, 0x4d, 0x4d, 0x4e, +0x4f, 0x4f, 0x50, 0x51, 0x53, 0x54, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x60, 0x62, 0x62, 0x63, +0x64, 0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x60, 0x60, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 0x56, 0x56, 0x54, 0x53, 0x51, +0x50, 0x4f, 0x4f, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x47, 0x45, 0x42, 0x40, 0x3d, 0x3b, 0x38, 0x36, 0x33, 0x30, 0x2d, 0x2a, +0x27, 0x25, 0x22, 0x1f, 0x1b, 0x19, 0x15, 0x11, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x4, 0x7, 0xa, 0xe, 0x12, 0x15, 0x19, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, 0x2f, 0x32, 0x36, 0x38, +0x3b, 0x3d, 0x40, 0x41, 0x45, 0x46, 0x48, 0x49, 0x4a, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x54, 0x54, 0x56, 0x57, 0x58, +0x59, 0x5b, 0x5b, 0x5d, 0x5e, 0x5f, 0x60, 0x62, 0x63, 0x64, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x64, 0x63, 0x63, 0x62, 0x60, 0x60, 0x5e, 0x5d, 0x5c, +0x5b, 0x5a, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x50, 0x50, 0x4f, 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x47, +0x46, 0x45, 0x43, 0x42, 0x41, 0x40, 0x40, 0x3e, 0x3d, 0x3c, 0x3a, 0x38, 0x36, 0x33, 0x2f, 0x2c, 0x27, 0x23, 0x1d, 0x14, +0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x10, 0x17, 0x1b, 0x20, 0x23, 0x27, 0x2a, 0x2e, 0x31, 0x34, 0x37, 0x3a, +0x3c, 0x3f, 0x41, 0x44, 0x45, 0x47, 0x49, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x51, 0x53, 0x54, 0x54, 0x56, 0x57, 0x57, 0x58, +0x59, 0x5a, 0x5b, 0x5b, 0x5b, 0x5d, 0x5d, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, +0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x64, 0x63, 0x63, 0x62, 0x62, 0x60, 0x60, 0x5f, 0x5e, 0x5d, 0x5d, 0x5c, 0x5b, +0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x57, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x50, 0x50, 0x4f, 0x4d, 0x4c, 0x4a, 0x48, 0x47, +0x44, 0x41, 0x3e, 0x3a, 0x36, 0x32, 0x2b, 0x23, 0x18, 0xb, 0x2, 0x0, 0x6, 0x11, 0x1f, 0x2c, 0x36, 0x3c, 0x41, 0x45, +0x47, 0x49, 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, +0x5c, 0x5d, 0x5e, 0x5f, 0x5e, 0x5f, 0x60, 0x60, 0x60, 0x60, 0x61, 0x62, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, +0x65, 0x65, 0x65, 0x66, 0x65, 0x66, 0x66, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x66, 0x66, 0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x63, 0x63, 0x63, 0x63, 0x62, 0x60, 0x60, 0x60, 0x5e, +0x5d, 0x5c, 0x5b, 0x5a, 0x58, 0x56, 0x54, 0x52, 0x50, 0x4d, 0x4b, 0x48, 0x45, 0x40, 0x3c, 0x35, 0x29, 0x1e, 0x17, 0x16, +0x1c, 0x28, 0x34, 0x3d, 0x45, 0x4b, 0x4e, 0x51, 0x54, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, +0x5d, 0x5d, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, +0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x65, 0x65, 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, +0x66, 0x65, 0x65, 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x58, 0x58, 0x56, 0x54, 0x54, 0x50, +0x4f, 0x4c, 0x48, 0x44, 0x3c, 0x33, 0x2d, 0x2d, 0x33, 0x3c, 0x43, 0x49, 0x4d, 0x50, 0x54, 0x57, 0x59, 0x5a, 0x5b, 0x5c, +0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, +0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, 0x64, 0x64, 0x63, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5d, 0x5d, 0x5c, 0x5b, +0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x54, 0x53, 0x50, 0x4e, 0x4b, 0x45, 0x3e, 0x3b, 0x3d, 0x43, 0x48, 0x4c, 0x4f, +0x51, 0x54, 0x56, 0x59, 0x5b, 0x5d, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, +0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x65, +0x66, 0x66, 0x66, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x64, 0x63, 0x63, 0x62, 0x62, 0x60, +0x60, 0x5f, 0x5e, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5c, 0x5b, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x52, 0x4f, +0x49, 0x45, 0x44, 0x47, 0x4d, 0x4f, 0x52, 0x54, 0x55, 0x57, 0x58, 0x5a, 0x5b, 0x5d, 0x5f, 0x60, 0x61, 0x61, 0x62, 0x62, +0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x65, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, +0x65, 0x65, 0x65, 0x65, 0x66, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x66, 0x65, 0x65, 0x64, +0x64, 0x63, 0x63, 0x62, 0x62, 0x61, 0x61, 0x60, 0x60, 0x60, 0x60, 0x60, 0x5f, 0x60, 0x60, 0x5f, 0x5f, 0x5e, 0x5d, 0x5d, +0x5b, 0x5a, 0x5a, 0x5a, 0x58, 0x57, 0x55, 0x51, 0x4d, 0x4a, 0x4a, 0x4e, 0x53, 0x56, 0x56, 0x57, 0x58, 0x5a, 0x5a, 0x5a, +0x5b, 0x5c, 0x5e, 0x60, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x65, 0x64, 0x65, 0x65, +0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x66, 0x66, 0x65, 0x65, 0x65, 0x64, 0x64, 0x63, 0x63, 0x63, 0x62, 0x62, 0x62, 0x61, 0x62, 0x61, 0x61, 0x61, 0x61, 0x61, +0x62, 0x61, 0x61, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5c, 0x5c, 0x5b, 0x5b, 0x5b, 0x5a, 0x58, 0x54, 0x4f, 0x4e, 0x4f, 0x53, +0x58, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x60, 0x61, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x64, +0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, +0x67, 0x66, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, 0x65, 0x65, 0x64, 0x64, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, +0x63, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x62, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5e, 0x5d, 0x5d, 0x5d, 0x5d, +0x5c, 0x5b, 0x58, 0x55, 0x52, 0x51, 0x54, 0x57, 0x5a, 0x5c, 0x5c, 0x5b, 0x5b, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5f, +0x60, 0x61, 0x63, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, +0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, +0x65, 0x64, 0x63, 0x64, 0x64, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x63, 0x63, 0x62, 0x61, +0x60, 0x60, 0x60, 0x60, 0x5f, 0x5f, 0x5f, 0x5f, 0x5d, 0x5b, 0x59, 0x56, 0x55, 0x54, 0x56, 0x5a, 0x5c, 0x5e, 0x5e, 0x5d, +0x5d, 0x5d, 0x5e, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x63, 0x64, 0x65, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, +0x66, 0x66, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, +0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, +0x65, 0x65, 0x64, 0x63, 0x63, 0x62, 0x62, 0x61, 0x61, 0x62, 0x61, 0x60, 0x60, 0x60, 0x60, 0x60, 0x5e, 0x5c, 0x5a, 0x58, +0x57, 0x58, 0x59, 0x5b, 0x5e, 0x60, 0x60, 0x5f, 0x5e, 0x5f, 0x5f, 0x60, 0x61, 0x61, 0x62, 0x61, 0x61, 0x61, 0x61, 0x62, +0x63, 0x64, 0x65, 0x66, 0x66, 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x66, 0x66, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x66, 0x66, 0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, +0x65, 0x65, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x63, 0x63, 0x62, 0x62, 0x63, 0x63, 0x62, 0x62, 0x62, +0x61, 0x61, 0x62, 0x60, 0x5e, 0x5c, 0x5a, 0x5a, 0x59, 0x5a, 0x5b, 0x5d, 0x60, 0x62, 0x61, 0x60, 0x60, 0x60, 0x60, 0x60, +0x62, 0x63, 0x63, 0x63, 0x63, 0x62, 0x62, 0x62, 0x62, 0x63, 0x64, 0x65, 0x65, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, +0x67, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, 0x64, 0x64, 0x63, 0x63, +0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x62, 0x62, 0x62, 0x63, 0x62, 0x60, 0x5f, 0x5c, 0x5b, 0x5b, 0x5b, 0x5b, 0x5d, 0x5f, +0x61, 0x63, 0x62, 0x62, 0x61, 0x61, 0x62, 0x61, 0x62, 0x63, 0x63, 0x63, 0x64, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, +0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, +0x66, 0x66, 0x65, 0x64, 0x64, 0x63, 0x64, 0x63, 0x64, 0x64, 0x65, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x62, 0x60, +0x5f, 0x5d, 0x5d, 0x5d, 0x5c, 0x5d, 0x5e, 0x60, 0x63, 0x63, 0x63, 0x63, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x64, 0x64, +0x65, 0x64, 0x64, 0x63, 0x64, 0x64, 0x63, 0x63, 0x64, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, 0x65, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x64, +0x64, 0x63, 0x63, 0x64, 0x64, 0x63, 0x63, 0x60, 0x5f, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x60, 0x61, 0x63, 0x65, 0x64, 0x63, +0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x64, 0x64, 0x65, 0x65, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x64, +0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x65, 0x64, 0x65, 0x64, 0x63, 0x62, 0x60, 0x60, 0x60, 0x60, 0x5f, +0x5f, 0x60, 0x60, 0x62, 0x63, 0x65, 0x65, 0x64, 0x63, 0x63, 0x63, 0x63, 0x64, 0x63, 0x63, 0x65, 0x65, 0x65, 0x65, 0x65, +0x65, 0x65, 0x65, 0x65, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, +0x64, 0x63, 0x62, 0x61, 0x61, 0x60, 0x60, 0x60, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x65, 0x65, 0x64, 0x64, 0x63, 0x65, +0x64, 0x65, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, 0x66, 0x65, 0x66, 0x66, 0x67, 0x66, 0x65, +0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x65, 0x65, 0x64, 0x63, 0x62, 0x62, 0x61, 0x61, 0x60, 0x61, 0x62, 0x62, 0x62, 0x63, +0x65, 0x66, 0x66, 0x65, 0x65, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x67, 0x66, 0x66, 0x66, 0x65, +0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x66, 0x65, +0x66, 0x67, 0x66, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x66, 0x65, 0x65, 0x66, 0x65, 0x65, 0x64, 0x63, 0x63, 0x63, +0x63, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x64, 0x65, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, +0x65, 0x66, 0x66, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x66, 0x65, 0x66, 0x66, 0x66, +0x66, 0x66, 0x66, 0x65, 0x64, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x65, 0x67, 0x67, 0x66, +0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x65, 0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x67, 0x67, 0x66, +0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, +0x66, 0x66, 0x66, 0x66, 0x67, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x65, 0x64, 0x63, 0x63, 0x63, 0x64, 0x63, 0x63, 0x63, +0x64, 0x64, 0x64, 0x65, 0x65, 0x67, 0x67, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x66, +0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x67, 0x67, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, +0x64, 0x64, 0x64, 0x65, 0x64, 0x64, 0x64, 0x64, 0x65, 0x64, 0x64, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x66, +0x65, 0x66, 0x66, 0x67, 0x66, 0x66, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, +0x66, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, +0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, +0x67, 0x67, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x66, 0x65, 0x65, 0x65, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, +0x67, 0x67, 0x66, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x65, 0x65, 0x66, 0x66, 0x66, 0x65, 0x65, 0x65, 0x65, 0x66, +0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, +0x66, 0x66, 0x66, 0x65, 0x66, 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x66, 0x67, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x66, 0x66, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, 0x67, 0x67, 0x67, 0x66, 0x67, +0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, +0x67, 0x67, 0x67, 0x0, 0x0, +}; + +int A_Streak_bmp_Length = sizeof(A_Streak_bmp); diff --git a/G3D/Engine/Logo/CORONA.c b/G3D/Engine/Logo/CORONA.c new file mode 100644 index 0000000..e5aa374 --- /dev/null +++ b/G3D/Engine/Logo/CORONA.c @@ -0,0 +1,899 @@ +/****************************************************************************************/ +/* CORONA.C */ +/* */ +/* Author: */ +/* Description: Embedded Corona bitmap */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +unsigned char Corona_bmp[] = { +0x42, 0x4d, 0x38, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x4, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x80, +0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x1, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, +0xb, 0x0, 0x0, 0x12, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1e, 0x4f, 0x0, 0x14, +0x10, 0x3b, 0x0, 0x14, 0x10, 0x38, 0x0, 0x10, 0xd, 0x31, 0x0, 0x24, 0x21, 0x4c, 0x0, 0x1e, 0x1a, 0x42, 0x0, 0x2b, +0x28, 0x53, 0x0, 0x28, 0x24, 0x4c, 0x0, 0x24, 0x21, 0x45, 0x0, 0x35, 0x31, 0x56, 0x0, 0x14, 0x10, 0x31, 0x0, 0xd, +0xa, 0x28, 0x0, 0x10, 0xd, 0x2b, 0x0, 0x1a, 0x17, 0x38, 0x0, 0x17, 0x14, 0x31, 0x0, 0x2b, 0x28, 0x49, 0x0, 0x21, +0x1e, 0x3b, 0x0, 0x14, 0x10, 0x2b, 0x0, 0xa, 0x6, 0x1e, 0x0, 0x17, 0x14, 0x2b, 0x0, 0x1a, 0x17, 0x2e, 0x0, 0x1e, +0x1a, 0x31, 0x0, 0xd, 0xa, 0x1e, 0x0, 0x10, 0xd, 0x21, 0x0, 0x14, 0x10, 0x24, 0x0, 0x21, 0x1e, 0x31, 0x0, 0x10, +0xd, 0x1e, 0x0, 0x17, 0x14, 0x24, 0x0, 0x28, 0x21, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x3, 0x0, 0xd, 0x0, 0xa, +0x6, 0x14, 0x0, 0x1e, 0x1a, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x6, 0x0, 0x3, +0x0, 0xa, 0x0, 0x10, 0xd, 0x17, 0x0, 0x17, 0x14, 0x1e, 0x0, 0x1e, 0x1a, 0x24, 0x0, 0x38, 0x35, 0x3f, 0x0, 0xa, +0x3, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0xd, 0x0, 0xa, 0x3, 0x10, 0x0, 0xd, 0x6, 0x14, 0x0, 0x24, +0x21, 0x28, 0x0, 0x2b, 0x28, 0x2e, 0x0, 0x3f, 0x3b, 0x42, 0x0, 0x45, 0x42, 0x49, 0x0, 0x4f, 0x4c, 0x53, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x6, 0x0, 0xa, 0x0, 0xd, 0x6, 0x10, 0x0, 0x14, 0xd, 0x17, 0x0, 0x17, +0x10, 0x1a, 0x0, 0x1a, 0x14, 0x1e, 0x0, 0x1e, 0x17, 0x21, 0x0, 0x21, 0x1a, 0x24, 0x0, 0x24, 0x1e, 0x28, 0x0, 0x28, +0x21, 0x2b, 0x0, 0x2b, 0x24, 0x2e, 0x0, 0x2e, 0x28, 0x31, 0x0, 0x35, 0x2e, 0x38, 0x0, 0x31, 0x2b, 0x35, 0x0, 0x38, +0x31, 0x3b, 0x0, 0x3f, 0x38, 0x42, 0x0, 0x3b, 0x35, 0x3f, 0x0, 0xd, 0x3, 0x10, 0x0, 0x14, 0xa, 0x17, 0x0, 0x21, +0x17, 0x21, 0x0, 0x28, 0x1e, 0x28, 0x0, 0x2e, 0x24, 0x2e, 0x0, 0x35, 0x2b, 0x35, 0x0, 0x3b, 0x31, 0x3b, 0x0, 0x42, +0x3f, 0x42, 0x0, 0x3f, 0x3b, 0x3f, 0x0, 0xa5, 0x81, 0x9f, 0x0, 0xc0, 0x9b, 0xb9, 0x0, 0xaf, 0x8e, 0xa5, 0x0, 0xff, +0xd4, 0xf2, 0x0, 0x9b, 0x7e, 0x92, 0x0, 0x81, 0x66, 0x77, 0x0, 0xee, 0xc3, 0xde, 0x0, 0xda, 0xaf, 0xc7, 0x0, 0xa9, +0x88, 0x98, 0x0, 0xb9, 0x98, 0xa9, 0x0, 0x4c, 0x45, 0x49, 0x0, 0x5d, 0x56, 0x59, 0x0, 0xff, 0xfc, 0xff, 0x0, 0xcd, +0xa5, 0xb3, 0x0, 0x92, 0x74, 0x7e, 0x0, 0xac, 0x8e, 0x98, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xe1, 0xee, 0x0, 0xe8, +0xb9, 0xc3, 0x0, 0xff, 0xff, 0xff, 0x0, 0xa5, 0x88, 0x8b, 0x0, 0xb6, 0x95, 0x98, 0x0, 0xfc, 0xc7, 0xca, 0x0, 0xff, +0xd0, 0xd4, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0x3b, 0x38, 0x38, 0x0, 0xf5, +0xbd, 0xb9, 0x0, 0xff, 0xcd, 0xc7, 0x0, 0xff, 0xf2, 0xeb, 0x0, 0xaf, 0x8e, 0x8b, 0x0, 0xff, 0xff, 0xf5, 0x0, 0xff, +0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xde, 0xd4, 0x0, 0xa9, 0x84, 0x7e, 0x0, 0xc0, 0x98, 0x92, 0x0, 0xd7, +0xac, 0xa5, 0x0, 0xb6, 0x92, 0x8b, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xe4, 0xb9, 0xaf, 0x0, 0xff, +0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0x95, +0x70, 0x63, 0x0, 0xff, 0xff, 0xff, 0x0, 0xa2, 0x7e, 0x70, 0x0, 0x8b, 0x70, 0x66, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, +0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xaf, 0x8b, 0x7a, 0x0, 0xcd, 0xa5, 0x92, 0x0, 0xb3, +0x92, 0x81, 0x0, 0xa9, 0x84, 0x70, 0x0, 0xff, 0xff, 0xff, 0x0, 0x81, 0x66, 0x56, 0x0, 0xb6, 0x8e, 0x74, 0x0, 0xc0, +0x98, 0x7e, 0x0, 0x98, 0x7a, 0x66, 0x0, 0x7e, 0x6a, 0x5d, 0x0, 0x4c, 0x42, 0x3b, 0x0, 0xa2, 0x7e, 0x63, 0x0, 0x60, +0x53, 0x49, 0x0, 0x95, 0x70, 0x53, 0x0, 0x84, 0x63, 0x49, 0x0, 0x9b, 0x77, 0x59, 0x0, 0xa9, 0x84, 0x66, 0x0, 0xaf, +0x8b, 0x6d, 0x0, 0x74, 0x63, 0x56, 0x0, 0x8b, 0x6a, 0x4c, 0x0, 0x77, 0x5d, 0x45, 0x0, 0x88, 0x6d, 0x56, 0x0, 0x59, +0x4c, 0x3f, 0x0, 0x8b, 0x7a, 0x6a, 0x0, 0x42, 0x3f, 0x3b, 0x0, 0x3f, 0x3b, 0x38, 0x0, 0xff, 0xff, 0xff, 0x0, 0x8e, +0x77, 0x59, 0x0, 0x3f, 0x3b, 0x31, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, +0xff, 0xff, 0x0, 0x2b, 0x6a, 0x6d, 0x0, 0x2b, 0x66, 0x6a, 0x0, 0x31, 0x70, 0x74, 0x0, 0x31, 0x6d, 0x70, 0x0, 0x38, +0x74, 0x77, 0x0, 0x38, 0x6d, 0x70, 0x0, 0x45, 0x7a, 0x7e, 0x0, 0x60, 0x98, 0x9b, 0x0, 0x2e, 0x53, 0x56, 0x0, 0x49, +0x74, 0x77, 0x0, 0x24, 0x60, 0x66, 0x0, 0x21, 0x59, 0x60, 0x0, 0x2b, 0x6a, 0x70, 0x0, 0x3f, 0x77, 0x7e, 0x0, 0x45, +0x7e, 0x84, 0x0, 0x4c, 0x84, 0x8b, 0x0, 0x2b, 0x60, 0x66, 0x0, 0x31, 0x66, 0x6d, 0x0, 0x59, 0x8e, 0x95, 0x0, 0x24, +0x4f, 0x56, 0x0, 0x2e, 0x59, 0x60, 0x0, 0x38, 0x60, 0x66, 0x0, 0x3f, 0x66, 0x6d, 0x0, 0x45, 0x6a, 0x70, 0x0, 0x24, +0x45, 0x4c, 0x0, 0x2e, 0x4c, 0x53, 0x0, 0x3b, 0x56, 0x5d, 0x0, 0x56, 0x70, 0x77, 0x0, 0x28, 0x3f, 0x45, 0x0, 0x2e, +0x45, 0x4c, 0x0, 0x38, 0x4f, 0x56, 0x0, 0x49, 0x60, 0x66, 0x0, 0x24, 0x35, 0x3b, 0x0, 0x45, 0x56, 0x5d, 0x0, 0x2b, +0x38, 0x3f, 0x0, 0x35, 0x42, 0x49, 0x0, 0x38, 0x45, 0x4c, 0x0, 0x2b, 0x3b, 0x45, 0x0, 0x1a, 0x24, 0x2b, 0x0, 0x24, +0x2e, 0x35, 0x0, 0x45, 0x4f, 0x59, 0x0, 0x35, 0x3b, 0x45, 0x0, 0x24, 0x28, 0x2e, 0x0, 0x2b, 0x2e, 0x35, 0x0, 0x31, +0x35, 0x3b, 0x0, 0x45, 0x49, 0x4f, 0x0, 0x28, 0x2b, 0x35, 0x0, 0x10, 0x14, 0x3f, 0x0, 0x1e, 0x21, 0x4c, 0x0, 0x10, +0x14, 0x35, 0x0, 0x10, 0x14, 0x42, 0x0, 0x14, 0x17, 0x45, 0x0, 0x17, 0x1a, 0x49, 0x0, 0x1e, 0x21, 0x4f, 0x0, 0x10, +0x10, 0x42, 0x0, 0xd, 0xd, 0x3b, 0x0, 0x10, 0x10, 0x3f, 0x0, 0x17, 0x17, 0x49, 0x0, 0xd, 0xd, 0x38, 0x0, 0x14, +0x14, 0x3f, 0x0, 0x1a, 0x1a, 0x49, 0x0, 0x1e, 0x1e, 0x4c, 0x0, 0x21, 0x21, 0x4f, 0x0, 0x24, 0x24, 0x53, 0x0, 0x28, +0x28, 0x56, 0x0, 0xa, 0xa, 0x28, 0x0, 0x2e, 0x2e, 0x5d, 0x0, 0x14, 0x14, 0x35, 0x0, 0x3f, 0x3f, 0x49, 0x0, 0x31, +0x31, 0x38, 0x0, 0x35, 0x35, 0x38, 0x0, 0x6a, 0x6a, 0x6d, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x26, +0x39, 0x27, 0x27, 0x26, 0x27, 0x39, 0x27, 0x27, 0x27, 0x28, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, +0x27, 0x28, 0x28, 0x28, 0x28, 0x27, 0x28, 0x28, 0x42, 0x28, 0x42, 0x28, 0x28, 0x29, 0x29, 0x28, 0x28, 0x28, 0x29, 0x28, +0x28, 0x29, 0x28, 0x29, 0x29, 0x28, 0x29, 0x29, 0x28, 0x28, 0x29, 0x42, 0x29, 0x29, 0x42, 0x29, 0x42, 0x29, 0x29, 0x29, +0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x42, 0x42, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x28, 0x29, +0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x28, 0x28, 0x29, 0x28, 0x42, 0x28, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, +0x42, 0x28, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x27, 0x28, 0x27, 0x27, 0x39, 0x28, 0x27, +0x27, 0x39, 0x27, 0x39, 0x39, 0x39, 0x27, 0x26, 0x27, 0x39, 0x39, 0x27, 0x27, 0x27, 0x39, 0x27, 0x27, 0x28, 0x28, 0x28, +0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x29, 0x29, +0x29, 0x28, 0x29, 0x28, 0x29, 0x29, 0x28, 0x29, 0x42, 0x29, 0x42, 0x29, 0x42, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x28, 0x28, 0x42, +0x28, 0x28, 0x29, 0x42, 0x28, 0x29, 0x29, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x27, 0x28, 0x27, 0x27, +0x28, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x27, 0x39, 0x27, 0x27, 0x27, 0x27, 0x39, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, +0x28, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x42, 0x42, 0x28, 0x28, 0x28, 0x42, +0x29, 0x29, 0x28, 0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x42, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, +0x2a, 0x29, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, +0x29, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, +0x29, 0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x42, 0x28, 0x42, 0x28, 0x29, 0x29, 0x28, 0x28, +0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x27, 0x28, 0x27, 0x28, 0x27, +0x27, 0x39, 0x27, 0x27, 0x28, 0x27, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x42, +0x42, 0x28, 0x29, 0x29, 0x28, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x2a, 0x29, +0x29, 0x29, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, +0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x42, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, +0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x27, 0x28, 0x28, 0x28, 0x27, 0x27, 0x28, 0x28, +0x28, 0x28, 0x28, 0x28, 0x42, 0x29, 0x42, 0x42, 0x42, 0x29, 0x42, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, +0x29, 0x2a, 0x2a, 0x1d, 0x2a, 0x1d, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x2a, 0x2a, 0x1d, 0x2a, 0x1d, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x29, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, +0x2a, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, +0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x42, 0x28, 0x42, 0x28, 0x29, 0x28, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, +0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x1d, 0x2b, +0x2b, 0x1d, 0x1d, 0x2a, 0x2b, 0x1d, 0x2b, 0x2b, 0x1d, 0x2b, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, +0x2a, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, +0x29, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x28, 0x29, 0x29, 0x29, 0x29, 0x28, +0x28, 0x42, 0x28, 0x28, 0x28, 0x27, 0x28, 0x28, 0x42, 0x42, 0x28, 0x29, 0x28, 0x42, 0x28, 0x29, 0x29, 0x29, 0x28, 0x29, +0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2a, 0x2b, 0x1d, 0x2b, 0x2b, 0x2a, 0x1d, 0x2b, +0x1d, 0x1d, 0x2b, 0x1d, 0x1d, 0x1d, 0x2a, 0x2b, 0x2a, 0x1d, 0x1d, 0x1d, 0x2b, 0x2b, 0x1d, 0x2b, 0x2a, 0x2b, 0x2b, 0x1d, +0x2a, 0x2b, 0x1d, 0x1d, 0x1d, 0x2a, 0x2b, 0x2a, 0x1d, 0x1d, 0x1d, 0x2b, 0x2a, 0x1d, 0x1d, 0x1d, 0x2a, 0x1d, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, +0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x28, 0x29, 0x28, 0x42, 0x28, 0x28, 0x28, 0x42, 0x29, 0x29, +0x29, 0x29, 0x28, 0x29, 0x42, 0x29, 0x42, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x1d, 0x1d, 0x2a, 0x1d, 0x2a, 0x2b, 0x2a, 0x2b, +0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2b, 0x1d, 0x2b, 0x1d, 0x2b, +0x2b, 0x1d, 0x2b, 0x1d, 0x1d, 0x1d, 0x2b, 0x2b, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x1d, 0x1d, 0x2b, 0x2a, +0x1d, 0x1d, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x1d, 0x1d, 0x1d, 0x2a, 0x1d, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x42, 0x28, 0x29, +0x29, 0x29, 0x28, 0x29, 0x42, 0x28, 0x28, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x2a, +0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x1d, 0x1d, 0x1d, 0x1d, 0x2a, 0x1d, 0x1d, 0x1d, 0x1d, 0x2b, 0x1d, +0x1d, 0x1d, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x1d, 0x2b, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, +0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2b, +0x2b, 0x2b, 0x2b, 0x1d, 0x1d, 0x2c, 0x1d, 0x2c, 0x1d, 0x2b, 0x2b, 0x2b, 0x1d, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2b, 0x1d, +0x1d, 0x1d, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x1d, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, +0x2a, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, +0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x1d, 0x2a, 0x1d, 0x2b, 0x2a, 0x1d, +0x2b, 0x1d, 0x1d, 0x2b, 0x2b, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, +0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x1e, 0x2b, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2b, +0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, +0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x2b, 0x1d, 0x1d, 0x1d, 0x2b, 0x1d, 0x1d, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, +0x1d, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, +0x2a, 0x1d, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x1d, 0x2b, 0x1d, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2c, +0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, +0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2c, +0x2b, 0x1e, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x1d, 0x2b, 0x2b, 0x2b, +0x2b, 0x1d, 0x1d, 0x2b, 0x2a, 0x2b, 0x1d, 0x1d, 0x2a, 0x1d, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, +0x29, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x1d, 0x2b, 0x2b, 0x1d, 0x1d, 0x1d, 0x2b, 0x2b, 0x1d, 0x1d, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, +0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x1e, 0x2c, +0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x1e, 0x2c, 0x2c, 0x1e, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, +0x2c, 0x1e, 0x1e, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, +0x2c, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2b, 0x2b, 0x1d, 0x2a, 0x1d, +0x2b, 0x1d, 0x1d, 0x1d, 0x1d, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, +0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x1d, 0x1d, 0x2b, 0x1d, 0x1d, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, +0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, +0x1e, 0x1e, 0x2c, 0x2c, 0x2d, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, +0x2d, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, +0x2c, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, +0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x1d, 0x2b, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x1d, 0x2a, 0x2a, 0x1d, 0x2a, 0x1d, 0x1d, 0x2a, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2c, +0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x1e, 0x2c, 0x1e, 0x2c, +0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2e, +0x2d, 0x2d, 0x1e, 0x2d, 0x1e, 0x2d, 0x1e, 0x2e, 0x1e, 0x1e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, +0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x2c, +0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, +0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x2b, +0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, +0x1e, 0x2c, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x2d, 0x1e, 0x2d, 0x1e, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, +0x2d, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x1e, 0x2d, 0x2e, 0x1e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, +0x2d, 0x1e, 0x2e, 0x2d, 0x2e, 0x1e, 0x1e, 0x2e, 0x2e, 0x1e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2d, 0x1e, 0x2d, 0x1e, 0x1e, +0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, +0x2c, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x1d, 0x1d, 0x2a, 0x1d, 0x1d, 0x2a, 0x1d, 0x2a, 0x1d, 0x2a, 0x1d, +0x2a, 0x2b, 0x1d, 0x2a, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x1e, 0x2b, 0x2c, 0x2c, +0x2c, 0x1e, 0x2c, 0x1e, 0x2c, 0x1e, 0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, 0x2d, 0x1e, 0x1e, +0x2e, 0x2e, 0x2d, 0x2d, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, +0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2e, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2e, 0x2e, +0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x1e, 0x2e, 0x2d, 0x2e, 0x2d, 0x2d, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x2d, 0x1e, +0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x1e, 0x2b, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2c, 0x1d, +0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x2a, 0x1d, 0x1d, 0x2b, 0x1d, 0x1d, 0x1d, 0x2b, 0x2b, 0x2c, 0x2b, 0x2c, +0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, +0x2e, 0x1e, 0x2e, 0x1e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, +0x2e, 0x2e, 0x1f, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, +0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x2e, 0x1f, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2d, +0x2e, 0x1e, 0x2d, 0x2d, 0x2e, 0x2d, 0x2d, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x2c, 0x2c, 0x1e, 0x1e, 0x1e, 0x2c, 0x2c, +0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2c, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x1d, 0x2a, 0x2a, 0x1d, 0x1d, 0x2b, 0x2b, +0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, 0x2c, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2d, +0x2d, 0x2d, 0x1e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, +0x2e, 0x2e, 0x1f, 0x2e, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, +0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, +0x1f, 0x2e, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2d, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x2d, +0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, +0x1d, 0x1d, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, +0x2d, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x2e, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, +0x1f, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, +0x1f, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x20, 0x2e, 0x20, 0x1f, 0x1f, 0x2e, +0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, +0x2e, 0x2e, 0x2d, 0x2e, 0x2d, 0x2e, 0x2e, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2c, 0x1e, +0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, +0x1e, 0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, 0x2d, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, +0x2e, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x1f, +0x20, 0x1f, 0x20, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x1f, +0x1f, 0x20, 0x1f, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x1f, 0x20, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, +0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2d, 0x2d, 0x2e, 0x1e, 0x2e, +0x1e, 0x2e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x1e, 0x2c, 0x2b, 0x2b, +0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x2e, 0x2e, 0x2e, +0x2e, 0x2d, 0x2e, 0x2d, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x20, 0x20, 0x20, +0x20, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, +0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x1e, 0x2e, 0x2d, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, +0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x2d, 0x1e, 0x2d, 0x2d, 0x2d, +0x1e, 0x2d, 0x2d, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, +0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, +0x21, 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x21, 0x20, 0x2f, 0x2f, 0x2f, 0x21, 0x21, 0x21, 0x21, 0x21, +0x21, 0x21, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x1f, 0x20, 0x1f, +0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x2e, 0x2e, 0x2d, 0x2e, 0x2d, +0x2d, 0x2d, 0x2d, 0x2e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, +0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x2e, +0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x20, 0x20, 0x1f, 0x20, 0x1f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x21, 0x20, +0x20, 0x21, 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x2f, 0x2f, 0x20, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x21, 0x30, 0x30, 0x21, +0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x2f, 0x20, 0x21, 0x21, 0x20, +0x20, 0x21, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, +0x20, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, 0x2d, +0x1e, 0x1e, 0x2c, 0x2c, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, +0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x21, 0x20, 0x20, 0x2f, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x30, 0x21, 0x21, 0x30, 0x30, 0x21, +0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x31, 0x30, 0x21, 0x21, 0x21, 0x21, 0x30, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, +0x21, 0x21, 0x21, 0x30, 0x21, 0x21, 0x2f, 0x2f, 0x20, 0x21, 0x21, 0x20, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, +0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2d, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x2e, 0x2e, +0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x21, 0x20, 0x21, 0x20, 0x20, 0x21, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x30, 0x21, 0x21, 0x21, 0x21, +0x21, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x21, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, +0x31, 0x21, 0x31, 0x21, 0x31, 0x30, 0x31, 0x21, 0x30, 0x21, 0x31, 0x31, 0x31, 0x30, 0x21, 0x21, 0x30, 0x21, 0x21, 0x21, +0x21, 0x2f, 0x20, 0x20, 0x21, 0x2f, 0x21, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x20, 0x20, 0x20, +0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, +0x1e, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x2f, 0x21, 0x20, 0x21, 0x21, 0x21, 0x30, 0x21, 0x21, 0x30, 0x21, 0x21, +0x21, 0x30, 0x30, 0x30, 0x21, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x43, 0x31, 0x31, 0x43, 0x31, 0x31, +0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, +0x31, 0x31, 0x21, 0x30, 0x30, 0x31, 0x31, 0x31, 0x21, 0x30, 0x30, 0x30, 0x21, 0x21, 0x21, 0x2f, 0x20, 0x20, 0x2f, 0x20, +0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x2e, 0x2e, 0x2e, +0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2e, 0x1e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, +0x1f, 0x1f, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x2f, 0x21, 0x20, 0x21, 0x21, 0x21, +0x21, 0x21, 0x21, 0x30, 0x31, 0x21, 0x21, 0x30, 0x31, 0x21, 0x31, 0x31, 0x31, 0x22, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, +0x31, 0x22, 0x32, 0x22, 0x22, 0x22, 0x31, 0x22, 0x32, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x31, 0x22, 0x22, 0x22, +0x32, 0x33, 0x31, 0x31, 0x22, 0x31, 0x31, 0x22, 0x31, 0x31, 0x22, 0x31, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x30, 0x21, +0x30, 0x30, 0x21, 0x30, 0x30, 0x30, 0x21, 0x20, 0x2f, 0x21, 0x20, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, +0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x1f, +0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, 0x2f, +0x20, 0x21, 0x21, 0x30, 0x21, 0x21, 0x30, 0x31, 0x30, 0x30, 0x21, 0x30, 0x31, 0x31, 0x22, 0x22, 0x31, 0x31, 0x31, 0x31, +0x31, 0x22, 0x22, 0x31, 0x22, 0x32, 0x22, 0x32, 0x22, 0x33, 0x33, 0x32, 0x32, 0x22, 0x22, 0x22, 0x32, 0x32, 0x33, 0x33, +0x33, 0x33, 0x32, 0x22, 0x33, 0x22, 0x32, 0x22, 0x33, 0x3a, 0x3a, 0x32, 0x33, 0x32, 0x22, 0x31, 0x22, 0x22, 0x22, 0x31, +0x22, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 0x21, 0x31, 0x31, 0x30, 0x30, 0x2f, 0x21, 0x21, 0x21, 0x21, +0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, +0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x2f, 0x20, 0x20, 0x21, 0x2f, 0x2f, 0x21, 0x21, 0x21, 0x21, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, +0x22, 0x22, 0x22, 0x33, 0x32, 0x22, 0x22, 0x31, 0x22, 0x22, 0x22, 0x22, 0x33, 0x32, 0x22, 0x33, 0x33, 0x44, 0x44, 0x44, +0x33, 0x32, 0x22, 0x32, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, 0x22, 0x32, 0x33, 0x32, 0x32, 0x33, 0x3b, 0x3a, 0x3a, 0x3b, +0x44, 0x33, 0x32, 0x33, 0x22, 0x31, 0x22, 0x22, 0x22, 0x31, 0x31, 0x31, 0x22, 0x22, 0x22, 0x22, 0x43, 0x31, 0x31, 0x31, +0x31, 0x31, 0x31, 0x21, 0x21, 0x30, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x20, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x1f, 0x20, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x2e, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, +0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x21, 0x2f, 0x21, 0x30, 0x21, 0x30, 0x21, 0x31, +0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33, 0x22, 0x32, 0x32, 0x22, 0x33, 0x32, +0x33, 0x33, 0x33, 0x3a, 0x44, 0x3a, 0x3a, 0x3a, 0x33, 0x33, 0x44, 0x33, 0x33, 0x33, 0x44, 0x44, 0x33, 0x33, 0x44, 0x33, +0x33, 0x33, 0x33, 0x44, 0x3b, 0x3b, 0x3c, 0x3a, 0x3a, 0x3b, 0x33, 0x33, 0x33, 0x33, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, +0x43, 0x22, 0x22, 0x22, 0x32, 0x22, 0x31, 0x31, 0x22, 0x32, 0x32, 0x30, 0x30, 0x21, 0x21, 0x21, 0x30, 0x21, 0x21, 0x30, +0x21, 0x20, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, +0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x2f, 0x21, 0x21, 0x30, 0x21, 0x21, +0x31, 0x31, 0x30, 0x21, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, +0x3a, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x3a, 0x3b, 0x3b, 0x3a, 0x3b, 0x3a, 0x3b, 0x33, 0x33, +0x3a, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3a, 0x24, 0x45, 0x3c, 0x3c, 0x45, 0x45, 0x3a, 0x3a, 0x3a, +0x3a, 0x3a, 0x33, 0x33, 0x33, 0x32, 0x33, 0x32, 0x22, 0x33, 0x22, 0x32, 0x32, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x22, +0x31, 0x31, 0x31, 0x30, 0x30, 0x31, 0x30, 0x30, 0x21, 0x21, 0x21, 0x21, 0x20, 0x2f, 0x21, 0x20, 0x20, 0x20, 0x2f, 0x2f, +0x1f, 0x1f, 0x20, 0x20, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x21, 0x20, +0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x31, 0x22, 0x22, 0x22, +0x33, 0x33, 0x33, 0x33, 0x32, 0x33, 0x3a, 0x3b, 0x3a, 0x3a, 0x44, 0x32, 0x33, 0x33, 0x44, 0x33, 0x3a, 0x3a, 0x3a, 0x3b, +0x54, 0x3b, 0x54, 0x54, 0x3b, 0x3b, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, +0x34, 0x3c, 0x3c, 0x45, 0x45, 0x45, 0x3b, 0x3b, 0x3a, 0x3b, 0x3a, 0x44, 0x33, 0x33, 0x33, 0x44, 0x33, 0x33, 0x33, 0x33, +0x22, 0x32, 0x32, 0x33, 0x33, 0x33, 0x23, 0x23, 0x22, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x21, 0x21, +0x21, 0x21, 0x2f, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, +0x20, 0x20, 0x20, 0x2f, 0x20, 0x2f, 0x2f, 0x2f, 0x30, 0x21, 0x21, 0x30, 0x31, 0x30, 0x21, 0x31, 0x31, 0x31, 0x31, 0x22, +0x22, 0x31, 0x22, 0x31, 0x22, 0x22, 0x22, 0x33, 0x3a, 0x3b, 0x3b, 0x33, 0x33, 0x3a, 0x3a, 0x3b, 0x24, 0x3b, 0x3b, 0x3a, +0x33, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x54, 0x45, 0x3c, 0x34, 0x3c, 0x45, 0x3b, 0x3b, 0x3b, 0x45, 0x3c, 0x45, +0x24, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x34, 0x34, 0x34, 0x34, 0x46, 0x55, 0x34, 0x45, 0x3b, 0x45, 0x3a, 0x44, 0x3a, +0x3a, 0x44, 0x3a, 0x3a, 0x3a, 0x33, 0x44, 0x33, 0x33, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, 0x32, 0x31, 0x31, 0x22, +0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x21, 0x30, 0x31, 0x30, 0x21, 0x30, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x2f, 0x20, 0x21, 0x2f, 0x21, 0x21, 0x30, 0x21, 0x31, +0x31, 0x31, 0x31, 0x31, 0x22, 0x22, 0x31, 0x31, 0x22, 0x32, 0x32, 0x22, 0x32, 0x32, 0x33, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, +0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x24, 0x3b, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x34, 0x16, 0x16, 0x17, 0x11, +0x11, 0xc, 0xb, 0xc, 0x3, 0x3, 0x3, 0xa, 0x3, 0x3, 0x3, 0x3, 0xa, 0xc, 0x11, 0x11, 0x13, 0x18, 0x1b, 0x35, +0x35, 0x46, 0x3c, 0x45, 0x3b, 0x3a, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3a, +0x3b, 0x3b, 0x3a, 0x33, 0x33, 0x32, 0x22, 0x31, 0x22, 0x22, 0x22, 0x43, 0x31, 0x31, 0x31, 0x30, 0x31, 0x21, 0x21, 0x21, +0x21, 0x30, 0x21, 0x21, 0x21, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x21, +0x21, 0x30, 0x21, 0x30, 0x31, 0x30, 0x31, 0x31, 0x31, 0x31, 0x22, 0x22, 0x31, 0x32, 0x22, 0x32, 0x32, 0x32, 0x32, 0x33, +0x32, 0x33, 0x33, 0x33, 0x3b, 0x45, 0x3c, 0x3c, 0x3c, 0x24, 0x24, 0x45, 0x34, 0x3c, 0x34, 0x3c, 0x3c, 0x12, 0x12, 0xc, +0x3, 0x2, 0x1, 0xe9, 0xe9, 0xf2, 0xf2, 0xf2, 0xf2, 0xe9, 0xe9, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe9, 0xe9, +0xe9, 0xe9, 0xe9, 0xf2, 0xf2, 0xf3, 0xf4, 0xf4, 0xf3, 0xe9, 0x1, 0x3, 0xc, 0x16, 0x3c, 0x24, 0x3b, 0x3b, 0x24, 0x3b, +0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3b, 0x3b, 0x24, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x32, 0x33, 0x32, 0x32, 0x32, 0x31, +0x22, 0x22, 0x31, 0x31, 0x31, 0x31, 0x30, 0x21, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x30, 0x21, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x32, +0x22, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x3a, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x16, +0x17, 0xe, 0x1, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xef, 0xf2, 0xf2, 0xf2, 0xf3, 0xf2, 0xf2, 0xe9, +0xe9, 0xe9, 0xf2, 0xe9, 0xf2, 0xe9, 0xe9, 0xf2, 0xea, 0xe9, 0xf3, 0xf3, 0xeb, 0xf5, 0xf5, 0xf5, 0x0, 0xf2, 0xf2, 0xe9, +0xe9, 0xe9, 0xe8, 0xe8, 0x1, 0x3, 0xc, 0x16, 0x3c, 0x45, 0x45, 0x3b, 0x3c, 0x3c, 0x3c, 0x3a, 0x3b, 0x3a, 0x3a, 0x3a, +0x33, 0x33, 0x33, 0x33, 0x32, 0x22, 0x33, 0x33, 0x22, 0x22, 0x22, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 0x21, +0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x2f, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x30, 0x30, 0x31, 0x30, 0x31, 0x31, +0x22, 0x22, 0x31, 0x22, 0x22, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, +0x3a, 0x3a, 0x3c, 0x1a, 0x11, 0xf9, 0xf1, 0xef, 0xea, 0xf3, 0x0, 0xf3, 0xf3, 0xf2, 0xe9, 0xe8, 0xe9, 0xea, 0xf2, 0xef, +0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf3, 0xf2, 0xea, 0xe9, 0xea, 0xf3, 0xf3, 0xf2, 0xea, 0xe9, 0xf2, 0xf3, 0xf2, 0xf3, 0x0, +0xf6, 0xf6, 0xf6, 0xf6, 0xf4, 0xf3, 0xf3, 0xea, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe8, 0x1, 0x3, 0x17, +0x34, 0x3c, 0x3c, 0x3c, 0x24, 0x24, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3a, 0x3a, 0x44, 0x33, 0x22, 0x22, 0x22, 0x22, 0x31, +0x22, 0x22, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x30, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x21, +0x21, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x31, 0x22, 0x22, 0x22, 0x33, 0x22, 0x33, 0x33, 0x33, 0x33, 0x44, +0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3a, 0x3a, 0x3b, 0x12, 0xf7, 0xf0, 0xe9, 0xf2, 0xea, 0xf2, 0xf2, 0xf2, 0x0, 0xf4, 0xf5, +0xf5, 0xf3, 0xf2, 0xe9, 0xe9, 0xe9, 0xf3, 0xf2, 0xf3, 0xf3, 0xf4, 0xf5, 0xf5, 0xf5, 0xf3, 0xf3, 0xf3, 0xf2, 0xf3, 0xf3, +0xf3, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf5, 0xf6, 0xf6, 0xf8, 0xf8, 0xf6, 0xf5, 0xf3, 0xf2, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, +0xea, 0xf2, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xef, 0xe9, 0xf1, 0xa, 0x1a, 0x3c, 0x24, 0x3c, 0x24, 0x45, 0x45, 0x45, 0x3b, +0x3a, 0x33, 0x33, 0x32, 0x33, 0x22, 0x32, 0x32, 0x32, 0x31, 0x22, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x21, 0x30, 0x21, +0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x31, 0x31, 0x22, 0x22, 0x31, 0x22, 0x31, 0x22, 0x22, 0x32, 0x32, +0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x12, 0x3, 0xed, 0xe8, 0xec, 0xec, 0xe8, +0xe9, 0xf2, 0xf2, 0xf3, 0x0, 0x0, 0xf4, 0xf5, 0xf5, 0xf5, 0xf4, 0xf2, 0xea, 0xf2, 0xf2, 0x5, 0x5, 0x5, 0x8, 0x1c, +0x1c, 0x1c, 0x10, 0x15, 0x15, 0x14, 0x15, 0x15, 0x14, 0x14, 0x14, 0x15, 0x15, 0x10, 0x1c, 0x1c, 0xf, 0x9, 0x9, 0x6, +0x4, 0xe6, 0xf3, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf2, 0xf2, 0xf2, 0xe9, 0xef, 0xf2, 0xf2, 0xef, 0xef, 0xf3, 0xea, 0xe9, +0xe9, 0xa, 0x17, 0x3c, 0x3c, 0x3c, 0x3c, 0x3b, 0x3a, 0x44, 0x3a, 0x33, 0x32, 0x33, 0x32, 0x22, 0x22, 0x32, 0x22, 0x22, +0x22, 0x22, 0x22, 0x31, 0x31, 0x30, 0x31, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x30, 0x21, 0x31, 0x31, 0x31, 0x22, 0x22, +0x22, 0x32, 0x32, 0x32, 0x22, 0x32, 0x22, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x33, 0x3a, 0x3a, 0x3b, 0x3b, 0x3a, 0x3c, 0xc, +0xf1, 0xe8, 0xe9, 0xe8, 0xe8, 0xe8, 0xee, 0xe8, 0xe9, 0xf2, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0x4, 0x1c, 0x10, 0x19, 0x1b, +0x35, 0x35, 0x35, 0x35, 0x48, 0x49, 0x4a, 0x4b, 0x57, 0x3d, 0x4a, 0x49, 0x48, 0x49, 0x4a, 0x49, 0x4a, 0x49, 0x49, 0x49, +0x4a, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x4e, 0x4c, 0x4a, 0x48, 0x35, 0x1b, 0x1b, 0x13, 0x14, 0xd, 0x5, 0xf2, 0xf3, 0xf2, +0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf2, 0xf2, 0xe9, 0x11, 0x34, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, +0x33, 0x33, 0x32, 0x33, 0x33, 0x32, 0x22, 0x32, 0x22, 0x22, 0x22, 0x22, 0x31, 0x31, 0x30, 0x21, 0x30, 0x21, 0x21, 0x2f, +0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x33, 0x32, 0x33, 0x32, 0x33, 0x33, 0x33, 0x33, 0x32, 0x33, 0x3a, 0x44, 0x33, 0x33, +0x3a, 0x3a, 0x3a, 0x3a, 0x12, 0xe7, 0xee, 0xe9, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xef, 0xf1, 0xd, 0x14, +0x1b, 0x25, 0x4a, 0x4b, 0x3d, 0x4c, 0x4c, 0x4a, 0x49, 0x35, 0x35, 0x49, 0x49, 0x4a, 0x4b, 0x4b, 0x4c, 0x4c, 0x4b, 0x4a, +0x49, 0x4a, 0x4b, 0x4b, 0x4b, 0x4a, 0x36, 0x4a, 0x4a, 0x3d, 0x4c, 0x4e, 0x4f, 0x51, 0x50, 0x4c, 0x4a, 0x48, 0x48, 0x48, +0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x25, 0x14, 0x5, 0xf4, 0xf4, 0xeb, 0xf4, 0xf4, 0xf4, 0xf3, 0xf2, 0xef, 0xef, +0xe8, 0xe8, 0x3, 0x24, 0x3b, 0x3a, 0x3a, 0x3a, 0x33, 0x33, 0x32, 0x33, 0x33, 0x32, 0x33, 0x33, 0x33, 0x32, 0x22, 0x31, +0x22, 0x31, 0x31, 0x31, 0x30, 0x30, 0x21, 0x30, 0x21, 0x31, 0x31, 0x22, 0x31, 0x22, 0x22, 0x32, 0x3a, 0x33, 0x33, 0x3a, +0x3a, 0x3a, 0x44, 0x3a, 0x3a, 0x33, 0x3a, 0x3a, 0x3a, 0x3b, 0x16, 0xf0, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xef, 0xef, +0xe9, 0xf2, 0xe, 0x17, 0x34, 0x34, 0x46, 0x35, 0x49, 0x49, 0x4b, 0x4c, 0x4c, 0x4d, 0x4e, 0x4c, 0x4b, 0x49, 0x48, 0x49, +0x4a, 0x4a, 0x4b, 0x4c, 0x58, 0x4e, 0x4d, 0x4b, 0x4a, 0x4a, 0x4b, 0x3d, 0x4b, 0x4a, 0x4b, 0x4a, 0x4b, 0x4d, 0x4e, 0x51, +0x53, 0x51, 0x4e, 0x4c, 0x4b, 0x36, 0x48, 0x49, 0x49, 0x49, 0x49, 0x36, 0x48, 0x48, 0x49, 0x48, 0x36, 0x36, 0x49, 0x36, +0x19, 0x10, 0xf5, 0xf5, 0xf4, 0xf3, 0xf2, 0xe9, 0xe9, 0xe8, 0xec, 0xee, 0xf0, 0x12, 0x3a, 0x33, 0x3a, 0x23, 0x23, 0x33, +0x33, 0x33, 0x33, 0x33, 0x33, 0x22, 0x32, 0x22, 0x22, 0x22, 0x22, 0x31, 0x31, 0x31, 0x30, 0x21, 0x21, 0x31, 0x31, 0x31, +0x22, 0x22, 0x32, 0x33, 0x3a, 0x33, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3a, 0x24, 0x3b, 0x3b, 0x3a, 0x12, 0x1, 0xee, 0xe8, +0xe8, 0xe8, 0xe9, 0xe9, 0xef, 0xea, 0xe9, 0x13, 0x35, 0x46, 0x46, 0x47, 0x47, 0x47, 0x46, 0x47, 0x35, 0x36, 0x4a, 0x4b, +0x4d, 0x3e, 0x50, 0x50, 0x4d, 0x4b, 0x49, 0x49, 0x4a, 0x4b, 0x3d, 0x3e, 0x50, 0x59, 0x50, 0x4d, 0x4b, 0x3d, 0x4c, 0x4d, +0x3d, 0x4b, 0x4c, 0x4c, 0x4d, 0x50, 0x51, 0x52, 0x52, 0x53, 0x50, 0x4d, 0x4b, 0x36, 0x36, 0x36, 0x4a, 0x4a, 0x4a, 0x4a, +0x49, 0x4a, 0x36, 0x36, 0x4a, 0x4b, 0x4a, 0x4b, 0x4a, 0x4a, 0x4a, 0x25, 0xd, 0xea, 0xe9, 0xe9, 0xe8, 0xec, 0xee, 0xec, +0xec, 0xee, 0xf0, 0x12, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, 0x33, 0x33, 0x22, 0x22, 0x32, 0x31, 0x31, 0x22, +0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x22, 0x22, 0x33, 0x22, 0x33, 0x3a, 0x3a, 0x3a, 0x45, 0x24, 0x24, 0x45, 0x24, +0x45, 0x45, 0x16, 0x1, 0xee, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xa, 0x46, 0x46, 0x46, 0x47, 0x48, 0x35, 0x35, +0x35, 0x47, 0x47, 0x47, 0x47, 0x49, 0x4a, 0x4c, 0x4d, 0x4e, 0x50, 0x4f, 0x50, 0x4e, 0x4c, 0x4a, 0x4b, 0x3d, 0x4d, 0x4e, +0x4f, 0x51, 0x4f, 0x50, 0x3e, 0x4d, 0x3e, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x51, 0x52, 0x40, 0x40, 0x53, 0x4e, 0x4c, +0x4b, 0x4a, 0x4b, 0x3d, 0x4b, 0x4b, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x3d, 0x4d, 0x4c, 0x4c, 0x4c, 0x4a, 0x36, 0x48, +0x47, 0x47, 0x1a, 0xa, 0xe8, 0xe8, 0xe8, 0xee, 0xe8, 0xe8, 0xec, 0xed, 0xe7, 0x38, 0x3a, 0x3a, 0x3a, 0x33, 0x3a, 0x33, +0x23, 0x32, 0x32, 0x33, 0x32, 0x22, 0x32, 0x22, 0x22, 0x31, 0x31, 0x31, 0x31, 0x22, 0x22, 0x31, 0x33, 0x33, 0x33, 0x3a, +0x3a, 0x44, 0x3b, 0x24, 0x3c, 0x34, 0x34, 0x34, 0x1a, 0xf9, 0xe9, 0xe9, 0xef, 0xe9, 0xe8, 0xe9, 0xe8, 0x1, 0x18, 0x46, +0x34, 0x46, 0x47, 0x35, 0x47, 0x35, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x35, 0x48, 0x49, 0x3d, 0x4c, 0x4e, 0x50, 0x4f, +0x53, 0x4f, 0x4e, 0x4b, 0x4c, 0x4c, 0x3e, 0x4e, 0x4f, 0x53, 0x53, 0x51, 0x50, 0x3e, 0x50, 0x4e, 0x50, 0x4e, 0x4e, 0x50, +0x4f, 0x53, 0x40, 0x67, 0x40, 0x53, 0x50, 0x4d, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4b, 0x4c, 0x3d, 0x4b, 0x4d, 0x4d, +0x4d, 0x3e, 0x4d, 0x4d, 0x4b, 0x4b, 0x49, 0x35, 0x46, 0x46, 0x34, 0x3c, 0x34, 0x17, 0xe5, 0xe8, 0xe8, 0xe8, 0xec, 0xec, +0xe8, 0xee, 0xb, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, 0x32, 0x33, 0x32, 0x32, 0x32, 0x22, 0x22, 0x22, 0x22, 0x31, +0x22, 0x31, 0x22, 0x22, 0x3b, 0x3a, 0x3b, 0x3a, 0x3b, 0x3a, 0x3b, 0x3c, 0x3c, 0x34, 0x34, 0x11, 0xf2, 0xf2, 0xf2, 0xf2, +0xf2, 0xf3, 0xf2, 0xd, 0x18, 0x46, 0x46, 0x46, 0x47, 0x46, 0x47, 0x35, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, +0x49, 0x49, 0x49, 0x4b, 0x4d, 0x3e, 0x50, 0x5a, 0x53, 0x53, 0x51, 0x50, 0x4c, 0x4d, 0x4e, 0x4f, 0x53, 0x3f, 0x40, 0xfa, +0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe2, 0xe2, 0x3f, 0x40, 0x41, 0x41, 0x40, 0x53, 0x4e, 0x4c, 0x4d, 0x4d, 0x3e, 0x4d, +0x4d, 0x4d, 0x4c, 0x4d, 0x4d, 0x4e, 0x4e, 0x50, 0x50, 0x4e, 0x58, 0x4c, 0x4b, 0x49, 0x48, 0x35, 0x46, 0x46, 0x34, 0x34, +0x34, 0x3c, 0x34, 0x1a, 0xe5, 0xe8, 0xe9, 0xe9, 0xec, 0xe8, 0xee, 0xed, 0x12, 0x3a, 0x44, 0x3a, 0x33, 0x33, 0x3a, 0x33, +0x33, 0x33, 0x33, 0x22, 0x32, 0x43, 0x31, 0x31, 0x22, 0x31, 0x22, 0x23, 0x3a, 0x3b, 0x3b, 0x24, 0x24, 0x24, 0x24, 0x45, +0x3c, 0x1a, 0x2, 0xf2, 0xf3, 0x0, 0xf4, 0xf4, 0xf4, 0x5, 0x1b, 0x35, 0x35, 0x35, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, +0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0x4a, 0x4a, 0x4a, 0x36, 0x36, 0x4b, 0x3e, 0x50, 0x51, 0x53, 0x3f, 0x3f, 0xdf, +0xdb, 0xd2, 0xcf, 0xd4, 0xcb, 0xcd, 0xbf, 0xbf, 0xbb, 0xcc, 0xc7, 0xcc, 0xc7, 0xc7, 0xcb, 0xcb, 0xcd, 0xbf, 0xd1, 0xd1, +0xd5, 0xd4, 0xdb, 0xe2, 0xe1, 0x4e, 0x50, 0x50, 0x3e, 0x4e, 0x4d, 0x4e, 0x50, 0x4f, 0x37, 0x4f, 0x59, 0x50, 0x4d, 0x4c, +0x49, 0x48, 0x48, 0x47, 0x46, 0x46, 0x46, 0x46, 0x34, 0x34, 0x34, 0x34, 0x34, 0x17, 0xf1, 0xe8, 0xe8, 0xe8, 0xe8, 0xee, +0xee, 0xb, 0x3b, 0x3a, 0x3a, 0x33, 0x3a, 0x3a, 0x33, 0x33, 0x33, 0x32, 0x33, 0x33, 0x31, 0x31, 0x22, 0x32, 0x32, 0x3b, +0x3b, 0x3a, 0x24, 0x24, 0x3c, 0x3c, 0x3c, 0x3c, 0x16, 0xf1, 0xea, 0xf2, 0xf3, 0xf3, 0xf5, 0xf5, 0x15, 0x4a, 0x4a, 0x4a, +0x4a, 0x36, 0x49, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x36, 0x4a, 0x4b, 0x4b, 0x4c, 0x3d, 0x4b, 0x4a, 0x4b, +0x4b, 0x4c, 0xe1, 0xdf, 0xd4, 0xd5, 0xcd, 0xcd, 0xbb, 0xb9, 0xb8, 0xc3, 0xc4, 0xc5, 0xc5, 0xc5, 0xc4, 0xbc, 0xc3, 0xc3, +0xc3, 0xc3, 0xc3, 0xc3, 0xc5, 0xc8, 0xbd, 0xc8, 0xc4, 0xba, 0xc7, 0xcb, 0xcb, 0xd4, 0xda, 0xdf, 0xfb, 0x50, 0x50, 0x4f, +0x37, 0x53, 0x51, 0x4f, 0x50, 0x4e, 0x3d, 0x4a, 0x49, 0x35, 0x35, 0x35, 0x47, 0x46, 0x47, 0x47, 0x46, 0x46, 0x47, 0x46, +0x34, 0x34, 0x34, 0xc, 0xe9, 0xe8, 0xec, 0xec, 0xec, 0xee, 0xf0, 0x24, 0x3b, 0x3b, 0x3a, 0x3a, 0x44, 0x44, 0x44, 0x33, +0x32, 0x33, 0x22, 0x31, 0x22, 0x32, 0x32, 0x33, 0x33, 0x3a, 0x24, 0x24, 0x24, 0x3c, 0x3c, 0x17, 0xe9, 0xe9, 0xe9, 0xf2, +0xf2, 0xf4, 0x5, 0x49, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4b, 0x4c, 0x4b, 0x4b, 0x4b, 0x4a, 0x49, 0x49, 0x36, 0x36, 0x4a, +0x4b, 0x3d, 0x4c, 0x4c, 0x4d, 0x4c, 0x4c, 0xe0, 0xd6, 0xd2, 0xbe, 0xca, 0xb8, 0xc4, 0xc5, 0xc5, 0xc4, 0xc3, 0xbb, 0xba, +0xba, 0xbf, 0xd1, 0xd1, 0xcd, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd5, 0xd1, 0xc8, 0xc8, 0xc5, 0xbc, 0xba, 0xb8, 0xc3, +0xc3, 0xba, 0xb9, 0xcb, 0xca, 0xd4, 0xd4, 0xda, 0x52, 0x53, 0x53, 0x4f, 0x4e, 0x3d, 0x4b, 0x4a, 0x48, 0x48, 0x35, 0x47, +0x47, 0x35, 0x35, 0x47, 0x47, 0x47, 0x47, 0x46, 0x46, 0x34, 0x34, 0x34, 0x34, 0x2, 0xe9, 0xe8, 0xe9, 0xe9, 0xe8, 0xee, +0x16, 0x3a, 0x3b, 0x3a, 0x44, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x32, 0x22, 0x22, 0x33, 0x33, 0x33, 0x3a, 0x3a, 0x3a, +0x3b, 0x24, 0xc, 0xe9, 0xe9, 0xef, 0xef, 0xe9, 0xf2, 0x13, 0x49, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x50, 0x3e, 0x4d, +0x4e, 0x4d, 0x4c, 0x4c, 0x4b, 0x36, 0x4a, 0x4b, 0x4b, 0x3d, 0x4d, 0x4d, 0x3e, 0xd8, 0xd3, 0xbe, 0xc6, 0xc0, 0xb6, 0xb8, +0xb8, 0xba, 0xbc, 0xbf, 0xcd, 0xd7, 0xfa, 0x3f, 0xfa, 0x41, 0x68, 0x68, 0x68, 0x41, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0x68, +0x68, 0xfd, 0x68, 0x41, 0x40, 0xda, 0xd0, 0xcc, 0xbb, 0xba, 0xba, 0xba, 0xc3, 0xc3, 0xc3, 0xcc, 0xd0, 0xd4, 0x37, 0x50, +0x4c, 0x4a, 0x36, 0x36, 0x36, 0x48, 0x48, 0x48, 0x49, 0x48, 0x49, 0x35, 0x47, 0x47, 0x47, 0x47, 0x47, 0x46, 0x46, 0x34, +0x46, 0x34, 0xc, 0xe9, 0xe9, 0xe8, 0xe9, 0xe8, 0xee, 0x12, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x3b, 0x3a, 0x3a, 0x22, +0x32, 0x32, 0x33, 0x33, 0x33, 0x32, 0x33, 0x33, 0x3a, 0xf7, 0xe8, 0xec, 0xe9, 0xe9, 0xef, 0xe9, 0x1a, 0x35, 0x47, 0x48, +0x49, 0x25, 0x4b, 0x4d, 0x4d, 0x50, 0x50, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x4d, 0x4c, 0x3d, 0x4b, 0x4c, 0x3e, 0xdb, +0xcf, 0xca, 0xc7, 0xb8, 0xb8, 0xc2, 0xc7, 0xca, 0xcf, 0xd9, 0xfa, 0xe3, 0x41, 0x41, 0x41, 0x67, 0xa1, 0xa7, 0x9e, 0xac, +0xac, 0xb0, 0xaa, 0xaa, 0xaa, 0x9a, 0x9a, 0x90, 0xac, 0xac, 0x9e, 0x68, 0x67, 0x40, 0x40, 0x40, 0xfa, 0xfa, 0xd0, 0xcc, +0xc3, 0xc4, 0xc4, 0xc4, 0xc3, 0xcb, 0xbe, 0xdb, 0xdd, 0x4a, 0x4a, 0x4a, 0x49, 0x36, 0x36, 0x36, 0x49, 0x49, 0x49, 0x48, +0x48, 0x35, 0x35, 0x35, 0x47, 0x47, 0x47, 0x47, 0x47, 0x46, 0x46, 0x17, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0x16, 0x3c, +0x3c, 0x24, 0x24, 0x24, 0x3b, 0x3b, 0x3b, 0x22, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x3a, 0x33, 0x12, 0xee, 0xed, 0xee, +0xec, 0xe9, 0x1, 0x34, 0x34, 0x47, 0x46, 0x47, 0x35, 0x48, 0x25, 0x4b, 0x4b, 0x4d, 0x50, 0x50, 0x51, 0x53, 0x53, 0x53, +0x5a, 0x51, 0x4f, 0x50, 0x3e, 0xdb, 0xd3, 0xca, 0xb6, 0xb8, 0xb8, 0xba, 0xc7, 0xd4, 0xdf, 0xe2, 0xfb, 0x37, 0x5b, 0xa1, +0xa7, 0xb0, 0xb0, 0xb0, 0xa4, 0xa5, 0xa6, 0x9c, 0x9c, 0x9c, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0x9c, 0x9c, 0x96, 0xa6, 0xa4, +0xaa, 0x9a, 0xa7, 0xa1, 0x67, 0x40, 0x40, 0xe3, 0x41, 0xd5, 0xcd, 0xc3, 0xba, 0xb8, 0xb6, 0xc1, 0xce, 0xd6, 0xe0, 0x4a, +0x4b, 0x4a, 0x4a, 0x4a, 0x36, 0x48, 0x49, 0x48, 0x49, 0x48, 0x35, 0x48, 0x35, 0x35, 0x35, 0x35, 0x47, 0x46, 0x46, 0x34, +0x1a, 0xe9, 0xe9, 0xef, 0xef, 0xe9, 0xe9, 0x16, 0x3c, 0x3c, 0x24, 0x24, 0x3b, 0x3a, 0x3a, 0x22, 0x32, 0x32, 0x33, 0x33, +0x23, 0x33, 0x33, 0x24, 0xee, 0xee, 0xee, 0xec, 0xee, 0xe7, 0x3c, 0x3c, 0x34, 0x34, 0x34, 0x47, 0x47, 0x48, 0x49, 0x49, +0x4b, 0x4b, 0x4d, 0x50, 0x4f, 0x51, 0x52, 0x3f, 0x5b, 0x3f, 0x52, 0xda, 0xd0, 0xcb, 0xb9, 0xb8, 0xb9, 0xc7, 0xcb, 0xda, +0x37, 0xfa, 0x3f, 0x40, 0xab, 0xa1, 0xa9, 0xa2, 0xa0, 0xa5, 0x9b, 0xa6, 0xa5, 0x98, 0x9c, 0x96, 0x96, 0x96, 0x96, 0x9c, +0x9c, 0x9c, 0x96, 0x96, 0x83, 0x96, 0x9c, 0xa6, 0xa5, 0xa5, 0xa0, 0xa4, 0xb0, 0x9a, 0xa7, 0x68, 0xe3, 0xe3, 0x40, 0xd9, +0xbe, 0xc6, 0xb7, 0xc0, 0xc0, 0xc9, 0xce, 0xd6, 0x3d, 0x4a, 0x4b, 0x4a, 0x4a, 0x4a, 0x4a, 0x36, 0x49, 0x49, 0x49, 0x49, +0x48, 0x48, 0x48, 0x47, 0x47, 0x47, 0x46, 0x47, 0x47, 0x1a, 0xe9, 0xe9, 0xef, 0xe9, 0xe8, 0xe9, 0x16, 0x3c, 0x24, 0x3b, +0x3a, 0x3a, 0x33, 0x32, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x33, 0x38, 0xf0, 0xed, 0xee, 0xee, 0xee, 0x2, 0x3c, 0x3c, 0x3c, +0x3c, 0x3c, 0x34, 0x34, 0x47, 0x47, 0x47, 0x35, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x50, 0x51, 0x52, 0x3f, 0x40, 0xd7, 0xcd, +0xbc, 0xc4, 0xc4, 0xc3, 0xcb, 0xda, 0xe2, 0x37, 0x3f, 0xab, 0xa1, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0x9d, 0x8f, 0x95, 0x84, +0x97, 0x7c, 0x82, 0x83, 0x87, 0x87, 0x83, 0x83, 0x83, 0x83, 0x83, 0x87, 0x87, 0x83, 0x82, 0x84, 0x9c, 0x9b, 0xa6, 0xa6, +0xa6, 0xa6, 0xa5, 0xa4, 0x9a, 0xa1, 0x5c, 0xfb, 0xe1, 0xd8, 0xbe, 0xc0, 0xb7, 0xb6, 0xc0, 0xc9, 0xd2, 0xdd, 0x3d, 0x3d, +0x4b, 0x4a, 0x4b, 0x4a, 0x36, 0x49, 0x49, 0x49, 0x49, 0x49, 0x48, 0x49, 0x48, 0x35, 0x35, 0x35, 0x35, 0x47, 0x1a, 0xea, +0xea, 0xf2, 0xea, 0xe9, 0x1, 0x3c, 0x3c, 0x3c, 0x3a, 0x3a, 0x3a, 0x32, 0x33, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, 0xf7, 0xec, +0xec, 0xec, 0xe8, 0xe8, 0x24, 0x24, 0x3c, 0x3c, 0x34, 0x3c, 0x3c, 0x34, 0x34, 0x34, 0x47, 0x47, 0x35, 0x49, 0x48, 0x4b, +0x4b, 0x4c, 0x3e, 0x50, 0xdf, 0xd0, 0xcd, 0xc4, 0xc5, 0xc5, 0xc5, 0xd5, 0x41, 0x40, 0x40, 0xab, 0xa1, 0xa3, 0xa2, 0xa4, +0xa0, 0xa0, 0x9d, 0x9d, 0x6b, 0x6b, 0x6c, 0x72, 0x6a, 0x82, 0x6a, 0x6f, 0x74, 0x74, 0x74, 0x73, 0x73, 0x73, 0x73, 0x74, +0x74, 0x87, 0x83, 0x96, 0x82, 0x82, 0x9c, 0x84, 0x9c, 0x9c, 0x9b, 0xa5, 0xa2, 0xa3, 0xa1, 0x9f, 0xfc, 0xe1, 0xe1, 0xdb, +0xca, 0xb6, 0xc2, 0xc2, 0xc1, 0xce, 0xd6, 0x4c, 0x3d, 0x4c, 0x4b, 0x4a, 0x4b, 0x4a, 0x4a, 0x4b, 0x4a, 0x4a, 0x49, 0x36, +0x49, 0x36, 0x36, 0x49, 0x35, 0x48, 0x35, 0x1b, 0xf3, 0xf2, 0xef, 0xea, 0xef, 0x3, 0x3c, 0x3c, 0x24, 0x3b, 0x3b, 0x33, +0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x12, 0xec, 0xec, 0xe8, 0xe8, 0xe8, 0x17, 0x3c, 0x34, 0x3c, 0x3c, 0x34, 0x34, 0x34, 0x34, +0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x35, 0x48, 0x49, 0x4a, 0x4b, 0xdd, 0xd3, 0xca, 0xba, 0xc3, 0xbc, 0xbc, 0xd5, 0x68, +0x68, 0x68, 0x9e, 0xb0, 0xa4, 0xa4, 0xa4, 0x9d, 0x9d, 0x6b, 0x6b, 0x61, 0x71, 0x61, 0x72, 0x6a, 0x6f, 0x73, 0x74, 0x80, +0x7d, 0x7d, 0x7d, 0x7d, 0x7b, 0x7d, 0x7d, 0x7d, 0x7b, 0x80, 0x79, 0x79, 0x87, 0x83, 0x83, 0x96, 0x82, 0x82, 0x95, 0xa5, +0xa0, 0xa2, 0xa8, 0xa9, 0xab, 0xad, 0xfb, 0xe2, 0xe2, 0xbe, 0xb6, 0xb9, 0xc2, 0xc6, 0xcf, 0xd6, 0x4c, 0x4c, 0x4d, 0x3d, +0x4c, 0x4c, 0x4c, 0x4c, 0x4b, 0x4b, 0x3d, 0x4b, 0x25, 0x4b, 0x4b, 0x4a, 0x49, 0x36, 0x49, 0x35, 0x14, 0xf3, 0xea, 0xf2, +0xea, 0xef, 0x1a, 0x3c, 0x3c, 0x3a, 0x3b, 0x33, 0x44, 0x3a, 0x3a, 0x3b, 0x3c, 0xf0, 0xe8, 0xec, 0xe8, 0xe8, 0x3, 0x3c, +0x34, 0x34, 0x34, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x49, 0xdc, 0xd2, +0xc9, 0xb6, 0xc2, 0xc7, 0xcb, 0xfa, 0x40, 0x41, 0x68, 0xb0, 0xa5, 0xa6, 0x9b, 0x95, 0x81, 0x6b, 0x6b, 0x61, 0x61, 0x6c, +0x66, 0x6a, 0x64, 0x73, 0x80, 0x7b, 0x7d, 0x7f, 0x85, 0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x86, 0x85, 0x7d, 0x7d, 0x80, +0x80, 0x7a, 0x7a, 0x87, 0x96, 0x82, 0x95, 0x98, 0x8f, 0xa4, 0xa4, 0xa2, 0xa8, 0xa9, 0xab, 0x37, 0x37, 0xfb, 0xbe, 0xb9, +0xc2, 0xb8, 0xb7, 0xbe, 0xdb, 0x3e, 0x4e, 0x3e, 0x3e, 0x4e, 0x4e, 0x4e, 0x4d, 0x4d, 0x3e, 0x4d, 0x3d, 0x3d, 0x4a, 0x4b, +0x4b, 0x36, 0x49, 0x49, 0x48, 0x5, 0xf2, 0xf3, 0xea, 0xe9, 0x2, 0x3c, 0x3b, 0x3a, 0x3b, 0x23, 0x33, 0x33, 0x3b, 0x3b, +0x12, 0xec, 0xe8, 0xe8, 0xe8, 0xe9, 0x1a, 0x34, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x35, 0x35, 0x48, 0x48, 0x35, 0x49, +0x49, 0x48, 0x48, 0x49, 0x49, 0xdc, 0xd6, 0xce, 0xc1, 0xc0, 0xc1, 0xc9, 0xe1, 0xe1, 0xfc, 0xab, 0xa9, 0xa4, 0xa0, 0xa6, +0x97, 0x84, 0x6c, 0x5f, 0x5f, 0x66, 0x6a, 0x64, 0x6f, 0x74, 0x80, 0x7b, 0x7d, 0x7f, 0x86, 0x86, 0x8e, 0x8a, 0x8a, 0x8a, +0x8a, 0x8e, 0x8a, 0x8e, 0x8b, 0x88, 0x85, 0x7f, 0x7f, 0x7b, 0x80, 0x7a, 0x87, 0x83, 0x82, 0x81, 0x81, 0x98, 0xa5, 0xa0, +0xa4, 0xa2, 0xa9, 0xab, 0x5c, 0x37, 0x37, 0xd4, 0xbb, 0xba, 0xb8, 0xc7, 0xd4, 0xdf, 0x50, 0x50, 0x4f, 0x4f, 0x4f, 0x50, +0x4e, 0x50, 0x3e, 0x4d, 0x4d, 0x4c, 0x4b, 0x4b, 0x4b, 0x36, 0x49, 0x49, 0x35, 0x18, 0xf2, 0xf2, 0xe9, 0xe9, 0xe8, 0x16, +0x3b, 0x24, 0x3b, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, 0xf0, 0xee, 0xe8, 0xe8, 0xe8, 0xc, 0x3c, 0x34, 0x46, 0x46, 0x47, 0x47, +0x35, 0x48, 0x35, 0x49, 0x49, 0x49, 0x49, 0x49, 0x36, 0x36, 0x4a, 0x4a, 0x3d, 0xd6, 0xce, 0xc1, 0xc0, 0xc0, 0xc9, 0xdd, +0x3d, 0x3e, 0xb1, 0xab, 0xa3, 0xa8, 0xa2, 0x6b, 0x6b, 0x61, 0x5f, 0x66, 0x5e, 0x64, 0x63, 0x60, 0x6e, 0x7b, 0x7f, 0x7f, +0x88, 0x86, 0x8e, 0x8a, 0x89, 0x89, 0x93, 0x93, 0x7e, 0x93, 0x93, 0x89, 0x8a, 0x8e, 0x8b, 0x8b, 0x88, 0x85, 0x7d, 0x80, +0x7a, 0x79, 0x83, 0x96, 0x84, 0x95, 0x81, 0x8f, 0xa0, 0xa4, 0xa2, 0x9a, 0xa1, 0x5b, 0xfa, 0xfa, 0xcb, 0xc3, 0xc3, 0xc3, +0xcb, 0xd0, 0xd9, 0x37, 0x37, 0x4f, 0x51, 0x4f, 0x4e, 0x3e, 0x4d, 0x4c, 0x3d, 0x4b, 0x4a, 0x4a, 0x49, 0x49, 0x35, 0x35, +0x47, 0x34, 0xd, 0xe9, 0xe9, 0xe8, 0xe8, 0x3, 0x3b, 0x3a, 0x3a, 0x33, 0x23, 0x33, 0x3a, 0x24, 0xec, 0xee, 0xe8, 0xe8, +0xe8, 0x34, 0x3c, 0x34, 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49, 0x49, 0x36, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, +0xd6, 0xce, 0xc1, 0xc7, 0xb7, 0xc0, 0xd2, 0xe4, 0x3e, 0xb1, 0xab, 0xa9, 0xa3, 0xa3, 0x9a, 0x9e, 0x62, 0x6b, 0x61, 0x5f, +0x64, 0x74, 0x6e, 0x7d, 0x7f, 0x88, 0x88, 0x8b, 0x8e, 0x8a, 0x89, 0x93, 0x91, 0x8c, 0x94, 0x94, 0x94, 0x94, 0x94, 0x91, +0x93, 0x89, 0x89, 0x8a, 0x8b, 0x88, 0x85, 0x7d, 0x7b, 0x7a, 0x79, 0x87, 0x96, 0x72, 0x84, 0x95, 0x95, 0xa5, 0xa0, 0xa4, +0x9a, 0xa1, 0x40, 0xe3, 0xe3, 0xcd, 0xc3, 0xc3, 0xba, 0xcb, 0xda, 0x51, 0x4f, 0x4f, 0x4e, 0x4e, 0x4d, 0x4d, 0x4c, 0x4b, +0x4b, 0x4a, 0x49, 0x49, 0x35, 0x47, 0x47, 0x47, 0x34, 0x34, 0x17, 0xe9, 0xe9, 0xe8, 0xee, 0xed, 0x38, 0x3a, 0x3a, 0x33, +0x3a, 0x3a, 0x44, 0xb, 0xee, 0xec, 0xe8, 0xec, 0xe7, 0x3c, 0x34, 0x3c, 0x34, 0x46, 0x46, 0x47, 0x47, 0x35, 0x47, 0x49, +0x48, 0x49, 0x49, 0x4a, 0x4a, 0x3d, 0x4b, 0x4d, 0xd2, 0xbe, 0xb7, 0xb6, 0xb7, 0xbe, 0xfb, 0xe1, 0x78, 0xab, 0xa9, 0xa3, +0xa8, 0x9a, 0x9e, 0x62, 0x62, 0x62, 0x61, 0x5f, 0x64, 0x74, 0x7b, 0x7f, 0x86, 0x8b, 0x8a, 0x8a, 0x89, 0x93, 0x93, 0x8c, +0x92, 0x92, 0x99, 0xaf, 0x99, 0xaf, 0x92, 0x94, 0x94, 0x8c, 0x93, 0x8a, 0x8a, 0x8b, 0x86, 0x85, 0x7f, 0x7d, 0x80, 0x7a, +0x79, 0x83, 0x82, 0x82, 0x7c, 0x95, 0x9b, 0xa5, 0xa4, 0x9a, 0xa1, 0x40, 0x40, 0xd0, 0xba, 0xba, 0xba, 0xc7, 0xd4, 0xd8, +0x4e, 0x3e, 0x4c, 0x4c, 0x4b, 0x4a, 0x36, 0x49, 0x49, 0x49, 0x35, 0x35, 0x47, 0x46, 0x47, 0x34, 0x34, 0x3c, 0x34, 0xf1, +0xee, 0xe8, 0xee, 0xee, 0x12, 0x3a, 0x33, 0x33, 0x3a, 0x3a, 0x3a, 0x3, 0xee, 0xe8, 0xe8, 0xe8, 0x17, 0x3c, 0x34, 0x34, +0x34, 0x46, 0x46, 0x47, 0x46, 0x47, 0x35, 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0xdd, 0xd2, 0xc1, 0xb6, 0xb6, +0xb7, 0xd3, 0xfb, 0xe2, 0x9f, 0xa1, 0xa8, 0xa2, 0xaa, 0x90, 0x62, 0x62, 0x62, 0x61, 0x5f, 0x6a, 0x6f, 0x6e, 0x7b, 0x7f, +0x86, 0x8e, 0x8a, 0x93, 0x91, 0x8c, 0x94, 0x92, 0x99, 0xb2, 0xb3, 0xb5, 0xb5, 0xb4, 0xaf, 0xaf, 0x92, 0x94, 0x91, 0x93, +0x89, 0x8a, 0x8b, 0x8b, 0x88, 0x85, 0x7d, 0x7b, 0x7a, 0x79, 0x6a, 0x82, 0x84, 0x95, 0x98, 0xa0, 0xa4, 0xaa, 0xa1, 0x3f, +0x3f, 0xdf, 0xcb, 0xb8, 0xb8, 0xb7, 0xc9, 0xd6, 0x3d, 0x3d, 0x4b, 0x4a, 0x36, 0x48, 0x48, 0x48, 0x35, 0x47, 0x47, 0x46, +0x47, 0x34, 0x46, 0x3c, 0x34, 0x3c, 0x45, 0x3, 0xe8, 0xec, 0xe8, 0xec, 0xb, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x1, +0xec, 0xe8, 0xe8, 0xe9, 0x1a, 0x3c, 0x34, 0x34, 0x34, 0x47, 0x46, 0x47, 0x47, 0x35, 0x35, 0x48, 0x49, 0x48, 0x36, 0x36, +0x36, 0x4a, 0x3d, 0xd6, 0xce, 0xc0, 0xc2, 0xb7, 0xca, 0xd8, 0xfb, 0x37, 0xab, 0xa3, 0xa2, 0xa2, 0x8d, 0x90, 0x6b, 0x62, +0x61, 0x5d, 0x5e, 0x64, 0x74, 0x7b, 0x7d, 0x88, 0x86, 0x8a, 0x89, 0x93, 0x8c, 0x92, 0x99, 0xaf, 0xb2, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xb2, 0x99, 0x92, 0x94, 0x8c, 0x91, 0x93, 0x89, 0x8a, 0x8b, 0x88, 0x7f, 0x7b, 0x80, 0x79, 0x83, 0x72, +0x7c, 0x81, 0x8f, 0x9d, 0xa2, 0xa8, 0xa1, 0xad, 0xfb, 0xfb, 0xcf, 0xb7, 0xb7, 0xc0, 0xc9, 0xd6, 0x3d, 0x4a, 0x36, 0x49, +0x49, 0x49, 0x49, 0x48, 0x47, 0x35, 0x47, 0x47, 0x47, 0x34, 0x34, 0x46, 0x3c, 0x3c, 0x3c, 0x17, 0xe8, 0xe8, 0xe8, 0xee, +0x3, 0x3a, 0x3a, 0x33, 0x3a, 0x3a, 0x38, 0xee, 0xee, 0xe8, 0xe8, 0xe8, 0x16, 0x3c, 0x34, 0x34, 0x34, 0x47, 0x46, 0x47, +0x47, 0x35, 0x48, 0x49, 0x48, 0x49, 0x36, 0x36, 0x36, 0x4a, 0x4a, 0xd6, 0xc9, 0xc0, 0xb6, 0xc7, 0xbe, 0xfb, 0xfb, 0xae, +0xab, 0xa3, 0xa2, 0x8d, 0x90, 0x90, 0x6b, 0x6b, 0x61, 0x5f, 0x5e, 0x73, 0x80, 0x7d, 0x7f, 0x86, 0x8e, 0x8a, 0x89, 0x91, +0x94, 0x92, 0x99, 0xb2, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xb2, 0xaf, 0x99, 0x92, 0x8c, 0x91, 0x89, 0x8a, +0x8e, 0x86, 0x85, 0x7d, 0x80, 0x7a, 0x87, 0x82, 0x7c, 0x81, 0x8f, 0x9d, 0xa4, 0xa2, 0xa9, 0x9f, 0xe2, 0xfb, 0xcf, 0xb7, +0xc2, 0xc2, 0xc9, 0xd2, 0xe4, 0x4b, 0x3d, 0x4b, 0x4a, 0x4a, 0x49, 0x48, 0x48, 0x48, 0x35, 0x47, 0x47, 0x47, 0x47, 0x46, +0x46, 0x34, 0x3c, 0x1a, 0xe8, 0xe8, 0xe8, 0xee, 0xf0, 0x3a, 0x3a, 0x33, 0x3a, 0x3a, 0x38, 0xee, 0xee, 0xe8, 0xe8, 0xe8, +0x34, 0x3c, 0x34, 0x34, 0x46, 0x47, 0x47, 0x47, 0x35, 0x48, 0x48, 0x48, 0x49, 0x49, 0x36, 0x36, 0x36, 0x4b, 0x4b, 0xd6, +0xc9, 0xc0, 0xb6, 0xb7, 0xcf, 0xfb, 0xe1, 0xad, 0xa1, 0xa3, 0xa2, 0xa2, 0x90, 0x62, 0x62, 0x61, 0x5d, 0x5f, 0x64, 0x73, +0x6e, 0x7d, 0x85, 0x86, 0x8e, 0x8a, 0x93, 0x8c, 0x94, 0x99, 0xaf, 0xb4, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xb4, 0xb2, 0x99, 0x92, 0x94, 0x91, 0x93, 0x89, 0x8e, 0x8b, 0x88, 0x7f, 0x7b, 0x74, 0x79, 0x6a, 0x82, 0x84, 0x81, 0x98, +0xa5, 0xa4, 0x9a, 0xa1, 0xfa, 0x3f, 0xd4, 0xbb, 0xb8, 0xba, 0xc6, 0xd3, 0xfb, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, 0x4b, +0x36, 0x49, 0x49, 0x48, 0x49, 0x35, 0x48, 0x47, 0x47, 0x46, 0x46, 0x1a, 0xe9, 0xe9, 0xe8, 0xe8, 0x1, 0x24, 0x3b, 0x3a, +0x3a, 0x3a, 0x24, 0xee, 0xec, 0xe8, 0xe8, 0xe8, 0x34, 0x34, 0x34, 0x34, 0x47, 0x47, 0x46, 0x47, 0x35, 0x35, 0x48, 0x48, +0x48, 0x48, 0x4a, 0x4a, 0x4a, 0x4a, 0x3d, 0xd8, 0xce, 0xb7, 0xb6, 0xc0, 0xbe, 0xe1, 0xfb, 0xae, 0xab, 0xa3, 0xa8, 0xa2, +0x90, 0x90, 0x62, 0x6b, 0x61, 0x5f, 0x5e, 0x63, 0x6e, 0x7d, 0x85, 0x8b, 0x76, 0x89, 0x91, 0x8c, 0x92, 0x99, 0xb2, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xb5, 0xaf, 0x99, 0x92, 0x94, 0x91, 0x93, 0x89, 0x8a, 0x8b, 0x88, 0x85, +0x7d, 0x80, 0x73, 0x87, 0x6a, 0x82, 0x84, 0x97, 0x9b, 0xa5, 0xaa, 0xa1, 0x67, 0x40, 0xd7, 0xc3, 0xc3, 0xc3, 0xcb, 0xd4, +0x37, 0x50, 0x50, 0x3e, 0x4d, 0x4d, 0x4c, 0x3d, 0x4b, 0x4b, 0x4a, 0x49, 0x56, 0x48, 0x48, 0x48, 0x47, 0x35, 0x46, 0x18, +0xe9, 0xe9, 0xe8, 0xe8, 0x1, 0x3c, 0x3b, 0x33, 0x33, 0x3b, 0x24, 0xee, 0xee, 0xe8, 0xe8, 0xe9, 0x16, 0x3c, 0x34, 0x34, +0x34, 0x46, 0x46, 0x47, 0x47, 0x35, 0x35, 0x35, 0x48, 0x49, 0x36, 0x36, 0x36, 0x4a, 0x4a, 0xd6, 0xce, 0xc0, 0xc0, 0xc0, +0xbe, 0xe1, 0xe1, 0x4f, 0xab, 0xa9, 0xa8, 0xa2, 0x90, 0x90, 0x6b, 0x61, 0x5d, 0x5e, 0x64, 0x63, 0x6e, 0x70, 0x70, 0x75, +0x8a, 0x93, 0x7e, 0x8c, 0x92, 0x99, 0xaf, 0xb3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xb2, 0xaf, 0x99, 0x92, +0x94, 0x91, 0x89, 0x8a, 0x8e, 0x8b, 0x88, 0x7f, 0x7b, 0x80, 0x73, 0x6a, 0x6a, 0x82, 0x84, 0x9c, 0x9b, 0xa5, 0x90, 0x68, +0x41, 0xe3, 0xd5, 0xc3, 0xc4, 0xc3, 0xcb, 0xd4, 0x37, 0x4f, 0x50, 0x4e, 0x4e, 0x4d, 0x4d, 0x4d, 0x4b, 0x4c, 0x4b, 0x4a, +0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, 0x18, 0xf2, 0xf2, 0xf2, 0xe9, 0x1, 0x3b, 0x3b, 0x33, 0x3a, 0x3a, 0x24, 0xf0, +0xee, 0xe8, 0xec, 0xe9, 0x16, 0x3c, 0x34, 0x34, 0x34, 0x34, 0x46, 0x46, 0x47, 0x47, 0x35, 0x35, 0x48, 0x48, 0x49, 0x49, +0x49, 0x4a, 0x4a, 0xdd, 0xce, 0xc1, 0xb6, 0xb6, 0xc6, 0xdf, 0xfb, 0xe2, 0xab, 0xa9, 0xa2, 0xa0, 0x9d, 0x6b, 0x71, 0x61, +0x5f, 0x5e, 0x64, 0x60, 0x69, 0x69, 0x88, 0x75, 0x8e, 0x77, 0x89, 0x91, 0x8c, 0x92, 0x99, 0xaf, 0xb5, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xb4, 0xaf, 0x99, 0x92, 0x92, 0x8c, 0x91, 0x93, 0x89, 0x8a, 0x8b, 0x88, 0x7f, 0x7d, 0x6e, 0x73, 0x64, 0x83, +0x72, 0x84, 0x97, 0x9b, 0xa5, 0x9d, 0xa7, 0x41, 0x40, 0x40, 0xcc, 0xc3, 0xc3, 0xba, 0xcb, 0xda, 0x4f, 0x50, 0x50, 0x4e, +0x4d, 0x4c, 0x4c, 0x3d, 0x4b, 0x4b, 0x4b, 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x46, 0x13, 0xe9, 0xe9, 0xe9, 0xe9, +0x2, 0x45, 0x3b, 0x33, 0x3a, 0x3a, 0x3a, 0x3, 0xee, 0xee, 0xec, 0xe8, 0xb, 0x24, 0x3c, 0x34, 0x3c, 0x34, 0x34, 0x47, +0x46, 0x47, 0x35, 0x49, 0x49, 0x36, 0x36, 0x4b, 0x4b, 0x3d, 0x4c, 0xe4, 0xd3, 0xca, 0xb8, 0xb8, 0xb9, 0xd4, 0x3f, 0x40, +0x41, 0xa7, 0xa0, 0xa5, 0x9b, 0x7c, 0x6c, 0x5f, 0x66, 0x5e, 0x64, 0x63, 0x60, 0x69, 0x69, 0x6d, 0x6d, 0x8e, 0x77, 0x89, +0x7e, 0x8c, 0x94, 0x99, 0xaf, 0xaf, 0xb3, 0xb3, 0xb2, 0xaf, 0x99, 0x99, 0x92, 0x8c, 0x91, 0x93, 0x89, 0x8a, 0x8a, 0x8b, +0x86, 0x85, 0x7d, 0x6e, 0x73, 0x87, 0x6a, 0x72, 0x7c, 0x81, 0x98, 0xa5, 0xa0, 0x9a, 0xa1, 0x5b, 0xfa, 0xd4, 0xba, 0xba, +0xba, 0xc7, 0xd4, 0xdf, 0x4e, 0x3e, 0x4e, 0x4c, 0x4c, 0x4b, 0x4b, 0x4b, 0x4a, 0x56, 0x49, 0x49, 0x49, 0x48, 0x35, 0x47, +0x47, 0x46, 0x46, 0xe, 0xea, 0xe9, 0xe9, 0xe8, 0xc, 0x3b, 0x3a, 0x33, 0x33, 0x3a, 0x33, 0xf7, 0xed, 0xec, 0xee, 0xec, +0xe7, 0x34, 0x34, 0x34, 0x46, 0x47, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x4b, 0x4b, 0x3d, 0x4c, 0x4c, 0x4e, 0x4e, 0x50, +0xd9, 0xd0, 0xba, 0xc3, 0xbc, 0xbf, 0xde, 0x41, 0x41, 0xa7, 0x9d, 0xa6, 0x9b, 0x97, 0x84, 0x72, 0x66, 0x5e, 0x5e, 0x64, +0x63, 0x60, 0x6e, 0x69, 0x70, 0x6d, 0x75, 0x76, 0x77, 0x89, 0x7e, 0x7e, 0x8c, 0x92, 0x99, 0x92, 0x92, 0x94, 0x8c, 0x8c, +0x91, 0x93, 0x89, 0x8a, 0x8e, 0x86, 0x88, 0x85, 0x7f, 0x7d, 0x7b, 0x74, 0x6f, 0x6a, 0x72, 0x7c, 0x81, 0x8f, 0xa5, 0xa4, +0xa8, 0xa1, 0x5b, 0x3f, 0x53, 0xd0, 0xb8, 0xb8, 0xb9, 0xca, 0xd3, 0xe1, 0x4d, 0x4d, 0x3d, 0x4c, 0x4b, 0x4b, 0x4b, 0x36, +0x36, 0x49, 0x48, 0x48, 0x35, 0x48, 0x47, 0x46, 0x47, 0x34, 0x34, 0xf1, 0xe9, 0xe8, 0xe9, 0xe8, 0x16, 0x3b, 0x3b, 0x33, +0x33, 0x3a, 0x3b, 0x24, 0xee, 0xee, 0xe8, 0xe9, 0xe9, 0x16, 0x34, 0x47, 0x47, 0x35, 0x48, 0x48, 0x36, 0x36, 0x4a, 0x4b, +0x4c, 0x4c, 0x4e, 0x4e, 0x50, 0x4f, 0x51, 0x37, 0xfa, 0xd0, 0xcd, 0xc4, 0xc5, 0xc4, 0xcd, 0x41, 0x41, 0x68, 0x9e, 0x8f, +0xa6, 0x9b, 0x97, 0x7c, 0x6c, 0x5f, 0x5f, 0x5e, 0x5e, 0x64, 0x63, 0x60, 0x6e, 0x69, 0x70, 0x6d, 0x75, 0x76, 0x77, 0x77, +0x89, 0x7e, 0x7e, 0x7e, 0x7e, 0x89, 0x89, 0x89, 0x77, 0x89, 0x8e, 0x8b, 0x86, 0x85, 0x7d, 0x7b, 0x80, 0x73, 0x6f, 0x6f, +0x6a, 0x66, 0x72, 0x7c, 0x81, 0xa6, 0xa0, 0xa2, 0xa7, 0x67, 0x37, 0xe2, 0xcf, 0xc7, 0xb8, 0xb8, 0xc6, 0xcf, 0xd8, 0x4c, +0x4d, 0x4c, 0x3d, 0x3d, 0x4b, 0x4a, 0x4a, 0x36, 0x49, 0x48, 0x49, 0x35, 0x35, 0x35, 0x47, 0x46, 0x46, 0x34, 0x1a, 0xe9, +0xe9, 0xe9, 0xe8, 0xee, 0x3c, 0x3b, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x2, 0xe8, 0xe8, 0xe9, 0xe9, 0xa, 0x47, 0x35, +0x47, 0x49, 0x49, 0x36, 0x4b, 0x4b, 0x3d, 0x4d, 0x3e, 0x4e, 0x50, 0x50, 0x51, 0x53, 0x53, 0x52, 0x3f, 0xe3, 0xd5, 0xba, +0xc5, 0xc5, 0xc5, 0xd5, 0x41, 0x41, 0x68, 0xa7, 0xa4, 0xa0, 0xa6, 0x95, 0x81, 0x71, 0x71, 0x65, 0x5f, 0x5e, 0x64, 0x64, +0x63, 0x60, 0x69, 0x69, 0x70, 0x70, 0x6d, 0x75, 0x76, 0x77, 0x77, 0x76, 0x76, 0x75, 0x75, 0x75, 0x8b, 0x75, 0x86, 0x85, +0x7d, 0x7b, 0x6e, 0x73, 0x64, 0x6a, 0x72, 0x65, 0x6c, 0x6c, 0x7c, 0x84, 0x9b, 0xa6, 0xa0, 0x9a, 0xa1, 0x5b, 0x3f, 0xda, +0xc7, 0xb6, 0xb9, 0xc6, 0xc9, 0xdb, 0x3e, 0x4c, 0x4c, 0x4b, 0x4b, 0x4b, 0x4a, 0x4a, 0x36, 0x36, 0x49, 0x48, 0x48, 0x35, +0x47, 0x47, 0x47, 0x47, 0x34, 0x34, 0xf9, 0xe9, 0xe8, 0xe8, 0xee, 0x3, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, +0xc, 0xe8, 0xef, 0xe9, 0xf2, 0xf3, 0x18, 0x48, 0x49, 0x49, 0x36, 0x4b, 0x4b, 0x4b, 0x4c, 0x4e, 0x3e, 0x4e, 0x50, 0x4f, +0x4f, 0x51, 0x51, 0x52, 0x53, 0x52, 0xde, 0xd5, 0xbc, 0xc4, 0xc4, 0xc4, 0xd7, 0x40, 0x40, 0x67, 0xa7, 0xaa, 0xa0, 0xa0, +0xa5, 0x8f, 0x8f, 0x61, 0x61, 0x5d, 0x5f, 0x5e, 0x64, 0x63, 0x60, 0x6e, 0x60, 0x69, 0x69, 0x69, 0x6d, 0x75, 0x6d, 0x6d, +0x70, 0x69, 0x70, 0x7f, 0x69, 0x7d, 0x69, 0x69, 0x6e, 0x74, 0x6f, 0x6a, 0x66, 0x5d, 0x61, 0x6b, 0x6b, 0x8f, 0x98, 0xa6, +0xa5, 0xa0, 0x9e, 0x68, 0x41, 0xe3, 0xde, 0xbb, 0xc3, 0xba, 0xb9, 0xbe, 0xd2, 0x3e, 0x4b, 0x4b, 0x4b, 0x4a, 0x4b, 0x36, +0x49, 0x36, 0x49, 0x49, 0x48, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x46, 0x34, 0x1a, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0x12, +0x3b, 0x3a, 0x3a, 0x23, 0x33, 0x3a, 0x24, 0x3b, 0x24, 0xf1, 0xef, 0xea, 0xf2, 0xf2, 0xd, 0x48, 0x49, 0x4a, 0x36, 0x25, +0x4b, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x59, 0x4f, 0x51, 0x4f, 0x51, 0x53, 0x51, 0x53, 0xd4, 0xd0, 0xbb, 0xba, 0xc3, +0xc3, 0xd0, 0xfa, 0xfa, 0x40, 0xab, 0xa9, 0xa2, 0xa2, 0xa0, 0x8f, 0x8f, 0x71, 0x71, 0x5f, 0x66, 0x5e, 0x64, 0x63, 0x64, +0x64, 0x63, 0x60, 0x69, 0x70, 0x70, 0x69, 0x6e, 0x60, 0x60, 0x60, 0x60, 0x60, 0x63, 0x63, 0x63, 0x63, 0x5e, 0x66, 0x5f, +0x65, 0x71, 0x6b, 0x9d, 0x8d, 0xa4, 0xa2, 0xa2, 0x9a, 0xa7, 0x41, 0x41, 0x41, 0xd7, 0xbc, 0xc4, 0xc3, 0xba, 0xcb, 0xd4, +0xe2, 0x4e, 0x4d, 0x3d, 0x4a, 0x4a, 0x36, 0x49, 0x49, 0x48, 0x49, 0x48, 0x48, 0x47, 0x47, 0x47, 0x47, 0x46, 0x46, 0x46, +0x34, 0x2, 0xe9, 0xe8, 0xe8, 0xe8, 0x3, 0x3b, 0x3a, 0x3a, 0x33, 0x33, 0x3a, 0x3a, 0x3b, 0x3c, 0x24, 0x17, 0xe9, 0xe9, +0xf2, 0xf3, 0xf3, 0x14, 0x48, 0x49, 0x36, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4e, 0x50, 0x50, 0x4e, 0x50, 0x50, +0x50, 0x50, 0x50, 0x50, 0xd9, 0xd4, 0xc7, 0xb8, 0xb8, 0xb9, 0xd0, 0xdf, 0xe2, 0xe2, 0x5b, 0xa1, 0xa3, 0xa4, 0xa0, 0xa5, +0x98, 0x97, 0x84, 0x66, 0x6a, 0x66, 0x66, 0x5f, 0x66, 0x5e, 0x64, 0x60, 0x6e, 0x60, 0x60, 0x63, 0x64, 0x64, 0x5e, 0x5e, +0x5e, 0x5e, 0x66, 0x5e, 0x5e, 0x66, 0x6c, 0x65, 0x81, 0x81, 0x8f, 0xa0, 0xa2, 0xaa, 0xa3, 0xab, 0x9f, 0x37, 0x3f, 0xfa, +0xd0, 0xc3, 0xc4, 0xc4, 0xc4, 0xcc, 0xd4, 0xdf, 0x4f, 0x4f, 0x50, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x49, 0x35, 0x47, +0x35, 0x47, 0x46, 0x46, 0x46, 0x34, 0x34, 0x34, 0x11, 0xe8, 0xe8, 0xe8, 0xee, 0xee, 0x12, 0x3b, 0x3b, 0x3a, 0x33, 0x33, +0x3a, 0x3a, 0x3b, 0x3c, 0x45, 0x3c, 0xf9, 0xe9, 0xf2, 0xf2, 0xf3, 0x4, 0x48, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4b, 0x4c, +0x57, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x3d, 0x4c, 0x4d, 0x4c, 0x4d, 0x3e, 0x4e, 0xd8, 0xcf, 0xca, 0xc2, 0xc2, 0xb6, 0xc7, +0xd3, 0xfb, 0x37, 0x53, 0x67, 0xa1, 0xaa, 0xa0, 0xa5, 0x9b, 0x9c, 0x82, 0x84, 0x7c, 0x71, 0x71, 0x6c, 0x66, 0x6a, 0x63, +0x63, 0x64, 0x6a, 0x5e, 0x5f, 0x65, 0x5d, 0x5f, 0x6c, 0x65, 0x65, 0x6c, 0x72, 0x72, 0x84, 0x95, 0x98, 0x98, 0xa0, 0xa4, +0xaa, 0xa9, 0x9f, 0xfb, 0x3e, 0xe1, 0xdb, 0xca, 0xb8, 0xba, 0xc3, 0xbb, 0xcb, 0xde, 0xfa, 0x53, 0x53, 0x51, 0x4f, 0x50, +0x4e, 0x4d, 0x4c, 0x3d, 0x4b, 0x4a, 0x48, 0x35, 0x47, 0x47, 0x47, 0x47, 0x34, 0x34, 0x3c, 0x16, 0xe9, 0xe8, 0xe8, 0xec, +0xee, 0xb, 0x3a, 0x3a, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x1a, 0xe9, 0xf2, 0xf2, 0xf2, 0xf3, +0x5, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4a, 0x4b, 0x4b, 0x3d, 0x4c, 0x3d, 0x4c, +0x4c, 0x4c, 0xe1, 0xd2, 0xc9, 0xc0, 0xc2, 0xb6, 0xc7, 0xcb, 0xda, 0x3f, 0xfa, 0x67, 0x41, 0xa7, 0x90, 0x98, 0x9b, 0x9b, +0xa6, 0xa6, 0x98, 0x98, 0x97, 0x82, 0x83, 0x87, 0x87, 0x83, 0x66, 0x72, 0x71, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, +0x95, 0x9c, 0x9c, 0xa6, 0xa5, 0xa2, 0x9a, 0xa7, 0xab, 0xfa, 0x37, 0xfb, 0xdb, 0xbe, 0xc0, 0xc0, 0xb6, 0xb7, 0xca, 0xcf, +0xd9, 0x4f, 0x51, 0x53, 0x37, 0x37, 0x51, 0x4f, 0x4e, 0x4e, 0x4d, 0x4c, 0x4b, 0x36, 0x4a, 0x36, 0x49, 0x35, 0x47, 0x46, +0x46, 0x34, 0x34, 0xe9, 0xe8, 0xe8, 0xe8, 0xee, 0xf0, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x33, 0x23, 0x3a, 0x3b, 0x3b, 0x3c, +0x3c, 0x34, 0x3c, 0x18, 0xf2, 0xf2, 0xf3, 0xf3, 0xf4, 0x5, 0x48, 0x35, 0x48, 0x48, 0x48, 0x47, 0x48, 0x49, 0x48, 0x49, +0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4a, 0x4a, 0x4b, 0x3d, 0x4b, 0x3d, 0xd6, 0xd2, 0xbe, 0xc7, 0xb8, 0xb8, 0xba, 0xbb, +0xd0, 0x40, 0xe3, 0x41, 0x68, 0x68, 0x9e, 0x9e, 0x9a, 0xa2, 0xa4, 0xa0, 0x9b, 0x9c, 0x96, 0x87, 0x83, 0x96, 0x9c, 0x9b, +0x98, 0xa0, 0xa0, 0xa5, 0xa6, 0xa5, 0xa0, 0xa0, 0xa0, 0xa0, 0x9d, 0x90, 0xa7, 0x68, 0x40, 0x3f, 0xfa, 0x5c, 0xd4, 0xcb, +0xc7, 0xb6, 0xb7, 0xc0, 0xc9, 0xce, 0xd6, 0xe4, 0x4d, 0x4e, 0x50, 0x4e, 0x50, 0x4f, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4d, +0x4c, 0x4b, 0x4b, 0x36, 0x48, 0x48, 0x35, 0x48, 0x46, 0x1a, 0xe9, 0xe8, 0xe9, 0xe8, 0xee, 0xed, 0x24, 0x3a, 0x3a, 0x3a, +0x3a, 0x23, 0x33, 0x3a, 0x3b, 0x3b, 0x3b, 0x34, 0x3c, 0x34, 0x34, 0x46, 0x11, 0xf2, 0xef, 0xea, 0xf2, 0xf2, 0x5, 0x46, +0x46, 0x47, 0x47, 0x35, 0x48, 0x47, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x36, 0x36, 0x36, 0x36, 0x36, 0x4a, 0x4a, 0x4b, +0x4b, 0x3e, 0xdb, 0xcf, 0xca, 0xb9, 0xba, 0xc3, 0xc3, 0xbc, 0xcd, 0xd5, 0x41, 0x41, 0xe3, 0xfa, 0x3f, 0x67, 0xa1, 0xa7, +0x90, 0x8f, 0x97, 0x96, 0x9c, 0xa6, 0xa5, 0xa0, 0xa2, 0xa8, 0xaa, 0xaa, 0xaa, 0x9a, 0xa7, 0xa7, 0xa1, 0xa1, 0x41, 0x41, +0x41, 0xe3, 0x40, 0xda, 0xd0, 0xbb, 0xba, 0xb8, 0xb8, 0xc2, 0xca, 0xce, 0xd6, 0xdc, 0x36, 0x36, 0x36, 0x4b, 0x4c, 0x4c, +0x3e, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x3e, 0x4d, 0x4c, 0x3d, 0x4b, 0x4a, 0x36, 0x48, 0x35, 0x47, 0x1b, 0xf2, 0xea, 0xef, +0xe9, 0xe8, 0xe8, 0x12, 0x3a, 0x3a, 0x3a, 0x33, 0x3a, 0x33, 0x33, 0x3a, 0x3a, 0x3c, 0x45, 0x3c, 0x34, 0x34, 0x34, 0x34, +0x3c, 0xc, 0xe8, 0xe8, 0xe8, 0xe9, 0xea, 0xe9, 0x1a, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x35, 0x48, 0x35, 0x49, 0x48, +0x48, 0x48, 0x49, 0x48, 0x49, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c, 0x3e, 0x50, 0xdf, 0xd4, 0xcb, 0xba, 0xc4, 0xc5, 0xc5, 0xc5, +0xc5, 0xcd, 0xd0, 0xd9, 0x37, 0x3f, 0x40, 0x67, 0x68, 0xfd, 0xfd, 0x62, 0xfd, 0x68, 0x68, 0x41, 0x67, 0x5b, 0x5b, 0x5b, +0x40, 0x3f, 0x3f, 0x3f, 0x3f, 0xfa, 0x40, 0xde, 0xd5, 0xcd, 0xbc, 0xc3, 0xb8, 0xb8, 0xb8, 0xc7, 0xca, 0xcf, 0xdb, 0xe1, +0x3d, 0x4a, 0x49, 0x36, 0x48, 0x48, 0x49, 0x4a, 0x4a, 0x3d, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4b, 0x3d, 0x4b, 0x4b, 0x4a, +0x36, 0x48, 0x48, 0x13, 0xf3, 0xea, 0xea, 0xf2, 0xe9, 0xe9, 0x17, 0x45, 0x3b, 0x3b, 0x3a, 0x3a, 0x33, 0x33, 0x33, 0x3a, +0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x24, 0x16, 0xe8, 0xe8, 0xe9, 0xe8, 0xe8, 0xe9, 0x17, 0x46, 0x46, +0x34, 0x46, 0x47, 0x47, 0x35, 0x47, 0x47, 0x47, 0x35, 0x48, 0x35, 0x49, 0x48, 0x49, 0x4b, 0x4b, 0x3d, 0x4c, 0x4d, 0x50, +0x50, 0x51, 0xfa, 0xde, 0xd5, 0xcd, 0xbc, 0xc4, 0xc3, 0xba, 0xb9, 0xb8, 0xb9, 0xbb, 0xcd, 0xcd, 0xd1, 0xfd, 0xfd, 0xfd, +0x68, 0x41, 0xe3, 0x40, 0x3f, 0xfb, 0xe2, 0xe2, 0xdf, 0xda, 0xda, 0xd4, 0xca, 0xbb, 0xba, 0xc3, 0xc4, 0xc5, 0xc4, 0xc4, +0xba, 0xca, 0xcf, 0xd3, 0xd8, 0x50, 0x4e, 0x4d, 0x4c, 0x4b, 0x36, 0x49, 0x35, 0x48, 0x47, 0x35, 0x49, 0x48, 0x36, 0x4a, +0x4a, 0x25, 0x4a, 0x36, 0x25, 0x4b, 0x4a, 0x4a, 0x36, 0x48, 0x15, 0xf3, 0xf2, 0xf2, 0xea, 0xe9, 0xe9, 0x18, 0x3c, 0x34, +0x3c, 0x3c, 0x45, 0x3b, 0x3a, 0x33, 0x22, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x3a, 0x3a, 0x3a, 0x3b, 0x3a, 0x16, +0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xa, 0x34, 0x34, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x35, 0x48, 0x48, +0x49, 0x36, 0x4a, 0x4b, 0x4c, 0x4d, 0x3e, 0x50, 0x50, 0x51, 0x51, 0x52, 0xfa, 0xe3, 0xde, 0xd4, 0xd0, 0xca, 0xc6, 0xb6, +0xb8, 0xba, 0xc3, 0xc5, 0xc8, 0xbd, 0xbd, 0xc8, 0xc5, 0xbc, 0xc3, 0xba, 0xb9, 0xb7, 0xb7, 0xc7, 0xba, 0xba, 0xba, 0xb8, +0xb8, 0xb8, 0xb8, 0xc3, 0xba, 0xbb, 0xcd, 0xd5, 0xde, 0xdf, 0x4e, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4c, 0x4b, 0x49, +0x48, 0x35, 0x35, 0x47, 0x47, 0x47, 0x35, 0x47, 0x48, 0x49, 0x48, 0x49, 0x49, 0x49, 0x49, 0x36, 0x48, 0x5, 0xf3, 0xf3, +0xf2, 0xea, 0xe9, 0xe8, 0x16, 0x3c, 0x3c, 0x3c, 0x24, 0x45, 0x3c, 0x3b, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, +0x33, 0x44, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x16, 0x1, 0xe8, 0xe9, 0xe8, 0xe8, 0xe8, 0xe9, 0x17, 0x34, 0x34, 0x34, +0x34, 0x46, 0x34, 0x47, 0x35, 0x47, 0x48, 0x49, 0x49, 0x36, 0x4b, 0x4b, 0x4c, 0x4c, 0x4e, 0x50, 0x50, 0x4f, 0x53, 0x52, +0x52, 0x53, 0x4f, 0x4e, 0x3e, 0xe1, 0xd8, 0xd3, 0xcf, 0xca, 0xcd, 0xbc, 0xc5, 0xbd, 0xc8, 0xc8, 0xc4, 0xc3, 0xc3, 0xba, +0xb8, 0xb6, 0xb6, 0xb6, 0xb6, 0xc7, 0xc7, 0xc6, 0xca, 0xbe, 0xcf, 0xcf, 0xda, 0xfa, 0x3f, 0x3f, 0x52, 0x51, 0x4f, 0x4e, +0x3d, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4b, 0x4a, 0x49, 0x35, 0x47, 0x47, 0x46, 0x46, 0x46, 0x47, 0x34, 0x47, 0x47, 0x35, +0x35, 0x35, 0x35, 0x14, 0xf3, 0x0, 0xf3, 0xf2, 0xf2, 0xea, 0x1, 0x16, 0x45, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x24, +0x33, 0x22, 0x22, 0x31, 0x22, 0x22, 0x22, 0x32, 0x33, 0x32, 0x33, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x24, 0x3, 0xee, +0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0x2, 0x16, 0x34, 0x3c, 0x34, 0x46, 0x46, 0x46, 0x35, 0x47, 0x48, 0x49, 0x49, 0x4a, 0x4b, +0x3d, 0x4d, 0x4d, 0x4e, 0x4f, 0x51, 0x51, 0x53, 0x51, 0x50, 0x4e, 0x3d, 0x3d, 0x3d, 0x3d, 0x4d, 0x50, 0x37, 0x40, 0x41, +0x68, 0xd5, 0xd5, 0xd5, 0xd4, 0xd0, 0xd4, 0xcf, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xdb, 0xdb, 0xd8, 0xe1, 0x3e, 0x3e, 0x4e, +0x50, 0x4f, 0x4f, 0x51, 0x53, 0x53, 0x4f, 0x4e, 0x4c, 0x4b, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4a, 0x49, 0x49, 0x35, 0x46, +0x46, 0x46, 0x34, 0x34, 0x3c, 0x34, 0x34, 0x46, 0x46, 0x18, 0xf2, 0xf2, 0xf2, 0xea, 0xf2, 0xf2, 0xf2, 0xa, 0x34, 0x3c, +0x24, 0x3b, 0x3a, 0x33, 0x3b, 0x33, 0x3b, 0x3a, 0x22, 0x22, 0x22, 0x30, 0x22, 0x31, 0x22, 0x22, 0x33, 0x33, 0x33, 0x44, +0x33, 0x3a, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, 0x12, 0xee, 0xec, 0xe8, 0xee, 0xe8, 0xe8, 0xe8, 0x2, 0x1a, 0x46, 0x34, 0x47, +0x47, 0x35, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4b, 0x4b, 0x3d, 0x4d, 0x4e, 0x50, 0x4f, 0x4f, 0x50, 0x4e, 0x4c, 0x4a, 0x4b, +0x4a, 0x4b, 0x3d, 0x4c, 0x4e, 0x51, 0x52, 0x40, 0x67, 0x41, 0x67, 0x3f, 0x4f, 0x50, 0x50, 0x4e, 0x4d, 0x3d, 0x4a, 0x4a, +0x3d, 0x4c, 0x3e, 0x4d, 0x4c, 0x3d, 0x3d, 0x4c, 0x3e, 0x50, 0x50, 0x50, 0x51, 0x4f, 0x50, 0x50, 0x4d, 0x4b, 0x49, 0x36, +0x48, 0x4a, 0x49, 0x4a, 0x49, 0x49, 0x48, 0x35, 0x46, 0x46, 0x34, 0x34, 0x3c, 0x3c, 0x3c, 0x1a, 0xe5, 0xe9, 0xe9, 0xe9, +0xe9, 0xe9, 0xe9, 0xf1, 0x17, 0x3c, 0x3c, 0x24, 0x3b, 0x3b, 0x3a, 0x3a, 0x33, 0x23, 0x33, 0x32, 0x22, 0x22, 0x31, 0x31, +0x31, 0x22, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x44, 0x3a, 0x3a, 0x3a, 0x38, 0x3, 0xee, 0xec, +0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0x1, 0x17, 0x46, 0x46, 0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x4a, 0x4a, 0x4c, 0x4d, 0x4e, +0x50, 0x4e, 0x58, 0x4d, 0x4c, 0x49, 0x4a, 0x36, 0x4b, 0x4a, 0x4b, 0x4d, 0x50, 0x4f, 0x53, 0x5b, 0x40, 0x40, 0x40, 0x53, +0x50, 0x50, 0x4e, 0x4d, 0x3d, 0x4a, 0x4a, 0x4a, 0x3d, 0x3d, 0x3d, 0x4c, 0x3d, 0x4a, 0x4b, 0x4b, 0x4b, 0x4d, 0x4e, 0x4e, +0x50, 0x50, 0x50, 0x4e, 0x4d, 0x4c, 0x36, 0x49, 0x49, 0x48, 0x48, 0x48, 0x48, 0x49, 0x48, 0x48, 0x46, 0x47, 0x34, 0x34, +0x3c, 0x17, 0xe5, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0x3, 0x3c, 0x3b, 0x45, 0x24, 0x3b, 0x3b, 0x3a, 0x33, 0x3a, +0x33, 0x32, 0x22, 0x22, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x22, 0x31, 0x22, 0x32, 0x32, 0x22, 0x33, 0x32, 0x33, 0x33, +0x33, 0x33, 0x33, 0x3a, 0x3a, 0x3b, 0x12, 0x2, 0xee, 0xe8, 0xec, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe, 0x35, 0x35, 0x47, +0x48, 0x48, 0x49, 0x36, 0x4b, 0x4c, 0x4d, 0x4d, 0x4d, 0x4c, 0x4d, 0x4b, 0x49, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4c, +0x4e, 0x4f, 0x53, 0x52, 0x3f, 0x5b, 0x53, 0x4e, 0x4d, 0x4d, 0x4d, 0x4d, 0x4b, 0x36, 0x49, 0x49, 0x4a, 0x4a, 0x3d, 0x3d, +0x3d, 0x4b, 0x4a, 0x4a, 0x4a, 0x4b, 0x4d, 0x4d, 0x4d, 0x4e, 0x4d, 0x4e, 0x4d, 0x4c, 0x4b, 0x49, 0x35, 0x47, 0x35, 0x47, +0x48, 0x35, 0x48, 0x47, 0x46, 0x46, 0x1a, 0xa, 0xe9, 0xe8, 0xe8, 0xe8, 0xee, 0xee, 0xec, 0xee, 0xf0, 0x24, 0x3a, 0x3a, +0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x22, 0x32, 0x31, 0x22, 0x31, 0x31, 0x30, 0x21, 0x31, 0x31, 0x31, +0x22, 0x31, 0x22, 0x32, 0x22, 0x32, 0x33, 0x32, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x3a, 0x3b, 0x3b, 0x12, 0x1, 0xe8, 0xec, +0xe9, 0xe8, 0xe9, 0xf2, 0xf2, 0xea, 0x5, 0x14, 0x48, 0x35, 0x49, 0x36, 0x4a, 0x4b, 0x4c, 0x4c, 0x4b, 0x4b, 0x49, 0x48, +0x35, 0x48, 0x48, 0x49, 0x49, 0x36, 0x4a, 0x4c, 0x4e, 0x50, 0x4f, 0x53, 0x52, 0x53, 0x4f, 0x4d, 0x3d, 0x4c, 0x4c, 0x4b, +0x4a, 0x49, 0x35, 0x48, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x36, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, +0x4c, 0x4b, 0x4b, 0x4a, 0x48, 0x47, 0x47, 0x46, 0x46, 0x46, 0x47, 0x1a, 0x14, 0xe9, 0xf2, 0xe9, 0xe9, 0xe8, 0xee, 0xee, +0xec, 0xee, 0xf0, 0x12, 0x3a, 0x3a, 0x23, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x22, 0x22, +0x31, 0x31, 0x30, 0x21, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x22, 0x22, 0x22, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x12, 0x1, 0xec, 0xe9, 0xe9, 0xe9, 0xef, 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0x10, 0x25, +0x25, 0x4a, 0x4b, 0x4a, 0x49, 0x49, 0x47, 0x35, 0x47, 0x48, 0x48, 0x47, 0x48, 0x49, 0x4a, 0x4c, 0x58, 0x4e, 0x4f, 0x4f, +0x51, 0x4f, 0x4e, 0x4b, 0x4a, 0x4b, 0x4b, 0x4a, 0x49, 0x48, 0x35, 0x35, 0x48, 0x49, 0x49, 0x4a, 0x49, 0x49, 0x49, 0x48, +0x49, 0x49, 0x49, 0x4a, 0x4a, 0x25, 0x4b, 0x3d, 0x4b, 0x4a, 0x25, 0x4a, 0x49, 0x48, 0x46, 0x46, 0x18, 0xf9, 0xe9, 0xe9, +0xe9, 0xf2, 0xea, 0xe9, 0xe8, 0xe8, 0xe8, 0xee, 0xf0, 0x12, 0x3a, 0x33, 0x33, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x23, 0x33, 0x33, 0x33, 0x22, 0x32, 0x22, 0x31, 0x30, 0x31, 0x30, 0x21, 0x21, 0x31, 0x21, 0x30, 0x30, 0x31, 0x31, 0x31, +0x31, 0x22, 0x22, 0x22, 0x22, 0x32, 0x33, 0x33, 0x3a, 0x3a, 0x33, 0x3a, 0x3b, 0x3a, 0x3b, 0x3b, 0x12, 0x2, 0xe8, 0xe9, +0xe9, 0xe9, 0xe9, 0xea, 0xf3, 0xf3, 0xf4, 0xf4, 0xf5, 0x4, 0x10, 0x15, 0x1b, 0x35, 0x47, 0x46, 0x46, 0x47, 0x46, 0x47, +0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x58, 0x4e, 0x50, 0x4f, 0x4e, 0x4c, 0x4a, 0x4a, 0x4a, 0x4a, 0x49, 0x48, 0x35, 0x35, 0x35, +0x35, 0x35, 0x48, 0x48, 0x48, 0x49, 0x48, 0x47, 0x35, 0x47, 0x35, 0x48, 0x36, 0x4a, 0x4a, 0x4a, 0x4a, 0x25, 0x36, 0x25, +0x15, 0x10, 0xf3, 0xf2, 0xe9, 0xe9, 0xe9, 0xe8, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xec, 0xe7, 0x12, 0x3a, 0x3a, 0x3a, 0x3a, +0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x33, 0x32, 0x33, 0x32, 0x22, 0x32, 0x32, 0x22, 0x31, 0x31, 0x31, 0x21, 0x21, 0x21, +0x21, 0x21, 0x31, 0x21, 0x30, 0x30, 0x31, 0x31, 0x31, 0x22, 0x31, 0x32, 0x22, 0x33, 0x32, 0x33, 0x33, 0x32, 0x33, 0x44, +0x3a, 0x3a, 0x3b, 0x3b, 0x24, 0x3c, 0x3c, 0xc, 0xee, 0xe9, 0xef, 0xea, 0xf2, 0xf3, 0xf3, 0xf4, 0x0, 0xf3, 0xeb, 0xf3, +0xea, 0xea, 0xe9, 0xd, 0xe, 0x11, 0x18, 0x1b, 0x48, 0x49, 0x4a, 0x4b, 0x4b, 0x4c, 0x4d, 0x4e, 0x4e, 0x4d, 0x4b, 0x49, +0x49, 0x56, 0x49, 0x48, 0x35, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x35, 0x47, 0x47, 0x47, 0x47, 0x35, +0x1b, 0x15, 0x15, 0xd, 0x8, 0xf4, 0xf5, 0xf5, 0xf4, 0xf2, 0xf3, 0xf3, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xec, 0x1, +0xb, 0x24, 0x24, 0x3b, 0x3a, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x32, 0x33, 0x32, 0x32, 0x22, 0x22, 0x31, 0x22, 0x22, 0x22, +0x22, 0x31, 0x31, 0x30, 0x21, 0x30, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x30, 0x31, 0x30, 0x31, 0x30, 0x22, 0x22, 0x22, +0x31, 0x22, 0x22, 0x22, 0x32, 0x33, 0x33, 0x44, 0x3a, 0x44, 0x3b, 0x3a, 0x45, 0x3c, 0x3b, 0x3b, 0x24, 0x16, 0xf9, 0xe9, +0xe9, 0xf3, 0xf3, 0xf2, 0xf3, 0xf2, 0xf2, 0xef, 0xe9, 0xe8, 0xe9, 0xe9, 0xef, 0xef, 0xea, 0xf2, 0xf3, 0x4, 0x4, 0x4, +0x7, 0xf, 0xf, 0xf, 0xf, 0x1c, 0x10, 0x14, 0x14, 0x15, 0x15, 0x14, 0x13, 0x11, 0x11, 0x11, 0xe, 0xe, 0xe, 0xd, +0xd, 0xd, 0xd, 0x5, 0xe9, 0xea, 0xe9, 0xf2, 0xf2, 0xf3, 0xf4, 0xf4, 0xf4, 0xeb, 0xf3, 0xeb, 0xf3, 0xf3, 0xea, 0xf2, +0xf2, 0xe9, 0xe8, 0xe8, 0xed, 0x3, 0x24, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, 0x32, 0x32, 0x22, +0x32, 0x22, 0x22, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x21, 0x30, 0x31, 0x31, 0x21, 0x21, 0x20, 0x20, 0x2f, 0x30, 0x21, +0x21, 0x21, 0x30, 0x30, 0x31, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x33, 0x22, 0x33, 0x33, 0x33, 0x3a, 0x3a, +0x3b, 0x3a, 0x3b, 0x3a, 0x45, 0x3b, 0x24, 0x34, 0x17, 0xe, 0xf2, 0xf2, 0xf2, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, +0xe9, 0xe9, 0xef, 0xe9, 0xf2, 0xf4, 0x4, 0xf5, 0xf5, 0xf6, 0xf6, 0xf8, 0x6, 0xf5, 0xf4, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, +0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xe9, 0xea, 0xf3, 0xf2, 0xf2, 0xe9, 0xea, 0xea, 0xe9, 0xe9, 0xea, 0xf2, 0xf2, 0xf3, +0xf3, 0xf3, 0xf3, 0xea, 0xea, 0xea, 0xea, 0xef, 0xef, 0xf1, 0xc, 0x12, 0x3b, 0x3a, 0x3a, 0x3a, 0x3b, 0x3a, 0x44, 0x3b, +0x44, 0x33, 0x33, 0x32, 0x33, 0x32, 0x22, 0x32, 0x31, 0x22, 0x22, 0x22, 0x30, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x21, +0x21, 0x2f, 0x20, 0x20, 0x21, 0x21, 0x20, 0x21, 0x21, 0x30, 0x21, 0x31, 0x30, 0x21, 0x31, 0x31, 0x22, 0x31, 0x22, 0x22, +0x22, 0x32, 0x22, 0x32, 0x32, 0x33, 0x33, 0x3a, 0x3a, 0x3a, 0x33, 0x3a, 0x3a, 0x24, 0x3c, 0x45, 0x3c, 0x34, 0x46, 0x1a, +0x17, 0x3, 0xf0, 0xee, 0xec, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xf2, 0xf3, 0xf3, 0xf3, 0x0, 0xf4, 0xf5, 0xf5, 0xf6, +0xf5, 0xf4, 0xf2, 0xe9, 0xf2, 0xf3, 0xf2, 0xf2, 0xe9, 0xe9, 0xe9, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xe9, 0xe9, +0xe9, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xf2, 0xe9, 0xea, 0xea, 0xe9, 0xf1, 0xa, 0x17, 0x46, 0x34, 0x34, 0x3b, +0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x22, 0x22, 0x31, 0x31, 0x31, 0x31, +0x30, 0x31, 0x30, 0x21, 0x30, 0x21, 0x2f, 0x21, 0x21, 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x20, 0x20, 0x21, 0x21, 0x21, +0x21, 0x31, 0x30, 0x30, 0x31, 0x31, 0x22, 0x31, 0x22, 0x22, 0x22, 0x32, 0x22, 0x22, 0x32, 0x32, 0x3a, 0x3a, 0x33, 0x33, +0x3a, 0x3a, 0x3b, 0x3c, 0x45, 0x34, 0x3c, 0x34, 0x3b, 0x3a, 0x3b, 0x24, 0x12, 0xc, 0xf0, 0xee, 0xec, 0xe8, 0xe8, 0xe9, +0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0x0, 0xf4, 0xf4, 0xf4, 0xf4, 0xe9, 0xe9, 0xe9, 0xea, 0xe9, 0xe9, 0xe9, 0xe8, 0xe9, 0xe8, +0xe9, 0xe8, 0xe9, 0xe8, 0xe9, 0xe9, 0xe8, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xf1, 0x2, 0xa, 0x17, +0x34, 0x3c, 0x45, 0x24, 0x3c, 0x3c, 0x3c, 0x24, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x22, 0x32, 0x22, +0x31, 0x22, 0x22, 0x22, 0x22, 0x31, 0x31, 0x31, 0x30, 0x21, 0x30, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x21, 0x21, 0x30, 0x21, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, +0x22, 0x31, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x3a, 0x3b, 0x3c, 0x45, 0x3c, 0x45, 0x3a, 0x33, 0x33, 0x3a, 0x3a, +0x3b, 0x3a, 0x3a, 0x3a, 0x3c, 0x12, 0xb, 0xc, 0x2, 0xf1, 0xe9, 0xe9, 0xf3, 0xf3, 0xf4, 0xf3, 0xf3, 0xf2, 0xe9, 0xe9, +0xe8, 0xe9, 0xe9, 0xe8, 0xe8, 0xee, 0xe8, 0xee, 0xec, 0xee, 0xe8, 0xe9, 0xe8, 0xe8, 0xe9, 0xe9, 0xee, 0x1, 0xf0, 0x3, +0xf7, 0x12, 0x16, 0x34, 0x3c, 0x3c, 0x45, 0x3b, 0x3c, 0x3b, 0x24, 0x3a, 0x3b, 0x3c, 0x24, 0x45, 0x3b, 0x3a, 0x33, 0x32, +0x33, 0x33, 0x22, 0x22, 0x22, 0x32, 0x32, 0x22, 0x22, 0x22, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x21, 0x21, 0x21, 0x21, +0x21, 0x20, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, 0x2f, 0x21, 0x21, 0x21, +0x21, 0x30, 0x30, 0x31, 0x31, 0x31, 0x22, 0x31, 0x31, 0x22, 0x31, 0x22, 0x31, 0x22, 0x22, 0x33, 0x3a, 0x3a, 0x45, 0x3b, +0x24, 0x3b, 0x3a, 0x33, 0x3a, 0x33, 0x3a, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x34, 0x34, 0x3c, 0x46, +0x1a, 0x18, 0x13, 0x11, 0x13, 0xa, 0xc, 0x3, 0x3, 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0xb, 0xc, 0xb, 0xf7, 0x12, +0x16, 0x16, 0x12, 0x24, 0x24, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3b, 0x45, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x3b, 0x3a, +0x3a, 0x3a, 0x3b, 0x3b, 0x33, 0x33, 0x32, 0x22, 0x22, 0x22, 0x32, 0x22, 0x22, 0x22, 0x31, 0x22, 0x31, 0x43, 0x31, 0x31, +0x30, 0x30, 0x31, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x2f, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, +0x22, 0x22, 0x32, 0x33, 0x3a, 0x3a, 0x3b, 0x3a, 0x3a, 0x23, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3a, 0x3a, +0x3a, 0x3b, 0x3b, 0x45, 0x3c, 0x24, 0x3c, 0x34, 0x45, 0x34, 0x55, 0x46, 0x34, 0x45, 0x3b, 0x3b, 0x3b, 0x45, 0x3b, 0x3b, +0x3a, 0x3a, 0x33, 0x3a, 0x3a, 0x3b, 0x3a, 0x3a, 0x3b, 0x3b, 0x3a, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, 0x3a, 0x3a, +0x3a, 0x3b, 0x3b, 0x3b, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x23, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x32, 0x31, 0x22, 0x31, 0x31, +0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x21, 0x30, 0x31, 0x21, 0x21, 0x21, 0x21, 0x20, 0x2f, 0x2f, 0x21, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x30, 0x21, +0x21, 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x33, 0x33, 0x44, 0x33, 0x3a, 0x33, 0x22, 0x22, 0x33, +0x22, 0x33, 0x33, 0x33, 0x32, 0x33, 0x32, 0x33, 0x44, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x45, 0x45, 0x3c, 0x3c, +0x34, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, 0x3a, 0x3a, 0x3a, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, +0x3a, 0x44, 0x3a, 0x33, 0x33, 0x33, 0x3a, 0x33, 0x33, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, 0x23, 0x22, 0x32, 0x32, 0x22, 0x22, +0x31, 0x22, 0x22, 0x31, 0x22, 0x31, 0x22, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x21, 0x30, 0x30, 0x21, 0x30, 0x20, 0x2f, +0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x2e, 0x20, 0x1f, 0x20, 0x1f, 0x20, 0x1f, 0x20, 0x20, +0x20, 0x2f, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x21, 0x21, 0x30, 0x30, 0x31, 0x30, 0x21, 0x21, 0x30, 0x30, 0x31, 0x22, +0x33, 0x33, 0x33, 0x32, 0x31, 0x31, 0x22, 0x22, 0x32, 0x22, 0x32, 0x22, 0x32, 0x22, 0x33, 0x33, 0x33, 0x3a, 0x3a, 0x3b, +0x3b, 0x3a, 0x3a, 0x3a, 0x3b, 0x45, 0x3c, 0x3c, 0x3b, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x33, +0x33, 0x33, 0x3a, 0x33, 0x3a, 0x33, 0x3a, 0x3a, 0x3a, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x33, 0x33, 0x3a, +0x3a, 0x33, 0x33, 0x22, 0x31, 0x31, 0x31, 0x22, 0x22, 0x22, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x21, 0x30, 0x21, +0x21, 0x30, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x2e, 0x1f, 0x1f, 0x2e, +0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x20, 0x20, 0x1f, 0x1f, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x21, 0x2f, 0x21, 0x2f, 0x21, +0x21, 0x21, 0x21, 0x30, 0x31, 0x31, 0x21, 0x31, 0x32, 0x33, 0x31, 0x31, 0x30, 0x31, 0x22, 0x22, 0x31, 0x22, 0x22, 0x31, +0x22, 0x33, 0x33, 0x32, 0x32, 0x33, 0x33, 0x33, 0x3a, 0x33, 0x33, 0x33, 0x3a, 0x45, 0x3c, 0x3b, 0x3b, 0x33, 0x33, 0x33, +0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x22, +0x33, 0x33, 0x22, 0x22, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x22, 0x22, 0x22, 0x22, 0x30, 0x31, 0x31, 0x30, 0x31, 0x31, +0x31, 0x31, 0x30, 0x30, 0x30, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, +0x1f, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x21, 0x20, 0x2f, 0x20, 0x2f, 0x21, 0x30, 0x21, 0x30, 0x30, 0x21, 0x31, 0x30, 0x31, +0x31, 0x30, 0x31, 0x31, 0x31, 0x31, 0x22, 0x31, 0x22, 0x22, 0x22, 0x22, 0x32, 0x22, 0x32, 0x32, 0x32, 0x33, 0x22, 0x32, +0x3a, 0x3b, 0x3b, 0x3b, 0x3a, 0x22, 0x33, 0x32, 0x32, 0x33, 0x32, 0x32, 0x33, 0x22, 0x22, 0x32, 0x32, 0x32, 0x32, 0x22, +0x33, 0x33, 0x22, 0x22, 0x33, 0x32, 0x22, 0x32, 0x22, 0x22, 0x22, 0x31, 0x22, 0x22, 0x22, 0x31, 0x32, 0x22, 0x31, 0x31, +0x31, 0x31, 0x31, 0x31, 0x31, 0x21, 0x30, 0x31, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x2f, 0x21, 0x21, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x1f, +0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x21, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x21, 0x30, 0x30, 0x31, 0x21, 0x30, 0x31, 0x31, 0x30, 0x31, 0x31, 0x31, 0x22, 0x22, +0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x3a, 0x3a, 0x44, 0x32, 0x32, 0x31, 0x22, 0x33, 0x33, 0x33, 0x32, +0x32, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x31, 0x31, 0x31, 0x22, 0x22, 0x22, 0x22, 0x31, 0x31, 0x31, +0x22, 0x31, 0x31, 0x31, 0x22, 0x31, 0x31, 0x31, 0x31, 0x30, 0x31, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x30, 0x21, 0x21, +0x20, 0x2f, 0x21, 0x20, 0x2f, 0x2f, 0x20, 0x2f, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x2e, +0x1f, 0x2e, 0x2e, 0x2d, 0x1e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x2e, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, +0x20, 0x1f, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x2f, 0x20, 0x21, 0x21, 0x21, 0x30, 0x21, 0x21, 0x21, 0x30, 0x21, +0x21, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x31, 0x31, 0x31, 0x22, 0x33, 0x33, +0x22, 0x22, 0x22, 0x22, 0x22, 0x31, 0x31, 0x22, 0x31, 0x22, 0x22, 0x31, 0x22, 0x31, 0x22, 0x22, 0x22, 0x22, 0x22, 0x31, +0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x21, 0x21, 0x31, 0x30, 0x31, 0x21, 0x21, 0x21, +0x21, 0x30, 0x2f, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x20, +0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x1e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, +0x1f, 0x2e, 0x1f, 0x2e, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x21, +0x21, 0x21, 0x21, 0x20, 0x2f, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x30, 0x30, 0x21, 0x31, 0x31, 0x31, 0x30, 0x21, +0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x22, 0x31, 0x31, 0x31, 0x22, 0x31, 0x31, 0x31, 0x43, 0x22, 0x31, 0x31, 0x31, +0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 0x31, 0x31, 0x31, 0x21, 0x31, 0x21, 0x21, +0x21, 0x21, 0x21, 0x30, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21, 0x20, 0x21, 0x21, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x1f, 0x2e, 0x1f, 0x1f, 0x2e, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x1e, 0x1e, 0x1e, +0x1e, 0x1e, 0x1e, 0x2d, 0x2e, 0x1e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, +0x20, 0x1f, 0x1f, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x2f, 0x21, 0x2f, 0x21, 0x21, 0x21, +0x21, 0x21, 0x30, 0x21, 0x21, 0x21, 0x30, 0x31, 0x31, 0x21, 0x21, 0x30, 0x30, 0x21, 0x21, 0x30, 0x30, 0x31, 0x31, 0x31, +0x31, 0x30, 0x31, 0x31, 0x31, 0x30, 0x21, 0x21, 0x30, 0x21, 0x31, 0x31, 0x21, 0x30, 0x31, 0x30, 0x21, 0x21, 0x21, 0x30, +0x21, 0x30, 0x21, 0x30, 0x21, 0x21, 0x21, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x21, 0x21, 0x20, 0x20, 0x2f, +0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x2d, +0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, +0x2e, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, +0x20, 0x2f, 0x2f, 0x21, 0x21, 0x21, 0x20, 0x20, 0x21, 0x2f, 0x2f, 0x20, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x21, 0x21, 0x21, +0x30, 0x21, 0x21, 0x30, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x31, 0x30, 0x21, 0x21, 0x21, 0x30, 0x21, 0x21, 0x21, +0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x2f, 0x21, 0x2f, 0x21, 0x20, 0x20, 0x21, 0x21, +0x2f, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x20, 0x1f, 0x1f, 0x2e, 0x1f, 0x20, 0x2e, 0x1f, +0x1f, 0x1f, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x2c, 0x1e, 0x1e, +0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x2e, 0x2d, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, +0x1f, 0x2e, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +0x20, 0x20, 0x2f, 0x2f, 0x20, 0x20, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x21, 0x21, +0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x21, 0x2f, 0x2f, 0x20, 0x21, 0x21, 0x21, 0x2f, 0x20, 0x20, +0x20, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, +0x2e, 0x1f, 0x2e, 0x1f, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, 0x2d, 0x2d, 0x2e, 0x2d, 0x2e, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, +0x2d, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x2d, 0x2e, +0x2d, 0x2e, 0x2e, 0x2d, 0x2e, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x20, 0x20, +0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x2f, 0x21, 0x21, 0x21, 0x21, 0x2f, +0x21, 0x20, 0x20, 0x20, 0x21, 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x2f, +0x21, 0x21, 0x20, 0x2f, 0x2f, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x1f, +0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, +0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x1e, 0x1e, 0x2c, +0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x1e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, +0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x1f, 0x1f, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x1f, 0x20, +0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x2e, 0x1f, 0x2e, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, +0x2d, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, +0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2d, 0x2e, +0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x1f, 0x1f, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, +0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, +0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x1f, 0x20, 0x1f, +0x20, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, +0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x1e, 0x2e, 0x2d, 0x1e, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x2c, +0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1d, 0x1d, 0x2b, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x1e, 0x1e, 0x2c, +0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, 0x2d, 0x2d, 0x2e, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, +0x2e, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, +0x2e, 0x20, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x20, +0x1f, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x1f, 0x2e, +0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, +0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x1d, 0x2b, +0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, +0x1e, 0x2d, 0x1e, 0x1e, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, +0x1f, 0x1f, 0x2e, 0x2e, 0x1f, 0x2e, 0x1f, 0x1f, 0x2e, 0x20, 0x1f, 0x1f, 0x1f, 0x2e, 0x20, 0x1f, 0x1f, 0x2e, 0x1f, 0x1f, +0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x2e, 0x1f, 0x20, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, +0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2e, 0x2d, 0x1e, 0x2d, 0x2d, 0x1e, 0x2d, +0x2d, 0x2d, 0x1e, 0x2d, 0x1e, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, +0x1d, 0x2b, 0x2b, 0x1d, 0x2a, 0x1d, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, +0x2c, 0x1e, 0x2c, 0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x2d, 0x2d, 0x2e, 0x2d, 0x2e, 0x2d, 0x1e, 0x2d, 0x2d, +0x1e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, +0x2e, 0x1f, 0x2e, 0x1f, 0x2e, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x1f, 0x2e, 0x2e, +0x2e, 0x1f, 0x1f, 0x1f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2d, 0x1e, 0x2e, 0x1e, 0x2d, 0x2e, +0x2d, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, +0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, 0x2a, 0x2a, 0x2a, 0x2b, 0x1d, 0x2a, 0x2b, 0x2b, 0x1d, +0x1d, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x1e, 0x1e, 0x1e, +0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2d, 0x1e, 0x2e, 0x2d, 0x2e, 0x2e, +0x2d, 0x2d, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2d, 0x2e, 0x2d, 0x2d, 0x2e, 0x2d, 0x2e, 0x2e, +0x2e, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2d, 0x2e, 0x2d, 0x2e, 0x2d, 0x1e, 0x2e, 0x2e, +0x2d, 0x2d, 0x1e, 0x2d, 0x2e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, 0x2c, 0x2c, +0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2a, 0x2a, 0x1d, 0x1d, 0x2a, +0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2b, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, +0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, 0x2c, 0x1e, 0x2c, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, +0x1e, 0x1e, 0x2d, 0x2e, 0x1e, 0x2e, 0x1e, 0x2d, 0x2d, 0x1e, 0x2d, 0x2e, 0x2d, 0x1e, 0x2e, 0x2e, 0x2d, 0x2d, 0x1e, 0x2e, +0x2e, 0x2d, 0x2d, 0x2d, 0x2e, 0x2d, 0x2e, 0x2e, 0x2d, 0x2e, 0x2d, 0x1e, 0x2d, 0x2e, 0x2d, 0x2e, 0x2d, 0x1e, 0x1e, 0x2d, +0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x2d, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, +0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x1d, +0x2a, 0x1d, 0x1d, 0x2a, 0x2a, 0x2a, 0x1d, 0x29, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x1d, 0x2a, +0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x1e, 0x2c, +0x1e, 0x2c, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x2d, 0x1e, 0x2d, 0x1e, +0x1e, 0x2d, 0x2d, 0x2d, 0x2d, 0x1e, 0x1e, 0x2e, 0x1e, 0x1e, 0x2d, 0x2d, 0x1e, 0x2e, 0x2d, 0x1e, 0x2d, 0x2e, 0x2e, 0x1e, +0x1e, 0x2d, 0x2d, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x2c, 0x1e, +0x1e, 0x1e, 0x2c, 0x1e, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, +0x1d, 0x2b, 0x2b, 0x2b, 0x2a, 0x1d, 0x2a, 0x1d, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x29, 0x29, 0x2a, 0x2a, 0x29, 0x29, +0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2b, 0x1d, 0x1d, 0x2b, 0x2b, 0x1d, 0x1d, 0x1d, 0x2b, 0x2c, 0x2c, +0x2b, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, 0x2c, +0x1e, 0x2c, 0x1e, 0x2c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, +0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x2d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x2c, +0x1e, 0x1e, 0x1e, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2b, 0x2b, +0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x1d, 0x2b, 0x2b, 0x2a, 0x2b, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, +0x1d, 0x1d, 0x2b, 0x2a, 0x1d, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, +0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, +0x2c, 0x1e, 0x1e, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, 0x1e, 0x2c, 0x1e, +0x1e, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, +0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x1d, 0x2b, 0x2b, 0x1d, 0x1d, 0x1d, +0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, +0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x2a, 0x1d, 0x2b, 0x2b, 0x2a, 0x1d, 0x2b, 0x1d, 0x2b, +0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2c, 0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, +0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, +0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x1e, 0x2c, 0x2b, +0x2c, 0x2c, 0x2b, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x1d, 0x1d, 0x2b, 0x2b, 0x1d, 0x2b, 0x1d, 0x2a, 0x2a, 0x1d, +0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, +0x2a, 0x1d, 0x1d, 0x2a, 0x1d, 0x1d, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x2b, 0x1d, 0x2b, +0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x1e, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c, +0x2b, 0x2c, 0x2b, 0x1e, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, +0x2c, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2c, 0x2b, 0x2c, 0x2b, 0x1d, 0x2b, 0x2b, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, +0x2b, 0x1d, 0x2a, 0x2a, 0x1d, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x2a, +0x2a, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x28, 0x29, 0x28, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, +0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2b, 0x1d, 0x2a, +0x2a, 0x1d, 0x2a, 0x2b, 0x1d, 0x1d, 0x1d, 0x2b, 0x2b, 0x2b, 0x1d, 0x2c, 0x2b, 0x1d, 0x2b, 0x2b, 0x1d, 0x2b, 0x2c, 0x2b, +0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2c, +0x2b, 0x2c, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x2b, 0x2b, 0x2c, 0x1d, 0x1d, 0x1d, 0x2b, 0x2b, 0x1d, 0x1d, +0x2b, 0x2b, 0x1d, 0x2a, 0x2a, 0x1d, 0x2a, 0x2b, 0x2a, 0x2a, 0x1d, 0x1d, 0x2a, 0x1d, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, +0x2a, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x28, 0x28, 0x29, 0x28, 0x28, 0x28, 0x29, 0x29, +0x29, 0x29, 0x28, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x2a, +0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x2b, 0x2a, 0x2a, 0x2a, +0x2a, 0x2b, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x1d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, 0x1d, 0x1d, 0x1d, +0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x1d, 0x2b, 0x2b, 0x1d, 0x2b, 0x2b, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x1d, 0x2b, 0x1d, +0x2b, 0x1d, 0x2b, 0x1d, 0x1d, 0x2a, 0x2a, 0x1d, 0x1d, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x2a, 0x2a, 0x29, +0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x42, 0x28, 0x29, +0x42, 0x29, 0x28, 0x28, 0x28, 0x28, 0x42, 0x28, 0x29, 0x29, 0x29, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x42, +0x29, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, +0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x1d, 0x2b, 0x2a, 0x2a, 0x1d, 0x2a, 0x2b, 0x2a, 0x1d, 0x2a, 0x2b, 0x1d, 0x1d, +0x2b, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x2b, 0x2b, 0x2a, 0x1d, 0x1d, 0x2a, 0x2b, 0x1d, 0x1d, 0x2a, 0x2a, 0x2b, 0x2a, +0x1d, 0x1d, 0x2a, 0x1d, 0x2a, 0x2b, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, +0x29, 0x28, 0x29, 0x42, 0x29, 0x42, 0x29, 0x28, 0x28, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x42, 0x42, +0x28, 0x28, 0x29, 0x28, 0x42, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x2a, +0x29, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x1d, 0x2a, 0x2a, 0x1d, 0x1d, 0x1d, 0x2b, 0x1d, 0x2b, 0x2a, 0x1d, 0x1d, 0x2b, 0x2b, +0x1d, 0x1d, 0x2b, 0x2a, 0x2a, 0x1d, 0x2a, 0x1d, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, +0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x2a, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x29, 0x28, 0x28, 0x29, 0x29, 0x28, 0x29, 0x42, 0x28, 0x28, 0x42, 0x28, 0x28, 0x28, 0x27, 0x28, +0x27, 0x27, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x28, 0x28, 0x42, 0x29, 0x28, 0x28, +0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, +0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x1d, +0x2a, 0x2a, 0x1d, 0x2a, 0x2a, 0x1d, 0x2a, 0x1d, 0x2a, 0x2a, 0x2a, 0x1d, 0x1d, 0x2a, 0x1d, 0x2a, 0x2a, 0x1d, 0x2a, 0x2a, +0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x29, +0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x28, 0x29, 0x28, 0x29, 0x29, 0x29, 0x42, 0x42, 0x28, 0x42, 0x28, +0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, +0x28, 0x42, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x28, 0x29, 0x29, 0x29, 0x42, 0x42, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, +0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x2a, +0x29, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x29, +0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x42, 0x28, 0x29, 0x28, 0x29, 0x42, 0x29, 0x28, 0x28, 0x28, +0x28, 0x28, 0x42, 0x28, 0x27, 0x28, 0x28, 0x28, 0x27, 0x27, 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x28, 0x27, 0x27, 0x28, +0x27, 0x27, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x42, 0x28, 0x42, +0x28, 0x29, 0x29, 0x29, 0x29, 0x28, 0x28, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x42, 0x29, 0x29, 0x29, 0x29, 0x29, +0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x29, 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x29, 0x29, 0x29, +0x2a, 0x29, 0x2a, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x29, 0x29, 0x2a, 0x2a, 0x29, 0x2a, 0x29, 0x2a, 0x2a, 0x29, 0x2a, 0x29, +0x2a, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x28, 0x28, 0x29, 0x28, 0x29, 0x42, 0x28, 0x29, +0x29, 0x42, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x27, 0x28, 0x28, 0x27, 0x28, 0x28, +0x27, 0x27, 0x39, 0x0, 0x0, +}; + +int Corona_bmp_Length = sizeof(Corona_bmp); diff --git a/G3D/Engine/Logo/LogoActor.c b/G3D/Engine/Logo/LogoActor.c new file mode 100644 index 0000000..41f6523 --- /dev/null +++ b/G3D/Engine/Logo/LogoActor.c @@ -0,0 +1,7356 @@ +/****************************************************************************************/ +/* LOGOACTOR.C */ +/* */ +/* Author: */ +/* Description: Embedded Genesis3D logo actor */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +unsigned char LogoActor_act[] = { +0x56, 0x46, 0x30, 0x30, 0x0, 0x0, 0xd7, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe4, 0x3b, 0x2, 0x0, 0xe4, 0x3b, 0x2, +0x0, 0xbb, 0x3c, 0x2, 0x0, 0x41, 0x43, 0x54, 0x52, 0xf1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, +0x0, 0x56, 0x46, 0x30, 0x30, 0x0, 0x0, 0xd7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9d, 0x1e, 0x2, 0x0, 0x9d, 0x1e, 0x2, +0x0, 0xe6, 0x1f, 0x2, 0x0, 0x42, 0x4f, 0x44, 0x5e, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd7, 0x6, 0x2, +0xe8, 0xce, 0xc3, 0x8c, 0xb1, 0xa9, 0x42, 0x29, 0xe2, 0x9, 0x43, 0xa0, 0x19, 0xa2, 0x3f, 0x22, 0x33, 0xa7, 0x3e, 0x1, +0xbe, 0x0, 0x0, 0x64, 0x9e, 0x4a, 0xc3, 0x62, 0x36, 0xd5, 0x42, 0x29, 0xe2, 0x9, 0x43, 0x7a, 0x72, 0xa5, 0xbe, 0x22, +0x33, 0xa7, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0x2, 0xe8, 0xce, 0xc3, 0x64, 0x36, 0xd5, 0x42, 0x29, 0xe2, 0x9, 0x43, 0xa0, +0x19, 0xa2, 0x3f, 0x22, 0x33, 0xa7, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0x64, 0x9e, 0x4a, 0xc3, 0x8c, 0xb1, 0xa9, 0x42, 0x29, +0xe2, 0x9, 0x43, 0x7a, 0x72, 0xa5, 0xbe, 0x22, 0x33, 0xa7, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0x2, 0xe8, 0xce, 0xc3, 0x6a, +0x7c, 0x86, 0x42, 0xe5, 0x2f, 0xfa, 0x42, 0xa0, 0x19, 0xa2, 0x3f, 0x64, 0x1e, 0xc9, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0x64, +0x9e, 0x4a, 0xc3, 0x68, 0x7c, 0x86, 0x42, 0xe5, 0x2f, 0xfa, 0x42, 0x7a, 0x72, 0xa5, 0xbe, 0x64, 0x1e, 0xc9, 0x3e, 0x1, +0xbe, 0x0, 0x0, 0x2, 0xe8, 0xce, 0xc3, 0x65, 0x13, 0x72, 0x42, 0x52, 0xcc, 0xd0, 0x42, 0xa0, 0x19, 0xa2, 0x3f, 0x0, +0x0, 0x0, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x64, 0x9e, 0x4a, 0xc3, 0x65, 0x13, 0x72, 0x42, 0x52, 0xcc, 0xd0, 0x42, 0x7a, +0x72, 0xa5, 0xbe, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x2, 0xe8, 0xce, 0xc3, 0x6a, 0x7c, 0x86, 0x42, 0xbf, +0x68, 0xa7, 0x42, 0xa0, 0x19, 0xa2, 0x3f, 0xce, 0x70, 0x1b, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x64, 0x9e, 0x4a, 0xc3, 0x6a, +0x7c, 0x86, 0x42, 0xbf, 0x68, 0xa7, 0x42, 0x7a, 0x72, 0xa5, 0xbe, 0xce, 0x70, 0x1b, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x2, +0xe8, 0xce, 0xc3, 0x8c, 0xb1, 0xa9, 0x42, 0x52, 0xd4, 0x8d, 0x42, 0xa0, 0x19, 0xa2, 0x3f, 0x6f, 0x66, 0x2c, 0x3f, 0x1, +0xbe, 0x0, 0x0, 0x64, 0x9e, 0x4a, 0xc3, 0x8c, 0xb1, 0xa9, 0x42, 0x52, 0xd4, 0x8d, 0x42, 0x7a, 0x72, 0xa5, 0xbe, 0x6f, +0x66, 0x2c, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x2, 0xe8, 0xce, 0xc3, 0x64, 0x36, 0xd5, 0x42, 0x52, 0xd4, 0x8d, 0x42, 0xa0, +0x19, 0xa2, 0x3f, 0x6f, 0x66, 0x2c, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x64, 0x9e, 0x4a, 0xc3, 0x64, 0x36, 0xd5, 0x42, 0x52, +0xd4, 0x8d, 0x42, 0x7a, 0x72, 0xa5, 0xbe, 0x6f, 0x66, 0x2c, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0xea, 0x7f, 0x52, 0x43, 0x62, +0x36, 0xd5, 0x42, 0x29, 0xe2, 0x9, 0x43, 0x7a, 0x72, 0xa5, 0xbe, 0x22, 0x33, 0xa7, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0xc4, +0xd8, 0xd2, 0x43, 0x8c, 0xb1, 0xa9, 0x42, 0x29, 0xe2, 0x9, 0x43, 0xa0, 0x19, 0xa2, 0x3f, 0x22, 0x33, 0xa7, 0x3e, 0x1, +0xbe, 0x0, 0x0, 0xc4, 0xd8, 0xd2, 0x43, 0x64, 0x36, 0xd5, 0x42, 0x29, 0xe2, 0x9, 0x43, 0xa0, 0x19, 0xa2, 0x3f, 0x22, +0x33, 0xa7, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0xea, 0x7f, 0x52, 0x43, 0x8c, 0xb1, 0xa9, 0x42, 0x29, 0xe2, 0x9, 0x43, 0x7a, +0x72, 0xa5, 0xbe, 0x22, 0x33, 0xa7, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0xc4, 0xd8, 0xd2, 0x43, 0x6a, 0x7c, 0x86, 0x42, 0xe5, +0x2f, 0xfa, 0x42, 0xa0, 0x19, 0xa2, 0x3f, 0x64, 0x1e, 0xc9, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0xea, 0x7f, 0x52, 0x43, 0x68, +0x7c, 0x86, 0x42, 0xe5, 0x2f, 0xfa, 0x42, 0x7a, 0x72, 0xa5, 0xbe, 0x64, 0x1e, 0xc9, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0xc4, +0xd8, 0xd2, 0x43, 0x65, 0x13, 0x72, 0x42, 0x52, 0xcc, 0xd0, 0x42, 0xa0, 0x19, 0xa2, 0x3f, 0x0, 0x0, 0x0, 0x3f, 0x1, +0xbe, 0x0, 0x0, 0xea, 0x7f, 0x52, 0x43, 0x65, 0x13, 0x72, 0x42, 0x52, 0xcc, 0xd0, 0x42, 0x7a, 0x72, 0xa5, 0xbe, 0x0, +0x0, 0x0, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0xc4, 0xd8, 0xd2, 0x43, 0x6a, 0x7c, 0x86, 0x42, 0xbf, 0x68, 0xa7, 0x42, 0xa0, +0x19, 0xa2, 0x3f, 0xce, 0x70, 0x1b, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0xea, 0x7f, 0x52, 0x43, 0x6a, 0x7c, 0x86, 0x42, 0xbf, +0x68, 0xa7, 0x42, 0x7a, 0x72, 0xa5, 0xbe, 0xce, 0x70, 0x1b, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0xc4, 0xd8, 0xd2, 0x43, 0x8c, +0xb1, 0xa9, 0x42, 0x52, 0xd4, 0x8d, 0x42, 0xa0, 0x19, 0xa2, 0x3f, 0x6f, 0x66, 0x2c, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0xea, +0x7f, 0x52, 0x43, 0x8c, 0xb1, 0xa9, 0x42, 0x52, 0xd4, 0x8d, 0x42, 0x7a, 0x72, 0xa5, 0xbe, 0x6f, 0x66, 0x2c, 0x3f, 0x1, +0xbe, 0x0, 0x0, 0xc4, 0xd8, 0xd2, 0x43, 0x64, 0x36, 0xd5, 0x42, 0x52, 0xd4, 0x8d, 0x42, 0xa0, 0x19, 0xa2, 0x3f, 0x6f, +0x66, 0x2c, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0xea, 0x7f, 0x52, 0x43, 0x64, 0x36, 0xd5, 0x42, 0x52, 0xd4, 0x8d, 0x42, 0x7a, +0x72, 0xa5, 0xbe, 0x6f, 0x66, 0x2c, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x2b, 0xb8, 0xf5, 0x43, 0xea, 0x87, 0x88, 0xc3, 0x36, +0x47, 0x1d, 0xc3, 0x2d, 0x7, 0x66, 0x3f, 0xa2, 0xba, 0x39, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0xda, 0xfb, 0x1a, 0x44, 0xea, +0x87, 0x88, 0xc3, 0xd1, 0xa3, 0xc0, 0xc3, 0x3b, 0xdf, 0x7f, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x92, +0x90, 0xef, 0xc3, 0xe8, 0x87, 0x88, 0xc3, 0x36, 0x47, 0x1d, 0xc3, 0xc7, 0x47, 0xb, 0x3e, 0xa2, 0xba, 0x39, 0x3f, 0x1, +0xbe, 0x0, 0x0, 0xda, 0xfb, 0x1a, 0x44, 0x84, 0xdb, 0xa6, 0xc3, 0xd1, 0xa3, 0xc0, 0xc3, 0x3b, 0xdf, 0x7f, 0x3f, 0x3b, +0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0xd6, 0x83, 0xb9, 0x43, 0x83, 0xdb, 0xa6, 0xc3, 0x5a, 0x7a, 0xd8, 0xc2, 0x78, +0xcf, 0x4d, 0x3f, 0x87, 0xa4, 0x2a, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x3c, 0x5c, 0xb3, 0xc3, 0x83, 0xdb, 0xa6, 0xc3, 0x5a, +0x7a, 0xd8, 0xc2, 0x57, 0x26, 0x6c, 0x3e, 0x76, 0xa4, 0x2a, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x8a, 0xe7, 0x22, 0xc4, 0x84, +0xdb, 0xa6, 0xc3, 0xd1, 0xa3, 0xc0, 0xc3, 0x6f, 0x12, 0x3, 0x3a, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x8a, +0xe7, 0x22, 0xc4, 0xea, 0x87, 0x88, 0xc3, 0xd1, 0xa3, 0xc0, 0xc3, 0x6f, 0x12, 0x3, 0x3a, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, +0xbe, 0x0, 0x0, 0xda, 0xfb, 0x1a, 0x44, 0x80, 0xdb, 0xa6, 0xc3, 0x1, 0x3, 0xdf, 0x43, 0x4c, 0xdf, 0x7f, 0x3f, 0x0, +0x14, 0x3, 0x3a, 0x1, 0xbe, 0x0, 0x0, 0x8a, 0xe7, 0x22, 0xc4, 0x80, 0xdb, 0xa6, 0xc3, 0x1, 0x3, 0xdf, 0x43, 0x6f, +0x12, 0x3, 0x3a, 0x0, 0xd0, 0x2, 0x3a, 0x1, 0xbe, 0x0, 0x0, 0xda, 0xfb, 0x1a, 0x44, 0xe6, 0x87, 0x88, 0xc3, 0x0, +0x3, 0xdf, 0x43, 0x4c, 0xdf, 0x7f, 0x3f, 0x0, 0x14, 0x3, 0x3a, 0x1, 0xbe, 0x0, 0x0, 0x8a, 0xe7, 0x22, 0xc4, 0xe6, +0x87, 0x88, 0xc3, 0x0, 0x3, 0xdf, 0x43, 0x6f, 0x12, 0x3, 0x3a, 0x0, 0xd0, 0x2, 0x3a, 0x1, 0xbe, 0x0, 0x0, 0x2b, +0xb8, 0xf5, 0x43, 0xe7, 0x87, 0x88, 0xc3, 0xe7, 0x1, 0x6e, 0x43, 0x2d, 0x7, 0x66, 0x3f, 0xc8, 0x3e, 0x80, 0x3e, 0x1, +0xbe, 0x0, 0x0, 0xd6, 0x83, 0xb9, 0x43, 0x82, 0xdb, 0xa6, 0xc3, 0xe0, 0xf7, 0x3c, 0x43, 0x78, 0xcf, 0x4d, 0x3f, 0xfc, +0x6a, 0x9e, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0x92, 0x90, 0xef, 0xc3, 0xe7, 0x87, 0x88, 0xc3, 0xe7, 0x1, 0x6e, 0x43, 0xc7, +0x47, 0xb, 0x3e, 0xa8, 0x3e, 0x80, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0x3c, 0x5c, 0xb3, 0xc3, 0x82, 0xdb, 0xa6, 0xc3, 0xe0, +0xf7, 0x3c, 0x43, 0x57, 0x26, 0x6c, 0x3e, 0xfc, 0x6a, 0x9e, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0x38, 0xdb, 0x23, 0xc4, 0x97, +0xb3, 0x21, 0x41, 0x48, 0xf5, 0x73, 0xc3, 0x96, 0x4, 0x48, 0xbe, 0x4c, 0x5f, 0xe0, 0xbe, 0x1, 0xbe, 0x0, 0x0, 0x76, +0x2d, 0x64, 0xc3, 0x97, 0xb3, 0x21, 0x41, 0x48, 0xf5, 0x73, 0xc3, 0x79, 0xca, 0x92, 0x3f, 0x4c, 0x5f, 0xe0, 0xbe, 0x1, +0xbe, 0x0, 0x0, 0x38, 0xdb, 0x23, 0xc4, 0x97, 0xb3, 0x21, 0x41, 0xac, 0xca, 0xa4, 0x43, 0x96, 0x4, 0x48, 0xbe, 0x16, +0x86, 0xae, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x76, 0x2d, 0x64, 0xc3, 0x97, 0xb3, 0x21, 0x41, 0xac, 0xca, 0xa4, 0x43, 0x79, +0xca, 0x92, 0x3f, 0x16, 0x86, 0xae, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x76, 0x2d, 0x64, 0xc3, 0x97, 0xb3, 0x21, 0x41, 0x48, +0xf5, 0x73, 0xc3, 0x77, 0x84, 0xd3, 0xbc, 0x4, 0x90, 0x3, 0x40, 0x1, 0xbe, 0x0, 0x0, 0x76, 0x2d, 0x64, 0xc3, 0x7b, +0xeb, 0x33, 0x43, 0x48, 0xf5, 0x73, 0xc3, 0x8b, 0x19, 0xd, 0xbf, 0x4, 0x90, 0x3, 0x40, 0x1, 0xbe, 0x0, 0x0, 0x76, +0x2d, 0x64, 0xc3, 0x97, 0xb3, 0x21, 0x41, 0xac, 0xca, 0xa4, 0x43, 0x77, 0x84, 0xd3, 0xbc, 0xb0, 0x6, 0x90, 0x3e, 0x1, +0xbe, 0x0, 0x0, 0x76, 0x2d, 0x64, 0xc3, 0x7b, 0xeb, 0x33, 0x43, 0xac, 0xca, 0xa4, 0x43, 0x8b, 0x19, 0xd, 0xbf, 0xb0, +0x6, 0x90, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0xb4, 0xc7, 0x68, 0x43, 0x97, 0xb3, 0x21, 0x41, 0x48, 0xf5, 0x73, 0xc3, 0xb7, +0xd5, 0x2c, 0x3c, 0xdf, 0xde, 0xa5, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x8a, 0x97, 0x16, 0x44, 0x97, 0xb3, 0x21, 0x41, 0x48, +0xf5, 0x73, 0xc3, 0x8b, 0x4f, 0x89, 0x3f, 0xdf, 0xde, 0xa5, 0x3f, 0x1, 0xbe, 0x0, 0x0, 0x8a, 0x97, 0x16, 0x44, 0x97, +0xb3, 0x21, 0x41, 0xac, 0xca, 0xa4, 0x43, 0x8b, 0x4f, 0x89, 0x3f, 0x2c, 0x79, 0xb4, 0xbe, 0x1, 0xbe, 0x0, 0x0, 0xb4, +0xc7, 0x68, 0x43, 0x97, 0xb3, 0x21, 0x41, 0xac, 0xca, 0xa4, 0x43, 0xb7, 0xd5, 0x2c, 0x3c, 0x2c, 0x79, 0xb4, 0xbe, 0x1, +0xbe, 0x0, 0x0, 0xb4, 0xc7, 0x68, 0x43, 0x7b, 0xeb, 0x33, 0x43, 0x48, 0xf5, 0x73, 0xc3, 0x8b, 0x19, 0xd, 0xbf, 0x4, +0x90, 0x3, 0x40, 0x1, 0xbe, 0x0, 0x0, 0xb4, 0xc7, 0x68, 0x43, 0x97, 0xb3, 0x21, 0x41, 0x48, 0xf5, 0x73, 0xc3, 0x77, +0x84, 0xd3, 0xbc, 0x4, 0x90, 0x3, 0x40, 0x1, 0xbe, 0x0, 0x0, 0xb4, 0xc7, 0x68, 0x43, 0x97, 0xb3, 0x21, 0x41, 0xac, +0xca, 0xa4, 0x43, 0x77, 0x84, 0xd3, 0xbc, 0xb0, 0x6, 0x90, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0xb4, 0xc7, 0x68, 0x43, 0x7b, +0xeb, 0x33, 0x43, 0xac, 0xca, 0xa4, 0x43, 0x8b, 0x19, 0xd, 0xbf, 0xb0, 0x6, 0x90, 0x3e, 0x1, 0xbe, 0x0, 0x0, 0x44, +0xc7, 0x93, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x1a, 0xac, 0xb4, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, +0xbe, 0x0, 0x0, 0x44, 0xc7, 0x93, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x39, 0xb1, 0x94, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, +0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0xa0, 0xb6, 0x95, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x39, 0xb1, 0x94, 0x42, 0x64, +0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0xa0, 0xb6, 0x95, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x1a, +0xac, 0xb4, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0x81, 0xf1, 0x90, 0x43, 0x37, +0x94, 0x7e, 0xc3, 0xfc, 0x26, 0xbb, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0x81, +0xf1, 0x90, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x1a, 0xac, 0xb4, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, +0xbe, 0x0, 0x0, 0x63, 0x8c, 0x98, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0xfc, 0x26, 0xbb, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, +0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0x63, 0x8c, 0x98, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x1a, 0xac, 0xb4, 0x42, 0x64, +0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0xf2, 0xce, 0x99, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0xfc, +0x26, 0xbb, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0xf2, 0xce, 0x99, 0x43, 0x37, +0x94, 0x7e, 0xc3, 0x39, 0xb1, 0x94, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0xbf, +0x9b, 0x9b, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x39, 0xb1, 0x94, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, +0xbe, 0x0, 0x0, 0xaa, 0x9d, 0x9b, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x8b, 0xf7, 0xb2, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, +0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0x7c, 0xb7, 0x9c, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0xfc, 0x26, 0xbb, 0x42, 0x64, +0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0x6d, 0x73, 0x9e, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0xd3, +0xea, 0xa0, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0xaa, 0x80, 0x9d, 0x43, 0x37, +0x94, 0x7e, 0xc3, 0x39, 0xb1, 0x94, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0xba, +0x60, 0x9f, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x39, 0xb1, 0x94, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, +0xbe, 0x0, 0x0, 0x58, 0x45, 0xa1, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x8b, 0xf7, 0xb2, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, +0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0xe3, 0x28, 0xa0, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0xfc, 0x26, 0xbb, 0x42, 0x64, +0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0x11, 0x14, 0xa3, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0xfc, +0x26, 0xbb, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0x11, 0x14, 0xa3, 0x43, 0x37, +0x94, 0x7e, 0xc3, 0x39, 0xb1, 0x94, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, 0xbe, 0x0, 0x0, 0x44, +0x47, 0xa1, 0x43, 0x37, 0x94, 0x7e, 0xc3, 0x39, 0xb1, 0x94, 0x42, 0x64, 0x31, 0x35, 0x0, 0x11, 0x0, 0x0, 0x0, 0x1, +0xbe, 0x0, 0x0, 0x44, 0xae, 0x4f, 0x42, 0x28, 0xe2, 0xa7, 0xc1, 0x3d, 0x3b, 0x9a, 0x41, 0xd8, 0xb9, 0x75, 0x3f, 0xb2, +0x11, 0x38, 0x3f, 0x1, 0xbe, 0x15, 0x0, 0xf0, 0xe0, 0x5d, 0x42, 0x36, 0xb, 0x2b, 0xc2, 0xa5, 0x3f, 0x78, 0x40, 0xb8, +0x90, 0x63, 0x3f, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x3b, 0x62, 0x2a, 0x42, 0x37, 0xb, 0x2b, 0xc2, 0x2e, +0xf8, 0xe, 0x42, 0xd6, 0x8c, 0x50, 0x3f, 0xda, 0x18, 0x8b, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0x79, 0xe0, 0x9a, 0xb7, 0x34, +0x7f, 0xd2, 0xc1, 0x5c, 0x38, 0xb, 0x37, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0xad, +0x19, 0x8a, 0x42, 0xdf, 0xef, 0x19, 0xc2, 0x3f, 0xc8, 0x81, 0x41, 0x5f, 0x5d, 0x7d, 0x3f, 0x3a, 0x58, 0xd7, 0x3e, 0x1, +0xbe, 0x20, 0x0, 0x4a, 0xc2, 0x73, 0x42, 0xe0, 0xef, 0x19, 0xc2, 0xdd, 0x2f, 0x11, 0x42, 0x9e, 0x62, 0x71, 0x3f, 0x2e, +0xb2, 0x8d, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0xf0, 0xe0, 0x5d, 0x42, 0xf5, 0xcf, 0x1d, 0xc1, 0xa5, 0x3f, 0x78, 0x40, 0xb8, +0x90, 0x63, 0x3f, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0xad, 0x19, 0x8a, 0x42, 0x55, 0x3d, 0x62, 0xc1, 0x3f, +0xc8, 0x81, 0x41, 0x5f, 0x5d, 0x7d, 0x3f, 0x3a, 0x58, 0xd7, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0x48, 0xc2, 0x73, 0x42, 0x59, +0x3d, 0x62, 0xc1, 0xe5, 0x2f, 0x11, 0x42, 0x9e, 0x62, 0x71, 0x3f, 0x2e, 0xb2, 0x8d, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0x3b, +0x62, 0x2a, 0x42, 0xfb, 0xcf, 0x1d, 0xc1, 0x2e, 0xf8, 0xe, 0x42, 0xd6, 0x8c, 0x50, 0x3f, 0xda, 0x18, 0x8b, 0x3e, 0x1, +0xbe, 0x20, 0x0, 0x83, 0x3b, 0x57, 0x41, 0x37, 0xb, 0x2b, 0xc2, 0x57, 0xd0, 0x57, 0x42, 0x72, 0xc4, 0x1e, 0x3f, 0xc8, +0xb1, 0x5, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0x18, 0x4f, 0x39, 0x42, 0xe0, 0xef, 0x19, 0xc2, 0x49, 0xd8, 0x56, 0x42, 0x9f, +0x75, 0x59, 0x3f, 0x18, 0xd4, 0x17, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0x92, 0xbb, 0xdf, 0x41, 0xe1, 0xef, 0x19, 0xc2, 0x51, +0x5e, 0x82, 0x42, 0xad, 0x18, 0x3a, 0x3f, 0xf0, 0x2c, 0x73, 0x3d, 0x1, 0xbe, 0x20, 0x0, 0x18, 0x4f, 0x39, 0x42, 0x59, +0x3d, 0x62, 0xc1, 0x49, 0xd8, 0x56, 0x42, 0x9f, 0x75, 0x59, 0x3f, 0x18, 0xd4, 0x17, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0x92, +0xbb, 0xdf, 0x41, 0x5b, 0x3d, 0x62, 0xc1, 0x51, 0x5e, 0x82, 0x42, 0xad, 0x18, 0x3a, 0x3f, 0xf0, 0x2c, 0x73, 0x3d, 0x1, +0xbe, 0x20, 0x0, 0x83, 0x3b, 0x57, 0x41, 0xfb, 0xcf, 0x1d, 0xc1, 0x57, 0xd0, 0x57, 0x42, 0x72, 0xc4, 0x1e, 0x3f, 0xc8, +0xb1, 0x5, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0x1c, 0xa4, 0xa6, 0xc1, 0x37, 0xb, 0x2b, 0xc2, 0x8a, 0x39, 0x4e, 0x42, 0x1d, +0x77, 0xc2, 0x3e, 0xc8, 0xb1, 0x5, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0xc7, 0x15, 0xbd, 0x40, 0xe0, 0xef, 0x19, 0xc2, 0x19, +0x5e, 0x8d, 0x42, 0x30, 0x62, 0x13, 0x3f, 0x40, 0xa8, 0x28, 0x3c, 0x1, 0xbe, 0x20, 0x0, 0x83, 0x5, 0x7b, 0xc1, 0xe0, +0xef, 0x19, 0xc2, 0xd6, 0x58, 0x8a, 0x42, 0xc1, 0x3b, 0xd9, 0x3e, 0x40, 0xa8, 0x28, 0x3c, 0x1, 0xbe, 0x20, 0x0, 0xc7, +0x15, 0xbd, 0x40, 0x5b, 0x3d, 0x62, 0xc1, 0x19, 0x5e, 0x8d, 0x42, 0x30, 0x62, 0x13, 0x3f, 0x40, 0xa8, 0x28, 0x3c, 0x1, +0xbe, 0x20, 0x0, 0x83, 0x5, 0x7b, 0xc1, 0x57, 0x3d, 0x62, 0xc1, 0xd6, 0x58, 0x8a, 0x42, 0xc1, 0x3b, 0xd9, 0x3e, 0x40, +0xa8, 0x28, 0x3c, 0x1, 0xbe, 0x20, 0x0, 0x1c, 0xa4, 0xa6, 0xc1, 0xf7, 0xcf, 0x1d, 0xc1, 0x8a, 0x39, 0x4e, 0x42, 0x1d, +0x77, 0xc2, 0x3e, 0xc8, 0xb1, 0x5, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0xa0, 0x9f, 0x3c, 0xc2, 0x35, 0xb, 0x2b, 0xc2, 0xca, +0xba, 0xeb, 0x41, 0xea, 0xcc, 0x3d, 0x3e, 0xda, 0x18, 0x8b, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0xe0, 0x10, 0x13, 0xc2, 0xe0, +0xef, 0x19, 0xc2, 0x57, 0xa1, 0x72, 0x42, 0xc8, 0xce, 0x8b, 0x3e, 0xf0, 0x2c, 0x73, 0x3d, 0x1, 0xbe, 0x20, 0x0, 0x1e, +0x68, 0x55, 0xc2, 0xdf, 0xef, 0x19, 0xc2, 0xa3, 0xf6, 0x3a, 0x42, 0xc7, 0x29, 0x1a, 0x3e, 0x18, 0xd4, 0x17, 0x3e, 0x1, +0xbe, 0x20, 0x0, 0xe0, 0x10, 0x13, 0xc2, 0x55, 0x3d, 0x62, 0xc1, 0x57, 0xa1, 0x72, 0x42, 0xc8, 0xce, 0x8b, 0x3e, 0xf0, +0x2c, 0x73, 0x3d, 0x1, 0xbe, 0x20, 0x0, 0x1e, 0x68, 0x55, 0xc2, 0x51, 0x3d, 0x62, 0xc1, 0xa3, 0xf6, 0x3a, 0x42, 0xc7, +0x29, 0x1a, 0x3e, 0x18, 0xd4, 0x17, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0xa0, 0x9f, 0x3c, 0xc2, 0xf3, 0xcf, 0x1d, 0xc1, 0xca, +0xba, 0xeb, 0x41, 0xea, 0xcc, 0x3d, 0x3e, 0xda, 0x18, 0x8b, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0xf8, 0xe0, 0x5d, 0xc2, 0x34, +0xb, 0x2b, 0xc2, 0x49, 0x3f, 0x78, 0xc0, 0x3e, 0x7a, 0xe3, 0x3d, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0xed, +0xcb, 0x82, 0xc2, 0xde, 0xef, 0x19, 0xc2, 0x97, 0xb2, 0xdb, 0x41, 0x28, 0xd6, 0x69, 0x3d, 0x2e, 0xb2, 0x8d, 0x3e, 0x1, +0xbe, 0x20, 0x0, 0x9f, 0x45, 0x8d, 0xc2, 0xdd, 0xef, 0x19, 0xc2, 0xb8, 0x8d, 0xce, 0x40, 0x2a, 0xa8, 0x28, 0x3c, 0x3a, +0x58, 0xd7, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0xed, 0xcb, 0x82, 0xc2, 0x4d, 0x3d, 0x62, 0xc1, 0x97, 0xb2, 0xdb, 0x41, 0x28, +0xd6, 0x69, 0x3d, 0x2e, 0xb2, 0x8d, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0xa1, 0x45, 0x8d, 0xc2, 0x4b, 0x3d, 0x62, 0xc1, 0xfc, +0x8d, 0xce, 0x40, 0x2a, 0xa8, 0x28, 0x3c, 0x3a, 0x58, 0xd7, 0x3e, 0x1, 0xbe, 0x20, 0x0, 0xf8, 0xe0, 0x5d, 0xc2, 0xed, +0xcf, 0x1d, 0xc1, 0x49, 0x3f, 0x78, 0xc0, 0x3e, 0x7a, 0xe3, 0x3d, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x45, +0x62, 0x2a, 0xc2, 0x33, 0xb, 0x2b, 0xc2, 0x29, 0xf8, 0xe, 0xc2, 0xea, 0xcc, 0x3d, 0x3e, 0x92, 0x73, 0x3a, 0x3f, 0x1, +0xbe, 0x20, 0x0, 0xb2, 0x19, 0x8a, 0xc2, 0xdc, 0xef, 0x19, 0xc2, 0x39, 0xc8, 0x81, 0xc1, 0x2a, 0xa8, 0x28, 0x3c, 0xe3, +0x53, 0x14, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x50, 0xc2, 0x73, 0xc2, 0xdb, 0xef, 0x19, 0xc2, 0xe0, 0x2f, 0x11, 0xc2, 0x28, +0xd6, 0x69, 0x3d, 0xea, 0x26, 0x39, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0xb2, 0x19, 0x8a, 0xc2, 0x47, 0x3d, 0x62, 0xc1, 0x39, +0xc8, 0x81, 0xc1, 0x2a, 0xa8, 0x28, 0x3c, 0xe3, 0x53, 0x14, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x50, 0xc2, 0x73, 0xc2, 0x45, +0x3d, 0x62, 0xc1, 0xe0, 0x2f, 0x11, 0xc2, 0x28, 0xd6, 0x69, 0x3d, 0xea, 0x26, 0x39, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x45, +0x62, 0x2a, 0xc2, 0xe7, 0xcf, 0x1d, 0xc1, 0x29, 0xf8, 0xe, 0xc2, 0xea, 0xcc, 0x3d, 0x3e, 0x92, 0x73, 0x3a, 0x3f, 0x1, +0xbe, 0x20, 0x0, 0xaf, 0x3b, 0x57, 0xc1, 0x32, 0xb, 0x2b, 0xc2, 0x54, 0xd0, 0x57, 0xc2, 0x1d, 0x77, 0xc2, 0x3e, 0x8e, +0x93, 0x5e, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x22, 0x4f, 0x39, 0xc2, 0xdb, 0xef, 0x19, 0xc2, 0x44, 0xd8, 0x56, 0xc2, 0x84, +0x29, 0x1a, 0x3e, 0xfa, 0xa, 0x5a, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x92, 0xbb, 0xdf, 0xc1, 0xdb, 0xef, 0x19, 0xc2, 0x4f, +0x5e, 0x82, 0xc2, 0xa7, 0xce, 0x8b, 0x3e, 0x31, 0xcd, 0x70, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x22, 0x4f, 0x39, 0xc2, 0x41, +0x3d, 0x62, 0xc1, 0x44, 0xd8, 0x56, 0xc2, 0x84, 0x29, 0x1a, 0x3e, 0xfa, 0xa, 0x5a, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x92, +0xbb, 0xdf, 0xc1, 0x43, 0x3d, 0x62, 0xc1, 0x4f, 0x5e, 0x82, 0xc2, 0xa7, 0xce, 0x8b, 0x3e, 0x31, 0xcd, 0x70, 0x3f, 0x1, +0xbe, 0x20, 0x0, 0xa4, 0x3b, 0x57, 0xc1, 0xe7, 0xcf, 0x1d, 0xc1, 0x52, 0xd0, 0x57, 0xc2, 0x1d, 0x77, 0xc2, 0x3e, 0x8e, +0x93, 0x5e, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x9, 0xa4, 0xa6, 0x41, 0x33, 0xb, 0x2b, 0xc2, 0x85, 0x39, 0x4e, 0xc2, 0x72, +0xc4, 0x1e, 0x3f, 0x8e, 0x93, 0x5e, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x9, 0x16, 0xbd, 0xc0, 0xdb, 0xef, 0x19, 0xc2, 0x16, +0x5e, 0x8d, 0xc2, 0x9f, 0x3b, 0xd9, 0x3e, 0x5f, 0x5d, 0x7d, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x73, 0x5, 0x7b, 0x41, 0xdc, +0xef, 0x19, 0xc2, 0xd1, 0x58, 0x8a, 0xc2, 0x20, 0x62, 0x13, 0x3f, 0x5f, 0x5d, 0x7d, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0xfe, +0x15, 0xbd, 0xc0, 0x43, 0x3d, 0x62, 0xc1, 0x15, 0x5e, 0x8d, 0xc2, 0x9f, 0x3b, 0xd9, 0x3e, 0x5f, 0x5d, 0x7d, 0x3f, 0x1, +0xbe, 0x20, 0x0, 0x73, 0x5, 0x7b, 0x41, 0x43, 0x3d, 0x62, 0xc1, 0xd1, 0x58, 0x8a, 0xc2, 0x20, 0x62, 0x13, 0x3f, 0x5f, +0x5d, 0x7d, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x9, 0xa4, 0xa6, 0x41, 0xeb, 0xcf, 0x1d, 0xc1, 0x85, 0x39, 0x4e, 0xc2, 0x72, +0xc4, 0x1e, 0x3f, 0x8e, 0x93, 0x5e, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x96, 0x9f, 0x3c, 0x42, 0x35, 0xb, 0x2b, 0xc2, 0xc1, +0xba, 0xeb, 0xc1, 0xc5, 0x8c, 0x50, 0x3f, 0x92, 0x73, 0x3a, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0xd6, 0x10, 0x13, 0x42, 0xdc, +0xef, 0x19, 0xc2, 0x53, 0xa1, 0x72, 0xc2, 0xad, 0x18, 0x3a, 0x3f, 0x31, 0xcd, 0x70, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x1d, +0x68, 0x55, 0x42, 0xdd, 0xef, 0x19, 0xc2, 0xa1, 0xf6, 0x3a, 0xc2, 0x9f, 0x75, 0x59, 0x3f, 0xfa, 0xa, 0x5a, 0x3f, 0x1, +0xbe, 0x20, 0x0, 0xd6, 0x10, 0x13, 0x42, 0x47, 0x3d, 0x62, 0xc1, 0x53, 0xa1, 0x72, 0xc2, 0xad, 0x18, 0x3a, 0x3f, 0x31, +0xcd, 0x70, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x1d, 0x68, 0x55, 0x42, 0x4b, 0x3d, 0x62, 0xc1, 0xa1, 0xf6, 0x3a, 0xc2, 0x9f, +0x75, 0x59, 0x3f, 0xfa, 0xa, 0x5a, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x96, 0x9f, 0x3c, 0x42, 0xef, 0xcf, 0x1d, 0xc1, 0xc1, +0xba, 0xeb, 0xc1, 0xc5, 0x8c, 0x50, 0x3f, 0x92, 0x73, 0x3a, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0xe8, 0xcb, 0x82, 0x42, 0xde, +0xef, 0x19, 0xc2, 0x8e, 0xb2, 0xdb, 0xc1, 0x9e, 0x62, 0x71, 0x3f, 0xea, 0x26, 0x39, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x9b, +0x45, 0x8d, 0x42, 0xdf, 0xef, 0x19, 0xc2, 0x8a, 0x8d, 0xce, 0xc0, 0x5f, 0x5d, 0x7d, 0x3f, 0xe3, 0x53, 0x14, 0x3f, 0x1, +0xbe, 0x20, 0x0, 0xe8, 0xcb, 0x82, 0x42, 0x4d, 0x3d, 0x62, 0xc1, 0x8e, 0xb2, 0xdb, 0xc1, 0x9e, 0x62, 0x71, 0x3f, 0xea, +0x26, 0x39, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0x9b, 0x45, 0x8d, 0x42, 0x53, 0x3d, 0x62, 0xc1, 0x8a, 0x8d, 0xce, 0xc0, 0x5f, +0x5d, 0x7d, 0x3f, 0xe3, 0x53, 0x14, 0x3f, 0x1, 0xbe, 0x20, 0x0, 0xbd, 0x33, 0x5d, 0x42, 0xf1, 0xf5, 0x17, 0xc2, 0x18, +0xfe, 0xb9, 0x40, 0x22, 0x88, 0x5f, 0x3f, 0x36, 0x75, 0xfe, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x73, 0x4a, 0x25, 0x42, 0xef, +0xf5, 0x17, 0xc2, 0x3, 0xd4, 0x14, 0x42, 0x52, 0xf, 0x4d, 0x3f, 0xc, 0xe5, 0x8c, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0xa7, +0xc6, 0xa1, 0xb7, 0xb0, 0x54, 0xac, 0xc1, 0x98, 0xd8, 0xd4, 0x36, 0x6f, 0x9f, 0xfd, 0x3e, 0x14, 0x75, 0xfe, 0x3e, 0x1, +0xbe, 0x23, 0x0, 0x4e, 0xe2, 0x88, 0x42, 0x9b, 0xda, 0x6, 0xc2, 0x3, 0xfb, 0x94, 0x41, 0x1c, 0x98, 0x78, 0x3f, 0xb6, +0xf6, 0xd6, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x39, 0x8b, 0x6e, 0x42, 0x9a, 0xda, 0x6, 0xc2, 0xe6, 0x9a, 0x19, 0x42, 0xf9, +0xf4, 0x6c, 0x3f, 0x5e, 0x6b, 0x8f, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0xbd, 0x33, 0x5d, 0x42, 0x2, 0xf6, 0xa2, 0xc0, 0x18, +0xfe, 0xb9, 0x40, 0x22, 0x88, 0x5f, 0x3f, 0x36, 0x75, 0xfe, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x4e, 0xe2, 0x88, 0x42, 0x54, +0xe8, 0x15, 0xc1, 0x3, 0xfb, 0x94, 0x41, 0x1c, 0x98, 0x78, 0x3f, 0xb6, 0xf6, 0xd6, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x39, +0x8b, 0x6e, 0x42, 0x50, 0xe8, 0x15, 0xc1, 0xe6, 0x9a, 0x19, 0x42, 0xf9, 0xf4, 0x6c, 0x3f, 0x5e, 0x6b, 0x8f, 0x3e, 0x1, +0xbe, 0x23, 0x0, 0x73, 0x4a, 0x25, 0x42, 0xf6, 0xf5, 0xa2, 0xc0, 0x3, 0xd4, 0x14, 0x42, 0x52, 0xf, 0x4d, 0x3f, 0xc, +0xe5, 0x8c, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0xde, 0xf9, 0x38, 0x41, 0xee, 0xf5, 0x17, 0xc2, 0x59, 0x8f, 0x59, 0x42, 0x1c, +0xb3, 0x1c, 0x3f, 0x24, 0x6b, 0xd, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0xdd, 0xb2, 0x31, 0x42, 0x99, 0xda, 0x6, 0xc2, 0x3a, +0x2e, 0x5d, 0x42, 0xf6, 0xb6, 0x55, 0x3f, 0xcc, 0x8, 0x1f, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x7, 0x66, 0xcd, 0x41, 0x98, +0xda, 0x6, 0xc2, 0xa7, 0x3d, 0x84, 0x42, 0x64, 0x3f, 0x37, 0x3f, 0x90, 0x33, 0x8d, 0x3d, 0x1, 0xbe, 0x23, 0x0, 0xdd, +0xb2, 0x31, 0x42, 0x4e, 0xe8, 0x15, 0xc1, 0x3a, 0x2e, 0x5d, 0x42, 0xf6, 0xb6, 0x55, 0x3f, 0xcc, 0x8, 0x1f, 0x3e, 0x1, +0xbe, 0x23, 0x0, 0x1, 0x66, 0xcd, 0x41, 0x4a, 0xe8, 0x15, 0xc1, 0xa3, 0x3d, 0x84, 0x42, 0x64, 0x3f, 0x37, 0x3f, 0x90, +0x33, 0x8d, 0x3d, 0x1, 0xbe, 0x23, 0x0, 0xde, 0xf9, 0x38, 0x41, 0xee, 0xf5, 0xa2, 0xc0, 0x59, 0x8f, 0x59, 0x42, 0x1c, +0xb3, 0x1c, 0x3f, 0x24, 0x6b, 0xd, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0xd8, 0xee, 0xb4, 0xc1, 0xee, 0xf5, 0x17, 0xc2, 0xf6, +0x30, 0x4b, 0x42, 0x84, 0xd8, 0xc1, 0x3e, 0x24, 0x6b, 0xd, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x73, 0x12, 0x5c, 0x40, 0x97, +0xda, 0x6, 0xc2, 0x9a, 0xb1, 0x8d, 0x42, 0x16, 0xa4, 0x11, 0x3f, 0xc0, 0x44, 0xae, 0x3c, 0x1, 0xbe, 0x23, 0x0, 0x5, +0xbf, 0x90, 0xc1, 0x97, 0xda, 0x6, 0xc2, 0xe7, 0x2a, 0x89, 0x42, 0x90, 0xf6, 0xd7, 0x3e, 0xc0, 0x44, 0xae, 0x3c, 0x1, +0xbe, 0x23, 0x0, 0x73, 0x12, 0x5c, 0x40, 0x48, 0xe8, 0x15, 0xc1, 0x9a, 0xb1, 0x8d, 0x42, 0x16, 0xa4, 0x11, 0x3f, 0xc0, +0x44, 0xae, 0x3c, 0x1, 0xbe, 0x23, 0x0, 0x5, 0xbf, 0x90, 0xc1, 0x48, 0xe8, 0x15, 0xc1, 0xe7, 0x2a, 0x89, 0x42, 0x90, +0xf6, 0xd7, 0x3e, 0xc0, 0x44, 0xae, 0x3c, 0x1, 0xbe, 0x23, 0x0, 0xd8, 0xee, 0xb4, 0xc1, 0xee, 0xf5, 0xa2, 0xc0, 0xf6, +0x30, 0x4b, 0x42, 0x84, 0xd8, 0xc1, 0x3e, 0x24, 0x6b, 0xd, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x32, 0x9f, 0x40, 0xc2, 0xef, +0xf5, 0x17, 0xc2, 0xbd, 0x6b, 0xde, 0x41, 0x31, 0x40, 0x42, 0x3e, 0xc, 0xe5, 0x8c, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x86, +0x71, 0x1b, 0xc2, 0x97, 0xda, 0x6, 0xc2, 0x97, 0x59, 0x6d, 0x42, 0xf4, 0xbf, 0x8c, 0x3e, 0x8, 0x33, 0x8d, 0x3d, 0x1, +0xbe, 0x23, 0x0, 0x27, 0xcd, 0x5b, 0xc2, 0x99, 0xda, 0x6, 0xc2, 0xee, 0x66, 0x33, 0x42, 0xa1, 0xa1, 0x1f, 0x3e, 0xcc, +0x8, 0x1f, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x86, 0x71, 0x1b, 0xc2, 0x4c, 0xe8, 0x15, 0xc1, 0x97, 0x59, 0x6d, 0x42, 0xf4, +0xbf, 0x8c, 0x3e, 0x8, 0x33, 0x8d, 0x3d, 0x1, 0xbe, 0x23, 0x0, 0x27, 0xcd, 0x5b, 0xc2, 0x4c, 0xe8, 0x15, 0xc1, 0xee, +0x66, 0x33, 0x42, 0xa1, 0xa1, 0x1f, 0x3e, 0xcc, 0x8, 0x1f, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x32, 0x9f, 0x40, 0xc2, 0xf6, +0xf5, 0xa2, 0xc0, 0xbd, 0x6b, 0xde, 0x41, 0x31, 0x40, 0x42, 0x3e, 0xc, 0xe5, 0x8c, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0xc7, +0x33, 0x5d, 0xc2, 0xf1, 0xf5, 0x17, 0xc2, 0xfd, 0xfd, 0xb9, 0xc0, 0xdc, 0xb9, 0xf0, 0x3d, 0x14, 0x75, 0xfe, 0x3e, 0x1, +0xbe, 0x23, 0x0, 0x3b, 0xa2, 0x84, 0xc2, 0x99, 0xda, 0x6, 0xc2, 0x4d, 0x4e, 0xc9, 0x41, 0x26, 0x53, 0x85, 0x3d, 0x5e, +0x6b, 0x8f, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0xf2, 0xa2, 0x8d, 0xc2, 0x9b, 0xda, 0x6, 0xc2, 0x47, 0x18, 0x7f, 0x40, 0x42, +0xe8, 0xa0, 0x3c, 0xb6, 0xf6, 0xd6, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0x3b, 0xa2, 0x84, 0xc2, 0x50, 0xe8, 0x15, 0xc1, 0x4d, +0x4e, 0xc9, 0x41, 0x26, 0x53, 0x85, 0x3d, 0x5e, 0x6b, 0x8f, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0xf2, 0xa2, 0x8d, 0xc2, 0x54, +0xe8, 0x15, 0xc1, 0x47, 0x18, 0x7f, 0x40, 0x42, 0xe8, 0xa0, 0x3c, 0xb6, 0xf6, 0xd6, 0x3e, 0x1, 0xbe, 0x23, 0x0, 0xc7, +0x33, 0x5d, 0xc2, 0x1, 0xf6, 0xa2, 0xc0, 0xfd, 0xfd, 0xb9, 0xc0, 0xdc, 0xb9, 0xf0, 0x3d, 0x14, 0x75, 0xfe, 0x3e, 0x1, +0xbe, 0x23, 0x0, 0x7b, 0x4a, 0x25, 0xc2, 0xf2, 0xf5, 0x17, 0xc2, 0x2, 0xd4, 0x14, 0xc2, 0x31, 0x40, 0x42, 0x3e, 0x9f, +0x2, 0x38, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x53, 0xe2, 0x88, 0xc2, 0x9b, 0xda, 0x6, 0xc2, 0xfc, 0xfa, 0x94, 0xc1, 0x42, +0xe8, 0xa0, 0x3c, 0xca, 0xf9, 0x12, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x4c, 0x8b, 0x6e, 0xc2, 0x9c, 0xda, 0x6, 0xc2, 0xe5, +0x9a, 0x19, 0xc2, 0x26, 0x53, 0x85, 0x3d, 0x76, 0xbf, 0x36, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x53, 0xe2, 0x88, 0xc2, 0x58, +0xe8, 0x15, 0xc1, 0xfc, 0xfa, 0x94, 0xc1, 0x42, 0xe8, 0xa0, 0x3c, 0xca, 0xf9, 0x12, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x4c, +0x8b, 0x6e, 0xc2, 0x5c, 0xe8, 0x15, 0xc1, 0xe5, 0x9a, 0x19, 0xc2, 0x26, 0x53, 0x85, 0x3d, 0x76, 0xbf, 0x36, 0x3f, 0x1, +0xbe, 0x23, 0x0, 0x7b, 0x4a, 0x25, 0xc2, 0xd, 0xf6, 0xa2, 0xc0, 0x2, 0xd4, 0x14, 0xc2, 0x31, 0x40, 0x42, 0x3e, 0x9f, +0x2, 0x38, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xfb, 0xf9, 0x38, 0xc1, 0xf3, 0xf5, 0x17, 0xc2, 0x58, 0x8f, 0x59, 0xc2, 0x84, +0xd8, 0xc1, 0x3e, 0x5d, 0x1a, 0x5b, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xe4, 0xb2, 0x31, 0xc2, 0x9d, 0xda, 0x6, 0xc2, 0x34, +0x2e, 0x5d, 0xc2, 0xa1, 0xa1, 0x1f, 0x3e, 0xf2, 0xb2, 0x56, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x10, 0x66, 0xcd, 0xc1, 0x9d, +0xda, 0x6, 0xc2, 0xa6, 0x3d, 0x84, 0xc2, 0xf4, 0xbf, 0x8c, 0x3e, 0xb3, 0xce, 0x6c, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xe7, +0xb2, 0x31, 0xc2, 0x62, 0xe8, 0x15, 0xc1, 0x3d, 0x2e, 0x5d, 0xc2, 0xa1, 0xa1, 0x1f, 0x3e, 0xf2, 0xb2, 0x56, 0x3f, 0x1, +0xbe, 0x23, 0x0, 0x10, 0x66, 0xcd, 0xc1, 0x62, 0xe8, 0x15, 0xc1, 0xa6, 0x3d, 0x84, 0xc2, 0xf4, 0xbf, 0x8c, 0x3e, 0xb3, +0xce, 0x6c, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xfb, 0xf9, 0x38, 0xc1, 0x16, 0xf6, 0xa2, 0xc0, 0x58, 0x8f, 0x59, 0xc2, 0x84, +0xd8, 0xc1, 0x3e, 0x5d, 0x1a, 0x5b, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xc9, 0xee, 0xb4, 0x41, 0xf3, 0xf5, 0x17, 0xc2, 0xf5, +0x30, 0x4b, 0xc2, 0x1c, 0xb3, 0x1c, 0x3f, 0x5d, 0x1a, 0x5b, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x70, 0x13, 0x5c, 0xc0, 0x9f, +0xda, 0x6, 0xc2, 0x95, 0xb1, 0x8d, 0xc2, 0x90, 0xf6, 0xd7, 0x3e, 0x0, 0x3, 0x79, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xf1, +0xbe, 0x90, 0x41, 0x9e, 0xda, 0x6, 0xc2, 0xe3, 0x2a, 0x89, 0xc2, 0x16, 0xa4, 0x11, 0x3f, 0x0, 0x3, 0x79, 0x3f, 0x1, +0xbe, 0x23, 0x0, 0x70, 0x13, 0x5c, 0xc0, 0x62, 0xe8, 0x15, 0xc1, 0x95, 0xb1, 0x8d, 0xc2, 0x90, 0xf6, 0xd7, 0x3e, 0x0, +0x3, 0x79, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xf1, 0xbe, 0x90, 0x41, 0x62, 0xe8, 0x15, 0xc1, 0xe3, 0x2a, 0x89, 0xc2, 0x16, +0xa4, 0x11, 0x3f, 0x0, 0x3, 0x79, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xc4, 0xee, 0xb4, 0x41, 0x16, 0xf6, 0xa2, 0xc0, 0xf3, +0x30, 0x4b, 0xc2, 0x1c, 0xb3, 0x1c, 0x3f, 0x5d, 0x1a, 0x5b, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x25, 0x9f, 0x40, 0x42, 0xf2, +0xf5, 0x17, 0xc2, 0xb1, 0x6b, 0xde, 0xc1, 0x52, 0xf, 0x4d, 0x3f, 0x9f, 0x2, 0x38, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x7c, +0x71, 0x1b, 0x42, 0x9d, 0xda, 0x6, 0xc2, 0x94, 0x59, 0x6d, 0xc2, 0x64, 0x3f, 0x37, 0x3f, 0xb3, 0xce, 0x6c, 0x3f, 0x1, +0xbe, 0x23, 0x0, 0x1a, 0xcd, 0x5b, 0x42, 0x9d, 0xda, 0x6, 0xc2, 0xe8, 0x66, 0x33, 0xc2, 0xf6, 0xb6, 0x55, 0x3f, 0xf2, +0xb2, 0x56, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x7c, 0x71, 0x1b, 0x42, 0x64, 0xe8, 0x15, 0xc1, 0x94, 0x59, 0x6d, 0xc2, 0x64, +0x3f, 0x37, 0x3f, 0xb3, 0xce, 0x6c, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x1a, 0xcd, 0x5b, 0x42, 0x60, 0xe8, 0x15, 0xc1, 0xe8, +0x66, 0x33, 0xc2, 0xf6, 0xb6, 0x55, 0x3f, 0xf2, 0xb2, 0x56, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x25, 0x9f, 0x40, 0x42, 0xe, +0xf6, 0xa2, 0xc0, 0xb1, 0x6b, 0xde, 0xc1, 0x52, 0xf, 0x4d, 0x3f, 0x9f, 0x2, 0x38, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x34, +0xa2, 0x84, 0x42, 0x9d, 0xda, 0x6, 0xc2, 0x36, 0x4e, 0xc9, 0xc1, 0xf9, 0xf4, 0x6c, 0x3f, 0x76, 0xbf, 0x36, 0x3f, 0x1, +0xbe, 0x23, 0x0, 0xed, 0xa2, 0x8d, 0x42, 0x9b, 0xda, 0x6, 0xc2, 0xb7, 0x17, 0x7f, 0xc0, 0x1c, 0x98, 0x78, 0x3f, 0xca, +0xf9, 0x12, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0x34, 0xa2, 0x84, 0x42, 0x5c, 0xe8, 0x15, 0xc1, 0x36, 0x4e, 0xc9, 0xc1, 0xf9, +0xf4, 0x6c, 0x3f, 0x76, 0xbf, 0x36, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xed, 0xa2, 0x8d, 0x42, 0x58, 0xe8, 0x15, 0xc1, 0xb7, +0x17, 0x7f, 0xc0, 0x1c, 0x98, 0x78, 0x3f, 0xca, 0xf9, 0x12, 0x3f, 0x1, 0xbe, 0x23, 0x0, 0xdc, 0xa6, 0x3e, 0x42, 0xed, +0xa1, 0x1a, 0xc2, 0x1f, 0x1c, 0xe5, 0xc1, 0x55, 0xf6, 0xcd, 0x3e, 0xd9, 0x41, 0x5d, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x0, +0x93, 0x5d, 0x42, 0xec, 0xa1, 0x1a, 0xc2, 0x3e, 0x15, 0x9b, 0x40, 0x44, 0xa4, 0x22, 0x3f, 0x70, 0x22, 0x5a, 0x3f, 0x1, +0xbe, 0x26, 0x0, 0x60, 0x58, 0xf, 0xb6, 0xa4, 0xac, 0xb1, 0xc1, 0xc0, 0xba, 0x18, 0xb7, 0x0, 0x0, 0x0, 0x3f, 0x0, +0x0, 0x0, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x39, 0xbc, 0x83, 0x42, 0x96, 0x86, 0x9, 0xc2, 0x85, 0x88, 0xd2, 0xc1, 0x67, +0x2b, 0xe7, 0x3e, 0xc2, 0x87, 0x7a, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0xce, 0x79, 0x8d, 0x42, 0x96, 0x86, 0x9, 0xc2, 0xf5, +0x12, 0xa7, 0xc0, 0xc3, 0x2b, 0x19, 0x3f, 0x1d, 0x90, 0x78, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0xdc, 0xa6, 0x3e, 0x42, 0x9f, +0x55, 0xb8, 0xc0, 0x1f, 0x1c, 0xe5, 0xc1, 0x55, 0xf6, 0xcd, 0x3e, 0xd9, 0x41, 0x5d, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x39, +0xbc, 0x83, 0x42, 0x2b, 0x98, 0x20, 0xc1, 0x85, 0x88, 0xd2, 0xc1, 0x67, 0x2b, 0xe7, 0x3e, 0xc2, 0x87, 0x7a, 0x3f, 0x1, +0xbe, 0x26, 0x0, 0xce, 0x79, 0x8d, 0x42, 0x2b, 0x98, 0x20, 0xc1, 0xf5, 0x12, 0xa7, 0xc0, 0xc3, 0x2b, 0x19, 0x3f, 0x1d, +0x90, 0x78, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0xfd, 0x92, 0x5d, 0x42, 0x9f, 0x55, 0xb8, 0xc0, 0x54, 0x15, 0x9b, 0x40, 0x44, +0xa4, 0x22, 0x3f, 0x70, 0x22, 0x5a, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0xde, 0xdc, 0x27, 0x42, 0xec, 0xa1, 0x1a, 0xc2, 0xd3, +0xeb, 0x11, 0x42, 0x2, 0x12, 0x51, 0x3f, 0x5c, 0x95, 0x34, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x5c, 0x83, 0x89, 0x42, 0x95, +0x86, 0x9, 0xc2, 0x2c, 0x67, 0x8b, 0x41, 0xbf, 0x10, 0x3e, 0x3f, 0xec, 0x6a, 0x6a, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x28, +0x30, 0x71, 0x42, 0x95, 0x86, 0x9, 0xc2, 0x46, 0x6b, 0x15, 0x42, 0xc2, 0x50, 0x5b, 0x3f, 0xad, 0xc2, 0x52, 0x3f, 0x1, +0xbe, 0x26, 0x0, 0x5c, 0x83, 0x89, 0x42, 0x2b, 0x98, 0x20, 0xc1, 0x2c, 0x67, 0x8b, 0x41, 0xbf, 0x10, 0x3e, 0x3f, 0xec, +0x6a, 0x6a, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x28, 0x30, 0x71, 0x42, 0x2d, 0x98, 0x20, 0xc1, 0x46, 0x6b, 0x15, 0x42, 0xc2, +0x50, 0x5b, 0x3f, 0xad, 0xc2, 0x52, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0xde, 0xdc, 0x27, 0x42, 0x9e, 0x55, 0xb8, 0xc0, 0xd3, +0xeb, 0x11, 0x42, 0x2, 0x12, 0x51, 0x3f, 0x5c, 0x95, 0x34, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x5d, 0x22, 0x48, 0x41, 0xec, +0xa1, 0x1a, 0xc2, 0x52, 0xb8, 0x58, 0x42, 0x61, 0x88, 0x60, 0x3f, 0xe6, 0xe4, 0xf5, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0xb, +0x88, 0x35, 0x42, 0x95, 0x86, 0x9, 0xc2, 0xd0, 0xb, 0x5a, 0x42, 0xe4, 0xd6, 0x70, 0x3f, 0x37, 0xa8, 0x31, 0x3f, 0x1, +0xbe, 0x26, 0x0, 0x13, 0x99, 0xd6, 0x41, 0x95, 0x86, 0x9, 0xc2, 0x1f, 0x53, 0x83, 0x42, 0xab, 0x94, 0x7a, 0x3f, 0xa8, +0x58, 0xd, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0xb, 0x88, 0x35, 0x42, 0x2d, 0x98, 0x20, 0xc1, 0xd0, 0xb, 0x5a, 0x42, 0xe4, +0xd6, 0x70, 0x3f, 0x37, 0xa8, 0x31, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x13, 0x99, 0xd6, 0x41, 0x2d, 0x98, 0x20, 0xc1, 0x1f, +0x53, 0x83, 0x42, 0xab, 0x94, 0x7a, 0x3f, 0xa8, 0x58, 0xd, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x5d, 0x22, 0x48, 0x41, 0x9e, +0x55, 0xb8, 0xc0, 0x58, 0xb8, 0x58, 0x42, 0x61, 0x88, 0x60, 0x3f, 0xe6, 0xe4, 0xf5, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x51, +0xd0, 0xad, 0xc1, 0xec, 0xa1, 0x1a, 0xc2, 0x3d, 0xbd, 0x4c, 0x42, 0x8a, 0x1f, 0x4b, 0x3f, 0x60, 0x7b, 0x86, 0x3e, 0x1, +0xbe, 0x26, 0x0, 0xe4, 0x94, 0x95, 0x40, 0x95, 0x86, 0x9, 0xc2, 0x60, 0x8d, 0x8d, 0x42, 0x34, 0x83, 0x78, 0x3f, 0xc2, +0xdb, 0xcb, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x41, 0x26, 0x87, 0xc1, 0x95, 0x86, 0x9, 0xc2, 0x3d, 0xc7, 0x89, 0x42, 0x3e, +0x6, 0x6b, 0x3f, 0x3a, 0xab, 0x85, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0xe4, 0x94, 0x95, 0x40, 0x2d, 0x98, 0x20, 0xc1, 0x60, +0x8d, 0x8d, 0x42, 0x34, 0x83, 0x78, 0x3f, 0xc2, 0xdb, 0xcb, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x41, 0x26, 0x87, 0xc1, 0x2d, +0x98, 0x20, 0xc1, 0x3d, 0xc7, 0x89, 0x42, 0x3e, 0x6, 0x6b, 0x3f, 0x3a, 0xab, 0x85, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x51, +0xd0, 0xad, 0xc1, 0x9e, 0x55, 0xb8, 0xc0, 0x38, 0xbd, 0x4c, 0x42, 0x8a, 0x1f, 0x4b, 0x3f, 0x60, 0x7b, 0x86, 0x3e, 0x1, +0xbe, 0x26, 0x0, 0xdd, 0xa6, 0x3e, 0xc2, 0xec, 0xa1, 0x1a, 0xc2, 0x15, 0x1c, 0xe5, 0x41, 0xd5, 0x4, 0x19, 0x3f, 0x9c, +0xf8, 0xa, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x26, 0x47, 0x17, 0xc2, 0x97, 0x86, 0x9, 0xc2, 0xcf, 0x6, 0x70, 0x42, 0x6b, +0x27, 0x52, 0x3f, 0x50, 0xa3, 0x10, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x22, 0xa3, 0x58, 0xc2, 0x95, 0x86, 0x9, 0xc2, 0xde, +0x35, 0x37, 0x42, 0x92, 0x96, 0x32, 0x3f, 0x60, 0xf8, 0x7a, 0x3d, 0x1, 0xbe, 0x26, 0x0, 0x26, 0x47, 0x17, 0xc2, 0x2d, +0x98, 0x20, 0xc1, 0xc9, 0x6, 0x70, 0x42, 0x6b, 0x27, 0x52, 0x3f, 0x50, 0xa3, 0x10, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x22, +0xa3, 0x58, 0xc2, 0x2d, 0x98, 0x20, 0xc1, 0xde, 0x35, 0x37, 0x42, 0x92, 0x96, 0x32, 0x3f, 0x60, 0xf8, 0x7a, 0x3d, 0x1, +0xbe, 0x26, 0x0, 0xdd, 0xa6, 0x3e, 0xc2, 0x9e, 0x55, 0xb8, 0xc0, 0x15, 0x1c, 0xe5, 0x41, 0xd5, 0x4, 0x19, 0x3f, 0x9c, +0xf8, 0xa, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0xff, 0x92, 0x5d, 0xc2, 0xed, 0xa1, 0x1a, 0xc2, 0x9d, 0x15, 0x9b, 0xc0, 0x78, +0xb7, 0xba, 0x3e, 0x40, 0x76, 0x17, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x38, 0xbc, 0x83, 0xc2, 0x95, 0x86, 0x9, 0xc2, 0x81, +0x88, 0xd2, 0x41, 0x4d, 0x6a, 0xc, 0x3f, 0xc0, 0x7, 0xaf, 0x3c, 0x1, 0xbe, 0x26, 0x0, 0xd0, 0x79, 0x8d, 0xc2, 0x96, +0x86, 0x9, 0xc2, 0xf1, 0x12, 0xa7, 0x40, 0x7a, 0xa8, 0xcd, 0x3e, 0x60, 0xfc, 0xed, 0x3c, 0x1, 0xbe, 0x26, 0x0, 0x38, +0xbc, 0x83, 0xc2, 0x2d, 0x98, 0x20, 0xc1, 0x81, 0x88, 0xd2, 0x41, 0x4d, 0x6a, 0xc, 0x3f, 0xc0, 0x7, 0xaf, 0x3c, 0x1, +0xbe, 0x26, 0x0, 0xcf, 0x79, 0x8d, 0xc2, 0x2d, 0x98, 0x20, 0xc1, 0xda, 0x12, 0xa7, 0x40, 0x7a, 0xa8, 0xcd, 0x3e, 0x60, +0xfc, 0xed, 0x3c, 0x1, 0xbe, 0x26, 0x0, 0xff, 0x92, 0x5d, 0xc2, 0x9e, 0x55, 0xb8, 0xc0, 0x9d, 0x15, 0x9b, 0xc0, 0x78, +0xb7, 0xba, 0x3e, 0x40, 0x76, 0x17, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0xdf, 0xdc, 0x27, 0xc2, 0xed, 0xa1, 0x1a, 0xc2, 0xd8, +0xeb, 0x11, 0xc2, 0xfa, 0xb7, 0x3b, 0x3e, 0x4a, 0xd5, 0x96, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x5b, 0x83, 0x89, 0xc2, 0x96, +0x86, 0x9, 0xc2, 0x3c, 0x67, 0x8b, 0xc1, 0x83, 0xde, 0x83, 0x3e, 0xa0, 0xa8, 0xac, 0x3d, 0x1, 0xbe, 0x26, 0x0, 0x26, +0x30, 0x71, 0xc2, 0x95, 0x86, 0x9, 0xc2, 0x4e, 0x6b, 0x15, 0xc2, 0xf9, 0xbc, 0x12, 0x3e, 0x4c, 0xf5, 0x34, 0x3e, 0x1, +0xbe, 0x26, 0x0, 0x5b, 0x83, 0x89, 0xc2, 0x2d, 0x98, 0x20, 0xc1, 0x3c, 0x67, 0x8b, 0xc1, 0x83, 0xde, 0x83, 0x3e, 0xa0, +0xa8, 0xac, 0x3d, 0x1, 0xbe, 0x26, 0x0, 0x26, 0x30, 0x71, 0xc2, 0x2b, 0x98, 0x20, 0xc1, 0x4e, 0x6b, 0x15, 0xc2, 0xf9, +0xbc, 0x12, 0x3e, 0x4c, 0xf5, 0x34, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0xdf, 0xdc, 0x27, 0xc2, 0x9f, 0x55, 0xb8, 0xc0, 0xd8, +0xeb, 0x11, 0xc2, 0xfa, 0xb7, 0x3b, 0x3e, 0x4a, 0xd5, 0x96, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x45, 0x22, 0x48, 0xc1, 0xec, +0xa1, 0x1a, 0xc2, 0x55, 0xb8, 0x58, 0xc2, 0xf5, 0xbc, 0xfb, 0x3d, 0x8c, 0xd, 0x5, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x5, +0x88, 0x35, 0xc2, 0x95, 0x86, 0x9, 0xc2, 0xd3, 0xb, 0x5a, 0xc2, 0xb8, 0x91, 0x72, 0x3d, 0x92, 0xaf, 0x9c, 0x3e, 0x1, +0xbe, 0x26, 0x0, 0x12, 0x99, 0xd6, 0xc1, 0x95, 0x86, 0x9, 0xc2, 0x20, 0x53, 0x83, 0xc2, 0x9c, 0x6a, 0xad, 0x3c, 0xb2, +0x4e, 0xe5, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x7, 0x88, 0x35, 0xc2, 0x2b, 0x98, 0x20, 0xc1, 0xd5, 0xb, 0x5a, 0xc2, 0xb8, +0x91, 0x72, 0x3d, 0x92, 0xaf, 0x9c, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0xf, 0x99, 0xd6, 0xc1, 0x2b, 0x98, 0x20, 0xc1, 0x20, +0x53, 0x83, 0xc2, 0x9c, 0x6a, 0xad, 0x3c, 0xb2, 0x4e, 0xe5, 0x3e, 0x1, 0xbe, 0x26, 0x0, 0x45, 0x22, 0x48, 0xc1, 0x9f, +0x55, 0xb8, 0xc0, 0x55, 0xb8, 0x58, 0xc2, 0xf5, 0xbc, 0xfb, 0x3d, 0x8c, 0xd, 0x5, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x54, +0xd0, 0xad, 0x41, 0xed, 0xa1, 0x1a, 0xc2, 0x39, 0xbd, 0x4c, 0xc2, 0x1b, 0x82, 0x53, 0x3e, 0x50, 0xc2, 0x3c, 0x3f, 0x1, +0xbe, 0x26, 0x0, 0xd6, 0x94, 0x95, 0xc0, 0x95, 0x86, 0x9, 0xc2, 0x5f, 0x8d, 0x8d, 0xc2, 0x80, 0x99, 0xef, 0x3c, 0x1f, +0x12, 0x1a, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x4d, 0x26, 0x87, 0x41, 0x95, 0x86, 0x9, 0xc2, 0x3e, 0xc7, 0x89, 0xc2, 0x10, +0xce, 0xa7, 0x3d, 0x62, 0x2a, 0x3d, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0xd6, 0x94, 0x95, 0xc0, 0x2c, 0x98, 0x20, 0xc1, 0x5f, +0x8d, 0x8d, 0xc2, 0x80, 0x99, 0xef, 0x3c, 0x1f, 0x12, 0x1a, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x4d, 0x26, 0x87, 0x41, 0x2c, +0x98, 0x20, 0xc1, 0x3e, 0xc7, 0x89, 0xc2, 0x10, 0xce, 0xa7, 0x3d, 0x62, 0x2a, 0x3d, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x54, +0xd0, 0xad, 0x41, 0x9f, 0x55, 0xb8, 0xc0, 0x39, 0xbd, 0x4c, 0xc2, 0x1b, 0x82, 0x53, 0x3e, 0x50, 0xc2, 0x3c, 0x3f, 0x1, +0xbe, 0x26, 0x0, 0x25, 0x47, 0x17, 0x42, 0x95, 0x86, 0x9, 0xc2, 0xce, 0x6, 0x70, 0xc2, 0x52, 0x62, 0x37, 0x3e, 0x2c, +0xd7, 0x5b, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x21, 0xa3, 0x58, 0x42, 0x96, 0x86, 0x9, 0xc2, 0xe3, 0x35, 0x37, 0xc2, 0xdd, +0xd2, 0x9a, 0x3e, 0x7a, 0x50, 0x70, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x23, 0x47, 0x17, 0x42, 0x2c, 0x98, 0x20, 0xc1, 0xcd, +0x6, 0x70, 0xc2, 0x52, 0x62, 0x37, 0x3e, 0x2c, 0xd7, 0x5b, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0x21, 0xa3, 0x58, 0x42, 0x2c, +0x98, 0x20, 0xc1, 0xe3, 0x35, 0x37, 0xc2, 0xdd, 0xd2, 0x9a, 0x3e, 0x7a, 0x50, 0x70, 0x3f, 0x1, 0xbe, 0x26, 0x0, 0xc3, +0x33, 0x5d, 0x42, 0xc1, 0x82, 0x23, 0xc2, 0x3, 0xfe, 0xb9, 0x40, 0x68, 0xb1, 0x44, 0x3f, 0xea, 0x3f, 0x43, 0x3f, 0x1, +0xbe, 0x29, 0x0, 0x77, 0x4a, 0x25, 0x42, 0xbf, 0x82, 0x23, 0xc2, 0x4, 0xd4, 0x14, 0x42, 0x87, 0x17, 0x60, 0x3f, 0xb9, +0x8a, 0xd, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x7, 0x9d, 0x17, 0xb6, 0x50, 0x6e, 0xc3, 0xc1, 0xea, 0xa9, 0x4a, 0xb6, 0x8c, +0x49, 0xff, 0x3e, 0xd2, 0x91, 0xfc, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0x51, 0xe2, 0x88, 0x42, 0x6b, 0x67, 0x12, 0xc2, 0xfa, +0xfa, 0x94, 0x41, 0x2d, 0xb3, 0x64, 0x3f, 0xc8, 0x5, 0x47, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x41, 0x8b, 0x6e, 0x42, 0x6a, +0x67, 0x12, 0xc2, 0xe4, 0x9a, 0x19, 0x42, 0x12, 0xf6, 0x75, 0x3f, 0xd3, 0x2f, 0x25, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xc3, +0x33, 0x5d, 0x42, 0x81, 0x5c, 0xff, 0xc0, 0x3, 0xfe, 0xb9, 0x40, 0x68, 0xb1, 0x44, 0x3f, 0xea, 0x3f, 0x43, 0x3f, 0x1, +0xbe, 0x29, 0x0, 0x51, 0xe2, 0x88, 0x42, 0x93, 0x1b, 0x44, 0xc1, 0xfa, 0xfa, 0x94, 0x41, 0x2d, 0xb3, 0x64, 0x3f, 0xc8, +0x5, 0x47, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x41, 0x8b, 0x6e, 0x42, 0x8f, 0x1b, 0x44, 0xc1, 0xe4, 0x9a, 0x19, 0x42, 0x12, +0xf6, 0x75, 0x3f, 0xd3, 0x2f, 0x25, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x77, 0x4a, 0x25, 0x42, 0x75, 0x5c, 0xff, 0xc0, 0x4, +0xd4, 0x14, 0x42, 0x87, 0x17, 0x60, 0x3f, 0xb9, 0x8a, 0xd, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xf3, 0xf9, 0x38, 0x41, 0xbe, +0x82, 0x23, 0xc2, 0x5c, 0x8f, 0x59, 0x42, 0xa0, 0xa6, 0x56, 0x3f, 0x58, 0x3, 0xa4, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0xe7, +0xb2, 0x31, 0x42, 0x69, 0x67, 0x12, 0xc2, 0x36, 0x2e, 0x5d, 0x42, 0xd2, 0x34, 0x7c, 0x3f, 0xcc, 0x9b, 0xfb, 0x3e, 0x1, +0xbe, 0x29, 0x0, 0xc, 0x66, 0xcd, 0x41, 0x68, 0x67, 0x12, 0xc2, 0xa4, 0x3d, 0x84, 0x42, 0x29, 0x42, 0x76, 0x3f, 0xc, +0x98, 0xb0, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0xe7, 0xb2, 0x31, 0x42, 0x8d, 0x1b, 0x44, 0xc1, 0x36, 0x2e, 0x5d, 0x42, 0xd2, +0x34, 0x7c, 0x3f, 0xcc, 0x9b, 0xfb, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0xc, 0x66, 0xcd, 0x41, 0x89, 0x1b, 0x44, 0xc1, 0xa4, +0x3d, 0x84, 0x42, 0x29, 0x42, 0x76, 0x3f, 0xc, 0x98, 0xb0, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0xfc, 0xf9, 0x38, 0x41, 0x6d, +0x5c, 0xff, 0xc0, 0x53, 0x8f, 0x59, 0x42, 0xa0, 0xa6, 0x56, 0x3f, 0x58, 0x3, 0xa4, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0xcd, +0xee, 0xb4, 0xc1, 0xbe, 0x82, 0x23, 0xc2, 0xfa, 0x30, 0x4b, 0x42, 0xd7, 0xf9, 0x2b, 0x3f, 0x4, 0x89, 0x1d, 0x3e, 0x1, +0xbe, 0x29, 0x0, 0xd0, 0x12, 0x5c, 0x40, 0x67, 0x67, 0x12, 0xc2, 0x99, 0xb1, 0x8d, 0x42, 0x57, 0x22, 0x64, 0x3f, 0xc0, +0x13, 0x53, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0xfd, 0xbe, 0x90, 0xc1, 0x67, 0x67, 0x12, 0xc2, 0xe8, 0x2a, 0x89, 0x42, 0xc0, +0x3f, 0x49, 0x3f, 0xe0, 0x55, 0xcf, 0x3d, 0x1, 0xbe, 0x29, 0x0, 0xd0, 0x12, 0x5c, 0x40, 0x88, 0x1b, 0x44, 0xc1, 0x99, +0xb1, 0x8d, 0x42, 0x57, 0x22, 0x64, 0x3f, 0xc0, 0x13, 0x53, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0xfd, 0xbe, 0x90, 0xc1, 0x88, +0x1b, 0x44, 0xc1, 0xe8, 0x2a, 0x89, 0x42, 0xc0, 0x3f, 0x49, 0x3f, 0xe0, 0x55, 0xcf, 0x3d, 0x1, 0xbe, 0x29, 0x0, 0xc9, +0xee, 0xb4, 0xc1, 0x6d, 0x5c, 0xff, 0xc0, 0xf1, 0x30, 0x4b, 0x42, 0xd7, 0xf9, 0x2b, 0x3f, 0x4, 0x89, 0x1d, 0x3e, 0x1, +0xbe, 0x29, 0x0, 0x2c, 0x9f, 0x40, 0xc2, 0xbf, 0x82, 0x23, 0xc2, 0xb3, 0x6b, 0xde, 0x41, 0x38, 0xbc, 0xe0, 0x3e, 0x68, +0xa2, 0xef, 0x3d, 0x1, 0xbe, 0x29, 0x0, 0x85, 0x71, 0x1b, 0xc2, 0x67, 0x67, 0x12, 0xc2, 0x98, 0x59, 0x6d, 0x42, 0x97, +0xad, 0x25, 0x3f, 0xc0, 0x13, 0xfa, 0x3c, 0x1, 0xbe, 0x29, 0x0, 0x20, 0xcd, 0x5b, 0xc2, 0x69, 0x67, 0x12, 0xc2, 0xea, +0x66, 0x33, 0x42, 0xeb, 0x1f, 0x0, 0x3f, 0x0, 0xe5, 0xef, 0x3b, 0x1, 0xbe, 0x29, 0x0, 0x85, 0x71, 0x1b, 0xc2, 0x8c, +0x1b, 0x44, 0xc1, 0x98, 0x59, 0x6d, 0x42, 0x97, 0xad, 0x25, 0x3f, 0xc0, 0x13, 0xfa, 0x3c, 0x1, 0xbe, 0x29, 0x0, 0x20, +0xcd, 0x5b, 0xc2, 0x8c, 0x1b, 0x44, 0xc1, 0xea, 0x66, 0x33, 0x42, 0xeb, 0x1f, 0x0, 0x3f, 0x0, 0xe5, 0xef, 0x3b, 0x1, +0xbe, 0x29, 0x0, 0x2c, 0x9f, 0x40, 0xc2, 0x75, 0x5c, 0xff, 0xc0, 0xb3, 0x6b, 0xde, 0x41, 0x38, 0xbc, 0xe0, 0x3e, 0x68, +0xa2, 0xef, 0x3d, 0x1, 0xbe, 0x29, 0x0, 0xc2, 0x33, 0x5d, 0xc2, 0xc1, 0x82, 0x23, 0xc2, 0x29, 0xfe, 0xb9, 0xc0, 0x91, +0x60, 0x6a, 0x3e, 0x9c, 0x47, 0x65, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0x37, 0xa2, 0x84, 0xc2, 0x69, 0x67, 0x12, 0xc2, 0x46, +0x4e, 0xc9, 0x41, 0x56, 0x63, 0xb1, 0x3e, 0x40, 0xca, 0x1, 0x3d, 0x1, 0xbe, 0x29, 0x0, 0xef, 0xa2, 0x8d, 0xc2, 0x6b, +0x67, 0x12, 0xc2, 0xfb, 0x17, 0x7f, 0x40, 0x5f, 0x44, 0x5b, 0x3e, 0x48, 0xd1, 0xca, 0x3d, 0x1, 0xbe, 0x29, 0x0, 0x37, +0xa2, 0x84, 0xc2, 0x90, 0x1b, 0x44, 0xc1, 0x46, 0x4e, 0xc9, 0x41, 0x56, 0x63, 0xb1, 0x3e, 0x40, 0xca, 0x1, 0x3d, 0x1, +0xbe, 0x29, 0x0, 0xef, 0xa2, 0x8d, 0xc2, 0x94, 0x1b, 0x44, 0xc1, 0xfb, 0x17, 0x7f, 0x40, 0x5f, 0x44, 0x5b, 0x3e, 0x48, +0xd1, 0xca, 0x3d, 0x1, 0xbe, 0x29, 0x0, 0xc2, 0x33, 0x5d, 0xc2, 0x81, 0x5c, 0xff, 0xc0, 0x29, 0xfe, 0xb9, 0xc0, 0x91, +0x60, 0x6a, 0x3e, 0x9c, 0x47, 0x65, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0x74, 0x4a, 0x25, 0xc2, 0xc2, 0x82, 0x23, 0xc2, 0x6, +0xd4, 0x14, 0xc2, 0xa3, 0x8f, 0xf9, 0x3d, 0xe, 0xe, 0xde, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0x50, 0xe2, 0x88, 0xc2, 0x6b, +0x67, 0x12, 0xc2, 0x4, 0xfb, 0x94, 0xc1, 0xfb, 0xb2, 0xd4, 0x3d, 0x24, 0x30, 0x56, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0x3f, +0x8b, 0x6e, 0xc2, 0x6c, 0x67, 0x12, 0xc2, 0xe9, 0x9a, 0x19, 0xc2, 0xa0, 0x37, 0x15, 0x3d, 0xfc, 0xc3, 0xae, 0x3e, 0x1, +0xbe, 0x29, 0x0, 0x50, 0xe2, 0x88, 0xc2, 0x98, 0x1b, 0x44, 0xc1, 0x4, 0xfb, 0x94, 0xc1, 0xfb, 0xb2, 0xd4, 0x3d, 0x24, +0x30, 0x56, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0x3f, 0x8b, 0x6e, 0xc2, 0x9c, 0x1b, 0x44, 0xc1, 0xe9, 0x9a, 0x19, 0xc2, 0xa0, +0x37, 0x15, 0x3d, 0xfc, 0xc3, 0xae, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0x74, 0x4a, 0x25, 0xc2, 0x8d, 0x5c, 0xff, 0xc0, 0x6, +0xd4, 0x14, 0xc2, 0xa3, 0x8f, 0xf9, 0x3d, 0xe, 0xe, 0xde, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0xf1, 0xf9, 0x38, 0xc1, 0xc3, +0x82, 0x23, 0xc2, 0x5c, 0x8f, 0x59, 0xc2, 0xb1, 0x8b, 0x22, 0x3e, 0x26, 0x90, 0x2a, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xe3, +0xb2, 0x31, 0xc2, 0x6d, 0x67, 0x12, 0xc2, 0x38, 0x2e, 0x5d, 0xc2, 0x41, 0x2a, 0x45, 0x3c, 0xd6, 0x87, 0xfd, 0x3e, 0x1, +0xbe, 0x29, 0x0, 0x7, 0x66, 0xcd, 0xc1, 0x6d, 0x67, 0x12, 0xc2, 0xa6, 0x3d, 0x84, 0xc2, 0x2e, 0x75, 0x10, 0x3d, 0xcc, +0x45, 0x24, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xe3, 0xb2, 0x31, 0xc2, 0xa2, 0x1b, 0x44, 0xc1, 0x3d, 0x2e, 0x5d, 0xc2, 0x41, +0x2a, 0x45, 0x3c, 0xd6, 0x87, 0xfd, 0x3e, 0x1, 0xbe, 0x29, 0x0, 0x7, 0x66, 0xcd, 0xc1, 0xa2, 0x1b, 0x44, 0xc1, 0xa6, +0x3d, 0x84, 0xc2, 0x2e, 0x75, 0x10, 0x3d, 0xcc, 0x45, 0x24, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xf1, 0xf9, 0x38, 0xc1, 0x95, +0x5c, 0xff, 0xc0, 0x5c, 0x8f, 0x59, 0xc2, 0x6e, 0x8b, 0x22, 0x3e, 0x26, 0x90, 0x2a, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xcb, +0xee, 0xb4, 0x41, 0xc3, 0x82, 0x23, 0xc2, 0xf6, 0x30, 0x4b, 0xc2, 0x49, 0x9f, 0xa6, 0x3e, 0x7f, 0x2f, 0x55, 0x3f, 0x1, +0xbe, 0x29, 0x0, 0xb0, 0x12, 0x5c, 0xc0, 0x6f, 0x67, 0x12, 0xc2, 0x98, 0xb1, 0x8d, 0xc2, 0x22, 0x39, 0xd9, 0x3d, 0xe2, +0xcc, 0x47, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x3, 0xbf, 0x90, 0x41, 0x6e, 0x67, 0x12, 0xc2, 0xe7, 0x2a, 0x89, 0xc2, 0xee, +0x26, 0x58, 0x3e, 0x5, 0xa7, 0x62, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xb0, 0x12, 0x5c, 0xc0, 0xa2, 0x1b, 0x44, 0xc1, 0x98, +0xb1, 0x8d, 0xc2, 0x22, 0x39, 0xd9, 0x3d, 0xe2, 0xcc, 0x47, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x3, 0xbf, 0x90, 0x41, 0xa2, +0x1b, 0x44, 0xc1, 0xe7, 0x2a, 0x89, 0xc2, 0xee, 0x26, 0x58, 0x3e, 0x5, 0xa7, 0x62, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xcb, +0xee, 0xb4, 0x41, 0x95, 0x5c, 0xff, 0xc0, 0xf6, 0x30, 0x4b, 0xc2, 0x49, 0x9f, 0xa6, 0x3e, 0x7f, 0x2f, 0x55, 0x3f, 0x1, +0xbe, 0x29, 0x0, 0x2f, 0x9f, 0x40, 0x42, 0xc2, 0x82, 0x23, 0xc2, 0xb8, 0x6b, 0xde, 0xc1, 0x5f, 0xeb, 0xe, 0x3f, 0x73, +0x9d, 0x5e, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x86, 0x71, 0x1b, 0x42, 0x6d, 0x67, 0x12, 0xc2, 0x97, 0x59, 0x6d, 0xc2, 0xeb, +0x37, 0xb3, 0x3e, 0x33, 0xc1, 0x74, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x24, 0xcd, 0x5b, 0x42, 0x6d, 0x67, 0x12, 0xc2, 0xeb, +0x66, 0x33, 0xc2, 0x22, 0x53, 0xfe, 0x3e, 0xf7, 0xb1, 0x7a, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x84, 0x71, 0x1b, 0x42, 0xa4, +0x1b, 0x44, 0xc1, 0x99, 0x59, 0x6d, 0xc2, 0xeb, 0x37, 0xb3, 0x3e, 0x33, 0xc1, 0x74, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x24, +0xcd, 0x5b, 0x42, 0xa0, 0x1b, 0x44, 0xc1, 0xeb, 0x66, 0x33, 0xc2, 0x22, 0x53, 0xfe, 0x3e, 0xf7, 0xb1, 0x7a, 0x3f, 0x1, +0xbe, 0x29, 0x0, 0x2f, 0x9f, 0x40, 0x42, 0x8d, 0x5c, 0xff, 0xc0, 0xb8, 0x6b, 0xde, 0xc1, 0x5f, 0xeb, 0xe, 0x3f, 0x73, +0x9d, 0x5e, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x38, 0xa2, 0x84, 0x42, 0x6d, 0x67, 0x12, 0xc2, 0x44, 0x4e, 0xc9, 0xc1, 0xe1, +0x97, 0x26, 0x3f, 0x2e, 0x75, 0x74, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xf1, 0xa2, 0x8d, 0x42, 0x6b, 0x67, 0x12, 0xc2, 0x1a, +0x18, 0x7f, 0xc0, 0x75, 0x78, 0x48, 0x3f, 0xa8, 0x37, 0x63, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0x38, 0xa2, 0x84, 0x42, 0x9c, +0x1b, 0x44, 0xc1, 0x44, 0x4e, 0xc9, 0xc1, 0xe1, 0x97, 0x26, 0x3f, 0x2e, 0x75, 0x74, 0x3f, 0x1, 0xbe, 0x29, 0x0, 0xf1, +0xa2, 0x8d, 0x42, 0x97, 0x1b, 0x44, 0xc1, 0x1a, 0x18, 0x7f, 0xc0, 0x75, 0x78, 0x48, 0x3f, 0xa8, 0x37, 0x63, 0x3f, 0x1, +0xbe, 0x29, 0x0, 0x85, 0x41, 0x5c, 0x42, 0x77, 0x84, 0x23, 0xc2, 0xc, 0xa4, 0xf7, 0xc0, 0x1e, 0xff, 0x59, 0x3f, 0xc2, +0x15, 0x18, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xbc, 0x62, 0x44, 0x42, 0x75, 0x84, 0x23, 0xc2, 0x4, 0xd7, 0xd0, 0x41, 0xa0, +0xfb, 0x56, 0x3f, 0x62, 0x4d, 0xbd, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0xfa, 0x3, 0x80, 0xb7, 0xbc, 0x71, 0xc3, 0xc1, 0x66, +0xf4, 0x35, 0xb6, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x10, 0xd4, 0x8d, 0x42, 0x20, +0x69, 0x12, 0xc2, 0x83, 0x82, 0xc1, 0x3f, 0xf3, 0x3e, 0x76, 0x3f, 0xae, 0xf3, 0xb, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x2a, +0x4f, 0x86, 0x42, 0x1f, 0x69, 0x12, 0xc2, 0xb9, 0xaa, 0xb6, 0x41, 0xde, 0x58, 0x74, 0x3f, 0x82, 0x89, 0xcf, 0x3e, 0x1, +0xbe, 0x2c, 0x0, 0x85, 0x41, 0x5c, 0x42, 0x31, 0x6a, 0xff, 0xc0, 0xc, 0xa4, 0xf7, 0xc0, 0x1e, 0xff, 0x59, 0x3f, 0xc2, +0x15, 0x18, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x10, 0xd4, 0x8d, 0x42, 0x6c, 0x22, 0x44, 0xc1, 0x83, 0x82, 0xc1, 0x3f, 0xf3, +0x3e, 0x76, 0x3f, 0xae, 0xf3, 0xb, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x2a, 0x4f, 0x86, 0x42, 0x68, 0x22, 0x44, 0xc1, 0xb9, +0xaa, 0xb6, 0x41, 0xde, 0x58, 0x74, 0x3f, 0x82, 0x89, 0xcf, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0xbc, 0x62, 0x44, 0x42, 0x25, +0x6a, 0xff, 0xc0, 0xfe, 0xd6, 0xd0, 0x41, 0xa0, 0xfb, 0x56, 0x3f, 0x62, 0x4d, 0xbd, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0x65, +0x1, 0xc3, 0x41, 0x74, 0x84, 0x23, 0xc2, 0xff, 0xe8, 0x47, 0x42, 0x9d, 0xbe, 0x32, 0x3f, 0x84, 0xd2, 0x47, 0x3e, 0x1, +0xbe, 0x2c, 0x0, 0xb5, 0xed, 0x61, 0x42, 0x1f, 0x69, 0x12, 0xc2, 0x19, 0x9f, 0x2b, 0x42, 0x5b, 0xb2, 0x66, 0x3f, 0x94, +0x80, 0x88, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0xe2, 0xa1, 0x23, 0x42, 0x1d, 0x69, 0x12, 0xc2, 0xbe, 0xc7, 0x67, 0x42, 0xdb, +0xdd, 0x4f, 0x3f, 0x28, 0x5f, 0x20, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0xb6, 0xed, 0x61, 0x42, 0x64, 0x22, 0x44, 0xc1, 0x17, +0x9f, 0x2b, 0x42, 0x5b, 0xb2, 0x66, 0x3f, 0x94, 0x80, 0x88, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0xe2, 0xa1, 0x23, 0x42, 0x62, +0x22, 0x44, 0xc1, 0xbe, 0xc7, 0x67, 0x42, 0xdb, 0xdd, 0x4f, 0x3f, 0x28, 0x5f, 0x20, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0x63, +0x1, 0xc3, 0x41, 0x1d, 0x6a, 0xff, 0xc0, 0xfd, 0xe8, 0x47, 0x42, 0x9d, 0xbe, 0x32, 0x3f, 0x84, 0xd2, 0x47, 0x3e, 0x1, +0xbe, 0x2c, 0x0, 0xdc, 0x7d, 0x1a, 0xc1, 0x74, 0x84, 0x23, 0xc2, 0x9b, 0xa, 0x5b, 0x42, 0x57, 0x3f, 0xf6, 0x3e, 0xe4, +0x47, 0xc, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0x88, 0xce, 0xa3, 0x41, 0x1d, 0x69, 0x12, 0xc2, 0x33, 0xd2, 0x87, 0x42, 0xc0, +0xeb, 0x2f, 0x3f, 0x70, 0xfa, 0x9a, 0x3d, 0x1, 0xbe, 0x2c, 0x0, 0xcc, 0xc5, 0x76, 0xbf, 0x1d, 0x69, 0x12, 0xc2, 0xf2, +0xd8, 0x8d, 0x42, 0x2f, 0xe1, 0xc, 0x3f, 0x80, 0xea, 0x1f, 0x3d, 0x1, 0xbe, 0x2c, 0x0, 0x8b, 0xce, 0xa3, 0x41, 0x60, +0x22, 0x44, 0xc1, 0x32, 0xd2, 0x87, 0x42, 0xc0, 0xeb, 0x2f, 0x3f, 0x70, 0xfa, 0x9a, 0x3d, 0x1, 0xbe, 0x2c, 0x0, 0xac, +0xc5, 0x76, 0xbf, 0x60, 0x22, 0x44, 0xc1, 0xf1, 0xd8, 0x8d, 0x42, 0x2f, 0xe1, 0xc, 0x3f, 0x80, 0xea, 0x1f, 0x3d, 0x1, +0xbe, 0x2c, 0x0, 0xe6, 0x7d, 0x1a, 0xc1, 0x1d, 0x6a, 0xff, 0xc0, 0x97, 0xa, 0x5b, 0x42, 0x57, 0x3f, 0xf6, 0x3e, 0xe4, +0x47, 0xc, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0xfc, 0xfe, 0x1f, 0xc2, 0x75, 0x84, 0x23, 0xc2, 0x9c, 0x81, 0x1a, 0x42, 0x23, +0xbb, 0x8a, 0x3e, 0x60, 0xb9, 0x5e, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0xf4, 0xcf, 0xba, 0xc1, 0x1d, 0x69, 0x12, 0xc2, 0xd0, +0xf3, 0x85, 0x42, 0x82, 0xae, 0xcd, 0x3e, 0x40, 0xc5, 0x3f, 0x3d, 0x1, 0xbe, 0x2c, 0x0, 0x9, 0xdf, 0x29, 0xc2, 0x1e, +0x69, 0x12, 0xc2, 0x66, 0x3f, 0x63, 0x42, 0x34, 0xf2, 0x89, 0x3e, 0x90, 0xc3, 0xc7, 0x3d, 0x1, 0xbe, 0x2c, 0x0, 0xf2, +0xcf, 0xba, 0xc1, 0x62, 0x22, 0x44, 0xc1, 0xcf, 0xf3, 0x85, 0x42, 0x82, 0xae, 0xcd, 0x3e, 0x40, 0xc5, 0x3f, 0x3d, 0x1, +0xbe, 0x2c, 0x0, 0x9, 0xdf, 0x29, 0xc2, 0x64, 0x22, 0x44, 0xc1, 0x66, 0x3f, 0x63, 0x42, 0x34, 0xf2, 0x89, 0x3e, 0x90, +0xc3, 0xc7, 0x3d, 0x1, 0xbe, 0x2c, 0x0, 0xfe, 0xfe, 0x1f, 0xc2, 0x25, 0x6a, 0xff, 0xc0, 0x99, 0x81, 0x1a, 0x42, 0x23, +0xbb, 0x8a, 0x3e, 0x60, 0xb9, 0x5e, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0x8c, 0x41, 0x5c, 0xc2, 0x77, 0x84, 0x23, 0xc2, 0xf3, +0xa3, 0xf7, 0x40, 0x8a, 0x3, 0x18, 0x3e, 0x7c, 0xd4, 0xcf, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0xaa, 0x9, 0x69, 0xc2, 0x1f, +0x69, 0x12, 0xc2, 0x3e, 0xd6, 0x21, 0x42, 0xa6, 0x7b, 0x1d, 0x3e, 0x8c, 0xa6, 0x43, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0x33, +0x80, 0x87, 0xc2, 0x20, 0x69, 0x12, 0xc2, 0xc8, 0xff, 0xa7, 0x41, 0x47, 0xe7, 0x9c, 0x3d, 0xa6, 0x99, 0x9e, 0x3e, 0x1, +0xbe, 0x2c, 0x0, 0xac, 0x9, 0x69, 0xc2, 0x68, 0x22, 0x44, 0xc1, 0x39, 0xd6, 0x21, 0x42, 0xa6, 0x7b, 0x1d, 0x3e, 0x8c, +0xa6, 0x43, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0x33, 0x80, 0x87, 0xc2, 0x6c, 0x22, 0x44, 0xc1, 0xc8, 0xff, 0xa7, 0x41, 0x47, +0xe7, 0x9c, 0x3d, 0xa6, 0x99, 0x9e, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0x8c, 0x41, 0x5c, 0xc2, 0x31, 0x6a, 0xff, 0xc0, 0xf3, +0xa3, 0xf7, 0x40, 0x8a, 0x3, 0x18, 0x3e, 0x7c, 0xd4, 0xcf, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0xc5, 0x62, 0x44, 0xc2, 0x78, +0x84, 0x23, 0xc2, 0xc, 0xd7, 0xd0, 0xc1, 0xc3, 0x11, 0x24, 0x3e, 0x4f, 0x59, 0x21, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x13, +0xd4, 0x8d, 0xc2, 0x21, 0x69, 0x12, 0xc2, 0xe8, 0x82, 0xc1, 0xbf, 0xd8, 0x10, 0x1c, 0x3d, 0xa4, 0x18, 0xe8, 0x3e, 0x1, +0xbe, 0x2c, 0x0, 0x2f, 0x4f, 0x86, 0xc2, 0x22, 0x69, 0x12, 0xc2, 0xc3, 0xaa, 0xb6, 0xc1, 0x22, 0x72, 0x3a, 0x3d, 0x3e, +0x3b, 0x18, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x13, 0xd4, 0x8d, 0xc2, 0x70, 0x22, 0x44, 0xc1, 0xe8, 0x82, 0xc1, 0xbf, 0xd8, +0x10, 0x1c, 0x3d, 0xa4, 0x18, 0xe8, 0x3e, 0x1, 0xbe, 0x2c, 0x0, 0x2f, 0x4f, 0x86, 0xc2, 0x74, 0x22, 0x44, 0xc1, 0xc3, +0xaa, 0xb6, 0xc1, 0x22, 0x72, 0x3a, 0x3d, 0x3e, 0x3b, 0x18, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xc5, 0x62, 0x44, 0xc2, 0x3d, +0x6a, 0xff, 0xc0, 0xc, 0xd7, 0xd0, 0xc1, 0xc3, 0x11, 0x24, 0x3e, 0x4f, 0x59, 0x21, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x75, +0x1, 0xc3, 0xc1, 0x79, 0x84, 0x23, 0xc2, 0x1, 0xe9, 0x47, 0xc2, 0xc7, 0x82, 0x9a, 0x3e, 0x5f, 0xb, 0x4e, 0x3f, 0x1, +0xbe, 0x2c, 0x0, 0xc0, 0xed, 0x61, 0xc2, 0x23, 0x69, 0x12, 0xc2, 0x1a, 0x9f, 0x2b, 0xc2, 0x26, 0x6d, 0xca, 0x3d, 0xb6, +0xbf, 0x3b, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xea, 0xa1, 0x23, 0xc2, 0x23, 0x69, 0x12, 0xc2, 0xc4, 0xc7, 0x67, 0xc2, 0x94, +0x88, 0x40, 0x3e, 0x36, 0xe8, 0x57, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xc1, 0xed, 0x61, 0xc2, 0x78, 0x22, 0x44, 0xc1, 0x1f, +0x9f, 0x2b, 0xc2, 0x26, 0x6d, 0xca, 0x3d, 0xb6, 0xbf, 0x3b, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xea, 0xa1, 0x23, 0xc2, 0x7b, +0x22, 0x44, 0xc1, 0xc4, 0xc7, 0x67, 0xc2, 0x94, 0x88, 0x40, 0x3e, 0x36, 0xe8, 0x57, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x7c, +0x1, 0xc3, 0xc1, 0x45, 0x6a, 0xff, 0xc0, 0x3, 0xe9, 0x47, 0xc2, 0xc7, 0x82, 0x9a, 0x3e, 0x5f, 0xb, 0x4e, 0x3f, 0x1, +0xbe, 0x2c, 0x0, 0xc0, 0x7d, 0x1a, 0x41, 0x79, 0x84, 0x23, 0xc2, 0x9e, 0xa, 0x5b, 0xc2, 0x54, 0xe0, 0x4, 0x3f, 0x7, +0xee, 0x5c, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x91, 0xce, 0xa3, 0xc1, 0x24, 0x69, 0x12, 0xc2, 0x33, 0xd2, 0x87, 0xc2, 0x80, +0x28, 0xa0, 0x3e, 0xb2, 0xa0, 0x6c, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x5d, 0xc3, 0x76, 0x3f, 0x24, 0x69, 0x12, 0xc2, 0xf3, +0xd8, 0x8d, 0xc2, 0xa3, 0x3d, 0xe6, 0x3e, 0x69, 0x1, 0x76, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x91, 0xce, 0xa3, 0xc1, 0x7b, +0x22, 0x44, 0xc1, 0x33, 0xd2, 0x87, 0xc2, 0x80, 0x28, 0xa0, 0x3e, 0xb2, 0xa0, 0x6c, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x5d, +0xc3, 0x76, 0x3f, 0x7b, 0x22, 0x44, 0xc1, 0xf3, 0xd8, 0x8d, 0xc2, 0xa3, 0x3d, 0xe6, 0x3e, 0x69, 0x1, 0x76, 0x3f, 0x1, +0xbe, 0x2c, 0x0, 0xc0, 0x7d, 0x1a, 0x41, 0x45, 0x6a, 0xff, 0xc0, 0x9e, 0xa, 0x5b, 0xc2, 0x54, 0xe0, 0x4, 0x3f, 0x7, +0xee, 0x5c, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xf2, 0xfe, 0x1f, 0x42, 0x78, 0x84, 0x23, 0xc2, 0x9b, 0x81, 0x1a, 0xc2, 0x6e, +0xa2, 0x3a, 0x3f, 0xa8, 0x51, 0x48, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xe4, 0xcf, 0xba, 0x41, 0x23, 0x69, 0x12, 0xc2, 0xd1, +0xf3, 0x85, 0xc2, 0xbf, 0x28, 0x19, 0x3f, 0xac, 0x3, 0x74, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x0, 0xdf, 0x29, 0x42, 0x23, +0x69, 0x12, 0xc2, 0x6e, 0x3f, 0x63, 0xc2, 0xe6, 0x6, 0x3b, 0x3f, 0x8e, 0x7, 0x67, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xdd, +0xcf, 0xba, 0x41, 0x7b, 0x22, 0x44, 0xc1, 0xd2, 0xf3, 0x85, 0xc2, 0xbf, 0x28, 0x19, 0x3f, 0xac, 0x3, 0x74, 0x3f, 0x1, +0xbe, 0x2c, 0x0, 0x0, 0xdf, 0x29, 0x42, 0x79, 0x22, 0x44, 0xc1, 0x6e, 0x3f, 0x63, 0xc2, 0xe6, 0x6, 0x3b, 0x3f, 0x8e, +0x7, 0x67, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xf2, 0xfe, 0x1f, 0x42, 0x3d, 0x6a, 0xff, 0xc0, 0x9b, 0x81, 0x1a, 0xc2, 0x6e, +0xa2, 0x3a, 0x3f, 0xa8, 0x51, 0x48, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xa1, 0x9, 0x69, 0x42, 0x22, 0x69, 0x12, 0xc2, 0x3d, +0xd6, 0x21, 0xc2, 0x16, 0xa1, 0x58, 0x3f, 0x5d, 0x16, 0x4f, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x2f, 0x80, 0x87, 0x42, 0x21, +0x69, 0x12, 0xc2, 0xc9, 0xff, 0xa7, 0xc1, 0x17, 0x63, 0x6c, 0x3f, 0x2d, 0xb3, 0x30, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0xa1, +0x9, 0x69, 0x42, 0x75, 0x22, 0x44, 0xc1, 0x3d, 0xd6, 0x21, 0xc2, 0x16, 0xa1, 0x58, 0x3f, 0x5d, 0x16, 0x4f, 0x3f, 0x1, +0xbe, 0x2c, 0x0, 0x2f, 0x80, 0x87, 0x42, 0x71, 0x22, 0x44, 0xc1, 0xc9, 0xff, 0xa7, 0xc1, 0x17, 0x63, 0x6c, 0x3f, 0x2d, +0xb3, 0x30, 0x3f, 0x1, 0xbe, 0x2c, 0x0, 0x8f, 0x41, 0x5c, 0x42, 0x86, 0xce, 0x21, 0xc2, 0x24, 0xa4, 0xf7, 0x40, 0x98, +0x69, 0x7, 0x3f, 0x30, 0x6a, 0xfe, 0x3d, 0x1, 0xbe, 0x2f, 0x0, 0xf4, 0xfe, 0x1f, 0x42, 0x85, 0xce, 0x21, 0xc2, 0x9e, +0x81, 0x1a, 0x42, 0x4c, 0x37, 0x99, 0x3e, 0xd0, 0x71, 0x35, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0x28, 0xf7, 0xf6, 0x35, 0xdc, +0x5, 0xc0, 0xc1, 0x4c, 0xe7, 0xbe, 0x35, 0xb3, 0xcd, 0xfd, 0x3e, 0x38, 0xf6, 0x0, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x31, +0x80, 0x87, 0x42, 0x30, 0xb3, 0x10, 0xc2, 0xcb, 0xff, 0xa7, 0x41, 0x18, 0x77, 0xeb, 0x3e, 0xe0, 0x68, 0x9c, 0x3c, 0x1, +0xbe, 0x2f, 0x0, 0xa9, 0x9, 0x69, 0x42, 0x2f, 0xb3, 0x10, 0xc2, 0x41, 0xd6, 0x21, 0x42, 0x24, 0x5f, 0xa1, 0x3e, 0x60, +0xe2, 0x56, 0x3d, 0x1, 0xbe, 0x2f, 0x0, 0x8b, 0x41, 0x5c, 0x42, 0xb1, 0xba, 0xf1, 0xc0, 0xed, 0xa3, 0xf7, 0x40, 0x98, +0x69, 0x7, 0x3f, 0x30, 0x6a, 0xfe, 0x3d, 0x1, 0xbe, 0x2f, 0x0, 0x31, 0x80, 0x87, 0x42, 0xad, 0x4a, 0x3d, 0xc1, 0xcb, +0xff, 0xa7, 0x41, 0x18, 0x77, 0xeb, 0x3e, 0xe0, 0x68, 0x9c, 0x3c, 0x1, 0xbe, 0x2f, 0x0, 0xa9, 0x9, 0x69, 0x42, 0xa9, +0x4a, 0x3d, 0xc1, 0x41, 0xd6, 0x21, 0x42, 0x24, 0x5f, 0xa1, 0x3e, 0x60, 0xe2, 0x56, 0x3d, 0x1, 0xbe, 0x2f, 0x0, 0xf4, +0xfe, 0x1f, 0x42, 0xa5, 0xba, 0xf1, 0xc0, 0x9e, 0x81, 0x1a, 0x42, 0x4c, 0x37, 0x99, 0x3e, 0xd0, 0x71, 0x35, 0x3e, 0x1, +0xbe, 0x2f, 0x0, 0xdd, 0x7d, 0x1a, 0x41, 0x85, 0xce, 0x21, 0xc2, 0x9e, 0xa, 0x5b, 0x42, 0x17, 0xe, 0x14, 0x3e, 0xee, +0xb4, 0xb5, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0xfd, 0xde, 0x29, 0x42, 0x2e, 0xb3, 0x10, 0xc2, 0x69, 0x3f, 0x63, 0x42, 0xb5, +0xdc, 0x39, 0x3e, 0xcc, 0xdd, 0x7, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0xf2, 0xcf, 0xba, 0x41, 0x2e, 0xb3, 0x10, 0xc2, 0xd1, +0xf3, 0x85, 0x42, 0xd8, 0x2b, 0xac, 0x3d, 0x98, 0x81, 0x7a, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0xff, 0xde, 0x29, 0x42, 0xa5, +0x4a, 0x3d, 0xc1, 0x68, 0x3f, 0x63, 0x42, 0xf9, 0xdc, 0x39, 0x3e, 0xcc, 0xdd, 0x7, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0xf2, +0xcf, 0xba, 0x41, 0xa3, 0x4a, 0x3d, 0xc1, 0xd1, 0xf3, 0x85, 0x42, 0xd8, 0x2b, 0xac, 0x3d, 0x98, 0x81, 0x7a, 0x3e, 0x1, +0xbe, 0x2f, 0x0, 0xd4, 0x7d, 0x1a, 0x41, 0x9e, 0xba, 0xf1, 0xc0, 0x96, 0xa, 0x5b, 0x42, 0x17, 0xe, 0x14, 0x3e, 0xee, +0xb4, 0xb5, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0x74, 0x1, 0xc3, 0xc1, 0x85, 0xce, 0x21, 0xc2, 0xfb, 0xe8, 0x47, 0x42, 0x29, +0x8, 0xfe, 0x3d, 0xc9, 0xe6, 0x16, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xd1, 0xc3, 0x76, 0x3f, 0x2e, 0xb3, 0x10, 0xc2, 0xf2, +0xd8, 0x8d, 0x42, 0x9d, 0x85, 0xbd, 0x3c, 0x1e, 0xa9, 0xc6, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0x93, 0xce, 0xa3, 0xc1, 0x2e, +0xb3, 0x10, 0xc2, 0x33, 0xd2, 0x87, 0x42, 0xf5, 0xf3, 0x26, 0x3c, 0x24, 0x29, 0x9, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x8, +0xc4, 0x76, 0x3f, 0xa1, 0x4a, 0x3d, 0xc1, 0xf1, 0xd8, 0x8d, 0x42, 0x9d, 0x85, 0xbd, 0x3c, 0x1e, 0xa9, 0xc6, 0x3e, 0x1, +0xbe, 0x2f, 0x0, 0x92, 0xce, 0xa3, 0xc1, 0xa1, 0x4a, 0x3d, 0xc1, 0x32, 0xd2, 0x87, 0x42, 0xf5, 0xf3, 0x26, 0x3c, 0x24, +0x29, 0x9, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x72, 0x1, 0xc3, 0xc1, 0x9e, 0xba, 0xf1, 0xc0, 0xfa, 0xe8, 0x47, 0x42, 0x29, +0x8, 0xfe, 0x3d, 0xc9, 0xe6, 0x16, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xc1, 0x62, 0x44, 0xc2, 0x85, 0xce, 0x21, 0xc2, 0x6, +0xd7, 0xd0, 0x41, 0x14, 0x59, 0x7b, 0x3e, 0xc9, 0x91, 0x4a, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xe4, 0xa1, 0x23, 0xc2, 0x2e, +0xb3, 0x10, 0xc2, 0xbf, 0xc7, 0x67, 0x42, 0x16, 0x6e, 0x39, 0x3d, 0x26, 0x3, 0x30, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xbc, +0xed, 0x61, 0xc2, 0x2e, 0xb3, 0x10, 0xc2, 0x17, 0x9f, 0x2b, 0x42, 0xee, 0x5f, 0xf9, 0x3d, 0x2e, 0x90, 0x50, 0x3f, 0x1, +0xbe, 0x2f, 0x0, 0xe3, 0xa1, 0x23, 0xc2, 0xa3, 0x4a, 0x3d, 0xc1, 0xbf, 0xc7, 0x67, 0x42, 0x16, 0x6e, 0x39, 0x3d, 0x26, +0x3, 0x30, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xbb, 0xed, 0x61, 0xc2, 0xa5, 0x4a, 0x3d, 0xc1, 0x16, 0x9f, 0x2b, 0x42, 0xee, +0x5f, 0xf9, 0x3d, 0x2e, 0x90, 0x50, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xbf, 0x62, 0x44, 0xc2, 0xa6, 0xba, 0xf1, 0xc0, 0x4, +0xd7, 0xd0, 0x41, 0x58, 0x59, 0x7b, 0x3e, 0xc9, 0x91, 0x4a, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x86, 0x41, 0x5c, 0xc2, 0x86, +0xce, 0x21, 0xc2, 0xfb, 0xa3, 0xf7, 0xc0, 0x15, 0xc8, 0xec, 0x3e, 0x2a, 0x1f, 0x62, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x2a, +0x4f, 0x86, 0xc2, 0x2f, 0xb3, 0x10, 0xc2, 0xbd, 0xaa, 0xb6, 0x41, 0xbd, 0x34, 0x75, 0x3e, 0xfa, 0xb8, 0x6a, 0x3f, 0x1, +0xbe, 0x2f, 0x0, 0x12, 0xd4, 0x8d, 0xc2, 0x30, 0xb3, 0x10, 0xc2, 0x68, 0x82, 0xc1, 0x3f, 0xbf, 0x99, 0xc0, 0x3e, 0x71, +0x8f, 0x79, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x2a, 0x4f, 0x86, 0xc2, 0xa9, 0x4a, 0x3d, 0xc1, 0xbd, 0xaa, 0xb6, 0x41, 0xbd, +0x34, 0x75, 0x3e, 0xfa, 0xb8, 0x6a, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x11, 0xd4, 0x8d, 0xc2, 0xad, 0x4a, 0x3d, 0xc1, 0x58, +0x82, 0xc1, 0x3f, 0xbf, 0x99, 0xc0, 0x3e, 0x71, 0x8f, 0x79, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x85, 0x41, 0x5c, 0xc2, 0xb2, +0xba, 0xf1, 0xc0, 0xff, 0xa3, 0xf7, 0xc0, 0x15, 0xc8, 0xec, 0x3e, 0x2a, 0x1f, 0x62, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xf1, +0xfe, 0x1f, 0xc2, 0x89, 0xce, 0x21, 0xc2, 0x9e, 0x81, 0x1a, 0xc2, 0xe, 0x32, 0x31, 0x3f, 0xeb, 0x8f, 0x54, 0x3f, 0x1, +0xbe, 0x2f, 0x0, 0x32, 0x80, 0x87, 0xc2, 0x31, 0xb3, 0x10, 0xc2, 0xd1, 0xff, 0xa7, 0xc1, 0x17, 0x12, 0x8, 0x3f, 0x18, +0x9, 0x7d, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xa2, 0x9, 0x69, 0xc2, 0x32, 0xb3, 0x10, 0xc2, 0x3f, 0xd6, 0x21, 0xc2, 0x21, +0x1e, 0x2d, 0x3f, 0x39, 0x7e, 0x74, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x31, 0x80, 0x87, 0xc2, 0xb1, 0x4a, 0x3d, 0xc1, 0xd2, +0xff, 0xa7, 0xc1, 0x17, 0x12, 0x8, 0x3f, 0x18, 0x9, 0x7d, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xa1, 0x9, 0x69, 0xc2, 0xb5, +0x4a, 0x3d, 0xc1, 0x40, 0xd6, 0x21, 0xc2, 0x21, 0x1e, 0x2d, 0x3f, 0x39, 0x7e, 0x74, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xf1, +0xfe, 0x1f, 0xc2, 0xbe, 0xba, 0xf1, 0xc0, 0x9e, 0x81, 0x1a, 0xc2, 0xe, 0x32, 0x31, 0x3f, 0xeb, 0x8f, 0x54, 0x3f, 0x1, +0xbe, 0x2f, 0x0, 0xc9, 0x7d, 0x1a, 0xc1, 0x8a, 0xce, 0x21, 0xc2, 0x96, 0xa, 0x5b, 0xc2, 0x1d, 0xca, 0x58, 0x3f, 0xf9, +0x11, 0x27, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xfe, 0xde, 0x29, 0xc2, 0x33, 0xb3, 0x10, 0xc2, 0x68, 0x3f, 0x63, 0xc2, 0x75, +0x56, 0x4f, 0x3f, 0xed, 0xf4, 0x5f, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xe5, 0xcf, 0xba, 0xc1, 0x34, 0xb3, 0x10, 0xc2, 0xcf, +0xf3, 0x85, 0xc2, 0x28, 0x48, 0x68, 0x3f, 0xf9, 0x4b, 0x43, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xfe, 0xde, 0x29, 0xc2, 0xb9, +0x4a, 0x3d, 0xc1, 0x68, 0x3f, 0x63, 0xc2, 0x75, 0x56, 0x4f, 0x3f, 0xed, 0xf4, 0x5f, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0xe5, +0xcf, 0xba, 0xc1, 0xbb, 0x4a, 0x3d, 0xc1, 0xd2, 0xf3, 0x85, 0xc2, 0x28, 0x48, 0x68, 0x3f, 0xf9, 0x4b, 0x43, 0x3f, 0x1, +0xbe, 0x2f, 0x0, 0xc9, 0x7d, 0x1a, 0xc1, 0xc6, 0xba, 0xf1, 0xc0, 0x96, 0xa, 0x5b, 0xc2, 0x1d, 0xca, 0x58, 0x3f, 0xf9, +0x11, 0x27, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x73, 0x1, 0xc3, 0x41, 0x89, 0xce, 0x21, 0xc2, 0xf9, 0xe8, 0x47, 0xc2, 0xae, +0xc, 0x5e, 0x3f, 0x4e, 0xb, 0xd6, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0x24, 0xc3, 0x76, 0xbf, 0x34, 0xb3, 0x10, 0xc2, 0xf2, +0xd8, 0x8d, 0xc2, 0x76, 0xe1, 0x77, 0x3f, 0xd0, 0x97, 0x1e, 0x3f, 0x1, 0xbe, 0x2f, 0x0, 0x99, 0xce, 0xa3, 0x41, 0x34, +0xb3, 0x10, 0xc2, 0x33, 0xd2, 0x87, 0xc2, 0xd3, 0x31, 0x7b, 0x3f, 0x76, 0x86, 0xf1, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0x24, +0xc3, 0x76, 0xbf, 0xbb, 0x4a, 0x3d, 0xc1, 0xf2, 0xd8, 0x8d, 0xc2, 0x76, 0xe1, 0x77, 0x3f, 0xd0, 0x97, 0x1e, 0x3f, 0x1, +0xbe, 0x2f, 0x0, 0x99, 0xce, 0xa3, 0x41, 0xbb, 0x4a, 0x3d, 0xc1, 0x33, 0xd2, 0x87, 0xc2, 0xd3, 0x31, 0x7b, 0x3f, 0x76, +0x86, 0xf1, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0x73, 0x1, 0xc3, 0x41, 0xc6, 0xba, 0xf1, 0xc0, 0xf9, 0xe8, 0x47, 0xc2, 0xae, +0xc, 0x5e, 0x3f, 0x4e, 0xb, 0xd6, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0xbe, 0x62, 0x44, 0x42, 0x89, 0xce, 0x21, 0xc2, 0x1, +0xd7, 0xd0, 0xc1, 0x5e, 0xf7, 0x3e, 0x3f, 0x9c, 0x6a, 0x5d, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0xe9, 0xa1, 0x23, 0x42, 0x34, +0xb3, 0x10, 0xc2, 0xbc, 0xc7, 0x67, 0xc2, 0xd2, 0x36, 0x72, 0x3f, 0x96, 0xd2, 0xa3, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0xc2, +0xed, 0x61, 0x42, 0x33, 0xb3, 0x10, 0xc2, 0x14, 0x9f, 0x2b, 0xc2, 0xb6, 0xa1, 0x5e, 0x3f, 0x8, 0x71, 0x45, 0x3e, 0x1, +0xbe, 0x2f, 0x0, 0xe9, 0xa1, 0x23, 0x42, 0xbb, 0x4a, 0x3d, 0xc1, 0xbc, 0xc7, 0x67, 0xc2, 0xd2, 0x36, 0x72, 0x3f, 0x96, +0xd2, 0xa3, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0xc2, 0xed, 0x61, 0x42, 0xb9, 0x4a, 0x3d, 0xc1, 0x14, 0x9f, 0x2b, 0xc2, 0xb6, +0xa1, 0x5e, 0x3f, 0x8, 0x71, 0x45, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0xbe, 0x62, 0x44, 0x42, 0xbe, 0xba, 0xf1, 0xc0, 0x1, +0xd7, 0xd0, 0xc1, 0x5e, 0xf7, 0x3e, 0x3f, 0x9c, 0x6a, 0x5d, 0x3e, 0x1, 0xbe, 0x2f, 0x0, 0x2f, 0x4f, 0x86, 0x42, 0x32, +0xb3, 0x10, 0xc2, 0xb1, 0xaa, 0xb6, 0xc1, 0x73, 0x80, 0x40, 0x3f, 0xb0, 0x9b, 0xb9, 0x3d, 0x1, 0xbe, 0x2f, 0x0, 0x12, +0xd4, 0x8d, 0x42, 0x31, 0xb3, 0x10, 0xc2, 0x48, 0x82, 0xc1, 0xbf, 0xc3, 0x80, 0x1d, 0x3f, 0xe0, 0xce, 0x5, 0x3d, 0x1, +0xbe, 0x2f, 0x0, 0x2f, 0x4f, 0x86, 0x42, 0xb5, 0x4a, 0x3d, 0xc1, 0xb1, 0xaa, 0xb6, 0xc1, 0x73, 0x80, 0x40, 0x3f, 0xb0, +0x9b, 0xb9, 0x3d, 0x1, 0xbe, 0x2f, 0x0, 0x12, 0xd4, 0x8d, 0x42, 0xb1, 0x4a, 0x3d, 0xc1, 0x48, 0x82, 0xc1, 0xbf, 0xc3, +0x80, 0x1d, 0x3f, 0xe0, 0xce, 0x5, 0x3d, 0x1, 0xbe, 0x2f, 0x0, 0x8e, 0x41, 0x5c, 0x42, 0x71, 0xbf, 0x29, 0xc2, 0xf2, +0xa3, 0xf7, 0xc0, 0xb6, 0xa0, 0x5f, 0x3f, 0x7e, 0xc3, 0xfc, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xc1, 0x62, 0x44, 0x42, 0x6f, +0xbf, 0x29, 0xc2, 0x1, 0xd7, 0xd0, 0x41, 0xe5, 0x27, 0x4d, 0x3f, 0x76, 0x33, 0x8b, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xab, +0x6, 0xc5, 0x36, 0xb1, 0xe7, 0xcf, 0xc1, 0x65, 0x7d, 0xb1, 0xb6, 0x96, 0xd0, 0xfd, 0x3e, 0x7e, 0xc3, 0xfc, 0x3e, 0x1, +0xbe, 0x32, 0x0, 0x14, 0xd4, 0x8d, 0x42, 0x1a, 0xa4, 0x18, 0xc2, 0x55, 0x82, 0xc1, 0x3f, 0xc0, 0xb0, 0x78, 0x3f, 0x20, +0x45, 0xd5, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x30, 0x4f, 0x86, 0x42, 0x19, 0xa4, 0x18, 0xc2, 0xb0, 0xaa, 0xb6, 0x41, 0x8d, +0xd, 0x6d, 0x3f, 0xa6, 0xb9, 0x8d, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x90, 0x41, 0x5c, 0x42, 0x2, 0xa1, 0x18, 0xc1, 0x32, +0xa4, 0xf7, 0xc0, 0xb6, 0xa0, 0x5f, 0x3f, 0x7e, 0xc3, 0xfc, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x14, 0xd4, 0x8d, 0x42, 0x56, +0xe, 0x5d, 0xc1, 0x55, 0x82, 0xc1, 0x3f, 0xc0, 0xb0, 0x78, 0x3f, 0x20, 0x45, 0xd5, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x30, +0x4f, 0x86, 0x42, 0x52, 0xe, 0x5d, 0xc1, 0xb0, 0xaa, 0xb6, 0x41, 0x8d, 0xd, 0x6d, 0x3f, 0xa6, 0xb9, 0x8d, 0x3e, 0x1, +0xbe, 0x32, 0x0, 0xc1, 0x62, 0x44, 0x42, 0xfc, 0xa0, 0x18, 0xc1, 0x1, 0xd7, 0xd0, 0x41, 0xe5, 0x27, 0x4d, 0x3f, 0x76, +0x33, 0x8b, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x6c, 0x1, 0xc3, 0x41, 0x6e, 0xbf, 0x29, 0xc2, 0x0, 0xe9, 0x47, 0x42, 0xb0, +0xcb, 0x1c, 0x3f, 0xb4, 0x7, 0xa, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xbd, 0xed, 0x61, 0x42, 0x19, 0xa4, 0x18, 0xc2, 0x15, +0x9f, 0x2b, 0x42, 0x89, 0xcf, 0x55, 0x3f, 0x5c, 0xa5, 0x1b, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xec, 0xa1, 0x23, 0x42, 0x17, +0xa4, 0x18, 0xc2, 0xc2, 0xc7, 0x67, 0x42, 0x8, 0x58, 0x37, 0x3f, 0xb0, 0x6c, 0x86, 0x3d, 0x1, 0xbe, 0x32, 0x0, 0xbc, +0xed, 0x61, 0x42, 0x4e, 0xe, 0x5d, 0xc1, 0x15, 0x9f, 0x2b, 0x42, 0x89, 0xcf, 0x55, 0x3f, 0x5c, 0xa5, 0x1b, 0x3e, 0x1, +0xbe, 0x32, 0x0, 0xea, 0xa1, 0x23, 0x42, 0x4c, 0xe, 0x5d, 0xc1, 0xc1, 0xc7, 0x67, 0x42, 0x8, 0x58, 0x37, 0x3f, 0xb0, +0x6c, 0x86, 0x3d, 0x1, 0xbe, 0x32, 0x0, 0x74, 0x1, 0xc3, 0x41, 0xf8, 0xa0, 0x18, 0xc1, 0xfa, 0xe8, 0x47, 0x42, 0xb0, +0xcb, 0x1c, 0x3f, 0xb4, 0x7, 0xa, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xdd, 0x7d, 0x1a, 0xc1, 0x6e, 0xbf, 0x29, 0xc2, 0x9d, +0xa, 0x5b, 0x42, 0xcc, 0x9, 0xc2, 0x3e, 0xb4, 0x7, 0xa, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x9a, 0xce, 0xa3, 0x41, 0x17, +0xa4, 0x18, 0xc2, 0x33, 0xd2, 0x87, 0x42, 0xa9, 0xbc, 0x11, 0x3f, 0x40, 0x29, 0x93, 0x3c, 0x1, 0xbe, 0x32, 0x0, 0xdd, +0xc3, 0x76, 0xbf, 0x17, 0xa4, 0x18, 0xc2, 0xf1, 0xd8, 0x8d, 0x42, 0xd9, 0x27, 0xd8, 0x3e, 0x40, 0x29, 0x93, 0x3c, 0x1, +0xbe, 0x32, 0x0, 0x9a, 0xce, 0xa3, 0x41, 0x4a, 0xe, 0x5d, 0xc1, 0x33, 0xd2, 0x87, 0x42, 0xa9, 0xbc, 0x11, 0x3f, 0x40, +0x29, 0x93, 0x3c, 0x1, 0xbe, 0x32, 0x0, 0xdd, 0xc3, 0x76, 0xbf, 0x4a, 0xe, 0x5d, 0xc1, 0xf1, 0xd8, 0x8d, 0x42, 0xd9, +0x27, 0xd8, 0x3e, 0x40, 0x29, 0x93, 0x3c, 0x1, 0xbe, 0x32, 0x0, 0xdd, 0x7d, 0x1a, 0xc1, 0xf8, 0xa0, 0x18, 0xc1, 0x9d, +0xa, 0x5b, 0x42, 0xcc, 0x9, 0xc2, 0x3e, 0xb4, 0x7, 0xa, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xf0, 0xfe, 0x1f, 0xc2, 0x6f, +0xbf, 0x29, 0xc2, 0x9f, 0x81, 0x1a, 0x42, 0x7f, 0xa2, 0x42, 0x3e, 0x76, 0x33, 0x8b, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xeb, +0xcf, 0xba, 0xc1, 0x17, 0xa4, 0x18, 0xc2, 0xd1, 0xf3, 0x85, 0x42, 0x1b, 0xf1, 0x8c, 0x3e, 0xb0, 0x6c, 0x86, 0x3d, 0x1, +0xbe, 0x32, 0x0, 0xff, 0xde, 0x29, 0xc2, 0x18, 0xa4, 0x18, 0xc2, 0x68, 0x3f, 0x63, 0x42, 0x32, 0x4, 0x20, 0x3e, 0x5c, +0xa5, 0x1b, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xef, 0xcf, 0xba, 0xc1, 0x4c, 0xe, 0x5d, 0xc1, 0xd1, 0xf3, 0x85, 0x42, 0x1b, +0xf1, 0x8c, 0x3e, 0xb0, 0x6c, 0x86, 0x3d, 0x1, 0xbe, 0x32, 0x0, 0x1, 0xdf, 0x29, 0xc2, 0x4e, 0xe, 0x5d, 0xc1, 0x67, +0x3f, 0x63, 0x42, 0x32, 0x4, 0x20, 0x3e, 0x5c, 0xa5, 0x1b, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xf0, 0xfe, 0x1f, 0xc2, 0xfc, +0xa0, 0x18, 0xc1, 0x9f, 0x81, 0x1a, 0x42, 0x7f, 0xa2, 0x42, 0x3e, 0x76, 0x33, 0x8b, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x88, +0x41, 0x5c, 0xc2, 0x71, 0xbf, 0x29, 0xc2, 0xec, 0xa3, 0xf7, 0x40, 0x78, 0x7e, 0xf1, 0x3d, 0x7e, 0xc3, 0xfc, 0x3e, 0x1, +0xbe, 0x32, 0x0, 0xa4, 0x9, 0x69, 0xc2, 0x19, 0xa4, 0x18, 0xc2, 0x43, 0xd6, 0x21, 0x42, 0x48, 0x18, 0x86, 0x3d, 0xa6, +0xb9, 0x8d, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x30, 0x80, 0x87, 0xc2, 0x1b, 0xa4, 0x18, 0xc2, 0xcc, 0xff, 0xa7, 0x41, 0xb1, +0xfa, 0xa3, 0x3c, 0x20, 0x45, 0xd5, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0xa0, 0x9, 0x69, 0xc2, 0x52, 0xe, 0x5d, 0xc1, 0x3c, +0xd6, 0x21, 0x42, 0x48, 0x18, 0x86, 0x3d, 0xa6, 0xb9, 0x8d, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x30, 0x80, 0x87, 0xc2, 0x56, +0xe, 0x5d, 0xc1, 0xcc, 0xff, 0xa7, 0x41, 0xb1, 0xfa, 0xa3, 0x3c, 0x20, 0x45, 0xd5, 0x3e, 0x1, 0xbe, 0x32, 0x0, 0x88, +0x41, 0x5c, 0xc2, 0x2, 0xa1, 0x18, 0xc1, 0xec, 0xa3, 0xf7, 0x40, 0x78, 0x7e, 0xf1, 0x3d, 0x7e, 0xc3, 0xfc, 0x3e, 0x1, +0xbe, 0x32, 0x0, 0xba, 0x62, 0x44, 0xc2, 0x72, 0xbf, 0x29, 0xc2, 0x3, 0xd7, 0xd0, 0xc1, 0x7f, 0xa2, 0x42, 0x3e, 0xc4, +0x29, 0x37, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x12, 0xd4, 0x8d, 0xc2, 0x1b, 0xa4, 0x18, 0xc2, 0x8e, 0x82, 0xc1, 0xbf, 0xb1, +0xfa, 0xa3, 0x3c, 0xee, 0x20, 0x12, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x2b, 0x4f, 0x86, 0xc2, 0x1c, 0xa4, 0x18, 0xc2, 0xc1, +0xaa, 0xb6, 0xc1, 0xc2, 0x17, 0x86, 0x3d, 0xac, 0xe6, 0x35, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x10, 0xd4, 0x8d, 0xc2, 0x5a, +0xe, 0x5d, 0xc1, 0x6b, 0x83, 0xc1, 0xbf, 0xb1, 0xfa, 0xa3, 0x3c, 0xee, 0x20, 0x12, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x2d, +0x4f, 0x86, 0xc2, 0x5e, 0xe, 0x5d, 0xc1, 0xc5, 0xaa, 0xb6, 0xc1, 0xc2, 0x17, 0x86, 0x3d, 0xac, 0xe6, 0x35, 0x3f, 0x1, +0xbe, 0x32, 0x0, 0xba, 0x62, 0x44, 0xc2, 0x8, 0xa1, 0x18, 0xc1, 0x15, 0xd7, 0xd0, 0xc1, 0x7f, 0xa2, 0x42, 0x3e, 0xc4, +0x29, 0x37, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x5c, 0x1, 0xc3, 0xc1, 0x73, 0xbf, 0x29, 0xc2, 0x0, 0xe9, 0x47, 0xc2, 0xcc, +0x9, 0xc2, 0x3e, 0x92, 0x41, 0x5a, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xb5, 0xed, 0x61, 0xc2, 0x1d, 0xa4, 0x18, 0xc2, 0x1e, +0x9f, 0x2b, 0xc2, 0x32, 0x4, 0x20, 0x3e, 0x27, 0xda, 0x55, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xdf, 0xa1, 0x23, 0xc2, 0x1d, +0xa4, 0x18, 0xc2, 0xc0, 0xc7, 0x67, 0xc2, 0x1b, 0xf1, 0x8c, 0x3e, 0xe8, 0xf5, 0x6b, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xb5, +0xed, 0x61, 0xc2, 0x62, 0xe, 0x5d, 0xc1, 0x1e, 0x9f, 0x2b, 0xc2, 0x32, 0x4, 0x20, 0x3e, 0x27, 0xda, 0x55, 0x3f, 0x1, +0xbe, 0x32, 0x0, 0xdb, 0xa1, 0x23, 0xc2, 0x64, 0xe, 0x5d, 0xc1, 0xc7, 0xc7, 0x67, 0xc2, 0x1b, 0xf1, 0x8c, 0x3e, 0xe8, +0xf5, 0x6b, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x5c, 0x1, 0xc3, 0xc1, 0xc, 0xa1, 0x18, 0xc1, 0x0, 0xe9, 0x47, 0xc2, 0xcc, +0x9, 0xc2, 0x3e, 0x92, 0x41, 0x5a, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xf1, 0x7d, 0x1a, 0x41, 0x73, 0xbf, 0x29, 0xc2, 0x9e, +0xa, 0x5b, 0xc2, 0xb0, 0xcb, 0x1c, 0x3f, 0x92, 0x41, 0x5a, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x8a, 0xce, 0xa3, 0xc1, 0x1e, +0xa4, 0x18, 0xc2, 0x33, 0xd2, 0x87, 0xc2, 0xd9, 0x27, 0xd8, 0x3e, 0x35, 0x2a, 0x78, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x11, +0xc6, 0x76, 0x3f, 0x1f, 0xa4, 0x18, 0xc2, 0xf6, 0xd8, 0x8d, 0xc2, 0xa9, 0xbc, 0x11, 0x3f, 0x35, 0x2a, 0x78, 0x3f, 0x1, +0xbe, 0x32, 0x0, 0x8a, 0xce, 0xa3, 0xc1, 0x64, 0xe, 0x5d, 0xc1, 0x33, 0xd2, 0x87, 0xc2, 0xd9, 0x27, 0xd8, 0x3e, 0x35, +0x2a, 0x78, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x11, 0xc6, 0x76, 0x3f, 0x64, 0xe, 0x5d, 0xc1, 0xf6, 0xd8, 0x8d, 0xc2, 0xa9, +0xbc, 0x11, 0x3f, 0x35, 0x2a, 0x78, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xf1, 0x7d, 0x1a, 0x41, 0xc, 0xa1, 0x18, 0xc1, 0x9e, +0xa, 0x5b, 0xc2, 0xb0, 0xcb, 0x1c, 0x3f, 0x92, 0x41, 0x5a, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xf9, 0xfe, 0x1f, 0x42, 0x72, +0xbf, 0x29, 0xc2, 0x9f, 0x81, 0x1a, 0xc2, 0xe5, 0x27, 0x4d, 0x3f, 0xc4, 0x29, 0x37, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xf8, +0xcf, 0xba, 0x41, 0x1e, 0xa4, 0x18, 0xc2, 0xd2, 0xf3, 0x85, 0xc2, 0xf7, 0x57, 0x37, 0x3f, 0xe8, 0xf5, 0x6b, 0x3f, 0x1, +0xbe, 0x32, 0x0, 0x7, 0xdf, 0x29, 0x42, 0x1d, 0xa4, 0x18, 0xc2, 0x68, 0x3f, 0x63, 0xc2, 0x89, 0xcf, 0x55, 0x3f, 0x27, +0xda, 0x55, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xf8, 0xcf, 0xba, 0x41, 0x64, 0xe, 0x5d, 0xc1, 0xd2, 0xf3, 0x85, 0xc2, 0xf7, +0x57, 0x37, 0x3f, 0xe8, 0xf5, 0x6b, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x7, 0xdf, 0x29, 0x42, 0x62, 0xe, 0x5d, 0xc1, 0x68, +0x3f, 0x63, 0xc2, 0x89, 0xcf, 0x55, 0x3f, 0x27, 0xda, 0x55, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xf7, 0xfe, 0x1f, 0x42, 0x8, +0xa1, 0x18, 0xc1, 0xa0, 0x81, 0x1a, 0xc2, 0xe5, 0x27, 0x4d, 0x3f, 0xc4, 0x29, 0x37, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xaa, +0x9, 0x69, 0x42, 0x1c, 0xa4, 0x18, 0xc2, 0x3b, 0xd6, 0x21, 0xc2, 0x8d, 0xd, 0x6d, 0x3f, 0xac, 0xe6, 0x35, 0x3f, 0x1, +0xbe, 0x32, 0x0, 0x34, 0x80, 0x87, 0x42, 0x1b, 0xa4, 0x18, 0xc2, 0xcc, 0xff, 0xa7, 0xc1, 0xc0, 0xb0, 0x78, 0x3f, 0xee, +0x20, 0x12, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0xab, 0x9, 0x69, 0x42, 0x5e, 0xe, 0x5d, 0xc1, 0x44, 0xd6, 0x21, 0xc2, 0x8d, +0xd, 0x6d, 0x3f, 0xac, 0xe6, 0x35, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x34, 0x80, 0x87, 0x42, 0x5a, 0xe, 0x5d, 0xc1, 0xcc, +0xff, 0xa7, 0xc1, 0xc0, 0xb0, 0x78, 0x3f, 0xee, 0x20, 0x12, 0x3f, 0x1, 0xbe, 0x32, 0x0, 0x8e, 0x41, 0x5c, 0x42, 0xc9, +0xc5, 0x36, 0xc2, 0x16, 0xa4, 0xf7, 0x40, 0x89, 0x7d, 0x5e, 0x3f, 0xc6, 0xd7, 0xfe, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xf8, +0xfe, 0x1f, 0x42, 0xc7, 0xc5, 0x36, 0xc2, 0xa3, 0x81, 0x1a, 0x42, 0xb8, 0x4, 0x4c, 0x3f, 0xbe, 0x47, 0x8d, 0x3e, 0x1, +0xbe, 0x35, 0x0, 0x19, 0x1f, 0xac, 0x37, 0x61, 0xf4, 0xe9, 0xc1, 0x6b, 0x50, 0x86, 0x37, 0x1a, 0x8a, 0xfb, 0x3e, 0xc6, +0xd7, 0xfe, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0x34, 0x80, 0x87, 0x42, 0x73, 0xaa, 0x25, 0xc2, 0xd4, 0xff, 0xa7, 0x41, 0x82, +0x8d, 0x77, 0x3f, 0x68, 0x59, 0xd7, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xac, 0x9, 0x69, 0x42, 0x71, 0xaa, 0x25, 0xc2, 0x46, +0xd6, 0x21, 0x42, 0x60, 0xea, 0x6b, 0x3f, 0x10, 0xce, 0x8f, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0x8f, 0x41, 0x5c, 0x42, 0x61, +0xba, 0x4c, 0xc1, 0x14, 0xa4, 0xf7, 0x40, 0x89, 0x7d, 0x5e, 0x3f, 0xc6, 0xd7, 0xfe, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0x34, +0x80, 0x87, 0x42, 0xdc, 0x93, 0x88, 0xc1, 0xd4, 0xff, 0xa7, 0x41, 0x82, 0x8d, 0x77, 0x3f, 0x68, 0x59, 0xd7, 0x3e, 0x1, +0xbe, 0x35, 0x0, 0xad, 0x9, 0x69, 0x42, 0xd9, 0x93, 0x88, 0xc1, 0x46, 0xd6, 0x21, 0x42, 0x60, 0xea, 0x6b, 0x3f, 0x10, +0xce, 0x8f, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xf9, 0xfe, 0x1f, 0x42, 0x5b, 0xba, 0x4c, 0xc1, 0xa2, 0x81, 0x1a, 0x42, 0xb8, +0x4, 0x4c, 0x3f, 0xbe, 0x47, 0x8d, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xd4, 0x7d, 0x1a, 0x41, 0xc6, 0xc5, 0x36, 0xc2, 0x9d, +0xa, 0x5b, 0x42, 0x82, 0xa8, 0x1b, 0x3f, 0x44, 0x30, 0xe, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0x2, 0xdf, 0x29, 0x42, 0x70, +0xaa, 0x25, 0xc2, 0x6e, 0x3f, 0x63, 0x42, 0x5c, 0xac, 0x54, 0x3f, 0x30, 0xce, 0x1f, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xfc, +0xcf, 0xba, 0x41, 0x6f, 0xaa, 0x25, 0xc2, 0xd3, 0xf3, 0x85, 0x42, 0xca, 0x34, 0x36, 0x3f, 0xd0, 0xbd, 0x8e, 0x3d, 0x1, +0xbe, 0x35, 0x0, 0x3, 0xdf, 0x29, 0x42, 0xd8, 0x93, 0x88, 0xc1, 0x6e, 0x3f, 0x63, 0x42, 0x5c, 0xac, 0x54, 0x3f, 0x30, +0xce, 0x1f, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xfc, 0xcf, 0xba, 0x41, 0xd7, 0x93, 0x88, 0xc1, 0xd3, 0xf3, 0x85, 0x42, 0xca, +0x34, 0x36, 0x3f, 0xd0, 0xbd, 0x8e, 0x3d, 0x1, 0xbe, 0x35, 0x0, 0xd7, 0x7d, 0x1a, 0x41, 0x57, 0xba, 0x4c, 0xc1, 0x9c, +0xa, 0x5b, 0x42, 0x82, 0xa8, 0x1b, 0x3f, 0x44, 0x30, 0xe, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0x6f, 0x1, 0xc3, 0xc1, 0xc6, +0xc5, 0x36, 0xc2, 0x1, 0xe9, 0x47, 0x42, 0x50, 0xc3, 0xbf, 0x3e, 0x44, 0x30, 0xe, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0x61, +0xc6, 0x76, 0x3f, 0x6f, 0xaa, 0x25, 0xc2, 0xf7, 0xd8, 0x8d, 0x42, 0x7c, 0x99, 0x10, 0x3f, 0xc0, 0x6d, 0xb4, 0x3c, 0x1, +0xbe, 0x35, 0x0, 0x88, 0xce, 0xa3, 0xc1, 0x70, 0xaa, 0x25, 0xc2, 0x35, 0xd2, 0x87, 0x42, 0x5d, 0xe1, 0xd5, 0x3e, 0xc0, +0x6d, 0xb4, 0x3c, 0x1, 0xbe, 0x35, 0x0, 0x7, 0xc6, 0x76, 0x3f, 0xd6, 0x93, 0x88, 0xc1, 0xf3, 0xd8, 0x8d, 0x42, 0x7c, +0x99, 0x10, 0x3f, 0xc0, 0x6d, 0xb4, 0x3c, 0x1, 0xbe, 0x35, 0x0, 0x88, 0xce, 0xa3, 0xc1, 0xd6, 0x93, 0x88, 0xc1, 0x35, +0xd2, 0x87, 0x42, 0x5d, 0xe1, 0xd5, 0x3e, 0xc0, 0x6d, 0xb4, 0x3c, 0x1, 0xbe, 0x35, 0x0, 0x69, 0x1, 0xc3, 0xc1, 0x57, +0xba, 0x4c, 0xc1, 0xff, 0xe8, 0x47, 0x42, 0x50, 0xc3, 0xbf, 0x3e, 0x44, 0x30, 0xe, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xb7, +0x62, 0x44, 0xc2, 0xc7, 0xc5, 0x36, 0xc2, 0x8, 0xd7, 0xd0, 0x41, 0xca, 0x15, 0x3e, 0x3e, 0xbe, 0x47, 0x8d, 0x3e, 0x1, +0xbe, 0x35, 0x0, 0xe1, 0xa1, 0x23, 0xc2, 0x70, 0xaa, 0x25, 0xc2, 0xc5, 0xc7, 0x67, 0x42, 0xc1, 0xaa, 0x8a, 0x3e, 0xd0, +0xbd, 0x8e, 0x3d, 0x1, 0xbe, 0x35, 0x0, 0xb8, 0xed, 0x61, 0xc2, 0x71, 0xaa, 0x25, 0xc2, 0x1c, 0x9f, 0x2b, 0x42, 0x3a, +0x77, 0x1b, 0x3e, 0xf0, 0xcd, 0x1f, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xe3, 0xa1, 0x23, 0xc2, 0xd7, 0x93, 0x88, 0xc1, 0xbd, +0xc7, 0x67, 0x42, 0xc1, 0xaa, 0x8a, 0x3e, 0xd0, 0xbd, 0x8e, 0x3d, 0x1, 0xbe, 0x35, 0x0, 0xb8, 0xed, 0x61, 0xc2, 0xd8, +0x93, 0x88, 0xc1, 0x1c, 0x9f, 0x2b, 0x42, 0x3a, 0x77, 0x1b, 0x3e, 0xf0, 0xcd, 0x1f, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xb7, +0x62, 0x44, 0xc2, 0x5b, 0xba, 0x4c, 0xc1, 0x8, 0xd7, 0xd0, 0x41, 0xca, 0x15, 0x3e, 0x3e, 0xbe, 0x47, 0x8d, 0x3e, 0x1, +0xbe, 0x35, 0x0, 0x84, 0x41, 0x5c, 0xc2, 0xc9, 0xc5, 0x36, 0xc2, 0xd1, 0xa3, 0xf7, 0xc0, 0xe, 0x65, 0xe8, 0x3d, 0xc6, +0xd7, 0xfe, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0x29, 0x4f, 0x86, 0xc2, 0x71, 0xaa, 0x25, 0xc2, 0xc6, 0xaa, 0xb6, 0x41, 0xb1, +0xfc, 0x79, 0x3d, 0xee, 0xcd, 0x8f, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xe, 0xd4, 0x8d, 0xc2, 0x73, 0xaa, 0x25, 0xc2, 0xb2, +0x82, 0xc1, 0x3f, 0x17, 0x2a, 0x7f, 0x3c, 0x68, 0x59, 0xd7, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0x2a, 0x4f, 0x86, 0xc2, 0xda, +0x93, 0x88, 0xc1, 0xb6, 0xaa, 0xb6, 0x41, 0xb1, 0xfc, 0x79, 0x3d, 0xee, 0xcd, 0x8f, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xe, +0xd4, 0x8d, 0xc2, 0xdc, 0x93, 0x88, 0xc1, 0xb2, 0x82, 0xc1, 0x3f, 0x17, 0x2a, 0x7f, 0x3c, 0x68, 0x59, 0xd7, 0x3e, 0x1, +0xbe, 0x35, 0x0, 0x86, 0x41, 0x5c, 0xc2, 0x61, 0xba, 0x4c, 0xc1, 0x10, 0xa4, 0xf7, 0xc0, 0xe, 0x65, 0xe8, 0x3d, 0xc6, +0xd7, 0xfe, 0x3e, 0x1, 0xbe, 0x35, 0x0, 0xed, 0xfe, 0x1f, 0xc2, 0xca, 0xc5, 0x36, 0xc2, 0x9b, 0x81, 0x1a, 0xc2, 0xca, +0x15, 0x3e, 0x3e, 0xe8, 0x33, 0x38, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x2e, 0x80, 0x87, 0xc2, 0x73, 0xaa, 0x25, 0xc2, 0xc5, +0xff, 0xa7, 0xc1, 0x17, 0x2a, 0x7f, 0x3c, 0x13, 0x2b, 0x13, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xa1, 0x9, 0x69, 0xc2, 0x74, +0xaa, 0x25, 0xc2, 0x3e, 0xd6, 0x21, 0xc2, 0xb1, 0xfc, 0x79, 0x3d, 0xd0, 0xf0, 0x36, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x2e, +0x80, 0x87, 0xc2, 0xde, 0x93, 0x88, 0xc1, 0xc5, 0xff, 0xa7, 0xc1, 0x17, 0x2a, 0x7f, 0x3c, 0x13, 0x2b, 0x13, 0x3f, 0x1, +0xbe, 0x35, 0x0, 0xa0, 0x9, 0x69, 0xc2, 0xdf, 0x93, 0x88, 0xc1, 0x3f, 0xd6, 0x21, 0xc2, 0xb1, 0xfc, 0x79, 0x3d, 0xd0, +0xf0, 0x36, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xec, 0xfe, 0x1f, 0xc2, 0x67, 0xba, 0x4c, 0xc1, 0x9b, 0x81, 0x1a, 0xc2, 0xca, +0x15, 0x3e, 0x3e, 0xe8, 0x33, 0x38, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xac, 0x7d, 0x1a, 0xc1, 0xcb, 0xc5, 0x36, 0xc2, 0x94, +0xa, 0x5b, 0xc2, 0x50, 0xc3, 0xbf, 0x3e, 0xb6, 0x4b, 0x5b, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xf7, 0xde, 0x29, 0xc2, 0x75, +0xaa, 0x25, 0xc2, 0x66, 0x3f, 0x63, 0xc2, 0x3a, 0x77, 0x1b, 0x3e, 0x4c, 0xe4, 0x56, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xd1, +0xcf, 0xba, 0xc1, 0x76, 0xaa, 0x25, 0xc2, 0xcd, 0xf3, 0x85, 0xc2, 0xc1, 0xaa, 0x8a, 0x3e, 0xd, 0x0, 0x6d, 0x3f, 0x1, +0xbe, 0x35, 0x0, 0xf6, 0xde, 0x29, 0xc2, 0xe0, 0x93, 0x88, 0xc1, 0x66, 0x3f, 0x63, 0xc2, 0x3a, 0x77, 0x1b, 0x3e, 0x4c, +0xe4, 0x56, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xd0, 0xcf, 0xba, 0xc1, 0xe1, 0x93, 0x88, 0xc1, 0xcd, 0xf3, 0x85, 0xc2, 0xc1, +0xaa, 0x8a, 0x3e, 0xd, 0x0, 0x6d, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xaa, 0x7d, 0x1a, 0xc1, 0x6b, 0xba, 0x4c, 0xc1, 0x94, +0xa, 0x5b, 0xc2, 0x50, 0xc3, 0xbf, 0x3e, 0xb6, 0x4b, 0x5b, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x84, 0x1, 0xc3, 0x41, 0xcb, +0xc5, 0x36, 0xc2, 0xf8, 0xe8, 0x47, 0xc2, 0x72, 0xa8, 0x1b, 0x3f, 0xb6, 0x4b, 0x5b, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x3b, +0xc3, 0x76, 0xbf, 0x77, 0xaa, 0x25, 0xc2, 0xef, 0xd8, 0x8d, 0xc2, 0x5d, 0xe1, 0xd5, 0x3e, 0x59, 0x34, 0x79, 0x3f, 0x1, +0xbe, 0x35, 0x0, 0x9c, 0xce, 0xa3, 0x41, 0x76, 0xaa, 0x25, 0xc2, 0x30, 0xd2, 0x87, 0xc2, 0x7c, 0x99, 0x10, 0x3f, 0x59, +0x34, 0x79, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x3, 0xc3, 0x76, 0xbf, 0xe2, 0x93, 0x88, 0xc1, 0xef, 0xd8, 0x8d, 0xc2, 0x5d, +0xe1, 0xd5, 0x3e, 0x59, 0x34, 0x79, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x9e, 0xce, 0xa3, 0x41, 0xe2, 0x93, 0x88, 0xc1, 0x31, +0xd2, 0x87, 0xc2, 0x7c, 0x99, 0x10, 0x3f, 0x59, 0x34, 0x79, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x84, 0x1, 0xc3, 0x41, 0x6b, +0xba, 0x4c, 0xc1, 0xf8, 0xe8, 0x47, 0xc2, 0x72, 0xa8, 0x1b, 0x3f, 0xb6, 0x4b, 0x5b, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xc2, +0x62, 0x44, 0x42, 0xca, 0xc5, 0x36, 0xc2, 0xf8, 0xd6, 0xd0, 0xc1, 0xb8, 0x4, 0x4c, 0x3f, 0xe8, 0x33, 0x38, 0x3f, 0x1, +0xbe, 0x35, 0x0, 0xeb, 0xa1, 0x23, 0x42, 0x76, 0xaa, 0x25, 0xc2, 0xbc, 0xc7, 0x67, 0xc2, 0xca, 0x34, 0x36, 0x3f, 0xd, +0x0, 0x6d, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xc2, 0xed, 0x61, 0x42, 0x75, 0xaa, 0x25, 0xc2, 0x13, 0x9f, 0x2b, 0xc2, 0x5c, +0xac, 0x54, 0x3f, 0x4c, 0xe4, 0x56, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xec, 0xa1, 0x23, 0x42, 0xe2, 0x93, 0x88, 0xc1, 0xbc, +0xc7, 0x67, 0xc2, 0xca, 0x34, 0x36, 0x3f, 0xd, 0x0, 0x6d, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xc2, 0xed, 0x61, 0x42, 0xe2, +0x93, 0x88, 0xc1, 0x13, 0x9f, 0x2b, 0xc2, 0x5c, 0xac, 0x54, 0x3f, 0x4c, 0xe4, 0x56, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0xc2, +0x62, 0x44, 0x42, 0x67, 0xba, 0x4c, 0xc1, 0xf8, 0xd6, 0xd0, 0xc1, 0xb8, 0x4, 0x4c, 0x3f, 0xe8, 0x33, 0x38, 0x3f, 0x1, +0xbe, 0x35, 0x0, 0x30, 0x4f, 0x86, 0x42, 0x74, 0xaa, 0x25, 0xc2, 0xa7, 0xaa, 0xb6, 0xc1, 0x60, 0xea, 0x6b, 0x3f, 0xd0, +0xf0, 0x36, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x14, 0xd4, 0x8d, 0x42, 0x73, 0xaa, 0x25, 0xc2, 0xa5, 0x81, 0xc1, 0xbf, 0x82, +0x8d, 0x77, 0x3f, 0x13, 0x2b, 0x13, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x30, 0x4f, 0x86, 0x42, 0xdf, 0x93, 0x88, 0xc1, 0xa8, +0xaa, 0xb6, 0xc1, 0x60, 0xea, 0x6b, 0x3f, 0xd0, 0xf0, 0x36, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x14, 0xd4, 0x8d, 0x42, 0xdd, +0x93, 0x88, 0xc1, 0xb5, 0x81, 0xc1, 0xbf, 0x82, 0x8d, 0x77, 0x3f, 0x13, 0x2b, 0x13, 0x3f, 0x1, 0xbe, 0x35, 0x0, 0x7, +0x73, 0x30, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xfe, 0x23, 0x5b, 0x42, 0x82, 0xe4, 0xd, 0x3e, 0x90, 0xca, 0x6d, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x75, 0xc8, 0x2b, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xcb, 0xad, 0x8c, 0x42, 0x58, 0x72, 0x15, 0x3e, 0x0, +0x4d, 0x5, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0xe9, 0x1e, 0x64, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xb3, 0x78, 0x8c, 0x42, 0x26, +0xfe, 0x68, 0x3d, 0x0, 0xd5, 0x69, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x83, 0xc1, 0x68, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xfe, +0x23, 0x5b, 0x42, 0x2f, 0xfa, 0x4a, 0x3d, 0x90, 0xca, 0x6d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe1, 0x89, 0x66, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0x51, 0x39, 0x8c, 0x42, 0x71, 0x55, 0x59, 0x3d, 0x80, 0xf2, 0xb0, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0xf3, +0xee, 0x68, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x28, 0x7b, 0x8b, 0x42, 0x95, 0xd4, 0x49, 0x3d, 0x40, 0x89, 0x32, 0x3c, 0x1, +0xbe, 0x38, 0x0, 0x47, 0x7f, 0x61, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0x98, 0xfa, 0x79, 0x3d, 0x10, +0x77, 0xc5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd3, 0x31, 0x66, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xa3, 0xf, 0xe6, 0x41, 0xde, +0x8f, 0x5b, 0x3d, 0x78, 0xd, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x53, 0x45, 0x4c, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xa3, +0xf, 0xe6, 0x41, 0x4e, 0xb6, 0xc1, 0x3d, 0x78, 0xd, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8d, 0xcb, 0x4d, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0xc5, 0xc6, 0xbc, 0x3d, 0x10, 0x77, 0xc5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x23, +0x4e, 0x6b, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x3c, 0x3e, 0x8a, 0x42, 0x6c, 0x78, 0x3a, 0x3d, 0xa0, 0x4e, 0xa4, 0x3c, 0x1, +0xbe, 0x38, 0x0, 0x65, 0xa7, 0x6d, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x88, 0x82, 0x88, 0x42, 0xf, 0x43, 0x2b, 0x3d, 0x40, +0xaf, 0x6, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x75, 0xe3, 0x68, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x68, 0x2, 0x5b, 0x42, 0x8, +0x1f, 0x4a, 0x3d, 0xb0, 0x49, 0x6e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc3, 0xfa, 0x6f, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x12, +0x48, 0x86, 0x42, 0x7f, 0x34, 0x1c, 0x3d, 0x30, 0x38, 0x4a, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xf, 0x8, 0x69, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0x51, 0xda, 0x5a, 0x42, 0xe, 0x32, 0x49, 0x3d, 0xbc, 0xe1, 0x6e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4b, +0x2f, 0x69, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xb8, 0xab, 0x5a, 0x42, 0x40, 0x33, 0x48, 0x3d, 0x28, 0x92, 0x6f, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x33, 0x59, 0x69, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xa2, 0x76, 0x5a, 0x42, 0xab, 0x23, 0x47, 0x3d, 0x38, +0x5b, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc3, 0x85, 0x69, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x9, 0x3b, 0x5a, 0x42, 0x4f, +0x3, 0x46, 0x3d, 0x30, 0x3d, 0x71, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf7, 0xb4, 0x69, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xf0, +0xf8, 0x59, 0x42, 0x2d, 0xd2, 0x44, 0x3d, 0x8c, 0x37, 0x72, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd5, 0xe6, 0x69, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0x58, 0xb0, 0x59, 0x42, 0x36, 0x8f, 0x43, 0x3d, 0x88, 0x4a, 0x73, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x2d, +0xaf, 0x4a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0x38, 0xd9, 0xc6, 0x3d, 0x10, 0x77, 0xc5, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x39, 0x48, 0x72, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xd6, 0x8e, 0x83, 0x42, 0xad, 0x4b, 0xd, 0x3d, 0x10, +0x62, 0x8e, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x49, 0x1a, 0x6a, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x3f, 0x61, 0x59, 0x42, 0xc4, +0x41, 0x42, 0x3d, 0x28, 0x76, 0x74, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x37, 0x4e, 0x6a, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xa9, +0xb, 0x59, 0x42, 0x2c, 0xf1, 0x40, 0x3d, 0x70, 0xba, 0x75, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9d, 0x82, 0x6a, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0x8d, 0xaf, 0x58, 0x42, 0x7c, 0x9e, 0x3f, 0x3d, 0x58, 0x17, 0x77, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x87, +0xb7, 0x6a, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xf5, 0x4c, 0x58, 0x42, 0x99, 0x47, 0x3e, 0x3d, 0xe8, 0x8c, 0x78, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xeb, 0xec, 0x6a, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xdb, 0xe3, 0x57, 0x42, 0x91, 0xed, 0x3c, 0x3d, 0x18, +0x1b, 0x7a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc7, 0x22, 0x6b, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x41, 0x74, 0x57, 0x42, 0x71, +0x91, 0x3b, 0x3d, 0xf0, 0xc1, 0x7b, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc7, 0x8f, 0x74, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xd1, +0x56, 0x80, 0x42, 0x38, 0x11, 0xfd, 0x3c, 0x8, 0x29, 0xbf, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x27, 0x59, 0x6b, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0x27, 0xfe, 0x56, 0x42, 0x1f, 0x31, 0x3a, 0x3d, 0x28, 0x81, 0x7d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xb5, +0xb9, 0x6b, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x4b, 0x3d, 0x56, 0x42, 0x2b, 0xc0, 0x37, 0x3d, 0x2, 0x2e, 0x80, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x2b, 0x19, 0x6c, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xc1, 0x66, 0x55, 0x42, 0x82, 0x55, 0x35, 0x3d, 0x54, +0xc4, 0x81, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x87, 0x77, 0x6c, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x8b, 0x7a, 0x54, 0x42, 0x3d, +0xf3, 0x32, 0x3d, 0xd0, 0x83, 0x83, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x63, 0xb8, 0x76, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xc3, +0x89, 0x79, 0x42, 0xbd, 0x1d, 0xe1, 0x3c, 0xa0, 0x42, 0xf5, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xd3, 0xd4, 0x6c, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0xac, 0x78, 0x53, 0x42, 0x42, 0x97, 0x30, 0x3d, 0x50, 0x6c, 0x85, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x7, +0x31, 0x6d, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x1f, 0x61, 0x52, 0x42, 0x92, 0x41, 0x2e, 0x3d, 0xd8, 0x7d, 0x87, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x27, 0x8c, 0x6d, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xea, 0x33, 0x51, 0x42, 0x38, 0xf3, 0x2b, 0x3d, 0x66, +0xb8, 0x89, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf1, 0xab, 0x4b, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x27, 0xd0, 0xe5, 0x41, 0xce, +0xa6, 0xc3, 0x3d, 0x8c, 0x2b, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb, 0xa9, 0x78, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xb1, +0xfb, 0x71, 0x42, 0xc6, 0xfd, 0xc7, 0x3c, 0x80, 0x40, 0x17, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x31, 0xe6, 0x6d, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0x6, 0xf1, 0x4f, 0x42, 0x36, 0xac, 0x29, 0x3d, 0xfc, 0x1b, 0x8c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6b, +0x3b, 0x6e, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xf9, 0x9e, 0x4e, 0x42, 0xa9, 0x84, 0x27, 0x3d, 0x46, 0x9c, 0x8e, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x11, 0x88, 0x6e, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x40, 0x44, 0x4d, 0x42, 0xaf, 0x94, 0x25, 0x3d, 0x12, +0x2d, 0x91, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xbb, 0x61, 0x7a, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x72, 0x3, 0x6a, 0x42, 0x53, +0xb1, 0xb1, 0x3c, 0x14, 0x72, 0x35, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x27, 0xcc, 0x6e, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xdb, +0xe0, 0x4b, 0x42, 0x3c, 0xdb, 0x23, 0x3d, 0x42, 0xce, 0x93, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xb5, 0x7, 0x6f, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0xcc, 0x74, 0x4a, 0x42, 0x68, 0x5a, 0x22, 0x3d, 0xf6, 0x7f, 0x96, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x73, +0xe2, 0x7b, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x2, 0xa1, 0x61, 0x42, 0x97, 0x3c, 0x9e, 0x3c, 0xc8, 0x35, 0x55, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xad, 0x3a, 0x6f, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x12, 0x0, 0x49, 0x42, 0x1b, 0x10, 0x21, 0x3d, 0xea, +0x41, 0x99, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x17, 0x65, 0x6f, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xab, 0x82, 0x47, 0x42, 0x61, +0xfd, 0x1f, 0x3d, 0x62, 0x14, 0x9c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x3b, 0x2b, 0x7d, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x67, +0xd4, 0x58, 0x42, 0x46, 0x99, 0x8d, 0x3c, 0xa0, 0x8b, 0x76, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf7, 0x86, 0x6f, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0x9c, 0xfc, 0x45, 0x42, 0x3a, 0x22, 0x1f, 0x3d, 0x3c, 0xf7, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf1, +0x45, 0x77, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x9c, 0x69, 0xbd, 0x41, 0xbb, 0xf2, 0xd9, 0x3c, 0x51, 0x4d, 0x31, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x5, 0x3c, 0x7e, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x99, 0x9d, 0x4f, 0x42, 0x56, 0x9b, 0x7f, 0x3c, 0xe, +0xba, 0x8c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xdf, 0x14, 0x7f, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x9c, 0xfc, 0x45, 0x42, 0x2a, +0xab, 0x69, 0x3c, 0x3c, 0xf7, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa4, 0x39, 0x80, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x84, +0xbc, 0x33, 0x42, 0xb1, 0x36, 0x46, 0x3c, 0x58, 0x89, 0xc1, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x31, 0x78, 0x81, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xcd, 0x8d, 0x12, 0x42, 0x4c, 0xc2, 0x5, 0x3c, 0x34, 0x32, 0x0, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe8, +0x6d, 0x83, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x3e, 0x95, 0xbc, 0x41, 0xc9, 0xe8, 0x0, 0x3b, 0xea, 0xb1, 0x31, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xe7, 0x6a, 0x77, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x16, 0xc6, 0xb8, 0x41, 0x94, 0x14, 0xd8, 0x3c, 0xae, +0x7f, 0x33, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb9, 0x7e, 0x77, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x92, 0x56, 0xb4, 0x41, 0xba, +0x14, 0xd7, 0x3c, 0x68, 0x99, 0x35, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6b, 0x81, 0x77, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xd, +0x1b, 0xb0, 0x41, 0x13, 0xf1, 0xd6, 0x3c, 0x8d, 0x9a, 0x37, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc7, 0x92, 0x47, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0xab, 0xeb, 0xd0, 0x3d, 0x10, 0x77, 0xc5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x61, +0x1e, 0x4b, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xaf, 0x11, 0xe5, 0x41, 0x9, 0x71, 0xc5, 0x3d, 0xba, 0x85, 0x1e, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x9d, 0x9c, 0x4a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x41, 0xd4, 0xe3, 0x41, 0xfd, 0x14, 0xc7, 0x3d, 0x11, +0x1c, 0x1f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x13, 0x34, 0x45, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x81, 0x2a, 0x31, 0x42, 0xa6, +0x97, 0xd8, 0x3d, 0xd8, 0x67, 0xc6, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa7, 0x26, 0x4a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xd7, +0x17, 0xe2, 0x41, 0x32, 0x93, 0xc8, 0x3d, 0x80, 0xee, 0x1f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf9, 0x2, 0x43, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x3c, 0xad, 0x2f, 0x42, 0x4f, 0xb0, 0xdf, 0x3d, 0xc, 0x3a, 0xc9, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x79, +0xff, 0x40, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xc3, 0x31, 0x2d, 0x42, 0x1e, 0x35, 0xe6, 0x3d, 0xd0, 0xed, 0xcd, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x7f, 0xbc, 0x49, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x79, 0xdc, 0xdf, 0x41, 0x9a, 0xea, 0xc9, 0x3d, 0x1a, +0xfd, 0x20, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x94, 0x29, 0x3f, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x1f, 0xb8, 0x29, 0x42, 0x9a, +0x26, 0xec, 0x3d, 0x2, 0x83, 0xd4, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4e, 0x81, 0x3d, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x4a, +0x40, 0x25, 0x42, 0x3c, 0x84, 0xf1, 0x3d, 0xa0, 0xf9, 0xdc, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa4, 0x6, 0x3c, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x46, 0xca, 0x1f, 0x42, 0x5, 0x4e, 0xf6, 0x3d, 0xce, 0x51, 0xe7, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x23, +0x5e, 0x49, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x1d, 0x22, 0xdd, 0x41, 0x43, 0x1c, 0xcb, 0x3d, 0xcc, 0x47, 0x22, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x96, 0xb9, 0x3a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x13, 0x56, 0x19, 0x42, 0x7b, 0x84, 0xfa, 0x3d, 0x8a, +0x8b, 0xf3, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x7, 0xa7, 0x39, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x92, 0x2d, 0x12, 0x42, 0xac, +0xfd, 0xfd, 0x3d, 0x5c, 0x8d, 0x0, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x99, 0xb, 0x49, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xc8, +0xe8, 0xd9, 0x41, 0xa6, 0x27, 0xcc, 0x3d, 0xa7, 0xce, 0x23, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd5, 0xdb, 0x38, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xa7, 0x9a, 0xa, 0x42, 0x91, 0x47, 0x0, 0x3e, 0xbf, 0xb9, 0x7, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xfd, +0x57, 0x38, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x4c, 0x9d, 0x2, 0x42, 0xf3, 0x1c, 0x1, 0x3e, 0xec, 0x4a, 0xf, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xdf, 0xc7, 0x48, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x8d, 0x53, 0xd6, 0x41, 0xcd, 0x2, 0xcd, 0x3d, 0x6, +0x81, 0x25, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x87, 0x1b, 0x38, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x13, 0x6b, 0xf4, 0x41, 0xfe, +0x7e, 0x1, 0x3e, 0xe6, 0x40, 0x17, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6c, 0x26, 0x38, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xb3, +0xc6, 0xe2, 0x41, 0x6e, 0x6d, 0x1, 0x3e, 0xbb, 0x9b, 0x1f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xfd, 0x95, 0x48, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x82, 0x85, 0xd2, 0x41, 0x48, 0xa4, 0xcd, 0x3d, 0x44, 0x4e, 0x27, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb3, +0x78, 0x38, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x7b, 0x4d, 0xd0, 0x41, 0xff, 0xe7, 0x0, 0x3e, 0x4a, 0x5b, 0x28, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xf1, 0x75, 0x48, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xa7, 0x7e, 0xce, 0x41, 0x17, 0xc, 0xce, 0x3d, 0x72, +0x36, 0x29, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x54, 0x12, 0x39, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x6d, 0xff, 0xbc, 0x41, 0xf8, +0xde, 0xff, 0x3d, 0xa6, 0x7f, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xbd, 0x67, 0x48, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xf9, +0x3e, 0xca, 0x41, 0x3b, 0x3a, 0xce, 0x3d, 0x7e, 0x39, 0x2b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3c, 0xe9, 0x39, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xb7, 0xe9, 0xa9, 0x41, 0x3d, 0x27, 0xfd, 0x3d, 0x54, 0x89, 0x3a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x65, +0x6b, 0x48, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x7e, 0xc6, 0xc5, 0x41, 0x2c, 0x2e, 0xce, 0x3d, 0x7a, 0x57, 0x2d, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xe1, 0xf7, 0x3a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x2d, 0xa0, 0x97, 0x41, 0xa1, 0xba, 0xf9, 0x3d, 0x48, +0x32, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdd, 0x80, 0x48, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x30, 0x15, 0xc1, 0x41, 0x71, +0xe8, 0xcd, 0x3d, 0x64, 0x90, 0x2f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3a, 0x3e, 0x3c, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xcd, +0x22, 0x86, 0x41, 0x31, 0x9a, 0xf5, 0x3d, 0x92, 0x7a, 0x4b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x2f, 0xa8, 0x48, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xe, 0x2b, 0xbc, 0x41, 0x90, 0x69, 0xcd, 0x3d, 0x2e, 0xe4, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x31, +0xdd, 0x48, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x1c, 0x77, 0xb7, 0x41, 0x98, 0xbd, 0xcc, 0x3d, 0x58, 0x1e, 0x34, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x55, 0xbc, 0x3d, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x39, 0xe3, 0x6a, 0x41, 0x65, 0xc5, 0xf0, 0x3d, 0x30, +0x62, 0x53, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x43, 0x20, 0x49, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xfa, 0xee, 0xb2, 0x41, 0x8a, +0xe4, 0xcb, 0x3d, 0xbc, 0x43, 0x36, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x26, 0x72, 0x3f, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x2e, +0x19, 0x4b, 0x41, 0xb8, 0x3b, 0xeb, 0x3d, 0x25, 0xe9, 0x5a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x69, 0x71, 0x49, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xa8, 0x92, 0xae, 0x41, 0xdf, 0xdd, 0xca, 0x3d, 0x58, 0x54, 0x38, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x9b, +0xd0, 0x49, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0x62, 0xaa, 0x41, 0x97, 0xa9, 0xc9, 0x3d, 0x40, 0x50, 0x3a, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xb7, 0x5f, 0x41, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x7d, 0xe7, 0x2c, 0x41, 0xb1, 0xfd, 0xe4, 0x3d, 0x5e, +0xf, 0x62, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe1, 0x3d, 0x4a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x77, 0x5d, 0xa6, 0x41, 0xb2, +0x47, 0xc8, 0x3d, 0x60, 0x37, 0x3c, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3b, 0xb9, 0x4a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x96, +0x84, 0xa2, 0x41, 0xb7, 0xb8, 0xc6, 0x3d, 0xcc, 0x9, 0x3e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xfd, 0x84, 0x43, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x26, 0x4e, 0x10, 0x41, 0x4e, 0xb, 0xde, 0x3d, 0xed, 0xd4, 0x68, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa5, +0x42, 0x4b, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x85, 0xd7, 0x9e, 0x41, 0x98, 0xfb, 0xc4, 0x3d, 0x72, 0xc7, 0x3f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xfd, 0xd3, 0x4b, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x5a, 0x86, 0x9b, 0x41, 0x4e, 0x25, 0xc3, 0x3d, 0x92, +0x59, 0x41, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdd, 0xc9, 0x45, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xb3, 0xfa, 0xec, 0x40, 0xaf, +0xb2, 0xd6, 0x3d, 0xbb, 0xf1, 0x6e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1d, 0x67, 0x4c, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x29, +0xc1, 0x98, 0x41, 0xbb, 0x48, 0xc1, 0x3d, 0x72, 0xa9, 0x42, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3b, 0x16, 0x48, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x92, 0x4a, 0xc1, 0x40, 0xf2, 0x41, 0xcf, 0x3d, 0xd2, 0x1d, 0x74, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd, +0xfc, 0x4c, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xf4, 0x87, 0x96, 0x41, 0x62, 0x66, 0xbf, 0x3d, 0xfe, 0xb6, 0x43, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xc5, 0x92, 0x4d, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xb5, 0xda, 0x94, 0x41, 0xcc, 0x7e, 0xbd, 0x3d, 0x49, +0x82, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x13, 0x6a, 0x4a, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xed, 0x8b, 0x9d, 0x40, 0x91, +0xb8, 0xc7, 0x3d, 0x32, 0x59, 0x78, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4d, 0x2b, 0x4e, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x73, +0xb9, 0x93, 0x41, 0xeb, 0x90, 0xbb, 0x3d, 0x42, 0xb, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6d, 0xc5, 0x4c, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0xc2, 0xbe, 0x81, 0x40, 0x98, 0x17, 0xc0, 0x3d, 0xca, 0xa3, 0x7b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x9b, +0xc5, 0x4e, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x2b, 0x24, 0x93, 0x41, 0x45, 0x9d, 0xb9, 0x3d, 0xf8, 0x51, 0x45, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x39, 0x28, 0x4f, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x22, 0xc6, 0x5b, 0x40, 0xfb, 0x5d, 0xb8, 0x3d, 0xac, +0xfd, 0x7d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb3, 0x61, 0x4f, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xda, 0x1a, 0x93, 0x41, 0xdb, +0xa3, 0xb7, 0x3d, 0x5c, 0x56, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xcf, 0xac, 0x73, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xda, +0x1a, 0x93, 0x41, 0xb7, 0x46, 0x4, 0x3d, 0x5c, 0x56, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x85, 0x92, 0x51, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0xb2, 0xf1, 0x43, 0x40, 0x3f, 0x8c, 0xb0, 0x3d, 0xc7, 0x66, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4d, +0x4, 0x54, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0xe0, 0xa1, 0xa8, 0x3d, 0x2b, 0xdf, 0x7f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x67, 0x4f, 0x78, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x7f, 0x85, 0xcc, 0x3c, 0x1a, +0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x29, 0xef, 0x73, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xda, 0x1a, 0x93, 0x41, 0xcc, +0x98, 0x2, 0x3d, 0x5c, 0x56, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x89, 0x31, 0x74, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xda, +0x1a, 0x93, 0x41, 0xe2, 0xea, 0x0, 0x3d, 0x5c, 0x56, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x39, 0xa8, 0x74, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x8c, 0x0, 0x94, 0x41, 0x8d, 0xd4, 0xfb, 0x3c, 0x92, 0xe9, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1b, +0x18, 0x75, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x9a, 0x45, 0x95, 0x41, 0x6b, 0x2b, 0xf6, 0x3c, 0xa0, 0x4f, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x4f, 0xb9, 0x83, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x9d, 0x8b, 0xa9, 0x41, 0x64, 0xca, 0x87, 0x3a, 0xd4, +0xb5, 0x3a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3, 0x73, 0x77, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x8e, 0x13, 0xac, 0x41, 0xb9, +0xab, 0xd7, 0x3c, 0xfe, 0x82, 0x39, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x61, 0xa7, 0x7a, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x8d, +0xec, 0x43, 0x40, 0x8c, 0x2b, 0xae, 0x3c, 0xa, 0x67, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x27, 0x81, 0x75, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x1, 0xea, 0x96, 0x41, 0x77, 0xdc, 0xf0, 0x3c, 0x87, 0x88, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6b, +0xd3, 0x7c, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x8e, 0xb1, 0x5b, 0x40, 0x7, 0xc, 0x92, 0x3c, 0xda, 0xfe, 0x7d, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x5d, 0xe3, 0x75, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xc1, 0xed, 0x98, 0x41, 0x7e, 0xe3, 0xeb, 0x3c, 0x57, +0x94, 0x42, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x7f, 0xd3, 0x7e, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x9a, 0xa7, 0x81, 0x40, 0xaa, +0x49, 0x70, 0x3c, 0x8b, 0xa6, 0x7b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd4, 0x53, 0x80, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xc1, +0x62, 0x9d, 0x40, 0xbc, 0xe7, 0x40, 0x3c, 0xb, 0x5e, 0x78, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc3, 0x3e, 0x76, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xdc, 0x50, 0x9b, 0x41, 0xb3, 0x44, 0xe7, 0x3c, 0xef, 0x72, 0x41, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf1, +0x27, 0x81, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x3d, 0xa, 0xc1, 0x40, 0xda, 0xfe, 0x15, 0x3c, 0x6c, 0x25, 0x74, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x15, 0xe6, 0x81, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xe, 0x9e, 0xec, 0x40, 0xde, 0x4, 0xdf, 0x3b, 0xbd, +0xfc, 0x6e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x43, 0x8e, 0x82, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x1a, 0xf, 0x10, 0x41, 0xba, +0xf5, 0x9a, 0x3b, 0xde, 0xe3, 0x68, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x55, 0x93, 0x76, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x4e, +0x13, 0x9e, 0x41, 0xe3, 0xfb, 0xe2, 0x3c, 0x5f, 0x24, 0x40, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8e, 0x19, 0x83, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xf5, 0x95, 0x2c, 0x41, 0xa5, 0x32, 0x45, 0x3b, 0xa3, 0x22, 0x62, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x11, +0xe1, 0x76, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x19, 0x35, 0xa1, 0x41, 0x41, 0xd, 0xdf, 0x3c, 0xa8, 0xa8, 0x3e, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x13, 0x81, 0x83, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x37, 0xb4, 0x4a, 0x41, 0xb9, 0xe2, 0xe2, 0x3a, 0x0, +0x1, 0x5b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xcd, 0xc4, 0x83, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xdd, 0x69, 0x6a, 0x41, 0x53, +0x5b, 0x6a, 0x3a, 0xf6, 0x7e, 0x53, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd5, 0x22, 0x77, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x94, +0xa0, 0xa4, 0x41, 0xd0, 0xb9, 0xdb, 0x3c, 0x14, 0xa, 0x3d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc2, 0xe4, 0x83, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x75, 0xdb, 0x85, 0x41, 0x6f, 0x12, 0x3, 0x3a, 0x63, 0x9c, 0x4b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xeb, +0xe0, 0x83, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xb0, 0x4d, 0x97, 0x41, 0x8c, 0x64, 0xf, 0x3a, 0x58, 0x59, 0x43, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x7d, 0x53, 0x77, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xf, 0x40, 0xa8, 0x41, 0xaa, 0x44, 0xd9, 0x3c, 0xda, +0x52, 0x3b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x29, 0xe3, 0xd9, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0x23, 0x5b, 0x42, 0x77, +0x2b, 0x7b, 0x3e, 0x90, 0xca, 0x6d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x17, 0x7e, 0xd0, 0xc2, 0x8, 0x59, 0x8e, 0xc1, 0xe3, +0xe2, 0x8c, 0x42, 0x13, 0x63, 0x81, 0x3e, 0x0, 0x14, 0x3, 0x3a, 0x1, 0xbe, 0x38, 0x0, 0x21, 0x22, 0x11, 0xc3, 0x8, +0x59, 0x8e, 0xc1, 0xcb, 0xad, 0x8c, 0x42, 0x35, 0x96, 0x40, 0x3e, 0x0, 0x4d, 0x5, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0xb5, +0xcc, 0x15, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0x23, 0x5b, 0x42, 0x5f, 0x8, 0x39, 0x3e, 0x90, 0xca, 0x6d, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x20, 0x8d, 0x13, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x4e, 0x6e, 0x8c, 0x42, 0x4b, 0xac, 0x3c, 0x3e, 0x0, +0x8f, 0x7d, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x3e, 0xf2, 0x15, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0xd9, 0xaf, 0x8b, 0x42, 0xd1, +0xcb, 0x38, 0x3e, 0x80, 0x95, 0x19, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0xcf, 0x61, 0xed, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x1, +0xe4, 0xe6, 0x41, 0x17, 0x64, 0x6b, 0x3e, 0xf0, 0xa8, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xab, 0xc, 0xe4, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0xed, 0xf1, 0x72, 0x3e, 0x10, 0x77, 0xc5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x60, +0x18, 0x1e, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0x9e, 0x9a, 0x2b, 0x3e, 0x10, 0x77, 0xc5, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xf5, 0xc2, 0x22, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x1, 0xe4, 0xe6, 0x41, 0xb, 0xd, 0x24, 0x3e, 0xde, +0xa8, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x67, 0xc0, 0xf7, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x8f, +0xff, 0x62, 0x3e, 0x2b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x33, 0x7b, 0xee, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0xda, +0x1a, 0x93, 0x41, 0x49, 0x80, 0x6a, 0x3e, 0x5c, 0x56, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xfe, 0xb7, 0x20, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0xda, 0x1a, 0x93, 0x41, 0x81, 0x5b, 0x27, 0x3e, 0x5c, 0x56, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x9a, +0x5a, 0x25, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x83, 0xda, 0x1f, 0x3e, 0x2b, 0xdf, 0x7f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x2b, 0xd6, 0x20, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x2e, 0x1f, 0x93, 0x41, 0xbf, 0x2a, 0x27, 0x3e, 0x54, +0x54, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x7f, 0x51, 0x18, 0xc3, 0x8, 0x59, 0x8e, 0xc1, 0x6a, 0x72, 0x8a, 0x42, 0xc7, +0xf4, 0x34, 0x3e, 0x20, 0xf4, 0x97, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0x4, 0xf4, 0x20, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x2e, +0x2c, 0x93, 0x41, 0x40, 0xfa, 0x26, 0x3e, 0x2b, 0x4e, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8b, 0x11, 0x21, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0xdb, 0x41, 0x93, 0x41, 0x8a, 0xca, 0x26, 0x3e, 0xe1, 0x43, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdc, +0xaa, 0x1a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x0, 0xb6, 0x88, 0x42, 0x2d, 0x27, 0x31, 0x3e, 0x0, 0x97, 0x0, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0x28, 0x66, 0x16, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x68, 0xe8, 0x5a, 0x42, 0x1f, 0x10, 0x38, 0x3e, 0x44, +0xac, 0x6e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x60, 0xfe, 0x1c, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xa0, 0x7a, 0x86, 0x42, 0x45, +0x63, 0x2d, 0x3e, 0x40, 0x3c, 0x44, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x95, 0xfe, 0x16, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x4c, +0x72, 0x5a, 0x42, 0x2f, 0x19, 0x37, 0x3e, 0xbc, 0x6b, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf6, 0x95, 0x17, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xad, 0xc1, 0x59, 0x42, 0x57, 0x24, 0x36, 0x3e, 0x0, 0x9, 0x73, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xbc, +0x2e, 0x21, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x2f, 0x60, 0x93, 0x41, 0x5a, 0x9b, 0x26, 0x3e, 0x87, 0x35, 0x45, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x1, 0x4c, 0x1f, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x45, 0xc0, 0x83, 0x42, 0xce, 0xa8, 0x29, 0x3e, 0xe0, +0x74, 0x8b, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x54, 0x2c, 0x18, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x90, 0xd6, 0x58, 0x42, 0xcf, +0x30, 0x35, 0x3e, 0xc4, 0x83, 0x76, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa1, 0x4b, 0x21, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x34, +0x87, 0x93, 0x41, 0x6e, 0x6c, 0x26, 0x3e, 0xc, 0x23, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xab, 0xc1, 0x18, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xed, 0xb0, 0x57, 0x42, 0x1c, 0x3f, 0x34, 0x3e, 0x8, 0xdc, 0x7a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xbe, +0x93, 0x21, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xef, 0x86, 0x80, 0x42, 0xc6, 0xf7, 0x25, 0x3e, 0x48, 0x50, 0xbc, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0xf8, 0x55, 0x19, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xc9, 0x50, 0x56, 0x42, 0xfd, 0x4e, 0x33, 0x3e, 0xc, +0x9, 0x80, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x2c, 0x68, 0x21, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xe0, 0xb6, 0x93, 0x41, 0x4b, +0x3e, 0x26, 0x3e, 0x80, 0xc, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3e, 0xe9, 0x19, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x23, +0xb6, 0x54, 0x42, 0xb3, 0x60, 0x32, 0x3e, 0xf4, 0x12, 0x83, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x94, 0xbc, 0x23, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x13, 0xe7, 0x79, 0x42, 0xd1, 0x78, 0x22, 0x3e, 0xe8, 0x7f, 0xf2, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xf1, +0x74, 0x1a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0xf0, 0x52, 0x42, 0x78, 0x7e, 0x31, 0x3e, 0xec, 0x6e, 0x86, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x76, 0xad, 0x25, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xf6, 0x55, 0x72, 0x42, 0x8f, 0x54, 0x1f, 0x3e, 0xac, +0xea, 0x15, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x7e, 0xf2, 0x1a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0xd, 0x51, 0x42, 0x4e, +0xb3, 0x30, 0x3e, 0x3a, 0x0, 0x8a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe5, 0x61, 0x1b, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xa6, +0xf, 0x4f, 0x42, 0xf4, 0xfe, 0x2f, 0x3e, 0xe2, 0xc6, 0x8d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x67, 0x84, 0x21, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0x37, 0xef, 0x93, 0x41, 0xae, 0x10, 0x26, 0x3e, 0xc3, 0xf1, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x64, +0x66, 0x27, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x88, 0x5a, 0x6a, 0x42, 0xbd, 0x8a, 0x1c, 0x3e, 0x4c, 0x28, 0x34, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x2c, 0xc3, 0x1b, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0xf5, 0x4c, 0x42, 0x67, 0x61, 0x2f, 0x3e, 0x4, +0xc3, 0x91, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4e, 0x16, 0x1c, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x79, 0xbe, 0x4a, 0x42, 0xec, +0xda, 0x2e, 0x3e, 0x5e, 0xf4, 0x95, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x5d, 0xe7, 0x28, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xc6, +0xf4, 0x61, 0x42, 0xa0, 0x1b, 0x1a, 0x3e, 0x98, 0xf8, 0x53, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4d, 0x5b, 0x1c, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0xa0, 0x6b, 0x48, 0x42, 0x40, 0x6b, 0x2e, 0x3e, 0x32, 0x5b, 0x9a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4d, +0xa0, 0x21, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x39, 0x30, 0x94, 0x41, 0x54, 0xe3, 0x25, 0x3e, 0x7, 0xd3, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x64, 0x30, 0x2a, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xb7, 0x24, 0x59, 0x42, 0xf2, 0x6, 0x18, 0x3e, 0x88, +0x5b, 0x75, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x27, 0x92, 0x1c, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x9c, 0xfc, 0x45, 0x42, 0x62, +0x12, 0x2e, 0x3e, 0x5e, 0xf7, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x77, 0x41, 0x2b, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0x53, +0xea, 0x4f, 0x42, 0xf9, 0x4c, 0x16, 0x3e, 0xb2, 0x28, 0x8c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x95, 0x1a, 0x2c, 0xc3, 0xc, +0x59, 0x8e, 0xc1, 0x9d, 0x45, 0x46, 0x42, 0x70, 0xed, 0x14, 0x3e, 0x16, 0x6d, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x7d, +0x79, 0x2d, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xe1, 0xfe, 0x33, 0x42, 0x5f, 0xb5, 0x12, 0x3e, 0xa6, 0xb, 0xc1, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x94, 0xf7, 0x2f, 0xc3, 0xc, 0x59, 0x8e, 0xc1, 0xe5, 0xc2, 0x12, 0x42, 0x86, 0xac, 0xe, 0x3e, 0xde, +0xff, 0xff, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x82, 0xe4, 0x33, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x9b, 0xd7, 0xbc, 0x41, 0xa8, +0x51, 0x8, 0x3e, 0x75, 0x92, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x24, 0x51, 0x24, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x9c, +0x69, 0xbd, 0x41, 0x6e, 0x88, 0x21, 0x3e, 0x51, 0x4d, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4b, 0x6f, 0x24, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0xf5, 0xad, 0xb9, 0x41, 0x69, 0x57, 0x21, 0x3e, 0xe8, 0x11, 0x33, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xee, +0x80, 0x24, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xa6, 0x10, 0xb6, 0x41, 0x19, 0x3b, 0x21, 0x3e, 0x15, 0xc8, 0x34, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x9, 0x86, 0x24, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xa8, 0x91, 0xb2, 0x41, 0xb5, 0x32, 0x21, 0x3e, 0xe7, +0x6f, 0x36, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdf, 0xbb, 0x21, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xe7, 0x79, 0x94, 0x41, 0xc3, +0xb6, 0x25, 0x3e, 0x18, 0xb0, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x20, 0xd7, 0x21, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x41, +0xcc, 0x94, 0x41, 0xb9, 0x8a, 0x25, 0x3e, 0x1a, 0x89, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa7, 0x7e, 0x24, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0x5, 0x31, 0xaf, 0x41, 0xc4, 0x3e, 0x21, 0x3e, 0x5f, 0x9, 0x38, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x99, +0x7b, 0x34, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x88, 0xc6, 0xa9, 0x41, 0x14, 0x5d, 0x7, 0x3e, 0xfa, 0x99, 0x3a, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xbd, 0x6a, 0x24, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xb7, 0xee, 0xab, 0x41, 0x3, 0x5f, 0x21, 0x3e, 0x7d, +0x94, 0x39, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x17, 0xcb, 0x34, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x6d, 0x81, 0x97, 0x41, 0x5d, +0xdc, 0x6, 0x3e, 0xd5, 0x40, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x50, 0x4a, 0x24, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xc1, +0xca, 0xa8, 0x41, 0x71, 0x93, 0x21, 0x3e, 0x30, 0x11, 0x3b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4, 0xd3, 0x34, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0x4b, 0x8, 0x86, 0x41, 0x85, 0xcf, 0x6, 0x3e, 0x27, 0x87, 0x4b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5d, +0x93, 0x34, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x40, 0xb6, 0x6a, 0x41, 0x8b, 0x36, 0x7, 0x3e, 0xdf, 0x6c, 0x53, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x61, 0x1d, 0x24, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x20, 0xc5, 0xa5, 0x41, 0xe, 0xdc, 0x21, 0x3e, 0x88, +0x7f, 0x3c, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x25, 0xc, 0x34, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xe0, 0xf3, 0x4a, 0x41, 0x6f, +0x11, 0x8, 0x3e, 0xfe, 0xf1, 0x5a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x56, 0x3d, 0x33, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x6c, +0xc9, 0x2c, 0x41, 0x31, 0x60, 0x9, 0x3e, 0x83, 0x16, 0x62, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc6, 0xe7, 0x23, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0xd7, 0xea, 0xa2, 0x41, 0xd3, 0x32, 0x22, 0x3e, 0x5e, 0xd9, 0x3d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf4, +0x26, 0x32, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xeb, 0x36, 0x10, 0x41, 0xd1, 0x22, 0xb, 0x3e, 0x6e, 0xda, 0x68, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x58, 0xad, 0x23, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xe6, 0x48, 0xa0, 0x41, 0x75, 0x91, 0x22, 0x3e, 0x87, +0x18, 0x3f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xcd, 0xd6, 0x30, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x90, 0xd8, 0xec, 0x40, 0x7, +0x43, 0xd, 0x3e, 0xcb, 0xf5, 0x6e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x14, 0x6e, 0x23, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x4a, +0xdf, 0x9d, 0x41, 0xf5, 0xf7, 0x22, 0x3e, 0x4, 0x3d, 0x40, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xae, 0x5a, 0x2f, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0xdf, 0x32, 0xc1, 0x40, 0x47, 0xaa, 0xf, 0x3e, 0xa3, 0x20, 0x74, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x9b, +0xb2, 0x2d, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xc4, 0x7c, 0x9d, 0x40, 0xd6, 0x58, 0x12, 0x3e, 0xf7, 0x5a, 0x78, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x5, 0x2a, 0x23, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xb, 0xae, 0x9b, 0x41, 0xe, 0x66, 0x23, 0x3e, 0xd4, +0x46, 0x41, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8d, 0xde, 0x2b, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x39, 0xb6, 0x81, 0x40, 0xb1, +0x4e, 0x15, 0x3e, 0xd7, 0xa4, 0x7b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8a, 0xde, 0x29, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x8c, +0xbe, 0x5b, 0x40, 0x54, 0x8b, 0x18, 0x3e, 0x22, 0xfe, 0x7d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1e, 0xe1, 0x22, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0x20, 0xb5, 0x99, 0x41, 0x5, 0xdc, 0x23, 0x3e, 0xe7, 0x35, 0x42, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8e, +0xb2, 0x27, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0xd0, 0xef, 0x43, 0x40, 0x88, 0xf, 0x1c, 0x3e, 0xe8, 0x66, 0x7f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x6b, 0x93, 0x22, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x8c, 0xf4, 0x97, 0x41, 0xda, 0x59, 0x24, 0x3e, 0x5f, +0xa, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe0, 0x40, 0x22, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x52, 0x6c, 0x96, 0x41, 0x8b, +0xdf, 0x24, 0x3e, 0x1a, 0xc4, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xee, 0x26, 0x22, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x4e, +0xf7, 0x95, 0x41, 0x7d, 0x9, 0x25, 0x3e, 0x7a, 0xfb, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa6, 0xc, 0x22, 0xc3, 0x10, +0x59, 0x8e, 0xc1, 0xf4, 0x8a, 0x95, 0x41, 0xf4, 0x33, 0x25, 0x3e, 0xcb, 0x2e, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa, +0xf2, 0x21, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x43, 0x27, 0x95, 0x41, 0x35, 0x5f, 0x25, 0x3e, 0xb, 0x5e, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x8e, 0xa3, 0x3e, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xcc, 0x66, 0x46, 0x42, 0x1f, 0x30, 0xaf, 0x3e, 0x4e, +0x2e, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6a, 0xa2, 0x76, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x7f, +0xdb, 0xa3, 0x3e, 0x2b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd0, 0x6a, 0x38, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x3b, +0x0, 0x3c, 0x40, 0x6d, 0x72, 0xb0, 0x3e, 0x2b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xec, 0x75, 0x0, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x9d, 0x45, 0x46, 0x42, 0x15, 0xc5, 0xbb, 0x3e, 0x16, 0x6d, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6f, +0x57, 0xd1, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xcb, 0xaf, 0x46, 0x42, 0x20, 0xb, 0x81, 0x3e, 0xe4, 0xa3, 0x9d, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xcf, 0x61, 0xed, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x17, 0x64, 0x6b, 0x3e, 0x2b, +0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1, 0x46, 0xce, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0xf9, +0x48, 0x82, 0x3e, 0x2b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb1, 0x64, 0xb2, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xa, +0x9e, 0x45, 0x42, 0x68, 0x91, 0x8d, 0x3e, 0x8a, 0xaa, 0x9f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6d, 0xa9, 0xcf, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x56, 0x38, 0x50, 0x42, 0x30, 0xb9, 0x81, 0x3e, 0xfa, 0x94, 0x8b, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xdd, +0x8a, 0xcd, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xe4, 0x5a, 0x59, 0x42, 0xbc, 0x94, 0x82, 0x3e, 0x48, 0x8e, 0x74, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x3c, 0x18, 0x3e, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x64, 0x9c, 0x48, 0x42, 0x4d, 0x4c, 0xaf, 0x3e, 0xec, +0xfe, 0x99, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xbb, 0xfb, 0xca, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x71, 0x17, 0x62, 0x42, 0xe5, +0x9d, 0x83, 0x3e, 0x44, 0x75, 0x53, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x33, 0xf7, 0xb1, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xac, +0xb, 0x48, 0x42, 0xb6, 0xbd, 0x8d, 0x3e, 0xfe, 0x10, 0x9b, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd, 0xfc, 0xc7, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x9, 0x6e, 0x6a, 0x42, 0x89, 0xd4, 0x84, 0x3e, 0x60, 0xde, 0x33, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x69, +0x6d, 0xb1, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x32, 0x5d, 0x4a, 0x42, 0x8c, 0xf5, 0x8d, 0x3e, 0xa8, 0xac, 0x96, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xd3, 0x8b, 0xc4, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xa1, 0x5e, 0x72, 0x42, 0xc9, 0x38, 0x86, 0x3e, 0xe8, +0xc9, 0x15, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x53, 0xc7, 0xb0, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x9f, 0x92, 0x4c, 0x42, 0xc9, +0x38, 0x8e, 0x3e, 0xaa, 0x7d, 0x92, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf7, 0x4, 0xb0, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xef, +0xab, 0x4e, 0x42, 0x6e, 0x87, 0x8e, 0x3e, 0xe4, 0x83, 0x8e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x10, 0xd0, 0x3d, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x50, 0xbc, 0x4a, 0x42, 0xd9, 0x5a, 0xaf, 0x3e, 0x90, 0xf8, 0x95, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9, +0xab, 0xc0, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x3d, 0xe9, 0x79, 0x42, 0x86, 0xca, 0x87, 0x3e, 0xa0, 0x6f, 0xf2, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0x51, 0x26, 0xaf, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x29, 0xa9, 0x50, 0x42, 0x7a, 0xe1, 0x8e, 0x3e, 0x34, +0xbf, 0x8a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x5f, 0x2b, 0xae, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x44, 0x8a, 0x52, 0x42, 0xf, +0x47, 0x8f, 0x3e, 0xdc, 0x2f, 0x87, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xaf, 0x59, 0xbc, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xef, +0x86, 0x80, 0x42, 0xdf, 0x89, 0x89, 0x3e, 0x48, 0x50, 0xbc, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x21, 0x14, 0xad, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x46, 0x4f, 0x54, 0x42, 0xb, 0xb8, 0x8f, 0x3e, 0xdc, 0xd5, 0x83, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xb3, +0xed, 0xab, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xb, 0xe9, 0x55, 0x42, 0x30, 0x2f, 0x90, 0x3e, 0xa6, 0xcd, 0x80, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x33, 0xca, 0xb7, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x45, 0xc0, 0x83, 0x42, 0x63, 0x62, 0x8b, 0x3e, 0xe0, +0x74, 0x8b, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x35, 0xc5, 0xaa, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x70, 0x48, 0x57, 0x42, 0x3f, +0xa7, 0x90, 0x3e, 0xe0, 0x67, 0x7c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9f, 0x9a, 0xa9, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x78, +0x6d, 0x58, 0x42, 0x19, 0x20, 0x91, 0x3e, 0xf4, 0x11, 0x78, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf3, 0x2e, 0xb3, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0xa0, 0x7a, 0x86, 0x42, 0x9e, 0x3f, 0x8d, 0x3e, 0x40, 0x3c, 0x44, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xf7, +0x6d, 0xa8, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x1a, 0x58, 0x59, 0x42, 0xbb, 0x99, 0x91, 0x3e, 0x8, 0x99, 0x74, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xed, 0x87, 0xae, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x0, 0xb6, 0x88, 0x42, 0x92, 0x21, 0x8f, 0x3e, 0x0, +0x97, 0x0, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x3b, 0x3f, 0xa7, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x64, 0x8, 0x5a, 0x42, 0x49, +0x14, 0x92, 0x3e, 0x14, 0xfd, 0x71, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe, 0xcb, 0x3d, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x8e, +0xc6, 0x4c, 0x42, 0xe6, 0x5b, 0xaf, 0x3e, 0x5c, 0x1b, 0x92, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6b, 0xe, 0xa6, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x49, 0x7e, 0x5a, 0x42, 0x9f, 0x8f, 0x92, 0x3e, 0x64, 0x3e, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x33, +0xd5, 0xa9, 0xc2, 0x8, 0x59, 0x8e, 0xc1, 0x6a, 0x72, 0x8a, 0x42, 0x5f, 0x8, 0x91, 0x3e, 0x20, 0xf4, 0x97, 0x3c, 0x1, +0xbe, 0x38, 0x0, 0x87, 0xdb, 0xa4, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xce, 0xb9, 0x5a, 0x42, 0xbf, 0xb, 0x93, 0x3e, 0xf4, +0x5c, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xb1, 0x16, 0xa5, 0xc2, 0x8, 0x59, 0x8e, 0xc1, 0xd9, 0xaf, 0x8b, 0x42, 0xe4, +0xf3, 0x92, 0x3e, 0x80, 0x95, 0x19, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0xda, 0x47, 0x4d, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xce, +0xb9, 0x5a, 0x42, 0x9b, 0x39, 0xac, 0x3e, 0xf4, 0x5c, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x75, 0x4c, 0xa0, 0xc2, 0x8, +0x59, 0x8e, 0xc1, 0x4e, 0x6e, 0x8c, 0x42, 0x21, 0xe4, 0x94, 0x3e, 0x0, 0x8f, 0x7d, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x79, +0x76, 0x9b, 0xc2, 0x8, 0x59, 0x8e, 0xc1, 0xcb, 0xad, 0x8c, 0x42, 0x17, 0xd9, 0x96, 0x3e, 0x0, 0x4d, 0x5, 0x3b, 0x1, +0xbe, 0x38, 0x0, 0xe0, 0x5d, 0x3a, 0xc2, 0x8, 0x59, 0x8e, 0xc1, 0xe3, 0xe2, 0x8c, 0x42, 0x5f, 0xd, 0xb0, 0x3e, 0x0, +0x14, 0x3, 0x3a, 0x1, 0xbe, 0x38, 0x0, 0x64, 0x3e, 0x4c, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xce, 0xb9, 0x5a, 0x42, 0x58, +0x6f, 0xac, 0x3e, 0xf4, 0x5c, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf0, 0x34, 0x4b, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xce, +0xb9, 0x5a, 0x42, 0x16, 0xa5, 0xac, 0x3e, 0xf4, 0x5c, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xae, 0x51, 0x49, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x20, 0x63, 0x5a, 0x42, 0xdd, 0x6, 0xad, 0x3e, 0x68, 0xa5, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa, +0x8b, 0x47, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x6f, 0xd8, 0x59, 0x42, 0xe1, 0x62, 0xad, 0x3e, 0xc0, 0xb2, 0x72, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x27, 0x20, 0xfc, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x51, 0xea, 0x4f, 0x42, 0x35, 0x41, 0xbc, 0x3e, 0xd4, +0x28, 0x8c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x46, 0x9, 0x3e, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x25, 0xbb, 0x4e, 0x42, 0x51, +0x4f, 0xaf, 0x3e, 0xe, 0x67, 0x8e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6c, 0xeb, 0x30, 0xc2, 0x8, 0x59, 0x8e, 0xc1, 0x51, +0x95, 0x8c, 0x42, 0xcb, 0xf6, 0xb1, 0x3e, 0x0, 0xb3, 0x33, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x4, 0xe1, 0x45, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0xbd, 0x19, 0x59, 0x42, 0x1f, 0xb9, 0xad, 0x3e, 0x38, 0x85, 0x75, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe, +0x2e, 0x28, 0xc2, 0x8, 0x59, 0x8e, 0xc1, 0xf0, 0xca, 0x8b, 0x42, 0x84, 0xbb, 0xb3, 0x3e, 0x40, 0xc1, 0xc, 0x3c, 0x1, +0xbe, 0x38, 0x0, 0x8e, 0x53, 0x44, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x7, 0x27, 0x58, 0x42, 0x78, 0x9, 0xae, 0x3e, 0xd0, +0x1c, 0x79, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xba, 0x25, 0x20, 0xc2, 0x8, 0x59, 0x8e, 0xc1, 0xbf, 0x83, 0x8a, 0x42, 0xab, +0x5b, 0xb5, 0x3e, 0x60, 0xd9, 0x93, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0x7e, 0xd2, 0x18, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xc1, +0xbf, 0x88, 0x42, 0x1f, 0xd7, 0xb6, 0x3e, 0xc0, 0xe0, 0xfe, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0xc4, 0xe2, 0x42, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x53, 0x0, 0x57, 0x42, 0x2e, 0x54, 0xae, 0x3e, 0x4c, 0x79, 0x7d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x56, +0x34, 0x12, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xf4, 0x7e, 0x86, 0x42, 0xe0, 0x2d, 0xb8, 0x3e, 0x30, 0xba, 0x43, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0x3a, 0x4b, 0xc, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x59, 0xc1, 0x83, 0x42, 0xf, 0x60, 0xb9, 0x3e, 0xa0, +0x64, 0x8b, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x8c, 0x8e, 0x41, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x9a, 0xa5, 0x55, 0x42, 0xfe, +0x98, 0xae, 0x3e, 0x72, 0x4d, 0x81, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x36, 0x17, 0x7, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xef, +0x86, 0x80, 0x42, 0x8b, 0x6d, 0xba, 0x3e, 0x48, 0x50, 0xbc, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x6e, 0xcc, 0x2, 0xc2, 0xc, +0x59, 0x8e, 0xc1, 0x14, 0xe7, 0x79, 0x42, 0xf9, 0x4b, 0xbb, 0x3e, 0x68, 0x80, 0xf2, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xea, +0x56, 0x40, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xdd, 0x16, 0x54, 0x42, 0xa, 0xd8, 0xae, 0x3e, 0xb0, 0x40, 0x84, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x2b, 0x3e, 0xff, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xf8, 0x55, 0x72, 0x42, 0x78, 0xf0, 0xbb, 0x3e, 0xac, +0xea, 0x15, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4b, 0x1e, 0xfb, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x86, 0x5a, 0x6a, 0x42, 0x4b, +0x5b, 0xbc, 0x3e, 0x4c, 0x28, 0x34, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x32, 0x4f, 0x3f, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0x4c, +0x63, 0x52, 0x42, 0x63, 0xd, 0xaf, 0x3e, 0xc8, 0x79, 0x87, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x67, 0x39, 0xf9, 0xc1, 0xc, +0x59, 0x8e, 0xc1, 0xc9, 0xf4, 0x61, 0x42, 0x72, 0x8c, 0xbc, 0x3e, 0x98, 0xf8, 0x53, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x53, +0x8f, 0xf9, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xb5, 0x24, 0x59, 0x42, 0xa9, 0x83, 0xbc, 0x3e, 0xcc, 0x5b, 0x75, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x9e, 0x8a, 0x3e, 0xc2, 0xc, 0x59, 0x8e, 0xc1, 0xe, 0x9a, 0x50, 0x42, 0x1a, 0x35, 0xaf, 0x3e, 0xe8, +0xdb, 0x8a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x79, 0x55, 0x11, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0x23, 0x5b, 0x42, 0xdc, +0x2b, 0xf3, 0x3e, 0xd0, 0xca, 0x6d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9c, 0x1f, 0x24, 0x42, 0x8, 0x59, 0x8e, 0xc1, 0xe3, +0xe2, 0x8c, 0x42, 0x33, 0xf9, 0xf6, 0x3e, 0x0, 0x14, 0x3, 0x3a, 0x1, 0xbe, 0x38, 0x0, 0x5c, 0x44, 0x13, 0x3e, 0x8, +0x59, 0x8e, 0xc1, 0xcb, 0xad, 0x8c, 0x42, 0x3b, 0xe1, 0xd5, 0x3e, 0x0, 0x4d, 0x5, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x2d, +0xb8, 0x90, 0xc0, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0x23, 0x5b, 0x42, 0x50, 0x1a, 0xd2, 0x3e, 0xd0, 0xca, 0x6d, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x7a, 0x8b, 0x11, 0xc0, 0x8, 0x59, 0x8e, 0xc1, 0x4e, 0x6e, 0x8c, 0x42, 0x46, 0xec, 0xd3, 0x3e, 0x0, +0xa0, 0x7d, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0xad, 0x69, 0x95, 0xc0, 0x8, 0x59, 0x8e, 0xc1, 0xd9, 0xaf, 0x8b, 0x42, 0xe7, +0xfb, 0xd1, 0x3e, 0x80, 0x95, 0x19, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0x5b, 0xb0, 0xd4, 0x41, 0xc, 0x59, 0x8e, 0xc1, 0x1, +0xe4, 0xe6, 0x41, 0x2c, 0x48, 0xeb, 0x3e, 0xf0, 0xa8, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf1, 0x4, 0xfa, 0x41, 0xc, +0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0x17, 0xf, 0xef, 0x3e, 0x32, 0x77, 0xc5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe7, +0x16, 0x4d, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0x6f, 0x63, 0xcb, 0x3e, 0x32, 0x77, 0xc5, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xf, 0xe0, 0x8b, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x1, 0xe4, 0xe6, 0x41, 0xa6, 0x9c, 0xc7, 0x3e, 0xf0, +0xa8, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf7, 0x35, 0xab, 0x41, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0xe8, +0x15, 0xe7, 0x3e, 0x2b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xcb, 0x4a, 0xd0, 0x41, 0x10, 0x59, 0x8e, 0xc1, 0xda, +0x1a, 0x93, 0x41, 0x45, 0xd6, 0xea, 0x3e, 0x6d, 0x56, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd7, 0x10, 0x77, 0xc1, 0x10, +0x59, 0x8e, 0xc1, 0xda, 0x1a, 0x93, 0x41, 0xe1, 0x43, 0xc9, 0x3e, 0x6d, 0x56, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x43, +0x9d, 0xa0, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x62, 0x83, 0xc5, 0x3e, 0x2b, 0xdf, 0x7f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xa7, 0xf3, 0x78, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x2e, 0x1f, 0x93, 0x41, 0x80, 0x2b, 0xc9, 0x3e, 0x54, +0x54, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xad, 0x51, 0xe1, 0xc0, 0x8, 0x59, 0x8e, 0xc1, 0x6a, 0x72, 0x8a, 0x42, 0x84, +0x10, 0xd0, 0x3e, 0x20, 0xf6, 0x97, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0x3f, 0xd1, 0x7a, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x2e, +0x2c, 0x93, 0x41, 0x40, 0x13, 0xc9, 0x3e, 0x2b, 0x4e, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x9f, 0xa9, 0x7c, 0xc1, 0x10, +0x59, 0x8e, 0xc1, 0xdb, 0x41, 0x93, 0x41, 0x65, 0xfb, 0xc8, 0x3e, 0xf2, 0x43, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd7, +0x3e, 0x16, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x0, 0xb6, 0x88, 0x42, 0xb7, 0x29, 0xce, 0x3e, 0x10, 0x98, 0x0, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0xbd, 0xe6, 0xa3, 0xc0, 0xc, 0x59, 0x8e, 0xc1, 0x68, 0xe8, 0x5a, 0x42, 0x30, 0x9e, 0xd1, 0x3e, 0x88, +0xac, 0x6e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd7, 0x76, 0x3b, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xa0, 0x7a, 0x86, 0x42, 0xc3, +0x47, 0xcc, 0x3e, 0x40, 0x3d, 0x44, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x4d, 0xf4, 0xb6, 0xc0, 0xc, 0x59, 0x8e, 0xc1, 0x4c, +0x72, 0x5a, 0x42, 0xb8, 0x22, 0xd1, 0x3e, 0x0, 0x6c, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xbd, 0xe0, 0xc9, 0xc0, 0xc, +0x59, 0x8e, 0xc1, 0xad, 0xc1, 0x59, 0x42, 0x4c, 0xa8, 0xd0, 0x3e, 0x0, 0x9, 0x73, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xcf, +0x7c, 0x7e, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x2f, 0x60, 0x93, 0x41, 0xce, 0xe3, 0xc8, 0x3e, 0x98, 0x35, 0x45, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xcf, 0x50, 0x60, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x45, 0xc0, 0x83, 0x42, 0x87, 0x6a, 0xca, 0x3e, 0x68, +0x75, 0x8b, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x7d, 0xac, 0xdc, 0xc0, 0xc, 0x59, 0x8e, 0xc1, 0x90, 0xd6, 0x58, 0x42, 0x88, +0x2e, 0xd0, 0x3e, 0xc4, 0x83, 0x76, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6f, 0x25, 0x80, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x34, +0x87, 0x93, 0x41, 0x57, 0xcc, 0xc8, 0x3e, 0x1c, 0x23, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x2d, 0x57, 0xef, 0xc0, 0xc, +0x59, 0x8e, 0xc1, 0xed, 0xb0, 0x57, 0x42, 0xaf, 0xb5, 0xcf, 0x3e, 0x4c, 0xdc, 0x7a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x63, +0x66, 0x82, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xef, 0x86, 0x80, 0x42, 0x4, 0x92, 0xc8, 0x3e, 0x48, 0x50, 0xbc, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0x7f, 0xf0, 0x0, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xc9, 0x50, 0x56, 0x42, 0x9f, 0x3d, 0xcf, 0x3e, 0x2c, +0x9, 0x80, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd7, 0x9, 0x81, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xe0, 0xb6, 0x93, 0x41, 0x46, +0xb5, 0xc8, 0x3e, 0x80, 0xc, 0x45, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xef, 0x24, 0xa, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x23, +0xb6, 0x54, 0x42, 0x7a, 0xc6, 0xce, 0x3e, 0xf4, 0x12, 0x83, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x17, 0xad, 0x93, 0xc1, 0xc, +0x59, 0x8e, 0xc1, 0x13, 0xe7, 0x79, 0x42, 0x89, 0xd2, 0xc6, 0x3e, 0x68, 0x80, 0xf2, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xff, +0xdf, 0x12, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0xf0, 0x52, 0x42, 0x5c, 0x55, 0xce, 0x3e, 0xec, 0x6e, 0x86, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x1f, 0x34, 0xa3, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xf6, 0x55, 0x72, 0x42, 0x68, 0x40, 0xc5, 0x3e, 0xf0, +0xea, 0x15, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xcf, 0xb8, 0x1a, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0xd, 0x51, 0x42, 0xc8, +0xef, 0xcd, 0x3e, 0x3a, 0x0, 0x8a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x57, 0xaf, 0x21, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xa6, +0xf, 0x4f, 0x42, 0x9a, 0x95, 0xcd, 0x3e, 0x4, 0xc7, 0x8d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9b, 0xeb, 0x81, 0xc1, 0x10, +0x59, 0x8e, 0xc1, 0x37, 0xef, 0x93, 0x41, 0x77, 0x9e, 0xc8, 0x3e, 0xd4, 0xf1, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8f, +0xfb, 0xb0, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x88, 0x5a, 0x6a, 0x42, 0x7f, 0xdb, 0xc3, 0x3e, 0x4c, 0x28, 0x34, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xb7, 0xc3, 0x27, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0xf5, 0x4c, 0x42, 0xd4, 0x46, 0xcd, 0x3e, 0x4, +0xc3, 0x91, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xcf, 0xf5, 0x2c, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x79, 0xbe, 0x4a, 0x42, 0x97, +0x3, 0xcd, 0x3e, 0x80, 0xf4, 0x95, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x5f, 0x3, 0xbd, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xc6, +0xf4, 0x61, 0x42, 0xf0, 0xa3, 0xc2, 0x3e, 0x98, 0xf8, 0x53, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa7, 0x45, 0x31, 0xc1, 0xc, +0x59, 0x8e, 0xc1, 0xa0, 0x6b, 0x48, 0x42, 0xc0, 0xcb, 0xcc, 0x3e, 0x54, 0x5b, 0x9a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd3, +0xca, 0x82, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x39, 0x30, 0x94, 0x41, 0xca, 0x87, 0xc8, 0x3e, 0x7, 0xd3, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x9b, 0x4b, 0xc7, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xb7, 0x24, 0x59, 0x42, 0x9a, 0x99, 0xc1, 0x3e, 0x88, +0x5b, 0x75, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4f, 0xb3, 0x34, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x9c, 0xfc, 0x45, 0x42, 0x51, +0x9f, 0xcc, 0x3e, 0x5e, 0xf7, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x27, 0xd4, 0xcf, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0x53, +0xea, 0x4f, 0x42, 0x7b, 0xbc, 0xc0, 0x3e, 0xd4, 0x28, 0x8c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xb, 0x9d, 0xd6, 0xc1, 0xc, +0x59, 0x8e, 0xc1, 0x9d, 0x45, 0x46, 0x42, 0xd8, 0xc, 0xc0, 0x3e, 0x16, 0x6d, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x53, +0x94, 0xe1, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xe1, 0xfe, 0x33, 0x42, 0xd0, 0xf0, 0xbe, 0x3e, 0xc8, 0xb, 0xc1, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x1b, 0x85, 0xf5, 0xc1, 0xc, 0x59, 0x8e, 0xc1, 0xe5, 0xc2, 0x12, 0x42, 0x42, 0xec, 0xbc, 0x3e, 0xde, +0xff, 0xff, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x48, 0x76, 0xa, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x9b, 0xd7, 0xbc, 0x41, 0xf5, +0xbe, 0xb9, 0x3e, 0x86, 0x92, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8b, 0x51, 0x98, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x9c, +0x69, 0xbd, 0x41, 0x57, 0x5a, 0xc6, 0x3e, 0x62, 0x4d, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc3, 0x42, 0x99, 0xc1, 0x10, +0x59, 0x8e, 0xc1, 0xf5, 0xad, 0xb9, 0x41, 0xd5, 0x41, 0xc6, 0x3e, 0xe8, 0x11, 0x33, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd7, +0xcf, 0x99, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xa6, 0x10, 0xb6, 0x41, 0xad, 0x33, 0xc6, 0x3e, 0x26, 0xc8, 0x34, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xc3, 0xf8, 0x99, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xa8, 0x91, 0xb2, 0x41, 0x7b, 0x2f, 0xc6, 0x3e, 0xf8, +0x6f, 0x36, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x67, 0xa7, 0x83, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xe7, 0x79, 0x94, 0x41, 0x82, +0x71, 0xc8, 0x3e, 0x29, 0xb0, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6f, 0x81, 0x84, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x41, +0xcc, 0x94, 0x41, 0x7d, 0x5b, 0xc8, 0x3e, 0x2b, 0x89, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa3, 0xbd, 0x99, 0xc1, 0x10, +0x59, 0x8e, 0xc1, 0x5, 0x31, 0xaf, 0x41, 0x83, 0x35, 0xc6, 0x3e, 0x70, 0x9, 0x38, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x96, +0xd2, 0xc, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x88, 0xc6, 0xa9, 0x41, 0xaa, 0x44, 0xb9, 0x3e, 0xfa, 0x99, 0x3a, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x53, 0x1e, 0x99, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xb7, 0xee, 0xab, 0x41, 0xa2, 0x45, 0xc6, 0x3e, 0x7d, +0x94, 0x39, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x92, 0x10, 0xe, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x6d, 0x81, 0x97, 0x41, 0x4f, +0x4, 0xb9, 0x3e, 0xe6, 0x40, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf3, 0x1a, 0x98, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xc1, +0xca, 0xa8, 0x41, 0xd9, 0x5f, 0xc6, 0x3e, 0x40, 0x11, 0x3b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x48, 0x30, 0xe, 0xc2, 0x10, +0x59, 0x8e, 0xc1, 0x4b, 0x8, 0x86, 0x41, 0xe3, 0xfd, 0xb8, 0x3e, 0x38, 0x87, 0x4b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xae, +0x31, 0xd, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x40, 0xb6, 0x6a, 0x41, 0x66, 0x31, 0xb9, 0x3e, 0xdf, 0x6c, 0x53, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x6f, 0xb3, 0x96, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x20, 0xc5, 0xa5, 0x41, 0x27, 0x84, 0xc6, 0x3e, 0x99, +0x7f, 0x3c, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc6, 0x14, 0xb, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0xe0, 0xf3, 0x4a, 0x41, 0xd8, +0x9e, 0xb9, 0x3e, 0xfe, 0xf1, 0x5a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8e, 0xd9, 0x7, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0x6c, +0xc9, 0x2c, 0x41, 0x39, 0x46, 0xba, 0x3e, 0x83, 0x16, 0x62, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x93, 0x6, 0x95, 0xc1, 0x10, +0x59, 0x8e, 0xc1, 0xd7, 0xea, 0xa2, 0x41, 0x8a, 0xaf, 0xc6, 0x3e, 0x6e, 0xd9, 0x3d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc, +0x80, 0x3, 0xc2, 0x10, 0x59, 0x8e, 0xc1, 0xeb, 0x36, 0x10, 0x41, 0x89, 0x27, 0xbb, 0x3e, 0x6e, 0xda, 0x68, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x27, 0x33, 0x93, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xe6, 0x48, 0xa0, 0x41, 0xdb, 0xde, 0xc6, 0x3e, 0x98, +0x18, 0x3f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdb, 0x7e, 0xfc, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x90, 0xd8, 0xec, 0x40, 0xa4, +0x37, 0xbc, 0x3e, 0xdc, 0xf5, 0x6e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1f, 0x39, 0x91, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x4a, +0xdf, 0x9d, 0x41, 0x1b, 0x12, 0xc7, 0x3e, 0x14, 0x3d, 0x40, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xef, 0x9d, 0xf0, 0xc1, 0x10, +0x59, 0x8e, 0xc1, 0xdf, 0x32, 0xc1, 0x40, 0x44, 0x6b, 0xbd, 0x3e, 0xb4, 0x20, 0x74, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x47, +0x5d, 0xe3, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xc4, 0x7c, 0x9d, 0x40, 0x8b, 0xc2, 0xbe, 0x3e, 0x8, 0x5b, 0x78, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x8f, 0x18, 0x8f, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xb, 0xae, 0x9b, 0x41, 0x28, 0x49, 0xc7, 0x3e, 0xd4, +0x46, 0x41, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdb, 0xbc, 0xd4, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x39, 0xb6, 0x81, 0x40, 0x57, +0x3d, 0xc0, 0x3e, 0xd7, 0xa4, 0x7b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xbf, 0xbc, 0xc4, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x8c, +0xbe, 0x5b, 0x40, 0xcb, 0xdb, 0xc1, 0x3e, 0x22, 0xfe, 0x7d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6b, 0xd1, 0x8c, 0xc1, 0x10, +0x59, 0x8e, 0xc1, 0x20, 0xb5, 0x99, 0x41, 0x23, 0x84, 0xc7, 0x3e, 0xf8, 0x35, 0x42, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd7, +0x5c, 0xb3, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0xd0, 0xef, 0x43, 0x40, 0xe5, 0x9d, 0xc3, 0x3e, 0xe8, 0x66, 0x7f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xbb, 0x63, 0x8a, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x8c, 0xf4, 0x97, 0x41, 0xd, 0xc3, 0xc7, 0x3e, 0x5f, +0xa, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x73, 0xcf, 0x87, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x52, 0x6c, 0x96, 0x41, 0xe6, +0x5, 0xc8, 0x3e, 0x1a, 0xc4, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdf, 0xff, 0x86, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x4e, +0xf7, 0x95, 0x41, 0xdf, 0x1a, 0xc8, 0x3e, 0x8b, 0xfb, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xab, 0x2d, 0x86, 0xc1, 0x10, +0x59, 0x8e, 0xc1, 0xf4, 0x8a, 0x95, 0x41, 0x1a, 0x30, 0xc8, 0x3e, 0xdc, 0x2e, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd3, +0x58, 0x85, 0xc1, 0x10, 0x59, 0x8e, 0xc1, 0x43, 0x27, 0x95, 0x41, 0xbb, 0x45, 0xc8, 0x3e, 0xb, 0x5e, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xe4, 0xd2, 0xef, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0x23, 0x5b, 0x42, 0xe0, 0x68, 0x1b, 0x3f, 0xd0, +0xca, 0x6d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf6, 0x37, 0xf9, 0x42, 0x8, 0x59, 0x8e, 0xc1, 0xe3, 0xe2, 0x8c, 0x42, 0x8b, +0x4f, 0x1d, 0x3f, 0x0, 0x14, 0x3, 0x3a, 0x1, 0xbe, 0x38, 0x0, 0x70, 0x17, 0x87, 0x42, 0x8, 0x59, 0x8e, 0xc1, 0xcb, +0xad, 0x8c, 0x42, 0x9b, 0x37, 0x6, 0x3f, 0x0, 0x5e, 0x5, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x94, 0x84, 0x7b, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xfe, 0x23, 0x5b, 0x42, 0x37, 0x54, 0x4, 0x3f, 0xd0, 0xca, 0x6d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x78, +0x41, 0x82, 0x42, 0x8, 0x59, 0x8e, 0xc1, 0x6a, 0x6e, 0x8c, 0x42, 0x21, 0x3d, 0x5, 0x3f, 0x0, 0x6d, 0x7d, 0x3b, 0x1, +0xbe, 0x38, 0x0, 0xa1, 0xee, 0x7a, 0x42, 0x8, 0x59, 0x8e, 0xc1, 0x40, 0xb0, 0x8b, 0x42, 0x2, 0x45, 0x4, 0x3f, 0x40, +0x67, 0x19, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0x8b, 0x30, 0xf9, 0x41, 0x10, 0x59, 0x8e, 0xc1, 0x37, 0xef, 0x93, 0x41, 0x98, +0xf9, 0xee, 0x3e, 0xd4, 0xf1, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5, 0xdc, 0xd3, 0x41, 0x10, 0x59, 0x8e, 0xc1, 0x3b, +0x0, 0x3c, 0x40, 0xad, 0x32, 0xeb, 0x3e, 0x2b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x52, 0x68, 0xa6, 0x42, 0x10, +0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0xd2, 0x8d, 0xc, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x78, +0xbd, 0xaf, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x37, 0xef, 0x93, 0x41, 0x47, 0x71, 0xe, 0x3f, 0xd4, 0xf1, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xc8, 0x4b, 0xab, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x68, 0xe7, 0x43, 0x40, 0xd, 0x8b, 0xd, 0x3f, 0x6f, +0x67, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x16, 0x20, 0xb0, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0xf5, 0x9c, 0x5b, 0x40, 0x34, +0x85, 0xe, 0x3f, 0x2a, 0x0, 0x7e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf0, 0x71, 0x71, 0x42, 0x8, 0x59, 0x8e, 0xc1, 0x53, +0x73, 0x8a, 0x42, 0x51, 0x4f, 0x3, 0x3f, 0x80, 0xbd, 0x97, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0x3b, 0xe5, 0xb4, 0x42, 0x10, +0x59, 0x8e, 0xc1, 0x71, 0x90, 0x81, 0x40, 0x57, 0x7c, 0xf, 0x3f, 0x5d, 0xa9, 0x7b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xde, +0xc, 0x68, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xa0, 0xb7, 0x88, 0x42, 0xfb, 0x5b, 0x2, 0x3f, 0xc0, 0x66, 0x0, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0xc4, 0x1e, 0x79, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x68, 0xe8, 0x5a, 0x42, 0x16, 0x16, 0x4, 0x3f, 0x88, +0xac, 0x6e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x38, 0x9b, 0xb9, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x93, 0x39, 0x9d, 0x40, 0x54, +0x70, 0x10, 0x3f, 0x6, 0x63, 0x78, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xad, 0xf5, 0xb0, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x87, +0xf8, 0x93, 0x41, 0x75, 0xb0, 0xe, 0x3f, 0x70, 0xed, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4c, 0x2a, 0xb2, 0x42, 0x10, +0x59, 0x8e, 0xc1, 0xd2, 0x8d, 0x94, 0x41, 0xe9, 0xee, 0xe, 0x3f, 0xb9, 0xa6, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe, +0x42, 0xbe, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0xe9, 0xc9, 0xc0, 0x40, 0x4e, 0x61, 0x11, 0x3f, 0x28, 0x2d, 0x74, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x54, 0x5b, 0xb3, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x12, 0xaf, 0x95, 0x41, 0x95, 0x2c, 0xf, 0x3f, 0xc1, +0x1d, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6b, 0xbf, 0x5e, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x2a, 0x7d, 0x86, 0x42, 0x1, +0x6b, 0x1, 0x3f, 0xc0, 0xf0, 0x43, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x13, 0xbd, 0x76, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x4c, +0x72, 0x5a, 0x42, 0x6b, 0xd8, 0x3, 0x3f, 0x0, 0x6c, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x7f, 0x5f, 0x74, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xad, 0xc1, 0x59, 0x42, 0x24, 0x9b, 0x3, 0x3f, 0x0, 0x9, 0x73, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x96, +0x89, 0x55, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xec, 0xc3, 0x83, 0x42, 0x74, 0x7c, 0x0, 0x3f, 0xd0, 0x3d, 0x8b, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0xb, 0x6, 0x72, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x90, 0xd6, 0x58, 0x42, 0x42, 0x5e, 0x3, 0x3f, 0xc4, +0x83, 0x76, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xba, 0xd9, 0xc2, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x6c, 0x41, 0xec, 0x40, 0x33, +0x4f, 0x12, 0x3f, 0xc0, 0x7, 0x6f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc6, 0x88, 0xb4, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x51, +0x5c, 0x97, 0x41, 0x98, 0x69, 0xf, 0x3f, 0x87, 0x52, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa1, 0xb2, 0xb5, 0x42, 0x10, +0x59, 0x8e, 0xc1, 0x87, 0x95, 0x99, 0x41, 0xe3, 0xa5, 0xf, 0x3f, 0xe9, 0x44, 0x42, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3e, +0x62, 0xc7, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0xd, 0xd0, 0xf, 0x41, 0x4, 0x3a, 0x13, 0x3f, 0xe0, 0xf2, 0x68, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xe6, 0xd8, 0xb6, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0xb9, 0x5a, 0x9c, 0x41, 0x65, 0xe1, 0xf, 0x3f, 0x1b, +0xf5, 0x40, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb4, 0xb0, 0x6f, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xed, 0xb0, 0x57, 0x42, 0xd5, +0x21, 0x3, 0x3f, 0x4c, 0xdc, 0x7a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x60, 0x6b, 0x4c, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xe9, +0x8b, 0x80, 0x42, 0xa7, 0x20, 0xff, 0x3e, 0x50, 0x5, 0xbc, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x7a, 0x5f, 0x6d, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xc9, 0x50, 0x56, 0x42, 0xcd, 0xe5, 0x2, 0x3f, 0x2c, 0x9, 0x80, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x5f, +0x12, 0x6b, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x23, 0xb6, 0x54, 0x42, 0x3b, 0xaa, 0x2, 0x3f, 0x16, 0x13, 0x83, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xea, 0xc8, 0x43, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xf2, 0xf3, 0x79, 0x42, 0x4e, 0x61, 0xfd, 0x3e, 0xe8, +0x1e, 0xf2, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x9d, 0xe3, 0x68, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0xf0, 0x52, 0x42, 0xac, +0x71, 0x2, 0x3f, 0xc, 0x6f, 0x86, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x94, 0xfb, 0xb7, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0xe4, +0xab, 0x9f, 0x41, 0x3f, 0x1c, 0x10, 0x3f, 0xfa, 0x62, 0x3f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6a, 0xab, 0xcb, 0x42, 0x10, +0x59, 0x8e, 0xc1, 0x6b, 0x44, 0x2c, 0x41, 0xd, 0x18, 0x14, 0x3f, 0x9, 0x36, 0x62, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x67, +0xe, 0xb9, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0xf5, 0x58, 0xa3, 0x41, 0xe3, 0x53, 0x10, 0x3f, 0x54, 0xa5, 0x3d, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x4d, 0x6, 0x3c, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xdf, 0x65, 0x72, 0x42, 0x4f, 0xcf, 0xfb, 0x3e, 0xa4, +0xae, 0x15, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x69, 0xed, 0x66, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0xd, 0x51, 0x42, 0xe2, +0x3e, 0x2, 0x3f, 0x5c, 0x0, 0x8a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc4, 0x2f, 0x65, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xa6, +0xf, 0x4f, 0x42, 0xcb, 0x11, 0x2, 0x3f, 0x4, 0xc7, 0x8d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe, 0x85, 0xcf, 0x42, 0x10, +0x59, 0x8e, 0xc1, 0x3d, 0x4f, 0x4a, 0x41, 0x7a, 0xdf, 0x14, 0x3f, 0xd, 0x19, 0x5b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x17, +0x5, 0xba, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0xd5, 0x31, 0xa7, 0x41, 0xc2, 0x85, 0x10, 0x3f, 0xea, 0xd2, 0x3b, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xa3, 0xdf, 0xba, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x83, 0x36, 0xab, 0x41, 0xff, 0xb1, 0x10, 0x3f, 0xc8, +0xeb, 0x39, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8a, 0x23, 0x35, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xa2, 0x6d, 0x6a, 0x42, 0xa9, +0x6a, 0xfa, 0x3e, 0xf4, 0xdf, 0x33, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xad, 0xaa, 0x63, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x26, +0xf5, 0x4c, 0x42, 0x68, 0xea, 0x1, 0x3f, 0x4, 0xc3, 0x91, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x2d, 0xef, 0xd2, 0x42, 0x10, +0x59, 0x8e, 0xc1, 0x83, 0xf0, 0x69, 0x41, 0x5c, 0x90, 0x15, 0x3f, 0xbb, 0x9b, 0x53, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd, +0x9e, 0xbb, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x6, 0x67, 0xaf, 0x41, 0x88, 0xd8, 0x10, 0x3f, 0xe1, 0xef, 0x37, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x54, 0x40, 0xbc, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x57, 0xc3, 0xb3, 0x41, 0x5d, 0xf9, 0x10, 0x3f, 0x33, +0xdf, 0x35, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc2, 0xe9, 0xd5, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x1d, 0x94, 0x85, 0x41, 0xb2, +0x2a, 0x16, 0x3f, 0x44, 0xbe, 0x4b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x78, 0xc6, 0xbc, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x7a, +0x4b, 0xb8, 0x41, 0x7f, 0x14, 0x11, 0x3f, 0xd0, 0xb9, 0x33, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x26, 0x5e, 0x62, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0x79, 0xbe, 0x4a, 0x42, 0xc9, 0xc8, 0x1, 0x3f, 0x80, 0xf4, 0x95, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa2, +0x20, 0x2f, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x2f, 0xb, 0x62, 0x42, 0x3c, 0x33, 0xf9, 0x3e, 0xec, 0xa3, 0x53, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x2f, 0x4a, 0x61, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xa0, 0x6b, 0x48, 0x42, 0xde, 0xac, 0x1, 0x3f, 0x54, +0x5b, 0x9a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x92, 0xfd, 0x29, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x97, 0x3e, 0x59, 0x42, 0x28, +0x29, 0xf8, 0x3e, 0xc0, 0xf9, 0x74, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc8, 0x6e, 0x60, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x9c, +0xfc, 0x45, 0x42, 0xa7, 0x96, 0x1, 0x3f, 0x80, 0xf7, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd4, 0x74, 0xd8, 0x42, 0x10, +0x59, 0x8e, 0xc1, 0x36, 0xfb, 0x96, 0x41, 0x6d, 0xae, 0x16, 0x3f, 0x78, 0x80, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x7a, +0x30, 0xbd, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x6d, 0xff, 0xbc, 0x41, 0xed, 0x29, 0x11, 0x3f, 0xb6, 0x7f, 0x31, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x21, 0x7f, 0xbd, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x8e, 0xe9, 0xc1, 0x41, 0xda, 0x39, 0x11, 0x3f, 0xdc, +0x2b, 0x2f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5b, 0x90, 0xda, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x85, 0x2d, 0xa9, 0x41, 0x9b, +0x1b, 0x17, 0x3f, 0x76, 0xe2, 0x3a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x19, 0xaa, 0xbd, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0xdc, +0x9a, 0xc6, 0x41, 0x91, 0x42, 0x11, 0x3f, 0x2, 0xf3, 0x2c, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5a, 0x3c, 0xdc, 0x42, 0x10, +0x59, 0x8e, 0xc1, 0xe, 0x2b, 0xbc, 0x41, 0x2e, 0x72, 0x17, 0x3f, 0x3f, 0xe4, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x60, +0xb1, 0xbd, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x58, 0x13, 0xcb, 0x41, 0x3, 0x44, 0x11, 0x3f, 0x6, 0xd5, 0x2a, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x5e, 0xba, 0x25, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xc8, 0x7, 0x50, 0x42, 0x4d, 0x4c, 0xf7, 0x3e, 0xfe, +0xf0, 0x8b, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x96, 0xdd, 0x5f, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xae, 0xa8, 0x43, 0x42, 0xf9, +0x87, 0x1, 0x3f, 0x4a, 0x60, 0xa3, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x13, 0x96, 0x5f, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x6d, +0x6a, 0x41, 0x42, 0xc3, 0x80, 0x1, 0x3f, 0xe, 0xa0, 0xa7, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6, 0x57, 0x22, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xcc, 0x66, 0x46, 0x42, 0xcb, 0x9c, 0xf6, 0x3e, 0x4e, 0x2e, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x3d, +0x98, 0x5f, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xd3, 0x41, 0x3f, 0x42, 0xf5, 0x80, 0x1, 0x3f, 0xcc, 0xb6, 0xab, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xf8, 0x6d, 0xdd, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x1b, 0x63, 0xcf, 0x41, 0xc, 0xb0, 0x17, 0x3f, 0x50, +0xca, 0x28, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xfb, 0x94, 0xbd, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x5, 0x53, 0xcf, 0x41, 0x4f, +0x3e, 0x11, 0x3f, 0xea, 0xd1, 0x28, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x81, 0xfb, 0x1f, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xe5, +0xe0, 0x3c, 0x42, 0xc4, 0x22, 0xf6, 0x3e, 0x3a, 0x38, 0xb0, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x15, 0xe4, 0x5f, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xe9, 0x2e, 0x3d, 0x42, 0xa0, 0x88, 0x1, 0x3f, 0x84, 0xa4, 0xaf, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x41, +0x11, 0xde, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x97, 0xcb, 0xe1, 0x41, 0x14, 0xd1, 0x17, 0x3f, 0xae, 0x12, 0x20, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xe5, 0x54, 0xbd, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xe1, 0x59, 0xd3, 0x41, 0x55, 0x31, 0x11, 0x3f, 0xbc, +0xe9, 0x26, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x33, 0x26, 0xde, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x85, 0x64, 0xf3, 0x41, 0x56, +0xd5, 0x17, 0x3f, 0x5a, 0xbd, 0x17, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xce, 0xac, 0xdd, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xf1, +0x16, 0x2, 0x42, 0xc3, 0xbc, 0x17, 0x3f, 0x42, 0xca, 0xf, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x20, 0xf1, 0xbc, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xec, 0x27, 0xd7, 0x41, 0x26, 0x1d, 0x11, 0x3f, 0x7e, 0x1c, 0x25, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x14, +0xa5, 0xdc, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xda, 0x13, 0xa, 0x42, 0x6a, 0x87, 0x17, 0x3f, 0x7a, 0x39, 0x8, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x2, 0xf, 0xdb, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xfb, 0xa8, 0x11, 0x42, 0x3b, 0x35, 0x17, 0x3f, 0xfe, +0xa, 0x1, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xac, 0x69, 0xbc, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0xbd, 0xda, 0x41, 0xc1, +0x1, 0x11, 0x3f, 0x1e, 0x6a, 0x23, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x99, 0xea, 0xd8, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x52, +0xd6, 0x18, 0x42, 0x37, 0xc6, 0x16, 0x3f, 0xa2, 0x7d, 0xf4, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x58, 0x51, 0xd6, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0x3e, 0x50, 0x1f, 0x42, 0x9a, 0x3f, 0x16, 0x3f, 0x26, 0x39, 0xe8, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x95, +0xc4, 0xbb, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x7b, 0xf6, 0xdd, 0x41, 0x54, 0xe0, 0x10, 0x3f, 0x43, 0xe3, 0x21, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xbd, 0x5c, 0xd3, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x1a, 0xcb, 0x24, 0x42, 0x83, 0xa6, 0x15, 0x3f, 0xcc, +0xd7, 0xdd, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc9, 0xc, 0xd0, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xe5, 0x46, 0x29, 0x42, 0xf0, +0xfa, 0x14, 0x3f, 0x92, 0x59, 0xd5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x7a, 0x61, 0xcc, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x9d, +0xc3, 0x2c, 0x42, 0xe2, 0x3c, 0x14, 0x3f, 0x9c, 0xbe, 0xce, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe0, 0x7, 0xbb, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xd7, 0xb0, 0xe0, 0x41, 0x1f, 0xba, 0x10, 0x3f, 0x92, 0x98, 0x20, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd2, +0x5a, 0xc8, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x4a, 0x41, 0x2f, 0x42, 0x59, 0x6c, 0x13, 0x3f, 0xa6, 0x6, 0xca, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xcf, 0xf8, 0xc3, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xe3, 0xbf, 0x30, 0x42, 0x44, 0x89, 0x12, 0x3f, 0xf4, +0x31, 0xc7, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x90, 0x33, 0xba, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x36, 0xec, 0xe2, 0x41, 0x32, +0x8f, 0x10, 0x3f, 0xf8, 0x89, 0x1f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x72, 0x3b, 0xbf, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x6a, +0x3f, 0x31, 0x42, 0xc4, 0x93, 0x11, 0x3f, 0x64, 0x40, 0xc6, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa4, 0x47, 0xb9, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xa0, 0xa8, 0xe4, 0x41, 0x6c, 0x5f, 0x10, 0x3f, 0x88, 0xb7, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xbc, +0x5f, 0xb2, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x6a, 0x3f, 0x31, 0x42, 0xba, 0xf9, 0xe, 0x3f, 0x64, 0x40, 0xc6, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x1c, 0x44, 0xb8, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x10, 0xe6, 0xe5, 0x41, 0xed, 0x2a, 0x10, 0x3f, 0x32, +0x21, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf8, 0x28, 0xb7, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x84, 0xa4, 0xe6, 0x41, 0xa6, +0xf1, 0xf, 0x3f, 0x4, 0xc7, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x38, 0xf6, 0xb5, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x1, +0xe4, 0xe6, 0x41, 0x96, 0xb3, 0xf, 0x3f, 0xf0, 0xa8, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xbc, 0x46, 0x8c, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0x1, 0xe4, 0xe6, 0x41, 0x2c, 0x44, 0x7, 0x3f, 0xf0, 0xa8, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x9d, +0x8f, 0x9b, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x6a, 0x3f, 0x31, 0x42, 0xfb, 0x5b, 0xa, 0x3f, 0x64, 0x40, 0xc6, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x32, 0xf3, 0x6e, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x6a, 0x3f, 0x31, 0x42, 0xb2, 0xe, 0x3, 0x3f, 0x64, +0x40, 0xc6, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x1a, 0x33, 0x78, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x1, 0xe4, 0xe6, 0x41, 0x3b, +0xfe, 0x3, 0x3f, 0xf0, 0xa8, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc7, 0x68, 0x5c, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x1, +0xe4, 0xe6, 0x41, 0x73, 0x2e, 0x1, 0x3f, 0xf0, 0xa8, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1d, 0xc4, 0x6c, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xea, 0x5f, 0x31, 0x42, 0x13, 0xd6, 0x2, 0x3f, 0xca, 0x2, 0xc6, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xb3, +0xb7, 0x6a, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x6f, 0xc1, 0x31, 0x42, 0xe, 0xa1, 0x2, 0x3f, 0x1a, 0x4a, 0xc5, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xf4, 0xcd, 0x68, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xf6, 0x63, 0x32, 0x42, 0x82, 0x6f, 0x2, 0x3f, 0x38, +0x16, 0xc4, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x99, 0xbd, 0x1e, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xae, 0xbe, 0x33, 0x42, 0x69, +0xe2, 0xf5, 0x3e, 0x6a, 0x85, 0xc1, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x3c, 0x9, 0x53, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xb8, +0xe3, 0xe7, 0x41, 0xb4, 0x3b, 0x0, 0x3f, 0xd3, 0x2f, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe1, 0x6, 0x67, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0x7f, 0x47, 0x33, 0x42, 0x70, 0x41, 0x2, 0x3f, 0x1e, 0x67, 0xc2, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x17, +0x5a, 0x4a, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xd9, 0xe2, 0xea, 0x41, 0x91, 0xb5, 0xfe, 0x3e, 0x8f, 0xc4, 0x1b, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x57, 0x5b, 0x42, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x5f, 0xe1, 0xef, 0x41, 0x61, 0x17, 0xfd, 0x3e, 0x23, +0x67, 0x19, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x7b, 0x62, 0x65, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xd, 0x6c, 0x34, 0x42, 0xe8, +0x16, 0x2, 0x3f, 0xf2, 0x3c, 0xc0, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xfc, 0xc, 0x3b, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x57, +0xdf, 0xf6, 0x41, 0xd8, 0x9c, 0xfb, 0x3e, 0x6e, 0x17, 0x16, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x7, 0x6f, 0x34, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xb7, 0xdc, 0xff, 0x41, 0x17, 0x46, 0xfa, 0x3e, 0xa2, 0xd5, 0x11, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xbf, +0xe0, 0x63, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x9d, 0xd1, 0x35, 0x42, 0xe9, 0xef, 0x1, 0x3f, 0xb4, 0x97, 0xbd, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x78, 0x81, 0x2e, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xc0, 0x6c, 0x5, 0x42, 0xfd, 0x12, 0xf9, 0x3e, 0x9c, +0xa1, 0xc, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4e, 0x44, 0x29, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xdb, 0xea, 0xb, 0x42, 0xac, +0x3, 0xf8, 0x3e, 0x5f, 0x7b, 0x6, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x21, 0xee, 0x24, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0xa8, +0x1a, 0x13, 0x42, 0x3, 0x23, 0xf7, 0x3e, 0xac, 0x59, 0xff, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xb0, 0x81, 0x62, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0x2c, 0x78, 0x37, 0x42, 0x64, 0xcc, 0x1, 0x3f, 0x3e, 0x77, 0xba, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x93, +0xb5, 0x21, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x25, 0xae, 0x1a, 0x42, 0x28, 0x7c, 0xf6, 0x3e, 0xda, 0xff, 0xf0, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xa2, 0x9a, 0x1f, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x4d, 0xa5, 0x22, 0x42, 0x1b, 0xf, 0xf6, 0x3e, 0x2a, +0xe9, 0xe1, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xce, 0x58, 0x61, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x16, 0x4a, 0x39, 0x42, 0x4f, +0xae, 0x1, 0x3f, 0xbc, 0x4, 0xb7, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4f, 0x9d, 0x1e, 0x42, 0xc, 0x59, 0x8e, 0xc1, 0x27, +0x0, 0x2b, 0x42, 0xdb, 0xdb, 0xf5, 0x3e, 0xba, 0x15, 0xd2, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9a, 0x79, 0x60, 0x42, 0xc, +0x59, 0x8e, 0xc1, 0xa9, 0x31, 0x3b, 0x42, 0xc4, 0x97, 0x1, 0x3f, 0x12, 0x69, 0xb3, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x52, +0xc3, 0x1, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xcb, 0xad, 0x8c, 0x42, 0x77, 0x65, 0x1f, 0x3f, 0x0, 0x5e, 0x5, 0x3b, 0x1, +0xbe, 0x38, 0x0, 0xb1, 0x15, 0xdb, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x8b, 0x36, 0x17, 0x3f, 0x3b, +0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x7e, 0x31, 0xfa, 0x42, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x2, +0x82, 0x1d, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x38, 0x51, 0x11, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xcb, +0xad, 0x8c, 0x42, 0xee, 0xb0, 0x25, 0x3f, 0x0, 0x5e, 0x5, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x75, 0x9b, 0x5f, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xfe, 0x23, 0x5b, 0x42, 0xfe, 0x5f, 0x45, 0x3f, 0xd0, 0xca, 0x6d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xfc, +0x4d, 0x64, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xe3, 0xe2, 0x8c, 0x42, 0x99, 0x46, 0x47, 0x3f, 0x0, 0x54, 0x3, 0x3a, 0x1, +0xbe, 0x38, 0x0, 0xb8, 0x3d, 0x2b, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xcb, 0xad, 0x8c, 0x42, 0xba, 0x2e, 0x30, 0x3f, 0x0, +0x5e, 0x5, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x26, 0x93, 0x26, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0x23, 0x5b, 0x42, 0x45, +0x4b, 0x2e, 0x3f, 0xd0, 0xca, 0x6d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xbc, 0xd2, 0x28, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0x6a, +0x6e, 0x8c, 0x42, 0x2f, 0x34, 0x2f, 0x3f, 0x0, 0x6d, 0x7d, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0xa8, 0x6d, 0x26, 0x43, 0x8, +0x59, 0x8e, 0xc1, 0x40, 0xb0, 0x8b, 0x42, 0x10, 0x3c, 0x2e, 0x3f, 0x40, 0x67, 0x19, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0x12, +0xd8, 0x6, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x37, 0xef, 0x93, 0x41, 0xda, 0x73, 0x21, 0x3f, 0xe5, 0xf1, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x80, 0x2d, 0x2, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x75, 0x90, 0x1f, 0x3f, 0x3b, +0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x29, 0xe6, 0x3a, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0xf1, +0x84, 0x36, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xbc, 0x90, 0x3f, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x37, +0xef, 0x93, 0x41, 0x55, 0x68, 0x38, 0x3f, 0xe5, 0xf1, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe4, 0x57, 0x3d, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x68, 0xe7, 0x43, 0x40, 0x2c, 0x82, 0x37, 0x3f, 0x6f, 0x67, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa, +0xc2, 0x3f, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xf5, 0x9c, 0x5b, 0x40, 0x52, 0x7c, 0x38, 0x3f, 0x2a, 0x0, 0x7e, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x7c, 0xe, 0x24, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0x53, 0x73, 0x8a, 0x42, 0x5f, 0x46, 0x2d, 0x3f, 0xa0, +0xbf, 0x97, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0x9e, 0x24, 0x42, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x71, 0x90, 0x81, 0x40, 0x64, +0x73, 0x39, 0x3f, 0x5d, 0xa9, 0x7b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x37, 0xb5, 0x21, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa0, +0xb7, 0x88, 0x42, 0x9, 0x53, 0x2c, 0x3f, 0xc0, 0x66, 0x0, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xb2, 0xf9, 0x25, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x68, 0xe8, 0x5a, 0x42, 0x24, 0xd, 0x2e, 0x3f, 0x88, 0xac, 0x6e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9d, +0x7f, 0x44, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x93, 0x39, 0x9d, 0x40, 0x73, 0x67, 0x3a, 0x3f, 0x6, 0x63, 0x78, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xd7, 0x2c, 0x40, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x87, 0xf8, 0x93, 0x41, 0x83, 0xa7, 0x38, 0x3f, 0x70, +0xed, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x27, 0xc7, 0x40, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xd2, 0x8d, 0x94, 0x41, 0xf7, +0xe5, 0x38, 0x3f, 0xca, 0xa6, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8, 0xd3, 0x46, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xe9, +0xc9, 0xc0, 0x40, 0x6d, 0x58, 0x3b, 0x3f, 0x28, 0x2d, 0x74, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xab, 0x5f, 0x41, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x12, 0xaf, 0x95, 0x41, 0xb3, 0x23, 0x39, 0x3f, 0xd2, 0x1d, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdc, +0x61, 0x1f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x2a, 0x7d, 0x86, 0x42, 0x20, 0x62, 0x2b, 0x3f, 0xc0, 0xf0, 0x43, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0x46, 0x61, 0x25, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x4c, 0x72, 0x5a, 0x42, 0x78, 0xcf, 0x2d, 0x3f, 0x0, +0x6c, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe0, 0xc9, 0x24, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xad, 0xc1, 0x59, 0x42, 0x32, +0x92, 0x2d, 0x3f, 0x40, 0x9, 0x73, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x66, 0x14, 0x1d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xec, +0xc3, 0x83, 0x42, 0x93, 0x73, 0x2a, 0x3f, 0x58, 0x3e, 0x8b, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x83, 0x33, 0x24, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x90, 0xd6, 0x58, 0x42, 0x61, 0x55, 0x2d, 0x3f, 0x4, 0x84, 0x76, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xdf, +0x1e, 0x49, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x6c, 0x41, 0xec, 0x40, 0x52, 0x46, 0x3c, 0x3f, 0xd1, 0x7, 0x6f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x65, 0xf6, 0x41, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x51, 0x5c, 0x97, 0x41, 0xb7, 0x60, 0x39, 0x3f, 0x87, +0x52, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x51, 0x8b, 0x42, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x87, 0x95, 0x99, 0x41, 0xf1, +0x9c, 0x39, 0x3f, 0xfa, 0x44, 0x42, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1e, 0x63, 0x4b, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xd, +0xd0, 0xf, 0x41, 0x23, 0x31, 0x3d, 0x3f, 0xe0, 0xf2, 0x68, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x75, 0x1e, 0x43, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0xb9, 0x5a, 0x9c, 0x41, 0x84, 0xd8, 0x39, 0x3f, 0x1b, 0xf5, 0x40, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x2c, +0x9e, 0x23, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xed, 0xb0, 0x57, 0x42, 0xf4, 0x18, 0x2d, 0x3f, 0x4c, 0xdc, 0x7a, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xd8, 0xcc, 0x1a, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xe9, 0x8b, 0x80, 0x42, 0x62, 0x87, 0x29, 0x3f, 0x50, +0x5, 0xbc, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xdf, 0x9, 0x23, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xc9, 0x50, 0x56, 0x42, 0xec, +0xdc, 0x2c, 0x3f, 0x2c, 0x9, 0x80, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x98, 0x76, 0x22, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x23, +0xb6, 0x54, 0x42, 0x49, 0xa1, 0x2c, 0x3f, 0x16, 0x13, 0x83, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x3b, 0xa4, 0x18, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xf2, 0xf3, 0x79, 0x42, 0xc6, 0xa7, 0x28, 0x3f, 0xe8, 0x1e, 0xf2, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xe8, +0xea, 0x21, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0xf0, 0x52, 0x42, 0xcb, 0x68, 0x2c, 0x3f, 0xc, 0x6f, 0x86, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xcb, 0xaf, 0x43, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xe4, 0xab, 0x9f, 0x41, 0x4d, 0x13, 0x3a, 0x3f, 0xfa, +0x62, 0x3f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb5, 0x87, 0x4d, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x6b, 0x44, 0x2c, 0x41, 0x1b, +0xf, 0x3e, 0x3f, 0x1a, 0x36, 0x62, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x35, 0x39, 0x44, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xf5, +0x58, 0xa3, 0x41, 0xf1, 0x4a, 0x3a, 0x3f, 0x54, 0xa5, 0x3d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x93, 0xb3, 0x16, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xdf, 0x65, 0x72, 0x42, 0xc6, 0xde, 0x27, 0x3f, 0xa4, 0xae, 0x15, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x5b, +0x6d, 0x21, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xfe, 0xd, 0x51, 0x42, 0xf0, 0x35, 0x2c, 0x3f, 0x5c, 0x0, 0x8a, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xf1, 0xfd, 0x20, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa6, 0xf, 0x4f, 0x42, 0xd9, 0x8, 0x2c, 0x3f, 0x26, +0xc7, 0x8d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x87, 0x74, 0x4f, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3d, 0x4f, 0x4a, 0x41, 0x99, +0xd6, 0x3e, 0x3f, 0xd, 0x19, 0x5b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8d, 0xb4, 0x44, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xd5, +0x31, 0xa7, 0x41, 0xe1, 0x7c, 0x3a, 0x3f, 0xea, 0xd2, 0x3b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd0, 0x21, 0x45, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x83, 0x36, 0xab, 0x41, 0xd, 0xa9, 0x3a, 0x3f, 0xc8, 0xeb, 0x39, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe3, +0xfa, 0x14, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa2, 0x6d, 0x6a, 0x42, 0x62, 0x2c, 0x27, 0x3f, 0x38, 0xe0, 0x33, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xac, 0x9c, 0x20, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0xf5, 0x4c, 0x42, 0x87, 0xe1, 0x2b, 0x3f, 0x26, +0xc3, 0x91, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x96, 0x29, 0x51, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x83, 0xf0, 0x69, 0x41, 0x7b, +0x87, 0x3f, 0x3f, 0xcc, 0x9b, 0x53, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6, 0x81, 0x45, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x6, +0x67, 0xaf, 0x41, 0x96, 0xcf, 0x3a, 0x3f, 0xe1, 0xef, 0x37, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x2a, 0xd2, 0x45, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x57, 0xc3, 0xb3, 0x41, 0x6b, 0xf0, 0x3a, 0x3f, 0x44, 0xdf, 0x35, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe1, +0xa6, 0x52, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x1d, 0x94, 0x85, 0x41, 0xc0, 0x21, 0x40, 0x3f, 0x44, 0xbe, 0x4b, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x3c, 0x15, 0x46, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x7a, 0x4b, 0xb8, 0x41, 0x9e, 0xb, 0x3b, 0x3f, 0xe0, +0xb9, 0x33, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8a, 0x49, 0x20, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x79, 0xbe, 0x4a, 0x42, 0xd7, +0xbf, 0x2b, 0x3f, 0x80, 0xf4, 0x95, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x28, 0x7a, 0x13, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x2f, +0xb, 0x62, 0x42, 0xbc, 0x90, 0x26, 0x3f, 0xec, 0xa3, 0x53, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x8c, 0x4, 0x20, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xa0, 0x6b, 0x48, 0x42, 0xec, 0xa3, 0x2b, 0x3f, 0x54, 0x5b, 0x9a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x66, +0x31, 0x12, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x97, 0x3e, 0x59, 0x42, 0xa2, 0xb, 0x26, 0x3f, 0xc0, 0xf9, 0x74, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xb2, 0xcd, 0x1f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x9c, 0xfc, 0x45, 0x42, 0xc5, 0x8d, 0x2b, 0x3f, 0x80, +0xf7, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6b, 0xec, 0x53, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x36, 0xfb, 0x96, 0x41, 0x7a, +0xa5, 0x40, 0x3f, 0x88, 0x80, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3d, 0x4a, 0x46, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x6d, +0xff, 0xbc, 0x41, 0xc, 0x21, 0x3b, 0x3f, 0xb6, 0x7f, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x90, 0x71, 0x46, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x8e, 0xe9, 0xc1, 0x41, 0xf9, 0x30, 0x3b, 0x3f, 0xed, 0x2b, 0x2f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x2f, +0xfa, 0x54, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x85, 0x2d, 0xa9, 0x41, 0xa9, 0x12, 0x41, 0x3f, 0x86, 0xe2, 0x3a, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xf, 0x87, 0x46, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xdc, 0x9a, 0xc6, 0x41, 0x9f, 0x39, 0x3b, 0x3f, 0x2, +0xf3, 0x2c, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x2f, 0xd0, 0x55, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xe, 0x2b, 0xbc, 0x41, 0x4d, +0x69, 0x41, 0x3f, 0x50, 0xe4, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb0, 0x8a, 0x46, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x58, +0x13, 0xcb, 0x41, 0x21, 0x3b, 0x3b, 0x3f, 0x6, 0xd5, 0x2a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x98, 0x20, 0x11, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xc8, 0x7, 0x50, 0x42, 0x45, 0x9d, 0x25, 0x3f, 0xfe, 0xf0, 0x8b, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x66, +0xa9, 0x1f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xae, 0xa8, 0x43, 0x42, 0x6, 0x7f, 0x2b, 0x3f, 0x4a, 0x60, 0xa3, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x86, 0x97, 0x1f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x6d, 0x6a, 0x41, 0x42, 0xd1, 0x77, 0x2b, 0x3f, 0xe, +0xa0, 0xa7, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc2, 0x47, 0x10, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xcc, 0x66, 0x46, 0x42, 0x84, +0x45, 0x25, 0x3f, 0x4e, 0x2e, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe, 0x98, 0x1f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd3, +0x41, 0x3f, 0x42, 0x3, 0x78, 0x2b, 0x3f, 0xcc, 0xb6, 0xab, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xfc, 0x68, 0x56, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x1b, 0x63, 0xcf, 0x41, 0x1a, 0xa7, 0x41, 0x3f, 0x60, 0xca, 0x28, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x7e, +0x7c, 0x46, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x5, 0x53, 0xcf, 0x41, 0x5d, 0x35, 0x3b, 0x3f, 0xfa, 0xd1, 0x28, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xe0, 0xb0, 0xf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xe5, 0xe0, 0x3c, 0x42, 0x70, 0x8, 0x25, 0x3f, 0x5c, +0x38, 0xb0, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6, 0xab, 0x1f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xe9, 0x2e, 0x3d, 0x42, 0xae, +0x7f, 0x2b, 0x3f, 0x84, 0xa4, 0xaf, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa1, 0xba, 0x56, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x97, +0xcb, 0xe1, 0x41, 0x21, 0xc8, 0x41, 0x3f, 0xae, 0x12, 0x20, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x73, 0x5c, 0x46, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xe1, 0x59, 0xd3, 0x41, 0x63, 0x28, 0x3b, 0x3f, 0xcc, 0xe9, 0x26, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1b, +0xc5, 0x56, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x85, 0x64, 0xf3, 0x41, 0x64, 0xcc, 0x41, 0x3f, 0x5a, 0xbd, 0x17, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x67, 0x88, 0x56, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xf1, 0x16, 0x2, 0x42, 0xd0, 0xb3, 0x41, 0x3f, 0x42, +0xca, 0xf, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x90, 0x2a, 0x46, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xec, 0x27, 0xd7, 0x41, 0x34, +0x14, 0x3b, 0x3f, 0x7e, 0x1c, 0x25, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8d, 0x4, 0x56, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xda, +0x13, 0xa, 0x42, 0x78, 0x7e, 0x41, 0x3f, 0x8a, 0x39, 0x8, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x83, 0x39, 0x55, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xfb, 0xa8, 0x11, 0x42, 0x49, 0x2c, 0x41, 0x3f, 0xfe, 0xa, 0x1, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd7, +0xe6, 0x45, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x26, 0xbd, 0xda, 0x41, 0xcf, 0xf8, 0x3a, 0x3f, 0x30, 0x6a, 0x23, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x4d, 0x27, 0x54, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x52, 0xd6, 0x18, 0x42, 0x55, 0xbd, 0x40, 0x3f, 0xa2, +0x7d, 0xf4, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xac, 0xda, 0x52, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x3e, 0x50, 0x1f, 0x42, 0xb9, +0x36, 0x40, 0x3f, 0x26, 0x39, 0xe8, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4a, 0x94, 0x45, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x7b, +0xf6, 0xdd, 0x41, 0x62, 0xd7, 0x3a, 0x3f, 0x54, 0xe3, 0x21, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5f, 0x60, 0x51, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x1a, 0xcb, 0x24, 0x42, 0xa1, 0x9d, 0x3f, 0x3f, 0xcc, 0xd7, 0xdd, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x67, +0xb8, 0x4f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xe5, 0x46, 0x29, 0x42, 0xf, 0xf2, 0x3e, 0x3f, 0x92, 0x59, 0xd5, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xbd, 0xe2, 0x4d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x9d, 0xc3, 0x2c, 0x42, 0xf0, 0x33, 0x3e, 0x3f, 0x9c, +0xbe, 0xce, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf3, 0x35, 0x45, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd7, 0xb0, 0xe0, 0x41, 0x3e, +0xb1, 0x3a, 0x3f, 0x92, 0x98, 0x20, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x6b, 0xdf, 0x4b, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x4a, +0x41, 0x2f, 0x42, 0x67, 0x63, 0x3d, 0x3f, 0xa6, 0x6, 0xca, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x69, 0xae, 0x49, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xe3, 0xbf, 0x30, 0x42, 0x63, 0x80, 0x3c, 0x3f, 0xf4, 0x31, 0xc7, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc6, +0xcb, 0x44, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x36, 0xec, 0xe2, 0x41, 0x40, 0x86, 0x3a, 0x3f, 0x9, 0x8a, 0x1f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xb9, 0x4f, 0x47, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x6a, 0x3f, 0x31, 0x42, 0xe3, 0x8a, 0x3b, 0x3f, 0x64, +0x40, 0xc6, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd2, 0x55, 0x44, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa0, 0xa8, 0xe4, 0x41, 0x8a, +0x56, 0x3a, 0x3f, 0x88, 0xb7, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdf, 0xe1, 0x40, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x6a, +0x3f, 0x31, 0x42, 0xc7, 0xf0, 0x38, 0x3f, 0x64, 0x40, 0xc6, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf, 0xd4, 0x43, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x10, 0xe6, 0xe5, 0x41, 0xfb, 0x21, 0x3a, 0x3f, 0x42, 0x21, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x7d, +0x46, 0x43, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x84, 0xa4, 0xe6, 0x41, 0xb4, 0xe8, 0x39, 0x3f, 0x4, 0xc7, 0x1d, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x1d, 0xad, 0x42, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x1, 0xe4, 0xe6, 0x41, 0xa4, 0xaa, 0x39, 0x3f, 0x0, +0xa9, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5e, 0xd5, 0x2d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x1, 0xe4, 0xe6, 0x41, 0x4b, +0x3b, 0x31, 0x3f, 0x0, 0xa9, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xce, 0x79, 0x35, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x6a, +0x3f, 0x31, 0x42, 0x9, 0x53, 0x34, 0x3f, 0x64, 0x40, 0xc6, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xcd, 0x6e, 0x23, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x6a, 0x3f, 0x31, 0x42, 0xc0, 0x5, 0x2d, 0x3f, 0x64, 0x40, 0xc6, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc7, +0xbe, 0x25, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x1, 0xe4, 0xe6, 0x41, 0x5a, 0xf5, 0x2d, 0x3f, 0x0, 0xa9, 0x1d, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x32, 0xcc, 0x1e, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x1, 0xe4, 0xe6, 0x41, 0x81, 0x25, 0x2b, 0x3f, 0x0, +0xa9, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8, 0xe3, 0x22, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xea, 0x5f, 0x31, 0x42, 0x31, +0xcd, 0x2c, 0x3f, 0xca, 0x2, 0xc6, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xec, 0x5f, 0x22, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x6f, +0xc1, 0x31, 0x42, 0x1c, 0x98, 0x2c, 0x3f, 0x1a, 0x4a, 0xc5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x7e, 0xe5, 0x21, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xf6, 0x63, 0x32, 0x42, 0x90, 0x66, 0x2c, 0x3f, 0x38, 0x16, 0xc4, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x66, +0x61, 0xf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xae, 0xbe, 0x33, 0x42, 0x42, 0xe8, 0x24, 0x3f, 0x6a, 0x85, 0xc1, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x50, 0x74, 0x1c, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb8, 0xe3, 0xe7, 0x41, 0xc2, 0x32, 0x2a, 0x3f, 0xe4, +0x2f, 0x1d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb8, 0x73, 0x21, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x7f, 0x47, 0x33, 0x42, 0x8f, +0x38, 0x2c, 0x3f, 0x40, 0x67, 0xc2, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x87, 0x48, 0x1a, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd9, +0xe2, 0xea, 0x41, 0xd7, 0x51, 0x29, 0x3f, 0xa0, 0xc4, 0x1b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd6, 0x48, 0x18, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x5f, 0xe1, 0xef, 0x41, 0xbf, 0x82, 0x28, 0x3f, 0x23, 0x67, 0x19, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa0, +0xa, 0x21, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd, 0x6c, 0x34, 0x42, 0x6, 0xe, 0x2c, 0x3f, 0x14, 0x3d, 0xc0, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x40, 0x75, 0x16, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x57, 0xdf, 0xf6, 0x41, 0x8b, 0xc5, 0x27, 0x3f, 0x7e, +0x17, 0x16, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc2, 0xcd, 0x14, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb7, 0xdc, 0xff, 0x41, 0x2a, +0x1a, 0x27, 0x3f, 0xa2, 0xd5, 0x11, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x30, 0xaa, 0x20, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x9d, +0xd1, 0x35, 0x42, 0xf7, 0xe6, 0x2b, 0x3f, 0xb4, 0x97, 0xbd, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x5e, 0x52, 0x13, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xc0, 0x6c, 0x5, 0x42, 0x9d, 0x80, 0x26, 0x3f, 0x9c, 0xa1, 0xc, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x14, +0x3, 0x12, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xdb, 0xea, 0xb, 0x42, 0xe4, 0xf8, 0x25, 0x3f, 0x5f, 0x7b, 0x6, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x89, 0xed, 0x10, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa8, 0x1a, 0x13, 0x42, 0xa0, 0x88, 0x25, 0x3f, 0xcc, +0x59, 0xff, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6c, 0x52, 0x20, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x2c, 0x78, 0x37, 0x42, 0x72, +0xc3, 0x2b, 0x3f, 0x60, 0x77, 0xba, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x66, 0x1f, 0x10, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x25, +0xae, 0x1a, 0x42, 0x33, 0x35, 0x25, 0x3f, 0xda, 0xff, 0xf0, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa8, 0x98, 0xf, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x4d, 0xa5, 0x22, 0x42, 0xac, 0xfe, 0x24, 0x3f, 0x4a, 0xe9, 0xe1, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x34, +0x8, 0x20, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x16, 0x4a, 0x39, 0x42, 0x6e, 0xa5, 0x2b, 0x3f, 0xbc, 0x4, 0xb7, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x54, 0x59, 0xf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x27, 0x0, 0x2b, 0x42, 0xfc, 0xe4, 0x24, 0x3f, 0xba, +0x15, 0xd2, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x66, 0xd0, 0x1f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa9, 0x31, 0x3b, 0x42, 0xd2, +0x8e, 0x2b, 0x3f, 0x34, 0x69, 0xb3, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6b, 0xe7, 0x59, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x37, +0xef, 0x93, 0x41, 0x1f, 0x11, 0x43, 0x3f, 0xe5, 0xf1, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd9, 0x3c, 0x55, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0xaa, 0x2d, 0x41, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3b, +0x64, 0x6a, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x40, 0xbd, 0x49, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xe8, 0xb0, 0x81, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x37, 0xef, 0x93, 0x41, 0x51, 0xda, 0x53, 0x3f, 0xe5, +0xf1, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4, 0xe3, 0x76, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0xc9, +0xcb, 0x4e, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x43, 0xb7, 0x7e, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3b, +0x0, 0x3c, 0x40, 0xec, 0xf6, 0x51, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x81, 0x94, 0x80, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x8d, 0xec, 0x43, 0x40, 0x28, 0xf4, 0x52, 0x3f, 0x2c, 0x67, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x9d, +0xc9, 0x81, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x8e, 0xb1, 0x5b, 0x40, 0x4e, 0xee, 0x53, 0x3f, 0xfc, 0xfe, 0x7d, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x5, 0x46, 0x64, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0x63, 0x43, 0x47, 0x3f, 0x54, +0x77, 0xc5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x7d, 0x93, 0x5f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa3, 0xf, 0xe6, 0x41, 0xb8, +0x5c, 0x45, 0x3f, 0x88, 0xd, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1e, 0x3b, 0x83, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa3, +0xf, 0xe6, 0x41, 0x69, 0x19, 0x55, 0x3f, 0x88, 0xd, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xbf, 0x44, 0x85, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x99, 0xa9, 0x31, 0x42, 0x98, 0xbf, 0x56, 0x3f, 0x54, 0x77, 0xc5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x50, +0x75, 0x69, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xcb, 0xad, 0x8c, 0x42, 0x96, 0x5c, 0x49, 0x3f, 0x0, 0x5e, 0x5, 0x3b, 0x1, +0xbe, 0x38, 0x0, 0xca, 0xc2, 0x64, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xce, 0xb9, 0x5a, 0x42, 0xea, 0x75, 0x47, 0x3f, 0x34, +0x5d, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf3, 0xce, 0x86, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xce, 0xb9, 0x5a, 0x42, 0xb0, +0xfe, 0x57, 0x3f, 0x34, 0x5d, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xca, 0x94, 0x69, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xb6, +0x9f, 0x8c, 0x42, 0x4d, 0x69, 0x49, 0x3f, 0x0, 0xa, 0x20, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0xc9, 0xf7, 0x69, 0x43, 0x8, +0x59, 0x8e, 0xc1, 0xcb, 0x93, 0x8c, 0x42, 0x58, 0x91, 0x49, 0x3f, 0x0, 0xa6, 0x36, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x41, +0x9e, 0x6a, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0x9, 0x8a, 0x8c, 0x42, 0xb7, 0xd4, 0x49, 0x3f, 0x0, 0x21, 0x49, 0x3b, 0x1, +0xbe, 0x38, 0x0, 0x3f, 0x88, 0x6b, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0x74, 0x82, 0x8c, 0x42, 0x6a, 0x33, 0x4a, 0x3f, 0x0, +0x7b, 0x57, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0xba, 0xb5, 0x6c, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0x9, 0x7d, 0x8c, 0x42, 0x71, +0xad, 0x4a, 0x3f, 0x0, 0xc6, 0x61, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0xb9, 0x26, 0x6e, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xc9, +0x79, 0x8c, 0x42, 0xbb, 0x42, 0x4b, 0x3f, 0x0, 0xef, 0x67, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x37, 0xdb, 0x6f, 0x43, 0x8, +0x59, 0x8e, 0xc1, 0xb3, 0x78, 0x8c, 0x42, 0x6b, 0xf3, 0x4b, 0x3f, 0x0, 0xf7, 0x69, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x1, +0x10, 0x7e, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xb3, 0x78, 0x8c, 0x42, 0x39, 0xb3, 0x51, 0x3f, 0x0, 0xf7, 0x69, 0x3b, 0x1, +0xbe, 0x38, 0x0, 0x9, 0x5, 0x85, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xb3, 0x78, 0x8c, 0x42, 0x5, 0x8c, 0x56, 0x3f, 0x0, +0xf7, 0x69, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0xf6, 0xfa, 0x82, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x9a, 0xa7, 0x81, 0x40, 0x71, +0xe5, 0x54, 0x3f, 0x9c, 0xa6, 0x7b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe0, 0xe1, 0x88, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xb3, +0x78, 0x8c, 0x42, 0x69, 0xac, 0x59, 0x3f, 0x0, 0xf7, 0x69, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x43, 0x18, 0x87, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x62, 0x9a, 0x5a, 0x42, 0x0, 0x3a, 0x58, 0x3f, 0x38, 0xd4, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd1, +0x87, 0x83, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xcb, 0xd0, 0xe5, 0x41, 0x79, 0x57, 0x55, 0x3f, 0x5a, 0x2b, 0x1e, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x8a, 0x28, 0x84, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xc1, 0x62, 0x9d, 0x40, 0x90, 0xd9, 0x55, 0x3f, 0x2d, +0x5e, 0x78, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf2, 0xfe, 0x81, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xe2, 0xf7, 0x93, 0x41, 0x7e, +0x19, 0x54, 0x3f, 0xc4, 0xed, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x12, 0x4c, 0x82, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3f, +0x8b, 0x94, 0x41, 0xe2, 0x57, 0x54, 0x3f, 0x9, 0xa8, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5c, 0x52, 0x85, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x3d, 0xa, 0xc1, 0x40, 0x9b, 0xca, 0x56, 0x3f, 0x8d, 0x25, 0x74, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x43, +0x98, 0x82, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x48, 0xa9, 0x95, 0x41, 0x8e, 0x95, 0x54, 0x3f, 0x92, 0x20, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x69, 0x78, 0x86, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xe, 0x9e, 0xec, 0x40, 0xa2, 0xb8, 0x57, 0x3f, 0xce, +0xfc, 0x6e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x8a, 0xe3, 0x82, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x5, 0x52, 0x97, 0x41, 0x80, +0xd2, 0x54, 0x3f, 0x60, 0x57, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe5, 0x2d, 0x83, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x72, +0x85, 0x99, 0x41, 0xaa, 0xe, 0x55, 0x3f, 0x94, 0x4c, 0x42, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb2, 0x9a, 0x87, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x1a, 0xf, 0x10, 0x41, 0x94, 0xa3, 0x58, 0x3f, 0xef, 0xe3, 0x68, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x55, +0x77, 0x83, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x8f, 0x43, 0x9c, 0x41, 0x1b, 0x4a, 0x55, 0x3f, 0x1d, 0x0, 0x41, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x83, 0x5c, 0x87, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x1e, 0x3c, 0x5a, 0x42, 0x3f, 0x71, 0x58, 0x3f, 0x88, +0x39, 0x71, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa3, 0xce, 0x83, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x42, 0x14, 0xe5, 0x41, 0xd1, +0x90, 0x55, 0x3f, 0x9c, 0x84, 0x1e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd8, 0xbf, 0x83, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x5d, +0x8c, 0x9f, 0x41, 0xd3, 0x84, 0x55, 0x3f, 0xeb, 0x71, 0x3f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x29, 0xad, 0x88, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0xf4, 0x95, 0x2c, 0x41, 0xbf, 0x81, 0x59, 0x3f, 0xc4, 0x22, 0x62, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x62, +0x4, 0x84, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x30, 0x30, 0xa3, 0x41, 0x45, 0xbc, 0x55, 0x3f, 0xaa, 0xb8, 0x3d, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xc1, 0xa3, 0x89, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x36, 0xb4, 0x4a, 0x41, 0x4d, 0x49, 0x5a, 0x3f, 0x22, +0x1, 0x5b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xdf, 0x41, 0x84, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x58, 0xff, 0xa6, 0x41, 0x13, +0xee, 0x55, 0x3f, 0xd5, 0xea, 0x3b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x50, 0x78, 0x84, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xd6, +0xf9, 0xaa, 0x41, 0x1e, 0x1a, 0x56, 0x3f, 0x8e, 0x8, 0x3a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x79, 0x7e, 0x8a, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0xdf, 0x69, 0x6a, 0x41, 0x61, 0xfa, 0x5a, 0x3f, 0x6, 0x7f, 0x53, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb8, +0xa7, 0x84, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xaf, 0x1f, 0xaf, 0x41, 0x85, 0x40, 0x56, 0x3f, 0xb2, 0x11, 0x38, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x13, 0xd0, 0x84, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xdc, 0x70, 0xb3, 0x41, 0x28, 0x61, 0x56, 0x3f, 0x53, +0x6, 0x36, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x52, 0x3d, 0x8b, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x75, 0xdb, 0x85, 0x41, 0xd9, +0x94, 0x5b, 0x3f, 0x84, 0x9c, 0x4b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x65, 0xf1, 0x84, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x61, +0xed, 0xb7, 0x41, 0x28, 0x7c, 0x56, 0x3f, 0x71, 0xe6, 0x33, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4d, 0xe0, 0x8b, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0xb1, 0x4d, 0x97, 0x41, 0xb5, 0x18, 0x5c, 0x3f, 0x79, 0x59, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xac, +0xb, 0x85, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3e, 0x95, 0xbc, 0x41, 0x64, 0x91, 0x56, 0x3f, 0xc, 0xb2, 0x31, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x1c, 0x1f, 0x85, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x49, 0x73, 0xc1, 0x41, 0x1f, 0xa1, 0x56, 0x3f, 0xf6, +0x63, 0x2f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x66, 0x67, 0x8c, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x9f, 0x8b, 0xa9, 0x41, 0x16, +0x86, 0x5c, 0x3f, 0xf6, 0xb5, 0x3a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa3, 0x29, 0x85, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xfa, +0x18, 0xc6, 0x41, 0xa4, 0xa9, 0x56, 0x3f, 0x8c, 0x30, 0x2d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x9f, 0xd2, 0x8c, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x3e, 0x95, 0xbc, 0x41, 0xdb, 0xdc, 0x5c, 0x3f, 0xc, 0xb2, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x3e, +0x2b, 0x85, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x51, 0x86, 0xca, 0x41, 0xf3, 0xaa, 0x56, 0x3f, 0xdf, 0x17, 0x2b, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xb2, 0x9b, 0x87, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x3, 0x9f, 0x59, 0x42, 0x5d, 0xa4, 0x58, 0x3f, 0x98, +0x8c, 0x73, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x3f, 0x11, 0x8a, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0x52, 0x39, 0x8c, 0x42, 0xe8, +0xa1, 0x5a, 0x3f, 0x80, 0x3, 0xb1, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x95, 0xf, 0x84, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd, +0xda, 0xe3, 0x41, 0x61, 0xc5, 0x55, 0x3f, 0x61, 0x19, 0x1f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd6, 0x29, 0x8b, 0x43, 0x8, +0x59, 0x8e, 0xc1, 0x29, 0x7b, 0x8b, 0x42, 0xe, 0x85, 0x5b, 0x3f, 0x80, 0x8d, 0x32, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0xcf, +0xd5, 0x87, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd, 0xc3, 0x58, 0x42, 0x6b, 0xd3, 0x58, 0x3f, 0xf4, 0xcd, 0x76, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xa3, 0x2b, 0x8c, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0x3a, 0x3e, 0x8a, 0x42, 0xb9, 0x55, 0x5c, 0x3f, 0xc0, +0x52, 0xa4, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0xde, 0xa, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x44, 0xa8, 0x57, 0x42, 0x58, +0xfe, 0x58, 0x3f, 0x54, 0xfd, 0x7a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xab, 0x16, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x89, +0x82, 0x88, 0x42, 0xf9, 0x13, 0x5d, 0x3f, 0x50, 0xb0, 0x6, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xea, 0xea, 0x8d, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x10, 0x48, 0x86, 0x42, 0xbe, 0xbf, 0x5d, 0x3f, 0x50, 0x3a, 0x4a, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x61, +0xa8, 0x8e, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd4, 0x8e, 0x83, 0x42, 0x19, 0x59, 0x5e, 0x3f, 0x20, 0x63, 0x8e, 0x3d, 0x1, +0xbe, 0x38, 0x0, 0xda, 0x3a, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x9f, 0x4e, 0x56, 0x42, 0x35, 0x25, 0x59, 0x3f, 0x5e, +0xd, 0x80, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x11, 0x4f, 0x8f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd1, 0x56, 0x80, 0x42, 0xf8, +0xdf, 0x5e, 0x3f, 0x18, 0x2a, 0xbf, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x86, 0xd8, 0x8f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xc3, +0x89, 0x79, 0x42, 0x40, 0x4f, 0x5f, 0x3f, 0xb0, 0x43, 0xf5, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xc5, 0x65, 0x88, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x23, 0xb6, 0x54, 0x42, 0xf1, 0x47, 0x59, 0x3f, 0x16, 0x13, 0x83, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4f, +0x3e, 0x90, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb3, 0xfb, 0x71, 0x42, 0xa1, 0xa1, 0x5f, 0x3f, 0x8, 0x41, 0x17, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x68, 0x80, 0x90, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x71, 0x3, 0x6a, 0x42, 0x2c, 0xd7, 0x5f, 0x3f, 0x9c, +0x72, 0x35, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x91, 0x89, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x25, 0xf0, 0x52, 0x42, 0xe9, +0x64, 0x59, 0x3f, 0xc, 0x6f, 0x86, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd8, 0x9e, 0x90, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x5, +0xa1, 0x61, 0x42, 0xbf, 0xef, 0x5f, 0x3f, 0x50, 0x36, 0x55, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9a, 0x99, 0x90, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x65, 0xd4, 0x58, 0x42, 0x8e, 0xeb, 0x5f, 0x3f, 0x28, 0x8c, 0x76, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x2e, +0xa4, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xfb, 0xd, 0x51, 0x42, 0x78, 0x7a, 0x59, 0x3f, 0x7e, 0x0, 0x8a, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xb0, 0x70, 0x90, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x97, 0x9d, 0x4f, 0x42, 0x64, 0xca, 0x5f, 0x3f, 0x52, +0xba, 0x8c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9d, 0xb5, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa7, 0xf, 0x4f, 0x42, 0x90, +0x88, 0x59, 0x3f, 0x26, 0xc7, 0x8d, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x19, 0x24, 0x90, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x9c, +0xfc, 0x45, 0x42, 0x65, 0x8c, 0x5f, 0x3f, 0x80, 0xf7, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xdb, 0xbd, 0x88, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x25, 0xf5, 0x4c, 0x42, 0x3f, 0x8f, 0x59, 0x3f, 0x26, 0xc3, 0x91, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xdb, +0xfa, 0x8f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb3, 0xfc, 0x41, 0x42, 0x9, 0x6b, 0x5f, 0x3f, 0x1a, 0x8b, 0xa6, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xee, 0xbc, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x7b, 0xbe, 0x4a, 0x42, 0x75, 0x8e, 0x59, 0x3f, 0xa2, +0xf4, 0x95, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x7f, 0xcc, 0x8f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xf4, 0xb, 0x3e, 0x42, 0x8d, +0x45, 0x5f, 0x3f, 0xde, 0x1, 0xae, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x2, 0x99, 0x8f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x5e, +0x2a, 0x3a, 0x42, 0xdf, 0x1b, 0x5f, 0x3f, 0xee, 0x5b, 0xb5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd0, 0xb2, 0x88, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xa1, 0x6b, 0x48, 0x42, 0x55, 0x86, 0x59, 0x3f, 0x54, 0x5b, 0x9a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6a, +0x60, 0x8f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xf6, 0x57, 0x36, 0x42, 0xf, 0xee, 0x5e, 0x3f, 0x4a, 0x99, 0xbc, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xb1, 0x22, 0x8f, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb7, 0x94, 0x32, 0x42, 0xe, 0xbc, 0x5e, 0x3f, 0xf2, +0xb9, 0xc3, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x83, 0x9f, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x9c, 0xfc, 0x45, 0x42, 0xab, +0x76, 0x59, 0x3f, 0x80, 0xf7, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xdb, 0xdf, 0x8e, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa5, +0xe0, 0x2e, 0x42, 0xfd, 0x85, 0x5e, 0x3f, 0xc2, 0xbd, 0xca, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe6, 0x97, 0x8e, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xbf, 0x3b, 0x2b, 0x42, 0xba, 0x4b, 0x5e, 0x3f, 0xe0, 0xa4, 0xd1, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x19, +0x85, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xad, 0xa8, 0x43, 0x42, 0x4e, 0x61, 0x59, 0x3f, 0x6c, 0x60, 0xa3, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x2c, 0x4b, 0x8e, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x2f, 0xa8, 0x27, 0x42, 0xaa, 0xd, 0x5e, 0x3f, 0x38, +0x6b, 0xd8, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x60, 0x63, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x6b, 0x6a, 0x41, 0x42, 0xfa, +0x45, 0x59, 0x3f, 0x30, 0xa0, 0xa7, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x8, 0xfa, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x1e, +0x28, 0x24, 0x42, 0xff, 0xcb, 0x5d, 0x3f, 0x9a, 0xc, 0xdf, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x77, 0xa4, 0x8d, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x8e, 0xbb, 0x20, 0x42, 0xba, 0x86, 0x5d, 0x3f, 0x4, 0x89, 0xe5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x56, +0x3a, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd5, 0x41, 0x3f, 0x42, 0xd1, 0x24, 0x59, 0x3f, 0xee, 0xb6, 0xab, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x80, 0x4a, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x81, 0x62, 0x1d, 0x42, 0xea, 0x3d, 0x5d, 0x3f, 0x7a, +0xe0, 0xeb, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xfc, 0x9, 0x88, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xe7, 0x2e, 0x3d, 0x42, 0xa0, +0xfd, 0x58, 0x3f, 0xa4, 0xa4, 0xaf, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x1d, 0xec, 0x8c, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xf2, +0x1c, 0x1a, 0x42, 0x80, 0xf1, 0x5c, 0x3f, 0xfa, 0x12, 0xf2, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4f, 0x89, 0x8c, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xe5, 0xea, 0x16, 0x42, 0x8c, 0xa1, 0x5c, 0x3f, 0xa4, 0x20, 0xf8, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x53, +0xd2, 0x87, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xaa, 0x31, 0x3b, 0x42, 0x9a, 0xd0, 0x58, 0x3f, 0x34, 0x69, 0xb3, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x18, 0x22, 0x8c, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x5b, 0xcc, 0x13, 0x42, 0xfd, 0x4d, 0x5c, 0x3f, 0x36, +0x9, 0xfe, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x58, 0x93, 0x87, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x16, 0x4a, 0x39, 0x42, 0x9d, +0x9d, 0x58, 0x3f, 0xde, 0x4, 0xb7, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd, 0x4d, 0x87, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x2c, +0x78, 0x37, 0x42, 0xbb, 0x64, 0x58, 0x3f, 0x60, 0x77, 0xba, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x76, 0xf8, 0x8c, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0xf0, 0x48, 0xc5, 0x41, 0x76, 0xfb, 0x5c, 0x3f, 0xc, 0x93, 0x2d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf2, +0x23, 0x85, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x55, 0xbb, 0xce, 0x41, 0xd, 0xa5, 0x56, 0x3f, 0xce, 0x19, 0x29, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xcc, 0x15, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xf5, 0xd9, 0xcd, 0x41, 0x40, 0x13, 0x5d, 0x3f, 0x90, +0x84, 0x29, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa2, 0x2a, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x50, 0x48, 0xd6, 0x41, 0x18, +0x24, 0x5d, 0x3f, 0x76, 0x86, 0x25, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf4, 0x36, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xfd, +0x93, 0xde, 0x41, 0xe, 0x2e, 0x5d, 0x3f, 0xc0, 0x98, 0x21, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xbb, 0x13, 0x85, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xff, 0xb7, 0xd2, 0x41, 0xf2, 0x97, 0x56, 0x3f, 0x7a, 0x36, 0x27, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xc8, +0x3a, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x0, 0xbd, 0xe6, 0x41, 0x33, 0x31, 0x5d, 0x3f, 0x7c, 0xbb, 0x1d, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x18, 0x36, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x57, 0xc3, 0xee, 0x41, 0x66, 0x2d, 0x5d, 0x3f, 0x9a, +0xee, 0x19, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe6, 0x28, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xff, 0xa6, 0xf6, 0x41, 0xb8, +0x22, 0x5d, 0x3f, 0x2b, 0x32, 0x16, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x95, 0x14, 0x8d, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xfd, +0x5a, 0xfe, 0x41, 0x45, 0x12, 0x5d, 0x3f, 0x58, 0x8c, 0x12, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x9c, 0xfa, 0x84, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x53, 0x7c, 0xd6, 0x41, 0x90, 0x83, 0x56, 0x3f, 0xd2, 0x6d, 0x25, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x86, +0xfa, 0x8c, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x25, 0xe9, 0x2, 0x42, 0x2a, 0xfd, 0x5c, 0x3f, 0x3a, 0x3, 0xf, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xb9, 0xda, 0x8c, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x78, 0x86, 0x6, 0x42, 0x69, 0xe3, 0x5c, 0x3f, 0xd0, +0x96, 0xb, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x2d, 0xb5, 0x8c, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x70, 0x5, 0xa, 0x42, 0x0, +0xc5, 0x5c, 0x3f, 0x2c, 0x47, 0x8, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x93, 0xd8, 0x84, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x4d, +0x8, 0xda, 0x41, 0xa, 0x68, 0x56, 0x3f, 0xd7, 0xbf, 0x23, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe5, 0x89, 0x8c, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x17, 0x66, 0xd, 0x42, 0x1, 0xa2, 0x5c, 0x3f, 0x3c, 0x14, 0x5, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xde, +0x58, 0x8c, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x64, 0xa8, 0x10, 0x42, 0x4a, 0x7a, 0x5c, 0x3f, 0x11, 0xfe, 0x1, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xc, 0x3, 0x87, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xc5, 0xd3, 0x35, 0x42, 0xd4, 0x28, 0x58, 0x3f, 0xc4, +0x93, 0xbd, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xee, 0xb8, 0x86, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb6, 0x74, 0x34, 0x42, 0xdd, +0xec, 0x57, 0x3f, 0xb2, 0x2c, 0xc0, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x25, 0xaf, 0x84, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x46, +0x39, 0xdd, 0x41, 0x7c, 0x46, 0x56, 0x3f, 0xea, 0x3c, 0x22, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb6, 0x6e, 0x86, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x0, 0x5b, 0x33, 0x42, 0xc4, 0xb0, 0x57, 0x3f, 0x4a, 0x42, 0xc2, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x61, +0x24, 0x86, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa1, 0x86, 0x32, 0x42, 0x9b, 0x74, 0x57, 0x3f, 0x8c, 0xd4, 0xc3, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xd6, 0x7f, 0x84, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x8d, 0xec, 0xdf, 0x41, 0x36, 0x20, 0x56, 0x3f, 0x90, +0xf5, 0x20, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xf3, 0xd9, 0x85, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x9d, 0xf7, 0x31, 0x42, 0x61, +0x38, 0x57, 0x3f, 0x7a, 0xe3, 0xc4, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa5, 0x4a, 0x84, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x23, +0x22, 0xe2, 0x41, 0x27, 0xf5, 0x55, 0x3f, 0xb8, 0xe9, 0x1f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x67, 0x8f, 0x85, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xef, 0xad, 0x31, 0x42, 0x5, 0xfc, 0x56, 0x3f, 0x12, 0x6f, 0xc5, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x1d, +0x6e, 0x96, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xcb, 0xad, 0x8c, 0x42, 0x94, 0xa3, 0x64, 0x3f, 0x0, 0x6e, 0x5, 0x3b, 0x1, +0xbe, 0x38, 0x0, 0xe1, 0x51, 0x8c, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0xa7, 0x74, 0x5c, 0x3f, 0x3b, +0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1d, 0x6e, 0x96, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x37, 0xef, 0x93, 0x41, 0x94, +0xa3, 0x64, 0x3f, 0xe5, 0xf1, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xcb, 0xdb, 0x9b, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xce, +0xb9, 0x5a, 0x42, 0x5f, 0x8, 0x69, 0x3f, 0x34, 0x5d, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x5f, 0x3e, 0xa6, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x2e, 0x70, 0x71, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xaa, +0x93, 0xa8, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x37, 0xef, 0x93, 0x41, 0xa4, 0x53, 0x73, 0x3f, 0xe5, 0xf1, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x9d, 0x5a, 0xb0, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xcb, 0xad, 0x8c, 0x42, 0x1b, 0x9f, 0x79, 0x3f, 0x0, +0x6e, 0x5, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x56, 0x1, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xce, 0xb9, 0x5a, 0x42, 0x6f, +0xb8, 0x77, 0x3f, 0x78, 0x5d, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x3f, 0x77, 0xa7, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x8d, +0xec, 0x43, 0x40, 0x6a, 0x6d, 0x72, 0x3f, 0x2c, 0x67, 0x7f, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5d, 0xac, 0xa8, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x8e, 0xb1, 0x5b, 0x40, 0xa1, 0x67, 0x73, 0x3f, 0xfc, 0xfe, 0x7d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5, +0x9, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb8, 0xb8, 0x5a, 0x42, 0xa9, 0xbe, 0x77, 0x3f, 0x68, 0x61, 0x6f, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xb5, 0xdd, 0xa9, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x9a, 0xa7, 0x81, 0x40, 0xc4, 0x5e, 0x74, 0x3f, 0xad, +0xa6, 0x7b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe3, 0x10, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x78, 0xb5, 0x5a, 0x42, 0x5, +0xc5, 0x77, 0x3f, 0xb8, 0x6d, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf3, 0x18, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd, +0xb0, 0x5a, 0x42, 0x92, 0xcb, 0x77, 0x3f, 0x2c, 0x82, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x48, 0xb, 0xab, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0xc1, 0x62, 0x9d, 0x40, 0xe3, 0x52, 0x75, 0x3f, 0x2d, 0x5e, 0x78, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xb4, +0xe1, 0xa8, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xe2, 0xf7, 0x93, 0x41, 0xd1, 0x92, 0x73, 0x3f, 0xd4, 0xed, 0x44, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xd2, 0x2e, 0xa9, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3f, 0x8b, 0x94, 0x41, 0x35, 0xd1, 0x73, 0x3f, 0x9, +0xa8, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x1e, 0x35, 0xac, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3d, 0xa, 0xc1, 0x40, 0xee, +0x43, 0x76, 0x3f, 0x9e, 0x25, 0x74, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4, 0x7b, 0xa9, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x48, +0xa9, 0x95, 0x41, 0xe0, 0xe, 0x74, 0x3f, 0x92, 0x20, 0x44, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x32, 0x21, 0xae, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x77, 0xa8, 0x5a, 0x42, 0x31, 0xd2, 0x77, 0x3f, 0x0, 0x9f, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa3, +0x29, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xbb, 0x9e, 0x5a, 0x42, 0x12, 0xd9, 0x77, 0x3f, 0xf8, 0xc3, 0x6f, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x29, 0x5b, 0xad, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xe, 0x9e, 0xec, 0x40, 0xf4, 0x31, 0x77, 0x3f, 0xdf, +0xfc, 0x6e, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x4b, 0xc6, 0xa9, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x5, 0x52, 0x97, 0x41, 0xd3, +0x4b, 0x74, 0x3f, 0x71, 0x57, 0x43, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa7, 0x10, 0xaa, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x72, +0x85, 0x99, 0x41, 0xfd, 0x87, 0x74, 0x3f, 0x94, 0x4c, 0x42, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x72, 0x7d, 0xae, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x1a, 0xf, 0x10, 0x41, 0xe7, 0x1c, 0x78, 0x3f, 0x0, 0xe4, 0x68, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x16, +0x5a, 0xaa, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x8f, 0x43, 0x9c, 0x41, 0x6e, 0xc3, 0x74, 0x3f, 0x1d, 0x0, 0x41, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x44, 0x32, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xcd, 0x92, 0x5a, 0x42, 0x5, 0xe0, 0x77, 0x3f, 0x10, +0xf1, 0x6f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x15, 0x3b, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb7, 0x84, 0x5a, 0x42, 0x29, +0xe7, 0x77, 0x3f, 0x88, 0x26, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xe6, 0x43, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xa2, +0x76, 0x5a, 0x42, 0x4e, 0xee, 0x77, 0x3f, 0xc0, 0x5b, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x85, 0x4c, 0xae, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xb4, 0x6a, 0x5a, 0x42, 0x51, 0xf5, 0x77, 0x3f, 0x18, 0x89, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xf7, +0x54, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xf6, 0x60, 0x5a, 0x42, 0x22, 0xfc, 0x77, 0x3f, 0xcc, 0xad, 0x70, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x36, 0x5d, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x5e, 0x59, 0x5a, 0x42, 0xd1, 0x2, 0x78, 0x3f, 0xa4, +0xca, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x47, 0x65, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xf6, 0x53, 0x5a, 0x42, 0x4e, +0x9, 0x78, 0x3f, 0x14, 0xdf, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x25, 0x6d, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb5, +0x50, 0x5a, 0x42, 0xaa, 0xf, 0x78, 0x3f, 0x68, 0xeb, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd2, 0x74, 0xae, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xa0, 0x4f, 0x5a, 0x42, 0xe4, 0x15, 0x78, 0x3f, 0x98, 0xef, 0x70, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x9a, +0xa2, 0xaa, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x5d, 0x8c, 0x9f, 0x41, 0x26, 0xfe, 0x74, 0x3f, 0xeb, 0x71, 0x3f, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xe9, 0x8f, 0xaf, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xf4, 0x95, 0x2c, 0x41, 0x12, 0xfb, 0x78, 0x3f, 0xd5, +0x22, 0x62, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x21, 0xe7, 0xaa, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x30, 0x30, 0xa3, 0x41, 0x98, +0x35, 0x75, 0x3f, 0xaa, 0xb8, 0x3d, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x82, 0x86, 0xb0, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x36, +0xb4, 0x4a, 0x41, 0xa0, 0xc2, 0x79, 0x3f, 0x32, 0x1, 0x5b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xa0, 0x24, 0xab, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x58, 0xff, 0xa6, 0x41, 0x66, 0x67, 0x75, 0x3f, 0xe6, 0xea, 0x3b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x11, +0x5b, 0xab, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xd6, 0xf9, 0xaa, 0x41, 0x71, 0x93, 0x75, 0x3f, 0x8e, 0x8, 0x3a, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x39, 0x61, 0xb1, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xdf, 0x69, 0x6a, 0x41, 0xa3, 0x73, 0x7a, 0x3f, 0x17, +0x7f, 0x53, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd5, 0xb2, 0xab, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xdc, 0x70, 0xb3, 0x41, 0x7b, +0xda, 0x75, 0x3f, 0x53, 0x6, 0x36, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x11, 0x20, 0xb2, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x75, +0xdb, 0x85, 0x41, 0x1b, 0xe, 0x7b, 0x3f, 0x84, 0x9c, 0x4b, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x27, 0xd4, 0xab, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x61, 0xed, 0xb7, 0x41, 0x7b, 0xf5, 0x75, 0x3f, 0x71, 0xe6, 0x33, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xd, +0xc3, 0xb2, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0xb1, 0x4d, 0x97, 0x41, 0x8, 0x92, 0x7b, 0x3f, 0x79, 0x59, 0x43, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0x6d, 0xee, 0xab, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x3e, 0x95, 0xbc, 0x41, 0xb7, 0xa, 0x76, 0x3f, 0xc, +0xb2, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0xe1, 0xd5, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xcc, 0x66, 0x46, 0x42, 0xb1, +0x33, 0x79, 0x3f, 0x6e, 0x2e, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x25, 0x4a, 0xb3, 0x43, 0x10, 0x59, 0x8e, 0xc1, 0x9f, +0x8b, 0xa9, 0x41, 0x69, 0xff, 0x7b, 0x3f, 0xf6, 0xb5, 0x3a, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x5f, 0xb5, 0xb3, 0x43, 0x10, +0x59, 0x8e, 0xc1, 0x3e, 0x95, 0xbc, 0x41, 0x2e, 0x56, 0x7c, 0x3f, 0xc, 0xb2, 0x31, 0x3f, 0x1, 0xbe, 0x38, 0x0, 0x16, +0xab, 0xb5, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xcd, 0x8d, 0x12, 0x42, 0x3e, 0xec, 0x7d, 0x3f, 0x55, 0x32, 0x0, 0x3f, 0x1, +0xbe, 0x38, 0x0, 0xa5, 0xe9, 0xb6, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x84, 0xbc, 0x33, 0x42, 0x20, 0xee, 0x7e, 0x3f, 0x9c, +0x89, 0xc1, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xda, 0x98, 0xb7, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x9c, 0xfc, 0x45, 0x42, 0xf2, +0x7b, 0x7f, 0x3f, 0xa0, 0xf7, 0x9e, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x6b, 0xe5, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xf5, +0x62, 0x48, 0x42, 0x46, 0x40, 0x79, 0x3f, 0xd6, 0x6b, 0x9a, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x58, 0xed, 0xaf, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xf6, 0x4f, 0x4a, 0x42, 0xa2, 0x46, 0x79, 0x3f, 0xf4, 0xc5, 0x96, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xa5, +0xed, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xc7, 0x2d, 0x4c, 0x42, 0xe5, 0x46, 0x79, 0x3f, 0xe6, 0x3c, 0x93, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xd7, 0xa7, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xae, 0xc1, 0x59, 0x42, 0x2d, 0x3f, 0x78, 0x3f, 0x40, +0x9, 0x73, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x71, 0xe5, 0xb7, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x97, 0x9d, 0x4f, 0x42, 0xe0, +0xb9, 0x7f, 0x3f, 0x52, 0xba, 0x8c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x58, 0xe6, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x71, +0xfc, 0x4d, 0x42, 0xff, 0x40, 0x79, 0x3f, 0x6c, 0xd0, 0x8f, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xec, 0x88, 0xb1, 0x43, 0x8, +0x59, 0x8e, 0xc1, 0x53, 0x60, 0x8c, 0x42, 0xd1, 0x93, 0x7a, 0x3f, 0x80, 0x15, 0x8c, 0x3b, 0x1, 0xbe, 0x38, 0x0, 0x3c, +0xd8, 0xae, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x91, 0xa, 0x59, 0x42, 0x5e, 0x66, 0x78, 0x3f, 0x28, 0xbf, 0x75, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x9f, 0xa0, 0xb2, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0x40, 0x96, 0x8b, 0x42, 0x2e, 0x76, 0x7b, 0x3f, 0x80, +0xbd, 0x25, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0xff, 0x5, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x49, 0x2a, 0x58, 0x42, 0x65, +0x8b, 0x78, 0x3f, 0xc4, 0x10, 0x79, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xb0, 0xa1, 0xb3, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0x90, +0x4f, 0x8a, 0x42, 0x41, 0x46, 0x7c, 0x3f, 0x20, 0x38, 0xa0, 0x3c, 0x1, 0xbe, 0x38, 0x0, 0x26, 0x8c, 0xb4, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x49, 0x8c, 0x88, 0x42, 0xc, 0x4, 0x7d, 0x3f, 0xb0, 0x89, 0x5, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x22, +0x31, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xd2, 0x20, 0x57, 0x42, 0x53, 0xae, 0x78, 0x3f, 0x58, 0xfe, 0x7c, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xfd, 0x5f, 0xb5, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x66, 0x4c, 0x86, 0x42, 0x7d, 0xaf, 0x7d, 0x3f, 0x40, +0xb7, 0x49, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x37, 0x1d, 0xb6, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xe9, 0x8f, 0x83, 0x42, 0xa6, +0x48, 0x7e, 0x3f, 0xe0, 0x52, 0x8e, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0xa5, 0x59, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x33, +0xee, 0x55, 0x42, 0x18, 0xcf, 0x78, 0x3f, 0x16, 0xc4, 0x80, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xd2, 0xc3, 0xb6, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0xd1, 0x56, 0x80, 0x42, 0x85, 0xcf, 0x7e, 0x3f, 0x18, 0x2a, 0xbf, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x88, +0x7f, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x64, 0x92, 0x54, 0x42, 0xc4, 0xed, 0x78, 0x3f, 0xda, 0x56, 0x83, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0x46, 0x4d, 0xb7, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xc3, 0x89, 0x79, 0x42, 0xbc, 0x3e, 0x7f, 0x3f, 0x38, +0x44, 0xf5, 0x3d, 0x1, 0xbe, 0x38, 0x0, 0x10, 0xb3, 0xb7, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xb3, 0xfb, 0x71, 0x42, 0x1d, +0x91, 0x7f, 0x3f, 0x8, 0x41, 0x17, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0xc8, 0xa2, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x67, +0xd, 0x53, 0x42, 0x57, 0xa, 0x79, 0x3f, 0xbe, 0x37, 0x86, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x28, 0xf5, 0xb7, 0x43, 0xc, +0x59, 0x8e, 0xc1, 0x71, 0x3, 0x6a, 0x42, 0xa8, 0xc6, 0x7f, 0x3f, 0x9c, 0x72, 0x35, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x97, +0x13, 0xb8, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x5, 0xa1, 0x61, 0x42, 0x4c, 0xdf, 0x7f, 0x3f, 0x50, 0x36, 0x55, 0x3e, 0x1, +0xbe, 0x38, 0x0, 0xea, 0xc0, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x40, 0x6c, 0x51, 0x42, 0xb8, 0x22, 0x79, 0x3f, 0xf8, +0x4d, 0x89, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x5b, 0xe, 0xb8, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0x65, 0xd4, 0x58, 0x42, 0xa, +0xdb, 0x7f, 0x3f, 0x68, 0x8c, 0x76, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x70, 0xd7, 0xaf, 0x43, 0xc, 0x59, 0x8e, 0xc1, 0xed, +0xbb, 0x4f, 0x42, 0xf0, 0x34, 0x79, 0x3f, 0xc8, 0x80, 0x8c, 0x3e, 0x1, 0xbe, 0x38, 0x0, 0x4, 0x2b, 0x92, 0x43, 0x3c, +0xcd, 0xce, 0x42, 0xe5, 0xec, 0x8a, 0xb9, 0x3b, 0xdf, 0x7f, 0x3f, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc9, +0x4d, 0x8e, 0x43, 0x80, 0xe4, 0xf, 0x42, 0xb6, 0xf7, 0x85, 0x42, 0xd4, 0x7d, 0x7c, 0x3f, 0x8c, 0x66, 0xc5, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x4, 0x2b, 0x92, 0x43, 0x70, 0xe4, 0xf, 0x42, 0x6f, 0x98, 0x8a, 0xb9, 0x3b, 0xdf, 0x7f, 0x3f, 0x0, +0x0, 0x0, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc9, 0x4d, 0x8e, 0x43, 0x40, 0xcd, 0xce, 0x42, 0xb5, 0xf7, 0x85, 0x42, 0xd4, +0x7d, 0x7c, 0x3f, 0x8c, 0x66, 0xc5, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x76, 0x4c, 0x83, 0x43, 0x80, 0xe4, 0xf, 0x42, 0x7c, +0x7f, 0x0, 0x43, 0x27, 0xdd, 0x72, 0x3f, 0xf6, 0x95, 0x8f, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x76, 0x4c, 0x83, 0x43, 0x40, +0xcd, 0xce, 0x42, 0x7c, 0x7f, 0x0, 0x43, 0x27, 0xdd, 0x72, 0x3f, 0xf6, 0x95, 0x8f, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x3e, +0x11, 0x64, 0x43, 0x80, 0xe4, 0xf, 0x42, 0xa5, 0xc7, 0x36, 0x43, 0x87, 0xc2, 0x63, 0x3f, 0x98, 0x32, 0x40, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x3d, 0x11, 0x64, 0x43, 0x44, 0xcd, 0xce, 0x42, 0xa3, 0xc7, 0x36, 0x43, 0x87, 0xc2, 0x63, 0x3f, 0x98, +0x32, 0x40, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xc0, 0xc7, 0x36, 0x43, 0x80, 0xe4, 0xf, 0x42, 0x26, 0x11, 0x64, 0x43, 0x6b, +0xf3, 0x4f, 0x3f, 0xc8, 0xeb, 0xe1, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0xc0, 0xc7, 0x36, 0x43, 0x44, 0xcd, 0xce, 0x42, 0x26, +0x11, 0x64, 0x43, 0x6b, 0xf3, 0x4f, 0x3f, 0xc8, 0xeb, 0xe1, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0x9a, 0x7f, 0x0, 0x43, 0x80, +0xe4, 0xf, 0x42, 0x6b, 0x4c, 0x83, 0x43, 0x5, 0x35, 0x38, 0x3f, 0x90, 0x2d, 0x52, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0x9c, +0x7f, 0x0, 0x43, 0x44, 0xcd, 0xce, 0x42, 0x6c, 0x4c, 0x83, 0x43, 0x5, 0x35, 0x38, 0x3f, 0x90, 0x2d, 0x52, 0x3d, 0x1, +0xbe, 0x3d, 0x0, 0xfa, 0xf7, 0x85, 0x42, 0x80, 0xe4, 0xf, 0x42, 0xc3, 0x4d, 0x8e, 0x43, 0xcb, 0x4c, 0x1d, 0x3f, 0x0, +0x8b, 0x60, 0x3c, 0x1, 0xbe, 0x3d, 0x0, 0xfa, 0xf7, 0x85, 0x42, 0x44, 0xcd, 0xce, 0x42, 0xc3, 0x4d, 0x8e, 0x43, 0xcb, +0x4c, 0x1d, 0x3f, 0x0, 0x8b, 0x60, 0x3c, 0x1, 0xbe, 0x3d, 0x0, 0x7a, 0xf5, 0x78, 0x39, 0x80, 0xe4, 0xf, 0x42, 0x1, +0x2b, 0x92, 0x43, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x14, 0x3, 0x3a, 0x1, 0xbe, 0x3d, 0x0, 0xfb, 0x1a, 0x82, 0x39, 0x44, +0xcd, 0xce, 0x42, 0x2, 0x2b, 0x92, 0x43, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x14, 0x3, 0x3a, 0x1, 0xbe, 0x3d, 0x0, 0xbc, +0xf7, 0x85, 0xc2, 0x80, 0xe4, 0xf, 0x42, 0xc7, 0x4d, 0x8e, 0x43, 0x8c, 0x66, 0xc5, 0x3e, 0x0, 0x8b, 0x60, 0x3c, 0x1, +0xbe, 0x3d, 0x0, 0xbd, 0xf7, 0x85, 0xc2, 0x44, 0xcd, 0xce, 0x42, 0xc6, 0x4d, 0x8e, 0x43, 0x8c, 0x66, 0xc5, 0x3e, 0x0, +0x8b, 0x60, 0x3c, 0x1, 0xbe, 0x3d, 0x0, 0x81, 0x7f, 0x0, 0xc3, 0x80, 0xe4, 0xf, 0x42, 0x73, 0x4c, 0x83, 0x43, 0xf6, +0x95, 0x8f, 0x3e, 0x90, 0x2d, 0x52, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0x80, 0x7f, 0x0, 0xc3, 0x44, 0xcd, 0xce, 0x42, 0x73, +0x4c, 0x83, 0x43, 0xf6, 0x95, 0x8f, 0x3e, 0x90, 0x2d, 0x52, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0xa6, 0xc7, 0x36, 0xc3, 0x80, +0xe4, 0xf, 0x42, 0x39, 0x11, 0x64, 0x43, 0x98, 0x32, 0x40, 0x3e, 0xc8, 0xeb, 0xe1, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0xa6, +0xc7, 0x36, 0xc3, 0x40, 0xcd, 0xce, 0x42, 0x39, 0x11, 0x64, 0x43, 0x98, 0x32, 0x40, 0x3e, 0xc8, 0xeb, 0xe1, 0x3d, 0x1, +0xbe, 0x3d, 0x0, 0x2d, 0x11, 0x64, 0xc3, 0x78, 0xe4, 0xf, 0x42, 0xc1, 0xc7, 0x36, 0x43, 0xc8, 0xeb, 0xe1, 0x3d, 0x54, +0x32, 0x40, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x2d, 0x11, 0x64, 0xc3, 0x40, 0xcd, 0xce, 0x42, 0xc0, 0xc7, 0x36, 0x43, 0xc8, +0xeb, 0xe1, 0x3d, 0x54, 0x32, 0x40, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x6d, 0x4c, 0x83, 0xc3, 0x78, 0xe4, 0xf, 0x42, 0x9b, +0x7f, 0x0, 0x43, 0x95, 0x2d, 0x52, 0x3d, 0xf6, 0x95, 0x8f, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x6d, 0x4c, 0x83, 0xc3, 0x40, +0xcd, 0xce, 0x42, 0x9b, 0x7f, 0x0, 0x43, 0x95, 0x2d, 0x52, 0x3d, 0xf6, 0x95, 0x8f, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xc3, +0x4d, 0x8e, 0xc3, 0x78, 0xe4, 0xf, 0x42, 0xfa, 0xf7, 0x85, 0x42, 0xf0, 0x8a, 0x60, 0x3c, 0x6a, 0x66, 0xc5, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xc3, 0x4d, 0x8e, 0xc3, 0x3c, 0xcd, 0xce, 0x42, 0xfa, 0xf7, 0x85, 0x42, 0xf0, 0x8a, 0x60, 0x3c, 0x6a, +0x66, 0xc5, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x3, 0x2b, 0x92, 0xc3, 0x70, 0xe4, 0xf, 0x42, 0x13, 0xe5, 0x89, 0x39, 0x6f, +0x12, 0x3, 0x3a, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x3, 0x2b, 0x92, 0xc3, 0x38, 0xcd, 0xce, 0x42, 0x9e, +0xa1, 0x88, 0x39, 0x6f, 0x12, 0x3, 0x3a, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc7, 0x4d, 0x8e, 0xc3, 0x68, +0xe4, 0xf, 0x42, 0xb8, 0xf7, 0x85, 0xc2, 0xf0, 0x8a, 0x60, 0x3c, 0xba, 0x4c, 0x1d, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc8, +0x4d, 0x8e, 0xc3, 0x38, 0xcd, 0xce, 0x42, 0xba, 0xf7, 0x85, 0xc2, 0xf0, 0x8a, 0x60, 0x3c, 0xba, 0x4c, 0x1d, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x73, 0x4c, 0x83, 0xc3, 0x68, 0xe4, 0xf, 0x42, 0x7d, 0x7f, 0x0, 0xc3, 0x95, 0x2d, 0x52, 0x3d, 0x5, +0x35, 0x38, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x74, 0x4c, 0x83, 0xc3, 0x38, 0xcd, 0xce, 0x42, 0x7e, 0x7f, 0x0, 0xc3, 0x95, +0x2d, 0x52, 0x3d, 0x5, 0x35, 0x38, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x3b, 0x11, 0x64, 0xc3, 0x68, 0xe4, 0xf, 0x42, 0xa2, +0xc7, 0x36, 0xc3, 0xc8, 0xeb, 0xe1, 0x3d, 0x5a, 0xf3, 0x4f, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x3a, 0x11, 0x64, 0xc3, 0x38, +0xcd, 0xce, 0x42, 0xa3, 0xc7, 0x36, 0xc3, 0xc8, 0xeb, 0xe1, 0x3d, 0x5a, 0xf3, 0x4f, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xbe, +0xc7, 0x36, 0xc3, 0x68, 0xe4, 0xf, 0x42, 0x27, 0x11, 0x64, 0xc3, 0x55, 0x32, 0x40, 0x3e, 0x87, 0xc2, 0x63, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xbe, 0xc7, 0x36, 0xc3, 0x38, 0xcd, 0xce, 0x42, 0x28, 0x11, 0x64, 0xc3, 0x55, 0x32, 0x40, 0x3e, 0x87, +0xc2, 0x63, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x98, 0x7f, 0x0, 0xc3, 0x68, 0xe4, 0xf, 0x42, 0x6a, 0x4c, 0x83, 0xc3, 0xf6, +0x95, 0x8f, 0x3e, 0x27, 0xdd, 0x72, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x99, 0x7f, 0x0, 0xc3, 0x38, 0xcd, 0xce, 0x42, 0x6b, +0x4c, 0x83, 0xc3, 0xf6, 0x95, 0x8f, 0x3e, 0x27, 0xdd, 0x72, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xf2, 0xf7, 0x85, 0xc2, 0x68, +0xe4, 0xf, 0x42, 0xc1, 0x4d, 0x8e, 0xc3, 0x8c, 0x66, 0xc5, 0x3e, 0xd4, 0x7d, 0x7c, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xf3, +0xf7, 0x85, 0xc2, 0x38, 0xcd, 0xce, 0x42, 0xc2, 0x4d, 0x8e, 0xc3, 0x8c, 0x66, 0xc5, 0x3e, 0xd4, 0x7d, 0x7c, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x30, 0x4a, 0x5a, 0xb9, 0x68, 0xe4, 0xf, 0x42, 0x1, 0x2b, 0x92, 0xc3, 0x0, 0x0, 0x0, 0x3f, 0x3b, +0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x76, 0x81, 0x5a, 0xb9, 0x38, 0xcd, 0xce, 0x42, 0x1, 0x2b, 0x92, 0xc3, 0x0, +0x0, 0x0, 0x3f, 0x3b, 0xdf, 0x7f, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xbf, 0xf7, 0x85, 0x42, 0x68, 0xe4, 0xf, 0x42, 0xc5, +0x4d, 0x8e, 0xc3, 0xba, 0x4c, 0x1d, 0x3f, 0xd4, 0x7d, 0x7c, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xbf, 0xf7, 0x85, 0x42, 0x38, +0xcd, 0xce, 0x42, 0xc5, 0x4d, 0x8e, 0xc3, 0xba, 0x4c, 0x1d, 0x3f, 0xd4, 0x7d, 0x7c, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x81, +0x7f, 0x0, 0x43, 0x68, 0xe4, 0xf, 0x42, 0x73, 0x4c, 0x83, 0xc3, 0x5, 0x35, 0x38, 0x3f, 0x27, 0xdd, 0x72, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x81, 0x7f, 0x0, 0x43, 0x38, 0xcd, 0xce, 0x42, 0x73, 0x4c, 0x83, 0xc3, 0x5, 0x35, 0x38, 0x3f, 0x27, +0xdd, 0x72, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xa9, 0xc7, 0x36, 0x43, 0x68, 0xe4, 0xf, 0x42, 0x3a, 0x11, 0x64, 0xc3, 0x5a, +0xf3, 0x4f, 0x3f, 0x87, 0xc2, 0x63, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xa8, 0xc7, 0x36, 0x43, 0x38, 0xcd, 0xce, 0x42, 0x3b, +0x11, 0x64, 0xc3, 0x5a, 0xf3, 0x4f, 0x3f, 0x87, 0xc2, 0x63, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x2b, 0x11, 0x64, 0x43, 0x70, +0xe4, 0xf, 0x42, 0xbf, 0xc7, 0x36, 0xc3, 0x87, 0xc2, 0x63, 0x3f, 0x6b, 0xf3, 0x4f, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x2a, +0x11, 0x64, 0x43, 0x38, 0xcd, 0xce, 0x42, 0xc0, 0xc7, 0x36, 0xc3, 0x87, 0xc2, 0x63, 0x3f, 0x6b, 0xf3, 0x4f, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x6d, 0x4c, 0x83, 0x43, 0x70, 0xe4, 0xf, 0x42, 0x9a, 0x7f, 0x0, 0xc3, 0x27, 0xdd, 0x72, 0x3f, 0x5, +0x35, 0x38, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x6d, 0x4c, 0x83, 0x43, 0x3c, 0xcd, 0xce, 0x42, 0x9b, 0x7f, 0x0, 0xc3, 0x27, +0xdd, 0x72, 0x3f, 0x5, 0x35, 0x38, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc5, 0x4d, 0x8e, 0x43, 0x70, 0xe4, 0xf, 0x42, 0xfa, +0xf7, 0x85, 0xc2, 0xd4, 0x7d, 0x7c, 0x3f, 0xca, 0x4c, 0x1d, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc5, 0x4d, 0x8e, 0x43, 0x3c, +0xcd, 0xce, 0x42, 0xfb, 0xf7, 0x85, 0xc2, 0xd4, 0x7d, 0x7c, 0x3f, 0xca, 0x4c, 0x1d, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x98, +0x80, 0x10, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0xa1, 0xe8, 0xfd, 0x41, 0x4c, 0x19, 0xf8, 0x3e, 0xf8, 0x3b, 0xe4, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x64, 0x77, 0xab, 0xc2, 0xb8, 0x76, 0x24, 0x42, 0xb6, 0x9a, 0x48, 0x43, 0x86, 0xff, 0xb4, 0x3e, 0xbc, +0x2, 0x21, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x79, 0x1c, 0x83, 0xc0, 0xb0, 0x76, 0x24, 0x42, 0x9c, 0xe9, 0xde, 0x41, 0x5d, +0x6a, 0xfc, 0x3e, 0xaa, 0x9f, 0xe7, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x64, 0x77, 0xab, 0xc2, 0x24, 0x84, 0xc4, 0x42, 0xb3, +0x9a, 0x48, 0x43, 0x86, 0xff, 0xb4, 0x3e, 0xbc, 0x2, 0x21, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x89, 0xe9, 0xa8, 0xc2, 0xb8, +0x76, 0x24, 0x42, 0x5a, 0x18, 0x4c, 0x43, 0x86, 0x1d, 0xb6, 0x3e, 0x50, 0xe7, 0x1a, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x88, +0xe9, 0xa8, 0xc2, 0x24, 0x84, 0xc4, 0x42, 0x5a, 0x18, 0x4c, 0x43, 0x86, 0x1d, 0xb6, 0x3e, 0x50, 0xe7, 0x1a, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x1f, 0xe4, 0xa4, 0xc2, 0xb8, 0x76, 0x24, 0x42, 0x4f, 0x6b, 0x4f, 0x43, 0xc2, 0xdf, 0xb7, 0x3e, 0x54, +0x16, 0x15, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x1f, 0xe4, 0xa4, 0xc2, 0x24, 0x84, 0xc4, 0x42, 0x4f, 0x6b, 0x4f, 0x43, 0xc2, +0xdf, 0xb7, 0x3e, 0x54, 0x16, 0x15, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x12, 0xd0, 0x9f, 0xc2, 0x24, 0x84, 0xc4, 0x42, 0x58, +0x52, 0x52, 0x43, 0x7a, 0x18, 0xba, 0x3e, 0x5c, 0x2, 0x10, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x12, 0xd0, 0x9f, 0xc2, 0xb8, +0x76, 0x24, 0x42, 0x58, 0x52, 0x52, 0x43, 0x7a, 0x18, 0xba, 0x3e, 0x5c, 0x2, 0x10, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x63, +0x92, 0x42, 0xc2, 0x24, 0x84, 0xc4, 0x42, 0xb3, 0x76, 0x5c, 0x43, 0x15, 0x72, 0xd5, 0x3e, 0xd0, 0x86, 0xfc, 0x3d, 0x1, +0xbe, 0x3d, 0x0, 0x98, 0xca, 0x97, 0xc1, 0xb8, 0x76, 0x24, 0x42, 0x14, 0x69, 0x60, 0x43, 0xa5, 0x66, 0xef, 0x3e, 0x88, +0xb7, 0xee, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0xc9, 0xab, 0x6, 0x41, 0x28, 0x84, 0xc4, 0x42, 0xe1, 0x82, 0x60, 0x43, 0x79, +0xae, 0x3, 0x3f, 0xd8, 0x5c, 0xee, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0x82, 0x62, 0x38, 0x42, 0xb8, 0x76, 0x24, 0x42, 0x3d, +0xf, 0x5b, 0x43, 0xbf, 0x29, 0x14, 0x3f, 0x48, 0xb8, 0x0, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x82, 0x62, 0x38, 0x42, 0x28, +0x84, 0xc4, 0x42, 0x3d, 0xf, 0x5b, 0x43, 0xbf, 0x29, 0x14, 0x3f, 0x48, 0xb8, 0x0, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xa3, +0xe4, 0x88, 0x42, 0xb8, 0x76, 0x24, 0x42, 0xf9, 0x92, 0x54, 0x43, 0x80, 0xf0, 0x1d, 0x3f, 0x5c, 0x11, 0xc, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xa3, 0xe4, 0x88, 0x42, 0x28, 0x84, 0xc4, 0x42, 0xf9, 0x92, 0x54, 0x43, 0x80, 0xf0, 0x1d, 0x3f, 0x5c, +0x11, 0xc, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x43, 0x69, 0x91, 0x42, 0x28, 0x84, 0xc4, 0x42, 0xf1, 0xc7, 0x51, 0x43, 0x68, +0xcd, 0x1f, 0x3f, 0x50, 0xf4, 0x10, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xcc, 0x10, 0xa4, 0x42, 0xb8, 0x76, 0x24, 0x42, 0x9d, +0x52, 0x46, 0x43, 0xda, 0xe1, 0x23, 0x3f, 0x94, 0x0, 0x25, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xe1, 0x12, 0xa5, 0x42, 0x28, +0x84, 0xc4, 0x42, 0x9e, 0x5c, 0x3f, 0x43, 0x58, 0x1a, 0x24, 0x3f, 0x84, 0x2e, 0x31, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xcb, +0x73, 0xdc, 0x40, 0xb0, 0x76, 0x24, 0x42, 0x10, 0x42, 0xdd, 0x41, 0x6d, 0x3, 0x3, 0x3f, 0xee, 0xcd, 0xe7, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xc5, 0x73, 0xdc, 0x40, 0x20, 0x84, 0xc4, 0x42, 0xc, 0x42, 0xdd, 0x41, 0x6d, 0x3, 0x3, 0x3f, 0xee, +0xcd, 0xe7, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x2e, 0x47, 0x51, 0x40, 0x20, 0x84, 0xc4, 0x42, 0x87, 0x43, 0xd7, 0x41, 0x26, +0x6e, 0x1, 0x3f, 0xd6, 0x75, 0xe8, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x3a, 0x47, 0x51, 0x40, 0xb0, 0x76, 0x24, 0x42, 0x8b, +0x43, 0xd7, 0x41, 0x26, 0x6e, 0x1, 0x3f, 0xd6, 0x75, 0xe8, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x13, 0xbb, 0x5, 0xbf, 0xb0, +0x76, 0x24, 0x42, 0x5, 0xf5, 0xd7, 0x41, 0xf4, 0x8a, 0xff, 0x3e, 0x70, 0x62, 0xe8, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x16, +0xbb, 0x5, 0xbf, 0x20, 0x84, 0xc4, 0x42, 0x5, 0xf5, 0xd7, 0x41, 0xf4, 0x8a, 0xff, 0x3e, 0x70, 0x62, 0xe8, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xdb, 0x40, 0xd7, 0x41, 0x20, 0x84, 0xc4, 0x42, 0xf6, 0x70, 0x91, 0x41, 0xf4, 0xc4, 0xb, 0x3f, 0x62, +0x18, 0xf0, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xe4, 0xf7, 0x25, 0x43, 0xb8, 0x76, 0x24, 0x42, 0xe8, 0xe6, 0xc, 0x43, 0xd4, +0x98, 0x48, 0x3f, 0x6, 0xbc, 0x84, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x4, 0x27, 0xc5, 0x41, 0xb0, 0x76, 0x24, 0x42, 0xbd, +0x42, 0x45, 0x41, 0x97, 0xc7, 0xa, 0x3f, 0xd6, 0x36, 0xf5, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xe4, 0xf7, 0x25, 0x43, 0x24, +0x84, 0xc4, 0x42, 0xe8, 0xe6, 0xc, 0x43, 0xd4, 0x98, 0x48, 0x3f, 0x6, 0xbc, 0x84, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x13, +0xae, 0x29, 0x43, 0xb8, 0x76, 0x24, 0x42, 0x8a, 0xb3, 0xc, 0x43, 0x76, 0x38, 0x4a, 0x3f, 0xfc, 0xe8, 0x84, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x13, 0xae, 0x29, 0x43, 0x24, 0x84, 0xc4, 0x42, 0x8a, 0xb3, 0xc, 0x43, 0x76, 0x38, 0x4a, 0x3f, 0xfc, +0xe8, 0x84, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x55, 0x72, 0x2d, 0x43, 0x24, 0x84, 0xc4, 0x42, 0x1c, 0xc0, 0xb, 0x43, 0x40, +0xde, 0x4b, 0x3f, 0xf8, 0xbd, 0x85, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x55, 0x72, 0x2d, 0x43, 0xb8, 0x76, 0x24, 0x42, 0x1e, +0xc0, 0xb, 0x43, 0x40, 0xde, 0x4b, 0x3f, 0xf8, 0xbd, 0x85, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xf6, 0xf6, 0x30, 0x43, 0xb8, +0x76, 0x24, 0x42, 0xbe, 0x2b, 0xa, 0x43, 0x30, 0x68, 0x4d, 0x3f, 0xbc, 0x1f, 0x87, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xd7, +0xcd, 0x43, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x39, 0x7a, 0xde, 0x42, 0xca, 0xa5, 0x55, 0x3f, 0x68, 0xaf, 0x9e, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xb7, 0x40, 0x50, 0x43, 0xb8, 0x76, 0x24, 0x42, 0x42, 0xa, 0xa8, 0x42, 0xbe, 0x17, 0x5b, 0x3f, 0x2c, +0x7f, 0xb6, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x86, 0x5b, 0x58, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x1, 0x6c, 0x67, 0x42, 0x59, +0xa3, 0x5e, 0x3f, 0xe0, 0x62, 0xcd, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xb, 0x29, 0x5e, 0x43, 0xb0, 0x76, 0x24, 0x42, 0x66, +0xd4, 0xa1, 0x41, 0x23, 0x2d, 0x61, 0x3f, 0xa0, 0x4d, 0xee, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xb, 0x29, 0x5e, 0x43, 0x20, +0x84, 0xc4, 0x42, 0x5e, 0xd4, 0xa1, 0x41, 0x23, 0x2d, 0x61, 0x3f, 0xa0, 0x4d, 0xee, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x31, +0x7e, 0x5e, 0x43, 0xb0, 0x76, 0x24, 0x42, 0xd9, 0xa2, 0x42, 0xc0, 0x5d, 0x52, 0x61, 0x3f, 0x86, 0x54, 0x1, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x30, 0x11, 0x5d, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xda, 0xc8, 0xfd, 0xc0, 0xb7, 0xb2, 0x60, 0x3f, 0x14, +0x78, 0x3, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x25, 0xd6, 0x54, 0x43, 0xb0, 0x76, 0x24, 0x42, 0xa4, 0x9a, 0xa1, 0xc1, 0x5, +0x19, 0x5d, 0x3f, 0xfa, 0xd5, 0x8, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xbe, 0x53, 0x4e, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xea, +0xbd, 0xb5, 0xc1, 0x21, 0x40, 0x5a, 0x3f, 0xd8, 0xef, 0x9, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x5f, 0x44, 0xdd, 0x41, 0xb0, +0x76, 0x24, 0x42, 0xf8, 0x89, 0xe1, 0x3f, 0x2a, 0x19, 0xc, 0x3f, 0x58, 0x75, 0xfe, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x5d, +0x44, 0xdd, 0x41, 0x20, 0x84, 0xc4, 0x42, 0xb7, 0x89, 0xe1, 0x3f, 0x2a, 0x19, 0xc, 0x3f, 0x58, 0x75, 0xfe, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xcd, 0x11, 0xcf, 0x41, 0xb0, 0x76, 0x24, 0x42, 0x9c, 0x20, 0xa0, 0x40, 0x65, 0x52, 0xb, 0x3f, 0x56, +0x9f, 0xfb, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xcb, 0x11, 0xcf, 0x41, 0x20, 0x84, 0xc4, 0x42, 0x8c, 0x20, 0xa0, 0x40, 0x65, +0x52, 0xb, 0x3f, 0x56, 0x9f, 0xfb, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xbe, 0xdc, 0xc6, 0x41, 0xb0, 0x76, 0x24, 0x42, 0xda, +0x7e, 0xa, 0x41, 0x83, 0xdf, 0xa, 0x3f, 0x72, 0x6d, 0xf8, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xbc, 0xdc, 0xc6, 0x41, 0x20, +0x84, 0xc4, 0x42, 0xd2, 0x7e, 0xa, 0x41, 0x83, 0xdf, 0xa, 0x3f, 0x72, 0x6d, 0xf8, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x28, +0x47, 0xc9, 0x41, 0x20, 0x84, 0xc4, 0x42, 0x3e, 0x39, 0x9a, 0xc1, 0x54, 0x1, 0xb, 0x3f, 0xb0, 0x6e, 0x8, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x35, 0x78, 0x3a, 0x43, 0xa8, 0x76, 0x24, 0x42, 0x38, 0x9e, 0xdd, 0xc2, 0x8e, 0x90, 0x51, 0x3f, 0x32, +0x78, 0x30, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc8, 0x1f, 0x97, 0x41, 0xa8, 0x76, 0x24, 0x42, 0x4e, 0x59, 0x98, 0xc1, 0x4e, +0x43, 0x8, 0x3f, 0x7a, 0x54, 0x8, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x35, 0x78, 0x3a, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x39, +0x9e, 0xdd, 0xc2, 0x8e, 0x90, 0x51, 0x3f, 0x32, 0x78, 0x30, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xff, 0x7c, 0x3b, 0x43, 0xa8, +0x76, 0x24, 0x42, 0x7e, 0xc4, 0xe4, 0xc2, 0x97, 0x2, 0x52, 0x3f, 0x7c, 0x8, 0x32, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xff, +0x7c, 0x3b, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x7f, 0xc4, 0xe4, 0xc2, 0x97, 0x2, 0x52, 0x3f, 0x7c, 0x8, 0x32, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xc3, 0xd0, 0x3b, 0x43, 0xa8, 0x76, 0x24, 0x42, 0x72, 0x82, 0xec, 0xc2, 0x39, 0x27, 0x52, 0x3f, 0xf1, +0xb9, 0x33, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc2, 0xd0, 0x3b, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x74, 0x82, 0xec, 0xc2, 0x39, +0x27, 0x52, 0x3f, 0xf1, 0xb9, 0x33, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xa3, 0x77, 0x3b, 0x43, 0xa8, 0x76, 0x24, 0x42, 0xdf, +0x30, 0xf4, 0xc2, 0x3b, 0x0, 0x52, 0x3f, 0xfd, 0x67, 0x35, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xd1, 0x22, 0x28, 0x43, 0x1c, +0x84, 0xc4, 0x42, 0x3d, 0xad, 0x14, 0xc3, 0x93, 0x8b, 0x49, 0x3f, 0x92, 0x8, 0x41, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xff, +0x73, 0x12, 0x43, 0xa8, 0x76, 0x24, 0x42, 0x7, 0x4f, 0x29, 0xc3, 0x99, 0xf, 0x40, 0x3f, 0xe9, 0xe, 0x4a, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x90, 0xb4, 0xf8, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0x7f, 0x7d, 0x39, 0xc3, 0xd4, 0x64, 0x36, 0x3f, 0xd9, +0x22, 0x51, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x84, 0x54, 0xb5, 0x42, 0xa0, 0x76, 0x24, 0x42, 0x19, 0x3a, 0x4b, 0xc3, 0x82, +0xa8, 0x27, 0x3f, 0xfc, 0xe4, 0x58, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x84, 0x54, 0xb5, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0x1b, +0x3a, 0x4b, 0xc3, 0x82, 0xa8, 0x27, 0x3f, 0xfc, 0xe4, 0x58, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xe0, 0x8a, 0x89, 0x42, 0xa0, +0x76, 0x24, 0x42, 0x9, 0x1e, 0x53, 0xc3, 0xe0, 0x14, 0x1e, 0x3f, 0x8a, 0x58, 0x5c, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x44, +0xbc, 0x7e, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0x71, 0x5c, 0x53, 0xc3, 0x3c, 0xdb, 0x1b, 0x3f, 0xcd, 0x73, 0x5c, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x9f, 0x9c, 0x45, 0x42, 0xa0, 0x76, 0x24, 0x42, 0xd3, 0x92, 0x4f, 0xc3, 0x17, 0x9c, 0x15, 0x3f, 0xb8, +0xcb, 0x5a, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x51, 0x9d, 0x33, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0x4, 0x3d, 0x4a, 0xc3, 0x40, +0xa4, 0x13, 0x3f, 0x4b, 0x76, 0x58, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xd0, 0x17, 0x1e, 0x41, 0xa8, 0x76, 0x24, 0x42, 0xe0, +0xab, 0xca, 0xc1, 0x72, 0x52, 0x4, 0x3f, 0xdc, 0x14, 0xb, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xd8, 0x17, 0x1e, 0x41, 0x20, +0x84, 0xc4, 0x42, 0xe1, 0xab, 0xca, 0xc1, 0x72, 0x52, 0x4, 0x3f, 0xdc, 0x14, 0xb, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xcc, +0xe4, 0x45, 0x41, 0xb0, 0x76, 0x24, 0x42, 0xb4, 0xcd, 0xb4, 0xc1, 0xf9, 0x68, 0x5, 0x3f, 0xbd, 0xe2, 0x9, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xc9, 0xe4, 0x45, 0x41, 0x20, 0x84, 0xc4, 0x42, 0xb8, 0xcd, 0xb4, 0xc1, 0xf9, 0x68, 0x5, 0x3f, 0xbd, +0xe2, 0x9, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x51, 0xcc, 0x77, 0x41, 0xb0, 0x76, 0x24, 0x42, 0x1a, 0x88, 0xa3, 0xc1, 0x47, +0xc6, 0x6, 0x3f, 0xfa, 0xf0, 0x8, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x4e, 0xcc, 0x77, 0x41, 0x20, 0x84, 0xc4, 0x42, 0x1e, +0x88, 0xa3, 0xc1, 0x47, 0xc6, 0x6, 0x3f, 0xfa, 0xf0, 0x8, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x1c, 0xb6, 0x35, 0xc1, 0x20, +0x84, 0xc4, 0x42, 0xba, 0xd, 0xed, 0xc1, 0x8c, 0x10, 0xf6, 0x3e, 0x16, 0xf6, 0xc, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x23, +0x3e, 0x42, 0xc2, 0xa0, 0x76, 0x24, 0x42, 0xc1, 0x54, 0x53, 0xc3, 0x90, 0x84, 0xd5, 0x3e, 0x76, 0x70, 0x5c, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x69, 0x24, 0x51, 0xc1, 0xa8, 0x76, 0x24, 0x42, 0x79, 0xc6, 0xbc, 0xc1, 0xa3, 0x90, 0xf4, 0x3e, 0x58, +0x52, 0xa, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x25, 0x3e, 0x42, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0xc2, 0x54, 0x53, 0xc3, 0x90, +0x84, 0xd5, 0x3e, 0x76, 0x70, 0x5c, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x2e, 0x95, 0x4e, 0xc2, 0xa0, 0x76, 0x24, 0x42, 0x94, +0x67, 0x55, 0xc3, 0xaf, 0xd1, 0xd2, 0x3e, 0xa8, 0x58, 0x5d, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x2e, 0x95, 0x4e, 0xc2, 0x1c, +0x84, 0xc4, 0x42, 0x94, 0x67, 0x55, 0xc3, 0xaf, 0xd1, 0xd2, 0x3e, 0xa8, 0x58, 0x5d, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x89, +0xe7, 0x5c, 0xc2, 0xa0, 0x76, 0x24, 0x42, 0x78, 0xe9, 0x56, 0xc3, 0xc9, 0xaf, 0xcf, 0x3e, 0x7a, 0x1, 0x5e, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x88, 0xe7, 0x5c, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0x7a, 0xe9, 0x56, 0xc3, 0xc9, 0xaf, 0xcf, 0x3e, 0x7a, +0x1, 0x5e, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xd, 0xf2, 0x6b, 0xc2, 0xa0, 0x76, 0x24, 0x42, 0x88, 0xc4, 0x57, 0xc3, 0xa5, +0x65, 0xcc, 0x3e, 0x4a, 0x61, 0x5e, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x10, 0x7b, 0xb4, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0xb9, +0x98, 0x4d, 0xc3, 0x24, 0xe, 0xb1, 0x3e, 0x56, 0xee, 0x59, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x3c, 0x20, 0xe9, 0xc2, 0xa0, +0x76, 0x24, 0x42, 0xbf, 0x59, 0x3f, 0xc3, 0xc, 0x7, 0x9a, 0x3e, 0x20, 0xb3, 0x53, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x29, +0xc8, 0xa, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x9, 0x55, 0x2f, 0xc3, 0xe6, 0x96, 0x86, 0x3e, 0x68, 0xb1, 0x4c, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x84, 0xf, 0x26, 0xc3, 0xa0, 0x76, 0x24, 0x42, 0x39, 0xc6, 0x14, 0xc3, 0x43, 0x73, 0x5d, 0x3e, 0x84, +0x13, 0x41, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x84, 0xf, 0x26, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x3a, 0xc6, 0x14, 0xc3, 0x43, +0x73, 0x5d, 0x3e, 0x84, 0x13, 0x41, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x95, 0x54, 0x34, 0xc3, 0xa0, 0x76, 0x24, 0x42, 0xeb, +0x63, 0x2, 0xc3, 0xab, 0x7b, 0x44, 0x3e, 0xe6, 0x8, 0x39, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x63, 0x22, 0x36, 0xc3, 0x1c, +0x84, 0xc4, 0x42, 0x2c, 0x41, 0xfb, 0xc2, 0xbd, 0x53, 0x41, 0x3e, 0x90, 0xf3, 0x36, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xf6, +0xf1, 0x36, 0xc3, 0xa0, 0x76, 0x24, 0x42, 0xf0, 0xbf, 0xdd, 0xc2, 0xab, 0xe8, 0x3f, 0x3e, 0x99, 0x7f, 0x30, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xed, 0x42, 0x33, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0xef, 0xe4, 0xd1, 0xc2, 0x9b, 0x5a, 0x46, 0x3e, 0xc9, +0xe7, 0x2d, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x30, 0xb4, 0xae, 0xc1, 0xa8, 0x76, 0x24, 0x42, 0x9a, 0xc6, 0x87, 0xc1, 0x4f, +0xe5, 0xec, 0x3e, 0x7a, 0x6c, 0x7, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x30, 0xb4, 0xae, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0x9f, +0xc6, 0x87, 0xc1, 0x4f, 0xe5, 0xec, 0x3e, 0x7a, 0x6c, 0x7, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xbd, 0xc1, 0x93, 0xc1, 0xa8, +0x76, 0x24, 0x42, 0xd4, 0xf1, 0x93, 0xc1, 0xa1, 0xd7, 0xef, 0x3e, 0xce, 0x16, 0x8, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xbe, +0xc1, 0x93, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0xd8, 0xf1, 0x93, 0xc1, 0xa1, 0xd7, 0xef, 0x3e, 0xce, 0x16, 0x8, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x3f, 0x3d, 0x77, 0xc1, 0xb0, 0x76, 0x24, 0x42, 0x99, 0x56, 0xa6, 0xc1, 0x4e, 0x7b, 0xf2, 0x3e, 0x4c, +0x18, 0x9, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x3b, 0x3d, 0x77, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0x9e, 0x56, 0xa6, 0xc1, 0x4e, +0x7b, 0xf2, 0x3e, 0x4c, 0x18, 0x9, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x13, 0xd9, 0x1, 0xc2, 0x20, 0x84, 0xc4, 0x42, 0x87, +0x83, 0x1d, 0x40, 0xf6, 0x99, 0xe3, 0x3e, 0xd8, 0xd8, 0xfd, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x6e, 0x19, 0x59, 0xc3, 0xa8, +0x76, 0x24, 0x42, 0xf7, 0x59, 0x71, 0xc1, 0x78, 0x26, 0x4, 0x3e, 0x20, 0x99, 0x6, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x7a, +0x89, 0xd9, 0xc1, 0xb0, 0x76, 0x24, 0x42, 0xce, 0xae, 0xbb, 0x40, 0x22, 0x36, 0xe8, 0x3e, 0x88, 0xde, 0xfa, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x6e, 0x19, 0x59, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x1, 0x5a, 0x71, 0xc1, 0x78, 0x26, 0x4, 0x3e, 0x20, +0x99, 0x6, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xf1, 0xfb, 0x5b, 0xc3, 0xb0, 0x76, 0x24, 0x42, 0x10, 0xd9, 0x4b, 0xc1, 0xb9, +0x34, 0xfe, 0x3d, 0xa7, 0x92, 0x5, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xf1, 0xfb, 0x5b, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x11, +0xd9, 0x4b, 0xc1, 0xb9, 0x34, 0xfe, 0x3d, 0xa7, 0x92, 0x5, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xf9, 0x78, 0x5e, 0xc3, 0xb0, +0x76, 0x24, 0x42, 0xa8, 0x1d, 0x1c, 0xc1, 0x73, 0x7f, 0xf5, 0x3d, 0x9e, 0x44, 0x4, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xfa, +0x78, 0x5e, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0xb1, 0x1d, 0x1c, 0xc1, 0x73, 0x7f, 0xf5, 0x3d, 0x9e, 0x44, 0x4, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xe8, 0x63, 0x60, 0xc3, 0xb0, 0x76, 0x24, 0x42, 0x93, 0x2a, 0xcd, 0xc0, 0x5c, 0xc9, 0xee, 0x3d, 0xf2, +0xcd, 0x2, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x26, 0xcd, 0x5f, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0xdc, 0x9a, 0xd3, 0x41, 0xcb, +0xd8, 0xf0, 0x3d, 0x34, 0xdc, 0xe8, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xb1, 0xdf, 0x59, 0xc3, 0xb0, 0x76, 0x24, 0x42, 0x10, +0x27, 0x5f, 0x42, 0xa7, 0xcb, 0x2, 0x3e, 0xf4, 0x31, 0xcf, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x2f, 0xd, 0x51, 0xc3, 0x20, +0x84, 0xc4, 0x42, 0x67, 0x70, 0xa3, 0x42, 0x36, 0x3b, 0x12, 0x3e, 0x6a, 0x82, 0xb8, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x2f, +0xa1, 0x3f, 0xc3, 0xb0, 0x76, 0x24, 0x42, 0x66, 0x24, 0xe7, 0x42, 0xb7, 0xb6, 0x30, 0x3e, 0x14, 0xe5, 0x9a, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x30, 0xa1, 0x3f, 0xc3, 0x24, 0x84, 0xc4, 0x42, 0x62, 0x24, 0xe7, 0x42, 0xb7, 0xb6, 0x30, 0x3e, 0x36, +0xe5, 0x9a, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x93, 0x38, 0x32, 0xc3, 0xb0, 0x76, 0x24, 0x42, 0xa0, 0x97, 0x6, 0x43, 0x6f, +0x2c, 0x48, 0x3e, 0x3e, 0x41, 0x8a, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x86, 0x31, 0x2e, 0xc3, 0x24, 0x84, 0xc4, 0x42, 0xc1, +0xb5, 0x9, 0x43, 0x82, 0x38, 0x4f, 0x3e, 0x6, 0x87, 0x87, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xa1, 0x52, 0x20, 0xc3, 0xb0, +0x76, 0x24, 0x42, 0x6f, 0xcc, 0xe, 0x43, 0x52, 0x7d, 0x67, 0x3e, 0x5a, 0x13, 0x83, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xb6, +0x93, 0x19, 0xc3, 0x24, 0x84, 0xc4, 0x42, 0x48, 0x2, 0xd, 0x43, 0xcb, 0x4a, 0x73, 0x3e, 0x2a, 0xa4, 0x84, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xb5, 0x5b, 0xbb, 0xc1, 0xb0, 0x76, 0x24, 0x42, 0xa, 0x7c, 0x81, 0x41, 0x6, 0x83, 0xeb, 0x3e, 0x34, +0xd7, 0xf1, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xb6, 0x5b, 0xbb, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0x6, 0x7c, 0x81, 0x41, 0x6, +0x83, 0xeb, 0x3e, 0x34, 0xd7, 0xf1, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xe6, 0x1d, 0xbf, 0xc1, 0xb0, 0x76, 0x24, 0x42, 0x6a, +0x50, 0x48, 0x41, 0xc6, 0x19, 0xeb, 0x3e, 0x1c, 0xc, 0xf5, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xe6, 0x1d, 0xbf, 0xc1, 0x20, +0x84, 0xc4, 0x42, 0x60, 0x50, 0x48, 0x41, 0xc6, 0x19, 0xeb, 0x3e, 0x1c, 0xc, 0xf5, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x56, +0xa6, 0xc9, 0xc1, 0xb0, 0x76, 0x24, 0x42, 0xc4, 0x64, 0xf, 0x41, 0xdc, 0xf2, 0xe9, 0x3e, 0xe4, 0x28, 0xf8, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x54, 0xa6, 0xc9, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0xb9, 0x64, 0xf, 0x41, 0xdc, 0xf2, 0xe9, 0x3e, 0xe4, +0x28, 0xf8, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x78, 0x88, 0xaa, 0xc2, 0x24, 0x84, 0xc4, 0x42, 0xb, 0x24, 0x42, 0x43, 0xfd, +0x67, 0xb5, 0x3e, 0xdc, 0x51, 0x2c, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xae, 0x24, 0xac, 0xc2, 0x24, 0x84, 0xc4, 0x42, 0x8b, +0x33, 0x45, 0x43, 0xa2, 0xb3, 0xb4, 0x3e, 0x1c, 0xf7, 0x26, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x5f, 0x16, 0x9a, 0xc2, 0x24, +0x84, 0xc4, 0x42, 0x4e, 0x8c, 0x54, 0x43, 0x8d, 0x99, 0xbc, 0x3e, 0xe8, 0x1c, 0xc, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xfb, +0x1f, 0x94, 0xc2, 0x24, 0x84, 0xc4, 0x42, 0xf6, 0xd7, 0x55, 0x43, 0x3b, 0x35, 0xbf, 0x3e, 0xc8, 0xd8, 0x9, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xec, 0x22, 0x20, 0xc2, 0x24, 0x84, 0xc4, 0x42, 0xe0, 0x2f, 0x5e, 0x43, 0x5, 0xfa, 0xdc, 0x3e, 0x50, +0x7f, 0xf6, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0xd4, 0xc5, 0xf2, 0xc1, 0x24, 0x84, 0xc4, 0x42, 0xc0, 0x87, 0x5f, 0x43, 0xa8, +0x73, 0xe5, 0x3e, 0x10, 0xcc, 0xf1, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0x98, 0xca, 0x97, 0xc1, 0x24, 0x84, 0xc4, 0x42, 0x14, +0x69, 0x60, 0x43, 0xa5, 0x66, 0xef, 0x3e, 0x88, 0xb7, 0xee, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0x8f, 0xe8, 0xa9, 0xc0, 0x28, +0x84, 0xc4, 0x42, 0x9c, 0xbe, 0x60, 0x43, 0xc9, 0x5a, 0xfb, 0x3e, 0x28, 0x8c, 0xed, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0x29, +0xf2, 0x9d, 0x41, 0x28, 0x84, 0xc4, 0x42, 0xda, 0xc6, 0x5f, 0x43, 0xcb, 0xa2, 0x8, 0x3f, 0xd0, 0xee, 0xf0, 0x3d, 0x1, +0xbe, 0x3d, 0x0, 0x51, 0xc6, 0xea, 0x41, 0x28, 0x84, 0xc4, 0x42, 0x23, 0x97, 0x5e, 0x43, 0x2c, 0xd6, 0xc, 0x3f, 0x10, +0x16, 0xf5, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0x6, 0x9f, 0x17, 0x42, 0x28, 0x84, 0xc4, 0x42, 0x65, 0x0, 0x5d, 0x43, 0x92, +0x94, 0x10, 0x3f, 0x0, 0xa5, 0xfa, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0xde, 0x2b, 0x80, 0x42, 0x28, 0x84, 0xc4, 0x42, 0x3a, +0x50, 0x56, 0x43, 0x31, 0x8, 0x1c, 0x3f, 0x48, 0x6, 0x9, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x68, 0x28, 0x99, 0x42, 0x28, +0x84, 0xc4, 0x42, 0x2d, 0x42, 0x4e, 0x43, 0x30, 0x7f, 0x21, 0x3f, 0x28, 0x1e, 0x17, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xb7, +0x90, 0x9f, 0x42, 0x28, 0x84, 0xc4, 0x42, 0xba, 0x54, 0x4a, 0x43, 0xef, 0xe5, 0x22, 0x3f, 0x68, 0xfd, 0x1d, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xcd, 0x10, 0xa4, 0x42, 0x28, 0x84, 0xc4, 0x42, 0x9d, 0x52, 0x46, 0x43, 0xda, 0xe1, 0x23, 0x3f, 0x94, +0x0, 0x25, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x4f, 0x17, 0xa6, 0x42, 0x28, 0x84, 0xc4, 0x42, 0xe6, 0x8e, 0x42, 0x43, 0x4c, +0x53, 0x24, 0x3f, 0xf4, 0x96, 0x2b, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x15, 0xb8, 0x40, 0x41, 0x20, 0x84, 0xc4, 0x42, 0xac, +0x2, 0xff, 0x41, 0xcc, 0x44, 0x5, 0x3f, 0x8, 0x1d, 0xe4, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x1c, 0x1c, 0x1f, 0x41, 0x20, +0x84, 0xc4, 0x42, 0x7c, 0x5d, 0xea, 0x41, 0x86, 0x59, 0x4, 0x3f, 0x10, 0x5f, 0xe6, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x7f, +0x1c, 0x83, 0xc0, 0x20, 0x84, 0xc4, 0x42, 0x98, 0xe9, 0xde, 0x41, 0x5d, 0x6a, 0xfc, 0x3e, 0xaa, 0x9f, 0xe7, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xa4, 0xa, 0xe2, 0xc0, 0x20, 0x84, 0xc4, 0x42, 0x71, 0xb4, 0xeb, 0x41, 0xf6, 0xd1, 0xf9, 0x3e, 0x92, +0x39, 0xe6, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x78, 0xec, 0x1f, 0x43, 0x24, 0x84, 0xc4, 0x42, 0xe4, 0x90, 0xa, 0x43, 0xf9, +0xf3, 0x45, 0x3f, 0x44, 0xc7, 0x86, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x75, 0x9d, 0x22, 0x43, 0x24, 0x84, 0xc4, 0x42, 0xf, +0x3b, 0xc, 0x43, 0x4f, 0x21, 0x47, 0x3f, 0x5c, 0x52, 0x85, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xf6, 0xf6, 0x30, 0x43, 0x24, +0x84, 0xc4, 0x42, 0xbe, 0x2b, 0xa, 0x43, 0x30, 0x68, 0x4d, 0x3f, 0xbc, 0x1f, 0x87, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x47, +0xee, 0x33, 0x43, 0x24, 0x84, 0xc4, 0x42, 0x8e, 0x15, 0x8, 0x43, 0x53, 0xb4, 0x4e, 0x3f, 0x2, 0xf3, 0x88, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x94, 0xa, 0x36, 0x43, 0x24, 0x84, 0xc4, 0x42, 0xac, 0x9c, 0x5, 0x43, 0xa5, 0xa0, 0x4f, 0x3f, 0xa8, +0x1c, 0x8b, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x16, 0xf8, 0x47, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x10, 0x5, 0xcf, 0x42, 0x25, +0x78, 0x57, 0x3f, 0x36, 0x72, 0xa5, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x4, 0x16, 0x4c, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xdf, +0x46, 0xbd, 0x42, 0x31, 0x45, 0x59, 0x3f, 0x22, 0x35, 0xad, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xb6, 0x40, 0x50, 0x43, 0x20, +0x84, 0xc4, 0x42, 0x40, 0xa, 0xa8, 0x42, 0xbe, 0x17, 0x5b, 0x3f, 0x2c, 0x7f, 0xb6, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x3e, +0x91, 0x54, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xd8, 0x19, 0x8e, 0x42, 0xdf, 0xfa, 0x5c, 0x3f, 0xba, 0xd7, 0xc1, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x71, 0xf7, 0x5a, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xc5, 0x3c, 0x3b, 0x42, 0x82, 0xc7, 0x5f, 0x3f, 0xba, +0xc, 0xd7, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xcd, 0xa3, 0x5c, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x2f, 0x1d, 0x15, 0x42, 0xe0, +0x82, 0x60, 0x3f, 0x3c, 0x63, 0xdf, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x6a, 0x9f, 0x5d, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x2f, +0x9, 0xe5, 0x41, 0xe9, 0xf0, 0x60, 0x3f, 0x38, 0xf4, 0xe6, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x96, 0xe1, 0x5e, 0x43, 0x20, +0x84, 0xc4, 0x42, 0xa8, 0x9d, 0xd1, 0x3f, 0xd0, 0x7d, 0x61, 0x3f, 0x42, 0x91, 0xfe, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x31, +0x7e, 0x5e, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xdb, 0xa2, 0x42, 0xc0, 0x5d, 0x52, 0x61, 0x3f, 0x86, 0x54, 0x1, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xb9, 0xd4, 0x5a, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xc5, 0xa2, 0x4a, 0xc1, 0x4e, 0xb8, 0x5f, 0x3f, 0x22, +0x8a, 0x5, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xfe, 0x2, 0x58, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x9a, 0x3, 0x87, 0xc1, 0x9e, +0x7c, 0x5e, 0x3f, 0xcc, 0x61, 0x7, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x25, 0xd6, 0x54, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xa5, +0x9a, 0xa1, 0xc1, 0x5, 0x19, 0x5d, 0x3f, 0xfa, 0xd5, 0x8, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x56, 0x88, 0x51, 0x43, 0x20, +0x84, 0xc4, 0x42, 0x26, 0x28, 0xb2, 0xc1, 0x11, 0xa7, 0x5b, 0x3f, 0xb6, 0xbd, 0x9, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x53, +0xcd, 0x4, 0x42, 0x20, 0x84, 0xc4, 0x42, 0x41, 0xad, 0xf7, 0xbf, 0xba, 0x85, 0xe, 0x3f, 0xaa, 0xd8, 0x0, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x93, 0xf2, 0xf0, 0x41, 0x20, 0x84, 0xc4, 0x42, 0x25, 0x42, 0x2e, 0xbf, 0x9d, 0x2c, 0xd, 0x3f, 0x38, +0x4c, 0x0, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x3, 0x27, 0xc5, 0x41, 0x20, 0x84, 0xc4, 0x42, 0xb5, 0x42, 0x45, 0x41, 0x97, +0xc7, 0xa, 0x3f, 0xd6, 0x36, 0xf5, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x71, 0x72, 0xca, 0x41, 0x20, 0x84, 0xc4, 0x42, 0xd0, +0x21, 0x7a, 0x41, 0xb6, 0x11, 0xb, 0x3f, 0xce, 0x52, 0xf2, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xfb, 0x4a, 0x36, 0x43, 0x20, +0x84, 0xc4, 0x42, 0x60, 0xb5, 0xd3, 0xc2, 0xd3, 0xbc, 0x4f, 0x3f, 0x5e, 0x4d, 0x2e, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x40, +0xbe, 0x38, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xc9, 0xb6, 0xd7, 0xc2, 0x3a, 0xcf, 0x50, 0x3f, 0xa1, 0x2d, 0x2f, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xa3, 0x77, 0x3b, 0x43, 0x20, 0x84, 0xc4, 0x42, 0xdf, 0x30, 0xf4, 0xc2, 0x3b, 0x0, 0x52, 0x3f, 0xfd, +0x67, 0x35, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc3, 0x75, 0x3a, 0x43, 0x20, 0x84, 0xc4, 0x42, 0x98, 0x28, 0xfb, 0xc2, 0x71, +0x8f, 0x51, 0x3f, 0x20, 0xee, 0x36, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x43, 0xcf, 0x38, 0x43, 0x1c, 0x84, 0xc4, 0x42, 0x37, +0x61, 0x0, 0xc3, 0xa1, 0xd6, 0x50, 0x3f, 0xb7, 0x27, 0x38, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x2a, 0x2f, 0x22, 0x43, 0x1c, +0x84, 0xc4, 0x42, 0x8d, 0x21, 0x1b, 0xc3, 0x24, 0xf1, 0x46, 0x3f, 0x4d, 0xdb, 0x43, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xed, +0x22, 0x1b, 0x43, 0x1c, 0x84, 0xc4, 0x42, 0x76, 0xe9, 0x21, 0xc3, 0xe4, 0xdb, 0x43, 0x3f, 0x9a, 0xd2, 0x46, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x1, 0x74, 0x12, 0x43, 0x1c, 0x84, 0xc4, 0x42, 0x9, 0x4f, 0x29, 0xc3, 0x99, 0xf, 0x40, 0x3f, 0xe9, +0xe, 0x4a, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x47, 0x98, 0x7, 0x43, 0x1c, 0x84, 0xc4, 0x42, 0x56, 0x9c, 0x31, 0xc3, 0xb5, +0x4f, 0x3b, 0x3f, 0x8a, 0xb0, 0x4d, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xf9, 0x83, 0xe5, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0xab, +0x8d, 0x3f, 0xc3, 0x5d, 0x32, 0x32, 0x3f, 0xcd, 0xc9, 0x53, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xfb, 0x94, 0xd4, 0x42, 0x1c, +0x84, 0xc4, 0x42, 0xc, 0x3d, 0x44, 0xc3, 0x41, 0x7e, 0x2e, 0x3f, 0x6b, 0xd6, 0x55, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc5, +0xdd, 0xc4, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0xce, 0xfb, 0x47, 0xc3, 0x5e, 0xe, 0x2b, 0x3f, 0xc8, 0x79, 0x57, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xa3, 0xa4, 0x92, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0x10, 0xf6, 0x51, 0xc3, 0x6a, 0x12, 0x20, 0x3f, 0x1b, +0xd7, 0x5b, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xe0, 0x8a, 0x89, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0xa, 0x1e, 0x53, 0xc3, 0xe0, +0x14, 0x1e, 0x3f, 0x8a, 0x58, 0x5c, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x48, 0xeb, 0x69, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0xb8, +0xc9, 0x52, 0xc3, 0x7d, 0x94, 0x19, 0x3f, 0xa4, 0x33, 0x5c, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x42, 0x51, 0x56, 0x42, 0x1c, +0x84, 0xc4, 0x42, 0x5f, 0x7e, 0x51, 0xc3, 0xc1, 0x6f, 0x17, 0x3f, 0xbe, 0xa2, 0x5b, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x9e, +0x9c, 0x45, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0xd4, 0x92, 0x4f, 0xc3, 0x17, 0x9c, 0x15, 0x3f, 0xb8, 0xcb, 0x5a, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xd7, 0x7b, 0x39, 0x42, 0x1c, 0x84, 0xc4, 0x42, 0x8f, 0x1f, 0x4d, 0xc3, 0x8c, 0x48, 0x14, 0x3f, 0x52, +0xb9, 0x59, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x8a, 0x8, 0x3, 0x41, 0x20, 0x84, 0xc4, 0x42, 0xcb, 0x38, 0xfe, 0xc1, 0xc, +0x95, 0x3, 0x3f, 0x68, 0xe6, 0xd, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x20, 0xf4, 0x5, 0x41, 0x20, 0x84, 0xc4, 0x42, 0x50, +0xa4, 0xe3, 0xc1, 0x7e, 0xa9, 0x3, 0x3f, 0x5c, 0x72, 0xc, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc9, 0x1f, 0x97, 0x41, 0x20, +0x84, 0xc4, 0x42, 0x57, 0x59, 0x98, 0xc1, 0x4e, 0x43, 0x8, 0x3f, 0x7a, 0x54, 0x8, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xe9, +0xd7, 0xb1, 0x41, 0x20, 0x84, 0xc4, 0x42, 0x9c, 0xbf, 0x94, 0xc1, 0x52, 0xb9, 0x9, 0x3f, 0x14, 0x22, 0x8, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x66, 0x8e, 0x34, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0xe6, 0xd3, 0x4d, 0xc3, 0xcf, 0x82, 0xd8, 0x3e, 0x3a, +0x8, 0x5a, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x82, 0x25, 0x39, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0xe5, 0xc6, 0x50, 0xc3, 0xe9, +0x81, 0xd7, 0x3e, 0x76, 0x52, 0x5b, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x10, 0xf2, 0x6b, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0x8a, +0xc4, 0x57, 0xc3, 0xa5, 0x65, 0xcc, 0x3e, 0x4a, 0x61, 0x5e, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xa8, 0x71, 0x7a, 0xc2, 0x1c, +0x84, 0xc4, 0x42, 0xe1, 0xe2, 0x57, 0xc3, 0xeb, 0x39, 0xc9, 0x3e, 0x98, 0x6e, 0x5e, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x99, +0x91, 0x83, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0x9b, 0x2e, 0x57, 0xc3, 0x3f, 0x73, 0xc6, 0x3e, 0xb0, 0x1f, 0x5e, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xa0, 0x6f, 0xc4, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0x40, 0xee, 0x49, 0xc3, 0x7f, 0x13, 0xaa, 0x3e, 0xd2, +0x53, 0x58, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x98, 0xb0, 0xd5, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0xbb, 0x52, 0x45, 0xc3, 0x5d, +0x87, 0xa2, 0x3e, 0xec, 0x4f, 0x56, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x3c, 0x20, 0xe9, 0xc2, 0x1c, 0x84, 0xc4, 0x42, 0xc0, +0x59, 0x3f, 0xc3, 0xc, 0x7, 0x9a, 0x3e, 0x20, 0xb3, 0x53, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc4, 0xa0, 0xff, 0xc2, 0x1c, +0x84, 0xc4, 0x42, 0xd8, 0x96, 0x37, 0xc3, 0x51, 0x2f, 0x90, 0x3e, 0xfd, 0x4d, 0x50, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x69, +0x83, 0x13, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x9d, 0x14, 0x28, 0xc3, 0xde, 0xe6, 0x7d, 0x3e, 0x5a, 0x85, 0x49, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0xdf, 0x95, 0x1a, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0xd2, 0x79, 0x21, 0xc3, 0x62, 0x87, 0x71, 0x3e, 0xc6, +0xa1, 0x46, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x54, 0x93, 0x20, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0xf3, 0x28, 0x1b, 0xc3, 0x56, +0xc, 0x67, 0x3e, 0x94, 0xde, 0x43, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x1f, 0xd3, 0x31, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x55, +0x5c, 0x6, 0xc3, 0x2b, 0xde, 0x48, 0x3e, 0x7e, 0xc5, 0x3a, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x95, 0x54, 0x34, 0xc3, 0x1c, +0x84, 0xc4, 0x42, 0xee, 0x63, 0x2, 0xc3, 0xab, 0x7b, 0x44, 0x3e, 0xe6, 0x8, 0x39, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x88, +0x32, 0x37, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x66, 0x0, 0xf1, 0xc2, 0xaf, 0x77, 0x3f, 0x3e, 0x78, 0xb5, 0x34, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x10, 0x7b, 0x37, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x68, 0xe1, 0xe6, 0xc2, 0x8c, 0xf8, 0x3e, 0x3e, 0xc8, +0x7e, 0x32, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xf6, 0xf1, 0x36, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0xf5, 0xbf, 0xdd, 0xc2, 0xab, +0xe8, 0x3f, 0x3e, 0x99, 0x7f, 0x30, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x3e, 0x8d, 0x35, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0xdb, +0x77, 0xd6, 0xc2, 0x92, 0x58, 0x42, 0x3e, 0xe6, 0xe7, 0x2e, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x86, 0xe9, 0xe3, 0xc1, 0x20, +0x84, 0xc4, 0x42, 0x92, 0xd6, 0x8a, 0xc1, 0xad, 0x13, 0xe7, 0x3e, 0x57, 0x97, 0x7, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x91, +0x2e, 0xca, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0x61, 0x3, 0x84, 0xc1, 0xd, 0xe4, 0xe9, 0x3e, 0xda, 0x37, 0x7, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x69, 0x24, 0x51, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0x79, 0xc6, 0xbc, 0xc1, 0xa3, 0x90, 0xf4, 0x3e, 0x58, +0x52, 0xa, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xc6, 0xc7, 0x39, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0xfb, 0x12, 0xd5, 0xc1, 0x88, +0xd7, 0xf5, 0x3e, 0x7a, 0xa6, 0xb, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x8, 0xd6, 0x52, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0xff, +0xfa, 0x85, 0xc1, 0xef, 0x1b, 0xf, 0x3e, 0x61, 0x53, 0x7, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xef, 0xfd, 0x55, 0xc3, 0x1c, +0x84, 0xc4, 0x42, 0x62, 0x19, 0x84, 0xc1, 0x31, 0x96, 0x9, 0x3e, 0x8, 0x39, 0x7, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0xe9, +0x63, 0x60, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0xa7, 0x2a, 0xcd, 0xc0, 0x5c, 0xc9, 0xee, 0x3d, 0xf2, 0xcd, 0x2, 0x3f, 0x1, +0xbe, 0x3d, 0x0, 0x37, 0x90, 0x61, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x92, 0xb6, 0x3e, 0xc0, 0xb0, 0xae, 0xea, 0x3d, 0xb6, +0x4d, 0x1, 0x3f, 0x1, 0xbe, 0x3d, 0x0, 0x55, 0xd1, 0x61, 0xc3, 0x1c, 0x84, 0xc4, 0x42, 0x7d, 0x7c, 0x85, 0x3e, 0x9f, +0xca, 0xe9, 0x3d, 0xac, 0xc5, 0xff, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xc6, 0xa0, 0x5e, 0xc3, 0x20, 0x84, 0xc4, 0x42, 0x23, +0x9b, 0xc, 0x42, 0xfe, 0xf3, 0xf4, 0x3d, 0xb0, 0x3f, 0xe1, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x80, 0xbe, 0x5c, 0xc3, 0x20, +0x84, 0xc4, 0x42, 0x7e, 0xfe, 0x32, 0x42, 0xac, 0x8b, 0xfb, 0x3d, 0x5e, 0xda, 0xd8, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xb1, +0xdf, 0x59, 0xc3, 0x20, 0x84, 0xc4, 0x42, 0x10, 0x27, 0x5f, 0x42, 0xa7, 0xcb, 0x2, 0x3e, 0xf4, 0x31, 0xcf, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xb4, 0xbd, 0x55, 0xc3, 0x20, 0x84, 0xc4, 0x42, 0x32, 0xa2, 0x89, 0x42, 0xa7, 0x6, 0xa, 0x3e, 0x8, +0xcc, 0xc3, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x69, 0xab, 0x4c, 0xc3, 0x20, 0x84, 0xc4, 0x42, 0x18, 0x61, 0xb8, 0x42, 0xe2, +0xe5, 0x19, 0x3e, 0x8a, 0x59, 0xaf, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xd2, 0x6b, 0x48, 0xc3, 0x24, 0x84, 0xc4, 0x42, 0x7c, +0xc4, 0xc9, 0x42, 0xca, 0x54, 0x21, 0x3e, 0x76, 0xbe, 0xa7, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xf0, 0x21, 0x44, 0xc3, 0x20, +0x84, 0xc4, 0x42, 0xd7, 0xea, 0xd8, 0x42, 0xc7, 0xd5, 0x28, 0x3e, 0x0, 0x1e, 0xa1, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x6, +0x49, 0x35, 0xc3, 0x24, 0x84, 0xc4, 0x42, 0x8, 0x9, 0x3, 0x43, 0xd9, 0xcf, 0x42, 0x3e, 0xe6, 0x5d, 0x8d, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0x93, 0x38, 0x32, 0xc3, 0x24, 0x84, 0xc4, 0x42, 0xa0, 0x97, 0x6, 0x43, 0x6f, 0x2c, 0x48, 0x3e, 0x3e, +0x41, 0x8a, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xd, 0x9a, 0x29, 0xc3, 0x24, 0x84, 0xc4, 0x42, 0xb7, 0x39, 0xc, 0x43, 0x7, +0x41, 0x57, 0x3e, 0xac, 0x53, 0x85, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x5e, 0xd8, 0x24, 0xc3, 0x24, 0x84, 0xc4, 0x42, 0xd7, +0xf9, 0xd, 0x43, 0xbc, 0x93, 0x5f, 0x3e, 0xa4, 0xcb, 0x83, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xa1, 0x52, 0x20, 0xc3, 0x24, +0x84, 0xc4, 0x42, 0x6f, 0xcc, 0xe, 0x43, 0x52, 0x7d, 0x67, 0x3e, 0x5a, 0x13, 0x83, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x5, +0x6f, 0x1c, 0xc3, 0x24, 0x84, 0xc4, 0x42, 0xce, 0x87, 0xe, 0x43, 0x45, 0x4b, 0x6e, 0x3e, 0x62, 0x4f, 0x83, 0x3e, 0x1, +0xbe, 0x3d, 0x0, 0xe5, 0xd7, 0xcd, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0xf9, 0x78, 0xb3, 0x41, 0x8d, 0x7d, 0xe9, 0x3e, 0xc0, +0x5f, 0xec, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x3b, 0xcb, 0xbf, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0xa9, 0xdc, 0x9c, 0x41, 0xc4, +0x6, 0xeb, 0x3e, 0xb2, 0xd8, 0xee, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x7c, 0x89, 0xd9, 0xc1, 0x20, 0x84, 0xc4, 0x42, 0xbe, +0xae, 0xbb, 0x40, 0x22, 0x36, 0xe8, 0x3e, 0x88, 0xde, 0xfa, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0xeb, 0x5b, 0xed, 0xc1, 0x20, +0x84, 0xc4, 0x42, 0x9e, 0x2a, 0x65, 0x40, 0x2d, 0xb, 0xe6, 0x3e, 0x1a, 0xde, 0xfc, 0x3e, 0x1, 0xbe, 0x3d, 0x0, 0x10, +0x88, 0x8e, 0x41, 0xa9, 0x75, 0x1, 0x3f, 0xed, 0x76, 0x61, 0x41, 0xda, 0x3, 0x1, 0x40, 0x14, 0x44, 0x2d, 0x3e, 0x1, +0xbe, 0x40, 0x0, 0x73, 0xa4, 0x23, 0x43, 0xdd, 0xbd, 0x17, 0x41, 0xee, 0x76, 0x61, 0x41, 0xab, 0x7, 0x82, 0xbf, 0x14, +0x44, 0x2d, 0x3e, 0x1, 0xbe, 0x40, 0x0, 0x10, 0x88, 0x8e, 0x41, 0xeb, 0xbd, 0x17, 0x41, 0xed, 0x76, 0x61, 0x41, 0xda, +0x3, 0x1, 0x40, 0x14, 0x44, 0x2d, 0x3e, 0x1, 0xbe, 0x40, 0x0, 0x73, 0xa4, 0x23, 0x43, 0xd4, 0x75, 0x1, 0x3f, 0xee, +0x76, 0x61, 0x41, 0xab, 0x7, 0x82, 0xbf, 0x14, 0x44, 0x2d, 0x3e, 0x1, 0xbe, 0x40, 0x0, 0x10, 0x88, 0x8e, 0x41, 0xcb, +0x3f, 0xd8, 0xc0, 0x65, 0x7, 0xd, 0x41, 0xda, 0x3, 0x1, 0x40, 0x60, 0x53, 0x97, 0x3e, 0x1, 0xbe, 0x40, 0x0, 0x73, +0xa4, 0x23, 0x43, 0xc6, 0x3f, 0xd8, 0xc0, 0x66, 0x7, 0xd, 0x41, 0xab, 0x7, 0x82, 0xbf, 0x40, 0x53, 0x97, 0x3e, 0x1, +0xbe, 0x40, 0x0, 0x10, 0x88, 0x8e, 0x41, 0xd5, 0x83, 0x18, 0xc1, 0xa1, 0x17, 0x8d, 0x3e, 0xd5, 0x3, 0x1, 0x40, 0x0, +0x0, 0x0, 0x3f, 0x1, 0xbe, 0x40, 0x0, 0x73, 0xa4, 0x23, 0x43, 0xd3, 0x83, 0x18, 0xc1, 0xd0, 0x17, 0x8d, 0x3e, 0xab, +0x7, 0x82, 0xbf, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x40, 0x0, 0x10, 0x88, 0x8e, 0x41, 0xcb, 0x3f, 0xd8, 0xc0, 0xf3, +0x35, 0x4, 0xc1, 0xd5, 0x3, 0x1, 0x40, 0x60, 0x56, 0x34, 0x3f, 0x1, 0xbe, 0x40, 0x0, 0x73, 0xa4, 0x23, 0x43, 0xc6, +0x3f, 0xd8, 0xc0, 0xf2, 0x35, 0x4, 0xc1, 0xab, 0x7, 0x82, 0xbf, 0x50, 0x56, 0x34, 0x3f, 0x1, 0xbe, 0x40, 0x0, 0x10, +0x88, 0x8e, 0x41, 0xa9, 0x75, 0x1, 0x3f, 0x7b, 0xa5, 0x58, 0xc1, 0xd5, 0x3, 0x1, 0x40, 0xfb, 0xae, 0x54, 0x3f, 0x1, +0xbe, 0x40, 0x0, 0x73, 0xa4, 0x23, 0x43, 0xd4, 0x75, 0x1, 0x3f, 0x7a, 0xa5, 0x58, 0xc1, 0xab, 0x7, 0x82, 0xbf, 0xfb, +0xae, 0x54, 0x3f, 0x1, 0xbe, 0x40, 0x0, 0x10, 0x88, 0x8e, 0x41, 0xeb, 0xbd, 0x17, 0x41, 0x73, 0xa5, 0x58, 0xc1, 0xd5, +0x3, 0x1, 0x40, 0xfb, 0xae, 0x54, 0x3f, 0x1, 0xbe, 0x40, 0x0, 0x73, 0xa4, 0x23, 0x43, 0xdd, 0xbd, 0x17, 0x41, 0x72, +0xa5, 0x58, 0xc1, 0xab, 0x7, 0x82, 0xbf, 0xfb, 0xae, 0x54, 0x3f, 0x1, 0xbe, 0x40, 0x0, 0x40, 0xab, 0x10, 0x41, 0x27, +0xde, 0xed, 0x40, 0x42, 0x7f, 0x64, 0x41, 0x64, 0x79, 0x17, 0x3e, 0x80, 0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x43, 0x0, 0xf4, +0xb1, 0x19, 0x43, 0x69, 0xb2, 0xb2, 0x41, 0x41, 0x7f, 0x64, 0x41, 0xad, 0xbe, 0x7a, 0x3d, 0x4e, 0xe, 0x83, 0x3f, 0x1, +0xbe, 0x43, 0x0, 0x40, 0xab, 0x10, 0x41, 0x6a, 0xb2, 0xb2, 0x41, 0x42, 0x7f, 0x64, 0x41, 0xad, 0xbe, 0x7a, 0x3d, 0x80, +0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x43, 0x0, 0xf4, 0xb1, 0x19, 0x43, 0x24, 0xde, 0xed, 0x40, 0x41, 0x7f, 0x64, 0x41, 0x64, +0x79, 0x17, 0x3e, 0x4e, 0xe, 0x83, 0x3f, 0x1, 0xbe, 0x43, 0x0, 0x40, 0xab, 0x10, 0x41, 0xd9, 0xf7, 0x93, 0xc0, 0xe5, +0xaa, 0xb0, 0x40, 0xce, 0xe1, 0x9a, 0x3e, 0x80, 0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x43, 0x0, 0xf4, 0xb1, 0x19, 0x43, 0xfc, +0xf7, 0x93, 0xc0, 0xe2, 0xaa, 0xb0, 0x40, 0xce, 0xe1, 0x9a, 0x3e, 0x4e, 0xe, 0x83, 0x3f, 0x1, 0xbe, 0x43, 0x0, 0x40, +0xab, 0x10, 0x41, 0x1d, 0xac, 0x13, 0xc1, 0x7e, 0x74, 0xa, 0xc1, 0x29, 0xb2, 0xe6, 0x3e, 0x80, 0xc2, 0xcb, 0x3c, 0x1, +0xbe, 0x43, 0x0, 0xf4, 0xb1, 0x19, 0x43, 0x1e, 0xac, 0x13, 0xc1, 0x7f, 0x74, 0xa, 0xc1, 0x29, 0xb2, 0xe6, 0x3e, 0x4e, +0xe, 0x83, 0x3f, 0x1, 0xbe, 0x43, 0x0, 0x40, 0xab, 0x10, 0x41, 0xd9, 0xf7, 0x93, 0xc0, 0x3b, 0x9f, 0xb6, 0xc1, 0x56, +0x99, 0xd, 0x3f, 0x80, 0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x43, 0x0, 0xf4, 0xb1, 0x19, 0x43, 0xfc, 0xf7, 0x93, 0xc0, 0x3b, +0x9f, 0xb6, 0xc1, 0x56, 0x99, 0xd, 0x3f, 0x4e, 0xe, 0x83, 0x3f, 0x1, 0xbe, 0x43, 0x0, 0x40, 0xab, 0x10, 0x41, 0x47, +0xde, 0xed, 0x40, 0x1f, 0xb4, 0xfc, 0xc1, 0xd2, 0xa7, 0x29, 0x3f, 0x80, 0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x43, 0x0, 0xf4, +0xb1, 0x19, 0x43, 0x24, 0xde, 0xed, 0x40, 0x1f, 0xb4, 0xfc, 0xc1, 0xd2, 0xa7, 0x29, 0x3f, 0x4e, 0xe, 0x83, 0x3f, 0x1, +0xbe, 0x43, 0x0, 0x40, 0xab, 0x10, 0x41, 0x72, 0xb2, 0xb2, 0x41, 0x1b, 0xb4, 0xfc, 0xc1, 0x1e, 0xc1, 0x49, 0x3f, 0x80, +0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x43, 0x0, 0xf4, 0xb1, 0x19, 0x43, 0x69, 0xb2, 0xb2, 0x41, 0x1b, 0xb4, 0xfc, 0xc1, 0xd, +0xc1, 0x49, 0x3f, 0x4e, 0xe, 0x83, 0x3f, 0x1, 0xbe, 0x43, 0x0, 0xda, 0x73, 0xbb, 0xc2, 0x7d, 0x9d, 0x3f, 0x41, 0xa2, +0x29, 0x6e, 0x41, 0xab, 0x7, 0x82, 0xbf, 0x14, 0x44, 0x2d, 0x3e, 0x1, 0xbe, 0x46, 0x0, 0x40, 0xbe, 0xd2, 0xc0, 0xef, +0xdb, 0x3f, 0x40, 0xa3, 0x29, 0x6e, 0x41, 0xda, 0x3, 0x1, 0x40, 0x14, 0x44, 0x2d, 0x3e, 0x1, 0xbe, 0x46, 0x0, 0x40, +0xbe, 0xd2, 0xc0, 0x8c, 0x9d, 0x3f, 0x41, 0xa3, 0x29, 0x6e, 0x41, 0xda, 0x3, 0x1, 0x40, 0x14, 0x44, 0x2d, 0x3e, 0x1, +0xbe, 0x46, 0x0, 0xda, 0x73, 0xbb, 0xc2, 0xf4, 0xdb, 0x3f, 0x40, 0xa2, 0x29, 0x6e, 0x41, 0xab, 0x7, 0x82, 0xbf, 0x14, +0x44, 0x2d, 0x3e, 0x1, 0xbe, 0x46, 0x0, 0x40, 0xbe, 0xd2, 0xc0, 0x89, 0x80, 0x88, 0xc0, 0x1b, 0xba, 0x19, 0x41, 0xda, +0x3, 0x1, 0x40, 0x60, 0x53, 0x97, 0x3e, 0x1, 0xbe, 0x46, 0x0, 0xda, 0x73, 0xbb, 0xc2, 0x86, 0x80, 0x88, 0xc0, 0x1a, +0xba, 0x19, 0x41, 0xab, 0x7, 0x82, 0xbf, 0x40, 0x53, 0x97, 0x3e, 0x1, 0xbe, 0x46, 0x0, 0x40, 0xbe, 0xd2, 0xc0, 0x69, +0x48, 0xe1, 0xc0, 0x96, 0xdb, 0x88, 0x3f, 0xd5, 0x3, 0x1, 0x40, 0x0, 0x0, 0x0, 0x3f, 0x1, 0xbe, 0x46, 0x0, 0xda, +0x73, 0xbb, 0xc2, 0x66, 0x48, 0xe1, 0xc0, 0x8f, 0xdb, 0x88, 0x3f, 0xab, 0x7, 0x82, 0xbf, 0x0, 0x0, 0x0, 0x3f, 0x1, +0xbe, 0x46, 0x0, 0x40, 0xbe, 0xd2, 0xc0, 0x89, 0x80, 0x88, 0xc0, 0x7b, 0x6, 0xef, 0xc0, 0xd5, 0x3, 0x1, 0x40, 0x60, +0x56, 0x34, 0x3f, 0x1, 0xbe, 0x46, 0x0, 0xda, 0x73, 0xbb, 0xc2, 0x86, 0x80, 0x88, 0xc0, 0x7c, 0x6, 0xef, 0xc0, 0xab, +0x7, 0x82, 0xbf, 0x50, 0x56, 0x34, 0x3f, 0x1, 0xbe, 0x46, 0x0, 0x40, 0xbe, 0xd2, 0xc0, 0xef, 0xdb, 0x3f, 0x40, 0xc5, +0xf2, 0x4b, 0xc1, 0xd5, 0x3, 0x1, 0x40, 0xfb, 0xae, 0x54, 0x3f, 0x1, 0xbe, 0x46, 0x0, 0xda, 0x73, 0xbb, 0xc2, 0xf4, +0xdb, 0x3f, 0x40, 0xc6, 0xf2, 0x4b, 0xc1, 0xab, 0x7, 0x82, 0xbf, 0xfb, 0xae, 0x54, 0x3f, 0x1, 0xbe, 0x46, 0x0, 0x40, +0xbe, 0xd2, 0xc0, 0x8c, 0x9d, 0x3f, 0x41, 0xbd, 0xf2, 0x4b, 0xc1, 0xd5, 0x3, 0x1, 0x40, 0xfb, 0xae, 0x54, 0x3f, 0x1, +0xbe, 0x46, 0x0, 0xda, 0x73, 0xbb, 0xc2, 0x7d, 0x9d, 0x3f, 0x41, 0xbe, 0xf2, 0x4b, 0xc1, 0xab, 0x7, 0x82, 0xbf, 0xfb, +0xae, 0x54, 0x3f, 0x1, 0xbe, 0x46, 0x0, 0x30, 0x51, 0x1d, 0xc3, 0xd2, 0xc0, 0xbd, 0x41, 0x79, 0x2b, 0x6c, 0x41, 0xad, +0xbe, 0x7a, 0x3d, 0x4e, 0xe, 0x83, 0x3f, 0x1, 0xbe, 0x49, 0x0, 0x0, 0x9f, 0x4a, 0xc1, 0xf7, 0xb, 0xd, 0x41, 0x7b, +0x2b, 0x6c, 0x41, 0x64, 0x79, 0x17, 0x3e, 0x80, 0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x49, 0x0, 0x0, 0x9f, 0x4a, 0xc1, 0xdc, +0xc0, 0xbd, 0x41, 0x7b, 0x2b, 0x6c, 0x41, 0xad, 0xbe, 0x7a, 0x3d, 0x80, 0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x49, 0x0, 0x30, +0x51, 0x1d, 0xc3, 0xe4, 0xb, 0xd, 0x41, 0x79, 0x2b, 0x6c, 0x41, 0x64, 0x79, 0x17, 0x3e, 0x4e, 0xe, 0x83, 0x3f, 0x1, +0xbe, 0x49, 0x0, 0x0, 0x9f, 0x4a, 0xc1, 0x64, 0x7c, 0x4f, 0xc0, 0x55, 0x3, 0xc0, 0x40, 0xce, 0xe1, 0x9a, 0x3e, 0x80, +0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x49, 0x0, 0x30, 0x51, 0x1d, 0xc3, 0xb0, 0x7c, 0x4f, 0xc0, 0x53, 0x3, 0xc0, 0x40, 0xce, +0xe1, 0x9a, 0x3e, 0x4e, 0xe, 0x83, 0x3f, 0x1, 0xbe, 0x49, 0x0, 0x0, 0x9f, 0x4a, 0xc1, 0x92, 0x1e, 0xfb, 0xc0, 0x45, +0xc8, 0x2, 0xc1, 0x29, 0xb2, 0xe6, 0x3e, 0x80, 0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x49, 0x0, 0x30, 0x51, 0x1d, 0xc3, 0x98, +0x1e, 0xfb, 0xc0, 0x47, 0xc8, 0x2, 0xc1, 0x29, 0xb2, 0xe6, 0x3e, 0x4e, 0xe, 0x83, 0x3f, 0x1, 0xbe, 0x49, 0x0, 0x0, +0x9f, 0x4a, 0xc1, 0x64, 0x7c, 0x4f, 0xc0, 0x1f, 0xc9, 0xb2, 0xc1, 0x56, 0x99, 0xd, 0x3f, 0x80, 0xc2, 0xcb, 0x3c, 0x1, +0xbe, 0x49, 0x0, 0x30, 0x51, 0x1d, 0xc3, 0xb0, 0x7c, 0x4f, 0xc0, 0x1f, 0xc9, 0xb2, 0xc1, 0x56, 0x99, 0xd, 0x3f, 0x4e, +0xe, 0x83, 0x3f, 0x1, 0xbe, 0x49, 0x0, 0x0, 0x9f, 0x4a, 0xc1, 0xf7, 0xb, 0xd, 0x41, 0x3, 0xde, 0xf8, 0xc1, 0xd2, +0xa7, 0x29, 0x3f, 0x80, 0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x49, 0x0, 0x30, 0x51, 0x1d, 0xc3, 0xe4, 0xb, 0xd, 0x41, 0x3, +0xde, 0xf8, 0xc1, 0xd2, 0xa7, 0x29, 0x3f, 0x4e, 0xe, 0x83, 0x3f, 0x1, 0xbe, 0x49, 0x0, 0x0, 0x9f, 0x4a, 0xc1, 0xdc, +0xc0, 0xbd, 0x41, 0xff, 0xdd, 0xf8, 0xc1, 0x1e, 0xc1, 0x49, 0x3f, 0x80, 0xc2, 0xcb, 0x3c, 0x1, 0xbe, 0x49, 0x0, 0x30, +0x51, 0x1d, 0xc3, 0xd2, 0xc0, 0xbd, 0x41, 0xff, 0xdd, 0xf8, 0xc1, 0xd, 0xc1, 0x49, 0x3f, 0x4e, 0xe, 0x83, 0x3f, 0x1, +0xbe, 0x49, 0x0, 0x6b, 0x4, 0x36, 0xcb, 0x90, 0xbe, 0x1c, 0x7f, 0x75, 0xbf, 0x83, 0xa3, 0xa3, 0xbc, 0x1, 0x0, 0x20, +0x0, 0x23, 0x53, 0x5e, 0xbe, 0x6f, 0x7c, 0x75, 0xbf, 0x83, 0xe7, 0x3a, 0xbe, 0x1, 0x0, 0x20, 0x0, 0x8e, 0xe9, 0x22, +0x38, 0x0, 0x0, 0x80, 0xbf, 0x3f, 0xde, 0x23, 0xb8, 0x1, 0x1, 0x20, 0x0, 0x54, 0x9b, 0x65, 0x3e, 0xce, 0x6c, 0x78, +0xbf, 0xc, 0x7d, 0xb7, 0x3d, 0x1, 0x2, 0x20, 0x0, 0x47, 0xba, 0x66, 0x3e, 0xf, 0x63, 0x78, 0xbf, 0x98, 0x25, 0xb5, +0x3d, 0x1, 0x0, 0x20, 0x0, 0x6d, 0x8f, 0x40, 0x3e, 0x62, 0x18, 0x79, 0xbf, 0xa9, 0xd3, 0x8, 0x3e, 0x1, 0x0, 0x20, +0x0, 0x25, 0x8b, 0x6c, 0x3e, 0x55, 0x13, 0x79, 0xbf, 0xcb, 0xc4, 0x13, 0xbb, 0x1, 0x0, 0x20, 0x0, 0x94, 0x32, 0x2c, +0x3f, 0xf6, 0x15, 0xf0, 0x30, 0x45, 0x6e, 0x3d, 0xbf, 0x1, 0x0, 0x20, 0x0, 0x55, 0x71, 0x6d, 0x3f, 0x4e, 0xad, 0x3a, +0xb3, 0x55, 0x62, 0xbf, 0x3e, 0x1, 0x0, 0x20, 0x0, 0x91, 0x1f, 0xf2, 0xbc, 0x5c, 0xcf, 0x19, 0xb5, 0x5f, 0xe3, 0x7f, +0x3f, 0x1, 0x0, 0x20, 0x0, 0xb2, 0x27, 0x8c, 0xbd, 0x9a, 0x79, 0x75, 0xbf, 0x12, 0x3, 0x8d, 0xbe, 0x1, 0x0, 0x20, +0x0, 0x65, 0x8f, 0x3, 0x3e, 0x4f, 0x76, 0x78, 0xbf, 0x40, 0xa5, 0x50, 0x3e, 0x1, 0x0, 0x20, 0x0, 0x5d, 0xba, 0x4, +0x3e, 0xa4, 0x7b, 0x78, 0xbf, 0x82, 0x81, 0x4f, 0x3e, 0x1, 0x0, 0x20, 0x0, 0x80, 0x5f, 0x96, 0x3d, 0x1, 0x1e, 0x79, +0xbf, 0xd1, 0x8b, 0x5f, 0x3e, 0x1, 0x0, 0x20, 0x0, 0x30, 0xa0, 0x7a, 0x3f, 0x7d, 0x35, 0x96, 0x30, 0x4c, 0xb8, 0x50, +0xbe, 0x1, 0x0, 0x20, 0x0, 0x21, 0xdc, 0x7, 0x3f, 0x58, 0x2b, 0x89, 0xb0, 0x91, 0xf9, 0x58, 0x3f, 0x1, 0x0, 0x20, +0x0, 0x3, 0xa3, 0x1c, 0xbf, 0xa3, 0x48, 0xf5, 0xb0, 0xa2, 0x7c, 0x4a, 0x3f, 0x1, 0x0, 0x20, 0x0, 0x29, 0xfe, 0xd9, +0x3d, 0xb2, 0x77, 0x75, 0xbf, 0x26, 0xbf, 0x86, 0xbe, 0x1, 0x0, 0x20, 0x0, 0x43, 0xf7, 0x83, 0xbc, 0x7d, 0x7e, 0x78, +0xbf, 0x4d, 0x97, 0x75, 0x3e, 0x1, 0x0, 0x20, 0x0, 0x2, 0x7e, 0x75, 0xbc, 0xcf, 0x90, 0x78, 0xbf, 0x28, 0x81, 0x74, +0x3e, 0x1, 0x0, 0x20, 0x0, 0x2b, 0x82, 0x8d, 0xbd, 0xe, 0x22, 0x79, 0xbf, 0x31, 0xb5, 0x60, 0x3e, 0x1, 0x0, 0x20, +0x0, 0x48, 0x78, 0x69, 0x3f, 0x9e, 0x7b, 0xc0, 0x2d, 0xe9, 0x6, 0xd2, 0x3e, 0x1, 0x0, 0x20, 0x0, 0x8b, 0x98, 0x69, +0x3f, 0x20, 0xd4, 0xd3, 0x2d, 0x38, 0x77, 0xd1, 0x3e, 0x1, 0x1, 0x20, 0x0, 0x18, 0x97, 0x8d, 0xbd, 0xa9, 0xf1, 0xea, +0xb0, 0x31, 0x63, 0x7f, 0x3f, 0x1, 0x1, 0x20, 0x0, 0x2e, 0xc8, 0x75, 0xbf, 0x7e, 0x84, 0xa5, 0xb0, 0xa3, 0x35, 0x8f, +0x3e, 0x1, 0x1, 0x20, 0x0, 0xe1, 0x81, 0x76, 0x3e, 0x72, 0x77, 0x75, 0xbf, 0x35, 0x1b, 0x1a, 0xbe, 0x1, 0x1, 0x20, +0x0, 0xc1, 0xff, 0x1d, 0xbe, 0x36, 0x82, 0x78, 0xbf, 0x48, 0x6f, 0x3c, 0x3e, 0x1, 0x1, 0x20, 0x0, 0xf6, 0xe6, 0x1c, +0xbe, 0x75, 0x9a, 0x78, 0xbf, 0x67, 0x59, 0x3b, 0x3e, 0x1, 0x1, 0x20, 0x0, 0x13, 0x81, 0x3d, 0xbe, 0xfc, 0x22, 0x79, +0xbf, 0x7c, 0xda, 0xb, 0x3e, 0x1, 0x1, 0x20, 0x0, 0xe9, 0x52, 0xfe, 0x3e, 0x4b, 0x69, 0x91, 0xb0, 0x2c, 0x2f, 0x5e, +0x3f, 0x1, 0x1, 0x20, 0x0, 0x26, 0xe0, 0xfe, 0x3e, 0xff, 0x27, 0x91, 0xb0, 0xb2, 0x6, 0x5e, 0x3f, 0x1, 0x1, 0x20, +0x0, 0xb5, 0x89, 0x24, 0xbf, 0x0, 0xe1, 0xf2, 0xb0, 0xde, 0x1e, 0x44, 0x3f, 0x1, 0x0, 0x20, 0x0, 0x26, 0xe5, 0x70, +0xbf, 0x5b, 0xaf, 0x33, 0xaf, 0xe5, 0x44, 0xad, 0xbe, 0x1, 0x0, 0x20, 0x0, 0x45, 0xcb, 0x70, 0xbf, 0x96, 0x59, 0x31, +0xaf, 0x8a, 0xd4, 0xad, 0xbe, 0x1, 0x0, 0x20, 0x0, 0x76, 0xf8, 0x90, 0x3e, 0xf1, 0x78, 0x75, 0xbf, 0x86, 0x90, 0xa0, +0x3c, 0x1, 0x0, 0x20, 0x0, 0x4e, 0xdd, 0x6e, 0xbe, 0xf, 0x80, 0x78, 0xbf, 0x25, 0x8, 0x6c, 0x3d, 0x1, 0x0, 0x20, +0x0, 0x21, 0xc9, 0x6d, 0xbe, 0xe5, 0x94, 0x78, 0xbf, 0xd5, 0x7a, 0x67, 0x3d, 0x1, 0x0, 0x20, 0x0, 0xbc, 0xaf, 0x6b, +0xbe, 0x71, 0x20, 0x79, 0xbf, 0x1, 0xa2, 0xb3, 0x3a, 0x1, 0x0, 0x20, 0x0, 0x31, 0x6c, 0xde, 0xbd, 0x34, 0x52, 0xee, +0xb0, 0x5b, 0x7c, 0x7e, 0x3f, 0x1, 0x0, 0x20, 0x0, 0x11, 0x6d, 0x78, 0xbf, 0xef, 0x90, 0xca, 0xb4, 0xa0, 0x3d, 0x77, +0x3e, 0x1, 0x0, 0x20, 0x0, 0x2e, 0xf3, 0xf, 0xbf, 0xa3, 0x5f, 0xc2, 0x34, 0xb5, 0xb1, 0x53, 0xbf, 0x1, 0x0, 0x20, +0x0, 0xa8, 0xae, 0xf, 0xbf, 0x11, 0x20, 0x64, 0x35, 0x3e, 0xe0, 0x53, 0xbf, 0x1, 0x0, 0x20, 0x0, 0x31, 0xb4, 0x5e, +0x3e, 0x9e, 0x7b, 0x75, 0xbf, 0x0, 0x85, 0x3a, 0x3e, 0x1, 0x0, 0x20, 0x0, 0x5d, 0x31, 0x64, 0xbe, 0xdc, 0x78, 0x78, +0xbf, 0x61, 0x70, 0xba, 0xbd, 0x1, 0x2, 0x20, 0x0, 0xcb, 0x11, 0x63, 0xbe, 0x41, 0x82, 0x78, 0xbf, 0xb6, 0xc7, 0xbc, +0xbd, 0x1, 0x2, 0x20, 0x0, 0xf0, 0xa9, 0x3f, 0xbe, 0x66, 0x1b, 0x79, 0xbf, 0x3b, 0xbd, 0x9, 0xbe, 0x1, 0x2, 0x20, +0x0, 0x2e, 0x2e, 0x2c, 0xbf, 0xb3, 0x17, 0xf0, 0xb0, 0x44, 0x72, 0x3d, 0x3f, 0x1, 0x2, 0x20, 0x0, 0x71, 0x46, 0x6d, +0xbf, 0xc9, 0x53, 0xc8, 0xae, 0xa7, 0x36, 0xc0, 0xbe, 0x1, 0x2, 0x20, 0x0, 0x56, 0xd0, 0xfc, 0x3c, 0xb2, 0x53, 0xe7, +0x30, 0xc9, 0xe0, 0x7f, 0xbf, 0x1, 0x2, 0x20, 0x0, 0xa, 0xee, 0x8c, 0x3d, 0x74, 0x7e, 0x75, 0xbf, 0xe7, 0xd4, 0x8c, +0x3e, 0x1, 0x2, 0x20, 0x0, 0xab, 0x16, 0x2, 0xbe, 0x5c, 0x6f, 0x78, 0xbf, 0x97, 0x14, 0x52, 0xbe, 0x1, 0x2, 0x20, +0x0, 0xa1, 0xeb, 0x0, 0xbe, 0xab, 0x69, 0x78, 0xbf, 0xda, 0x37, 0x53, 0xbe, 0x1, 0x2, 0x20, 0x0, 0xee, 0x8a, 0x94, +0xbd, 0xc8, 0x15, 0x79, 0xbf, 0x58, 0x6c, 0x60, 0xbe, 0x1, 0x2, 0x20, 0x0, 0x19, 0xae, 0x7a, 0xbf, 0x85, 0xff, 0x95, +0xb0, 0x3e, 0xac, 0x4f, 0x3e, 0x1, 0x2, 0x20, 0x0, 0x59, 0x75, 0x7, 0xbf, 0x1e, 0x8f, 0x89, 0x30, 0xcb, 0x39, 0x59, +0xbf, 0x1, 0x2, 0x20, 0x0, 0x93, 0xaf, 0x1c, 0x3f, 0x8b, 0x62, 0x18, 0x33, 0xea, 0x72, 0x4a, 0xbf, 0x1, 0x1, 0x20, +0x0, 0x52, 0x42, 0xd9, 0xbd, 0x5c, 0x80, 0x75, 0xbf, 0xf4, 0x92, 0x86, 0x3e, 0x1, 0x1, 0x20, 0x0, 0xf8, 0x92, 0x8f, +0x3c, 0x31, 0x67, 0x78, 0xbf, 0x58, 0xf5, 0x76, 0xbe, 0x1, 0x1, 0x20, 0x0, 0xea, 0xc7, 0x98, 0x3c, 0x8a, 0x54, 0x78, +0xbf, 0xc5, 0xa, 0x78, 0xbe, 0x1, 0x1, 0x20, 0x0, 0x74, 0x48, 0x8f, 0x3d, 0xbc, 0x11, 0x79, 0xbf, 0x58, 0x8e, 0x61, +0xbe, 0x1, 0x1, 0x20, 0x0, 0x4d, 0x48, 0x69, 0xbf, 0x79, 0xd3, 0xc8, 0x34, 0xbc, 0xdb, 0xd2, 0xbe, 0x1, 0x1, 0x20, +0x0, 0xc2, 0x27, 0x69, 0xbf, 0x85, 0x79, 0x9d, 0x34, 0x8a, 0x6b, 0xd3, 0xbe, 0x1, 0x1, 0x20, 0x0, 0x61, 0x22, 0x90, +0x3d, 0x5b, 0x48, 0xe0, 0x33, 0x80, 0x5d, 0x7f, 0xbf, 0x1, 0x1, 0x20, 0x0, 0x64, 0xb7, 0x75, 0x3f, 0xd1, 0xb0, 0xa5, +0x30, 0xaf, 0xa8, 0x8f, 0xbe, 0x1, 0x1, 0x20, 0x0, 0x51, 0x29, 0x76, 0xbe, 0x9c, 0x80, 0x75, 0xbf, 0x15, 0xbf, 0x19, +0x3e, 0x1, 0x3d, 0x20, 0x0, 0x19, 0x61, 0x1f, 0x3e, 0x77, 0x63, 0x78, 0xbf, 0xd, 0xcd, 0x3d, 0xbe, 0x1, 0x0, 0x20, +0x0, 0x46, 0x79, 0x20, 0x3e, 0xea, 0x4a, 0x78, 0xbf, 0x35, 0xe2, 0x3e, 0xbe, 0x1, 0xe7, 0x20, 0x0, 0xfb, 0x5a, 0x3e, +0x3e, 0xcd, 0x10, 0x79, 0xbf, 0x2c, 0xb8, 0xc, 0xbe, 0x1, 0xe7, 0x20, 0x0, 0xdf, 0x81, 0xfd, 0xbe, 0xbd, 0xc9, 0x91, +0x30, 0xdd, 0x6a, 0x5e, 0xbf, 0x1, 0xbe, 0x20, 0x0, 0x9f, 0xf4, 0xfc, 0xbe, 0xc9, 0xa, 0x92, 0x30, 0xe, 0x93, 0x5e, +0xbf, 0x1, 0xe7, 0x20, 0x0, 0xf1, 0x91, 0x24, 0x3f, 0x40, 0xde, 0xf2, 0x30, 0xf5, 0x17, 0x44, 0xbf, 0x1, 0x0, 0x20, +0x0, 0x36, 0xb, 0x71, 0x3f, 0xef, 0x21, 0x37, 0x2f, 0xac, 0x70, 0xac, 0x3e, 0x1, 0x0, 0x20, 0x0, 0xce, 0x24, 0x71, +0x3f, 0xeb, 0x75, 0x39, 0x2f, 0x44, 0xe1, 0xab, 0x3e, 0x1, 0x0, 0x20, 0x0, 0xdf, 0x38, 0x70, 0x3e, 0x9b, 0x65, 0x78, +0xbf, 0x5f, 0xc3, 0x71, 0xbd, 0x1, 0x0, 0x20, 0x0, 0x5e, 0x4c, 0x71, 0x3e, 0x73, 0x50, 0x78, 0xbf, 0x87, 0x4e, 0x76, +0xbd, 0x1, 0x0, 0x20, 0x0, 0xf1, 0xd8, 0xe0, 0x3d, 0xb6, 0x6a, 0xee, 0x30, 0xd5, 0x73, 0x7e, 0xbf, 0x1, 0x0, 0x20, +0x0, 0x95, 0x5d, 0x78, 0x3f, 0xbd, 0x12, 0x9e, 0x30, 0x20, 0x36, 0x78, 0xbe, 0x1, 0x0, 0x20, 0x0, 0x76, 0x58, 0x10, +0x3f, 0x1d, 0xb6, 0x80, 0xb0, 0xb4, 0x6c, 0x53, 0x3f, 0x1, 0x0, 0x20, 0x0, 0xe0, 0x9c, 0x10, 0x3f, 0x1d, 0x70, 0x80, +0xb0, 0xed, 0x3d, 0x53, 0x3f, 0x1, 0x0, 0x20, 0x0, 0x6a, 0x5a, 0x90, 0xbe, 0xaf, 0x7f, 0x75, 0xbf, 0xd5, 0x61, 0xf1, +0xbc, 0x1, 0x0, 0x23, 0x0, 0x18, 0xb0, 0x57, 0xbe, 0xba, 0x80, 0x75, 0xbf, 0xce, 0x2f, 0x42, 0xbe, 0x1, 0x0, 0x23, +0x0, 0xf4, 0x22, 0x23, 0x38, 0x0, 0x0, 0x80, 0xbf, 0x66, 0xf1, 0x23, 0x38, 0x1, 0x0, 0x23, 0x0, 0xbd, 0x35, 0x62, +0x3e, 0x70, 0x64, 0x78, 0xbf, 0x1d, 0x3d, 0xca, 0x3d, 0x1, 0x0, 0x23, 0x0, 0xba, 0x48, 0x63, 0x3e, 0x69, 0x4d, 0x78, +0xbf, 0x4f, 0x7a, 0xcc, 0x3d, 0x1, 0x0, 0x23, 0x0, 0x34, 0xa1, 0x3b, 0x3e, 0xc7, 0x10, 0x79, 0xbf, 0xfa, 0x55, 0x10, +0x3e, 0x1, 0x0, 0x23, 0x0, 0x9d, 0x76, 0x6c, 0x3e, 0x39, 0x13, 0x79, 0xbf, 0xb7, 0xc7, 0xda, 0x3b, 0x1, 0x0, 0x23, +0x0, 0x7f, 0xde, 0x32, 0x3f, 0xe9, 0xe6, 0x98, 0xb0, 0xf2, 0x24, 0x37, 0xbf, 0x1, 0x0, 0x23, 0x0, 0xf, 0xd5, 0x69, +0x3f, 0x6c, 0x0, 0x58, 0xb1, 0x72, 0x68, 0xd0, 0x3e, 0x1, 0x0, 0x23, 0x0, 0xcf, 0xce, 0x83, 0xbd, 0xc1, 0x16, 0x93, +0xb0, 0x22, 0x78, 0x7f, 0x3f, 0x1, 0x0, 0x23, 0x0, 0x68, 0xd2, 0x70, 0xbd, 0xf9, 0x7f, 0x75, 0xbf, 0xbc, 0xf9, 0x8d, +0xbe, 0x1, 0x0, 0x23, 0x0, 0x80, 0x46, 0xf8, 0x3d, 0xf0, 0x63, 0x78, 0xbf, 0xb4, 0x7a, 0x56, 0x3e, 0x1, 0x0, 0x23, +0x0, 0x8c, 0x7e, 0xfa, 0x3d, 0x21, 0x4c, 0x78, 0xbf, 0xfe, 0x8d, 0x57, 0x3e, 0x1, 0x0, 0x23, 0x0, 0x38, 0x9f, 0x86, +0x3d, 0xd1, 0x11, 0x79, 0xbf, 0x51, 0xe1, 0x62, 0x3e, 0x1, 0x0, 0x23, 0x0, 0xa5, 0x59, 0x7c, 0x3f, 0xd0, 0x93, 0x34, +0xb1, 0xc, 0x4c, 0x2c, 0xbe, 0x1, 0x0, 0x23, 0x0, 0x2c, 0x65, 0x7c, 0x3f, 0x99, 0xb3, 0x34, 0xb1, 0x23, 0x3d, 0x2b, +0xbe, 0x1, 0x0, 0x23, 0x0, 0xfa, 0xd, 0x0, 0x3f, 0x1d, 0x72, 0x37, 0x35, 0xc6, 0xab, 0x5d, 0x3f, 0x1, 0x0, 0x23, +0x0, 0xc6, 0x71, 0x23, 0xbf, 0x7a, 0x3e, 0xa9, 0x34, 0x66, 0x8, 0x45, 0x3f, 0x1, 0x0, 0x23, 0x0, 0xc5, 0xad, 0xec, +0x3d, 0xb7, 0x7d, 0x75, 0xbf, 0x75, 0x96, 0x84, 0xbe, 0x1, 0x0, 0x23, 0x0, 0x3b, 0x95, 0xc8, 0xbc, 0x20, 0x69, 0x78, +0xbf, 0xc, 0x37, 0x76, 0x3e, 0x1, 0x0, 0x23, 0x0, 0xff, 0x48, 0xbf, 0xbc, 0x89, 0x59, 0x78, 0xbf, 0x9c, 0x4f, 0x77, +0x3e, 0x1, 0x0, 0x23, 0x0, 0x60, 0x1b, 0x9d, 0xbd, 0xf0, 0x15, 0x79, 0xbf, 0xd, 0xf3, 0x5e, 0x3e, 0x1, 0x0, 0x23, +0x0, 0xb, 0x87, 0x65, 0x3f, 0xf8, 0xc4, 0x57, 0xb1, 0x43, 0xbe, 0xe2, 0x3e, 0x1, 0x0, 0x23, 0x0, 0x8b, 0x92, 0xd4, +0xbd, 0xa0, 0xe6, 0x82, 0xb0, 0x5, 0x9e, 0x7e, 0x3f, 0x1, 0x0, 0x23, 0x0, 0xea, 0xc, 0x78, 0xbf, 0xd7, 0x6b, 0x2a, +0x31, 0xed, 0x33, 0x7d, 0x3e, 0x1, 0x0, 0x23, 0x0, 0xee, 0xfa, 0x77, 0xbf, 0x2f, 0x46, 0x2a, 0x31, 0x36, 0x4d, 0x7e, +0x3e, 0x1, 0x0, 0x23, 0x0, 0xec, 0xbd, 0x7b, 0x3e, 0xd0, 0x7a, 0x75, 0xbf, 0xcd, 0xa, 0x11, 0xbe, 0x1, 0x0, 0x23, +0x0, 0x16, 0x76, 0x24, 0xbe, 0x6, 0x72, 0x78, 0xbf, 0xf, 0x31, 0x38, 0x3e, 0x1, 0x0, 0x23, 0x0, 0xef, 0x4c, 0x23, +0xbe, 0x91, 0x70, 0x78, 0xbf, 0xa, 0x58, 0x39, 0x3e, 0x1, 0x0, 0x23, 0x0, 0xfe, 0x42, 0x42, 0xbe, 0x94, 0x1b, 0x79, +0xbf, 0x8f, 0x7, 0x6, 0x3e, 0x1, 0x0, 0x23, 0x0, 0x91, 0x5f, 0xee, 0x3e, 0x1d, 0xae, 0x28, 0xb1, 0xfd, 0x8f, 0x62, +0x3f, 0x1, 0x0, 0x23, 0x0, 0xe5, 0x1d, 0x2b, 0xbf, 0xc5, 0x1, 0x88, 0x30, 0x58, 0x68, 0x3e, 0x3f, 0x1, 0x0, 0x23, +0x0, 0xa3, 0xd7, 0x6d, 0xbf, 0xf9, 0xe3, 0x57, 0x31, 0x87, 0x63, 0xbd, 0xbe, 0x1, 0x0, 0x23, 0x0, 0x2, 0x87, 0x90, +0x3e, 0x60, 0x78, 0x75, 0xbf, 0xf3, 0x69, 0xf4, 0x3c, 0x1, 0x0, 0x23, 0x0, 0xc4, 0xc8, 0x70, 0xbe, 0x3f, 0x7b, 0x78, +0xbf, 0x0, 0x42, 0x50, 0x3d, 0x1, 0x0, 0x23, 0x0, 0x56, 0xad, 0x6f, 0xbe, 0x69, 0x88, 0x78, 0xbf, 0xce, 0xed, 0x54, +0x3d, 0x1, 0x0, 0x23, 0x0, 0x74, 0x9b, 0x6b, 0xbe, 0x93, 0x20, 0x79, 0xbf, 0x55, 0xd5, 0xbd, 0xbb, 0x1, 0x0, 0x23, +0x0, 0x36, 0x7f, 0x12, 0xbe, 0x1b, 0x5, 0x65, 0xb0, 0xde, 0x5d, 0x7d, 0x3f, 0x1, 0x0, 0x23, 0x0, 0x39, 0x74, 0x11, +0xbe, 0x8a, 0xe0, 0x65, 0xb0, 0x7b, 0x67, 0x7d, 0x3f, 0x1, 0x0, 0x23, 0x0, 0x3, 0x5d, 0x7a, 0xbf, 0x93, 0x8b, 0x2f, +0x31, 0xfd, 0xb2, 0x55, 0x3e, 0x1, 0x0, 0x23, 0x0, 0xa9, 0xa1, 0x8, 0xbf, 0x5d, 0xc4, 0x32, 0x31, 0x65, 0x7d, 0x58, +0xbf, 0x1, 0x0, 0x23, 0x0, 0xa0, 0x9, 0x58, 0x3e, 0x54, 0x77, 0x75, 0xbf, 0x42, 0x8a, 0x42, 0x3e, 0x1, 0x0, 0x23, +0x0, 0xd0, 0xda, 0x60, 0xbe, 0x41, 0x81, 0x78, 0xbf, 0xfa, 0x69, 0xc7, 0xbd, 0x1, 0x0, 0x23, 0x0, 0xb, 0xc7, 0x5f, +0xbe, 0xf8, 0x97, 0x78, 0xbf, 0x85, 0x2b, 0xc5, 0xbd, 0x1, 0x0, 0x23, 0x0, 0x1e, 0xc7, 0x3a, 0xbe, 0x4, 0x23, 0x79, +0xbf, 0x94, 0x78, 0xf, 0xbe, 0x1, 0x4, 0x23, 0x0, 0x29, 0x85, 0x32, 0xbf, 0xef, 0x21, 0x98, 0x30, 0x8, 0x7c, 0x37, +0x3f, 0x1, 0x4, 0x23, 0x0, 0x3a, 0xe7, 0x69, 0xbf, 0xb0, 0x0, 0x58, 0x31, 0xd8, 0x16, 0xd0, 0xbe, 0x1, 0x4, 0x23, +0x0, 0x5e, 0xbb, 0x86, 0x3d, 0xee, 0x81, 0x92, 0x30, 0x8, 0x72, 0x7f, 0xbf, 0x1, 0x4, 0x23, 0x0, 0xd0, 0x51, 0x72, +0x3d, 0x14, 0x78, 0x75, 0xbf, 0x1c, 0x26, 0x8e, 0x3e, 0x1, 0x4, 0x23, 0x0, 0x13, 0x7a, 0xf5, 0xbd, 0xbf, 0x81, 0x78, +0xbf, 0x44, 0x1f, 0x55, 0xbe, 0x1, 0x4, 0x23, 0x0, 0xbe, 0x40, 0xf3, 0xbd, 0x42, 0x99, 0x78, 0xbf, 0x14, 0xb, 0x54, +0xbe, 0x1, 0x4, 0x23, 0x0, 0x52, 0xd8, 0x84, 0xbd, 0xf9, 0x21, 0x79, 0xbf, 0x26, 0x8, 0x62, 0xbe, 0x1, 0x4, 0x23, +0x0, 0x6d, 0x48, 0x7c, 0xbf, 0x7d, 0x2c, 0xbc, 0xb3, 0xbd, 0xdd, 0x2d, 0x3e, 0x1, 0x4, 0x23, 0x0, 0xad, 0x3c, 0x7c, +0xbf, 0xe, 0x36, 0x61, 0xb4, 0x96, 0xed, 0x2e, 0x3e, 0x1, 0x4, 0x23, 0x0, 0x39, 0xe4, 0xff, 0xbe, 0xa6, 0xc8, 0x37, +0xb5, 0xdc, 0xbb, 0x5d, 0xbf, 0x1, 0x4, 0x23, 0x0, 0x57, 0xd1, 0x23, 0x3f, 0x31, 0xe8, 0x70, 0xb0, 0xf7, 0xb8, 0x44, +0xbf, 0x1, 0x4, 0x23, 0x0, 0xf7, 0xe6, 0xeb, 0xbd, 0x57, 0x7a, 0x75, 0xbf, 0x90, 0xc5, 0x84, 0x3e, 0x1, 0x3, 0x23, +0x0, 0x2c, 0x4e, 0xd4, 0x3c, 0x8c, 0x7c, 0x78, 0xbf, 0x22, 0xd5, 0x74, 0xbe, 0x1, 0x3, 0x23, 0x0, 0x64, 0x9d, 0xdd, +0x3c, 0xca, 0x8b, 0x78, 0xbf, 0x0, 0xbc, 0x73, 0xbe, 0x1, 0x3, 0x23, 0x0, 0x24, 0xf0, 0x9e, 0x3d, 0xd8, 0x1d, 0x79, +0xbf, 0x3a, 0x12, 0x5e, 0xbe, 0x1, 0x3, 0x23, 0x0, 0xce, 0x98, 0x65, 0xbf, 0x8d, 0xc6, 0x57, 0x31, 0x4e, 0x76, 0xe2, +0xbe, 0x1, 0x3, 0x23, 0x0, 0x53, 0x93, 0xd7, 0x3d, 0x32, 0x4b, 0x82, 0x30, 0xec, 0x93, 0x7e, 0xbf, 0x1, 0x3, 0x23, +0x0, 0x57, 0x27, 0x78, 0x3f, 0xca, 0x3e, 0x73, 0x34, 0x56, 0x94, 0x7b, 0xbe, 0x1, 0x3, 0x23, 0x0, 0x12, 0x39, 0x78, +0x3f, 0xc1, 0xc8, 0x2a, 0xb1, 0xdf, 0x7b, 0x7a, 0xbe, 0x1, 0x3, 0x23, 0x0, 0xa5, 0x5e, 0x7b, 0xbe, 0x3e, 0x7d, 0x75, +0xbf, 0x22, 0x6e, 0x11, 0x3e, 0x1, 0x3, 0x23, 0x0, 0x53, 0xec, 0x25, 0x3e, 0xa4, 0x73, 0x78, 0xbf, 0x10, 0xbd, 0x36, +0xbe, 0x1, 0x3, 0x23, 0x0, 0x18, 0x15, 0x27, 0x3e, 0xbf, 0x74, 0x78, 0xbf, 0xbe, 0x95, 0x35, 0xbe, 0x1, 0x3, 0x23, +0x0, 0x3a, 0x28, 0x43, 0x3e, 0x36, 0x18, 0x79, 0xbf, 0xd6, 0x1d, 0x5, 0xbe, 0x1, 0x3, 0x23, 0x0, 0xfd, 0x1d, 0xee, +0xbe, 0xda, 0x5b, 0xaf, 0x33, 0x3a, 0xa1, 0x62, 0xbf, 0x1, 0x3, 0x23, 0x0, 0x34, 0x7a, 0x2b, 0x3f, 0xac, 0xc8, 0x88, +0xb0, 0x3a, 0x15, 0x3e, 0xbf, 0x1, 0x3, 0x23, 0x0, 0x63, 0xc5, 0x6d, 0x3f, 0x53, 0xe5, 0x57, 0xb1, 0x1c, 0xbf, 0xbd, +0x3e, 0x1, 0x3, 0x23, 0x0, 0x84, 0x2d, 0x72, 0x3e, 0x70, 0x6a, 0x78, 0xbf, 0x61, 0x5f, 0x4a, 0xbd, 0x1, 0x3, 0x23, +0x0, 0x72, 0x48, 0x73, 0x3e, 0xeb, 0x5c, 0x78, 0xbf, 0x34, 0xb4, 0x45, 0xbd, 0x1, 0x2, 0x23, 0x0, 0x5b, 0xb, 0x14, +0x3e, 0x59, 0xbf, 0x63, 0x30, 0x79, 0x4f, 0x7d, 0xbf, 0x1, 0x2, 0x23, 0x0, 0x43, 0x17, 0x15, 0x3e, 0xed, 0xe2, 0x62, +0x30, 0xa7, 0x45, 0x7d, 0xbf, 0x1, 0x2, 0x23, 0x0, 0xaf, 0x72, 0x7a, 0x3f, 0xc6, 0xbe, 0x2f, 0xb1, 0x22, 0x1b, 0x54, +0xbe, 0x1, 0x2, 0x23, 0x0, 0xda, 0xb8, 0x8, 0x3f, 0x5a, 0xd1, 0x32, 0xb1, 0xc0, 0x6e, 0x58, 0x3f, 0x1, 0x2, 0x23, +0x0, 0x65, 0xcf, 0x78, 0xbe, 0x97, 0x80, 0x75, 0xbf, 0x78, 0x6c, 0x15, 0x3e, 0x1, 0xda, 0x26, 0x0, 0x3b, 0x98, 0x90, +0xbe, 0xd, 0x7f, 0x75, 0xbf, 0x18, 0x12, 0xcc, 0xbc, 0x1, 0xda, 0x26, 0x0, 0x74, 0x3b, 0x23, 0x38, 0x0, 0x0, 0x80, +0xbf, 0x7, 0x17, 0x23, 0xb8, 0x1, 0xda, 0x26, 0x0, 0x5b, 0x3a, 0x71, 0x3e, 0xc1, 0x65, 0x78, 0xbf, 0xe8, 0x1, 0x61, +0xbd, 0x1, 0xdb, 0x26, 0x0, 0xf4, 0x4d, 0x72, 0x3e, 0xd2, 0x50, 0x78, 0xbf, 0xbb, 0x8e, 0x65, 0xbd, 0x1, 0xdb, 0x26, +0x0, 0x3d, 0x8a, 0x6c, 0x3e, 0x74, 0x13, 0x79, 0xbf, 0xe0, 0xeb, 0xe7, 0x3a, 0x1, 0xdb, 0x26, 0x0, 0x45, 0xc6, 0x40, +0x3e, 0xd3, 0x10, 0x79, 0xbf, 0x3d, 0x62, 0x9, 0xbe, 0x1, 0xdb, 0x26, 0x0, 0xff, 0x27, 0x2, 0x3e, 0x13, 0x46, 0x65, +0xb1, 0x73, 0xec, 0x7d, 0xbf, 0x1, 0xdb, 0x26, 0x0, 0xec, 0x68, 0x79, 0x3f, 0xb, 0x2b, 0x1e, 0xb1, 0x8f, 0xd9, 0x66, +0xbe, 0x1, 0xdb, 0x26, 0x0, 0x8, 0xa2, 0xc, 0x3f, 0xbf, 0x5a, 0x61, 0xb3, 0x7f, 0xe9, 0x55, 0x3f, 0x1, 0xdb, 0x26, +0x0, 0x4, 0xe7, 0xc, 0x3f, 0xa6, 0x78, 0xee, 0x30, 0x15, 0xbc, 0x55, 0x3f, 0x1, 0xdb, 0x26, 0x0, 0x27, 0x8, 0x5b, +0xbe, 0x5b, 0x7c, 0x75, 0xbf, 0x45, 0xc2, 0x3e, 0xbe, 0x1, 0xdb, 0x26, 0x0, 0x6b, 0xf5, 0x63, 0x3e, 0xe, 0x6d, 0x78, +0xbf, 0x3d, 0x73, 0xbf, 0x3d, 0x1, 0xdb, 0x26, 0x0, 0xd6, 0x14, 0x65, 0x3e, 0xb4, 0x63, 0x78, 0xbf, 0xe7, 0x1b, 0xbd, +0x3d, 0x1, 0xdb, 0x26, 0x0, 0xad, 0x22, 0x3e, 0x3e, 0x8b, 0x18, 0x79, 0xbf, 0xb3, 0x28, 0xc, 0x3e, 0x1, 0xdb, 0x26, +0x0, 0x5c, 0x79, 0x2f, 0x3f, 0xa2, 0x13, 0x8d, 0x34, 0x55, 0x66, 0x3a, 0xbf, 0x1, 0xdb, 0x26, 0x0, 0xaf, 0xbc, 0x6b, +0x3f, 0x7d, 0x43, 0x96, 0xaf, 0xe3, 0xa3, 0xc7, 0x3e, 0x1, 0xdb, 0x26, 0x0, 0x80, 0x8c, 0x40, 0xbd, 0x74, 0xce, 0x5d, +0x31, 0x8d, 0xb7, 0x7f, 0x3f, 0x1, 0xdc, 0x26, 0x0, 0xd7, 0x4b, 0x82, 0xbd, 0x89, 0x79, 0x75, 0xbf, 0x7a, 0x9a, 0x8d, +0xbe, 0x1, 0x0, 0x26, 0x0, 0xf1, 0xc5, 0xff, 0x3d, 0x92, 0x76, 0x78, 0xbf, 0xe1, 0xe5, 0x52, 0x3e, 0x1, 0x0, 0x26, +0x0, 0x12, 0xe, 0x1, 0x3e, 0x50, 0x7c, 0x78, 0xbf, 0xa3, 0xc2, 0x51, 0x3e, 0x1, 0x0, 0x26, 0x0, 0x33, 0x88, 0x8e, +0x3d, 0x26, 0x1e, 0x79, 0xbf, 0x24, 0xd1, 0x60, 0x3e, 0x1, 0x0, 0x26, 0x0, 0x5d, 0x7f, 0x7b, 0x3f, 0xe2, 0xb0, 0x16, +0xb1, 0xf9, 0x34, 0x3f, 0xbe, 0x1, 0x0, 0x26, 0x0, 0x2c, 0xd, 0x4, 0x3f, 0x3c, 0xad, 0xff, 0x30, 0x42, 0x50, 0x5b, +0x3f, 0x1, 0x0, 0x26, 0x0, 0x5b, 0x26, 0x20, 0xbf, 0xcb, 0x29, 0x9c, 0xb4, 0x4b, 0xb8, 0x47, 0x3f, 0x1, 0x0, 0x26, +0x0, 0x5, 0x5c, 0xe3, 0x3d, 0xab, 0x77, 0x75, 0xbf, 0xc8, 0xc6, 0x85, 0xbe, 0x1, 0x0, 0x26, 0x0, 0x9, 0x56, 0xa6, +0xbc, 0xa8, 0x7e, 0x78, 0xbf, 0xf7, 0x40, 0x75, 0x3e, 0x1, 0x0, 0x26, 0x0, 0xb1, 0x20, 0x9d, 0xbc, 0x41, 0x91, 0x78, +0xbf, 0x1a, 0x2b, 0x74, 0x3e, 0x1, 0x0, 0x26, 0x0, 0x8e, 0x58, 0x95, 0xbd, 0x21, 0x22, 0x79, 0xbf, 0x5b, 0x6e, 0x5f, +0x3e, 0x1, 0x0, 0x26, 0x0, 0x22, 0x9a, 0x67, 0x3f, 0x13, 0xe0, 0x2c, 0xb4, 0x56, 0x24, 0xda, 0x3e, 0x1, 0x0, 0x26, +0x0, 0xdb, 0xbb, 0x67, 0x3f, 0x83, 0xeb, 0x16, 0xaf, 0xe6, 0x94, 0xd9, 0x3e, 0x1, 0x0, 0x26, 0x0, 0x6e, 0x40, 0xb1, +0xbd, 0x26, 0xab, 0x61, 0x31, 0x16, 0xa, 0x7f, 0x3f, 0x1, 0x0, 0x26, 0x0, 0xc1, 0xfe, 0x76, 0xbf, 0xea, 0x89, 0xda, +0x33, 0x9, 0x9a, 0x86, 0x3e, 0x1, 0x0, 0x26, 0x0, 0xf5, 0x27, 0x79, 0x3e, 0x77, 0x77, 0x75, 0xbf, 0xa7, 0xc8, 0x15, +0xbe, 0x1, 0x0, 0x26, 0x0, 0xaa, 0x46, 0x21, 0xbe, 0x3c, 0x82, 0x78, 0xbf, 0xbc, 0xa2, 0x39, 0x3e, 0x1, 0x0, 0x26, +0x0, 0x3e, 0x2e, 0x20, 0xbe, 0x84, 0x9a, 0x78, 0xbf, 0x9f, 0x8c, 0x38, 0x3e, 0x1, 0x0, 0x26, 0x0, 0x75, 0xec, 0x3f, +0xbe, 0xf6, 0x22, 0x79, 0xbf, 0x52, 0x84, 0x8, 0x3e, 0x1, 0x0, 0x26, 0x0, 0xc, 0x87, 0xf6, 0x3e, 0x4b, 0xd, 0x32, +0x35, 0xce, 0x5e, 0x60, 0x3f, 0x1, 0x0, 0x26, 0x0, 0xf7, 0x14, 0xf7, 0x3e, 0xd8, 0x4f, 0x51, 0x35, 0xc4, 0x37, 0x60, +0x3f, 0x1, 0x0, 0x26, 0x0, 0x45, 0xf0, 0x27, 0xbf, 0x6f, 0x9a, 0xb5, 0x34, 0x72, 0x37, 0x41, 0x3f, 0x1, 0x0, 0x26, +0x0, 0x80, 0x58, 0x6f, 0xbf, 0x1, 0xd5, 0xdf, 0x2f, 0xaf, 0xa7, 0xb5, 0xbe, 0x1, 0xa1, 0x26, 0x0, 0x27, 0x3d, 0x6f, +0xbf, 0xd5, 0x8d, 0xdd, 0x2f, 0x8d, 0x37, 0xb6, 0xbe, 0x1, 0x2, 0x26, 0x0, 0x96, 0xc5, 0x90, 0x3e, 0x1, 0x79, 0x75, +0xbf, 0xee, 0xfe, 0xc8, 0x3c, 0x1, 0x2, 0x26, 0x0, 0x93, 0xde, 0x6f, 0xbe, 0xed, 0x7f, 0x78, 0xbf, 0x3a, 0x45, 0x5b, +0x3d, 0x1, 0x2, 0x26, 0x0, 0x1d, 0xca, 0x6e, 0xbe, 0x8b, 0x94, 0x78, 0xbf, 0x8b, 0xb6, 0x56, 0x3d, 0x1, 0x2, 0x26, +0x0, 0x9a, 0xae, 0x6b, 0xbe, 0x55, 0x20, 0x79, 0xbf, 0x63, 0xef, 0x2d, 0xbb, 0x1, 0x2, 0x26, 0x0, 0xe9, 0xf8, 0x0, +0xbe, 0xe, 0x2d, 0x65, 0x31, 0x1e, 0xf6, 0x7d, 0x3f, 0x1, 0x2, 0x26, 0x0, 0xbb, 0x77, 0x79, 0xbf, 0x31, 0x9, 0x90, +0x34, 0xfb, 0xd8, 0x65, 0x3e, 0x1, 0x2, 0x26, 0x0, 0xf4, 0x3b, 0xc, 0xbf, 0xd0, 0x39, 0x70, 0xb3, 0x78, 0x2c, 0x56, +0xbf, 0x1, 0x2, 0x26, 0x0, 0xeb, 0xf6, 0xb, 0xbf, 0x77, 0xa6, 0xa, 0xb4, 0x9b, 0x59, 0x56, 0xbf, 0x1, 0x2, 0x26, +0x0, 0x5e, 0x69, 0x5b, 0x3e, 0xb3, 0x7b, 0x75, 0xbf, 0xfe, 0x5f, 0x3e, 0x3e, 0x1, 0x2, 0x26, 0x0, 0xf1, 0x8a, 0x62, +0xbe, 0x9d, 0x78, 0x78, 0xbf, 0x78, 0x66, 0xc2, 0xbd, 0x1, 0x2, 0x26, 0x0, 0xfa, 0x6a, 0x61, 0xbe, 0x9c, 0x81, 0x78, +0xbf, 0xdc, 0xbd, 0xc4, 0xbd, 0x1, 0x2, 0x26, 0x0, 0xea, 0x3c, 0x3d, 0xbe, 0x3e, 0x1b, 0x79, 0xbf, 0x23, 0x12, 0xd, +0xbe, 0x1, 0x2, 0x26, 0x0, 0x9d, 0x76, 0x2f, 0xbf, 0x37, 0xbd, 0x6a, 0x31, 0xea, 0x68, 0x3a, 0x3f, 0x1, 0x2, 0x26, +0x0, 0xa3, 0x8f, 0x6b, 0xbf, 0xa9, 0xd6, 0x92, 0x2f, 0x23, 0x78, 0xc8, 0xbe, 0x1, 0x1, 0x26, 0x0, 0x47, 0xca, 0x45, +0x3d, 0xd1, 0xef, 0x5d, 0xb1, 0x8c, 0xb3, 0x7f, 0xbf, 0x1, 0x1, 0x26, 0x0, 0x9, 0x12, 0x83, 0x3d, 0x85, 0x7e, 0x75, +0xbf, 0x75, 0x6c, 0x8d, 0x3e, 0x1, 0x1, 0x26, 0x0, 0x1e, 0xd4, 0xfc, 0xbd, 0x1a, 0x6f, 0x78, 0xbf, 0xa7, 0x54, 0x54, +0xbe, 0x1, 0x1, 0x26, 0x0, 0xcb, 0x7d, 0xfa, 0xbd, 0x0, 0x69, 0x78, 0xbf, 0x69, 0x77, 0x55, 0xbe, 0x1, 0x1, 0x26, +0x0, 0xb0, 0xb3, 0x8c, 0xbd, 0xa3, 0x15, 0x79, 0xbf, 0x54, 0xb1, 0x61, 0xbe, 0x1, 0x1, 0x26, 0x0, 0x76, 0x8c, 0x7b, +0xbf, 0x2c, 0x97, 0x9c, 0xb3, 0x8a, 0x20, 0x3e, 0x3e, 0x1, 0x1, 0x26, 0x0, 0xc5, 0xa5, 0x3, 0xbf, 0x8c, 0x38, 0x0, +0xb1, 0x64, 0x8e, 0x5b, 0xbf, 0x1, 0x1, 0x26, 0x0, 0xf8, 0x30, 0x20, 0x3f, 0x18, 0xfa, 0x3d, 0x32, 0xc8, 0xaf, 0x47, +0xbf, 0x1, 0x1, 0x26, 0x0, 0x8e, 0xa0, 0xe2, 0xbd, 0x63, 0x80, 0x75, 0xbf, 0xa5, 0x9a, 0x85, 0x3e, 0x1, 0x1, 0x26, +0x0, 0x6e, 0xee, 0xb1, 0x3c, 0x4, 0x67, 0x78, 0xbf, 0xad, 0x9e, 0x76, 0xbe, 0x1, 0x1, 0x26, 0x0, 0x7a, 0x20, 0xbb, +0x3c, 0x16, 0x54, 0x78, 0xbf, 0xd6, 0xb3, 0x77, 0xbe, 0x1, 0x1, 0x26, 0x0, 0x5d, 0x1e, 0x97, 0x3d, 0xa8, 0x11, 0x79, +0xbf, 0x79, 0x47, 0x60, 0xbe, 0x1, 0x1, 0x26, 0x0, 0x5, 0x68, 0x67, 0xbf, 0x9d, 0x35, 0xb, 0x2f, 0xac, 0xf8, 0xda, +0xbe, 0x1, 0x1, 0x26, 0x0, 0x0, 0x46, 0x67, 0xbf, 0x88, 0x7a, 0x6, 0x2f, 0x3e, 0x88, 0xdb, 0xbe, 0x1, 0x1, 0x26, +0x0, 0x3a, 0xbd, 0xb3, 0x3d, 0x22, 0xc8, 0x61, 0xb1, 0x1f, 0x3, 0x7f, 0xbf, 0x1, 0x1, 0x26, 0x0, 0x7a, 0xee, 0x76, +0x3f, 0x0, 0x66, 0x25, 0xb1, 0x4b, 0x11, 0x87, 0xbe, 0x1, 0x0, 0x26, 0x0, 0xab, 0xa7, 0x22, 0x3e, 0x71, 0x63, 0x78, +0xbf, 0xdb, 0x0, 0x3b, 0xbe, 0x1, 0x0, 0x26, 0x0, 0x6c, 0xbf, 0x23, 0x3e, 0xdc, 0x4a, 0x78, 0xbf, 0x3d, 0x16, 0x3c, +0xbe, 0x1, 0x0, 0x26, 0x0, 0x13, 0xb5, 0xf5, 0xbe, 0xf9, 0xcd, 0x17, 0x33, 0x5b, 0x98, 0x60, 0xbf, 0x1, 0xbe, 0x26, +0x0, 0x26, 0x27, 0xf5, 0xbe, 0x96, 0x27, 0xb8, 0x33, 0x1e, 0xbf, 0x60, 0xbf, 0x1, 0x0, 0x26, 0x0, 0xc9, 0xf6, 0x27, +0x3f, 0x74, 0xfa, 0x23, 0x34, 0xc7, 0x31, 0x41, 0xbf, 0x1, 0x0, 0x26, 0x0, 0xc3, 0x80, 0x6f, 0x3f, 0xc4, 0x32, 0xe3, +0xaf, 0xee, 0xd2, 0xb4, 0x3e, 0x1, 0xe0, 0x26, 0x0, 0xd4, 0x9b, 0x6f, 0x3f, 0x2c, 0x78, 0xe5, 0xaf, 0x49, 0x43, 0xb4, +0x3e, 0x1, 0xe0, 0x26, 0x0, 0x69, 0x5a, 0x90, 0xbe, 0xaf, 0x7f, 0x75, 0xbf, 0x1, 0x62, 0xf1, 0xbc, 0x1, 0xd5, 0x29, +0x0, 0x1b, 0xb0, 0x57, 0xbe, 0xba, 0x80, 0x75, 0xbf, 0xc8, 0x2f, 0x42, 0xbe, 0x1, 0xd5, 0x29, 0x0, 0xbe, 0x18, 0x23, +0x38, 0x0, 0x0, 0x80, 0xbf, 0x7b, 0xf6, 0x23, 0x38, 0x1, 0xd5, 0x29, 0x0, 0xbf, 0x35, 0x62, 0x3e, 0x70, 0x64, 0x78, +0xbf, 0x15, 0x3d, 0xca, 0x3d, 0x1, 0xd5, 0x29, 0x0, 0xb5, 0x48, 0x63, 0x3e, 0x6a, 0x4d, 0x78, 0xbf, 0x2f, 0x7a, 0xcc, +0x3d, 0x1, 0xd5, 0x29, 0x0, 0x38, 0xa1, 0x3b, 0x3e, 0xc7, 0x10, 0x79, 0xbf, 0xf5, 0x55, 0x10, 0x3e, 0x1, 0xd5, 0x29, +0x0, 0xa3, 0x76, 0x6c, 0x3e, 0x39, 0x13, 0x79, 0xbf, 0x2a, 0xc8, 0xda, 0x3b, 0x1, 0xd5, 0x29, 0x0, 0x80, 0xde, 0x32, +0x3f, 0x53, 0x30, 0xbe, 0x2f, 0xf2, 0x24, 0x37, 0xbf, 0x1, 0xd5, 0x29, 0x0, 0x15, 0xd5, 0x69, 0x3f, 0xc, 0xb, 0xfc, +0x30, 0x5b, 0x68, 0xd0, 0x3e, 0x1, 0xd5, 0x29, 0x0, 0x8b, 0xce, 0x83, 0xbd, 0x56, 0xf0, 0x7e, 0x30, 0x22, 0x78, 0x7f, +0x3f, 0x1, 0xd5, 0x29, 0x0, 0x77, 0xd2, 0x70, 0xbd, 0xf9, 0x7f, 0x75, 0xbf, 0xb7, 0xf9, 0x8d, 0xbe, 0x1, 0xd5, 0x29, +0x0, 0x8c, 0x46, 0xf8, 0x3d, 0xef, 0x63, 0x78, 0xbf, 0xc1, 0x7a, 0x56, 0x3e, 0x1, 0xd5, 0x29, 0x0, 0x95, 0x7e, 0xfa, +0x3d, 0x1f, 0x4c, 0x78, 0xbf, 0x24, 0x8e, 0x57, 0x3e, 0x1, 0xd5, 0x29, 0x0, 0x43, 0x9f, 0x86, 0x3d, 0xd0, 0x11, 0x79, +0xbf, 0x61, 0xe1, 0x62, 0x3e, 0x1, 0xd5, 0x29, 0x0, 0xa0, 0x59, 0x7c, 0x3f, 0xbc, 0xe, 0xba, 0x30, 0x76, 0x4c, 0x2c, +0xbe, 0x1, 0xd5, 0x29, 0x0, 0x27, 0x65, 0x7c, 0x3f, 0xc0, 0x3d, 0xba, 0x30, 0x8a, 0x3d, 0x2b, 0xbe, 0x1, 0xd5, 0x29, +0x0, 0xf6, 0xd, 0x0, 0x3f, 0xd2, 0xfc, 0xe4, 0x30, 0xc7, 0xab, 0x5d, 0x3f, 0x1, 0xd5, 0x29, 0x0, 0xcb, 0x71, 0x23, +0xbf, 0xab, 0xa7, 0x16, 0x35, 0x61, 0x8, 0x45, 0x3f, 0x1, 0xd5, 0x29, 0x0, 0xd4, 0xad, 0xec, 0x3d, 0xb7, 0x7d, 0x75, +0xbf, 0x6f, 0x96, 0x84, 0xbe, 0x1, 0xd5, 0x29, 0x0, 0xf, 0x95, 0xc8, 0xbc, 0x1f, 0x69, 0x78, 0xbf, 0x15, 0x37, 0x76, +0x3e, 0x1, 0xd5, 0x29, 0x0, 0xa0, 0x48, 0xbf, 0xbc, 0x89, 0x59, 0x78, 0xbf, 0x9e, 0x4f, 0x77, 0x3e, 0x1, 0xd5, 0x29, +0x0, 0x6a, 0x1b, 0x9d, 0xbd, 0xf0, 0x15, 0x79, 0xbf, 0xe, 0xf3, 0x5e, 0x3e, 0x1, 0xd5, 0x29, 0x0, 0xb, 0x87, 0x65, +0x3f, 0xea, 0xd7, 0x1c, 0x34, 0x43, 0xbe, 0xe2, 0x3e, 0x1, 0xd5, 0x29, 0x0, 0x27, 0x92, 0xd4, 0xbd, 0xb4, 0x34, 0x6d, +0x30, 0x7, 0x9e, 0x7e, 0x3f, 0x1, 0xd5, 0x29, 0x0, 0xed, 0xc, 0x78, 0xbf, 0xc9, 0x5, 0x9a, 0x34, 0xbd, 0x33, 0x7d, +0x3e, 0x1, 0xd5, 0x29, 0x0, 0xef, 0xfa, 0x77, 0xbf, 0x4a, 0x18, 0xab, 0xb0, 0x27, 0x4d, 0x7e, 0x3e, 0x1, 0xd5, 0x29, +0x0, 0xf8, 0xbd, 0x7b, 0x3e, 0xd0, 0x7a, 0x75, 0xbf, 0xcc, 0xa, 0x11, 0xbe, 0x1, 0xd5, 0x29, 0x0, 0x26, 0x76, 0x24, +0xbe, 0x7, 0x72, 0x78, 0xbf, 0x4, 0x31, 0x38, 0x3e, 0x1, 0xe8, 0x29, 0x0, 0x6, 0x4d, 0x23, 0xbe, 0x90, 0x70, 0x78, +0xbf, 0x1, 0x58, 0x39, 0x3e, 0x1, 0xe8, 0x29, 0x0, 0xa, 0x43, 0x42, 0xbe, 0x93, 0x1b, 0x79, 0xbf, 0x8c, 0x7, 0x6, +0x3e, 0x1, 0xe8, 0x29, 0x0, 0x8b, 0x5f, 0xee, 0x3e, 0x1, 0x38, 0x0, 0x35, 0xfe, 0x8f, 0x62, 0x3f, 0x1, 0xe8, 0x29, +0x0, 0xf7, 0x1d, 0x2b, 0xbf, 0xee, 0x58, 0x94, 0xaf, 0x48, 0x68, 0x3e, 0x3f, 0x1, 0xe8, 0x29, 0x0, 0xa6, 0xd7, 0x6d, +0xbf, 0x82, 0x1f, 0xfa, 0xb0, 0x7c, 0x63, 0xbd, 0xbe, 0x1, 0xe8, 0x29, 0x0, 0x4, 0x87, 0x90, 0x3e, 0x5f, 0x78, 0x75, +0xbf, 0xf7, 0x69, 0xf4, 0x3c, 0x1, 0xe8, 0x29, 0x0, 0xc6, 0xc8, 0x70, 0xbe, 0x3e, 0x7b, 0x78, 0xbf, 0x8, 0x42, 0x50, +0x3d, 0x1, 0xe9, 0x29, 0x0, 0x57, 0xad, 0x6f, 0xbe, 0x69, 0x88, 0x78, 0xbf, 0xdb, 0xed, 0x54, 0x3d, 0x1, 0xe9, 0x29, +0x0, 0x76, 0x9b, 0x6b, 0xbe, 0x92, 0x20, 0x79, 0xbf, 0x29, 0xd5, 0xbd, 0xbb, 0x1, 0xe9, 0x29, 0x0, 0x27, 0x7f, 0x12, +0xbe, 0x78, 0x1a, 0x5b, 0x30, 0xde, 0x5d, 0x7d, 0x3f, 0x1, 0xe9, 0x29, 0x0, 0x29, 0x74, 0x11, 0xbe, 0x1b, 0x94, 0x5b, +0x30, 0x7b, 0x67, 0x7d, 0x3f, 0x1, 0xe9, 0x29, 0x0, 0x3, 0x5d, 0x7a, 0xbf, 0x94, 0xaf, 0xb2, 0xb0, 0xd, 0xb3, 0x55, +0x3e, 0x1, 0xe9, 0x29, 0x0, 0xac, 0xa1, 0x8, 0xbf, 0xde, 0x41, 0xe9, 0xb0, 0x62, 0x7d, 0x58, 0xbf, 0x1, 0xe9, 0x29, +0x0, 0xa3, 0x9, 0x58, 0x3e, 0x54, 0x77, 0x75, 0xbf, 0x41, 0x8a, 0x42, 0x3e, 0x1, 0xe9, 0x29, 0x0, 0xd9, 0xda, 0x60, +0xbe, 0x40, 0x81, 0x78, 0xbf, 0xf, 0x6a, 0xc7, 0xbd, 0x1, 0xe9, 0x29, 0x0, 0x1d, 0xc7, 0x5f, 0xbe, 0xf6, 0x97, 0x78, +0xbf, 0xb3, 0x2b, 0xc5, 0xbd, 0x1, 0xe9, 0x29, 0x0, 0x21, 0xc7, 0x3a, 0xbe, 0x4, 0x23, 0x79, 0xbf, 0x98, 0x78, 0xf, +0xbe, 0x1, 0xe9, 0x29, 0x0, 0x29, 0x85, 0x32, 0xbf, 0xa8, 0x46, 0xbc, 0xaf, 0x7, 0x7c, 0x37, 0x3f, 0x1, 0xe9, 0x29, +0x0, 0x35, 0xe7, 0x69, 0xbf, 0xa0, 0x3, 0xfc, 0xb0, 0xf1, 0x16, 0xd0, 0xbe, 0x1, 0xe9, 0x29, 0x0, 0x64, 0xbb, 0x86, +0x3d, 0xe5, 0x4d, 0x7e, 0xb0, 0x7, 0x72, 0x7f, 0xbf, 0x1, 0xe9, 0x29, 0x0, 0xcc, 0x51, 0x72, 0x3d, 0x15, 0x78, 0x75, +0xbf, 0x1b, 0x26, 0x8e, 0x3e, 0x1, 0xea, 0x29, 0x0, 0x10, 0x7a, 0xf5, 0xbd, 0xbf, 0x81, 0x78, 0xbf, 0x44, 0x1f, 0x55, +0xbe, 0x1, 0xea, 0x29, 0x0, 0xba, 0x40, 0xf3, 0xbd, 0x41, 0x99, 0x78, 0xbf, 0x24, 0xb, 0x54, 0xbe, 0x1, 0xea, 0x29, +0x0, 0x4b, 0xd8, 0x84, 0xbd, 0xf9, 0x21, 0x79, 0xbf, 0x21, 0x8, 0x62, 0xbe, 0x1, 0xea, 0x29, 0x0, 0x69, 0x48, 0x7c, +0xbf, 0x2b, 0x2, 0x86, 0x33, 0xfc, 0xdd, 0x2d, 0x3e, 0x1, 0xea, 0x29, 0x0, 0xab, 0x3c, 0x7c, 0xbf, 0xfb, 0xa1, 0x1f, +0x34, 0xbf, 0xed, 0x2e, 0x3e, 0x1, 0xea, 0x29, 0x0, 0x31, 0xe4, 0xff, 0xbe, 0x90, 0x26, 0xcf, 0xb4, 0xde, 0xbb, 0x5d, +0xbf, 0x1, 0xea, 0x29, 0x0, 0x57, 0xd1, 0x23, 0x3f, 0xf1, 0x36, 0x5c, 0x2f, 0xf8, 0xb8, 0x44, 0xbf, 0x1, 0xea, 0x29, +0x0, 0xf8, 0xe6, 0xeb, 0xbd, 0x56, 0x7a, 0x75, 0xbf, 0x91, 0xc5, 0x84, 0x3e, 0x1, 0xea, 0x29, 0x0, 0x1d, 0x4e, 0xd4, +0x3c, 0x8e, 0x7c, 0x78, 0xbf, 0xe, 0xd5, 0x74, 0xbe, 0x1, 0xea, 0x29, 0x0, 0x5, 0x9d, 0xdd, 0x3c, 0xcc, 0x8b, 0x78, +0xbf, 0xe0, 0xbb, 0x73, 0xbe, 0x1, 0xea, 0x29, 0x0, 0x13, 0xf0, 0x9e, 0x3d, 0xd9, 0x1d, 0x79, 0xbf, 0x28, 0x12, 0x5e, +0xbe, 0x1, 0xea, 0x29, 0x0, 0xc3, 0x98, 0x65, 0xbf, 0x62, 0x82, 0xfd, 0xb0, 0x79, 0x76, 0xe2, 0xbe, 0x1, 0xea, 0x29, +0x0, 0x5, 0x93, 0xd7, 0x3d, 0xb0, 0x89, 0x6c, 0xb0, 0xed, 0x93, 0x7e, 0xbf, 0x1, 0xeb, 0x29, 0x0, 0x5e, 0x27, 0x78, +0x3f, 0x91, 0x9d, 0xab, 0x30, 0xe4, 0x93, 0x7b, 0xbe, 0x1, 0xeb, 0x29, 0x0, 0x19, 0x39, 0x78, 0x3f, 0x12, 0xd3, 0xab, +0x30, 0x54, 0x7b, 0x7a, 0xbe, 0x1, 0xeb, 0x29, 0x0, 0x9f, 0x5e, 0x7b, 0xbe, 0x3e, 0x7d, 0x75, 0xbf, 0x24, 0x6e, 0x11, +0x3e, 0x1, 0xeb, 0x29, 0x0, 0x44, 0xec, 0x25, 0x3e, 0xa5, 0x73, 0x78, 0xbf, 0xc, 0xbd, 0x36, 0xbe, 0x1, 0xeb, 0x29, +0x0, 0x19, 0x15, 0x27, 0x3e, 0xbf, 0x74, 0x78, 0xbf, 0xbe, 0x95, 0x35, 0xbe, 0x1, 0xeb, 0x29, 0x0, 0x33, 0x28, 0x43, +0x3e, 0x37, 0x18, 0x79, 0xbf, 0xd4, 0x1d, 0x5, 0xbe, 0x1, 0xeb, 0x29, 0x0, 0xf6, 0x1d, 0xee, 0xbe, 0xf5, 0xed, 0x4e, +0xb4, 0x3c, 0xa1, 0x62, 0xbf, 0x1, 0xeb, 0x29, 0x0, 0x35, 0x7a, 0x2b, 0x3f, 0xe3, 0xa6, 0x4e, 0xb2, 0x3a, 0x15, 0x3e, +0xbf, 0x1, 0xeb, 0x29, 0x0, 0x64, 0xc5, 0x6d, 0x3f, 0xa3, 0x29, 0xfa, 0x30, 0x1a, 0xbf, 0xbd, 0x3e, 0x1, 0xeb, 0x29, +0x0, 0x86, 0x2d, 0x72, 0x3e, 0x70, 0x6a, 0x78, 0xbf, 0x52, 0x5f, 0x4a, 0xbd, 0x1, 0xeb, 0x29, 0x0, 0x69, 0x48, 0x73, +0x3e, 0xeb, 0x5c, 0x78, 0xbf, 0x3c, 0xb4, 0x45, 0xbd, 0x1, 0xeb, 0x29, 0x0, 0x36, 0xb, 0x14, 0x3e, 0xe1, 0x65, 0x5a, +0xb0, 0x7b, 0x4f, 0x7d, 0xbf, 0x1, 0xeb, 0x29, 0x0, 0x1c, 0x17, 0x15, 0x3e, 0xa0, 0xeb, 0x59, 0xb0, 0xa8, 0x45, 0x7d, +0xbf, 0x1, 0xeb, 0x29, 0x0, 0xae, 0x72, 0x7a, 0x3f, 0xf2, 0xf9, 0xb2, 0x30, 0x2a, 0x1b, 0x54, 0xbe, 0x1, 0xec, 0x29, +0x0, 0xe1, 0xb8, 0x8, 0x3f, 0x13, 0x4d, 0xe9, 0x30, 0xbc, 0x6e, 0x58, 0x3f, 0x1, 0xec, 0x29, 0x0, 0xf0, 0xc2, 0x8f, +0xbe, 0xed, 0x7e, 0x75, 0xbf, 0x3f, 0xc6, 0x20, 0xbd, 0x1, 0xec, 0x2f, 0x0, 0xe5, 0xd3, 0x50, 0xbe, 0x8d, 0x80, 0x75, +0xbf, 0x30, 0x8f, 0x49, 0xbe, 0x1, 0xec, 0x2f, 0x0, 0x2a, 0xa1, 0xe6, 0x37, 0x0, 0x0, 0x80, 0xbf, 0xfa, 0xa1, 0x48, +0x38, 0x1, 0xec, 0x2f, 0x0, 0x76, 0x5c, 0x5e, 0x3e, 0xc, 0x66, 0x78, 0xbf, 0x39, 0x30, 0xda, 0x3d, 0x1, 0xec, 0x2f, +0x0, 0x58, 0x1b, 0x5f, 0x3e, 0x96, 0x51, 0x78, 0xbf, 0xf6, 0xf2, 0xdc, 0x3d, 0x1, 0xec, 0x2f, 0x0, 0xf2, 0x5c, 0x36, +0x3e, 0x48, 0x11, 0x79, 0xbf, 0x3e, 0xe2, 0x16, 0x3e, 0x1, 0xec, 0x2f, 0x0, 0x62, 0xf8, 0x6b, 0x3e, 0xd0, 0x14, 0x79, +0xbf, 0x45, 0xc1, 0x72, 0x3c, 0x1, 0xec, 0x2f, 0x0, 0xb8, 0x25, 0x39, 0x3f, 0x2, 0x63, 0x6, 0xb4, 0x84, 0xcb, 0x30, +0xbf, 0x1, 0xec, 0x2f, 0x0, 0x24, 0x8, 0x66, 0x3f, 0x22, 0xd7, 0x8e, 0x31, 0x95, 0xb0, 0xe0, 0x3e, 0x1, 0xec, 0x2f, +0x0, 0xb2, 0x61, 0xcb, 0xbd, 0xc1, 0xba, 0xc9, 0x30, 0xb, 0xbc, 0x7e, 0x3f, 0x1, 0xec, 0x2f, 0x0, 0x81, 0x3b, 0x49, +0xbd, 0x73, 0x80, 0x75, 0xbf, 0x29, 0xec, 0x8e, 0xbe, 0x1, 0xec, 0x2f, 0x0, 0xe8, 0xc6, 0xe8, 0x3d, 0x6a, 0x63, 0x78, +0xbf, 0x81, 0xd1, 0x5a, 0x3e, 0x1, 0xed, 0x2f, 0x0, 0x4f, 0x52, 0xea, 0x3d, 0xc9, 0x4a, 0x78, 0xbf, 0x3a, 0x26, 0x5c, +0x3e, 0x1, 0xed, 0x2f, 0x0, 0x26, 0xf0, 0x6c, 0x3d, 0x8, 0x11, 0x79, 0xbf, 0xc2, 0x2c, 0x65, 0x3e, 0x1, 0xed, 0x2f, +0x0, 0xd, 0xb4, 0x7d, 0x3f, 0x1e, 0xb1, 0x0, 0xb4, 0xab, 0xdb, 0x8, 0xbe, 0x1, 0xed, 0x2f, 0x0, 0x6a, 0xbe, 0x7d, +0x3f, 0xa1, 0xb8, 0x99, 0xb4, 0xd1, 0xa6, 0x7, 0xbe, 0x1, 0xed, 0x2f, 0x0, 0x65, 0x62, 0xf0, 0x3e, 0xb9, 0xea, 0x17, +0x32, 0xd7, 0x7, 0x62, 0x3f, 0x1, 0xed, 0x2f, 0x0, 0xd9, 0x3a, 0x2a, 0xbf, 0xb1, 0x9, 0x9d, 0x34, 0x70, 0x33, 0x3f, +0x3f, 0x1, 0xed, 0x2f, 0x0, 0x33, 0xf3, 0xfe, 0x3d, 0xa8, 0x7e, 0x75, 0xbf, 0xf7, 0x6c, 0x82, 0xbe, 0x1, 0xed, 0x2f, +0x0, 0x2b, 0x59, 0x7, 0xbd, 0xad, 0x66, 0x78, 0xbf, 0xc5, 0x51, 0x75, 0x3e, 0x1, 0xed, 0x2f, 0x0, 0x54, 0x9, 0x4, +0xbd, 0x36, 0x53, 0x78, 0xbf, 0xf9, 0xa8, 0x76, 0x3e, 0x1, 0xed, 0x2f, 0x0, 0x53, 0xcd, 0xac, 0xbd, 0x2c, 0x14, 0x79, +0xbf, 0xf4, 0x26, 0x5c, 0x3e, 0x1, 0xed, 0x2f, 0x0, 0x3e, 0x68, 0x61, 0x3f, 0xe8, 0x11, 0xbd, 0x34, 0xf6, 0xb6, 0xf2, +0x3e, 0x1, 0xed, 0x2f, 0x0, 0x0, 0xec, 0xd, 0xbe, 0xa0, 0xd6, 0xd1, 0x33, 0x85, 0x87, 0x7d, 0x3f, 0x1, 0xed, 0x2f, +0x0, 0x91, 0x1a, 0x7a, 0xbf, 0x7f, 0xde, 0x4, 0x34, 0x2, 0x82, 0x5a, 0x3e, 0x1, 0xee, 0x2f, 0x0, 0x5f, 0x9, 0x7a, +0xbf, 0x96, 0xe3, 0x1c, 0x34, 0x11, 0xbc, 0x5b, 0x3e, 0x1, 0xee, 0x2f, 0x0, 0x8a, 0x4d, 0x80, 0x3e, 0xdd, 0x7b, 0x75, +0xbf, 0x40, 0x22, 0x8, 0xbe, 0x1, 0xee, 0x2f, 0x0, 0xd7, 0xf7, 0x2a, 0xbe, 0x94, 0x6e, 0x78, 0xbf, 0xf4, 0x77, 0x32, +0x3e, 0x1, 0xee, 0x2f, 0x0, 0xbf, 0x21, 0x2a, 0xbe, 0xa5, 0x67, 0x78, 0xbf, 0x91, 0xdd, 0x33, 0x3e, 0x1, 0xee, 0x2f, +0x0, 0x76, 0xee, 0x46, 0xbe, 0x7f, 0x19, 0x79, 0xbf, 0x4, 0x80, 0xfe, 0x3d, 0x1, 0xee, 0x2f, 0x0, 0xf9, 0x50, 0xde, +0x3e, 0x35, 0xa6, 0x62, 0x32, 0x8d, 0x9b, 0x66, 0x3f, 0x1, 0xee, 0x2f, 0x0, 0x25, 0xaa, 0x31, 0xbf, 0x63, 0x58, 0x20, +0x34, 0x21, 0x50, 0x38, 0x3f, 0x1, 0xee, 0x2f, 0x0, 0x6a, 0x69, 0x6a, 0xbf, 0x9, 0x43, 0xf5, 0x33, 0x9b, 0xc9, 0xcd, +0xbe, 0x1, 0xee, 0x2f, 0x0, 0x23, 0xe2, 0x8f, 0x3e, 0x22, 0x79, 0x75, 0xbf, 0x22, 0xa2, 0x22, 0x3d, 0x1, 0xee, 0x2f, +0x0, 0x61, 0xa1, 0x72, 0xbe, 0x1d, 0x78, 0x78, 0xbf, 0x25, 0x10, 0x2f, 0x3d, 0x1, 0xee, 0x2f, 0x0, 0xe4, 0xd7, 0x71, +0xbe, 0x51, 0x80, 0x78, 0xbf, 0xf4, 0xc0, 0x34, 0x3d, 0x1, 0xee, 0x2f, 0x0, 0x9, 0x5e, 0x6b, 0xbe, 0xfb, 0x1e, 0x79, +0xbf, 0xe9, 0x9, 0x61, 0xbc, 0x1, 0xee, 0x2f, 0x0, 0x98, 0xed, 0x35, 0xbe, 0x16, 0x5b, 0xbb, 0x33, 0x67, 0xed, 0x7b, +0x3f, 0x1, 0xee, 0x2f, 0x0, 0x30, 0x12, 0x7c, 0xbf, 0x5f, 0xf9, 0x96, 0x33, 0x1a, 0xb7, 0x32, 0x3e, 0x1, 0xef, 0x2f, +0x0, 0x36, 0xa, 0x1, 0xbf, 0xc1, 0x99, 0x43, 0xb1, 0x50, 0x19, 0x5d, 0xbf, 0x1, 0xef, 0x2f, 0x0, 0x5d, 0x11, 0x51, +0x3e, 0x81, 0x77, 0x75, 0xbf, 0xa3, 0xff, 0x49, 0x3e, 0x1, 0xef, 0x2f, 0x0, 0x81, 0x6b, 0x5d, 0xbe, 0xa3, 0x7f, 0x78, +0xbf, 0x6c, 0xb4, 0xd6, 0xbd, 0x1, 0xef, 0x2f, 0x0, 0x4, 0xac, 0x5c, 0xbe, 0xc7, 0x93, 0x78, 0xbf, 0x50, 0xf0, 0xd3, +0xbd, 0x1, 0xef, 0x2f, 0x0, 0x98, 0xc5, 0x35, 0xbe, 0x83, 0x22, 0x79, 0xbf, 0x9e, 0xd0, 0x15, 0xbe, 0x1, 0xef, 0x2f, +0x0, 0xe8, 0xd1, 0x38, 0xbf, 0xa9, 0x79, 0x9, 0x34, 0x20, 0x23, 0x31, 0x3f, 0x1, 0xef, 0x2f, 0x0, 0x93, 0x26, 0x66, +0xbf, 0x74, 0x64, 0xb3, 0x33, 0xc9, 0x33, 0xe0, 0xbe, 0x1, 0xef, 0x2f, 0x0, 0x95, 0xa5, 0xcd, 0x3d, 0x70, 0x90, 0x2d, +0xb3, 0xc5, 0xb4, 0x7e, 0xbf, 0x1, 0xef, 0x2f, 0x0, 0xf0, 0x48, 0x4a, 0x3d, 0x9a, 0x77, 0x75, 0xbf, 0xf5, 0x22, 0x8f, +0x3e, 0x1, 0xef, 0x2f, 0x0, 0xf5, 0xd3, 0xe6, 0xbd, 0x44, 0x82, 0x78, 0xbf, 0x91, 0x23, 0x59, 0xbe, 0x1, 0xef, 0x2f, +0x0, 0x8c, 0x47, 0xe5, 0xbd, 0x98, 0x9a, 0x78, 0xbf, 0xea, 0xcd, 0x57, 0xbe, 0x1, 0xef, 0x2f, 0x0, 0x1a, 0x71, 0x6a, +0xbd, 0xc2, 0x22, 0x79, 0xbf, 0xfc, 0x20, 0x64, 0xbe, 0x1, 0xef, 0x2f, 0x0, 0x83, 0xa4, 0x7d, 0xbf, 0xe2, 0x68, 0x6c, +0xb1, 0x78, 0xa5, 0xa, 0x3e, 0x1, 0xf0, 0x2f, 0x0, 0xe4, 0x99, 0x7d, 0xbf, 0xe7, 0x37, 0x6c, 0xb1, 0x4, 0xdb, 0xb, +0x3e, 0x1, 0xf0, 0x2f, 0x0, 0xb2, 0x5a, 0xf0, 0xbe, 0x2f, 0x10, 0xad, 0xb4, 0xe3, 0x9, 0x62, 0xbf, 0x1, 0xf0, 0x2f, +0x0, 0x50, 0x93, 0x2a, 0x3f, 0x1a, 0x81, 0x60, 0xb4, 0x88, 0xe4, 0x3e, 0xbf, 0x1, 0xf0, 0x2f, 0x0, 0x76, 0x63, 0xfe, +0xbd, 0x64, 0x79, 0x75, 0xbf, 0x19, 0xa6, 0x82, 0x3e, 0x1, 0xf0, 0x2f, 0x0, 0xc2, 0x85, 0xb, 0x3d, 0x1, 0x7f, 0x78, +0xbf, 0xa0, 0xa0, 0x73, 0xbe, 0x1, 0xf0, 0x2f, 0x0, 0x4a, 0xd6, 0xe, 0x3d, 0x25, 0x92, 0x78, 0xbf, 0x85, 0x48, 0x72, +0xbe, 0x1, 0xf0, 0x2f, 0x0, 0xc, 0x1d, 0xae, 0x3d, 0x9e, 0x1f, 0x79, 0xbf, 0xf8, 0x14, 0x5b, 0xbe, 0x1, 0xf0, 0x2f, +0x0, 0x55, 0x87, 0x61, 0xbf, 0x64, 0xc4, 0x8e, 0xb1, 0x50, 0x43, 0xf2, 0xbe, 0x1, 0xf0, 0x2f, 0x0, 0x3c, 0x1b, 0xf, +0x3e, 0x24, 0xca, 0xb3, 0xb0, 0xdd, 0x7c, 0x7d, 0xbf, 0x1, 0xf0, 0x2f, 0x0, 0xd5, 0x33, 0x7a, 0x3f, 0x2b, 0x4c, 0x5f, +0x31, 0x4a, 0xb1, 0x58, 0xbe, 0x1, 0xf0, 0x2f, 0x0, 0xc3, 0x44, 0x7a, 0x3f, 0xf8, 0x83, 0x5f, 0x31, 0xa3, 0x77, 0x57, +0xbe, 0x1, 0xf0, 0x2f, 0x0, 0x27, 0x2b, 0x80, 0xbe, 0x30, 0x7c, 0x75, 0xbf, 0x57, 0x9a, 0x8, 0x3e, 0x1, 0xf0, 0x2f, +0x0, 0x73, 0x5, 0x2c, 0x3e, 0x18, 0x77, 0x78, 0xbf, 0xfe, 0xb4, 0x30, 0xbe, 0x1, 0xf1, 0x2f, 0x0, 0x71, 0xdb, 0x2c, +0x3e, 0xaa, 0x7d, 0x78, 0xbf, 0xf6, 0x4e, 0x2f, 0xbe, 0x1, 0xf1, 0x2f, 0x0, 0xf1, 0x92, 0x47, 0x3e, 0x4b, 0x1a, 0x79, +0xbf, 0xba, 0x48, 0xfc, 0xbd, 0x1, 0xf1, 0x2f, 0x0, 0x25, 0x40, 0xde, 0xbe, 0xe0, 0x6e, 0x61, 0xb1, 0x9a, 0x9f, 0x66, +0xbf, 0x1, 0xf1, 0x2f, 0x0, 0x1d, 0x0, 0x32, 0x3f, 0x68, 0x82, 0xad, 0x30, 0x1d, 0xfd, 0x37, 0xbf, 0x1, 0xf1, 0x2f, +0x0, 0xab, 0x4b, 0x6a, 0x3f, 0xd7, 0xb1, 0x8e, 0x31, 0xee, 0x50, 0xce, 0x3e, 0x1, 0xf1, 0x2f, 0x0, 0xdd, 0x9e, 0x73, +0x3e, 0x8f, 0x6d, 0x78, 0xbf, 0xc5, 0xe4, 0x27, 0xbd, 0x1, 0xf1, 0x2f, 0x0, 0xdd, 0x67, 0x74, 0x3e, 0x0, 0x65, 0x78, +0xbf, 0x9b, 0x34, 0x22, 0xbd, 0x1, 0xf1, 0x2f, 0x0, 0x1a, 0x2b, 0x37, 0x3e, 0xe4, 0x28, 0x9e, 0xb0, 0x5, 0xdf, 0x7b, +0xbf, 0x1, 0xf1, 0x2f, 0x0, 0x7d, 0x26, 0x7c, 0x3f, 0xbb, 0x2c, 0x66, 0x31, 0x8a, 0xea, 0x30, 0xbe, 0x1, 0xf1, 0x2f, +0x0, 0xc0, 0x9, 0x1, 0x3f, 0xa, 0xe8, 0xf, 0x35, 0x94, 0x19, 0x5d, 0x3f, 0x1, 0xf1, 0x2f, 0x0, 0xf5, 0xc2, 0x8f, +0xbe, 0xec, 0x7e, 0x75, 0xbf, 0xab, 0xc6, 0x20, 0x3d, 0x1, 0xbc, 0x2c, 0x0, 0x25, 0x2b, 0x80, 0xbe, 0x31, 0x7c, 0x75, +0xbf, 0x38, 0x9a, 0x8, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x5c, 0xfa, 0xe6, 0x37, 0x0, 0x0, 0x80, 0xbf, 0x41, 0x25, 0x47, +0xb8, 0x1, 0xbc, 0x2c, 0x0, 0xe4, 0x9e, 0x73, 0x3e, 0x8f, 0x6d, 0x78, 0xbf, 0x3c, 0xe5, 0x27, 0x3d, 0x1, 0xbc, 0x2c, +0x0, 0xd5, 0x67, 0x74, 0x3e, 0x0, 0x65, 0x78, 0xbf, 0x2f, 0x35, 0x22, 0x3d, 0x1, 0xbc, 0x2c, 0x0, 0xf1, 0xc5, 0x58, +0x3e, 0xdc, 0x18, 0x79, 0xbf, 0xa9, 0x91, 0xbb, 0x3d, 0x1, 0xbc, 0x2c, 0x0, 0xdc, 0xdd, 0x66, 0x3e, 0xb0, 0x13, 0x79, +0xbf, 0x61, 0xd3, 0x4d, 0xbd, 0x1, 0xbc, 0x2c, 0x0, 0xc0, 0x9, 0x1, 0x3f, 0x94, 0x69, 0x23, 0xb1, 0x95, 0x19, 0x5d, +0xbf, 0x1, 0xbc, 0x2c, 0x0, 0x7a, 0x26, 0x7c, 0x3f, 0xc5, 0x51, 0xa9, 0xad, 0xc6, 0xea, 0x30, 0x3e, 0x1, 0xbc, 0x2c, +0x0, 0xff, 0x2a, 0x37, 0x3e, 0x4d, 0x63, 0x4c, 0x34, 0x6, 0xdf, 0x7b, 0x3f, 0x1, 0xbc, 0x2c, 0x0, 0x75, 0x63, 0xfe, +0xbd, 0x66, 0x79, 0x75, 0xbf, 0xd, 0xa6, 0x82, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x7c, 0x5, 0x2c, 0x3e, 0x16, 0x77, 0x78, +0xbf, 0x1e, 0xb5, 0x30, 0x3e, 0x1, 0xbc, 0x2c, 0x0, 0x74, 0xdb, 0x2c, 0x3e, 0xa8, 0x7d, 0x78, 0xbf, 0x22, 0x4f, 0x2f, +0x3e, 0x1, 0xbc, 0x2c, 0x0, 0xe2, 0xfc, 0xef, 0x3d, 0x6d, 0x1e, 0x79, 0xbf, 0x5a, 0x3, 0x4b, 0x3e, 0x1, 0xbc, 0x2c, +0x0, 0xb9, 0x4b, 0x6a, 0x3f, 0xa0, 0x84, 0x13, 0xb4, 0xa9, 0x50, 0xce, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x22, 0x0, 0x32, +0x3f, 0x59, 0xdf, 0x3f, 0x33, 0x18, 0xfd, 0x37, 0x3f, 0x1, 0xbc, 0x2c, 0x0, 0x12, 0x40, 0xde, 0xbe, 0xd4, 0x21, 0x1c, +0x34, 0x9f, 0x9f, 0x66, 0x3f, 0x1, 0xbc, 0x2c, 0x0, 0x7, 0x49, 0x4a, 0x3d, 0x9d, 0x77, 0x75, 0xbf, 0xe6, 0x22, 0x8f, +0xbe, 0x1, 0xbc, 0x2c, 0x0, 0xbf, 0x85, 0xb, 0x3d, 0xff, 0x7e, 0x78, 0xbf, 0xc9, 0xa0, 0x73, 0x3e, 0x1, 0xbc, 0x2c, +0x0, 0x5c, 0xd6, 0xe, 0x3d, 0x22, 0x92, 0x78, 0xbf, 0xbf, 0x48, 0x72, 0x3e, 0x1, 0xbc, 0x2c, 0x0, 0xcf, 0x22, 0xb4, +0xbc, 0x43, 0x22, 0x79, 0xbf, 0xe2, 0x7d, 0x6a, 0x3e, 0x1, 0xbc, 0x2c, 0x0, 0xd3, 0x33, 0x7a, 0x3f, 0xfd, 0x71, 0xdb, +0x32, 0x5e, 0xb1, 0x58, 0x3e, 0x1, 0xbc, 0x2c, 0x0, 0xc2, 0x44, 0x7a, 0x3f, 0x3c, 0x89, 0x19, 0xb4, 0xa6, 0x77, 0x57, +0x3e, 0x1, 0xbc, 0x2c, 0x0, 0x39, 0x1b, 0xf, 0x3e, 0xfa, 0xf8, 0x85, 0x34, 0xde, 0x7c, 0x7d, 0x3f, 0x1, 0xbc, 0x2c, +0x0, 0x58, 0x87, 0x61, 0xbf, 0x44, 0x11, 0x7, 0x33, 0x43, 0x43, 0xf2, 0x3e, 0x1, 0xbc, 0x2c, 0x0, 0x62, 0x11, 0x51, +0x3e, 0x82, 0x77, 0x75, 0xbf, 0x7f, 0xff, 0x49, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0xf0, 0xd3, 0xe6, 0xbd, 0x43, 0x82, 0x78, +0xbf, 0xa8, 0x23, 0x59, 0x3e, 0x1, 0xbc, 0x2c, 0x0, 0x7d, 0x47, 0xe5, 0xbd, 0x97, 0x9a, 0x78, 0xbf, 0x7, 0xce, 0x57, +0x3e, 0x1, 0xbc, 0x2c, 0x0, 0x45, 0x50, 0x1c, 0xbe, 0xe7, 0x22, 0x79, 0xbf, 0x24, 0x2e, 0x30, 0x3e, 0x1, 0xbc, 0x2c, +0x0, 0x45, 0x93, 0x2a, 0x3f, 0xbf, 0xa5, 0xb5, 0x34, 0x92, 0xe4, 0x3e, 0x3f, 0x1, 0xbc, 0x2c, 0x0, 0xa7, 0x5a, 0xf0, +0xbe, 0xf1, 0xe5, 0x2a, 0x34, 0xe5, 0x9, 0x62, 0x3f, 0x1, 0xbc, 0x2c, 0x0, 0x83, 0xa4, 0x7d, 0xbf, 0x80, 0x98, 0x52, +0xb4, 0x68, 0xa5, 0xa, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0xe3, 0x99, 0x7d, 0xbf, 0xad, 0xf8, 0xf5, 0x2e, 0x5, 0xdb, 0xb, +0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x27, 0xe2, 0x8f, 0x3e, 0x22, 0x79, 0x75, 0xbf, 0x9e, 0xa1, 0x22, 0xbd, 0x1, 0xbc, 0x2c, +0x0, 0x88, 0x6b, 0x5d, 0xbe, 0xa2, 0x7f, 0x78, 0xbf, 0xa1, 0xb4, 0xd6, 0x3d, 0x1, 0xbc, 0x2c, 0x0, 0x4, 0xac, 0x5c, +0xbe, 0xc7, 0x93, 0x78, 0xbf, 0x5d, 0xf0, 0xd3, 0x3d, 0x1, 0xbc, 0x2c, 0x0, 0x67, 0x45, 0x66, 0xbe, 0x1a, 0x20, 0x79, +0xbf, 0x15, 0x6e, 0x49, 0x3d, 0x1, 0xbc, 0x2c, 0x0, 0x9b, 0xa5, 0xcd, 0x3d, 0xba, 0xf4, 0x1c, 0x35, 0xc4, 0xb4, 0x7e, +0x3f, 0x1, 0xbc, 0x2c, 0x0, 0x9b, 0x26, 0x66, 0xbf, 0xc6, 0x7d, 0xb5, 0x32, 0xad, 0x33, 0xe0, 0x3e, 0x1, 0xbc, 0x2c, +0x0, 0xe8, 0xd1, 0x38, 0xbf, 0x81, 0x4f, 0xbf, 0xb0, 0x21, 0x23, 0x31, 0xbf, 0x1, 0xbc, 0x2c, 0x0, 0x8d, 0x4d, 0x80, +0x3e, 0xdd, 0x7b, 0x75, 0xbf, 0x54, 0x22, 0x8, 0x3e, 0x1, 0xbc, 0x2c, 0x0, 0x64, 0xa1, 0x72, 0xbe, 0x1e, 0x78, 0x78, +0xbf, 0xce, 0xf, 0x2f, 0xbd, 0x1, 0xbc, 0x2c, 0x0, 0xf4, 0xd7, 0x71, 0xbe, 0x51, 0x80, 0x78, 0xbf, 0x66, 0xc0, 0x34, +0xbd, 0x1, 0xbc, 0x2c, 0x0, 0xcd, 0x23, 0x58, 0xbe, 0xed, 0x1a, 0x79, 0xbf, 0xeb, 0xca, 0xbd, 0xbd, 0x1, 0xbc, 0x2c, +0x0, 0x42, 0xa, 0x1, 0xbf, 0x71, 0x69, 0x23, 0x31, 0x49, 0x19, 0x5d, 0x3f, 0x1, 0xbc, 0x2c, 0x0, 0x32, 0x12, 0x7c, +0xbf, 0xb7, 0xad, 0x81, 0x2d, 0xe1, 0xb6, 0x32, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x93, 0xed, 0x35, 0xbe, 0xf8, 0xa3, 0x22, +0xb1, 0x66, 0xed, 0x7b, 0xbf, 0x1, 0xbc, 0x2c, 0x0, 0x3b, 0xf3, 0xfe, 0x3d, 0xa7, 0x7e, 0x75, 0xbf, 0x0, 0x6d, 0x82, +0x3e, 0x1, 0xbc, 0x2c, 0x0, 0xcc, 0xf7, 0x2a, 0xbe, 0x96, 0x6e, 0x78, 0xbf, 0xe0, 0x77, 0x32, 0xbe, 0x1, 0xbc, 0x2c, +0x0, 0xaf, 0x21, 0x2a, 0xbe, 0xa7, 0x67, 0x78, 0xbf, 0x77, 0xdd, 0x33, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x50, 0xac, 0xee, +0xbd, 0x5c, 0x15, 0x79, 0xbf, 0xc8, 0x17, 0x4c, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x6b, 0x69, 0x6a, 0xbf, 0xa6, 0xd, 0x7c, +0x33, 0x92, 0xc9, 0xcd, 0x3e, 0x1, 0xbc, 0x2c, 0x0, 0x25, 0xaa, 0x31, 0xbf, 0x6f, 0xd9, 0xd0, 0xb4, 0x21, 0x50, 0x38, +0xbf, 0x1, 0xbc, 0x2c, 0x0, 0xe0, 0x50, 0xde, 0x3e, 0xaf, 0x3b, 0xbf, 0xb2, 0x93, 0x9b, 0x66, 0xbf, 0x1, 0xbc, 0x2c, +0x0, 0xa6, 0x3b, 0x49, 0xbd, 0x72, 0x80, 0x75, 0xbf, 0x32, 0xec, 0x8e, 0x3e, 0x1, 0xbc, 0x2c, 0x0, 0x1a, 0x59, 0x7, +0xbd, 0xae, 0x66, 0x78, 0xbf, 0xb5, 0x51, 0x75, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x6a, 0x9, 0x4, 0xbd, 0x37, 0x53, 0x78, +0xbf, 0xf1, 0xa8, 0x76, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x1d, 0x36, 0xb9, 0x3c, 0x87, 0x11, 0x79, 0xbf, 0xf1, 0x89, 0x6b, +0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x8d, 0x1a, 0x7a, 0xbf, 0x23, 0x66, 0x88, 0xb4, 0x40, 0x82, 0x5a, 0xbe, 0x1, 0xbc, 0x2c, +0x0, 0x59, 0x9, 0x7a, 0xbf, 0xf0, 0xa8, 0xc2, 0xae, 0x69, 0xbc, 0x5b, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0x1e, 0xec, 0xd, +0xbe, 0x15, 0xef, 0x24, 0xb1, 0x83, 0x87, 0x7d, 0xbf, 0x1, 0xbc, 0x2c, 0x0, 0x40, 0x68, 0x61, 0x3f, 0x95, 0x37, 0xd9, +0xb0, 0xe8, 0xb6, 0xf2, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0xea, 0xd3, 0x50, 0xbe, 0x8c, 0x80, 0x75, 0xbf, 0x3e, 0x8f, 0x49, +0x3e, 0x1, 0xbc, 0x2c, 0x0, 0xc3, 0xc6, 0xe8, 0x3d, 0x6d, 0x63, 0x78, 0xbf, 0x66, 0xd1, 0x5a, 0xbe, 0x1, 0xbc, 0x2c, +0x0, 0xed, 0x51, 0xea, 0x3d, 0xcd, 0x4a, 0x78, 0xbf, 0xd, 0x26, 0x5c, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0xde, 0xe8, 0x1c, +0x3e, 0xe3, 0x10, 0x79, 0xbf, 0x33, 0x3d, 0x31, 0xbe, 0x1, 0xbc, 0x2c, 0x0, 0xd8, 0x3a, 0x2a, 0xbf, 0x45, 0xb1, 0x88, +0xb4, 0x71, 0x33, 0x3f, 0xbf, 0x1, 0x1, 0x2c, 0x0, 0x3b, 0x62, 0xf0, 0x3e, 0xcf, 0x22, 0x65, 0xb2, 0xe1, 0x7, 0x62, +0xbf, 0x1, 0x0, 0x2c, 0x0, 0xb, 0xb4, 0x7d, 0x3f, 0x97, 0x30, 0x3, 0xaf, 0xca, 0xdb, 0x8, 0x3e, 0x1, 0x0, 0x2c, +0x0, 0x6a, 0xbe, 0x7d, 0x3f, 0xec, 0x7d, 0x6, 0xaf, 0xdf, 0xa6, 0x7, 0x3e, 0x1, 0x0, 0x2c, 0x0, 0x83, 0x5c, 0x5e, +0x3e, 0xc, 0x66, 0x78, 0xbf, 0x14, 0x30, 0xda, 0xbd, 0x1, 0xbe, 0x2c, 0x0, 0x7f, 0x1b, 0x5f, 0x3e, 0x93, 0x51, 0x78, +0xbf, 0x5, 0xf3, 0xdc, 0xbd, 0x1, 0xdb, 0x2c, 0x0, 0xb9, 0x61, 0xcb, 0xbd, 0x24, 0xf8, 0x26, 0xb1, 0xb, 0xbc, 0x7e, +0xbf, 0x1, 0x8, 0x2c, 0x0, 0x1e, 0x8, 0x66, 0x3f, 0x7e, 0x50, 0xce, 0xb0, 0xac, 0xb0, 0xe0, 0xbe, 0x1, 0x8, 0x2c, +0x0, 0xaf, 0x25, 0x39, 0x3f, 0x10, 0xc6, 0xbe, 0x30, 0x8f, 0xcb, 0x30, 0x3f, 0x1, 0x8, 0x2c, 0x0, 0xf3, 0xc2, 0x8f, +0xbe, 0xed, 0x7e, 0x75, 0xbf, 0xa9, 0xc6, 0x20, 0x3d, 0x1, 0x0, 0x32, 0x0, 0x23, 0x2b, 0x80, 0xbe, 0x31, 0x7c, 0x75, +0xbf, 0x3d, 0x9a, 0x8, 0xbe, 0x1, 0xf, 0x32, 0x0, 0xdc, 0x6, 0xe7, 0x37, 0x0, 0x0, 0x80, 0xbf, 0xa9, 0x21, 0x47, +0xb8, 0x1, 0xf, 0x32, 0x0, 0xd8, 0x9e, 0x73, 0x3e, 0x8f, 0x6d, 0x78, 0xbf, 0x3f, 0xe5, 0x27, 0x3d, 0x1, 0x5a, 0x32, +0x0, 0xbe, 0x67, 0x74, 0x3e, 0x2, 0x65, 0x78, 0xbf, 0x3, 0x35, 0x22, 0x3d, 0x1, 0x5a, 0x32, 0x0, 0xe9, 0xc5, 0x58, +0x3e, 0xdc, 0x18, 0x79, 0xbf, 0xa9, 0x91, 0xbb, 0x3d, 0x1, 0x5a, 0x32, 0x0, 0xd8, 0xdd, 0x66, 0x3e, 0xb0, 0x13, 0x79, +0xbf, 0x60, 0xd3, 0x4d, 0xbd, 0x1, 0x5a, 0x32, 0x0, 0xbf, 0x9, 0x1, 0x3f, 0x84, 0x35, 0xf, 0xb5, 0x94, 0x19, 0x5d, +0xbf, 0x1, 0x5a, 0x32, 0x0, 0x7c, 0x26, 0x7c, 0x3f, 0x7f, 0xf2, 0xc9, 0xae, 0xab, 0xea, 0x30, 0x3e, 0x1, 0x5a, 0x32, +0x0, 0x21, 0x2b, 0x37, 0x3e, 0x24, 0x71, 0xc5, 0x30, 0x5, 0xdf, 0x7b, 0x3f, 0x1, 0x5a, 0x32, 0x0, 0x6e, 0x63, 0xfe, +0xbd, 0x66, 0x79, 0x75, 0xbf, 0xc, 0xa6, 0x82, 0xbe, 0x1, 0x5a, 0x32, 0x0, 0x77, 0x5, 0x2c, 0x3e, 0x17, 0x77, 0x78, +0xbf, 0xf, 0xb5, 0x30, 0x3e, 0x1, 0x5a, 0x32, 0x0, 0x6b, 0xdb, 0x2c, 0x3e, 0xa9, 0x7d, 0x78, 0xbf, 0x0, 0x4f, 0x2f, +0x3e, 0x1, 0x5a, 0x32, 0x0, 0xdf, 0xfc, 0xef, 0x3d, 0x6d, 0x1e, 0x79, 0xbf, 0x4f, 0x3, 0x4b, 0x3e, 0x1, 0x5a, 0x32, +0x0, 0xb5, 0x4b, 0x6a, 0x3f, 0x59, 0x22, 0x25, 0x33, 0xc1, 0x50, 0xce, 0xbe, 0x1, 0x5a, 0x32, 0x0, 0x2e, 0x0, 0x32, +0x3f, 0x12, 0x93, 0x73, 0x34, 0xc, 0xfd, 0x37, 0x3f, 0x1, 0x5a, 0x32, 0x0, 0x27, 0x40, 0xde, 0xbe, 0x64, 0xed, 0x11, +0x35, 0x9b, 0x9f, 0x66, 0x3f, 0x1, 0x5b, 0x32, 0x0, 0xa, 0x49, 0x4a, 0x3d, 0x9c, 0x77, 0x75, 0xbf, 0xe6, 0x22, 0x8f, +0xbe, 0x1, 0x5b, 0x32, 0x0, 0xb5, 0x85, 0xb, 0x3d, 0xfe, 0x7e, 0x78, 0xbf, 0xcb, 0xa0, 0x73, 0x3e, 0x1, 0x33, 0x32, +0x0, 0x4e, 0xd6, 0xe, 0x3d, 0x21, 0x92, 0x78, 0xbf, 0xc2, 0x48, 0x72, 0x3e, 0x1, 0x33, 0x32, 0x0, 0xd3, 0x22, 0xb4, +0xbc, 0x43, 0x22, 0x79, 0xbf, 0xe4, 0x7d, 0x6a, 0x3e, 0x1, 0x33, 0x32, 0x0, 0xd6, 0x33, 0x7a, 0x3f, 0x14, 0x52, 0x2e, +0xb4, 0x39, 0xb1, 0x58, 0x3e, 0x1, 0x33, 0x32, 0x0, 0xc3, 0x44, 0x7a, 0x3f, 0x4c, 0x9b, 0xb, 0xae, 0xa3, 0x77, 0x57, +0x3e, 0x1, 0x33, 0x32, 0x0, 0x20, 0x1b, 0xf, 0x3e, 0xe0, 0xb4, 0xc8, 0x30, 0xde, 0x7c, 0x7d, 0x3f, 0x1, 0x33, 0x32, +0x0, 0x4b, 0x87, 0x61, 0xbf, 0x43, 0xea, 0x8e, 0x30, 0x75, 0x43, 0xf2, 0x3e, 0x1, 0x34, 0x32, 0x0, 0x68, 0x11, 0x51, +0x3e, 0x82, 0x77, 0x75, 0xbf, 0x81, 0xff, 0x49, 0xbe, 0x1, 0x34, 0x32, 0x0, 0x0, 0xd4, 0xe6, 0xbd, 0x43, 0x82, 0x78, +0xbf, 0xa7, 0x23, 0x59, 0x3e, 0x1, 0x34, 0x32, 0x0, 0x8e, 0x47, 0xe5, 0xbd, 0x97, 0x9a, 0x78, 0xbf, 0x6, 0xce, 0x57, +0x3e, 0x1, 0x34, 0x32, 0x0, 0x48, 0x50, 0x1c, 0xbe, 0xe7, 0x22, 0x79, 0xbf, 0x1e, 0x2e, 0x30, 0x3e, 0x1, 0x34, 0x32, +0x0, 0x46, 0x93, 0x2a, 0x3f, 0x3, 0xe7, 0x8, 0x34, 0x92, 0xe4, 0x3e, 0x3f, 0x1, 0x34, 0x32, 0x0, 0xbb, 0x5a, 0xf0, +0xbe, 0x3e, 0x22, 0x56, 0x32, 0xe0, 0x9, 0x62, 0x3f, 0x1, 0x34, 0x32, 0x0, 0x82, 0xa4, 0x7d, 0xbf, 0xde, 0x52, 0x4, +0xb4, 0x9e, 0xa5, 0xa, 0xbe, 0x1, 0x34, 0x32, 0x0, 0xe3, 0x99, 0x7d, 0xbf, 0x88, 0xc1, 0x9b, 0xb4, 0x18, 0xdb, 0xb, +0xbe, 0x1, 0x34, 0x32, 0x0, 0x26, 0xe2, 0x8f, 0x3e, 0x22, 0x79, 0x75, 0xbf, 0xae, 0xa1, 0x22, 0xbd, 0x1, 0x34, 0x32, +0x0, 0x79, 0x6b, 0x5d, 0xbe, 0xa3, 0x7f, 0x78, 0xbf, 0xa6, 0xb4, 0xd6, 0x3d, 0x1, 0x34, 0x32, 0x0, 0xf9, 0xab, 0x5c, +0xbe, 0xc8, 0x93, 0x78, 0xbf, 0x5e, 0xf0, 0xd3, 0x3d, 0x1, 0x34, 0x32, 0x0, 0x59, 0x45, 0x66, 0xbe, 0x1b, 0x20, 0x79, +0xbf, 0x16, 0x6e, 0x49, 0x3d, 0x1, 0x34, 0x32, 0x0, 0x79, 0xa5, 0xcd, 0x3d, 0x7f, 0x52, 0xe9, 0x34, 0xc5, 0xb4, 0x7e, +0x3f, 0x1, 0x35, 0x32, 0x0, 0x99, 0x26, 0x66, 0xbf, 0x4d, 0xdd, 0xb, 0x35, 0xaf, 0x33, 0xe0, 0x3e, 0x1, 0x35, 0x32, +0x0, 0xf1, 0xd1, 0x38, 0xbf, 0xd0, 0x94, 0x5a, 0xb0, 0x17, 0x23, 0x31, 0xbf, 0x1, 0x35, 0x32, 0x0, 0x8e, 0x4d, 0x80, +0x3e, 0xdc, 0x7b, 0x75, 0xbf, 0x5f, 0x22, 0x8, 0x3e, 0x1, 0x35, 0x32, 0x0, 0x5a, 0xa1, 0x72, 0xbe, 0x1e, 0x78, 0x78, +0xbf, 0xfc, 0xf, 0x2f, 0xbd, 0x1, 0x35, 0x32, 0x0, 0xec, 0xd7, 0x71, 0xbe, 0x51, 0x80, 0x78, 0xbf, 0x9a, 0xc0, 0x34, +0xbd, 0x1, 0x35, 0x32, 0x0, 0xc2, 0x23, 0x58, 0xbe, 0xee, 0x1a, 0x79, 0xbf, 0xf5, 0xca, 0xbd, 0xbd, 0x1, 0x35, 0x32, +0x0, 0x41, 0xa, 0x1, 0xbf, 0x36, 0xa6, 0xf, 0x35, 0x48, 0x19, 0x5d, 0x3f, 0x1, 0x35, 0x32, 0x0, 0x32, 0x12, 0x7c, +0xbf, 0xe, 0xec, 0xab, 0xb3, 0xf4, 0xb6, 0x32, 0xbe, 0x1, 0x35, 0x32, 0x0, 0x82, 0xed, 0x35, 0xbe, 0xcf, 0xf0, 0x49, +0xb5, 0x67, 0xed, 0x7b, 0xbf, 0x1, 0x35, 0x32, 0x0, 0x42, 0xf3, 0xfe, 0x3d, 0xa7, 0x7e, 0x75, 0xbf, 0x2, 0x6d, 0x82, +0x3e, 0x1, 0x35, 0x32, 0x0, 0xc3, 0xf7, 0x2a, 0xbe, 0x96, 0x6e, 0x78, 0xbf, 0xdf, 0x77, 0x32, 0xbe, 0x1, 0x36, 0x32, +0x0, 0xa9, 0x21, 0x2a, 0xbe, 0xa6, 0x67, 0x78, 0xbf, 0x8a, 0xdd, 0x33, 0xbe, 0x1, 0x36, 0x32, 0x0, 0x43, 0xac, 0xee, +0xbd, 0x5c, 0x15, 0x79, 0xbf, 0xc6, 0x17, 0x4c, 0xbe, 0x1, 0x36, 0x32, 0x0, 0x6c, 0x69, 0x6a, 0xbf, 0x91, 0xb9, 0x92, +0x34, 0x8b, 0xc9, 0xcd, 0x3e, 0x1, 0x36, 0x32, 0x0, 0x20, 0xaa, 0x31, 0xbf, 0xb4, 0x5e, 0x3a, 0xb4, 0x27, 0x50, 0x38, +0xbf, 0x1, 0x36, 0x32, 0x0, 0xe0, 0x50, 0xde, 0x3e, 0x93, 0xfd, 0xe, 0xb5, 0x91, 0x9b, 0x66, 0xbf, 0x1, 0x36, 0x32, +0x0, 0x9e, 0x3b, 0x49, 0xbd, 0x71, 0x80, 0x75, 0xbf, 0x32, 0xec, 0x8e, 0x3e, 0x1, 0x36, 0x32, 0x0, 0x2b, 0x59, 0x7, +0xbd, 0xaf, 0x66, 0x78, 0xbf, 0x9f, 0x51, 0x75, 0xbe, 0x1, 0x36, 0x32, 0x0, 0xaa, 0x9, 0x4, 0xbd, 0x39, 0x53, 0x78, +0xbf, 0xc7, 0xa8, 0x76, 0xbe, 0x1, 0x36, 0x32, 0x0, 0xc9, 0x35, 0xb9, 0x3c, 0x87, 0x11, 0x79, 0xbf, 0xe0, 0x89, 0x6b, +0xbe, 0x1, 0x36, 0x32, 0x0, 0x96, 0x1a, 0x7a, 0xbf, 0xcb, 0x56, 0xed, 0x2d, 0xaa, 0x81, 0x5a, 0xbe, 0x1, 0x36, 0x32, +0x0, 0x63, 0x9, 0x7a, 0xbf, 0x5b, 0x6d, 0xdc, 0x2d, 0xbc, 0xbb, 0x5b, 0xbe, 0x1, 0x36, 0x32, 0x0, 0x49, 0xec, 0xd, +0xbe, 0x42, 0xcc, 0xc8, 0xb0, 0x82, 0x87, 0x7d, 0xbf, 0x1, 0x36, 0x32, 0x0, 0x42, 0x68, 0x61, 0x3f, 0x86, 0x13, 0x8f, +0xb0, 0xe3, 0xb6, 0xf2, 0xbe, 0x1, 0x36, 0x32, 0x0, 0xec, 0xd3, 0x50, 0xbe, 0x8c, 0x80, 0x75, 0xbf, 0x3c, 0x8f, 0x49, +0x3e, 0x1, 0x36, 0x32, 0x0, 0xe0, 0xc6, 0xe8, 0x3d, 0x6c, 0x63, 0x78, 0xbf, 0x67, 0xd1, 0x5a, 0xbe, 0x1, 0x37, 0x32, +0x0, 0x50, 0x52, 0xea, 0x3d, 0xca, 0x4a, 0x78, 0xbf, 0x22, 0x26, 0x5c, 0xbe, 0x1, 0x37, 0x32, 0x0, 0xea, 0xe8, 0x1c, +0x3e, 0xe3, 0x10, 0x79, 0xbf, 0x30, 0x3d, 0x31, 0xbe, 0x1, 0x37, 0x32, 0x0, 0xd8, 0x3a, 0x2a, 0xbf, 0x55, 0x46, 0x77, +0xb0, 0x72, 0x33, 0x3f, 0xbf, 0x1, 0x37, 0x32, 0x0, 0x65, 0x62, 0xf0, 0x3e, 0xc3, 0x6e, 0xd0, 0xb0, 0xd7, 0x7, 0x62, +0xbf, 0x1, 0x37, 0x32, 0x0, 0xa, 0xb4, 0x7d, 0x3f, 0xa7, 0x39, 0x4, 0x34, 0xf7, 0xdb, 0x8, 0x3e, 0x1, 0x37, 0x32, +0x0, 0x69, 0xbe, 0x7d, 0x3f, 0x64, 0xb, 0x2b, 0xaf, 0x0, 0xa7, 0x7, 0x3e, 0x1, 0x37, 0x32, 0x0, 0x7d, 0x5c, 0x5e, +0x3e, 0xc, 0x66, 0x78, 0xbf, 0x19, 0x30, 0xda, 0xbd, 0x1, 0x37, 0x32, 0x0, 0x73, 0x1b, 0x5f, 0x3e, 0x94, 0x51, 0x78, +0xbf, 0x9, 0xf3, 0xdc, 0xbd, 0x1, 0x37, 0x32, 0x0, 0x6a, 0x61, 0xcb, 0xbd, 0x48, 0x1d, 0x33, 0xb5, 0xd, 0xbc, 0x7e, +0xbf, 0x1, 0x37, 0x32, 0x0, 0x1d, 0x8, 0x66, 0x3f, 0x5b, 0x47, 0xb9, 0xb4, 0xae, 0xb0, 0xe0, 0xbe, 0x1, 0x37, 0x32, +0x0, 0xb1, 0x25, 0x39, 0x3f, 0x3d, 0xe8, 0x89, 0x34, 0x8c, 0xcb, 0x30, 0x3f, 0x1, 0x37, 0x32, 0x0, 0xf5, 0xc2, 0x8f, +0xbe, 0xed, 0x7e, 0x75, 0xbf, 0x58, 0xc6, 0x20, 0xbd, 0x1, 0xcf, 0x35, 0x0, 0xe6, 0xd3, 0x50, 0xbe, 0x8d, 0x80, 0x75, +0xbf, 0x29, 0x8f, 0x49, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0x1e, 0x99, 0xe6, 0x37, 0x0, 0x0, 0x80, 0xbf, 0x3b, 0xa2, 0x48, +0x38, 0x1, 0xd5, 0x35, 0x0, 0x6a, 0x5c, 0x5e, 0x3e, 0xd, 0x66, 0x78, 0xbf, 0x35, 0x30, 0xda, 0x3d, 0x1, 0xd5, 0x35, +0x0, 0x57, 0x1b, 0x5f, 0x3e, 0x96, 0x51, 0x78, 0xbf, 0x19, 0xf3, 0xdc, 0x3d, 0x1, 0xd5, 0x35, 0x0, 0xe3, 0x5c, 0x36, +0x3e, 0x48, 0x11, 0x79, 0xbf, 0x3e, 0xe2, 0x16, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0x58, 0xf8, 0x6b, 0x3e, 0xd1, 0x14, 0x79, +0xbf, 0xfe, 0xc0, 0x72, 0x3c, 0x1, 0xd5, 0x35, 0x0, 0xb6, 0x25, 0x39, 0x3f, 0xfc, 0xac, 0x5, 0xb3, 0x86, 0xcb, 0x30, +0xbf, 0x1, 0xd5, 0x35, 0x0, 0x22, 0x8, 0x66, 0x3f, 0xd9, 0x68, 0x15, 0xb3, 0x9c, 0xb0, 0xe0, 0x3e, 0x1, 0xd5, 0x35, +0x0, 0xbc, 0x61, 0xcb, 0xbd, 0xdc, 0x8a, 0x8c, 0x33, 0xb, 0xbc, 0x7e, 0x3f, 0x1, 0xd5, 0x35, 0x0, 0x96, 0x3b, 0x49, +0xbd, 0x73, 0x80, 0x75, 0xbf, 0x2a, 0xec, 0x8e, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0xbc, 0xc6, 0xe8, 0x3d, 0x6b, 0x63, 0x78, +0xbf, 0x7f, 0xd1, 0x5a, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0x25, 0x52, 0xea, 0x3d, 0xca, 0x4a, 0x78, 0xbf, 0x2d, 0x26, 0x5c, +0x3e, 0x1, 0xd5, 0x35, 0x0, 0x5, 0xf0, 0x6c, 0x3d, 0x9, 0x11, 0x79, 0xbf, 0xb8, 0x2c, 0x65, 0x3e, 0x1, 0xd5, 0x35, +0x0, 0xc, 0xb4, 0x7d, 0x3f, 0x41, 0x75, 0x15, 0xb4, 0xa3, 0xdb, 0x8, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0x6a, 0xbe, 0x7d, +0x3f, 0xca, 0xfc, 0x42, 0xb4, 0xbc, 0xa6, 0x7, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0x64, 0x62, 0xf0, 0x3e, 0x33, 0x6b, 0x7e, +0xae, 0xd8, 0x7, 0x62, 0x3f, 0x1, 0xd5, 0x35, 0x0, 0xd1, 0x3a, 0x2a, 0xbf, 0x41, 0xbc, 0x84, 0x33, 0x77, 0x33, 0x3f, +0x3f, 0x1, 0xd5, 0x35, 0x0, 0x39, 0xf3, 0xfe, 0x3d, 0xa9, 0x7e, 0x75, 0xbf, 0xf2, 0x6c, 0x82, 0xbe, 0x1, 0xd5, 0x35, +0x0, 0xa, 0x59, 0x7, 0xbd, 0xae, 0x66, 0x78, 0xbf, 0xb5, 0x51, 0x75, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0x60, 0x9, 0x4, +0xbd, 0x37, 0x53, 0x78, 0xbf, 0xf5, 0xa8, 0x76, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0x42, 0xcd, 0xac, 0xbd, 0x2d, 0x14, 0x79, +0xbf, 0xe5, 0x26, 0x5c, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0x4d, 0x68, 0x61, 0x3f, 0x3, 0xf2, 0xa6, 0x34, 0xbc, 0xb6, 0xf2, +0x3e, 0x1, 0xd5, 0x35, 0x0, 0x15, 0xec, 0xd, 0xbe, 0x5f, 0x9d, 0x2a, 0x35, 0x84, 0x87, 0x7d, 0x3f, 0x1, 0xd5, 0x35, +0x0, 0x90, 0x1a, 0x7a, 0xbf, 0x8b, 0x7d, 0x88, 0x34, 0x1a, 0x82, 0x5a, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0x5b, 0x9, 0x7a, +0xbf, 0x0, 0xa7, 0x8a, 0x2f, 0x44, 0xbc, 0x5b, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0x8e, 0x4d, 0x80, 0x3e, 0xdd, 0x7b, 0x75, +0xbf, 0x3c, 0x22, 0x8, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0xc5, 0xf7, 0x2a, 0xbe, 0x96, 0x6e, 0x78, 0xbf, 0xe3, 0x77, 0x32, +0x3e, 0x1, 0xd5, 0x35, 0x0, 0x9c, 0x21, 0x2a, 0xbe, 0xa8, 0x67, 0x78, 0xbf, 0x7b, 0xdd, 0x33, 0x3e, 0x1, 0xd5, 0x35, +0x0, 0x61, 0xee, 0x46, 0xbe, 0x80, 0x19, 0x79, 0xbf, 0xf7, 0x7f, 0xfe, 0x3d, 0x1, 0xd5, 0x35, 0x0, 0xde, 0x50, 0xde, +0x3e, 0xd9, 0xce, 0x15, 0x35, 0x93, 0x9b, 0x66, 0x3f, 0x1, 0xd5, 0x35, 0x0, 0x21, 0xaa, 0x31, 0xbf, 0x10, 0xd9, 0xac, +0x34, 0x25, 0x50, 0x38, 0x3f, 0x1, 0xd5, 0x35, 0x0, 0x64, 0x69, 0x6a, 0xbf, 0x27, 0x66, 0x0, 0x31, 0xb7, 0xc9, 0xcd, +0xbe, 0x1, 0xd5, 0x35, 0x0, 0x23, 0xe2, 0x8f, 0x3e, 0x22, 0x79, 0x75, 0xbf, 0x8, 0xa2, 0x22, 0x3d, 0x1, 0xd5, 0x35, +0x0, 0x5c, 0xa1, 0x72, 0xbe, 0x1e, 0x78, 0x78, 0xbf, 0x58, 0x10, 0x2f, 0x3d, 0x1, 0xd5, 0x35, 0x0, 0xf4, 0xd7, 0x71, +0xbe, 0x50, 0x80, 0x78, 0xbf, 0xfd, 0xc0, 0x34, 0x3d, 0x1, 0xd5, 0x35, 0x0, 0xc, 0x5e, 0x6b, 0xbe, 0xfa, 0x1e, 0x79, +0xbf, 0xfb, 0x9, 0x61, 0xbc, 0x1, 0xd5, 0x35, 0x0, 0x89, 0xed, 0x35, 0xbe, 0x8e, 0x8d, 0x3, 0x35, 0x67, 0xed, 0x7b, +0x3f, 0x1, 0xd5, 0x35, 0x0, 0x31, 0x12, 0x7c, 0xbf, 0xc3, 0x69, 0x8f, 0xb3, 0xe9, 0xb6, 0x32, 0x3e, 0x1, 0xd5, 0x35, +0x0, 0x41, 0xa, 0x1, 0xbf, 0xfd, 0x55, 0xe, 0xb5, 0x49, 0x19, 0x5d, 0xbf, 0x1, 0xd5, 0x35, 0x0, 0x5a, 0x11, 0x51, +0x3e, 0x81, 0x77, 0x75, 0xbf, 0x9c, 0xff, 0x49, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0x82, 0x6b, 0x5d, 0xbe, 0xa3, 0x7f, 0x78, +0xbf, 0x72, 0xb4, 0xd6, 0xbd, 0x1, 0xd5, 0x35, 0x0, 0xeb, 0xab, 0x5c, 0xbe, 0xc9, 0x93, 0x78, 0xbf, 0x4, 0xf0, 0xd3, +0xbd, 0x1, 0xd5, 0x35, 0x0, 0x97, 0xc5, 0x35, 0xbe, 0x84, 0x22, 0x79, 0xbf, 0x9d, 0xd0, 0x15, 0xbe, 0x1, 0xd5, 0x35, +0x0, 0xec, 0xd1, 0x38, 0xbf, 0xa3, 0xbe, 0x88, 0x34, 0x1b, 0x23, 0x31, 0x3f, 0x1, 0xd5, 0x35, 0x0, 0x9e, 0x26, 0x66, +0xbf, 0xc6, 0xb3, 0x44, 0x33, 0x9d, 0x33, 0xe0, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0xc1, 0xa5, 0xcd, 0x3d, 0x56, 0xae, 0xa1, +0xb3, 0xc5, 0xb4, 0x7e, 0xbf, 0x1, 0xd5, 0x35, 0x0, 0xe5, 0x48, 0x4a, 0x3d, 0x9a, 0x77, 0x75, 0xbf, 0xf3, 0x22, 0x8f, +0x3e, 0x1, 0xd5, 0x35, 0x0, 0xe6, 0xd3, 0xe6, 0xbd, 0x44, 0x82, 0x78, 0xbf, 0x8d, 0x23, 0x59, 0xbe, 0x1, 0xd5, 0x35, +0x0, 0x7a, 0x47, 0xe5, 0xbd, 0x98, 0x9a, 0x78, 0xbf, 0xf3, 0xcd, 0x57, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0x22, 0x71, 0x6a, +0xbd, 0xc2, 0x22, 0x79, 0xbf, 0xfa, 0x20, 0x64, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0x84, 0xa4, 0x7d, 0xbf, 0x95, 0xc1, 0xc7, +0x33, 0x4b, 0xa5, 0xa, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0xe5, 0x99, 0x7d, 0xbf, 0x3e, 0xdb, 0x9c, 0x33, 0xd8, 0xda, 0xb, +0x3e, 0x1, 0xd5, 0x35, 0x0, 0x91, 0x5a, 0xf0, 0xbe, 0x70, 0xa1, 0x2d, 0xb0, 0xec, 0x9, 0x62, 0xbf, 0x1, 0xd5, 0x35, +0x0, 0x4a, 0x93, 0x2a, 0x3f, 0x8c, 0xcf, 0xa6, 0xb3, 0x8d, 0xe4, 0x3e, 0xbf, 0x1, 0xd5, 0x35, 0x0, 0x75, 0x63, 0xfe, +0xbd, 0x64, 0x79, 0x75, 0xbf, 0x16, 0xa6, 0x82, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0xb4, 0x85, 0xb, 0x3d, 0x1, 0x7f, 0x78, +0xbf, 0xa2, 0xa0, 0x73, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0x6e, 0xd6, 0xe, 0x3d, 0x24, 0x92, 0x78, 0xbf, 0x97, 0x48, 0x72, +0xbe, 0x1, 0xd5, 0x35, 0x0, 0x15, 0x1d, 0xae, 0x3d, 0x9e, 0x1f, 0x79, 0xbf, 0xf5, 0x14, 0x5b, 0xbe, 0x1, 0xd5, 0x35, +0x0, 0x5c, 0x87, 0x61, 0xbf, 0xfa, 0xb5, 0x6a, 0x33, 0x37, 0x43, 0xf2, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0x24, 0x1b, 0xf, +0x3e, 0xad, 0xd4, 0xc9, 0xb3, 0xdd, 0x7c, 0x7d, 0xbf, 0x1, 0xd5, 0x35, 0x0, 0xd0, 0x33, 0x7a, 0x3f, 0x8c, 0xd5, 0x88, +0xb3, 0xaa, 0xb1, 0x58, 0xbe, 0x1, 0xd5, 0x35, 0x0, 0xbd, 0x44, 0x7a, 0x3f, 0x55, 0x6f, 0x20, 0xb4, 0xa, 0x78, 0x57, +0xbe, 0x1, 0xd5, 0x35, 0x0, 0x25, 0x2b, 0x80, 0xbe, 0x30, 0x7c, 0x75, 0xbf, 0x4a, 0x9a, 0x8, 0x3e, 0x1, 0xd5, 0x35, +0x0, 0x78, 0x5, 0x2c, 0x3e, 0x18, 0x77, 0x78, 0xbf, 0xf2, 0xb4, 0x30, 0xbe, 0x1, 0xbe, 0x35, 0x0, 0x6b, 0xdb, 0x2c, +0x3e, 0xaa, 0x7d, 0x78, 0xbf, 0xe9, 0x4e, 0x2f, 0xbe, 0x1, 0xc8, 0x35, 0x0, 0xf1, 0x92, 0x47, 0x3e, 0x4a, 0x1a, 0x79, +0xbf, 0xb4, 0x48, 0xfc, 0xbd, 0x1, 0xc8, 0x35, 0x0, 0x3b, 0x40, 0xde, 0xbe, 0xef, 0x41, 0x14, 0xb1, 0x95, 0x9f, 0x66, +0xbf, 0x1, 0x0, 0x35, 0x0, 0x21, 0x0, 0x32, 0x3f, 0xdc, 0xdf, 0x9e, 0xb3, 0x18, 0xfd, 0x37, 0xbf, 0x1, 0xd5, 0x35, +0x0, 0xb0, 0x4b, 0x6a, 0x3f, 0x6e, 0x90, 0x0, 0xb1, 0xd8, 0x50, 0xce, 0x3e, 0x1, 0xd5, 0x35, 0x0, 0xd7, 0x9e, 0x73, +0x3e, 0x90, 0x6d, 0x78, 0xbf, 0xd5, 0xe4, 0x27, 0xbd, 0x1, 0xd5, 0x35, 0x0, 0xde, 0x67, 0x74, 0x3e, 0x0, 0x65, 0x78, +0xbf, 0xa3, 0x34, 0x22, 0xbd, 0x1, 0xd5, 0x35, 0x0, 0x1d, 0x2b, 0x37, 0x3e, 0xfc, 0x5c, 0x2e, 0xb3, 0x6, 0xdf, 0x7b, +0xbf, 0x1, 0xd5, 0x35, 0x0, 0x7c, 0x26, 0x7c, 0x3f, 0x6f, 0x74, 0x1e, 0xb4, 0x92, 0xea, 0x30, 0xbe, 0x1, 0xd5, 0x35, +0x0, 0xb3, 0x9, 0x1, 0x3f, 0xc7, 0x58, 0x5e, 0xb1, 0x9c, 0x19, 0x5d, 0x3f, 0x1, 0xd5, 0x35, 0x0, 0x7e, 0x50, 0x7e, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x4c, 0xa1, 0xea, 0x3d, 0x1, 0xbe, 0x3d, 0x0, 0x9a, 0xa, 0x71, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x13, 0x74, 0xac, 0x3e, 0x1, 0x0, 0x3d, 0x0, 0x74, 0x3, 0x58, 0x3f, 0x1f, 0x37, 0x43, 0x34, 0x1f, 0x62, 0x9, +0x3f, 0x1, 0x0, 0x3d, 0x0, 0xb5, 0x79, 0x4d, 0x3f, 0x3b, 0xae, 0x8b, 0x34, 0x1, 0xb2, 0x18, 0x3f, 0x1, 0x0, 0x3d, +0x0, 0xe4, 0xc1, 0x41, 0x3f, 0x87, 0xe4, 0x8b, 0x34, 0x78, 0x50, 0x27, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x87, 0x57, 0x27, +0x3f, 0x8, 0x8d, 0x14, 0x34, 0xc9, 0xbb, 0x41, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x6b, 0xb9, 0x18, 0x3f, 0xd4, 0xf1, 0x27, +0xb4, 0x31, 0x74, 0x4d, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x60, 0xb9, 0xf1, 0x3e, 0x76, 0x3a, 0xa5, 0xb4, 0x54, 0xac, 0x61, +0x3f, 0x1, 0x0, 0x3d, 0x0, 0x72, 0x6b, 0xcf, 0x3e, 0x7a, 0x5f, 0xa4, 0xb4, 0x47, 0xd, 0x6a, 0x3f, 0x1, 0x0, 0x3d, +0x0, 0x20, 0x94, 0x86, 0x3e, 0x4c, 0x42, 0x20, 0xb4, 0x90, 0xff, 0x76, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0xef, 0xd4, 0x40, +0x3e, 0xb9, 0x72, 0x1f, 0xb4, 0x82, 0x6b, 0x7b, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0xaf, 0xb3, 0x1d, 0x3d, 0x86, 0x1f, 0x97, +0xb4, 0x68, 0xcf, 0x7f, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x61, 0x21, 0x1d, 0xbd, 0x2e, 0xd1, 0x1d, 0xb4, 0xc2, 0xcf, 0x7f, +0x3f, 0x1, 0x0, 0x3d, 0x0, 0x55, 0xb1, 0x40, 0xbe, 0x63, 0xec, 0xf1, 0x33, 0x37, 0x6d, 0x7b, 0x3f, 0x1, 0x0, 0x3d, +0x0, 0xc3, 0x82, 0x86, 0xbe, 0xad, 0x26, 0xa1, 0x34, 0xec, 0x1, 0x77, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x9c, 0x5b, 0xcf, +0xbe, 0xe8, 0x49, 0x72, 0x34, 0xc7, 0x10, 0x6a, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x99, 0xaa, 0xf1, 0xbe, 0xe, 0x82, 0xed, +0x33, 0x47, 0xb0, 0x61, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x39, 0xb3, 0x18, 0xbf, 0xd, 0xd, 0x83, 0x33, 0xcb, 0x78, 0x4d, +0x3f, 0x1, 0x0, 0x3d, 0x0, 0xfb, 0x51, 0x27, 0xbf, 0x8e, 0x4a, 0x4, 0x33, 0x94, 0xc0, 0x41, 0x3f, 0x1, 0x0, 0x3d, +0x0, 0xbf, 0xbd, 0x41, 0xbf, 0x58, 0x36, 0x45, 0x33, 0x42, 0x55, 0x27, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x4b, 0x76, 0x4d, +0xbf, 0x64, 0x53, 0x65, 0x33, 0x97, 0xb6, 0x18, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x68, 0xae, 0x61, 0xbf, 0x37, 0xaf, 0xb9, +0x32, 0x95, 0xb1, 0xf1, 0x3e, 0x1, 0x0, 0x3d, 0x0, 0x36, 0xf, 0x6a, 0xbf, 0x9e, 0x4c, 0xd3, 0x31, 0xb1, 0x62, 0xcf, +0x3e, 0x1, 0x0, 0x3d, 0x0, 0xfa, 0x0, 0x77, 0xbf, 0x6d, 0xe5, 0x3b, 0xb2, 0xb4, 0x89, 0x86, 0x3e, 0x1, 0x0, 0x3d, +0x0, 0x92, 0x6c, 0x7b, 0xbf, 0x24, 0x4a, 0x54, 0xb2, 0xc0, 0xbe, 0x40, 0x3e, 0x1, 0x0, 0x3d, 0x0, 0xa6, 0xcf, 0x7f, +0xbf, 0xd2, 0xe1, 0x4a, 0xb2, 0x9e, 0x51, 0x1d, 0x3d, 0x1, 0x0, 0x3d, 0x0, 0x84, 0xcf, 0x7f, 0xbf, 0x6e, 0xb, 0x21, +0xb3, 0xf8, 0x86, 0x1d, 0xbd, 0x1, 0x0, 0x3d, 0x0, 0xf3, 0x6b, 0x7b, 0xbf, 0x60, 0x3b, 0xb4, 0xb3, 0xce, 0xcb, 0x40, +0xbe, 0x1, 0x0, 0x3d, 0x0, 0x1c, 0x0, 0x77, 0xbf, 0x5, 0xa3, 0xf, 0xb4, 0x14, 0x90, 0x86, 0xbe, 0x1, 0x0, 0x3d, +0x0, 0xe9, 0xd, 0x6a, 0xbf, 0x1a, 0x82, 0x2b, 0xb4, 0x93, 0x68, 0xcf, 0xbe, 0x1, 0x0, 0x3d, 0x0, 0xed, 0xac, 0x61, +0xbf, 0x7b, 0x9d, 0x7, 0xb4, 0x23, 0xb7, 0xf1, 0xbe, 0x1, 0x0, 0x3d, 0x0, 0x99, 0x74, 0x4d, 0xbf, 0x18, 0x48, 0xf7, +0xb3, 0xde, 0xb8, 0x18, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0xf, 0xbc, 0x41, 0xbf, 0x17, 0x7c, 0x4, 0xb4, 0x39, 0x57, 0x27, +0xbf, 0x1, 0x0, 0x3d, 0x0, 0x4f, 0x50, 0x27, 0xbf, 0x8b, 0x88, 0x43, 0xb4, 0x5, 0xc2, 0x41, 0xbf, 0x1, 0x0, 0x3d, +0x0, 0x91, 0xb1, 0x18, 0xbf, 0x15, 0x4, 0x6a, 0xb4, 0x8, 0x7a, 0x4d, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0xad, 0xa7, 0xf1, +0xbe, 0xec, 0x16, 0x71, 0xb4, 0x11, 0xb1, 0x61, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x15, 0x59, 0xcf, 0xbe, 0x4f, 0xad, 0x72, +0xb4, 0x58, 0x11, 0x6a, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x2e, 0x81, 0x86, 0xbe, 0x4c, 0xc1, 0x71, 0xb4, 0x23, 0x2, 0x77, +0xbf, 0x1, 0x0, 0x3d, 0x0, 0x3a, 0xaf, 0x40, 0xbe, 0x46, 0x75, 0x1f, 0xb4, 0x52, 0x6d, 0x7b, 0xbf, 0x1, 0x0, 0x3d, +0x0, 0x4d, 0x21, 0x1d, 0xbd, 0xc, 0xcf, 0x9d, 0xb3, 0xc4, 0xcf, 0x7f, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0xb4, 0xaf, 0x1d, +0x3d, 0x0, 0x0, 0x0, 0x0, 0x6b, 0xcf, 0x7f, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0xed, 0xd1, 0x40, 0x3e, 0x0, 0x0, 0x0, +0x0, 0xa7, 0x6b, 0x7b, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x16, 0x92, 0x86, 0x3e, 0xdb, 0x7d, 0xf4, 0xb2, 0xd7, 0xff, 0x76, +0xbf, 0x1, 0x0, 0x3d, 0x0, 0x89, 0x68, 0xcf, 0x3e, 0x2, 0x1d, 0x5c, 0xb3, 0xea, 0xd, 0x6a, 0xbf, 0x1, 0x0, 0x3d, +0x0, 0x2a, 0xb6, 0xf1, 0x3e, 0x7f, 0xfc, 0xb6, 0xb3, 0x30, 0xad, 0x61, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x97, 0xb7, 0x18, +0x3f, 0xe4, 0xe5, 0xaa, 0xb3, 0x8e, 0x75, 0x4d, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0xa5, 0x55, 0x27, 0x3f, 0x10, 0x9b, 0xd9, +0xb3, 0x6c, 0xbd, 0x41, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x5, 0xc0, 0x41, 0x3f, 0x2c, 0x5b, 0xc1, 0xb3, 0xa0, 0x52, 0x27, +0xbf, 0x1, 0x0, 0x3d, 0x0, 0xeb, 0x77, 0x4d, 0x3f, 0x66, 0xbd, 0x9f, 0xb3, 0x66, 0xb4, 0x18, 0xbf, 0x1, 0x0, 0x3d, +0x0, 0xfb, 0xae, 0x61, 0x3f, 0x13, 0xe, 0xfa, 0xb2, 0x6f, 0xaf, 0xf1, 0xbe, 0x1, 0x0, 0x3d, 0x0, 0x67, 0xf, 0x6a, +0x3f, 0xce, 0x43, 0xe2, 0xb1, 0xd4, 0x61, 0xcf, 0xbe, 0x1, 0x0, 0x3d, 0x0, 0xdb, 0x8, 0x71, 0x3f, 0xc8, 0xb, 0xb2, +0x30, 0xd7, 0x7d, 0xac, 0xbe, 0x1, 0x0, 0x3d, 0x0, 0xe5, 0x4f, 0x7e, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x6, 0xcb, 0xea, +0xbd, 0x1, 0x0, 0x3d, 0x0, 0x77, 0x5c, 0x67, 0x3f, 0xa2, 0x33, 0x38, 0x3d, 0xfd, 0xf2, 0xd9, 0x3e, 0x1, 0x0, 0x3d, +0x0, 0xe9, 0x2e, 0x67, 0x3f, 0xd4, 0xd9, 0x48, 0x3d, 0x58, 0x79, 0xda, 0x3e, 0x1, 0x0, 0x3d, 0x0, 0xdd, 0x99, 0x76, +0x3f, 0x4b, 0xf7, 0x1e, 0xb4, 0x3a, 0x76, 0x89, 0xbe, 0x1, 0x0, 0x3d, 0x0, 0x4f, 0x3a, 0x79, 0x3f, 0xb4, 0xc0, 0x26, +0xb4, 0x92, 0xf9, 0x69, 0xbe, 0x1, 0x0, 0x3d, 0x0, 0xf9, 0xe8, 0x62, 0x3f, 0x41, 0xb4, 0xbc, 0xb3, 0x12, 0xc, 0xed, +0xbe, 0x1, 0x0, 0x3d, 0x0, 0x9a, 0x10, 0x53, 0x3f, 0x20, 0xf8, 0x3c, 0xb3, 0x1, 0xdf, 0x10, 0xbf, 0x1, 0x0, 0x3d, +0x0, 0xf, 0x44, 0x4a, 0x3f, 0x0, 0x0, 0x0, 0x0, 0xc, 0xec, 0x1c, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x85, 0x74, 0x30, +0x3f, 0x0, 0x0, 0x0, 0x0, 0xa3, 0x78, 0x39, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x95, 0x0, 0x97, 0x3e, 0x8f, 0xb2, 0x22, +0x3d, 0xd4, 0x66, 0x74, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0xfd, 0x55, 0x6b, 0x3e, 0x6a, 0x29, 0x34, 0x3d, 0xa2, 0xe4, 0x78, +0xbf, 0x1, 0x0, 0x3d, 0x0, 0xbc, 0xc7, 0x8e, 0x3d, 0x56, 0x6f, 0xd, 0x3d, 0x5d, 0x39, 0x7f, 0xbf, 0x1, 0x0, 0x3d, +0x0, 0x1f, 0xc2, 0x8e, 0xbd, 0x67, 0x93, 0x1a, 0x3d, 0xcb, 0x31, 0x7f, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x48, 0xfc, 0xb, +0xbe, 0x1d, 0x6f, 0xe8, 0x3c, 0x1c, 0x7e, 0x7d, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0xa5, 0xf4, 0x85, 0xbe, 0xda, 0x8a, 0x71, +0x3b, 0xc6, 0x14, 0x77, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0xd7, 0x64, 0xdd, 0xbe, 0x12, 0xcb, 0x9, 0x3c, 0xbd, 0xd1, 0x66, +0xbf, 0x1, 0x0, 0x3d, 0x0, 0x61, 0x78, 0xed, 0xbe, 0x0, 0x0, 0x0, 0x0, 0xa7, 0xcc, 0x62, 0xbf, 0x1, 0x0, 0x3d, +0x0, 0x6c, 0xe3, 0x2f, 0xbf, 0xaa, 0x48, 0xa4, 0x3c, 0x20, 0xf0, 0x39, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x6f, 0xbb, 0x77, +0xbf, 0xd0, 0x9e, 0x5e, 0x3d, 0xc9, 0x11, 0x7c, 0x3e, 0x1, 0x0, 0x3d, 0x0, 0x3a, 0x1b, 0x6a, 0xbf, 0xb6, 0x2, 0x60, +0x3d, 0xbd, 0x45, 0xcd, 0x3e, 0x1, 0x0, 0x3d, 0x0, 0xe9, 0x2a, 0x68, 0xbf, 0xda, 0xd7, 0x5c, 0x3d, 0x44, 0xf3, 0xd5, +0x3e, 0x1, 0x0, 0x3d, 0x0, 0x35, 0xa0, 0x94, 0xbe, 0x5c, 0x53, 0xe2, 0x33, 0xa, 0xfa, 0x74, 0x3f, 0x1, 0x0, 0x3d, +0x0, 0xbd, 0x72, 0x4c, 0xbd, 0x11, 0xe1, 0xaa, 0x33, 0x4f, 0xae, 0x7f, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x97, 0x99, 0x0, +0xbe, 0xe3, 0xa7, 0xfc, 0x33, 0x24, 0xf9, 0x7d, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x4b, 0x9a, 0xc1, 0x3d, 0xda, 0xce, 0x36, +0x33, 0x85, 0xda, 0x7e, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x5f, 0x12, 0x2a, 0x3e, 0xc4, 0xaf, 0x3c, 0x33, 0xcb, 0x71, 0x7c, +0x3f, 0x1, 0x0, 0x3d, 0x0, 0xb, 0x3a, 0xa1, 0x3e, 0x37, 0x32, 0xbc, 0x33, 0xf0, 0xf9, 0x72, 0x3f, 0x1, 0x0, 0x3d, +0x0, 0xea, 0xdd, 0x2b, 0x3f, 0xc0, 0x32, 0x38, 0x3d, 0x9a, 0x61, 0x3d, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x5c, 0x13, 0x2c, +0x3f, 0xa9, 0xd8, 0x48, 0x3d, 0x1a, 0x20, 0x3d, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x55, 0x74, 0xd9, 0x3c, 0x0, 0x0, 0x0, +0x0, 0xe8, 0xe8, 0x7f, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0x7f, 0xa0, 0xf2, 0xbd, 0x0, 0x0, 0x0, 0x0, 0x78, 0x32, 0x7e, +0xbf, 0x1, 0x4, 0x3d, 0x0, 0x13, 0xb5, 0x8c, 0x3d, 0x0, 0x0, 0x0, 0x0, 0x24, 0x65, 0x7f, 0xbf, 0x1, 0x4, 0x3d, +0x0, 0xa4, 0xad, 0x3a, 0xbe, 0xd0, 0xe0, 0x4c, 0xb4, 0xc7, 0xb5, 0x7b, 0xbf, 0x1, 0x4, 0x3d, 0x0, 0xe6, 0x56, 0xb5, +0xbe, 0x10, 0x48, 0xc2, 0xb4, 0xd0, 0x67, 0x6f, 0xbf, 0x1, 0x4, 0x3d, 0x0, 0x94, 0x19, 0x99, 0xbe, 0x7a, 0xc9, 0xc1, +0xb4, 0x75, 0x49, 0x74, 0xbf, 0x1, 0x4, 0x3d, 0x0, 0xa6, 0xa5, 0x53, 0xbf, 0xc2, 0xba, 0x22, 0x3d, 0xdd, 0xa8, 0xf, +0xbf, 0x1, 0x4, 0x3d, 0x0, 0x39, 0xd1, 0x5c, 0xbf, 0xe2, 0x32, 0x34, 0x3d, 0xd3, 0x7, 0x1, 0xbf, 0x1, 0x4, 0x3d, +0x0, 0x1e, 0xdb, 0x6e, 0xbf, 0x53, 0x73, 0xd, 0x3d, 0x7c, 0x5d, 0xb7, 0xbe, 0x1, 0x4, 0x3d, 0x0, 0xef, 0x43, 0x79, +0xbf, 0xb, 0x9c, 0x1a, 0x3d, 0x7, 0x1c, 0x66, 0xbe, 0x1, 0x4, 0x3d, 0x0, 0x99, 0xa6, 0x7c, 0xbf, 0x5b, 0x78, 0xe8, +0x3c, 0x70, 0x85, 0x22, 0xbe, 0x1, 0x4, 0x3d, 0x0, 0x76, 0xde, 0x7f, 0xbf, 0xa4, 0x9e, 0x71, 0x3b, 0x49, 0x26, 0x2, +0xbd, 0x1, 0x4, 0x3d, 0x0, 0x39, 0x17, 0x7d, 0xbf, 0x43, 0xd3, 0x9, 0x3c, 0xc9, 0xb2, 0x19, 0x3e, 0x1, 0x3, 0x3d, +0x0, 0x9b, 0x2b, 0x65, 0xbf, 0x27, 0x58, 0xa4, 0x3c, 0xd5, 0xf3, 0xe3, 0x3e, 0x1, 0x3, 0x3d, 0x0, 0xe, 0x4e, 0x42, +0xbd, 0x17, 0x9c, 0x5e, 0x3d, 0x40, 0x55, 0x7f, 0x3f, 0x1, 0x3, 0x3d, 0x0, 0xce, 0xbb, 0xed, 0x3d, 0xb2, 0x0, 0x60, +0x3d, 0x39, 0xe2, 0x7d, 0x3f, 0x1, 0x3, 0x3d, 0x0, 0xe7, 0xba, 0x9, 0x3e, 0xdd, 0xd5, 0x5c, 0x3d, 0x4d, 0x4c, 0x7d, +0x3f, 0x1, 0x3, 0x3d, 0x0, 0x47, 0x8d, 0x54, 0x3f, 0xe9, 0x80, 0xea, 0x33, 0x33, 0xae, 0xe, 0x3f, 0x1, 0x3, 0x3d, +0x0, 0x91, 0x72, 0x69, 0x3f, 0x9e, 0x8e, 0xcb, 0x33, 0x54, 0x20, 0xd2, 0x3e, 0x1, 0x3, 0x3d, 0x0, 0xce, 0xbc, 0x70, +0x3f, 0xb7, 0xab, 0xbb, 0x33, 0xa5, 0x24, 0xae, 0x3e, 0x1, 0x3, 0x3d, 0x0, 0x55, 0xc2, 0x7a, 0x3f, 0x1d, 0x89, 0x9a, +0x33, 0x13, 0x24, 0x4e, 0x3e, 0x1, 0x3, 0x3d, 0x0, 0x8f, 0xd1, 0x7d, 0x3f, 0x51, 0xbf, 0x88, 0x33, 0x9, 0x65, 0x5, +0x3e, 0x1, 0x3, 0x3d, 0x0, 0x55, 0xef, 0x7f, 0x3f, 0xe8, 0x60, 0x41, 0x33, 0x33, 0xc4, 0xb8, 0xbc, 0x1, 0x3, 0x3d, +0x0, 0xeb, 0x34, 0xf6, 0xbe, 0xd, 0x35, 0x38, 0x3d, 0xb5, 0x29, 0x60, 0xbf, 0x1, 0x3, 0x3d, 0x0, 0x7d, 0x93, 0xf5, +0xbe, 0x74, 0xdd, 0x48, 0x3d, 0xaa, 0x47, 0x60, 0xbf, 0x1, 0x3, 0x3d, 0x0, 0xff, 0xca, 0x6f, 0xbf, 0x2a, 0xfa, 0xbd, +0xb3, 0xb8, 0x47, 0xb3, 0xbe, 0x1, 0x3, 0x3d, 0x0, 0xe6, 0x41, 0x7a, 0xbf, 0x8e, 0xd3, 0x9c, 0xb3, 0xc6, 0xac, 0x57, +0xbe, 0x1, 0x3, 0x3d, 0x0, 0xa4, 0xce, 0x6b, 0xbf, 0x33, 0xd9, 0xc6, 0xb3, 0xf8, 0x4e, 0xc7, 0xbe, 0x1, 0x3, 0x3d, +0x0, 0x13, 0x38, 0x7d, 0xbf, 0x9a, 0x77, 0xb7, 0xb3, 0x91, 0x86, 0x16, 0xbe, 0x1, 0x2, 0x3d, 0x0, 0x16, 0xe8, 0x7f, +0xbf, 0xe9, 0xf1, 0xb1, 0xb3, 0xf1, 0x46, 0xdd, 0xbc, 0x1, 0x2, 0x3d, 0x0, 0x9d, 0xdf, 0x7f, 0xbf, 0xbb, 0x56, 0x88, +0xb3, 0x9, 0xc1, 0x0, 0x3d, 0x1, 0x2, 0x3d, 0x0, 0xa5, 0xb5, 0x4c, 0xbf, 0xd, 0xbe, 0x22, 0x3d, 0x39, 0x62, 0x19, +0x3f, 0x1, 0x2, 0x3d, 0x0, 0xc0, 0xdb, 0x41, 0xbf, 0xf7, 0x35, 0x34, 0x3d, 0x44, 0xd1, 0x26, 0x3f, 0x1, 0x2, 0x3d, +0x0, 0x6, 0x6e, 0x24, 0xbf, 0x39, 0x74, 0xd, 0x3d, 0x11, 0x3, 0x44, 0x3f, 0x1, 0x2, 0x3d, 0x0, 0x43, 0x7f, 0x7, +0xbf, 0xde, 0x9b, 0x1a, 0x3d, 0x8d, 0xfc, 0x58, 0x3f, 0x1, 0x2, 0x3d, 0x0, 0x65, 0x45, 0xf1, 0xbe, 0x13, 0x78, 0xe8, +0x3c, 0x6b, 0xad, 0x61, 0x3f, 0x1, 0x2, 0x3d, 0x0, 0x72, 0xcc, 0xb5, 0xbe, 0x88, 0xa0, 0x71, 0x3b, 0xb, 0x51, 0x6f, +0x3f, 0x1, 0x2, 0x3d, 0x0, 0xf1, 0xfe, 0x37, 0xbe, 0x4c, 0xd0, 0x9, 0x3c, 0x3, 0xd3, 0x7b, 0x3f, 0x1, 0x2, 0x3d, +0x0, 0x5a, 0x25, 0x5, 0x3e, 0xfc, 0x44, 0xa4, 0x3c, 0x5a, 0xc6, 0x7d, 0x3f, 0x1, 0x2, 0x3d, 0x0, 0x72, 0x77, 0x6d, +0x3f, 0x8f, 0x96, 0x5e, 0x3d, 0x24, 0x3b, 0xbd, 0x3e, 0x1, 0x2, 0x3d, 0x0, 0xb9, 0xb9, 0x79, 0x3f, 0x86, 0xfd, 0x5f, +0x3d, 0x57, 0x41, 0x5a, 0x3e, 0x1, 0x2, 0x3d, 0x0, 0x7, 0xb5, 0x7a, 0x3f, 0xcc, 0xd2, 0x5c, 0x3d, 0x65, 0xa8, 0x47, +0x3e, 0x1, 0x2, 0x3d, 0x0, 0xbb, 0x61, 0x4c, 0x3f, 0x2d, 0x3b, 0xdb, 0xb3, 0xf7, 0x27, 0x1a, 0xbf, 0x1, 0x2, 0x3d, +0x0, 0x73, 0xad, 0x2f, 0x3f, 0x41, 0x46, 0xb2, 0xb3, 0x3e, 0x35, 0x3a, 0xbf, 0x1, 0x2, 0x3d, 0x0, 0x1d, 0x10, 0x21, +0x3f, 0x52, 0x6a, 0x8f, 0xb3, 0xf9, 0xfb, 0x46, 0xbf, 0x1, 0x1, 0x3d, 0x0, 0xdb, 0xc3, 0x2, 0x3f, 0x31, 0xa3, 0xb1, +0xb3, 0x3b, 0x15, 0x5c, 0xbf, 0x1, 0x1, 0x3d, 0x0, 0x82, 0x2a, 0xe5, 0x3e, 0x5d, 0xd2, 0x23, 0xb4, 0xd7, 0xec, 0x64, +0xbf, 0x1, 0x1, 0x3d, 0x0, 0xe2, 0x9f, 0x9c, 0x3e, 0xd3, 0x1d, 0x73, 0xb4, 0x4b, 0xba, 0x73, 0xbf, 0x1, 0x1, 0x3d, +0x0, 0x14, 0x3b, 0x7b, 0xbf, 0xf, 0x37, 0x38, 0x3d, 0x5b, 0x45, 0x3f, 0x3e, 0x1, 0x1, 0x3d, 0x0, 0x2f, 0x3e, 0x7b, +0xbf, 0x79, 0xe1, 0x48, 0x3d, 0x84, 0xf6, 0x3d, 0x3e, 0x1, 0x1, 0x3d, 0x0, 0xe2, 0xf8, 0x1e, 0xbf, 0x45, 0x17, 0xeb, +0x33, 0x94, 0xa8, 0x48, 0x3f, 0x1, 0x1, 0x3d, 0x0, 0xac, 0x35, 0x0, 0xbf, 0x49, 0xa8, 0xea, 0x33, 0xd3, 0x94, 0x5d, +0x3f, 0x1, 0x1, 0x3d, 0x0, 0x7, 0x42, 0xe3, 0xbe, 0x79, 0xe, 0x87, 0x34, 0x76, 0x66, 0x65, 0x3f, 0x1, 0x1, 0x3d, +0x0, 0x55, 0x7a, 0xaa, 0xbe, 0xe9, 0x8, 0xe2, 0x34, 0x79, 0x64, 0x71, 0x3f, 0x1, 0x1, 0x3d, 0x0, 0x21, 0xfe, 0x8d, +0xbe, 0xa3, 0x5d, 0x10, 0x35, 0x59, 0xf5, 0x75, 0x3f, 0x1, 0x1, 0x3d, 0x0, 0xda, 0x4b, 0xa5, 0x3e, 0x83, 0xb7, 0x22, +0x3d, 0x7, 0x14, 0x72, 0x3f, 0x1, 0x1, 0x3d, 0x0, 0xec, 0x8c, 0xc5, 0x3e, 0x27, 0x2e, 0x34, 0x3d, 0x7b, 0xe8, 0x6b, +0x3f, 0x1, 0x1, 0x3d, 0x0, 0xf9, 0x9d, 0x7, 0x3f, 0x4c, 0x70, 0xd, 0x3d, 0x5b, 0xf2, 0x58, 0x3f, 0x1, 0x1, 0x3d, +0x0, 0x2f, 0x82, 0x24, 0x3f, 0x46, 0x93, 0x1a, 0x3d, 0x3c, 0xe8, 0x43, 0x3f, 0x1, 0x1, 0x3d, 0x0, 0x3d, 0x5c, 0x31, +0x3f, 0xd4, 0x6d, 0xe8, 0x3c, 0x82, 0x76, 0x38, 0x3f, 0x1, 0x1, 0x3d, 0x0, 0x47, 0x85, 0x47, 0x3f, 0xe5, 0x83, 0x71, +0x3b, 0x31, 0x65, 0x20, 0x3f, 0x1, 0x0, 0x3d, 0x0, 0x19, 0x48, 0x61, 0x3f, 0xa8, 0xc5, 0x9, 0x3c, 0x78, 0x24, 0xf3, +0x3e, 0x1, 0x0, 0x3d, 0x0, 0xc8, 0xa0, 0x7b, 0x3f, 0x95, 0x2a, 0xa4, 0x3c, 0x65, 0x51, 0x3b, 0x3e, 0x1, 0x0, 0x3d, +0x0, 0x8f, 0x62, 0x23, 0x3f, 0x72, 0x95, 0x5e, 0x3d, 0x29, 0x97, 0x44, 0xbf, 0x1, 0xbe, 0x3d, 0x0, 0x3c, 0x13, 0x1, +0x3f, 0x5e, 0xfd, 0x5f, 0x3d, 0x77, 0xa2, 0x5c, 0xbf, 0x1, 0x0, 0x3d, 0x0, 0xcd, 0xe9, 0xf9, 0x3e, 0xb7, 0xd2, 0x5c, +0x3d, 0x5c, 0x1, 0x5f, 0xbf, 0x1, 0xf4, 0x3d, 0x0, 0x9e, 0x56, 0xa6, 0xbe, 0x5d, 0x20, 0x13, 0xb4, 0x8, 0x1d, 0x72, +0xbf, 0x1, 0xf4, 0x3d, 0x0, 0x50, 0x38, 0xf5, 0xbe, 0x56, 0xb9, 0xc, 0xb4, 0x71, 0xba, 0x60, 0xbf, 0x1, 0xf4, 0x3d, +0x0, 0x69, 0x50, 0xb, 0xbf, 0x68, 0x41, 0xfd, 0xb3, 0xf9, 0xc5, 0x56, 0xbf, 0x1, 0xf4, 0x3d, 0x0, 0x9b, 0xce, 0x28, +0xbf, 0x35, 0x8d, 0xc4, 0xb3, 0x52, 0x75, 0x40, 0xbf, 0x1, 0xf4, 0x3d, 0x0, 0xde, 0x3e, 0x36, 0xbf, 0x68, 0xe5, 0x50, +0xb3, 0xe6, 0xc8, 0x33, 0xbf, 0x1, 0xf4, 0x3d, 0x0, 0xb3, 0x95, 0x4f, 0xbf, 0xbe, 0xa5, 0x9d, 0xb2, 0xac, 0xd0, 0x15, +0xbf, 0x1, 0xf4, 0x3d, 0x0, 0x61, 0xb1, 0xdd, 0xbd, 0xe, 0x36, 0x38, 0x3d, 0x33, 0x3c, 0x7e, 0x3f, 0x1, 0xf4, 0x3d, +0x0, 0x64, 0x20, 0xe0, 0xbd, 0x3e, 0xdf, 0x48, 0x3d, 0xc, 0x27, 0x7e, 0x3f, 0x1, 0xf4, 0x3d, 0x0, 0x6c, 0x92, 0x11, +0x3f, 0xe6, 0x63, 0xf2, 0x33, 0x3, 0x95, 0x52, 0x3f, 0x1, 0xf4, 0x3d, 0x0, 0xa2, 0x80, 0x2e, 0x3f, 0xaa, 0xcb, 0x6b, +0x33, 0x44, 0x4f, 0x3b, 0x3f, 0x1, 0xf4, 0x3d, 0x0, 0x33, 0xe6, 0x8, 0x3f, 0x32, 0x7f, 0x38, 0x34, 0x13, 0x52, 0x58, +0x3f, 0x1, 0xf4, 0x3d, 0x0, 0xdb, 0x36, 0x3a, 0x3f, 0x9, 0x6a, 0x54, 0x33, 0xbe, 0xab, 0x2f, 0x3f, 0x1, 0xf4, 0x3d, +0x0, 0xe3, 0xf0, 0x4d, 0x3f, 0xa2, 0x3c, 0xc5, 0x33, 0x1d, 0x11, 0x18, 0x3f, 0x1, 0xf4, 0x3d, 0x0, 0xd0, 0x74, 0x56, +0x3f, 0x45, 0x29, 0x11, 0x34, 0x3a, 0xcd, 0xb, 0x3f, 0x1, 0xf4, 0x3d, 0x0, 0x62, 0xaa, 0x7f, 0x3f, 0x71, 0xb0, 0x22, +0x3d, 0x5c, 0xb0, 0x3, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x8b, 0x7b, 0x7e, 0x3f, 0x3e, 0x26, 0x34, 0x3d, 0x85, 0x9f, 0xcb, +0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x91, 0x1f, 0x77, 0x3f, 0x86, 0x6d, 0xd, 0x3d, 0xb4, 0x7b, 0x84, 0xbe, 0x1, 0xf4, 0x3d, +0x0, 0xb3, 0x76, 0x6b, 0x3f, 0x23, 0x8e, 0x1a, 0x3d, 0xd6, 0xfe, 0xc7, 0xbe, 0x1, 0xf4, 0x3d, 0x0, 0x3a, 0x46, 0x64, +0x3f, 0xff, 0x68, 0xe8, 0x3c, 0xf8, 0x4a, 0xe7, 0xbe, 0x1, 0xf4, 0x3d, 0x0, 0x85, 0xc6, 0x53, 0x3f, 0x9b, 0x77, 0x71, +0x3b, 0xc2, 0xd3, 0xf, 0xbf, 0x1, 0xf4, 0x3d, 0x0, 0x75, 0x2d, 0x36, 0x3f, 0x8f, 0xc2, 0x9, 0x3c, 0x3d, 0xd7, 0x33, +0xbf, 0x1, 0xf4, 0x3d, 0x0, 0xe7, 0x4, 0xed, 0x3e, 0xce, 0x2c, 0xa4, 0x3c, 0xfe, 0xdb, 0x62, 0xbf, 0x1, 0xf4, 0x3d, +0x0, 0xf6, 0x38, 0xc, 0xbf, 0xef, 0x9a, 0x5e, 0x3d, 0xa1, 0xba, 0x55, 0xbf, 0x1, 0xf4, 0x3d, 0x0, 0xd3, 0x40, 0x2d, +0xbf, 0xcc, 0x0, 0x60, 0x3d, 0xeb, 0xf1, 0x3b, 0xbf, 0x1, 0xf4, 0x3d, 0x0, 0x87, 0xb9, 0x30, 0xbf, 0xd, 0xd6, 0x5c, +0x3d, 0xe, 0xb3, 0x38, 0xbf, 0x1, 0xf4, 0x3d, 0x0, 0x3d, 0xd7, 0x7f, 0xbf, 0xf2, 0x58, 0xb5, 0xb2, 0x56, 0x73, 0x10, +0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x5b, 0xb0, 0x7a, 0xbf, 0x51, 0xd5, 0xc3, 0x32, 0x9c, 0x80, 0x4f, 0x3e, 0x1, 0xf4, 0x3d, +0x0, 0xa0, 0x5, 0x76, 0xbf, 0xb6, 0xda, 0xa6, 0x33, 0x28, 0x8d, 0x8d, 0x3e, 0x1, 0xf4, 0x3d, 0x0, 0x3d, 0x3d, 0x69, +0xbf, 0x45, 0xd0, 0xfe, 0x33, 0xb1, 0xc, 0xd3, 0x3e, 0x1, 0xf4, 0x3d, 0x0, 0x23, 0x3, 0x61, 0xbf, 0x5c, 0xce, 0xe4, +0x33, 0x10, 0x2d, 0xf4, 0x3e, 0x1, 0xf4, 0x3d, 0x0, 0x2f, 0xad, 0x4b, 0xbf, 0x77, 0x8a, 0xb1, 0x33, 0x34, 0x16, 0x1b, +0x3f, 0x1, 0xf4, 0x3d, 0x0, 0xad, 0xdc, 0x91, 0xbc, 0x73, 0xf4, 0x7f, 0xbf, 0xbf, 0xfe, 0xc2, 0x3b, 0x1, 0xf4, 0x3d, +0x0, 0x71, 0x48, 0x34, 0x38, 0x0, 0x0, 0x80, 0xbf, 0xa2, 0x9e, 0x85, 0xb7, 0x1, 0xf4, 0x3d, 0x0, 0x3f, 0x91, 0xd5, +0xbc, 0xab, 0xe7, 0x7f, 0xbf, 0x23, 0xe3, 0x1, 0x3c, 0x1, 0xf4, 0x3d, 0x0, 0x42, 0x45, 0x82, 0xba, 0xbe, 0x77, 0x7f, +0xbf, 0x4a, 0xfb, 0x83, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x2d, 0x85, 0x8c, 0xba, 0xbb, 0xea, 0x7f, 0xbf, 0x36, 0x82, 0xd0, +0x3c, 0x1, 0xf4, 0x3d, 0x0, 0x92, 0x3e, 0xb1, 0x39, 0x8c, 0xe7, 0x7f, 0xbf, 0x4c, 0xbf, 0xdf, 0x3c, 0x1, 0xf4, 0x3d, +0x0, 0xa2, 0xbe, 0x7f, 0x3d, 0xc8, 0x75, 0x7f, 0xbf, 0xe5, 0x6e, 0x91, 0x3c, 0x1, 0xf4, 0x3d, 0x0, 0xc, 0x11, 0xc3, +0x3c, 0x60, 0xeb, 0x7f, 0xbf, 0xde, 0x68, 0x1, 0x3c, 0x1, 0xf4, 0x3d, 0x0, 0x9b, 0x2e, 0xd8, 0x3c, 0x82, 0xe7, 0x7f, +0xbf, 0xdb, 0xd6, 0xe9, 0x3b, 0x1, 0xf4, 0x3d, 0x0, 0xfa, 0x17, 0x94, 0x3c, 0x8e, 0x41, 0x7f, 0xbf, 0x9c, 0x8f, 0x97, +0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x7d, 0x37, 0x89, 0x3c, 0xcf, 0x4c, 0x7f, 0xbf, 0xe0, 0x67, 0x93, 0xbd, 0x1, 0xf4, 0x3d, +0x0, 0x17, 0x19, 0xd, 0x3d, 0x72, 0x56, 0x7f, 0xbf, 0x5a, 0x38, 0x81, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0xe, 0x86, 0x8e, +0xbd, 0xfb, 0x4b, 0x7f, 0xbf, 0xaf, 0xc5, 0xcf, 0xbc, 0x1, 0xf4, 0x3d, 0x0, 0xb2, 0xdc, 0x90, 0xbd, 0xfb, 0x52, 0x7f, +0xbf, 0x95, 0x9a, 0x86, 0xbc, 0x1, 0xf4, 0x3d, 0x0, 0x9f, 0xdd, 0x89, 0xbd, 0xa6, 0x47, 0x7f, 0xbf, 0xa4, 0x2, 0x7, +0xbd, 0x1, 0xf4, 0x3d, 0x0, 0xe5, 0xe, 0x96, 0xbd, 0x1b, 0x4f, 0x7f, 0xbf, 0x5e, 0x8d, 0x9b, 0xbb, 0x1, 0xf4, 0x3d, +0x0, 0x51, 0xb6, 0x9c, 0xbd, 0xa2, 0x3a, 0x7f, 0xbf, 0x21, 0x7d, 0x4e, 0xbc, 0x1, 0xf4, 0x3d, 0x0, 0xde, 0x5f, 0xb2, +0x3b, 0x85, 0x49, 0x7f, 0xbf, 0x5c, 0x51, 0x98, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0xf8, 0x54, 0xf7, 0x39, 0x16, 0x40, 0x7f, +0xbf, 0x7e, 0x9d, 0x9c, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0xeb, 0x95, 0x81, 0xbd, 0x80, 0x72, 0x7f, 0xbf, 0x14, 0x3c, 0x90, +0x3c, 0x1, 0xf4, 0x3d, 0x0, 0xe4, 0x75, 0x8d, 0xbd, 0x8c, 0x5f, 0x7f, 0xbf, 0x8f, 0x3a, 0x33, 0x3c, 0x1, 0xf4, 0x3d, +0x0, 0x5, 0x49, 0x7a, 0x3d, 0xcf, 0x45, 0x7f, 0xbf, 0xa3, 0x6c, 0x34, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x61, 0x69, 0x78, +0xbd, 0x7, 0x48, 0x7f, 0xbf, 0x9, 0xdf, 0x33, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x53, 0x12, 0x70, 0xbd, 0x9, 0x48, 0x7f, +0xbf, 0x56, 0xda, 0x3e, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x11, 0x3a, 0x58, 0xbc, 0x6e, 0x4a, 0x7f, 0xbf, 0x65, 0xed, 0x95, +0xbd, 0x1, 0xf4, 0x3d, 0x0, 0xf1, 0x4b, 0x88, 0xbc, 0xf8, 0x44, 0x7f, 0xbf, 0x5d, 0xd0, 0x96, 0xbd, 0x1, 0xf4, 0x3d, +0x0, 0x45, 0x4b, 0x0, 0xbd, 0x8, 0x63, 0x7f, 0xbf, 0xa7, 0x9c, 0x7c, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x65, 0xf2, 0xd, +0xbd, 0xb3, 0x5f, 0x7f, 0xbf, 0x3c, 0xa5, 0x78, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0xf6, 0x3, 0x6b, 0xbc, 0x6c, 0xeb, 0x7f, +0xbf, 0x12, 0x54, 0xa8, 0xbc, 0x1, 0xf4, 0x3d, 0x0, 0xc2, 0x18, 0x1d, 0xbd, 0x43, 0x72, 0x7f, 0xbf, 0xcc, 0xa9, 0x5a, +0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x38, 0x24, 0x95, 0x3d, 0xdc, 0x29, 0x7f, 0xbf, 0xc2, 0x22, 0xf, 0xbd, 0x1, 0xf4, 0x3d, +0x0, 0x93, 0x1b, 0x94, 0xbc, 0x31, 0x8c, 0x7f, 0xbf, 0x22, 0xdc, 0x67, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x4a, 0x20, 0xf4, +0xbb, 0xf5, 0x8f, 0x7f, 0xbf, 0xa3, 0x75, 0x6d, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0xac, 0xdc, 0x2f, 0xbc, 0x6c, 0xf3, 0x7f, +0xbf, 0xb8, 0x47, 0x86, 0xbc, 0x1, 0xf4, 0x3d, 0x0, 0x15, 0x4d, 0x85, 0x3c, 0x5c, 0xe7, 0x7f, 0xbf, 0xbc, 0xcb, 0xb4, +0xbc, 0x1, 0xf4, 0x3d, 0x0, 0x2c, 0x8d, 0x24, 0x3d, 0x64, 0x6f, 0x7f, 0xbf, 0x89, 0x85, 0x58, 0xbd, 0x1, 0xf4, 0x3d, +0x0, 0x55, 0x40, 0x7d, 0xbd, 0x71, 0x67, 0x7f, 0xbf, 0xd5, 0xa5, 0xeb, 0x3c, 0x1, 0xf4, 0x3d, 0x0, 0xd5, 0x86, 0x82, +0xbd, 0x24, 0x54, 0x7f, 0xbf, 0x44, 0x75, 0xc, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0xff, 0xc6, 0x6d, 0xbd, 0x17, 0x54, 0x7f, +0xbf, 0xa3, 0x19, 0x31, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x43, 0x75, 0xfc, 0xbd, 0x25, 0xc, 0x7e, 0xbf, 0x4c, 0x30, 0x51, +0xba, 0x1, 0xf4, 0x3d, 0x0, 0x72, 0x3d, 0x63, 0xbd, 0x21, 0x49, 0x7f, 0xbf, 0x6d, 0x9a, 0x4c, 0x3d, 0x1, 0xf4, 0x3d, +0x0, 0xf2, 0x8d, 0x4a, 0xbd, 0x4b, 0x4d, 0x7f, 0xbf, 0x37, 0x60, 0x60, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x24, 0x47, 0x38, +0xbd, 0x2, 0x4c, 0x7f, 0xbf, 0xbf, 0xfb, 0x70, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0xab, 0x3b, 0xc, 0xbd, 0xb8, 0x4e, 0x7f, +0xbf, 0x7d, 0x36, 0x85, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0xa2, 0x77, 0xfa, 0xbc, 0xb9, 0x4e, 0x7f, 0xbf, 0x67, 0xe5, 0x88, +0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x4, 0x8d, 0x5e, 0xbc, 0x4f, 0x62, 0x7f, 0xbf, 0x39, 0x3c, 0x8b, 0x3d, 0x1, 0xf4, 0x3d, +0x0, 0x10, 0x7d, 0xe7, 0xbb, 0x36, 0x5e, 0x7f, 0xbf, 0xc0, 0x16, 0x8f, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x3c, 0x5d, 0x53, +0x3c, 0x6e, 0x58, 0x7f, 0xbf, 0x2b, 0xf5, 0x8f, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x24, 0xed, 0x29, 0xbd, 0xbd, 0xf2, 0x7e, +0xbf, 0x38, 0xda, 0xa4, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0xdc, 0x58, 0xbd, 0xbc, 0xb0, 0x2b, 0x7f, 0xbf, 0x16, 0xc5, 0x9d, +0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x55, 0x42, 0xd4, 0x3c, 0x55, 0x4b, 0x7f, 0xbf, 0xd7, 0x66, 0x8e, 0x3d, 0x1, 0xf4, 0x3d, +0x0, 0x1b, 0x1e, 0x42, 0x3d, 0x68, 0x49, 0x7f, 0xbf, 0x4, 0xf6, 0x6b, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x38, 0x44, 0x2, +0x3d, 0x66, 0x47, 0x7f, 0xbf, 0xca, 0x1d, 0x8b, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0xaa, 0x87, 0x20, 0x3d, 0xda, 0x4e, 0x7f, +0xbf, 0x9c, 0x92, 0x7e, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0xfc, 0x37, 0x6f, 0x3d, 0x30, 0x49, 0x7f, 0xbf, 0xbb, 0x61, 0x3e, +0x3d, 0x1, 0xf4, 0x3d, 0x0, 0xa3, 0xba, 0x52, 0x3d, 0x14, 0x4e, 0x7f, 0xbf, 0x25, 0xca, 0x57, 0x3d, 0x1, 0xf4, 0x3d, +0x0, 0x5e, 0x44, 0x7c, 0x3d, 0xe7, 0x6b, 0x7f, 0xbf, 0x1b, 0x4, 0xdc, 0x3c, 0x1, 0xf4, 0x3d, 0x0, 0x7, 0x7c, 0x7e, +0x3d, 0x37, 0x5a, 0x7f, 0xbf, 0xe, 0x78, 0xd, 0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x54, 0x31, 0x95, 0x3d, 0x6e, 0x51, 0x7f, +0xbf, 0x86, 0x6c, 0x71, 0x3b, 0x1, 0xf4, 0x3d, 0x0, 0xaf, 0xa7, 0xb5, 0x3d, 0x52, 0xd, 0x7e, 0xbf, 0x44, 0xe6, 0xae, +0x3d, 0x1, 0xf4, 0x3d, 0x0, 0x64, 0xeb, 0xaa, 0x3d, 0xb0, 0xb5, 0x7e, 0xbf, 0x78, 0xaf, 0x63, 0x3d, 0x1, 0xf4, 0x3d, +0x0, 0x40, 0x2f, 0x9a, 0x3d, 0x63, 0x44, 0x7f, 0xbf, 0x2f, 0x70, 0xe6, 0xbb, 0x1, 0xf4, 0x3d, 0x0, 0xff, 0x24, 0x98, +0x3d, 0x57, 0x44, 0x7f, 0xbf, 0x83, 0xa0, 0x67, 0xbc, 0x1, 0xf4, 0x3d, 0x0, 0x2, 0xa0, 0x92, 0x3d, 0xd0, 0x48, 0x7f, +0xbf, 0x7a, 0x1c, 0xaf, 0xbc, 0x1, 0xf4, 0x3d, 0x0, 0x2d, 0x81, 0x8b, 0x3d, 0xe8, 0x45, 0x7f, 0xbf, 0xb5, 0x86, 0x3, +0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x62, 0xa0, 0x85, 0x3d, 0xf1, 0x48, 0x7f, 0xbf, 0xa9, 0xe7, 0x14, 0xbd, 0x1, 0xf4, 0x3d, +0x0, 0x13, 0x75, 0x71, 0x3d, 0x9d, 0x47, 0x7f, 0xbf, 0x20, 0xaa, 0x3d, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x7, 0x40, 0x45, +0x3d, 0x4d, 0x5f, 0x7f, 0xbf, 0xa1, 0x3, 0x50, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0xea, 0xc8, 0x33, 0x3c, 0x57, 0xf4, 0x7f, +0xbf, 0xff, 0x61, 0x7b, 0xbc, 0x1, 0xf4, 0x3d, 0x0, 0x57, 0xc3, 0x90, 0x3b, 0x45, 0xff, 0x7f, 0xbf, 0x49, 0xc9, 0xdd, +0xba, 0x1, 0xf4, 0x3d, 0x0, 0xca, 0x8d, 0x67, 0x3f, 0xc1, 0x72, 0x26, 0x3d, 0x67, 0x5a, 0xd9, 0x3e, 0x1, 0xf4, 0x3d, +0x0, 0x53, 0xbb, 0x77, 0x3f, 0xb9, 0x3c, 0xaa, 0x3c, 0x60, 0xa2, 0x80, 0x3e, 0x1, 0x0, 0x3d, 0x0, 0x73, 0xb5, 0x7e, +0x3f, 0x7f, 0x1a, 0x44, 0xb3, 0x84, 0x6f, 0xcd, 0xbd, 0x1, 0xf4, 0x3d, 0x0, 0x4f, 0x7b, 0x4, 0x3f, 0x5d, 0xa3, 0xf5, +0x3b, 0xa6, 0xb, 0x5b, 0xbf, 0x1, 0xbe, 0x3d, 0x0, 0x38, 0xa0, 0x89, 0x3e, 0x3, 0x9c, 0x2, 0x3d, 0x67, 0x71, 0x76, +0xbf, 0x1, 0x1e, 0x3d, 0x0, 0xd2, 0xb, 0x2a, 0x3e, 0x6c, 0x93, 0xb8, 0x3c, 0x32, 0x61, 0x7c, 0xbf, 0x1, 0x1e, 0x3d, +0x0, 0x2, 0x85, 0xd8, 0x3d, 0x5e, 0xb2, 0xb6, 0x3b, 0xb2, 0x8f, 0x7e, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x7f, 0x9, 0x49, +0x3d, 0x0, 0x0, 0x0, 0x0, 0x5, 0xb1, 0x7f, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x30, 0x16, 0x8c, 0x3b, 0x55, 0xb8, 0xa2, +0x3b, 0x99, 0xfe, 0x7f, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x82, 0x63, 0xb9, 0xbd, 0x60, 0xe9, 0x23, 0x3d, 0x3a, 0xbe, 0x7e, +0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x45, 0xb6, 0x19, 0xbe, 0xff, 0xa0, 0x89, 0x3c, 0x15, 0x10, 0x7d, 0xbf, 0x1, 0x1e, 0x3d, +0x0, 0x9c, 0x35, 0x52, 0xbe, 0xa1, 0x99, 0x71, 0x3b, 0xd0, 0x8b, 0x7a, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x12, 0x4f, 0x8e, +0xbe, 0x8a, 0x79, 0x2, 0x3c, 0x7d, 0xe7, 0x75, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0xf, 0x45, 0x39, 0xbf, 0x45, 0xc1, 0xd8, +0x3c, 0x6c, 0x89, 0x30, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x84, 0xc1, 0x52, 0xbf, 0x54, 0xad, 0xee, 0x3b, 0xe6, 0x4e, 0x11, +0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x49, 0x4a, 0x7f, 0xbf, 0x7b, 0x1e, 0x54, 0x3c, 0x47, 0x15, 0x96, 0xbd, 0x1, 0x1e, 0x3d, +0x0, 0xd0, 0x50, 0x69, 0xbf, 0x3d, 0x63, 0x55, 0x3d, 0x1d, 0x4, 0xd1, 0x3e, 0x1, 0x1e, 0x3d, 0x0, 0xbf, 0xda, 0x21, +0xbf, 0x2b, 0xa4, 0x3f, 0x3c, 0x7e, 0x51, 0x46, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xe1, 0xf6, 0xb5, 0x3e, 0x6e, 0x5c, 0xf, +0x34, 0x76, 0x49, 0x6f, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x50, 0x40, 0xf5, 0x3e, 0x7c, 0x18, 0xe, 0x34, 0x42, 0xb8, 0x60, +0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xf3, 0x74, 0x42, 0x3f, 0x86, 0x40, 0xab, 0x3c, 0x35, 0x6a, 0x26, 0x3f, 0x1, 0x1e, 0x3d, +0x0, 0x3e, 0xa6, 0x2b, 0x3f, 0x41, 0x71, 0x26, 0x3d, 0x7c, 0xa4, 0x3d, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0xe9, 0x5c, 0x7, +0x3f, 0x9c, 0x40, 0xaa, 0x3c, 0x58, 0x38, 0x59, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x42, 0x55, 0x4d, 0x3e, 0x0, 0x0, 0x0, +0x0, 0xee, 0xcc, 0x7a, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x7f, 0xf6, 0xfa, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x23, 0x5f, +0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x67, 0x95, 0x2a, 0xbf, 0xab, 0x5a, 0xf6, 0x3b, 0x2f, 0xe0, 0x3e, 0xbf, 0x1, 0x1e, 0x3d, +0x0, 0x2b, 0x8e, 0x57, 0xbf, 0x36, 0xb3, 0x2, 0x3d, 0xf8, 0xdb, 0x9, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x9c, 0xef, 0x64, +0xbf, 0x6, 0xc7, 0xb8, 0x3c, 0xea, 0xd4, 0xe4, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0x92, 0x8a, 0x6b, 0xbf, 0x74, 0xdd, 0xb6, +0x3b, 0xba, 0x8a, 0xc8, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0x77, 0xdc, 0x70, 0xbf, 0xb6, 0x5c, 0x3b, 0xb4, 0x2e, 0x75, 0xad, +0xbe, 0x1, 0x1e, 0x3d, 0x0, 0xfd, 0x80, 0x74, 0xbf, 0x3e, 0xd3, 0xa2, 0x3b, 0xe3, 0xaf, 0x97, 0xbe, 0x1, 0x1e, 0x3d, +0x0, 0xc7, 0x67, 0x7a, 0xbf, 0xf9, 0xe, 0x24, 0x3d, 0xd3, 0xeb, 0x50, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0xee, 0x41, 0x7d, +0xbf, 0xf4, 0xc5, 0x89, 0x3c, 0x6e, 0x7d, 0x14, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0xe1, 0xf9, 0x7e, 0xbf, 0xdd, 0xe3, 0x71, +0x3b, 0x11, 0xd5, 0xb6, 0xbd, 0x1, 0x1e, 0x3d, 0x0, 0xf6, 0xf6, 0x7f, 0xbf, 0x67, 0x92, 0x2, 0x3c, 0xb8, 0xbc, 0x6e, +0xbc, 0x1, 0x1e, 0x3d, 0x0, 0xf0, 0x88, 0x7b, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x21, 0x6b, 0x3e, 0x3e, 0x1, 0x1e, 0x3d, +0x0, 0xc5, 0xc3, 0x5e, 0xbf, 0x28, 0xf4, 0xd8, 0x3c, 0x7f, 0xeb, 0xfb, 0x3e, 0x1, 0x1e, 0x3d, 0x0, 0x85, 0x40, 0x48, +0xbf, 0x62, 0xd2, 0xee, 0x3b, 0x18, 0x79, 0x1f, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x7c, 0x92, 0x23, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x3e, 0xed, 0x44, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x21, 0xc3, 0xb7, 0xbe, 0x19, 0xfd, 0x53, 0x3c, 0x96, 0xeb, 0x6e, +0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x1d, 0xff, 0xfd, 0x3d, 0x31, 0x5f, 0x55, 0x3d, 0x5c, 0xac, 0x7d, 0x3f, 0x1, 0x1e, 0x3d, +0x0, 0x15, 0x99, 0xe, 0x3f, 0xea, 0x18, 0x3f, 0x3c, 0x14, 0x96, 0x54, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x1f, 0x76, 0x7f, +0x3f, 0x51, 0x5d, 0x2a, 0x33, 0xec, 0xc6, 0x84, 0xbd, 0x1, 0x1e, 0x3d, 0x0, 0xa0, 0xf8, 0x7a, 0x3f, 0x13, 0xc1, 0xbf, +0x32, 0x0, 0xf8, 0x49, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0x48, 0xd9, 0x58, 0x3f, 0x13, 0xc0, 0xaa, 0x3c, 0xd9, 0xf4, 0x7, +0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x8e, 0xd4, 0xf6, 0xbe, 0x9b, 0x75, 0x26, 0x3d, 0xb3, 0xb, 0x60, 0xbf, 0x1, 0x1e, 0x3d, +0x0, 0x61, 0xee, 0x20, 0xbf, 0x35, 0x4d, 0xab, 0x3c, 0xd3, 0x4, 0x47, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x3, 0x77, 0x5c, +0xbf, 0xcd, 0x8b, 0xe0, 0xb3, 0xbc, 0x1e, 0x2, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0xf1, 0xbe, 0x7b, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x6a, 0xe7, 0x39, 0x3e, 0x1, 0x1e, 0x3d, 0x0, 0x20, 0xc4, 0x6b, 0xbf, 0x86, 0xc3, 0xf6, 0x3b, 0x2d, 0x77, 0xc7, +0x3e, 0x1, 0x1e, 0x3d, 0x0, 0x1e, 0x6c, 0x48, 0xbf, 0x6c, 0xba, 0x2, 0x3d, 0x68, 0xf, 0x1f, 0x3f, 0x1, 0x1e, 0x3d, +0x0, 0x30, 0x86, 0x36, 0xbf, 0x69, 0xd2, 0xb8, 0x3c, 0xb2, 0x68, 0x33, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xf7, 0x4f, 0x2b, +0xbf, 0x56, 0xeb, 0xb6, 0x3b, 0xed, 0x39, 0x3e, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x50, 0x42, 0x20, 0xbf, 0xf3, 0x55, 0x2b, +0x35, 0xdc, 0xa1, 0x47, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x19, 0x29, 0x17, 0xbf, 0xd4, 0xda, 0xa2, 0x3b, 0x6b, 0x9a, 0x4e, +0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x56, 0xb2, 0x2, 0xbf, 0xf1, 0xd, 0x24, 0x3d, 0x7a, 0xe2, 0x5b, 0x3f, 0x1, 0x1e, 0x3d, +0x0, 0xd9, 0x9a, 0xea, 0xbe, 0xe8, 0xc3, 0x89, 0x3c, 0xc3, 0x80, 0x63, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x9f, 0xb1, 0xd0, +0xbe, 0x51, 0xdd, 0x71, 0x3b, 0x40, 0xc4, 0x69, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xd7, 0x4f, 0xad, 0xbe, 0xc5, 0x8b, 0x2, +0x3c, 0xf9, 0xe0, 0x70, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x38, 0x9b, 0x11, 0xbe, 0x39, 0x59, 0x7a, 0x34, 0x14, 0x66, 0x7d, +0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x19, 0xb8, 0x3b, 0x3e, 0x9c, 0xa7, 0xd8, 0x3c, 0x13, 0x92, 0x7b, 0x3f, 0x1, 0x1e, 0x3d, +0x0, 0xca, 0xc9, 0xab, 0x3e, 0xf2, 0x70, 0xee, 0x3b, 0x27, 0x27, 0x71, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x15, 0x2b, 0x5, +0x3f, 0x4, 0x8, 0xd, 0x34, 0x1c, 0xa3, 0x5a, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x72, 0xb, 0x44, 0x3f, 0xc0, 0x61, 0x53, +0x3c, 0x5e, 0x98, 0x24, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xf1, 0x2f, 0x7a, 0x3f, 0x31, 0x59, 0x55, 0x3d, 0xa0, 0x50, 0x52, +0x3e, 0x1, 0x1e, 0x3d, 0x0, 0x2, 0x94, 0x77, 0x3f, 0x1e, 0xb5, 0x3e, 0x3c, 0x42, 0x1c, 0x82, 0xbe, 0x1, 0x1e, 0x3d, +0x0, 0xe8, 0x50, 0x88, 0x3e, 0xa0, 0xba, 0x9d, 0xb4, 0x8f, 0xc2, 0x76, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0xb5, 0x5c, 0xd, +0x3e, 0x5c, 0xc6, 0x9f, 0xb4, 0x85, 0x8c, 0x7d, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x2f, 0x2c, 0x63, 0xbe, 0xb9, 0x95, 0xab, +0x3c, 0x2d, 0x90, 0x79, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0xb1, 0x36, 0x7b, 0xbf, 0x56, 0x79, 0x26, 0x3d, 0xa2, 0xa4, 0x40, +0x3e, 0x1, 0x1e, 0x3d, 0x0, 0x39, 0x85, 0x6e, 0xbf, 0x47, 0xf4, 0xab, 0x3c, 0xb4, 0xa2, 0xb9, 0x3e, 0x1, 0x1e, 0x3d, +0x0, 0xcc, 0xe3, 0x3e, 0xbf, 0xd6, 0x7b, 0xcb, 0x33, 0x23, 0x94, 0x2a, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x72, 0xd4, 0x3, +0xbe, 0x2a, 0x39, 0xfc, 0x34, 0xa2, 0xde, 0x7d, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x37, 0xd2, 0xb4, 0x3d, 0xba, 0x4f, 0xf6, +0x3b, 0x34, 0xfe, 0x7e, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xd9, 0xe1, 0xb2, 0x3e, 0x34, 0xa8, 0x2, 0x3d, 0x6a, 0xba, 0x6f, +0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x43, 0xb5, 0xe4, 0x3e, 0x62, 0xa5, 0xb8, 0x3c, 0x89, 0xf7, 0x64, 0x3f, 0x1, 0x1e, 0x3d, +0x0, 0x65, 0x13, 0x0, 0x3f, 0xdd, 0xb9, 0xb6, 0x3b, 0x77, 0xa7, 0x5d, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xbc, 0x68, 0xc, +0x3f, 0x4c, 0x17, 0xc, 0x34, 0x20, 0xf, 0x56, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x1c, 0xd6, 0x15, 0x3f, 0x8f, 0xbe, 0xa2, +0x3b, 0xc8, 0x90, 0x4f, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x5f, 0xc9, 0x28, 0x3f, 0x35, 0xe6, 0x23, 0x3d, 0x14, 0x34, 0x40, +0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xcb, 0x29, 0x34, 0x3f, 0xb9, 0x9a, 0x89, 0x3c, 0x11, 0xd2, 0x35, 0x3f, 0x1, 0x1e, 0x3d, +0x0, 0xc8, 0x1c, 0x3e, 0x3f, 0xaf, 0x91, 0x71, 0x3b, 0x2a, 0x71, 0x2b, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x89, 0x52, 0x4a, +0x3f, 0xb2, 0x6f, 0x2, 0x3c, 0xfe, 0xd5, 0x1c, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x28, 0xb8, 0x65, 0x3f, 0x6, 0x77, 0x89, +0x34, 0xf6, 0xf6, 0xe1, 0x3e, 0x1, 0x1e, 0x3d, 0x0, 0x4e, 0xbb, 0x7d, 0x3f, 0x4, 0x44, 0xd8, 0x3c, 0x2a, 0x4d, 0x5, +0x3e, 0x1, 0x1e, 0x3d, 0x0, 0xbb, 0xe6, 0x7f, 0x3f, 0x37, 0x4, 0xee, 0x3b, 0xf5, 0x89, 0xdb, 0xbc, 0x1, 0x1e, 0x3d, +0x0, 0x10, 0x7b, 0x59, 0x3f, 0x21, 0x1c, 0x53, 0x3c, 0x23, 0x2, 0x7, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0xad, 0xaf, 0xfe, +0x3e, 0x6c, 0x59, 0x55, 0x3d, 0x6, 0xae, 0x5d, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x7e, 0x1c, 0x75, 0x3d, 0x5, 0xff, 0x3e, +0x3c, 0x17, 0x86, 0x7f, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0xe, 0x9e, 0x55, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x86, 0x14, 0xd, +0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x8f, 0x4d, 0x66, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x72, 0x93, 0xdf, 0xbe, 0x1, 0x1e, 0x3d, +0x0, 0x8d, 0xf8, 0x7e, 0xbf, 0xea, 0xa0, 0xac, 0x3c, 0xd7, 0x4c, 0xb2, 0xbd, 0x1, 0x1e, 0x3d, 0x0, 0x4b, 0xeb, 0xda, +0xbd, 0x3e, 0x77, 0x26, 0x3d, 0xc, 0x52, 0x7e, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x46, 0xfb, 0xa2, 0x3d, 0x14, 0x46, 0xab, +0x3c, 0xc8, 0x21, 0x7f, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xe2, 0x27, 0xd8, 0x3e, 0xd7, 0xb5, 0x3b, 0x34, 0x31, 0x11, 0x68, +0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x75, 0x19, 0x69, 0x3f, 0x3a, 0x47, 0xff, 0x33, 0x8d, 0xaa, 0xd3, 0x3e, 0x1, 0x1e, 0x3d, +0x0, 0x1a, 0x67, 0x7a, 0x3f, 0x74, 0x99, 0xf5, 0x3b, 0x23, 0xd2, 0x54, 0x3e, 0x1, 0x1e, 0x3d, 0x0, 0xea, 0x68, 0x7f, +0x3f, 0x4e, 0x94, 0x2, 0x3d, 0xd1, 0x64, 0x75, 0xbd, 0x1, 0x1e, 0x3d, 0x0, 0x8c, 0x6d, 0x7c, 0x3f, 0x5d, 0x7d, 0xb8, +0x3c, 0xda, 0xe5, 0x28, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0x7d, 0x74, 0x79, 0x3f, 0xd6, 0x9d, 0xb6, 0x3b, 0x37, 0xff, 0x65, +0xbe, 0x1, 0x1e, 0x3d, 0x0, 0x4a, 0xcd, 0x75, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x8d, 0x12, 0x8f, 0xbe, 0x1, 0x1e, 0x3d, +0x0, 0x51, 0x5a, 0x72, 0x3f, 0x3f, 0xa6, 0xa2, 0x3b, 0x12, 0xeb, 0xa4, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0xa6, 0x3d, 0x69, +0x3f, 0x38, 0xd0, 0x23, 0x3d, 0xf7, 0xb, 0xd2, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0xdb, 0xaa, 0x62, 0x3f, 0xe5, 0x86, 0x89, +0x3c, 0x92, 0xd1, 0xed, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0x5b, 0xad, 0x5b, 0x3f, 0xc2, 0x6b, 0x71, 0x3b, 0x34, 0x71, 0x3, +0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x10, 0x42, 0x51, 0x3f, 0xc4, 0x63, 0x2, 0x3c, 0x6c, 0x74, 0x13, 0xbf, 0x1, 0x1e, 0x3d, +0x0, 0xd8, 0x9, 0xd5, 0x3e, 0xbf, 0x52, 0xd8, 0x3c, 0x44, 0xb0, 0x68, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x9b, 0x88, 0x89, +0x3e, 0xaf, 0x26, 0xee, 0x3b, 0x81, 0x95, 0x76, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x33, 0x94, 0x8a, 0x3d, 0x0, 0x0, 0x0, +0x0, 0xcd, 0x69, 0x7f, 0xbf, 0x1, 0x1e, 0x3d, 0x0, 0x13, 0xc, 0x82, 0xbe, 0x3b, 0x93, 0x53, 0x3c, 0x14, 0x95, 0x77, +0xbf, 0x1, 0x1e, 0x3d, 0x0, 0xa6, 0xc1, 0x2e, 0xbf, 0xbb, 0x5f, 0x55, 0x3d, 0xc5, 0x98, 0x3a, 0xbf, 0x1, 0x1e, 0x3d, +0x0, 0x24, 0xf0, 0x6f, 0xbf, 0x4d, 0x94, 0x3f, 0x3c, 0xc6, 0x66, 0xb2, 0xbe, 0x1, 0x1e, 0x3d, 0x0, 0x4b, 0xe8, 0x44, +0xbf, 0xba, 0xc, 0x38, 0x33, 0x73, 0x98, 0x23, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0xc3, 0x16, 0x2d, 0xbf, 0xd4, 0x7e, 0x7f, +0x33, 0xdb, 0x9d, 0x3c, 0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x74, 0x79, 0xbc, 0xbe, 0xba, 0x67, 0xac, 0x3c, 0x7e, 0xf6, 0x6d, +0x3f, 0x1, 0x1e, 0x3d, 0x0, 0x58, 0x89, 0x8b, 0x39, 0xa4, 0xba, 0x51, 0xbe, 0xb4, 0x92, 0x7a, 0x3f, 0x1, 0x90, 0x40, +0x0, 0x8d, 0x39, 0xc8, 0x39, 0xec, 0xd8, 0xea, 0x2c, 0xff, 0xff, 0x7f, 0x3f, 0x1, 0x90, 0x40, 0x0, 0x58, 0x89, 0x8b, +0x39, 0xa4, 0xba, 0xd1, 0xbe, 0x6a, 0x89, 0x69, 0x3f, 0x1, 0x90, 0x40, 0x0, 0x59, 0x89, 0x8b, 0x39, 0xa3, 0xb3, 0x3d, +0xbf, 0x25, 0xe6, 0x2b, 0x3f, 0x1, 0x90, 0x40, 0x0, 0x5b, 0x89, 0x8b, 0x39, 0x4f, 0x1b, 0x5e, 0xbf, 0x42, 0x98, 0xfe, +0x3e, 0x1, 0x90, 0x40, 0x0, 0x59, 0x89, 0x8b, 0x39, 0xf8, 0x82, 0x7e, 0xbf, 0x96, 0x85, 0xdc, 0x3d, 0x1, 0x90, 0x40, +0x0, 0x56, 0x89, 0x8b, 0x39, 0xf8, 0x82, 0x7e, 0xbf, 0x91, 0x85, 0xdc, 0xbd, 0x1, 0x90, 0x40, 0x0, 0x57, 0x89, 0x8b, +0x39, 0x52, 0x1b, 0x5e, 0xbf, 0x39, 0x98, 0xfe, 0xbe, 0x1, 0x90, 0x40, 0x0, 0x57, 0x89, 0x8b, 0x39, 0xa5, 0xb3, 0x3d, +0xbf, 0x22, 0xe6, 0x2b, 0xbf, 0x1, 0x90, 0x40, 0x0, 0x54, 0x89, 0x8b, 0x39, 0x94, 0xba, 0xd1, 0xbe, 0x6e, 0x89, 0x69, +0xbf, 0x1, 0x90, 0x40, 0x0, 0x5a, 0x89, 0x8b, 0x39, 0x7f, 0xba, 0x51, 0xbe, 0xb6, 0x92, 0x7a, 0xbf, 0x1, 0x90, 0x40, +0x0, 0x8d, 0x39, 0xc8, 0x39, 0x67, 0x1c, 0x64, 0x35, 0xff, 0xff, 0x7f, 0xbf, 0x1, 0x90, 0x40, 0x0, 0xa7, 0x7a, 0x29, +0x39, 0xb2, 0xba, 0x51, 0xbe, 0xb3, 0x92, 0x7a, 0x3f, 0x1, 0x91, 0x43, 0x0, 0xb0, 0x30, 0x73, 0x39, 0x3a, 0x6b, 0x2b, +0xac, 0x0, 0x0, 0x80, 0x3f, 0x1, 0x91, 0x43, 0x0, 0xd8, 0x74, 0x29, 0x39, 0xb0, 0xba, 0xd1, 0xbe, 0x68, 0x89, 0x69, +0x3f, 0x1, 0x91, 0x43, 0x0, 0x75, 0x6b, 0x29, 0x39, 0xa8, 0xb3, 0x3d, 0xbf, 0x20, 0xe6, 0x2b, 0x3f, 0x1, 0x91, 0x43, +0x0, 0x77, 0x6b, 0x29, 0x39, 0x4f, 0x1b, 0x5e, 0xbf, 0x43, 0x98, 0xfe, 0x3e, 0x1, 0x91, 0x43, 0x0, 0x44, 0x71, 0x29, +0x39, 0xf9, 0x82, 0x7e, 0xbf, 0x8e, 0x85, 0xdc, 0x3d, 0x1, 0x91, 0x43, 0x0, 0x41, 0x71, 0x29, 0x39, 0xf8, 0x82, 0x7e, +0xbf, 0xb9, 0x85, 0xdc, 0xbd, 0x1, 0x91, 0x43, 0x0, 0x75, 0x6b, 0x29, 0x39, 0x51, 0x1b, 0x5e, 0xbf, 0x3e, 0x98, 0xfe, +0xbe, 0x1, 0x91, 0x43, 0x0, 0xaa, 0x65, 0x29, 0x39, 0xa7, 0xb3, 0x3d, 0xbf, 0x21, 0xe6, 0x2b, 0xbf, 0x1, 0x91, 0x43, +0x0, 0xa, 0x6f, 0x29, 0x39, 0x9c, 0xba, 0xd1, 0xbe, 0x6d, 0x89, 0x69, 0xbf, 0x1, 0x91, 0x43, 0x0, 0xd8, 0x74, 0x29, +0x39, 0x8c, 0xba, 0x51, 0xbe, 0xb6, 0x92, 0x7a, 0xbf, 0x1, 0x91, 0x43, 0x0, 0xb0, 0x30, 0x73, 0x39, 0x1a, 0x6a, 0x9, +0x35, 0x0, 0x0, 0x80, 0xbf, 0x1, 0x91, 0x43, 0x0, 0xa6, 0x88, 0x27, 0x3a, 0x87, 0xfc, 0x28, 0xad, 0xfd, 0xff, 0x7f, +0x3f, 0x1, 0x91, 0x46, 0x0, 0x20, 0x82, 0xe9, 0x39, 0xa4, 0xba, 0x51, 0xbe, 0xb3, 0x92, 0x7a, 0x3f, 0x1, 0x91, 0x46, +0x0, 0x20, 0x82, 0xe9, 0x39, 0xa4, 0xba, 0xd1, 0xbe, 0x69, 0x89, 0x69, 0x3f, 0x1, 0x91, 0x46, 0x0, 0x21, 0x82, 0xe9, +0x39, 0xa2, 0xb3, 0x3d, 0xbf, 0x23, 0xe6, 0x2b, 0x3f, 0x1, 0x91, 0x46, 0x0, 0x24, 0x82, 0xe9, 0x39, 0x4e, 0x1b, 0x5e, +0xbf, 0x41, 0x98, 0xfe, 0x3e, 0x1, 0x91, 0x46, 0x0, 0x20, 0x82, 0xe9, 0x39, 0xf7, 0x82, 0x7e, 0xbf, 0x95, 0x85, 0xdc, +0x3d, 0x1, 0x91, 0x46, 0x0, 0x1b, 0x82, 0xe9, 0x39, 0xf8, 0x82, 0x7e, 0xbf, 0x91, 0x85, 0xdc, 0xbd, 0x1, 0x92, 0x46, +0x0, 0x1c, 0x82, 0xe9, 0x39, 0x51, 0x1b, 0x5e, 0xbf, 0x39, 0x98, 0xfe, 0xbe, 0x1, 0x92, 0x46, 0x0, 0x1c, 0x82, 0xe9, +0x39, 0xa5, 0xb3, 0x3d, 0xbf, 0x21, 0xe6, 0x2b, 0xbf, 0x1, 0x92, 0x46, 0x0, 0x1a, 0x82, 0xe9, 0x39, 0x94, 0xba, 0xd1, +0xbe, 0x6d, 0x89, 0x69, 0xbf, 0x1, 0x92, 0x46, 0x0, 0x22, 0x82, 0xe9, 0x39, 0x7e, 0xba, 0x51, 0xbe, 0xb5, 0x92, 0x7a, +0xbf, 0x1, 0x92, 0x46, 0x0, 0xa6, 0x88, 0x27, 0x3a, 0x48, 0x1b, 0x64, 0x35, 0xfd, 0xff, 0x7f, 0xbf, 0x1, 0x92, 0x46, +0x0, 0xb0, 0x30, 0x73, 0x39, 0xa2, 0xe9, 0xa0, 0x2c, 0x0, 0x0, 0x80, 0x3f, 0x1, 0x92, 0x49, 0x0, 0x6f, 0x80, 0x29, +0x39, 0xad, 0xba, 0x51, 0xbe, 0xb3, 0x92, 0x7a, 0x3f, 0x1, 0x92, 0x49, 0x0, 0x3b, 0x86, 0x29, 0x39, 0xac, 0xba, 0xd1, +0xbe, 0x69, 0x89, 0x69, 0x3f, 0x1, 0x92, 0x49, 0x0, 0x9c, 0x8f, 0x29, 0x39, 0xa5, 0xb3, 0x3d, 0xbf, 0x22, 0xe6, 0x2b, +0x3f, 0x1, 0x92, 0x49, 0x0, 0xd5, 0x89, 0x29, 0x39, 0x4f, 0x1b, 0x5e, 0xbf, 0x43, 0x98, 0xfe, 0x3e, 0x1, 0x92, 0x49, +0x0, 0x9, 0x84, 0x29, 0x39, 0xf9, 0x82, 0x7e, 0xbf, 0x8e, 0x85, 0xdc, 0x3d, 0x1, 0x60, 0x49, 0x0, 0x5, 0x84, 0x29, +0x39, 0xf8, 0x82, 0x7e, 0xbf, 0xb9, 0x85, 0xdc, 0xbd, 0x1, 0x60, 0x49, 0x0, 0xd2, 0x89, 0x29, 0x39, 0x51, 0x1b, 0x5e, +0xbf, 0x3e, 0x98, 0xfe, 0xbe, 0x1, 0x60, 0x49, 0x0, 0xa0, 0x8f, 0x29, 0x39, 0xa7, 0xb3, 0x3d, 0xbf, 0x21, 0xe6, 0x2b, +0xbf, 0x1, 0x60, 0x49, 0x0, 0x3d, 0x86, 0x29, 0x39, 0x9c, 0xba, 0xd1, 0xbe, 0x6d, 0x89, 0x69, 0xbf, 0x1, 0x60, 0x49, +0x0, 0x71, 0x80, 0x29, 0x39, 0x8c, 0xba, 0x51, 0xbe, 0xb6, 0x92, 0x7a, 0xbf, 0x1, 0x60, 0x49, 0x0, 0xb0, 0x30, 0x73, +0x39, 0x95, 0x6a, 0x9, 0x35, 0x0, 0x0, 0x80, 0xbf, 0x1, 0x60, 0x49, 0x0, 0x14, 0x4, 0x9f, 0x38, 0xad, 0xba, 0x51, +0xbe, 0xb4, 0x92, 0x7a, 0x3f, 0x1, 0x61, 0x0, 0x0, 0x29, 0x2d, 0xe4, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x1, 0x61, 0x0, 0x0, 0x1c, 0xfc, 0x9e, 0x38, 0xa7, 0xba, 0xd1, 0xbe, 0x6a, 0x89, 0x69, 0x3f, 0x1, 0x61, 0x0, +0x0, 0x3b, 0xef, 0x9e, 0x38, 0xa2, 0xb3, 0x3d, 0xbf, 0x25, 0xe6, 0x2b, 0x3f, 0x1, 0x61, 0x0, 0x0, 0x3b, 0xef, 0x9e, +0x38, 0x4c, 0x1b, 0x5e, 0xbf, 0x50, 0x98, 0xfe, 0x3e, 0x1, 0x61, 0x0, 0x0, 0x2f, 0xf7, 0x9e, 0x38, 0xf9, 0x82, 0x7e, +0xbf, 0xb2, 0x85, 0xdc, 0x3d, 0x1, 0x61, 0x0, 0x0, 0x9, 0x4, 0x9f, 0x38, 0xf8, 0x82, 0x7e, 0xbf, 0xf2, 0x85, 0xdc, +0xbd, 0x1, 0x61, 0x0, 0x0, 0x7, 0x4, 0x9f, 0x38, 0x4c, 0x1b, 0x5e, 0xbf, 0x50, 0x98, 0xfe, 0xbe, 0x1, 0x61, 0x0, +0x0, 0x9, 0x4, 0x9f, 0x38, 0xa4, 0xb3, 0x3d, 0xbf, 0x23, 0xe6, 0x2b, 0xbf, 0x1, 0x61, 0x0, 0x0, 0xf, 0x4, 0x9f, +0x38, 0xa9, 0xba, 0xd1, 0xbe, 0x6a, 0x89, 0x69, 0xbf, 0x1, 0x61, 0x0, 0x0, 0x11, 0x4, 0x9f, 0x38, 0xa9, 0xba, 0x51, +0xbe, 0xb4, 0x92, 0x7a, 0xbf, 0x1, 0x61, 0x0, 0x0, 0x23, 0x2d, 0xe4, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0xbf, 0x1, 0x62, 0x0, 0x0, 0xc4, 0xe3, 0x2f, 0x36, 0x0, 0x0, 0x80, 0x3f, 0x11, 0x40, 0x5e, 0xb3, 0x1, 0x63, 0x0, +0x0, 0x7d, 0xc4, 0xb1, 0x35, 0x0, 0x0, 0x80, 0xbf, 0xf5, 0xfb, 0x0, 0x34, 0x1, 0x63, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x64, 0x0, 0x0, 0x0, 0x0, 0x80, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x64, 0x0, 0x0, 0x48, 0x9f, 0x5d, 0x37, 0x28, 0xf4, 0x20, 0x3f, 0x96, 0x12, 0x47, +0xbf, 0x1, 0x64, 0x0, 0x0, 0xc6, 0xc4, 0xfd, 0x36, 0x2f, 0xf4, 0x20, 0x3f, 0x90, 0x12, 0x47, 0x3f, 0x1, 0x64, 0x0, +0x0, 0xe3, 0x57, 0xe6, 0x3e, 0x2d, 0xa1, 0x64, 0x3f, 0x6f, 0x11, 0x94, 0xb3, 0x1, 0x64, 0x0, 0x0, 0xca, 0x54, 0xe6, +0xbe, 0xf5, 0xa1, 0x64, 0x3f, 0x96, 0xa, 0x29, 0xb4, 0x1, 0x64, 0x0, 0x0, 0x71, 0x29, 0x16, 0x3a, 0xfd, 0xff, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x38, 0x0, 0x10, 0x74, 0x61, 0x3c, 0xcc, 0xf9, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0x0, 0x38, 0x0, 0xed, 0x73, 0x21, 0x3b, 0xce, 0xff, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x38, +0x0, 0x2b, 0x2e, 0xc9, 0x3c, 0x3d, 0xec, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x38, 0x0, 0x2f, 0xc5, 0x37, +0x3c, 0xe1, 0xfb, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x38, 0x0, 0x36, 0x83, 0x69, 0x3e, 0x40, 0x41, 0x79, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x38, 0x0, 0xdd, 0xdb, 0x58, 0x3e, 0x87, 0x31, 0x7a, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0x1, 0x38, 0x0, 0xe5, 0x5e, 0x4a, 0x3e, 0x73, 0xf3, 0x7a, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x38, +0x0, 0xd9, 0xbf, 0x3d, 0x3e, 0x6, 0x91, 0x7b, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x38, 0x0, 0xcd, 0x9b, 0x32, +0x3e, 0x65, 0x13, 0x7c, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x38, 0x0, 0x18, 0xb4, 0xbc, 0x3c, 0x9d, 0xee, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x38, 0x0, 0xac, 0x30, 0x19, 0x3c, 0x23, 0xfd, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0x0, 0x38, 0x0, 0xe1, 0x31, 0x2a, 0x3e, 0x77, 0x70, 0x7c, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xdf, 0x38, +0x0, 0xe, 0x3e, 0x26, 0x3e, 0x98, 0x9a, 0x7c, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4c, 0x38, 0x0, 0xef, 0x7a, 0x22, +0x3e, 0xc0, 0xc1, 0x7c, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd5, 0x38, 0x0, 0xa0, 0xee, 0x1e, 0x3e, 0xd6, 0xe5, 0x7c, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd5, 0x38, 0x0, 0x46, 0xa2, 0x1b, 0x3e, 0xa5, 0x6, 0x7d, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0xd5, 0x38, 0x0, 0xd, 0x9d, 0xe3, 0x3d, 0xff, 0x69, 0x7e, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd5, 0x38, +0x0, 0x53, 0xd3, 0xb1, 0x3d, 0x7d, 0x8, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd5, 0x38, 0x0, 0x18, 0xb4, 0xad, +0x3d, 0xda, 0x13, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xaf, 0x38, 0x0, 0x1c, 0x27, 0xa3, 0x3c, 0x1, 0xf3, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xaf, 0x38, 0x0, 0x9d, 0xe0, 0xa8, 0x3d, 0xd0, 0x20, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0xb0, 0x38, 0x0, 0x6d, 0x6e, 0xa4, 0x3d, 0x6e, 0x2c, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xb0, 0x38, +0x0, 0x6b, 0x70, 0x73, 0x3c, 0xc4, 0xf8, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xb0, 0x38, 0x0, 0xa9, 0xdb, 0x9f, +0x3d, 0xd, 0x38, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x32, 0x90, 0xab, 0x3d, 0xa5, 0x19, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0xc1, 0xf4, 0xac, 0x3c, 0x65, 0xf1, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0xd0, 0x38, 0x0, 0x3a, 0xdd, 0xa3, 0x3b, 0x2e, 0xff, 0x7f, 0xbf, 0x94, 0xf1, 0xbb, 0x34, 0x1, 0xd0, 0x38, +0x0, 0xbb, 0xf7, 0x75, 0x3b, 0x8b, 0xff, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0xdc, 0x15, 0x68, +0x3d, 0xb7, 0x96, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x74, 0x49, 0x74, 0x3d, 0x58, 0x8b, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0xb6, 0x9c, 0x98, 0x3c, 0xa1, 0xf4, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0xd0, 0x38, 0x0, 0x6e, 0xa1, 0x4b, 0x3c, 0xf0, 0xfa, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, +0x0, 0x5c, 0x49, 0x2, 0x3c, 0xee, 0xfd, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x42, 0x50, 0x5a, +0x3d, 0xd9, 0xa2, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x7c, 0xb1, 0xfd, 0x3d, 0x3e, 0x7, 0x7e, +0xbf, 0xd6, 0x87, 0x3, 0x35, 0x1, 0xd0, 0x38, 0x0, 0x85, 0x2c, 0x88, 0x3d, 0xf9, 0x6e, 0x7f, 0xbf, 0x2d, 0x4b, 0xf5, +0x34, 0x1, 0xd0, 0x38, 0x0, 0x6e, 0xa3, 0x81, 0x3d, 0x92, 0x7c, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, +0x0, 0xce, 0xe5, 0x86, 0x3e, 0x6c, 0xf4, 0x76, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x34, 0x80, 0x87, +0x3e, 0x49, 0xdf, 0x76, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x63, 0xef, 0x61, 0x3d, 0x39, 0x9c, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x51, 0xb0, 0xcc, 0x3b, 0xb9, 0xfe, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0xd0, 0x38, 0x0, 0x6a, 0x28, 0x8f, 0x3d, 0xb2, 0x5f, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, +0x0, 0x9d, 0x84, 0x94, 0x3d, 0x73, 0x53, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x8b, 0xc8, 0x9a, +0x3d, 0x90, 0x44, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x5d, 0x48, 0x88, 0x3e, 0xbc, 0xc3, 0x76, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x4c, 0x6f, 0x7, 0x3e, 0x44, 0xc0, 0x7d, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0xd0, 0x38, 0x0, 0x6c, 0xd6, 0x89, 0x3e, 0x70, 0x8c, 0x76, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, +0x0, 0x37, 0xfd, 0x88, 0x3e, 0xb2, 0xaa, 0x76, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x56, 0x6c, 0x6c, +0x3d, 0xbe, 0x92, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0x7a, 0xa6, 0x7e, 0x3d, 0x3a, 0x81, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x38, 0x0, 0xd3, 0xc1, 0xf8, 0x3d, 0xc5, 0x1a, 0x7e, 0xbf, 0x29, 0xf9, 0x0, +0x35, 0x1, 0xd0, 0x38, 0x0, 0xf8, 0x40, 0x85, 0x3d, 0x21, 0x75, 0x7f, 0xbf, 0x24, 0x19, 0xf4, 0x34, 0x1, 0xd0, 0x38, +0x0, 0x6, 0x43, 0x7a, 0x3d, 0x8f, 0x85, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xec, 0x38, 0x0, 0x22, 0xb4, 0x24, +0x3e, 0xb8, 0xaa, 0x7c, 0xbf, 0xa0, 0xe2, 0x27, 0x35, 0x1, 0xd0, 0x38, 0x0, 0xe9, 0x3b, 0x8b, 0x3d, 0x5f, 0x68, 0x7f, +0xbf, 0xb8, 0x61, 0x10, 0x35, 0x1, 0xd0, 0x38, 0x0, 0xc8, 0x64, 0x30, 0x3d, 0x34, 0xc3, 0x7f, 0xbf, 0x5f, 0xf7, 0x9, +0x35, 0x1, 0xd0, 0x38, 0x0, 0x21, 0x1c, 0x1, 0x3d, 0x70, 0xdf, 0x7f, 0xbf, 0x62, 0x7, 0x7, 0x35, 0x1, 0xd0, 0x38, +0x0, 0x86, 0x11, 0xf2, 0x3c, 0x62, 0xe3, 0x7f, 0xbf, 0x92, 0x10, 0x6c, 0x36, 0x1, 0xd5, 0x38, 0x0, 0x4f, 0x7, 0x1f, +0x3d, 0x96, 0xce, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x38, 0x0, 0xad, 0x23, 0x88, 0x3c, 0xf4, 0xf6, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x38, 0x0, 0xb6, 0xfa, 0xd4, 0x3c, 0xd9, 0xe9, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0x2, 0x38, 0x0, 0xaa, 0x46, 0x8, 0x3d, 0xb8, 0xdb, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x38, +0x0, 0xb4, 0xc4, 0xd, 0x3d, 0xbc, 0xd8, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x38, 0x0, 0xc2, 0xf1, 0x29, +0x3d, 0x91, 0xc7, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd5, 0x38, 0x0, 0x3d, 0xd8, 0x24, 0x3d, 0xe8, 0xca, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd5, 0x38, 0x0, 0xdb, 0x6a, 0x1a, 0x3d, 0x6a, 0xd1, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0xd5, 0x38, 0x0, 0x8f, 0x4f, 0xec, 0x3e, 0x1b, 0x1a, 0x63, 0xbf, 0x13, 0xad, 0xe5, 0x34, 0x1, 0xd5, 0x38, +0x0, 0xe0, 0x15, 0xe6, 0x3e, 0xcb, 0xb1, 0x64, 0xbf, 0x7, 0x13, 0xe5, 0x34, 0x1, 0xd5, 0x38, 0x0, 0x62, 0x29, 0xe0, +0x3e, 0x1b, 0x29, 0x66, 0xbf, 0x2e, 0x7c, 0xe4, 0x34, 0x1, 0xd5, 0x38, 0x0, 0xa2, 0x87, 0xda, 0x3e, 0xba, 0x82, 0x67, +0xbf, 0x74, 0xeb, 0xe3, 0x34, 0x1, 0xd5, 0x38, 0x0, 0xea, 0x1d, 0xd5, 0x3e, 0xcf, 0xc4, 0x68, 0xbf, 0x87, 0x5f, 0xe3, +0x34, 0x1, 0xd5, 0x38, 0x0, 0xa5, 0x7, 0xd0, 0x3e, 0x9c, 0xea, 0x69, 0xbf, 0x52, 0xd2, 0xe2, 0x34, 0x1, 0xd5, 0x38, +0x0, 0x74, 0x94, 0xcd, 0x3e, 0x12, 0x75, 0x6a, 0xbf, 0x37, 0x8f, 0xe2, 0x34, 0x1, 0xd5, 0x38, 0x0, 0x53, 0x77, 0xe5, +0x3e, 0x9a, 0xd9, 0x64, 0xbf, 0x85, 0x83, 0xe4, 0x34, 0x1, 0xd5, 0x38, 0x0, 0x56, 0x88, 0xeb, 0x3e, 0xd3, 0x4d, 0x63, +0xbf, 0x1, 0xce, 0xe4, 0x34, 0x1, 0xd5, 0x38, 0x0, 0x10, 0xea, 0x2, 0x3e, 0x37, 0xe6, 0x7d, 0xbf, 0x60, 0x20, 0xf0, +0x34, 0x1, 0xd5, 0x38, 0x0, 0x52, 0x17, 0x6c, 0x3d, 0xc, 0x93, 0x7f, 0xbf, 0x5, 0xfc, 0x4a, 0xad, 0x1, 0xc7, 0x15, +0x0, 0xb0, 0xa9, 0xa0, 0x3b, 0x37, 0xff, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x0, 0x0, 0x8b, 0x5d, 0x84, +0x3c, 0x72, 0xf7, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x0, 0x0, 0xdd, 0x60, 0x4, 0x3c, 0xdd, 0xfd, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x0, 0x0, 0xf, 0x8f, 0x30, 0x3c, 0x32, 0xfc, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0x3, 0x0, 0x0, 0xfc, 0x27, 0x72, 0x3c, 0xd8, 0xf8, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x0, +0x0, 0xce, 0xa1, 0x5e, 0x3d, 0x1f, 0x9f, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x0, 0x0, 0x5d, 0x4c, 0x4c, +0x3c, 0xe8, 0xfa, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x0, 0x0, 0xce, 0xac, 0xdd, 0x3b, 0x80, 0xfe, 0x7f, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x0, 0x0, 0xd2, 0xfe, 0x5c, 0x3c, 0xa, 0xfa, 0x7f, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x1, 0x3, 0x0, 0x0, 0x3d, 0x4d, 0x96, 0x3c, 0xf8, 0xf4, 0x7f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x0, +0x0, 0x50, 0x0, 0x38, 0xdb, 0x23, 0xc4, 0x84, 0xdb, 0xa6, 0xc3, 0xd1, 0xa3, 0xc0, 0xc3, 0xda, 0xfb, 0x1a, 0x44, 0x7b, +0xeb, 0x33, 0x43, 0x1, 0x3, 0xdf, 0x43, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x80, 0x3f, 0xb4, 0x77, 0xc2, 0x3f, 0x54, 0x71, 0xc, 0x43, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x7f, 0x43, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x40, 0x53, 0x15, 0x2e, 0x0, 0x0, 0x0, 0x80, 0x40, 0x53, 0x15, 0xae, 0x0, +0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x94, +0x16, 0x5c, 0xc0, 0x19, 0x8e, 0x89, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd6, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0xb0, 0x66, 0x26, 0xaf, 0x0, 0x0, 0x0, 0x80, 0xb0, 0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x80, 0x3f, 0x9b, 0xb0, 0xc6, 0xc3, 0xe, +0xe2, 0x5, 0xc3, 0xdc, 0x32, 0x13, 0x43, 0x1, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x40, +0x29, 0x1c, 0x31, 0x80, 0xa7, 0x40, 0x31, 0x40, 0x29, 0x1c, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x3a, 0xa, 0x6b, 0xa2, 0x80, +0xa7, 0x40, 0xb1, 0x3a, 0xa, 0x6b, 0xa2, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x73, 0x8e, 0xa8, 0xc1, 0x5d, +0x3f, 0x16, 0x36, 0x2, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xf0, 0x66, 0x2, 0x31, 0x80, +0xa7, 0x40, 0x31, 0xf0, 0x66, 0x2, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0xc, 0x45, 0x44, 0xa2, 0x80, 0xa7, 0x40, 0xb1, 0xd, +0x45, 0x44, 0xa2, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x6f, 0x8e, 0xa8, 0xc1, 0x5d, 0x3f, 0x16, 0x36, 0x3, +0x0, 0x80, 0x3f, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xb0, 0x66, 0x26, 0xaf, 0x0, 0x0, 0x0, 0x80, 0xb0, +0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, +0x0, 0x80, 0x3f, 0xf8, 0x36, 0xc4, 0xc3, 0xb0, 0xd0, 0x7, 0xc3, 0xa0, 0x60, 0xd, 0x43, 0x1, 0x0, 0x80, 0x3f, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0xff, 0x4b, 0x31, 0x0, 0x9c, 0x33, 0xb1, 0x0, 0xff, 0x4b, 0xb1, 0x0, +0x0, 0x80, 0x3f, 0x9d, 0x1f, 0x8f, 0x22, 0x0, 0x9c, 0x33, 0x31, 0x9c, 0x1f, 0x8f, 0x22, 0x0, 0x0, 0x80, 0x3f, 0x0, +0x7a, 0x68, 0xbf, 0xf7, 0x1f, 0x2b, 0xc2, 0xc5, 0x15, 0x95, 0xc2, 0x5, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0xf0, 0xde, 0x29, 0xb1, 0x5c, 0xa7, 0x17, 0x31, 0xf0, 0xde, 0x29, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x1a, +0x43, 0x49, 0x22, 0x5c, 0xa7, 0x17, 0xb1, 0x1a, 0x43, 0x49, 0x22, 0x0, 0x0, 0x80, 0x3f, 0xf8, 0xed, 0x14, 0x42, 0xa8, +0xdc, 0x4f, 0xc2, 0xd6, 0xd7, 0xe4, 0xc2, 0x6, 0x0, 0xc2, 0x3f, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x0, +0x19, 0x42, 0x31, 0xc0, 0xe6, 0xdc, 0x2f, 0x0, 0x19, 0x42, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x70, 0x7c, 0x27, 0xa1, 0xc0, +0xe6, 0xdc, 0xaf, 0x70, 0x7c, 0x27, 0xa1, 0x0, 0x0, 0x80, 0x3f, 0xa, 0x1d, 0x13, 0x43, 0xb0, 0x3b, 0x2a, 0xc2, 0x7d, +0xa7, 0x8d, 0xc2, 0x7, 0x0, 0x5c, 0xc0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x20, 0x57, 0xae, 0xb1, 0x60, +0x8, 0xb9, 0x31, 0x20, 0x57, 0xae, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x55, 0x5, 0x7c, 0x23, 0x60, 0x8, 0xb9, 0xb1, 0x54, +0x5, 0x7c, 0x23, 0x0, 0x0, 0x80, 0x3f, 0xca, 0x31, 0x9c, 0x42, 0x9f, 0x25, 0xc3, 0x41, 0xfe, 0xed, 0x14, 0x42, 0x8, +0x0, 0xc6, 0xc3, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x70, 0xfb, 0x13, 0x32, 0xf8, 0xb9, 0x29, 0x23, 0x70, +0xfb, 0x13, 0xb2, 0x0, 0x0, 0x80, 0x3f, 0xe0, 0xce, 0x12, 0x31, 0xf7, 0xb9, 0x29, 0x23, 0xe0, 0xce, 0x12, 0xb1, 0x0, +0x0, 0x80, 0x3f, 0x60, 0x66, 0x86, 0xc2, 0xa0, 0x1d, 0xca, 0x41, 0x94, 0x73, 0xea, 0x41, 0x9, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x34, 0x48, 0x4d, 0xb2, 0xc0, 0x12, 0xc3, 0x30, 0x34, 0x48, 0x4d, 0x32, 0x0, +0x0, 0x80, 0x3f, 0x8, 0x6d, 0x1c, 0x23, 0xc0, 0x12, 0xc3, 0xb0, 0x9, 0x6d, 0x1c, 0x23, 0x0, 0x0, 0x80, 0x3f, 0x80, +0x6a, 0x4b, 0xc1, 0x51, 0x36, 0xc2, 0x41, 0x2, 0x41, 0x39, 0x42, 0xa, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0xc0, 0xb9, 0x9a, 0x31, 0x50, 0xc7, 0x99, 0x2f, 0xc0, 0xb9, 0x9a, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0xf5, +0xe2, 0x39, 0xa1, 0x50, 0xc7, 0x99, 0xaf, 0xf5, 0xe2, 0x39, 0xa1, 0x0, 0x0, 0x80, 0x3f, 0x77, 0xd6, 0x15, 0x43, 0x23, +0xab, 0x87, 0x42, 0xea, 0xe2, 0xbc, 0x42, 0xb, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x7b, +0xdf, 0xa, 0x22, 0xe0, 0xfb, 0xb, 0xb0, 0x7b, 0xdf, 0xa, 0x22, 0x0, 0x0, 0x80, 0x3f, 0xe8, 0xf7, 0xfd, 0x31, 0xe0, +0xfb, 0xb, 0x30, 0xe8, 0xf7, 0xfd, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x6e, 0x95, 0x4, 0x43, 0x35, 0xaa, 0x1, 0x42, 0x80, +0x6a, 0x4b, 0x42, 0xc, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x15, 0xb2, 0x4d, 0x22, 0xe0, +0xe7, 0xf5, 0xb0, 0x15, 0xb2, 0x4d, 0x22, 0x0, 0x0, 0x80, 0x3f, 0xa8, 0x23, 0x56, 0x31, 0xe0, 0xe7, 0xf5, 0x30, 0xa8, +0x23, 0x56, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0xe3, 0x8f, 0x18, 0x43, 0xc4, 0xa5, 0x99, 0x41, 0xc8, 0x31, 0x1c, 0xc2, 0xd, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xc0, 0x5c, 0x3b, 0x30, 0x80, 0x96, 0x11, 0x2f, 0xc0, +0x5c, 0x3b, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0x5d, 0x1b, 0x55, 0x9f, 0x80, 0x96, 0x11, 0xaf, 0x5e, 0x1b, 0x55, 0x9f, 0x0, +0x0, 0x80, 0x3f, 0xec, 0xe2, 0x3c, 0x42, 0xda, 0xda, 0xa9, 0x40, 0x58, 0x1, 0x77, 0xc2, 0xe, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xfc, 0x1b, 0x26, 0xaf, 0x60, 0x97, 0xd7, 0xaf, 0xfc, 0x1b, 0x26, 0x2f, 0x0, +0x0, 0x80, 0x3f, 0xba, 0xe3, 0xb, 0x9f, 0x60, 0x97, 0xd7, 0x2f, 0xb9, 0xe3, 0xb, 0x9f, 0x0, 0x0, 0x80, 0x3f, 0x88, +0xbd, 0xef, 0xc1, 0x22, 0xe3, 0xce, 0x41, 0x66, 0xb9, 0xaa, 0xc2, 0xf, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0x48, 0xa1, 0x94, 0xb0, 0xdc, 0x21, 0x1a, 0x31, 0x48, 0xa1, 0x94, 0x30, 0x0, 0x0, 0x80, 0x3f, 0x5b, +0xf9, 0xb2, 0x21, 0xdc, 0x21, 0x1a, 0xb1, 0x5c, 0xf9, 0xb2, 0x21, 0x0, 0x0, 0x80, 0x3f, 0xa, 0x1d, 0x93, 0xc2, 0xb5, +0xfa, 0xcd, 0x40, 0xb1, 0xd3, 0x9f, 0xc2, 0x10, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x20, +0xd6, 0x0, 0xb1, 0x1e, 0xc, 0x13, 0x32, 0x20, 0xd6, 0x0, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x1b, 0x2, 0x14, 0x23, 0x1e, +0xc, 0x13, 0xb2, 0x1b, 0x2, 0x14, 0x23, 0x0, 0x0, 0x80, 0x3f, 0xd4, 0x72, 0x2d, 0xc3, 0x59, 0xb2, 0x80, 0xc2, 0xbf, +0x79, 0xe8, 0xbf, 0x11, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x90, 0xf6, 0x9e, 0xa0, 0x80, +0x43, 0x80, 0x2f, 0x90, 0xf6, 0x9e, 0xa0, 0x0, 0x0, 0x80, 0x3f, 0xe8, 0xa2, 0x1e, 0x31, 0x80, 0x43, 0x80, 0xaf, 0xe8, +0xa2, 0x1e, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x54, 0xae, 0xd2, 0xc1, 0xfa, 0xba, 0x9, 0xc2, 0x26, 0x45, 0x7e, 0x42, 0x12, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x88, 0xa9, 0xa, 0xb2, 0x34, 0xff, 0x3a, 0xa4, 0x88, +0xa9, 0xa, 0x32, 0x0, 0x0, 0x80, 0x3f, 0x38, 0x9e, 0x2c, 0x32, 0x35, 0xff, 0x3a, 0xa4, 0x38, 0x9e, 0x2c, 0xb2, 0x0, +0x0, 0x80, 0x3f, 0xf, 0x70, 0xb7, 0x42, 0x28, 0x25, 0xa4, 0xc1, 0xef, 0x35, 0x61, 0x42, 0x13, 0x0, 0x0, 0x0, 0x44, +0xae, 0x4f, 0x42, 0x28, 0xe2, 0xa7, 0xc1, 0x3d, 0x3b, 0x9a, 0x41, 0x44, 0xae, 0x4f, 0x42, 0x28, 0xe2, 0xa7, 0xc1, 0x3d, +0x3b, 0x9a, 0x41, 0x0, 0x0, 0x80, 0x3f, 0xc0, 0x52, 0x4, 0x32, 0x13, 0xc3, 0x18, 0x23, 0xc0, 0x52, 0x4, 0xb2, 0x0, +0x0, 0x80, 0x3f, 0x60, 0xc5, 0x13, 0x31, 0x13, 0xc3, 0x18, 0x23, 0x60, 0xc5, 0x13, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x73, +0xe8, 0x28, 0x43, 0x9, 0xd1, 0x3f, 0xc0, 0x51, 0x5b, 0x2e, 0x41, 0x14, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0x0, 0x7e, 0xb4, 0x30, 0x0, 0x1a, 0xdc, 0x2e, 0x0, 0x7e, 0xb4, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0x9d, +0x2e, 0x9b, 0x9f, 0x0, 0x1a, 0xdc, 0xae, 0x9d, 0x2e, 0x9b, 0x9f, 0x0, 0x0, 0x80, 0x3f, 0xa6, 0xa4, 0xa1, 0x42, 0x7, +0x38, 0x32, 0x41, 0x52, 0xae, 0x52, 0x42, 0x15, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x38, +0x2f, 0xbe, 0xb1, 0x52, 0xcf, 0x3e, 0xb1, 0x38, 0x2f, 0xbe, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x10, 0xc1, 0xd, 0xa3, 0x52, +0xcf, 0x3e, 0x31, 0x11, 0xc1, 0xd, 0xa3, 0x0, 0x0, 0x80, 0x3f, 0x20, 0xda, 0xe1, 0x41, 0xd, 0xdf, 0x1, 0x42, 0x71, +0xb0, 0xa6, 0x42, 0x16, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x90, 0x32, 0xad, 0xb0, 0x10, +0x7e, 0x89, 0x30, 0x90, 0x32, 0xad, 0x30, 0x0, 0x0, 0x80, 0x3f, 0xb1, 0xa, 0x3a, 0x21, 0x10, 0x7e, 0x89, 0xb0, 0xb2, +0xa, 0x3a, 0x21, 0x0, 0x0, 0x80, 0x3f, 0xc0, 0x9d, 0x27, 0xc2, 0x9a, 0xb4, 0x26, 0x42, 0x0, 0xc0, 0x5f, 0x42, 0x17, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xc0, 0xe7, 0xda, 0x2f, 0x98, 0xa9, 0xb5, 0x31, 0xc0, +0xe7, 0xda, 0xaf, 0x0, 0x0, 0x80, 0x3f, 0xdf, 0x56, 0x9b, 0xa1, 0x98, 0xa9, 0xb5, 0xb1, 0xe0, 0x56, 0x9b, 0xa1, 0x0, +0x0, 0x80, 0x3f, 0xa0, 0x67, 0x83, 0x42, 0x43, 0xeb, 0xfa, 0x41, 0x9b, 0x86, 0x13, 0x42, 0x18, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x21, 0x2, 0xad, 0x10, 0x0, 0x48, 0x31, 0x0, 0x21, 0x2, 0x2d, 0x0, +0x0, 0x80, 0x3f, 0xa1, 0x53, 0x4b, 0x1e, 0x10, 0x0, 0x48, 0xb1, 0xa0, 0x53, 0x4b, 0x1e, 0x0, 0x0, 0x80, 0x3f, 0x90, +0xbd, 0x6f, 0x42, 0x73, 0x10, 0xad, 0xc1, 0x51, 0x5b, 0x2e, 0xc2, 0x19, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0xe0, 0xe2, 0x4b, 0x2e, 0xf0, 0xa1, 0x8d, 0xb1, 0xe0, 0xe2, 0x4b, 0xae, 0x0, 0x0, 0x80, 0x3f, 0xdd, +0x99, 0xe1, 0x1f, 0xf0, 0xa1, 0x8d, 0x31, 0xdc, 0x99, 0xe1, 0x1f, 0x0, 0x0, 0x80, 0x3f, 0x60, 0x1, 0xf7, 0xc1, 0x5b, +0x1, 0x8c, 0xc2, 0x22, 0x7b, 0x8f, 0xc2, 0x1a, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x0, +0xa4, 0xb6, 0xb0, 0x30, 0x12, 0x87, 0x30, 0x0, 0xa4, 0xb6, 0x30, 0x0, 0x0, 0x80, 0x3f, 0xeb, 0xba, 0x40, 0x21, 0x30, +0x12, 0x87, 0xb0, 0xec, 0xba, 0x40, 0x21, 0x0, 0x0, 0x80, 0x3f, 0x40, 0x8d, 0x89, 0xc0, 0x39, 0xfd, 0x4e, 0x41, 0xd, +0x90, 0x99, 0xc2, 0x1b, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xb0, 0x66, 0x26, 0xaf, 0x0, +0x0, 0x0, 0x80, 0xb0, 0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x80, 0x0, 0x0, 0x80, 0x3f, 0x9a, 0xcf, 0xc2, 0x43, 0x86, 0xae, 0x3, 0xc3, 0x2a, 0x58, 0x3, 0x42, 0x1, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xa0, 0x5d, 0xa1, 0x30, 0x88, 0xac, 0xaf, 0x30, 0xa0, +0x5d, 0xa1, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0x82, 0x77, 0x5d, 0xa1, 0x88, 0xac, 0xaf, 0xb0, 0x82, 0x77, 0x5d, 0xa1, 0x0, +0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x88, 0x41, 0xd1, 0xc1, 0x99, 0x6, 0x85, 0xb5, 0x1d, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xd0, 0xcd, 0xcd, 0x30, 0x88, 0xac, 0xaf, 0x30, 0xd0, 0xcd, 0xcd, 0xb0, 0x0, +0x0, 0x80, 0x3f, 0x65, 0x3a, 0x8d, 0xa1, 0x88, 0xac, 0xaf, 0xb0, 0x65, 0x3a, 0x8d, 0xa1, 0x0, 0x0, 0x80, 0x3f, 0x0, +0x0, 0x0, 0x0, 0x1d, 0x5b, 0x9e, 0xc1, 0x99, 0x6, 0x85, 0xb5, 0x1e, 0x0, 0x0, 0x0, 0xa1, 0x45, 0x8d, 0xc2, 0x37, +0xb, 0x2b, 0xc2, 0x16, 0x5e, 0x8d, 0xc2, 0x9b, 0x45, 0x8d, 0x42, 0xe7, 0xcf, 0x1d, 0xc1, 0x19, 0x5e, 0x8d, 0x42, 0x1, +0x5, 0x35, 0x3f, 0xb0, 0x66, 0x26, 0xaf, 0xe7, 0x4, 0x35, 0xbf, 0xb1, 0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0xdb, +0xd9, 0x89, 0xae, 0xe7, 0x4, 0x35, 0x3f, 0xda, 0xd9, 0x89, 0xae, 0x1, 0x5, 0x35, 0x3f, 0x18, 0x92, 0xc1, 0xc3, 0x6e, +0xd, 0xac, 0xc2, 0x5c, 0x5d, 0x17, 0x43, 0x1, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x11, +0xda, 0xd3, 0xaf, 0xe6, 0x4, 0xb5, 0xb2, 0x11, 0xda, 0xd3, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0xa8, 0x2a, 0x64, 0xb0, 0xe6, +0x4, 0xb5, 0x32, 0xa8, 0x2a, 0x64, 0x30, 0x0, 0x0, 0x80, 0x3f, 0xf7, 0x99, 0x93, 0xbe, 0x86, 0x11, 0x6a, 0xc2, 0x40, +0x65, 0x3c, 0xb6, 0x20, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xf9, 0x54, 0x68, 0xb1, 0xcc, +0x4, 0xb5, 0xb2, 0xf7, 0x54, 0x68, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x4e, 0x72, 0x84, 0xb2, 0xcc, 0x4, 0xb5, 0x32, 0x4e, +0x72, 0x84, 0x32, 0x0, 0x0, 0x80, 0x3f, 0x82, 0x97, 0x93, 0xbe, 0xc6, 0x7c, 0x38, 0xc1, 0x8, 0xfe, 0x4c, 0xb7, 0x21, +0x0, 0x0, 0x0, 0xf2, 0xa2, 0x8d, 0xc2, 0xf3, 0xf5, 0x17, 0xc2, 0x95, 0xb1, 0x8d, 0xc2, 0xed, 0xa2, 0x8d, 0x42, 0xee, +0xf5, 0xa2, 0xc0, 0x9a, 0xb1, 0x8d, 0x42, 0x1, 0x5, 0x35, 0x3f, 0xb0, 0x66, 0x26, 0xaf, 0xe7, 0x4, 0x35, 0x3f, 0xb1, +0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0xdb, 0xd9, 0x89, 0x2e, 0xe7, 0x4, 0x35, 0xbf, 0xda, 0xd9, 0x89, 0x2e, 0x1, +0x5, 0x35, 0x3f, 0x2a, 0x10, 0x88, 0xc3, 0x84, 0xbc, 0xa2, 0xc2, 0xfc, 0x80, 0x5f, 0x43, 0x1, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xa2, 0xf2, 0xc5, 0x30, 0x81, 0xb6, 0x5, 0xa1, 0xa2, 0xf2, 0xc5, 0xb0, 0x0, +0x0, 0x80, 0x3f, 0x4c, 0xed, 0x2c, 0xb0, 0x81, 0xb6, 0x5, 0xa1, 0x4c, 0xed, 0x2c, 0x30, 0x0, 0x0, 0x80, 0x3f, 0x10, +0xce, 0xd3, 0xbe, 0xc0, 0x1a, 0x57, 0xc2, 0x80, 0xfb, 0x85, 0xb6, 0x23, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0x71, 0xe2, 0x7, 0x31, 0x0, 0x5, 0xb5, 0x32, 0x71, 0xe2, 0x7, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0xc2, +0xeb, 0x5f, 0xb0, 0x0, 0x5, 0xb5, 0xb2, 0xc1, 0xeb, 0x5f, 0x30, 0x0, 0x0, 0x80, 0x3f, 0xdb, 0xc9, 0x53, 0xbf, 0xbe, +0x81, 0x7b, 0xc1, 0xab, 0x14, 0xca, 0x37, 0x24, 0x0, 0x0, 0x0, 0xd0, 0x79, 0x8d, 0xc2, 0xed, 0xa1, 0x1a, 0xc2, 0x5f, +0x8d, 0x8d, 0xc2, 0xce, 0x79, 0x8d, 0x42, 0x9e, 0x55, 0xb8, 0xc0, 0x60, 0x8d, 0x8d, 0x42, 0x1, 0x5, 0x35, 0x3f, 0xb0, +0x66, 0x26, 0xaf, 0xe7, 0x4, 0x35, 0xbf, 0xb1, 0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0xdb, 0xd9, 0x89, 0xae, 0xe7, +0x4, 0x35, 0x3f, 0xda, 0xd9, 0x89, 0xae, 0x1, 0x5, 0x35, 0x3f, 0x75, 0x8d, 0x10, 0xc3, 0x10, 0x42, 0xb4, 0xc2, 0x3c, +0x6, 0x2d, 0x43, 0x1, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xd2, 0x5f, 0x60, 0x30, 0x21, +0xfe, 0x3d, 0x21, 0xd2, 0x5f, 0x60, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0xb5, 0xc5, 0xd8, 0x30, 0x22, 0xfe, 0x3d, 0x21, 0xb5, +0xc5, 0xd8, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0x60, 0x58, 0xf, 0xb6, 0xc0, 0x1d, 0x59, 0xc2, 0xc0, 0xba, 0x18, 0xb7, 0x26, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xac, 0xcd, 0xc6, 0x31, 0x51, 0x1, 0x76, 0x24, 0xac, +0xcd, 0xc6, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x15, 0x64, 0x9e, 0x32, 0x52, 0x1, 0x76, 0x24, 0x15, 0x64, 0x9e, 0xb2, 0x0, +0x0, 0x80, 0x3f, 0xe, 0xa4, 0x20, 0xbf, 0x84, 0x48, 0x44, 0xc2, 0x16, 0x44, 0x24, 0xb7, 0x27, 0x0, 0x0, 0x0, 0xef, +0xa2, 0x8d, 0xc2, 0xc3, 0x82, 0x23, 0xc2, 0x98, 0xb1, 0x8d, 0xc2, 0xf1, 0xa2, 0x8d, 0x42, 0x6d, 0x5c, 0xff, 0xc0, 0x99, +0xb1, 0x8d, 0x42, 0x1, 0x5, 0x35, 0x3f, 0xb0, 0x66, 0x26, 0xaf, 0xe7, 0x4, 0x35, 0x3f, 0xb1, 0x66, 0x26, 0x2f, 0x0, +0x0, 0x80, 0x3f, 0xdb, 0xd9, 0x89, 0x2e, 0xe7, 0x4, 0x35, 0xbf, 0xda, 0xd9, 0x89, 0x2e, 0x1, 0x5, 0x35, 0x3f, 0xe9, +0xa6, 0x41, 0xc1, 0x1c, 0xf6, 0x9c, 0xc2, 0x47, 0xb0, 0x4f, 0x43, 0x1, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0x51, 0xe5, 0x54, 0xb0, 0xe6, 0x4, 0xb5, 0x32, 0x51, 0xe5, 0x54, 0x30, 0x0, 0x0, 0x80, 0x3f, 0xe2, +0x76, 0xd, 0x30, 0xe6, 0x4, 0xb5, 0xb2, 0xe2, 0x76, 0xd, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0x8c, 0xe0, 0x8f, 0x3e, 0x6e, +0xed, 0x58, 0xc2, 0xf, 0x27, 0x8d, 0xb7, 0x29, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x45, +0x63, 0x92, 0x2f, 0xda, 0x30, 0xc6, 0x9e, 0x45, 0x63, 0x92, 0xaf, 0x0, 0x0, 0x80, 0x3f, 0xcc, 0x4b, 0x2d, 0xaf, 0xdb, +0x30, 0xc6, 0x9e, 0xcc, 0x4b, 0x2d, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0x7f, 0xa0, 0x8a, 0x37, 0xfc, 0xbd, 0x65, 0xc2, 0x83, +0x9e, 0x77, 0xb7, 0x2a, 0x0, 0x0, 0x0, 0x13, 0xd4, 0x8d, 0xc2, 0x79, 0x84, 0x23, 0xc2, 0xf3, 0xd8, 0x8d, 0xc2, 0x10, +0xd4, 0x8d, 0x42, 0x1d, 0x6a, 0xff, 0xc0, 0xf2, 0xd8, 0x8d, 0x42, 0xf4, 0xff, 0xff, 0x3e, 0xb1, 0x66, 0x26, 0xaf, 0xdb, +0xb3, 0x5d, 0xbf, 0xb1, 0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0xc2, 0x24, 0xc0, 0xae, 0xdb, 0xb3, 0x5d, 0x3f, 0xc1, +0x24, 0xc0, 0xae, 0xf4, 0xff, 0xff, 0x3e, 0xc, 0x57, 0xe2, 0x42, 0xc7, 0xd0, 0xaf, 0xc2, 0x4, 0x32, 0x19, 0xc3, 0x1, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xed, 0x98, 0x7a, 0x2f, 0xb3, 0x41, 0xaa, 0xb2, 0xeb, +0x98, 0x7a, 0xaf, 0x0, 0x0, 0x80, 0x3f, 0xcc, 0xec, 0xaa, 0x30, 0xb3, 0x41, 0xaa, 0x32, 0xcc, 0xec, 0xaa, 0xb0, 0x0, +0x0, 0x80, 0x3f, 0xf7, 0x7, 0x40, 0xb7, 0x18, 0x5d, 0x5a, 0xc2, 0x7, 0x57, 0x1c, 0xb7, 0x2c, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x70, 0xb5, 0x35, 0x32, 0xb3, 0x41, 0xaa, 0xb2, 0x70, 0xb5, 0x35, 0xb2, 0x0, +0x0, 0x80, 0x3f, 0xaa, 0xfb, 0x8, 0xb0, 0xb3, 0x41, 0xaa, 0x32, 0xae, 0xfb, 0x8, 0x30, 0x0, 0x0, 0x80, 0x3f, 0x8f, +0x57, 0x8f, 0xbe, 0xaf, 0x60, 0x86, 0xc1, 0x96, 0xcf, 0x1e, 0xb7, 0x2d, 0x0, 0x0, 0x0, 0x12, 0xd4, 0x8d, 0xc2, 0x8a, +0xce, 0x21, 0xc2, 0xf2, 0xd8, 0x8d, 0xc2, 0x12, 0xd4, 0x8d, 0x42, 0x9e, 0xba, 0xf1, 0xc0, 0xf2, 0xd8, 0x8d, 0x42, 0xf4, +0xff, 0xff, 0x3e, 0xb1, 0x66, 0x26, 0xaf, 0xdb, 0xb3, 0x5d, 0x3f, 0xb1, 0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0xc2, +0x24, 0xc0, 0x2e, 0xdb, 0xb3, 0x5d, 0xbf, 0xc1, 0x24, 0xc0, 0x2e, 0xf4, 0xff, 0xff, 0x3e, 0xff, 0x8b, 0x6d, 0x43, 0xbf, +0xab, 0xb0, 0xc2, 0x53, 0x98, 0xb0, 0xc2, 0x1, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x26, +0xf3, 0xff, 0xb0, 0xc0, 0x67, 0x3b, 0x32, 0x26, 0xf3, 0xff, 0x30, 0x0, 0x0, 0x80, 0x3f, 0xd2, 0xd1, 0x7d, 0x30, 0xc0, +0x67, 0x3b, 0xb2, 0xd2, 0xd1, 0x7d, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0x1d, 0xa0, 0x83, 0xbe, 0x9e, 0x52, 0x65, 0xc2, 0x7c, +0x97, 0x41, 0x36, 0x2f, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x4a, 0x90, 0x6b, 0xb1, 0xe7, +0xd9, 0x6e, 0xb3, 0x4e, 0x90, 0x6b, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x73, 0x6c, 0x9c, 0x32, 0xe7, 0xd9, 0x6e, 0x33, 0x73, +0x6c, 0x9c, 0xb2, 0x0, 0x0, 0x80, 0x3f, 0xc0, 0x9f, 0x30, 0xb6, 0x18, 0xbe, 0x87, 0xc1, 0xc4, 0xfa, 0x96, 0xb6, 0x30, +0x0, 0x0, 0x0, 0x12, 0xd4, 0x8d, 0xc2, 0x73, 0xbf, 0x29, 0xc2, 0xf6, 0xd8, 0x8d, 0xc2, 0x14, 0xd4, 0x8d, 0x42, 0xf8, +0xa0, 0x18, 0xc1, 0xf1, 0xd8, 0x8d, 0x42, 0xf4, 0xff, 0xff, 0x3e, 0xb1, 0x66, 0x26, 0xaf, 0xdb, 0xb3, 0x5d, 0xbf, 0xb1, +0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0xc2, 0x24, 0xc0, 0xae, 0xdb, 0xb3, 0x5d, 0x3f, 0xc1, 0x24, 0xc0, 0xae, 0xf4, +0xff, 0xff, 0x3e, 0x89, 0x7, 0xbb, 0x43, 0x4a, 0xb3, 0xac, 0xc2, 0xdf, 0x8b, 0xde, 0xc2, 0x1, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x63, 0x46, 0x2f, 0x18, 0x9f, 0xed, 0xb1, 0x0, 0x63, 0x46, 0xaf, 0x0, +0x0, 0x80, 0x3f, 0x15, 0xb2, 0x51, 0x30, 0x18, 0x9f, 0xed, 0x31, 0x15, 0xb2, 0x51, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0xab, +0x6, 0xc5, 0x36, 0x38, 0xb0, 0x80, 0xc2, 0x65, 0x7d, 0xb1, 0xb6, 0x32, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0x32, 0x7b, 0x83, 0x30, 0x18, 0x9f, 0xed, 0xb1, 0x30, 0x7b, 0x83, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0xc5, +0xb4, 0x8f, 0x32, 0x18, 0x9f, 0xed, 0x31, 0xc5, 0xb4, 0x8f, 0xb2, 0x0, 0x0, 0x80, 0x3f, 0xab, 0x6, 0xc5, 0x36, 0x2f, +0x84, 0xc1, 0xc1, 0x65, 0x7d, 0xb1, 0xb6, 0x33, 0x0, 0x0, 0x0, 0xe, 0xd4, 0x8d, 0xc2, 0xcb, 0xc5, 0x36, 0xc2, 0xef, +0xd8, 0x8d, 0xc2, 0x14, 0xd4, 0x8d, 0x42, 0x57, 0xba, 0x4c, 0xc1, 0xf7, 0xd8, 0x8d, 0x42, 0xf4, 0xff, 0xff, 0x3e, 0xb1, +0x66, 0x26, 0xaf, 0xdb, 0xb3, 0x5d, 0x3f, 0xb1, 0x66, 0x26, 0x2f, 0x0, 0x0, 0x80, 0x3f, 0xc2, 0x24, 0xc0, 0x2e, 0xdb, +0xb3, 0x5d, 0xbf, 0xc1, 0x24, 0xc0, 0x2e, 0xf4, 0xff, 0xff, 0x3e, 0x9f, 0x86, 0xc5, 0x43, 0x20, 0x30, 0xa6, 0xc2, 0xd, +0xba, 0xa8, 0x41, 0x1, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x41, 0x66, 0xea, 0x2f, 0xf4, +0xff, 0x7f, 0xb2, 0x41, 0x66, 0xea, 0xaf, 0x0, 0x0, 0x80, 0x3f, 0x82, 0xf4, 0xb9, 0xb0, 0xf4, 0xff, 0x7f, 0x32, 0x82, +0xf4, 0xb9, 0x30, 0x0, 0x0, 0x80, 0x3f, 0xdc, 0x3e, 0x9e, 0x3e, 0xc2, 0x5d, 0x87, 0xc2, 0x7, 0x71, 0xa, 0x38, 0x35, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x27, 0x90, 0x97, 0xb1, 0x7, 0x26, 0x91, 0xb2, 0x27, +0x90, 0x97, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x9c, 0x0, 0x4a, 0x32, 0x7, 0x26, 0x91, 0x32, 0x9c, 0x0, 0x4a, 0xb2, 0x0, +0x0, 0x80, 0x3f, 0x28, 0x47, 0xf, 0x35, 0x77, 0x36, 0xcd, 0xc1, 0xb9, 0x7a, 0x20, 0x37, 0x36, 0x0, 0x0, 0x0, 0xc2, +0xe4, 0x83, 0xc3, 0x10, 0x59, 0x8e, 0xc1, 0x3b, 0x0, 0x3c, 0x40, 0x97, 0x13, 0xb8, 0x43, 0x8, 0x59, 0x8e, 0xc1, 0xe3, +0xe2, 0x8c, 0x42, 0x0, 0x0, 0x80, 0x3f, 0xb0, 0x66, 0x26, 0xaf, 0x0, 0x0, 0x0, 0x80, 0xb0, 0x66, 0x26, 0x2f, 0x0, +0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x80, 0x3f, 0x36, +0xc8, 0x79, 0xc2, 0xa1, 0x9c, 0x27, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0xe8, 0x59, 0xcf, 0xb1, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x59, 0xcf, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x80, 0x3f, 0xae, 0xf6, 0x81, 0x3f, 0x9a, +0x93, 0x2a, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x80, +0xb4, 0xde, 0x31, 0x0, 0x0, 0x0, 0x80, 0x80, 0xb4, 0xde, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0xf7, 0xef, 0xe0, 0x35, 0xa8, 0x30, 0xd3, 0xc1, 0x0, +0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x40, 0x53, 0x15, 0x2e, 0x0, +0x0, 0x0, 0x80, 0x40, 0x53, 0x15, 0xae, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x6c, 0x7c, 0x91, 0x42, 0xd6, 0x88, 0xb8, 0x42, 0x28, 0x57, 0xc9, 0x42, 0x0, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x70, 0x4f, 0x8d, 0xb0, 0xe3, 0xb0, 0x1a, 0x22, 0x70, +0x4f, 0x8d, 0x30, 0x0, 0x0, 0x80, 0x3f, 0xcc, 0x1e, 0x8c, 0xb1, 0xe2, 0xb0, 0x1a, 0x22, 0xcc, 0x1e, 0x8c, 0x31, 0x0, +0x0, 0x80, 0x3f, 0x8a, 0xaa, 0xaf, 0xb4, 0x28, 0x2e, 0x93, 0xc2, 0xb, 0x74, 0xd4, 0xb6, 0x3b, 0x0, 0x0, 0x0, 0x3, +0x2b, 0x92, 0xc3, 0x68, 0xe4, 0xf, 0x42, 0x1, 0x2b, 0x92, 0xc3, 0x4, 0x2b, 0x92, 0x43, 0x44, 0xcd, 0xce, 0x42, 0x2, +0x2b, 0x92, 0x43, 0x1b, 0xff, 0x6e, 0x3f, 0x40, 0x53, 0x15, 0x2e, 0x1d, 0x7c, 0xb7, 0xbe, 0x40, 0x53, 0x15, 0xae, 0x0, +0x0, 0x80, 0x3f, 0x28, 0x68, 0xdd, 0x2c, 0x1d, 0x7c, 0xb7, 0x3e, 0x29, 0x68, 0xdd, 0x2c, 0x1b, 0xff, 0x6e, 0x3f, 0x2f, +0x91, 0x97, 0x42, 0x6b, 0x14, 0x18, 0x43, 0x11, 0x6, 0xc6, 0x42, 0x0, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0xe0, 0xd9, 0xd1, 0xb0, 0x8b, 0x2, 0xaf, 0x32, 0xe0, 0xd9, 0xd1, 0x30, 0x0, 0x0, 0x80, 0x3f, 0x4a, +0x55, 0xa0, 0x31, 0x8b, 0x2, 0xaf, 0xb2, 0x4a, 0x55, 0xa0, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x53, 0x64, 0x2e, 0x36, 0x7a, +0xd, 0x23, 0x43, 0xc6, 0xb0, 0x6f, 0xb6, 0x3d, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xc0, +0x1a, 0x37, 0xb1, 0x8b, 0x2, 0xaf, 0x32, 0xc0, 0x1a, 0x37, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x70, 0x8a, 0x34, 0xb1, 0x8b, +0x2, 0xaf, 0xb2, 0x70, 0x8a, 0x34, 0x31, 0x0, 0x0, 0x80, 0x3f, 0xbd, 0xe4, 0x98, 0x35, 0x48, 0xb9, 0x9e, 0x42, 0xfe, +0x43, 0x6a, 0x36, 0x3e, 0x0, 0x0, 0x0, 0x10, 0x88, 0x8e, 0x41, 0xd5, 0x83, 0x18, 0xc1, 0x7b, 0xa5, 0x58, 0xc1, 0x73, +0xa4, 0x23, 0x43, 0xeb, 0xbd, 0x17, 0x41, 0xee, 0x76, 0x61, 0x41, 0x0, 0x0, 0x80, 0x3f, 0x40, 0x53, 0x15, 0x2e, 0x0, +0x0, 0x0, 0x80, 0x40, 0x53, 0x15, 0xae, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x9e, 0xc, 0x9e, 0xc3, 0xa2, 0x76, 0xb5, 0x42, 0x3a, 0x3f, 0xd0, 0x42, 0x0, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x30, 0x22, 0x16, 0xb2, 0xd0, 0x4c, 0xa4, 0xb1, 0x30, +0x22, 0x16, 0x32, 0x0, 0x0, 0x80, 0x3f, 0xe6, 0xb5, 0xc0, 0xa3, 0xd0, 0x4c, 0xa4, 0x31, 0xe6, 0xb5, 0xc0, 0xa3, 0x0, +0x0, 0x80, 0x3f, 0x8e, 0x85, 0x24, 0x43, 0x2c, 0x3, 0x3d, 0xbf, 0xf0, 0x9c, 0xc0, 0xb5, 0x40, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x26, 0x16, 0x31, 0xea, 0x4c, 0xdf, 0x22, 0x0, 0x26, 0x16, 0xb1, 0x0, +0x0, 0x80, 0x3f, 0x80, 0x5c, 0xbe, 0x31, 0xe9, 0x4c, 0xdf, 0x22, 0x80, 0x5c, 0xbe, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x2a, +0x3f, 0x2e, 0x42, 0x0, 0x3, 0xbd, 0x3f, 0x37, 0x73, 0x2c, 0xb6, 0x41, 0x0, 0x0, 0x0, 0x40, 0xab, 0x10, 0x41, 0x1e, +0xac, 0x13, 0xc1, 0x1f, 0xb4, 0xfc, 0xc1, 0xf4, 0xb1, 0x19, 0x43, 0x72, 0xb2, 0xb2, 0x41, 0x42, 0x7f, 0x64, 0x41, 0x0, +0x0, 0x80, 0x3f, 0x40, 0x53, 0x15, 0x2e, 0x0, 0x0, 0x0, 0x80, 0x40, 0x53, 0x15, 0xae, 0x0, 0x0, 0x80, 0x3f, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0xae, 0xea, 0xa2, 0xc3, 0xb6, +0xae, 0xa1, 0x42, 0xe1, 0x1a, 0xe2, 0x42, 0x0, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xbc, +0x72, 0xb4, 0x31, 0x78, 0xff, 0x6a, 0x31, 0xbc, 0x72, 0xb4, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0xf2, 0xa4, 0x25, 0xa3, 0x78, +0xff, 0x6a, 0xb1, 0xf3, 0xa4, 0x25, 0xa3, 0x0, 0x0, 0x80, 0x3f, 0x69, 0x22, 0x1b, 0x43, 0xb9, 0x3a, 0x3, 0xc0, 0xc7, +0x2c, 0xd9, 0xb6, 0x43, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x70, 0x90, 0xe4, 0xb1, 0x1c, +0xb7, 0xd5, 0xa2, 0x70, 0x90, 0xe4, 0x31, 0x0, 0x0, 0x80, 0x3f, 0x60, 0x5e, 0xef, 0x30, 0x1b, 0xb7, 0xd5, 0xa2, 0x60, +0x5e, 0xef, 0xb0, 0x0, 0x0, 0x80, 0x3f, 0x47, 0xe2, 0x1d, 0x42, 0x0, 0x0, 0x0, 0x0, 0xa0, 0xfd, 0x4c, 0xb5, 0x44, +0x0, 0x0, 0x0, 0xda, 0x73, 0xbb, 0xc2, 0x69, 0x48, 0xe1, 0xc0, 0xc6, 0xf2, 0x4b, 0xc1, 0x40, 0xbe, 0xd2, 0xc0, 0x8c, +0x9d, 0x3f, 0x41, 0xa3, 0x29, 0x6e, 0x41, 0x0, 0x0, 0x80, 0x3f, 0x40, 0x53, 0x15, 0x2e, 0x0, 0x0, 0x0, 0x80, 0x40, +0x53, 0x15, 0xae, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x80, 0x3f, 0x4, 0x5f, 0x89, 0x43, 0xae, 0x7a, 0xb0, 0x42, 0xe3, 0xa8, 0xce, 0x42, 0x0, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x20, 0x1c, 0x1, 0x32, 0xa0, 0x96, 0xa6, 0xb1, 0x20, 0x1c, 0x1, 0xb2, 0x0, +0x0, 0x80, 0x3f, 0x68, 0x8, 0xa8, 0x23, 0xa0, 0x96, 0xa6, 0x31, 0x68, 0x8, 0xa8, 0x23, 0x0, 0x0, 0x80, 0x3f, 0xfc, +0xa2, 0xbc, 0xc2, 0x97, 0x10, 0x99, 0xbf, 0x2f, 0xcd, 0xc4, 0xb6, 0x46, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0x98, 0x26, 0x32, 0xb2, 0xb4, 0xb0, 0x63, 0x1f, 0x98, 0x26, 0x32, 0x32, 0x0, 0x0, 0x80, 0x3f, 0x0, +0x98, 0x23, 0xad, 0xb3, 0xb0, 0x63, 0x1f, 0x0, 0x98, 0x23, 0x2d, 0x0, 0x0, 0x80, 0x3f, 0x12, 0xc9, 0xe8, 0xc1, 0x0, +0x16, 0xcc, 0xbf, 0x80, 0x5a, 0x90, 0x31, 0x47, 0x0, 0x0, 0x0, 0x30, 0x51, 0x1d, 0xc3, 0x98, 0x1e, 0xfb, 0xc0, 0x3, +0xde, 0xf8, 0xc1, 0x0, 0x9f, 0x4a, 0xc1, 0xdc, 0xc0, 0xbd, 0x41, 0x7b, 0x2b, 0x6c, 0x41, 0x0, 0x0, 0x80, 0x3f, 0x40, +0x53, 0x15, 0x2e, 0x0, 0x0, 0x0, 0x80, 0x40, 0x53, 0x15, 0xae, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x73, 0x9b, 0xaf, 0x43, 0x1e, 0xeb, 0x9e, 0x42, 0x5a, +0x25, 0xe1, 0x42, 0x0, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x78, 0x63, 0x29, 0xb2, 0xd8, +0x94, 0x79, 0xb1, 0x78, 0x63, 0x29, 0x32, 0x0, 0x0, 0x80, 0x3f, 0x3c, 0x24, 0xa5, 0xa3, 0xd8, 0x94, 0x79, 0x31, 0x3c, +0x24, 0xa5, 0xa3, 0x0, 0x0, 0x80, 0x3f, 0xff, 0xf8, 0x20, 0xc3, 0x70, 0x88, 0x2d, 0xc0, 0x2, 0xf4, 0xba, 0x35, 0x49, +0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0xe0, 0x55, 0x8, 0x32, 0xd1, 0x9c, 0xc, 0xa1, 0xe0, +0x55, 0x8, 0xb2, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x4, 0x4, 0xaf, 0xd2, 0x9c, 0xc, 0xa1, 0x0, 0x4, 0x4, 0x2f, 0x0, +0x0, 0x80, 0x3f, 0x1b, 0x6b, 0x12, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe0, 0x0, 0x37, 0x4a, 0x0, 0x0, 0x0, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, +0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x40, 0x53, 0x15, 0x2e, 0x0, 0x0, 0x0, 0x80, 0x40, 0x53, 0x15, 0xae, 0x0, +0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0xa3, +0xed, 0xdf, 0x42, 0x3a, 0x37, 0xdf, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, +0x0, 0x80, 0x3f, 0xa0, 0xe9, 0xf4, 0xb0, 0x0, 0x0, 0x0, 0x80, 0xa0, 0xe9, 0xf4, 0x30, 0x0, 0x0, 0x80, 0x3f, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x80, 0x3f, 0x98, 0xfc, 0x9, 0xc2, 0x0, +0x30, 0x13, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x40, +0x53, 0x15, 0x2e, 0x0, 0x0, 0x0, 0x80, 0x40, 0x53, 0x15, 0xae, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x72, 0xc9, 0x4, 0x42, 0x9a, 0x5d, 0xe0, 0x42, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, 0x1c, 0x6, 0x50, 0x46, +0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x46, 0x1c, 0x6, 0xd0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0xd7, 0x59, 0x31, 0x0, +0x0, 0x0, 0x80, 0x0, 0xd7, 0x59, 0xb1, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x94, 0x2f, 0x13, 0x42, 0x0, 0x30, 0x13, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x4e, +0x0, 0x0, 0x0, 0x53, 0x42, 0x4b, 0x42, 0x50, 0x0, 0x0, 0x0, 0xaa, 0x3, 0x0, 0x0, 0x40, 0x1, 0x0, 0x0, 0x45, +0x1, 0x0, 0x0, 0x4c, 0x1, 0x0, 0x0, 0x55, 0x1, 0x0, 0x0, 0x5e, 0x1, 0x0, 0x0, 0x67, 0x1, 0x0, 0x0, 0x6f, +0x1, 0x0, 0x0, 0x77, 0x1, 0x0, 0x0, 0x7f, 0x1, 0x0, 0x0, 0x87, 0x1, 0x0, 0x0, 0x8f, 0x1, 0x0, 0x0, 0x97, +0x1, 0x0, 0x0, 0x9f, 0x1, 0x0, 0x0, 0xa7, 0x1, 0x0, 0x0, 0xaf, 0x1, 0x0, 0x0, 0xb7, 0x1, 0x0, 0x0, 0xbf, +0x1, 0x0, 0x0, 0xc7, 0x1, 0x0, 0x0, 0xcf, 0x1, 0x0, 0x0, 0xd7, 0x1, 0x0, 0x0, 0xdf, 0x1, 0x0, 0x0, 0xe7, +0x1, 0x0, 0x0, 0xef, 0x1, 0x0, 0x0, 0xf7, 0x1, 0x0, 0x0, 0xff, 0x1, 0x0, 0x0, 0x7, 0x2, 0x0, 0x0, 0xf, +0x2, 0x0, 0x0, 0x17, 0x2, 0x0, 0x0, 0x1f, 0x2, 0x0, 0x0, 0x27, 0x2, 0x0, 0x0, 0x30, 0x2, 0x0, 0x0, 0x39, +0x2, 0x0, 0x0, 0x42, 0x2, 0x0, 0x0, 0x49, 0x2, 0x0, 0x0, 0x51, 0x2, 0x0, 0x0, 0x59, 0x2, 0x0, 0x0, 0x60, +0x2, 0x0, 0x0, 0x68, 0x2, 0x0, 0x0, 0x6f, 0x2, 0x0, 0x0, 0x76, 0x2, 0x0, 0x0, 0x7e, 0x2, 0x0, 0x0, 0x85, +0x2, 0x0, 0x0, 0x8c, 0x2, 0x0, 0x0, 0x94, 0x2, 0x0, 0x0, 0x9b, 0x2, 0x0, 0x0, 0xa2, 0x2, 0x0, 0x0, 0xaa, +0x2, 0x0, 0x0, 0xb1, 0x2, 0x0, 0x0, 0xb8, 0x2, 0x0, 0x0, 0xc0, 0x2, 0x0, 0x0, 0xc7, 0x2, 0x0, 0x0, 0xce, +0x2, 0x0, 0x0, 0xd6, 0x2, 0x0, 0x0, 0xdd, 0x2, 0x0, 0x0, 0xe4, 0x2, 0x0, 0x0, 0xec, 0x2, 0x0, 0x0, 0xf3, +0x2, 0x0, 0x0, 0xfb, 0x2, 0x0, 0x0, 0x4, 0x3, 0x0, 0x0, 0xb, 0x3, 0x0, 0x0, 0x12, 0x3, 0x0, 0x0, 0x19, +0x3, 0x0, 0x0, 0x20, 0x3, 0x0, 0x0, 0x28, 0x3, 0x0, 0x0, 0x2f, 0x3, 0x0, 0x0, 0x3b, 0x3, 0x0, 0x0, 0x43, +0x3, 0x0, 0x0, 0x4a, 0x3, 0x0, 0x0, 0x55, 0x3, 0x0, 0x0, 0x5d, 0x3, 0x0, 0x0, 0x64, 0x3, 0x0, 0x0, 0x6b, +0x3, 0x0, 0x0, 0x73, 0x3, 0x0, 0x0, 0x7a, 0x3, 0x0, 0x0, 0x81, 0x3, 0x0, 0x0, 0x89, 0x3, 0x0, 0x0, 0x90, +0x3, 0x0, 0x0, 0x96, 0x3, 0x0, 0x0, 0x9d, 0x3, 0x0, 0x0, 0xa3, 0x3, 0x0, 0x0, 0x52, 0x4f, 0x4f, 0x54, 0x0, +0x4c, 0x49, 0x4e, 0x4b, 0x54, 0x4f, 0x0, 0x43, 0x4f, 0x52, 0x4f, 0x4e, 0x41, 0x30, 0x31, 0x0, 0x43, 0x52, 0x5f, 0x45, +0x46, 0x30, 0x31, 0x41, 0x0, 0x43, 0x52, 0x5f, 0x45, 0x46, 0x30, 0x31, 0x42, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, +0x31, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x32, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x33, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x30, 0x34, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x35, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, +0x36, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x37, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x38, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x30, 0x39, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x30, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, +0x31, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x32, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x33, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x31, 0x34, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x35, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, +0x36, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x37, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x38, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x31, 0x39, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x32, 0x30, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x32, +0x31, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x32, 0x32, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x32, 0x33, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x32, 0x34, 0x0, 0x43, 0x4f, 0x52, 0x4f, 0x4e, 0x41, 0x30, 0x32, 0x0, 0x43, 0x46, 0x5f, 0x45, 0x46, +0x30, 0x32, 0x41, 0x0, 0x43, 0x52, 0x5f, 0x45, 0x46, 0x30, 0x32, 0x42, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x31, 0x0, +0x47, 0x45, 0x41, 0x52, 0x30, 0x31, 0x42, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x31, 0x43, 0x0, 0x47, 0x45, 0x41, 0x52, +0x30, 0x32, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x32, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x30, 0x33, 0x0, 0x47, 0x45, +0x41, 0x52, 0x30, 0x33, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x33, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x30, 0x36, 0x0, +0x47, 0x45, 0x41, 0x52, 0x30, 0x34, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x34, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x30, +0x39, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x35, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x35, 0x42, 0x0, 0x42, 0x4f, 0x4e, +0x45, 0x31, 0x32, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x36, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x36, 0x42, 0x0, 0x42, +0x4f, 0x4e, 0x45, 0x31, 0x35, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x37, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x37, 0x42, +0x0, 0x42, 0x4f, 0x4e, 0x45, 0x31, 0x38, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x38, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, +0x38, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x31, 0x0, 0x47, 0x45, 0x4e, 0x45, 0x53, 0x49, 0x53, 0x0, 0x47, 0x45, +0x4e, 0x45, 0x53, 0x49, 0x53, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x30, 0x37, 0x0, 0x43, 0x4f, 0x52, 0x4f, 0x4e, 0x41, +0x0, 0x42, 0x4f, 0x4e, 0x45, 0x31, 0x36, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x30, 0x31, 0x0, 0x42, 0x49, 0x47, 0x47, 0x45, +0x41, 0x52, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x31, 0x30, 0x0, 0x53, 0x4d, 0x5f, 0x4c, 0x45, 0x46, 0x54, 0x50, 0x53, 0x54, +0x4e, 0x0, 0x4c, 0x5f, 0x43, 0x59, 0x4c, 0x30, 0x32, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x32, 0x0, 0x4c, 0x45, 0x46, +0x54, 0x50, 0x49, 0x53, 0x54, 0x4f, 0x4e, 0x0, 0x4c, 0x5f, 0x43, 0x59, 0x4c, 0x30, 0x31, 0x0, 0x42, 0x4f, 0x4e, 0x45, +0x32, 0x35, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x36, 0x0, 0x52, 0x5f, 0x43, 0x59, 0x4c, 0x30, 0x32, 0x0, 0x42, 0x4f, +0x4e, 0x45, 0x32, 0x38, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x39, 0x0, 0x52, 0x5f, 0x43, 0x59, 0x4c, 0x30, 0x31, 0x0, +0x42, 0x4f, 0x4e, 0x45, 0x33, 0x31, 0x0, 0x41, 0x52, 0x43, 0x30, 0x32, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x33, 0x33, 0x0, +0x41, 0x52, 0x43, 0x30, 0x31, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x33, 0x0, 0xe, 0x0, 0x48, 0x7, 0xd, 0x1, 0x0, +0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x80, 0x6, 0xd, 0x1, 0x0, 0x0, 0x7f, 0x43, 0x0, +0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0xb8, 0x5, 0xd, 0x1, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, +0x0, 0x7f, 0x43, 0xf0, 0x4, 0xd, 0x1, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0x43, 0x0, +0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, +0x0, 0x7f, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0x43, 0x0, +0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, +0x0, 0x7f, 0x43, 0x28, 0x4, 0xd, 0x1, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x0, 0x0, 0x7f, 0x43, 0x53, +0x42, 0x4b, 0x42, 0xe, 0x0, 0x0, 0x0, 0x7d, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x4a, +0x0, 0x0, 0x0, 0x56, 0x0, 0x0, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x5e, 0x0, 0x0, 0x0, 0x61, 0x0, 0x0, 0x0, 0x64, +0x0, 0x0, 0x0, 0x67, 0x0, 0x0, 0x0, 0x6a, 0x0, 0x0, 0x0, 0x6d, 0x0, 0x0, 0x0, 0x70, 0x0, 0x0, 0x0, 0x72, +0x0, 0x0, 0x0, 0x75, 0x0, 0x0, 0x0, 0x67, 0x65, 0x61, 0x72, 0x0, 0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, +0x20, 0x23, 0x31, 0x30, 0x0, 0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x23, 0x38, 0x0, 0x6d, 0x61, 0x73, +0x6b, 0x0, 0x67, 0x31, 0x0, 0x65, 0x31, 0x0, 0x6e, 0x31, 0x0, 0x65, 0x32, 0x0, 0x73, 0x31, 0x0, 0x69, 0x31, 0x0, +0x73, 0x32, 0x0, 0x33, 0x0, 0x64, 0x31, 0x0, 0x47, 0x65, 0x6e, 0x6c, 0x6f, 0x67, 0x6f, 0x0, 0x1, 0x0, 0x0, 0x0, +0x7, 0x8, 0x0, 0x0, 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x55, 0x0, +0x56, 0x0, 0x53, 0x0, 0x3, 0x0, 0x4, 0x0, 0x5, 0x0, 0x0, 0x0, 0x55, 0x0, 0x53, 0x0, 0x52, 0x0, 0x3, 0x0, +0x5, 0x0, 0x6, 0x0, 0x0, 0x0, 0x57, 0x0, 0x58, 0x0, 0x55, 0x0, 0x7, 0x0, 0x7, 0x0, 0x7, 0x0, 0x0, 0x0, +0x57, 0x0, 0x55, 0x0, 0x52, 0x0, 0x7, 0x0, 0x7, 0x0, 0x7, 0x0, 0x0, 0x0, 0x58, 0x0, 0x59, 0x0, 0x56, 0x0, +0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x0, 0x58, 0x0, 0x56, 0x0, 0x55, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, +0x0, 0x0, 0x59, 0x0, 0x5a, 0x0, 0x53, 0x0, 0x9, 0x0, 0x9, 0x0, 0x9, 0x0, 0x0, 0x0, 0x59, 0x0, 0x53, 0x0, +0x56, 0x0, 0x9, 0x0, 0x9, 0x0, 0x9, 0x0, 0x0, 0x0, 0x53, 0x0, 0x5b, 0x0, 0x54, 0x0, 0x1, 0x0, 0xa, 0x0, +0x2, 0x0, 0x0, 0x0, 0x5c, 0x0, 0x5d, 0x0, 0x5b, 0x0, 0xb, 0x0, 0xc, 0x0, 0xd, 0x0, 0x0, 0x0, 0x5c, 0x0, +0x5b, 0x0, 0x53, 0x0, 0xb, 0x0, 0xd, 0x0, 0x5, 0x0, 0x0, 0x0, 0x5a, 0x0, 0x5e, 0x0, 0x5c, 0x0, 0xe, 0x0, +0xe, 0x0, 0xe, 0x0, 0x0, 0x0, 0x5a, 0x0, 0x5c, 0x0, 0x53, 0x0, 0xe, 0x0, 0xe, 0x0, 0xe, 0x0, 0x0, 0x0, +0x5e, 0x0, 0x5f, 0x0, 0x5d, 0x0, 0xf, 0x0, 0xf, 0x0, 0xf, 0x0, 0x0, 0x0, 0x5e, 0x0, 0x5d, 0x0, 0x5c, 0x0, +0xf, 0x0, 0xf, 0x0, 0xf, 0x0, 0x0, 0x0, 0x5f, 0x0, 0x60, 0x0, 0x5b, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, +0x0, 0x0, 0x5f, 0x0, 0x5b, 0x0, 0x5d, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x0, 0x0, 0x5b, 0x0, 0x61, 0x0, +0x54, 0x0, 0xa, 0x0, 0x11, 0x0, 0x2, 0x0, 0x0, 0x0, 0x62, 0x0, 0x63, 0x0, 0x61, 0x0, 0x12, 0x0, 0x13, 0x0, +0x14, 0x0, 0x0, 0x0, 0x62, 0x0, 0x61, 0x0, 0x5b, 0x0, 0x12, 0x0, 0x14, 0x0, 0xd, 0x0, 0x0, 0x0, 0x60, 0x0, +0x64, 0x0, 0x62, 0x0, 0x15, 0x0, 0x16, 0x0, 0x15, 0x0, 0x0, 0x0, 0x60, 0x0, 0x62, 0x0, 0x5b, 0x0, 0x15, 0x0, +0x15, 0x0, 0x15, 0x0, 0x0, 0x0, 0x64, 0x0, 0x65, 0x0, 0x63, 0x0, 0x17, 0x0, 0x17, 0x0, 0x17, 0x0, 0x0, 0x0, +0x64, 0x0, 0x63, 0x0, 0x62, 0x0, 0x17, 0x0, 0x17, 0x0, 0x17, 0x0, 0x0, 0x0, 0x65, 0x0, 0x66, 0x0, 0x61, 0x0, +0x18, 0x0, 0x18, 0x0, 0x18, 0x0, 0x0, 0x0, 0x65, 0x0, 0x61, 0x0, 0x63, 0x0, 0x18, 0x0, 0x18, 0x0, 0x18, 0x0, +0x0, 0x0, 0x61, 0x0, 0x67, 0x0, 0x54, 0x0, 0x11, 0x0, 0x19, 0x0, 0x2, 0x0, 0x0, 0x0, 0x68, 0x0, 0x69, 0x0, +0x67, 0x0, 0x1a, 0x0, 0x1b, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x68, 0x0, 0x67, 0x0, 0x61, 0x0, 0x1a, 0x0, 0x1c, 0x0, +0x14, 0x0, 0x0, 0x0, 0x66, 0x0, 0x6a, 0x0, 0x68, 0x0, 0x1d, 0x0, 0x1e, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x66, 0x0, +0x68, 0x0, 0x61, 0x0, 0x1d, 0x0, 0x1d, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x6a, 0x0, 0x6b, 0x0, 0x69, 0x0, 0x1f, 0x0, +0x1f, 0x0, 0x1f, 0x0, 0x0, 0x0, 0x6a, 0x0, 0x69, 0x0, 0x68, 0x0, 0x1f, 0x0, 0x1f, 0x0, 0x1f, 0x0, 0x0, 0x0, +0x6b, 0x0, 0x6c, 0x0, 0x67, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x0, 0x0, 0x6b, 0x0, 0x67, 0x0, 0x69, 0x0, +0x20, 0x0, 0x20, 0x0, 0x21, 0x0, 0x0, 0x0, 0x67, 0x0, 0x6d, 0x0, 0x54, 0x0, 0x19, 0x0, 0x22, 0x0, 0x2, 0x0, +0x0, 0x0, 0x6e, 0x0, 0x6f, 0x0, 0x6d, 0x0, 0x23, 0x0, 0x24, 0x0, 0x25, 0x0, 0x0, 0x0, 0x6e, 0x0, 0x6d, 0x0, +0x67, 0x0, 0x23, 0x0, 0x25, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x6c, 0x0, 0x70, 0x0, 0x6e, 0x0, 0x26, 0x0, 0x26, 0x0, +0x26, 0x0, 0x0, 0x0, 0x6c, 0x0, 0x6e, 0x0, 0x67, 0x0, 0x26, 0x0, 0x26, 0x0, 0x26, 0x0, 0x0, 0x0, 0x70, 0x0, +0x71, 0x0, 0x6f, 0x0, 0x27, 0x0, 0x27, 0x0, 0x27, 0x0, 0x0, 0x0, 0x70, 0x0, 0x6f, 0x0, 0x6e, 0x0, 0x27, 0x0, +0x27, 0x0, 0x27, 0x0, 0x0, 0x0, 0x71, 0x0, 0x72, 0x0, 0x6d, 0x0, 0x28, 0x0, 0x28, 0x0, 0x28, 0x0, 0x0, 0x0, +0x71, 0x0, 0x6d, 0x0, 0x6f, 0x0, 0x28, 0x0, 0x28, 0x0, 0x29, 0x0, 0x0, 0x0, 0x6d, 0x0, 0x73, 0x0, 0x54, 0x0, +0x22, 0x0, 0x2a, 0x0, 0x2, 0x0, 0x0, 0x0, 0x74, 0x0, 0x75, 0x0, 0x73, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, +0x0, 0x0, 0x74, 0x0, 0x73, 0x0, 0x6d, 0x0, 0x2b, 0x0, 0x2d, 0x0, 0x25, 0x0, 0x0, 0x0, 0x72, 0x0, 0x76, 0x0, +0x74, 0x0, 0x2e, 0x0, 0x2e, 0x0, 0x2e, 0x0, 0x0, 0x0, 0x72, 0x0, 0x74, 0x0, 0x6d, 0x0, 0x2e, 0x0, 0x2e, 0x0, +0x2e, 0x0, 0x0, 0x0, 0x76, 0x0, 0x77, 0x0, 0x75, 0x0, 0x2f, 0x0, 0x2f, 0x0, 0x2f, 0x0, 0x0, 0x0, 0x76, 0x0, +0x75, 0x0, 0x74, 0x0, 0x2f, 0x0, 0x2f, 0x0, 0x2f, 0x0, 0x0, 0x0, 0x77, 0x0, 0x78, 0x0, 0x73, 0x0, 0x30, 0x0, +0x30, 0x0, 0x30, 0x0, 0x0, 0x0, 0x77, 0x0, 0x73, 0x0, 0x75, 0x0, 0x30, 0x0, 0x30, 0x0, 0x30, 0x0, 0x0, 0x0, +0x73, 0x0, 0x79, 0x0, 0x54, 0x0, 0x2a, 0x0, 0x31, 0x0, 0x2, 0x0, 0x0, 0x0, 0x7a, 0x0, 0x7b, 0x0, 0x79, 0x0, +0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x0, 0x0, 0x7a, 0x0, 0x79, 0x0, 0x73, 0x0, 0x32, 0x0, 0x34, 0x0, 0x2d, 0x0, +0x0, 0x0, 0x78, 0x0, 0x7c, 0x0, 0x7a, 0x0, 0x35, 0x0, 0x35, 0x0, 0x35, 0x0, 0x0, 0x0, 0x78, 0x0, 0x7a, 0x0, +0x73, 0x0, 0x35, 0x0, 0x35, 0x0, 0x35, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x7d, 0x0, 0x7b, 0x0, 0x36, 0x0, 0x36, 0x0, +0x36, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x7b, 0x0, 0x7a, 0x0, 0x36, 0x0, 0x36, 0x0, 0x36, 0x0, 0x0, 0x0, 0x7d, 0x0, +0x7e, 0x0, 0x79, 0x0, 0x37, 0x0, 0x37, 0x0, 0x37, 0x0, 0x0, 0x0, 0x7d, 0x0, 0x79, 0x0, 0x7b, 0x0, 0x37, 0x0, +0x37, 0x0, 0x37, 0x0, 0x0, 0x0, 0x79, 0x0, 0x7f, 0x0, 0x54, 0x0, 0x31, 0x0, 0x38, 0x0, 0x2, 0x0, 0x0, 0x0, +0x80, 0x0, 0x81, 0x0, 0x7f, 0x0, 0x39, 0x0, 0x3a, 0x0, 0x3b, 0x0, 0x0, 0x0, 0x80, 0x0, 0x7f, 0x0, 0x79, 0x0, +0x39, 0x0, 0x3b, 0x0, 0x34, 0x0, 0x0, 0x0, 0x7e, 0x0, 0x82, 0x0, 0x80, 0x0, 0x3c, 0x0, 0x3d, 0x0, 0x3c, 0x0, +0x0, 0x0, 0x7e, 0x0, 0x80, 0x0, 0x79, 0x0, 0x3c, 0x0, 0x3c, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x82, 0x0, 0x83, 0x0, +0x81, 0x0, 0x3e, 0x0, 0x3e, 0x0, 0x3e, 0x0, 0x0, 0x0, 0x82, 0x0, 0x81, 0x0, 0x80, 0x0, 0x3e, 0x0, 0x3e, 0x0, +0x3e, 0x0, 0x0, 0x0, 0x83, 0x0, 0x84, 0x0, 0x7f, 0x0, 0x3f, 0x0, 0x3f, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x83, 0x0, +0x7f, 0x0, 0x81, 0x0, 0x3f, 0x0, 0x3f, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x85, 0x0, 0x54, 0x0, 0x38, 0x0, +0x40, 0x0, 0x2, 0x0, 0x0, 0x0, 0x86, 0x0, 0x87, 0x0, 0x85, 0x0, 0x41, 0x0, 0x42, 0x0, 0x43, 0x0, 0x0, 0x0, +0x86, 0x0, 0x85, 0x0, 0x7f, 0x0, 0x41, 0x0, 0x43, 0x0, 0x3b, 0x0, 0x0, 0x0, 0x84, 0x0, 0x88, 0x0, 0x86, 0x0, +0x44, 0x0, 0x45, 0x0, 0x44, 0x0, 0x0, 0x0, 0x84, 0x0, 0x86, 0x0, 0x7f, 0x0, 0x44, 0x0, 0x44, 0x0, 0x44, 0x0, +0x0, 0x0, 0x88, 0x0, 0x89, 0x0, 0x87, 0x0, 0x46, 0x0, 0x46, 0x0, 0x46, 0x0, 0x0, 0x0, 0x88, 0x0, 0x87, 0x0, +0x86, 0x0, 0x46, 0x0, 0x46, 0x0, 0x46, 0x0, 0x0, 0x0, 0x89, 0x0, 0x8a, 0x0, 0x85, 0x0, 0x47, 0x0, 0x47, 0x0, +0x47, 0x0, 0x0, 0x0, 0x89, 0x0, 0x85, 0x0, 0x87, 0x0, 0x47, 0x0, 0x47, 0x0, 0x48, 0x0, 0x0, 0x0, 0x85, 0x0, +0x52, 0x0, 0x54, 0x0, 0x40, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x8b, 0x0, 0x8c, 0x0, 0x52, 0x0, 0x49, 0x0, +0x4a, 0x0, 0x6, 0x0, 0x0, 0x0, 0x8b, 0x0, 0x52, 0x0, 0x85, 0x0, 0x49, 0x0, 0x6, 0x0, 0x43, 0x0, 0x0, 0x0, +0x8a, 0x0, 0x8d, 0x0, 0x8b, 0x0, 0x4b, 0x0, 0x4b, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x8a, 0x0, 0x8b, 0x0, 0x85, 0x0, +0x4b, 0x0, 0x4b, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x8d, 0x0, 0x8e, 0x0, 0x8c, 0x0, 0x4c, 0x0, 0x4c, 0x0, 0x4c, 0x0, +0x0, 0x0, 0x8d, 0x0, 0x8c, 0x0, 0x8b, 0x0, 0x4c, 0x0, 0x4c, 0x0, 0x4c, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x57, 0x0, +0x52, 0x0, 0x4d, 0x0, 0x4d, 0x0, 0x4d, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x52, 0x0, 0x8c, 0x0, 0x4d, 0x0, 0x4d, 0x0, +0x4e, 0x0, 0x0, 0x0, 0x8f, 0x0, 0x90, 0x0, 0x91, 0x0, 0x4f, 0x0, 0x50, 0x0, 0x51, 0x0, 0x0, 0x0, 0x92, 0x0, +0x93, 0x0, 0x90, 0x0, 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x0, 0x0, 0x92, 0x0, 0x90, 0x0, 0x8f, 0x0, 0x52, 0x0, +0x54, 0x0, 0x55, 0x0, 0x0, 0x0, 0x94, 0x0, 0x95, 0x0, 0x92, 0x0, 0x56, 0x0, 0x56, 0x0, 0x56, 0x0, 0x0, 0x0, +0x94, 0x0, 0x92, 0x0, 0x8f, 0x0, 0x56, 0x0, 0x56, 0x0, 0x56, 0x0, 0x0, 0x0, 0x95, 0x0, 0x96, 0x0, 0x93, 0x0, +0x57, 0x0, 0x57, 0x0, 0x57, 0x0, 0x0, 0x0, 0x95, 0x0, 0x93, 0x0, 0x92, 0x0, 0x57, 0x0, 0x57, 0x0, 0x57, 0x0, +0x0, 0x0, 0x96, 0x0, 0x97, 0x0, 0x90, 0x0, 0x58, 0x0, 0x58, 0x0, 0x58, 0x0, 0x0, 0x0, 0x96, 0x0, 0x90, 0x0, +0x93, 0x0, 0x58, 0x0, 0x58, 0x0, 0x58, 0x0, 0x0, 0x0, 0x90, 0x0, 0x98, 0x0, 0x91, 0x0, 0x50, 0x0, 0x59, 0x0, +0x51, 0x0, 0x0, 0x0, 0x99, 0x0, 0x9a, 0x0, 0x98, 0x0, 0x5a, 0x0, 0x5b, 0x0, 0x5c, 0x0, 0x0, 0x0, 0x99, 0x0, +0x98, 0x0, 0x90, 0x0, 0x5a, 0x0, 0x5c, 0x0, 0x54, 0x0, 0x0, 0x0, 0x97, 0x0, 0x9b, 0x0, 0x99, 0x0, 0x5d, 0x0, +0x5e, 0x0, 0x5d, 0x0, 0x0, 0x0, 0x97, 0x0, 0x99, 0x0, 0x90, 0x0, 0x5d, 0x0, 0x5d, 0x0, 0x5d, 0x0, 0x0, 0x0, +0x9b, 0x0, 0x9c, 0x0, 0x9a, 0x0, 0x5f, 0x0, 0x5f, 0x0, 0x5f, 0x0, 0x0, 0x0, 0x9b, 0x0, 0x9a, 0x0, 0x99, 0x0, +0x5f, 0x0, 0x5f, 0x0, 0x5f, 0x0, 0x0, 0x0, 0x9c, 0x0, 0x9d, 0x0, 0x98, 0x0, 0x60, 0x0, 0x60, 0x0, 0x60, 0x0, +0x0, 0x0, 0x9c, 0x0, 0x98, 0x0, 0x9a, 0x0, 0x60, 0x0, 0x60, 0x0, 0x60, 0x0, 0x0, 0x0, 0x98, 0x0, 0x9e, 0x0, +0x91, 0x0, 0x59, 0x0, 0x61, 0x0, 0x51, 0x0, 0x0, 0x0, 0x9f, 0x0, 0xa0, 0x0, 0x9e, 0x0, 0x62, 0x0, 0x63, 0x0, +0x64, 0x0, 0x0, 0x0, 0x9f, 0x0, 0x9e, 0x0, 0x98, 0x0, 0x62, 0x0, 0x64, 0x0, 0x5c, 0x0, 0x0, 0x0, 0x9d, 0x0, +0xa1, 0x0, 0x9f, 0x0, 0x65, 0x0, 0x65, 0x0, 0x65, 0x0, 0x0, 0x0, 0x9d, 0x0, 0x9f, 0x0, 0x98, 0x0, 0x65, 0x0, +0x65, 0x0, 0x65, 0x0, 0x0, 0x0, 0xa1, 0x0, 0xa2, 0x0, 0xa0, 0x0, 0x66, 0x0, 0x66, 0x0, 0x66, 0x0, 0x0, 0x0, +0xa1, 0x0, 0xa0, 0x0, 0x9f, 0x0, 0x66, 0x0, 0x66, 0x0, 0x66, 0x0, 0x0, 0x0, 0xa2, 0x0, 0xa3, 0x0, 0x9e, 0x0, +0x67, 0x0, 0x67, 0x0, 0x67, 0x0, 0x0, 0x0, 0xa2, 0x0, 0x9e, 0x0, 0xa0, 0x0, 0x67, 0x0, 0x67, 0x0, 0x68, 0x0, +0x0, 0x0, 0x9e, 0x0, 0xa4, 0x0, 0x91, 0x0, 0x61, 0x0, 0x69, 0x0, 0x51, 0x0, 0x0, 0x0, 0xa5, 0x0, 0xa6, 0x0, +0xa4, 0x0, 0x6a, 0x0, 0x6b, 0x0, 0x6c, 0x0, 0x0, 0x0, 0xa5, 0x0, 0xa4, 0x0, 0x9e, 0x0, 0x6a, 0x0, 0x6c, 0x0, +0x64, 0x0, 0x0, 0x0, 0xa3, 0x0, 0xa7, 0x0, 0xa5, 0x0, 0x6d, 0x0, 0x6d, 0x0, 0x6d, 0x0, 0x0, 0x0, 0xa3, 0x0, +0xa5, 0x0, 0x9e, 0x0, 0x6d, 0x0, 0x6d, 0x0, 0x6d, 0x0, 0x0, 0x0, 0xa7, 0x0, 0xa8, 0x0, 0xa6, 0x0, 0x6e, 0x0, +0x6e, 0x0, 0x6e, 0x0, 0x0, 0x0, 0xa7, 0x0, 0xa6, 0x0, 0xa5, 0x0, 0x6e, 0x0, 0x6e, 0x0, 0x6e, 0x0, 0x0, 0x0, +0xa8, 0x0, 0xa9, 0x0, 0xa4, 0x0, 0x6f, 0x0, 0x6f, 0x0, 0x6f, 0x0, 0x0, 0x0, 0xa8, 0x0, 0xa4, 0x0, 0xa6, 0x0, +0x6f, 0x0, 0x6f, 0x0, 0x6f, 0x0, 0x0, 0x0, 0xa4, 0x0, 0xaa, 0x0, 0x91, 0x0, 0x69, 0x0, 0x70, 0x0, 0x51, 0x0, +0x0, 0x0, 0xab, 0x0, 0xac, 0x0, 0xaa, 0x0, 0x71, 0x0, 0x72, 0x0, 0x73, 0x0, 0x0, 0x0, 0xab, 0x0, 0xaa, 0x0, +0xa4, 0x0, 0x71, 0x0, 0x73, 0x0, 0x6c, 0x0, 0x0, 0x0, 0xa9, 0x0, 0xad, 0x0, 0xab, 0x0, 0x74, 0x0, 0x75, 0x0, +0x74, 0x0, 0x0, 0x0, 0xa9, 0x0, 0xab, 0x0, 0xa4, 0x0, 0x74, 0x0, 0x74, 0x0, 0x74, 0x0, 0x0, 0x0, 0xad, 0x0, +0xae, 0x0, 0xac, 0x0, 0x76, 0x0, 0x76, 0x0, 0x76, 0x0, 0x0, 0x0, 0xad, 0x0, 0xac, 0x0, 0xab, 0x0, 0x76, 0x0, +0x76, 0x0, 0x76, 0x0, 0x0, 0x0, 0xae, 0x0, 0xaf, 0x0, 0xaa, 0x0, 0x77, 0x0, 0x77, 0x0, 0x77, 0x0, 0x0, 0x0, +0xae, 0x0, 0xaa, 0x0, 0xac, 0x0, 0x77, 0x0, 0x77, 0x0, 0x77, 0x0, 0x0, 0x0, 0xaa, 0x0, 0xb0, 0x0, 0x91, 0x0, +0x70, 0x0, 0x78, 0x0, 0x51, 0x0, 0x0, 0x0, 0xb1, 0x0, 0xb2, 0x0, 0xb0, 0x0, 0x79, 0x0, 0x7a, 0x0, 0x7b, 0x0, +0x0, 0x0, 0xb1, 0x0, 0xb0, 0x0, 0xaa, 0x0, 0x79, 0x0, 0x7b, 0x0, 0x73, 0x0, 0x0, 0x0, 0xaf, 0x0, 0xb3, 0x0, +0xb1, 0x0, 0x7c, 0x0, 0x7c, 0x0, 0x7c, 0x0, 0x0, 0x0, 0xaf, 0x0, 0xb1, 0x0, 0xaa, 0x0, 0x7c, 0x0, 0x7c, 0x0, +0x7c, 0x0, 0x0, 0x0, 0xb3, 0x0, 0xb4, 0x0, 0xb2, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x0, 0x0, 0xb3, 0x0, +0xb2, 0x0, 0xb1, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x0, 0x0, 0xb4, 0x0, 0xb5, 0x0, 0xb0, 0x0, 0x7e, 0x0, +0x7e, 0x0, 0x7e, 0x0, 0x0, 0x0, 0xb4, 0x0, 0xb0, 0x0, 0xb2, 0x0, 0x7e, 0x0, 0x7e, 0x0, 0x7e, 0x0, 0x0, 0x0, +0xb0, 0x0, 0xb6, 0x0, 0x91, 0x0, 0x78, 0x0, 0x7f, 0x0, 0x51, 0x0, 0x0, 0x0, 0xb7, 0x0, 0xb8, 0x0, 0xb6, 0x0, +0x80, 0x0, 0x81, 0x0, 0x82, 0x0, 0x0, 0x0, 0xb7, 0x0, 0xb6, 0x0, 0xb0, 0x0, 0x80, 0x0, 0x82, 0x0, 0x7b, 0x0, +0x0, 0x0, 0xb5, 0x0, 0xb9, 0x0, 0xb7, 0x0, 0x83, 0x0, 0x84, 0x0, 0x83, 0x0, 0x0, 0x0, 0xb5, 0x0, 0xb7, 0x0, +0xb0, 0x0, 0x83, 0x0, 0x83, 0x0, 0x83, 0x0, 0x0, 0x0, 0xb9, 0x0, 0xba, 0x0, 0xb8, 0x0, 0x85, 0x0, 0x85, 0x0, +0x85, 0x0, 0x0, 0x0, 0xb9, 0x0, 0xb8, 0x0, 0xb7, 0x0, 0x85, 0x0, 0x85, 0x0, 0x85, 0x0, 0x0, 0x0, 0xba, 0x0, +0xbb, 0x0, 0xb6, 0x0, 0x86, 0x0, 0x86, 0x0, 0x86, 0x0, 0x0, 0x0, 0xba, 0x0, 0xb6, 0x0, 0xb8, 0x0, 0x86, 0x0, +0x86, 0x0, 0x86, 0x0, 0x0, 0x0, 0xb6, 0x0, 0xbc, 0x0, 0x91, 0x0, 0x7f, 0x0, 0x87, 0x0, 0x51, 0x0, 0x0, 0x0, +0xbd, 0x0, 0xbe, 0x0, 0xbc, 0x0, 0x88, 0x0, 0x89, 0x0, 0x8a, 0x0, 0x0, 0x0, 0xbd, 0x0, 0xbc, 0x0, 0xb6, 0x0, +0x88, 0x0, 0x8a, 0x0, 0x82, 0x0, 0x0, 0x0, 0xbb, 0x0, 0xbf, 0x0, 0xbd, 0x0, 0x8b, 0x0, 0x8b, 0x0, 0x8b, 0x0, +0x0, 0x0, 0xbb, 0x0, 0xbd, 0x0, 0xb6, 0x0, 0x8b, 0x0, 0x8b, 0x0, 0x8b, 0x0, 0x0, 0x0, 0xbf, 0x0, 0xc0, 0x0, +0xbe, 0x0, 0x8c, 0x0, 0x8c, 0x0, 0x8c, 0x0, 0x0, 0x0, 0xbf, 0x0, 0xbe, 0x0, 0xbd, 0x0, 0x8c, 0x0, 0x8c, 0x0, +0x8c, 0x0, 0x0, 0x0, 0xc0, 0x0, 0xc1, 0x0, 0xbc, 0x0, 0x8d, 0x0, 0x8d, 0x0, 0x8d, 0x0, 0x0, 0x0, 0xc0, 0x0, +0xbc, 0x0, 0xbe, 0x0, 0x8d, 0x0, 0x8d, 0x0, 0x8e, 0x0, 0x0, 0x0, 0xbc, 0x0, 0xc2, 0x0, 0x91, 0x0, 0x87, 0x0, +0x8f, 0x0, 0x51, 0x0, 0x0, 0x0, 0xc3, 0x0, 0xc4, 0x0, 0xc2, 0x0, 0x90, 0x0, 0x91, 0x0, 0x92, 0x0, 0x0, 0x0, +0xc3, 0x0, 0xc2, 0x0, 0xbc, 0x0, 0x90, 0x0, 0x92, 0x0, 0x8a, 0x0, 0x0, 0x0, 0xc1, 0x0, 0xc5, 0x0, 0xc3, 0x0, +0x93, 0x0, 0x93, 0x0, 0x93, 0x0, 0x0, 0x0, 0xc1, 0x0, 0xc3, 0x0, 0xbc, 0x0, 0x93, 0x0, 0x93, 0x0, 0x93, 0x0, +0x0, 0x0, 0xc5, 0x0, 0xc6, 0x0, 0xc4, 0x0, 0x94, 0x0, 0x94, 0x0, 0x94, 0x0, 0x0, 0x0, 0xc5, 0x0, 0xc4, 0x0, +0xc3, 0x0, 0x94, 0x0, 0x94, 0x0, 0x94, 0x0, 0x0, 0x0, 0xc6, 0x0, 0xc7, 0x0, 0xc2, 0x0, 0x95, 0x0, 0x95, 0x0, +0x95, 0x0, 0x0, 0x0, 0xc6, 0x0, 0xc2, 0x0, 0xc4, 0x0, 0x95, 0x0, 0x95, 0x0, 0x95, 0x0, 0x0, 0x0, 0xc2, 0x0, +0x8f, 0x0, 0x91, 0x0, 0x8f, 0x0, 0x4f, 0x0, 0x51, 0x0, 0x0, 0x0, 0xc8, 0x0, 0xc9, 0x0, 0x8f, 0x0, 0x96, 0x0, +0x97, 0x0, 0x55, 0x0, 0x0, 0x0, 0xc8, 0x0, 0x8f, 0x0, 0xc2, 0x0, 0x96, 0x0, 0x55, 0x0, 0x92, 0x0, 0x0, 0x0, +0xc7, 0x0, 0xca, 0x0, 0xc8, 0x0, 0x98, 0x0, 0x99, 0x0, 0x98, 0x0, 0x0, 0x0, 0xc7, 0x0, 0xc8, 0x0, 0xc2, 0x0, +0x98, 0x0, 0x98, 0x0, 0x98, 0x0, 0x0, 0x0, 0xca, 0x0, 0xcb, 0x0, 0xc9, 0x0, 0x9a, 0x0, 0x9a, 0x0, 0x9a, 0x0, +0x0, 0x0, 0xca, 0x0, 0xc9, 0x0, 0xc8, 0x0, 0x9a, 0x0, 0x9a, 0x0, 0x9a, 0x0, 0x0, 0x0, 0xcb, 0x0, 0x94, 0x0, +0x8f, 0x0, 0x9b, 0x0, 0x9b, 0x0, 0x9b, 0x0, 0x0, 0x0, 0xcb, 0x0, 0x8f, 0x0, 0xc9, 0x0, 0x9b, 0x0, 0x9b, 0x0, +0x9b, 0x0, 0x0, 0x0, 0xcc, 0x0, 0xcd, 0x0, 0xce, 0x0, 0x9c, 0x0, 0x9d, 0x0, 0x9e, 0x0, 0x0, 0x0, 0xcf, 0x0, +0xd0, 0x0, 0xcd, 0x0, 0x9f, 0x0, 0xa0, 0x0, 0xa1, 0x0, 0x0, 0x0, 0xcf, 0x0, 0xcd, 0x0, 0xcc, 0x0, 0x9f, 0x0, +0xa1, 0x0, 0xa2, 0x0, 0x0, 0x0, 0xd1, 0x0, 0xd2, 0x0, 0xcf, 0x0, 0xa3, 0x0, 0xa3, 0x0, 0xa3, 0x0, 0x0, 0x0, +0xd1, 0x0, 0xcf, 0x0, 0xcc, 0x0, 0xa3, 0x0, 0xa3, 0x0, 0xa3, 0x0, 0x0, 0x0, 0xd2, 0x0, 0xd3, 0x0, 0xd0, 0x0, +0xa4, 0x0, 0xa4, 0x0, 0xa4, 0x0, 0x0, 0x0, 0xd2, 0x0, 0xd0, 0x0, 0xcf, 0x0, 0xa4, 0x0, 0xa4, 0x0, 0xa4, 0x0, +0x0, 0x0, 0xd3, 0x0, 0xd4, 0x0, 0xcd, 0x0, 0xa5, 0x0, 0xa5, 0x0, 0xa5, 0x0, 0x0, 0x0, 0xd3, 0x0, 0xcd, 0x0, +0xd0, 0x0, 0xa5, 0x0, 0xa5, 0x0, 0xa6, 0x0, 0x0, 0x0, 0xcd, 0x0, 0xd5, 0x0, 0xce, 0x0, 0x9d, 0x0, 0xa7, 0x0, +0x9e, 0x0, 0x0, 0x0, 0xd6, 0x0, 0xd7, 0x0, 0xd5, 0x0, 0xa8, 0x0, 0xa9, 0x0, 0xaa, 0x0, 0x0, 0x0, 0xd6, 0x0, +0xd5, 0x0, 0xcd, 0x0, 0xa8, 0x0, 0xaa, 0x0, 0xa1, 0x0, 0x0, 0x0, 0xd4, 0x0, 0xd8, 0x0, 0xd6, 0x0, 0xab, 0x0, +0xab, 0x0, 0xab, 0x0, 0x0, 0x0, 0xd4, 0x0, 0xd6, 0x0, 0xcd, 0x0, 0xab, 0x0, 0xab, 0x0, 0xab, 0x0, 0x0, 0x0, +0xd8, 0x0, 0xd9, 0x0, 0xd7, 0x0, 0xac, 0x0, 0xac, 0x0, 0xac, 0x0, 0x0, 0x0, 0xd8, 0x0, 0xd7, 0x0, 0xd6, 0x0, +0xac, 0x0, 0xac, 0x0, 0xac, 0x0, 0x0, 0x0, 0xd9, 0x0, 0xda, 0x0, 0xd5, 0x0, 0xad, 0x0, 0xad, 0x0, 0xad, 0x0, +0x0, 0x0, 0xd9, 0x0, 0xd5, 0x0, 0xd7, 0x0, 0xad, 0x0, 0xad, 0x0, 0xad, 0x0, 0x0, 0x0, 0xd5, 0x0, 0xdb, 0x0, +0xce, 0x0, 0xa7, 0x0, 0xae, 0x0, 0x9e, 0x0, 0x0, 0x0, 0xdc, 0x0, 0xdd, 0x0, 0xdb, 0x0, 0xaf, 0x0, 0xb0, 0x0, +0xb1, 0x0, 0x0, 0x0, 0xdc, 0x0, 0xdb, 0x0, 0xd5, 0x0, 0xaf, 0x0, 0xb1, 0x0, 0xaa, 0x0, 0x0, 0x0, 0xda, 0x0, +0xde, 0x0, 0xdc, 0x0, 0xb2, 0x0, 0xb2, 0x0, 0xb2, 0x0, 0x0, 0x0, 0xda, 0x0, 0xdc, 0x0, 0xd5, 0x0, 0xb2, 0x0, +0xb2, 0x0, 0xb2, 0x0, 0x0, 0x0, 0xde, 0x0, 0xdf, 0x0, 0xdd, 0x0, 0xb3, 0x0, 0xb3, 0x0, 0xb3, 0x0, 0x0, 0x0, +0xde, 0x0, 0xdd, 0x0, 0xdc, 0x0, 0xb3, 0x0, 0xb3, 0x0, 0xb3, 0x0, 0x0, 0x0, 0xdf, 0x0, 0xe0, 0x0, 0xdb, 0x0, +0xb4, 0x0, 0xb4, 0x0, 0xb4, 0x0, 0x0, 0x0, 0xdf, 0x0, 0xdb, 0x0, 0xdd, 0x0, 0xb4, 0x0, 0xb4, 0x0, 0xb4, 0x0, +0x0, 0x0, 0xdb, 0x0, 0xe1, 0x0, 0xce, 0x0, 0xae, 0x0, 0xb5, 0x0, 0x9e, 0x0, 0x0, 0x0, 0xe2, 0x0, 0xe3, 0x0, +0xe1, 0x0, 0xb6, 0x0, 0xb7, 0x0, 0xb8, 0x0, 0x0, 0x0, 0xe2, 0x0, 0xe1, 0x0, 0xdb, 0x0, 0xb6, 0x0, 0xb8, 0x0, +0xb1, 0x0, 0x0, 0x0, 0xe0, 0x0, 0xe4, 0x0, 0xe2, 0x0, 0xb9, 0x0, 0xba, 0x0, 0xb9, 0x0, 0x0, 0x0, 0xe0, 0x0, +0xe2, 0x0, 0xdb, 0x0, 0xb9, 0x0, 0xb9, 0x0, 0xb9, 0x0, 0x0, 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe3, 0x0, 0xbb, 0x0, +0xbb, 0x0, 0xbb, 0x0, 0x0, 0x0, 0xe4, 0x0, 0xe3, 0x0, 0xe2, 0x0, 0xbb, 0x0, 0xbb, 0x0, 0xbb, 0x0, 0x0, 0x0, +0xe5, 0x0, 0xe6, 0x0, 0xe1, 0x0, 0xbc, 0x0, 0xbc, 0x0, 0xbc, 0x0, 0x0, 0x0, 0xe5, 0x0, 0xe1, 0x0, 0xe3, 0x0, +0xbc, 0x0, 0xbc, 0x0, 0xbc, 0x0, 0x0, 0x0, 0xe1, 0x0, 0xe7, 0x0, 0xce, 0x0, 0xb5, 0x0, 0xbd, 0x0, 0x9e, 0x0, +0x0, 0x0, 0xe8, 0x0, 0xe9, 0x0, 0xe7, 0x0, 0xbe, 0x0, 0xbf, 0x0, 0xc0, 0x0, 0x0, 0x0, 0xe8, 0x0, 0xe7, 0x0, +0xe1, 0x0, 0xbe, 0x0, 0xc0, 0x0, 0xb8, 0x0, 0x0, 0x0, 0xe6, 0x0, 0xea, 0x0, 0xe8, 0x0, 0xc1, 0x0, 0xc2, 0x0, +0xc1, 0x0, 0x0, 0x0, 0xe6, 0x0, 0xe8, 0x0, 0xe1, 0x0, 0xc1, 0x0, 0xc1, 0x0, 0xc1, 0x0, 0x0, 0x0, 0xea, 0x0, +0xeb, 0x0, 0xe9, 0x0, 0xc3, 0x0, 0xc3, 0x0, 0xc3, 0x0, 0x0, 0x0, 0xea, 0x0, 0xe9, 0x0, 0xe8, 0x0, 0xc3, 0x0, +0xc3, 0x0, 0xc3, 0x0, 0x0, 0x0, 0xeb, 0x0, 0xec, 0x0, 0xe7, 0x0, 0xc4, 0x0, 0xc4, 0x0, 0xc4, 0x0, 0x0, 0x0, +0xeb, 0x0, 0xe7, 0x0, 0xe9, 0x0, 0xc4, 0x0, 0xc4, 0x0, 0xc5, 0x0, 0x0, 0x0, 0xe7, 0x0, 0xed, 0x0, 0xce, 0x0, +0xbd, 0x0, 0xc6, 0x0, 0x9e, 0x0, 0x0, 0x0, 0xee, 0x0, 0xef, 0x0, 0xed, 0x0, 0xc7, 0x0, 0xc8, 0x0, 0xc9, 0x0, +0x0, 0x0, 0xee, 0x0, 0xed, 0x0, 0xe7, 0x0, 0xc7, 0x0, 0xc9, 0x0, 0xc0, 0x0, 0x0, 0x0, 0xec, 0x0, 0xf0, 0x0, +0xee, 0x0, 0xca, 0x0, 0xca, 0x0, 0xca, 0x0, 0x0, 0x0, 0xec, 0x0, 0xee, 0x0, 0xe7, 0x0, 0xca, 0x0, 0xca, 0x0, +0xca, 0x0, 0x0, 0x0, 0xf0, 0x0, 0xf1, 0x0, 0xef, 0x0, 0xcb, 0x0, 0xcb, 0x0, 0xcb, 0x0, 0x0, 0x0, 0xf0, 0x0, +0xef, 0x0, 0xee, 0x0, 0xcb, 0x0, 0xcb, 0x0, 0xcb, 0x0, 0x0, 0x0, 0xf1, 0x0, 0xf2, 0x0, 0xed, 0x0, 0xcc, 0x0, +0xcc, 0x0, 0xcc, 0x0, 0x0, 0x0, 0xf1, 0x0, 0xed, 0x0, 0xef, 0x0, 0xcc, 0x0, 0xcc, 0x0, 0xcd, 0x0, 0x0, 0x0, +0xed, 0x0, 0xf3, 0x0, 0xce, 0x0, 0xc6, 0x0, 0xce, 0x0, 0x9e, 0x0, 0x0, 0x0, 0xf4, 0x0, 0xf5, 0x0, 0xf3, 0x0, +0xcf, 0x0, 0xd0, 0x0, 0xd1, 0x0, 0x0, 0x0, 0xf4, 0x0, 0xf3, 0x0, 0xed, 0x0, 0xcf, 0x0, 0xd1, 0x0, 0xc9, 0x0, +0x0, 0x0, 0xf2, 0x0, 0xf6, 0x0, 0xf4, 0x0, 0xd2, 0x0, 0xd2, 0x0, 0xd2, 0x0, 0x0, 0x0, 0xf2, 0x0, 0xf4, 0x0, +0xed, 0x0, 0xd2, 0x0, 0xd2, 0x0, 0xd2, 0x0, 0x0, 0x0, 0xf6, 0x0, 0xf7, 0x0, 0xf5, 0x0, 0xd3, 0x0, 0xd3, 0x0, +0xd3, 0x0, 0x0, 0x0, 0xf6, 0x0, 0xf5, 0x0, 0xf4, 0x0, 0xd3, 0x0, 0xd3, 0x0, 0xd3, 0x0, 0x0, 0x0, 0xf7, 0x0, +0xf8, 0x0, 0xf3, 0x0, 0xd4, 0x0, 0xd4, 0x0, 0xd4, 0x0, 0x0, 0x0, 0xf7, 0x0, 0xf3, 0x0, 0xf5, 0x0, 0xd4, 0x0, +0xd4, 0x0, 0xd4, 0x0, 0x0, 0x0, 0xf3, 0x0, 0xf9, 0x0, 0xce, 0x0, 0xce, 0x0, 0xd5, 0x0, 0x9e, 0x0, 0x0, 0x0, +0xfa, 0x0, 0xfb, 0x0, 0xf9, 0x0, 0xd6, 0x0, 0xd7, 0x0, 0xd8, 0x0, 0x0, 0x0, 0xfa, 0x0, 0xf9, 0x0, 0xf3, 0x0, +0xd6, 0x0, 0xd8, 0x0, 0xd1, 0x0, 0x0, 0x0, 0xf8, 0x0, 0xfc, 0x0, 0xfa, 0x0, 0xd9, 0x0, 0xd9, 0x0, 0xd9, 0x0, +0x0, 0x0, 0xf8, 0x0, 0xfa, 0x0, 0xf3, 0x0, 0xd9, 0x0, 0xd9, 0x0, 0xd9, 0x0, 0x0, 0x0, 0xfc, 0x0, 0xfd, 0x0, +0xfb, 0x0, 0xda, 0x0, 0xda, 0x0, 0xda, 0x0, 0x0, 0x0, 0xfc, 0x0, 0xfb, 0x0, 0xfa, 0x0, 0xda, 0x0, 0xda, 0x0, +0xda, 0x0, 0x0, 0x0, 0xfd, 0x0, 0xfe, 0x0, 0xf9, 0x0, 0xdb, 0x0, 0xdb, 0x0, 0xdb, 0x0, 0x0, 0x0, 0xfd, 0x0, +0xf9, 0x0, 0xfb, 0x0, 0xdb, 0x0, 0xdb, 0x0, 0xdb, 0x0, 0x0, 0x0, 0xf9, 0x0, 0xff, 0x0, 0xce, 0x0, 0xd5, 0x0, +0xdc, 0x0, 0x9e, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0xff, 0x0, 0xdd, 0x0, 0xde, 0x0, 0xdf, 0x0, 0x0, 0x0, +0x0, 0x1, 0xff, 0x0, 0xf9, 0x0, 0xdd, 0x0, 0xdf, 0x0, 0xd8, 0x0, 0x0, 0x0, 0xfe, 0x0, 0x2, 0x1, 0x0, 0x1, +0xe0, 0x0, 0xe1, 0x0, 0xe0, 0x0, 0x0, 0x0, 0xfe, 0x0, 0x0, 0x1, 0xf9, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, +0x0, 0x0, 0x2, 0x1, 0x3, 0x1, 0x1, 0x1, 0xe2, 0x0, 0xe2, 0x0, 0xe2, 0x0, 0x0, 0x0, 0x2, 0x1, 0x1, 0x1, +0x0, 0x1, 0xe2, 0x0, 0xe2, 0x0, 0xe2, 0x0, 0x0, 0x0, 0x3, 0x1, 0x4, 0x1, 0xff, 0x0, 0xe3, 0x0, 0xe3, 0x0, +0xe3, 0x0, 0x0, 0x0, 0x3, 0x1, 0xff, 0x0, 0x1, 0x1, 0xe3, 0x0, 0xe3, 0x0, 0xe3, 0x0, 0x0, 0x0, 0xff, 0x0, +0xcc, 0x0, 0xce, 0x0, 0xdc, 0x0, 0x9c, 0x0, 0x9e, 0x0, 0x0, 0x0, 0x5, 0x1, 0x6, 0x1, 0xcc, 0x0, 0xe4, 0x0, +0xe5, 0x0, 0xa2, 0x0, 0x0, 0x0, 0x5, 0x1, 0xcc, 0x0, 0xff, 0x0, 0xe4, 0x0, 0xa2, 0x0, 0xdf, 0x0, 0x0, 0x0, +0x4, 0x1, 0x7, 0x1, 0x5, 0x1, 0xe6, 0x0, 0xe7, 0x0, 0xe6, 0x0, 0x0, 0x0, 0x4, 0x1, 0x5, 0x1, 0xff, 0x0, +0xe6, 0x0, 0xe6, 0x0, 0xe6, 0x0, 0x0, 0x0, 0x7, 0x1, 0x8, 0x1, 0x6, 0x1, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, +0x0, 0x0, 0x7, 0x1, 0x6, 0x1, 0x5, 0x1, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0x0, 0x0, 0x8, 0x1, 0xd1, 0x0, +0xcc, 0x0, 0xe9, 0x0, 0xe9, 0x0, 0xe9, 0x0, 0x0, 0x0, 0x8, 0x1, 0xcc, 0x0, 0x6, 0x1, 0xe9, 0x0, 0xe9, 0x0, +0xea, 0x0, 0x0, 0x0, 0x9, 0x1, 0xa, 0x1, 0xb, 0x1, 0xeb, 0x0, 0xec, 0x0, 0xed, 0x0, 0x0, 0x0, 0xc, 0x1, +0xd, 0x1, 0xa, 0x1, 0xee, 0x0, 0xef, 0x0, 0xf0, 0x0, 0x0, 0x0, 0xc, 0x1, 0xa, 0x1, 0x9, 0x1, 0xee, 0x0, +0xf0, 0x0, 0xf1, 0x0, 0x0, 0x0, 0xe, 0x1, 0xf, 0x1, 0xc, 0x1, 0xf2, 0x0, 0xf2, 0x0, 0xf2, 0x0, 0x0, 0x0, +0xe, 0x1, 0xc, 0x1, 0x9, 0x1, 0xf2, 0x0, 0xf2, 0x0, 0xf2, 0x0, 0x0, 0x0, 0xf, 0x1, 0x10, 0x1, 0xd, 0x1, +0xf3, 0x0, 0xf3, 0x0, 0xf3, 0x0, 0x0, 0x0, 0xf, 0x1, 0xd, 0x1, 0xc, 0x1, 0xf3, 0x0, 0xf3, 0x0, 0xf3, 0x0, +0x0, 0x0, 0x10, 0x1, 0x11, 0x1, 0xa, 0x1, 0xf4, 0x0, 0xf4, 0x0, 0xf4, 0x0, 0x0, 0x0, 0x10, 0x1, 0xa, 0x1, +0xd, 0x1, 0xf4, 0x0, 0xf4, 0x0, 0xf4, 0x0, 0x0, 0x0, 0xa, 0x1, 0x12, 0x1, 0xb, 0x1, 0xec, 0x0, 0xf5, 0x0, +0xed, 0x0, 0x0, 0x0, 0x13, 0x1, 0x14, 0x1, 0x12, 0x1, 0xf6, 0x0, 0xf7, 0x0, 0xf8, 0x0, 0x0, 0x0, 0x13, 0x1, +0x12, 0x1, 0xa, 0x1, 0xf6, 0x0, 0xf8, 0x0, 0xf0, 0x0, 0x0, 0x0, 0x11, 0x1, 0x15, 0x1, 0x13, 0x1, 0xf9, 0x0, +0xfa, 0x0, 0xf9, 0x0, 0x0, 0x0, 0x11, 0x1, 0x13, 0x1, 0xa, 0x1, 0xf9, 0x0, 0xf9, 0x0, 0xf9, 0x0, 0x0, 0x0, +0x15, 0x1, 0x16, 0x1, 0x14, 0x1, 0xfb, 0x0, 0xfb, 0x0, 0xfb, 0x0, 0x0, 0x0, 0x15, 0x1, 0x14, 0x1, 0x13, 0x1, +0xfb, 0x0, 0xfb, 0x0, 0xfb, 0x0, 0x0, 0x0, 0x16, 0x1, 0x17, 0x1, 0x12, 0x1, 0xfc, 0x0, 0xfc, 0x0, 0xfc, 0x0, +0x0, 0x0, 0x16, 0x1, 0x12, 0x1, 0x14, 0x1, 0xfc, 0x0, 0xfc, 0x0, 0xfc, 0x0, 0x0, 0x0, 0x12, 0x1, 0x18, 0x1, +0xb, 0x1, 0xf5, 0x0, 0xfd, 0x0, 0xed, 0x0, 0x0, 0x0, 0x19, 0x1, 0x1a, 0x1, 0x18, 0x1, 0xfe, 0x0, 0xff, 0x0, +0x0, 0x1, 0x0, 0x0, 0x19, 0x1, 0x18, 0x1, 0x12, 0x1, 0xfe, 0x0, 0x0, 0x1, 0xf8, 0x0, 0x0, 0x0, 0x17, 0x1, +0x1b, 0x1, 0x19, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x17, 0x1, 0x19, 0x1, 0x12, 0x1, 0x1, 0x1, +0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x1b, 0x1, 0x1c, 0x1, 0x1a, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0x0, 0x0, +0x1b, 0x1, 0x1a, 0x1, 0x19, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0x0, 0x0, 0x1c, 0x1, 0x1d, 0x1, 0x18, 0x1, +0x3, 0x1, 0x3, 0x1, 0x3, 0x1, 0x0, 0x0, 0x1c, 0x1, 0x18, 0x1, 0x1a, 0x1, 0x3, 0x1, 0x3, 0x1, 0x4, 0x1, +0x0, 0x0, 0x18, 0x1, 0x1e, 0x1, 0xb, 0x1, 0xfd, 0x0, 0x5, 0x1, 0xed, 0x0, 0x0, 0x0, 0x1f, 0x1, 0x20, 0x1, +0x1e, 0x1, 0x6, 0x1, 0x7, 0x1, 0x8, 0x1, 0x0, 0x0, 0x1f, 0x1, 0x1e, 0x1, 0x18, 0x1, 0x6, 0x1, 0x8, 0x1, +0x0, 0x1, 0x0, 0x0, 0x1d, 0x1, 0x21, 0x1, 0x1f, 0x1, 0x9, 0x1, 0x9, 0x1, 0x9, 0x1, 0x0, 0x0, 0x1d, 0x1, +0x1f, 0x1, 0x18, 0x1, 0x9, 0x1, 0x9, 0x1, 0x9, 0x1, 0x0, 0x0, 0x21, 0x1, 0x22, 0x1, 0x20, 0x1, 0xa, 0x1, +0xa, 0x1, 0xa, 0x1, 0x0, 0x0, 0x21, 0x1, 0x20, 0x1, 0x1f, 0x1, 0xa, 0x1, 0xa, 0x1, 0xa, 0x1, 0x0, 0x0, +0x22, 0x1, 0x23, 0x1, 0x1e, 0x1, 0xb, 0x1, 0xb, 0x1, 0xb, 0x1, 0x0, 0x0, 0x22, 0x1, 0x1e, 0x1, 0x20, 0x1, +0xb, 0x1, 0xb, 0x1, 0xb, 0x1, 0x0, 0x0, 0x1e, 0x1, 0x24, 0x1, 0xb, 0x1, 0x5, 0x1, 0xc, 0x1, 0xed, 0x0, +0x0, 0x0, 0x25, 0x1, 0x26, 0x1, 0x24, 0x1, 0xd, 0x1, 0xe, 0x1, 0xf, 0x1, 0x0, 0x0, 0x25, 0x1, 0x24, 0x1, +0x1e, 0x1, 0xd, 0x1, 0xf, 0x1, 0x8, 0x1, 0x0, 0x0, 0x23, 0x1, 0x27, 0x1, 0x25, 0x1, 0x10, 0x1, 0x11, 0x1, +0x10, 0x1, 0x0, 0x0, 0x23, 0x1, 0x25, 0x1, 0x1e, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x0, 0x0, 0x27, 0x1, +0x28, 0x1, 0x26, 0x1, 0x12, 0x1, 0x12, 0x1, 0x12, 0x1, 0x0, 0x0, 0x27, 0x1, 0x26, 0x1, 0x25, 0x1, 0x12, 0x1, +0x12, 0x1, 0x12, 0x1, 0x0, 0x0, 0x28, 0x1, 0x29, 0x1, 0x24, 0x1, 0x13, 0x1, 0x13, 0x1, 0x13, 0x1, 0x0, 0x0, +0x28, 0x1, 0x24, 0x1, 0x26, 0x1, 0x13, 0x1, 0x13, 0x1, 0x13, 0x1, 0x0, 0x0, 0x24, 0x1, 0x2a, 0x1, 0xb, 0x1, +0xc, 0x1, 0x14, 0x1, 0xed, 0x0, 0x0, 0x0, 0x2b, 0x1, 0x2c, 0x1, 0x2a, 0x1, 0x15, 0x1, 0x16, 0x1, 0x17, 0x1, +0x0, 0x0, 0x2b, 0x1, 0x2a, 0x1, 0x24, 0x1, 0x15, 0x1, 0x17, 0x1, 0xf, 0x1, 0x0, 0x0, 0x29, 0x1, 0x2d, 0x1, +0x2b, 0x1, 0x18, 0x1, 0x18, 0x1, 0x18, 0x1, 0x0, 0x0, 0x29, 0x1, 0x2b, 0x1, 0x24, 0x1, 0x18, 0x1, 0x18, 0x1, +0x18, 0x1, 0x0, 0x0, 0x2d, 0x1, 0x2e, 0x1, 0x2c, 0x1, 0x19, 0x1, 0x19, 0x1, 0x19, 0x1, 0x0, 0x0, 0x2d, 0x1, +0x2c, 0x1, 0x2b, 0x1, 0x19, 0x1, 0x19, 0x1, 0x19, 0x1, 0x0, 0x0, 0x2e, 0x1, 0x2f, 0x1, 0x2a, 0x1, 0x1a, 0x1, +0x1a, 0x1, 0x1a, 0x1, 0x0, 0x0, 0x2e, 0x1, 0x2a, 0x1, 0x2c, 0x1, 0x1a, 0x1, 0x1a, 0x1, 0x1a, 0x1, 0x0, 0x0, +0x2a, 0x1, 0x30, 0x1, 0xb, 0x1, 0x14, 0x1, 0x1b, 0x1, 0xed, 0x0, 0x0, 0x0, 0x31, 0x1, 0x32, 0x1, 0x30, 0x1, +0x1c, 0x1, 0x1d, 0x1, 0x1e, 0x1, 0x0, 0x0, 0x31, 0x1, 0x30, 0x1, 0x2a, 0x1, 0x1c, 0x1, 0x1e, 0x1, 0x17, 0x1, +0x0, 0x0, 0x2f, 0x1, 0x33, 0x1, 0x31, 0x1, 0x1f, 0x1, 0x20, 0x1, 0x1f, 0x1, 0x0, 0x0, 0x2f, 0x1, 0x31, 0x1, +0x2a, 0x1, 0x1f, 0x1, 0x1f, 0x1, 0x1f, 0x1, 0x0, 0x0, 0x33, 0x1, 0x34, 0x1, 0x32, 0x1, 0x21, 0x1, 0x21, 0x1, +0x21, 0x1, 0x0, 0x0, 0x33, 0x1, 0x32, 0x1, 0x31, 0x1, 0x21, 0x1, 0x21, 0x1, 0x21, 0x1, 0x0, 0x0, 0x34, 0x1, +0x35, 0x1, 0x30, 0x1, 0x22, 0x1, 0x22, 0x1, 0x22, 0x1, 0x0, 0x0, 0x34, 0x1, 0x30, 0x1, 0x32, 0x1, 0x22, 0x1, +0x22, 0x1, 0x22, 0x1, 0x0, 0x0, 0x30, 0x1, 0x36, 0x1, 0xb, 0x1, 0x1b, 0x1, 0x23, 0x1, 0xed, 0x0, 0x0, 0x0, +0x37, 0x1, 0x38, 0x1, 0x36, 0x1, 0x24, 0x1, 0x25, 0x1, 0x26, 0x1, 0x0, 0x0, 0x37, 0x1, 0x36, 0x1, 0x30, 0x1, +0x24, 0x1, 0x26, 0x1, 0x1e, 0x1, 0x0, 0x0, 0x35, 0x1, 0x39, 0x1, 0x37, 0x1, 0x27, 0x1, 0x27, 0x1, 0x27, 0x1, +0x0, 0x0, 0x35, 0x1, 0x37, 0x1, 0x30, 0x1, 0x27, 0x1, 0x27, 0x1, 0x27, 0x1, 0x0, 0x0, 0x39, 0x1, 0x3a, 0x1, +0x38, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x0, 0x0, 0x39, 0x1, 0x38, 0x1, 0x37, 0x1, 0x28, 0x1, 0x28, 0x1, +0x28, 0x1, 0x0, 0x0, 0x3a, 0x1, 0x3b, 0x1, 0x36, 0x1, 0x29, 0x1, 0x29, 0x1, 0x29, 0x1, 0x0, 0x0, 0x3a, 0x1, +0x36, 0x1, 0x38, 0x1, 0x29, 0x1, 0x29, 0x1, 0x2a, 0x1, 0x0, 0x0, 0x36, 0x1, 0x3c, 0x1, 0xb, 0x1, 0x23, 0x1, +0x2b, 0x1, 0xed, 0x0, 0x0, 0x0, 0x3d, 0x1, 0x3e, 0x1, 0x3c, 0x1, 0x2c, 0x1, 0x2d, 0x1, 0x2e, 0x1, 0x0, 0x0, +0x3d, 0x1, 0x3c, 0x1, 0x36, 0x1, 0x2c, 0x1, 0x2e, 0x1, 0x26, 0x1, 0x0, 0x0, 0x3b, 0x1, 0x3f, 0x1, 0x3d, 0x1, +0x2f, 0x1, 0x2f, 0x1, 0x2f, 0x1, 0x0, 0x0, 0x3b, 0x1, 0x3d, 0x1, 0x36, 0x1, 0x2f, 0x1, 0x2f, 0x1, 0x2f, 0x1, +0x0, 0x0, 0x3f, 0x1, 0x40, 0x1, 0x3e, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x0, 0x0, 0x3f, 0x1, 0x3e, 0x1, +0x3d, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x0, 0x0, 0x40, 0x1, 0x41, 0x1, 0x3c, 0x1, 0x31, 0x1, 0x31, 0x1, +0x31, 0x1, 0x0, 0x0, 0x40, 0x1, 0x3c, 0x1, 0x3e, 0x1, 0x31, 0x1, 0x31, 0x1, 0x31, 0x1, 0x0, 0x0, 0x3c, 0x1, +0x9, 0x1, 0xb, 0x1, 0x2b, 0x1, 0xeb, 0x0, 0xed, 0x0, 0x0, 0x0, 0x42, 0x1, 0x43, 0x1, 0x9, 0x1, 0x32, 0x1, +0x33, 0x1, 0xf1, 0x0, 0x0, 0x0, 0x42, 0x1, 0x9, 0x1, 0x3c, 0x1, 0x32, 0x1, 0xf1, 0x0, 0x2e, 0x1, 0x0, 0x0, +0x41, 0x1, 0x44, 0x1, 0x42, 0x1, 0x34, 0x1, 0x35, 0x1, 0x34, 0x1, 0x0, 0x0, 0x41, 0x1, 0x42, 0x1, 0x3c, 0x1, +0x34, 0x1, 0x34, 0x1, 0x34, 0x1, 0x0, 0x0, 0x44, 0x1, 0x45, 0x1, 0x43, 0x1, 0x36, 0x1, 0x36, 0x1, 0x36, 0x1, +0x0, 0x0, 0x44, 0x1, 0x43, 0x1, 0x42, 0x1, 0x36, 0x1, 0x36, 0x1, 0x36, 0x1, 0x0, 0x0, 0x45, 0x1, 0xe, 0x1, +0x9, 0x1, 0x37, 0x1, 0x37, 0x1, 0x37, 0x1, 0x0, 0x0, 0x45, 0x1, 0x9, 0x1, 0x43, 0x1, 0x37, 0x1, 0x37, 0x1, +0x37, 0x1, 0x0, 0x0, 0x83, 0x1, 0x84, 0x1, 0x85, 0x1, 0x38, 0x1, 0x39, 0x1, 0x3a, 0x1, 0x0, 0x0, 0x86, 0x1, +0x87, 0x1, 0x84, 0x1, 0x3b, 0x1, 0x3c, 0x1, 0x3d, 0x1, 0x0, 0x0, 0x86, 0x1, 0x84, 0x1, 0x83, 0x1, 0x3b, 0x1, +0x3d, 0x1, 0x3e, 0x1, 0x0, 0x0, 0x88, 0x1, 0x89, 0x1, 0x86, 0x1, 0x3f, 0x1, 0x3f, 0x1, 0x3f, 0x1, 0x0, 0x0, +0x88, 0x1, 0x86, 0x1, 0x83, 0x1, 0x3f, 0x1, 0x3f, 0x1, 0x3f, 0x1, 0x0, 0x0, 0x89, 0x1, 0x8a, 0x1, 0x87, 0x1, +0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x0, 0x0, 0x89, 0x1, 0x87, 0x1, 0x86, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, +0x0, 0x0, 0x8a, 0x1, 0x8b, 0x1, 0x84, 0x1, 0x41, 0x1, 0x41, 0x1, 0x41, 0x1, 0x0, 0x0, 0x8a, 0x1, 0x84, 0x1, +0x87, 0x1, 0x41, 0x1, 0x41, 0x1, 0x41, 0x1, 0x0, 0x0, 0x84, 0x1, 0x8c, 0x1, 0x85, 0x1, 0x39, 0x1, 0x42, 0x1, +0x3a, 0x1, 0x0, 0x0, 0x8d, 0x1, 0x8e, 0x1, 0x8c, 0x1, 0x43, 0x1, 0x44, 0x1, 0x45, 0x1, 0x0, 0x0, 0x8d, 0x1, +0x8c, 0x1, 0x84, 0x1, 0x43, 0x1, 0x45, 0x1, 0x3d, 0x1, 0x0, 0x0, 0x8b, 0x1, 0x8f, 0x1, 0x8d, 0x1, 0x46, 0x1, +0x47, 0x1, 0x46, 0x1, 0x0, 0x0, 0x8b, 0x1, 0x8d, 0x1, 0x84, 0x1, 0x46, 0x1, 0x46, 0x1, 0x46, 0x1, 0x0, 0x0, +0x8f, 0x1, 0x90, 0x1, 0x8e, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x0, 0x0, 0x8f, 0x1, 0x8e, 0x1, 0x8d, 0x1, +0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x0, 0x0, 0x90, 0x1, 0x91, 0x1, 0x8c, 0x1, 0x49, 0x1, 0x49, 0x1, 0x49, 0x1, +0x0, 0x0, 0x90, 0x1, 0x8c, 0x1, 0x8e, 0x1, 0x49, 0x1, 0x49, 0x1, 0x49, 0x1, 0x0, 0x0, 0x8c, 0x1, 0x92, 0x1, +0x85, 0x1, 0x42, 0x1, 0x4a, 0x1, 0x3a, 0x1, 0x0, 0x0, 0x93, 0x1, 0x94, 0x1, 0x92, 0x1, 0x4b, 0x1, 0x4c, 0x1, +0x4d, 0x1, 0x0, 0x0, 0x93, 0x1, 0x92, 0x1, 0x8c, 0x1, 0x4b, 0x1, 0x4d, 0x1, 0x45, 0x1, 0x0, 0x0, 0x91, 0x1, +0x95, 0x1, 0x93, 0x1, 0x4e, 0x1, 0x4e, 0x1, 0x4e, 0x1, 0x0, 0x0, 0x91, 0x1, 0x93, 0x1, 0x8c, 0x1, 0x4e, 0x1, +0x4e, 0x1, 0x4e, 0x1, 0x0, 0x0, 0x95, 0x1, 0x96, 0x1, 0x94, 0x1, 0x4f, 0x1, 0x4f, 0x1, 0x4f, 0x1, 0x0, 0x0, +0x95, 0x1, 0x94, 0x1, 0x93, 0x1, 0x4f, 0x1, 0x4f, 0x1, 0x4f, 0x1, 0x0, 0x0, 0x96, 0x1, 0x97, 0x1, 0x92, 0x1, +0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x0, 0x0, 0x96, 0x1, 0x92, 0x1, 0x94, 0x1, 0x50, 0x1, 0x50, 0x1, 0x51, 0x1, +0x0, 0x0, 0x92, 0x1, 0x98, 0x1, 0x85, 0x1, 0x4a, 0x1, 0x52, 0x1, 0x3a, 0x1, 0x0, 0x0, 0x99, 0x1, 0x9a, 0x1, +0x98, 0x1, 0x53, 0x1, 0x54, 0x1, 0x55, 0x1, 0x0, 0x0, 0x99, 0x1, 0x98, 0x1, 0x92, 0x1, 0x53, 0x1, 0x55, 0x1, +0x4d, 0x1, 0x0, 0x0, 0x97, 0x1, 0x9b, 0x1, 0x99, 0x1, 0x56, 0x1, 0x56, 0x1, 0x56, 0x1, 0x0, 0x0, 0x97, 0x1, +0x99, 0x1, 0x92, 0x1, 0x56, 0x1, 0x56, 0x1, 0x56, 0x1, 0x0, 0x0, 0x9b, 0x1, 0x9c, 0x1, 0x9a, 0x1, 0x57, 0x1, +0x57, 0x1, 0x57, 0x1, 0x0, 0x0, 0x9b, 0x1, 0x9a, 0x1, 0x99, 0x1, 0x57, 0x1, 0x57, 0x1, 0x57, 0x1, 0x0, 0x0, +0x9c, 0x1, 0x9d, 0x1, 0x98, 0x1, 0x58, 0x1, 0x58, 0x1, 0x58, 0x1, 0x0, 0x0, 0x9c, 0x1, 0x98, 0x1, 0x9a, 0x1, +0x58, 0x1, 0x58, 0x1, 0x58, 0x1, 0x0, 0x0, 0x98, 0x1, 0x9e, 0x1, 0x85, 0x1, 0x52, 0x1, 0x59, 0x1, 0x3a, 0x1, +0x0, 0x0, 0x9f, 0x1, 0xa0, 0x1, 0x9e, 0x1, 0x5a, 0x1, 0x5b, 0x1, 0x5c, 0x1, 0x0, 0x0, 0x9f, 0x1, 0x9e, 0x1, +0x98, 0x1, 0x5a, 0x1, 0x5c, 0x1, 0x55, 0x1, 0x0, 0x0, 0x9d, 0x1, 0xa1, 0x1, 0x9f, 0x1, 0x5d, 0x1, 0x5d, 0x1, +0x5d, 0x1, 0x0, 0x0, 0x9d, 0x1, 0x9f, 0x1, 0x98, 0x1, 0x5d, 0x1, 0x5d, 0x1, 0x5d, 0x1, 0x0, 0x0, 0xa1, 0x1, +0xa2, 0x1, 0xa0, 0x1, 0x5e, 0x1, 0x5e, 0x1, 0x5e, 0x1, 0x0, 0x0, 0xa1, 0x1, 0xa0, 0x1, 0x9f, 0x1, 0x5e, 0x1, +0x5e, 0x1, 0x5e, 0x1, 0x0, 0x0, 0xa2, 0x1, 0xa3, 0x1, 0x9e, 0x1, 0x5f, 0x1, 0x5f, 0x1, 0x5f, 0x1, 0x0, 0x0, +0xa2, 0x1, 0x9e, 0x1, 0xa0, 0x1, 0x5f, 0x1, 0x5f, 0x1, 0x5f, 0x1, 0x0, 0x0, 0x9e, 0x1, 0xa4, 0x1, 0x85, 0x1, +0x59, 0x1, 0x60, 0x1, 0x3a, 0x1, 0x0, 0x0, 0xa5, 0x1, 0xa6, 0x1, 0xa4, 0x1, 0x61, 0x1, 0x62, 0x1, 0x63, 0x1, +0x0, 0x0, 0xa5, 0x1, 0xa4, 0x1, 0x9e, 0x1, 0x61, 0x1, 0x63, 0x1, 0x5c, 0x1, 0x0, 0x0, 0xa3, 0x1, 0xa7, 0x1, +0xa5, 0x1, 0x64, 0x1, 0x64, 0x1, 0x64, 0x1, 0x0, 0x0, 0xa3, 0x1, 0xa5, 0x1, 0x9e, 0x1, 0x64, 0x1, 0x64, 0x1, +0x64, 0x1, 0x0, 0x0, 0xa7, 0x1, 0xa8, 0x1, 0xa6, 0x1, 0x65, 0x1, 0x65, 0x1, 0x65, 0x1, 0x0, 0x0, 0xa7, 0x1, +0xa6, 0x1, 0xa5, 0x1, 0x65, 0x1, 0x65, 0x1, 0x65, 0x1, 0x0, 0x0, 0xa8, 0x1, 0xa9, 0x1, 0xa4, 0x1, 0x66, 0x1, +0x66, 0x1, 0x66, 0x1, 0x0, 0x0, 0xa8, 0x1, 0xa4, 0x1, 0xa6, 0x1, 0x66, 0x1, 0x66, 0x1, 0x66, 0x1, 0x0, 0x0, +0xa4, 0x1, 0xaa, 0x1, 0x85, 0x1, 0x60, 0x1, 0x67, 0x1, 0x3a, 0x1, 0x0, 0x0, 0xab, 0x1, 0xac, 0x1, 0xaa, 0x1, +0x68, 0x1, 0x69, 0x1, 0x6a, 0x1, 0x0, 0x0, 0xab, 0x1, 0xaa, 0x1, 0xa4, 0x1, 0x68, 0x1, 0x6a, 0x1, 0x63, 0x1, +0x0, 0x0, 0xa9, 0x1, 0xad, 0x1, 0xab, 0x1, 0x6b, 0x1, 0x6c, 0x1, 0x6b, 0x1, 0x0, 0x0, 0xa9, 0x1, 0xab, 0x1, +0xa4, 0x1, 0x6b, 0x1, 0x6b, 0x1, 0x6b, 0x1, 0x0, 0x0, 0xad, 0x1, 0xae, 0x1, 0xac, 0x1, 0x6d, 0x1, 0x6d, 0x1, +0x6d, 0x1, 0x0, 0x0, 0xad, 0x1, 0xac, 0x1, 0xab, 0x1, 0x6d, 0x1, 0x6d, 0x1, 0x6d, 0x1, 0x0, 0x0, 0xae, 0x1, +0xaf, 0x1, 0xaa, 0x1, 0x6e, 0x1, 0x6e, 0x1, 0x6e, 0x1, 0x0, 0x0, 0xae, 0x1, 0xaa, 0x1, 0xac, 0x1, 0x6e, 0x1, +0x6e, 0x1, 0x6e, 0x1, 0x0, 0x0, 0xaa, 0x1, 0xb0, 0x1, 0x85, 0x1, 0x67, 0x1, 0x6f, 0x1, 0x3a, 0x1, 0x0, 0x0, +0xb1, 0x1, 0xb2, 0x1, 0xb0, 0x1, 0x70, 0x1, 0x71, 0x1, 0x72, 0x1, 0x0, 0x0, 0xb1, 0x1, 0xb0, 0x1, 0xaa, 0x1, +0x70, 0x1, 0x72, 0x1, 0x6a, 0x1, 0x0, 0x0, 0xaf, 0x1, 0xb3, 0x1, 0xb1, 0x1, 0x73, 0x1, 0x73, 0x1, 0x73, 0x1, +0x0, 0x0, 0xaf, 0x1, 0xb1, 0x1, 0xaa, 0x1, 0x73, 0x1, 0x73, 0x1, 0x73, 0x1, 0x0, 0x0, 0xb3, 0x1, 0xb4, 0x1, +0xb2, 0x1, 0x74, 0x1, 0x74, 0x1, 0x74, 0x1, 0x0, 0x0, 0xb3, 0x1, 0xb2, 0x1, 0xb1, 0x1, 0x74, 0x1, 0x74, 0x1, +0x74, 0x1, 0x0, 0x0, 0xb4, 0x1, 0xb5, 0x1, 0xb0, 0x1, 0x75, 0x1, 0x75, 0x1, 0x75, 0x1, 0x0, 0x0, 0xb4, 0x1, +0xb0, 0x1, 0xb2, 0x1, 0x75, 0x1, 0x75, 0x1, 0x76, 0x1, 0x0, 0x0, 0xb0, 0x1, 0xb6, 0x1, 0x85, 0x1, 0x6f, 0x1, +0x77, 0x1, 0x3a, 0x1, 0x0, 0x0, 0xb7, 0x1, 0xb8, 0x1, 0xb6, 0x1, 0x78, 0x1, 0x79, 0x1, 0x7a, 0x1, 0x0, 0x0, +0xb7, 0x1, 0xb6, 0x1, 0xb0, 0x1, 0x78, 0x1, 0x7a, 0x1, 0x72, 0x1, 0x0, 0x0, 0xb5, 0x1, 0xb9, 0x1, 0xb7, 0x1, +0x7b, 0x1, 0x7b, 0x1, 0x7b, 0x1, 0x0, 0x0, 0xb5, 0x1, 0xb7, 0x1, 0xb0, 0x1, 0x7b, 0x1, 0x7b, 0x1, 0x7b, 0x1, +0x0, 0x0, 0xb9, 0x1, 0xba, 0x1, 0xb8, 0x1, 0x7c, 0x1, 0x7c, 0x1, 0x7c, 0x1, 0x0, 0x0, 0xb9, 0x1, 0xb8, 0x1, +0xb7, 0x1, 0x7c, 0x1, 0x7c, 0x1, 0x7c, 0x1, 0x0, 0x0, 0xba, 0x1, 0xbb, 0x1, 0xb6, 0x1, 0x7d, 0x1, 0x7d, 0x1, +0x7d, 0x1, 0x0, 0x0, 0xba, 0x1, 0xb6, 0x1, 0xb8, 0x1, 0x7d, 0x1, 0x7d, 0x1, 0x7d, 0x1, 0x0, 0x0, 0xb6, 0x1, +0x83, 0x1, 0x85, 0x1, 0x77, 0x1, 0x38, 0x1, 0x3a, 0x1, 0x0, 0x0, 0xbc, 0x1, 0xbd, 0x1, 0x83, 0x1, 0x7e, 0x1, +0x7f, 0x1, 0x3e, 0x1, 0x0, 0x0, 0xbc, 0x1, 0x83, 0x1, 0xb6, 0x1, 0x7e, 0x1, 0x3e, 0x1, 0x7a, 0x1, 0x0, 0x0, +0xbb, 0x1, 0xbe, 0x1, 0xbc, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x0, 0x0, 0xbb, 0x1, 0xbc, 0x1, 0xb6, 0x1, +0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x0, 0x0, 0xbe, 0x1, 0xbf, 0x1, 0xbd, 0x1, 0x81, 0x1, 0x81, 0x1, 0x81, 0x1, +0x0, 0x0, 0xbe, 0x1, 0xbd, 0x1, 0xbc, 0x1, 0x81, 0x1, 0x81, 0x1, 0x81, 0x1, 0x0, 0x0, 0xbf, 0x1, 0x88, 0x1, +0x83, 0x1, 0x82, 0x1, 0x82, 0x1, 0x82, 0x1, 0x0, 0x0, 0xbf, 0x1, 0x83, 0x1, 0xbd, 0x1, 0x82, 0x1, 0x82, 0x1, +0x82, 0x1, 0x0, 0x0, 0x46, 0x1, 0x47, 0x1, 0x48, 0x1, 0x83, 0x1, 0x84, 0x1, 0x85, 0x1, 0x0, 0x0, 0x49, 0x1, +0x4a, 0x1, 0x47, 0x1, 0x86, 0x1, 0x87, 0x1, 0x88, 0x1, 0x0, 0x0, 0x49, 0x1, 0x47, 0x1, 0x46, 0x1, 0x86, 0x1, +0x88, 0x1, 0x89, 0x1, 0x0, 0x0, 0x4b, 0x1, 0x4c, 0x1, 0x49, 0x1, 0x8a, 0x1, 0x8a, 0x1, 0x8a, 0x1, 0x0, 0x0, +0x4b, 0x1, 0x49, 0x1, 0x46, 0x1, 0x8a, 0x1, 0x8a, 0x1, 0x8a, 0x1, 0x0, 0x0, 0x4c, 0x1, 0x4d, 0x1, 0x4a, 0x1, +0x8b, 0x1, 0x8b, 0x1, 0x8b, 0x1, 0x0, 0x0, 0x4c, 0x1, 0x4a, 0x1, 0x49, 0x1, 0x8b, 0x1, 0x8b, 0x1, 0x8b, 0x1, +0x0, 0x0, 0x4d, 0x1, 0x4e, 0x1, 0x47, 0x1, 0x8c, 0x1, 0x8c, 0x1, 0x8c, 0x1, 0x0, 0x0, 0x4d, 0x1, 0x47, 0x1, +0x4a, 0x1, 0x8c, 0x1, 0x8c, 0x1, 0x8c, 0x1, 0x0, 0x0, 0x47, 0x1, 0x4f, 0x1, 0x48, 0x1, 0x84, 0x1, 0x8d, 0x1, +0x85, 0x1, 0x0, 0x0, 0x50, 0x1, 0x51, 0x1, 0x4f, 0x1, 0x8e, 0x1, 0x8f, 0x1, 0x90, 0x1, 0x0, 0x0, 0x50, 0x1, +0x4f, 0x1, 0x47, 0x1, 0x8e, 0x1, 0x90, 0x1, 0x88, 0x1, 0x0, 0x0, 0x4e, 0x1, 0x52, 0x1, 0x50, 0x1, 0x91, 0x1, +0x91, 0x1, 0x91, 0x1, 0x0, 0x0, 0x4e, 0x1, 0x50, 0x1, 0x47, 0x1, 0x91, 0x1, 0x91, 0x1, 0x91, 0x1, 0x0, 0x0, +0x52, 0x1, 0x53, 0x1, 0x51, 0x1, 0x92, 0x1, 0x92, 0x1, 0x92, 0x1, 0x0, 0x0, 0x52, 0x1, 0x51, 0x1, 0x50, 0x1, +0x92, 0x1, 0x92, 0x1, 0x92, 0x1, 0x0, 0x0, 0x53, 0x1, 0x54, 0x1, 0x4f, 0x1, 0x93, 0x1, 0x93, 0x1, 0x93, 0x1, +0x0, 0x0, 0x53, 0x1, 0x4f, 0x1, 0x51, 0x1, 0x93, 0x1, 0x93, 0x1, 0x93, 0x1, 0x0, 0x0, 0x4f, 0x1, 0x55, 0x1, +0x48, 0x1, 0x8d, 0x1, 0x94, 0x1, 0x85, 0x1, 0x0, 0x0, 0x56, 0x1, 0x57, 0x1, 0x55, 0x1, 0x95, 0x1, 0x96, 0x1, +0x97, 0x1, 0x0, 0x0, 0x56, 0x1, 0x55, 0x1, 0x4f, 0x1, 0x95, 0x1, 0x97, 0x1, 0x90, 0x1, 0x0, 0x0, 0x54, 0x1, +0x58, 0x1, 0x56, 0x1, 0x98, 0x1, 0x99, 0x1, 0x98, 0x1, 0x0, 0x0, 0x54, 0x1, 0x56, 0x1, 0x4f, 0x1, 0x98, 0x1, +0x98, 0x1, 0x98, 0x1, 0x0, 0x0, 0x58, 0x1, 0x59, 0x1, 0x57, 0x1, 0x9a, 0x1, 0x9a, 0x1, 0x9a, 0x1, 0x0, 0x0, +0x58, 0x1, 0x57, 0x1, 0x56, 0x1, 0x9a, 0x1, 0x9a, 0x1, 0x9a, 0x1, 0x0, 0x0, 0x59, 0x1, 0x5a, 0x1, 0x55, 0x1, +0x9b, 0x1, 0x9b, 0x1, 0x9b, 0x1, 0x0, 0x0, 0x59, 0x1, 0x55, 0x1, 0x57, 0x1, 0x9b, 0x1, 0x9b, 0x1, 0x9b, 0x1, +0x0, 0x0, 0x55, 0x1, 0x5b, 0x1, 0x48, 0x1, 0x94, 0x1, 0x9c, 0x1, 0x85, 0x1, 0x0, 0x0, 0x5c, 0x1, 0x5d, 0x1, +0x5b, 0x1, 0x9d, 0x1, 0x9e, 0x1, 0x9f, 0x1, 0x0, 0x0, 0x5c, 0x1, 0x5b, 0x1, 0x55, 0x1, 0x9d, 0x1, 0x9f, 0x1, +0x97, 0x1, 0x0, 0x0, 0x5a, 0x1, 0x5e, 0x1, 0x5c, 0x1, 0xa0, 0x1, 0xa0, 0x1, 0xa0, 0x1, 0x0, 0x0, 0x5a, 0x1, +0x5c, 0x1, 0x55, 0x1, 0xa0, 0x1, 0xa0, 0x1, 0xa0, 0x1, 0x0, 0x0, 0x5e, 0x1, 0x5f, 0x1, 0x5d, 0x1, 0xa1, 0x1, +0xa1, 0x1, 0xa1, 0x1, 0x0, 0x0, 0x5e, 0x1, 0x5d, 0x1, 0x5c, 0x1, 0xa1, 0x1, 0xa1, 0x1, 0xa1, 0x1, 0x0, 0x0, +0x5f, 0x1, 0x60, 0x1, 0x5b, 0x1, 0xa2, 0x1, 0xa2, 0x1, 0xa2, 0x1, 0x0, 0x0, 0x5f, 0x1, 0x5b, 0x1, 0x5d, 0x1, +0xa2, 0x1, 0xa2, 0x1, 0xa3, 0x1, 0x0, 0x0, 0x5b, 0x1, 0x61, 0x1, 0x48, 0x1, 0x9c, 0x1, 0xa4, 0x1, 0x85, 0x1, +0x0, 0x0, 0x62, 0x1, 0x63, 0x1, 0x61, 0x1, 0xa5, 0x1, 0xa6, 0x1, 0xa7, 0x1, 0x0, 0x0, 0x62, 0x1, 0x61, 0x1, +0x5b, 0x1, 0xa5, 0x1, 0xa7, 0x1, 0x9f, 0x1, 0x0, 0x0, 0x60, 0x1, 0x64, 0x1, 0x62, 0x1, 0xa8, 0x1, 0xa8, 0x1, +0xa8, 0x1, 0x0, 0x0, 0x60, 0x1, 0x62, 0x1, 0x5b, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0x0, 0x0, 0x64, 0x1, +0x65, 0x1, 0x63, 0x1, 0xa9, 0x1, 0xa9, 0x1, 0xa9, 0x1, 0x0, 0x0, 0x64, 0x1, 0x63, 0x1, 0x62, 0x1, 0xa9, 0x1, +0xa9, 0x1, 0xa9, 0x1, 0x0, 0x0, 0x65, 0x1, 0x66, 0x1, 0x61, 0x1, 0xaa, 0x1, 0xaa, 0x1, 0xaa, 0x1, 0x0, 0x0, +0x65, 0x1, 0x61, 0x1, 0x63, 0x1, 0xaa, 0x1, 0xaa, 0x1, 0xaa, 0x1, 0x0, 0x0, 0x61, 0x1, 0x67, 0x1, 0x48, 0x1, +0xa4, 0x1, 0xab, 0x1, 0x85, 0x1, 0x0, 0x0, 0x68, 0x1, 0x69, 0x1, 0x67, 0x1, 0xac, 0x1, 0xad, 0x1, 0xae, 0x1, +0x0, 0x0, 0x68, 0x1, 0x67, 0x1, 0x61, 0x1, 0xac, 0x1, 0xae, 0x1, 0xa7, 0x1, 0x0, 0x0, 0x66, 0x1, 0x6a, 0x1, +0x68, 0x1, 0xaf, 0x1, 0xaf, 0x1, 0xaf, 0x1, 0x0, 0x0, 0x66, 0x1, 0x68, 0x1, 0x61, 0x1, 0xaf, 0x1, 0xaf, 0x1, +0xaf, 0x1, 0x0, 0x0, 0x6a, 0x1, 0x6b, 0x1, 0x69, 0x1, 0xb0, 0x1, 0xb0, 0x1, 0xb0, 0x1, 0x0, 0x0, 0x6a, 0x1, +0x69, 0x1, 0x68, 0x1, 0xb0, 0x1, 0xb0, 0x1, 0xb0, 0x1, 0x0, 0x0, 0x6b, 0x1, 0x6c, 0x1, 0x67, 0x1, 0xb1, 0x1, +0xb1, 0x1, 0xb1, 0x1, 0x0, 0x0, 0x6b, 0x1, 0x67, 0x1, 0x69, 0x1, 0xb1, 0x1, 0xb1, 0x1, 0xb1, 0x1, 0x0, 0x0, +0x67, 0x1, 0x6d, 0x1, 0x48, 0x1, 0xab, 0x1, 0xb2, 0x1, 0x85, 0x1, 0x0, 0x0, 0x6e, 0x1, 0x6f, 0x1, 0x6d, 0x1, +0xb3, 0x1, 0xb4, 0x1, 0xb5, 0x1, 0x0, 0x0, 0x6e, 0x1, 0x6d, 0x1, 0x67, 0x1, 0xb3, 0x1, 0xb5, 0x1, 0xae, 0x1, +0x0, 0x0, 0x6c, 0x1, 0x70, 0x1, 0x6e, 0x1, 0xb6, 0x1, 0xb6, 0x1, 0xb6, 0x1, 0x0, 0x0, 0x6c, 0x1, 0x6e, 0x1, +0x67, 0x1, 0xb6, 0x1, 0xb6, 0x1, 0xb6, 0x1, 0x0, 0x0, 0x70, 0x1, 0x71, 0x1, 0x6f, 0x1, 0xb7, 0x1, 0xb7, 0x1, +0xb7, 0x1, 0x0, 0x0, 0x70, 0x1, 0x6f, 0x1, 0x6e, 0x1, 0xb7, 0x1, 0xb7, 0x1, 0xb7, 0x1, 0x0, 0x0, 0x71, 0x1, +0x72, 0x1, 0x6d, 0x1, 0xb8, 0x1, 0xb8, 0x1, 0xb8, 0x1, 0x0, 0x0, 0x71, 0x1, 0x6d, 0x1, 0x6f, 0x1, 0xb8, 0x1, +0xb8, 0x1, 0xb8, 0x1, 0x0, 0x0, 0x6d, 0x1, 0x73, 0x1, 0x48, 0x1, 0xb2, 0x1, 0xb9, 0x1, 0x85, 0x1, 0x0, 0x0, +0x74, 0x1, 0x75, 0x1, 0x73, 0x1, 0xba, 0x1, 0xbb, 0x1, 0xbc, 0x1, 0x0, 0x0, 0x74, 0x1, 0x73, 0x1, 0x6d, 0x1, +0xba, 0x1, 0xbc, 0x1, 0xb5, 0x1, 0x0, 0x0, 0x72, 0x1, 0x76, 0x1, 0x74, 0x1, 0xbd, 0x1, 0xbe, 0x1, 0xbd, 0x1, +0x0, 0x0, 0x72, 0x1, 0x74, 0x1, 0x6d, 0x1, 0xbd, 0x1, 0xbd, 0x1, 0xbd, 0x1, 0x0, 0x0, 0x76, 0x1, 0x77, 0x1, +0x75, 0x1, 0xbf, 0x1, 0xbf, 0x1, 0xbf, 0x1, 0x0, 0x0, 0x76, 0x1, 0x75, 0x1, 0x74, 0x1, 0xbf, 0x1, 0xbf, 0x1, +0xbf, 0x1, 0x0, 0x0, 0x77, 0x1, 0x78, 0x1, 0x73, 0x1, 0xc0, 0x1, 0xc0, 0x1, 0xc0, 0x1, 0x0, 0x0, 0x77, 0x1, +0x73, 0x1, 0x75, 0x1, 0xc0, 0x1, 0xc0, 0x1, 0xc0, 0x1, 0x0, 0x0, 0x73, 0x1, 0x79, 0x1, 0x48, 0x1, 0xb9, 0x1, +0xc1, 0x1, 0x85, 0x1, 0x0, 0x0, 0x7a, 0x1, 0x7b, 0x1, 0x79, 0x1, 0xc2, 0x1, 0xc3, 0x1, 0xc4, 0x1, 0x0, 0x0, +0x7a, 0x1, 0x79, 0x1, 0x73, 0x1, 0xc2, 0x1, 0xc4, 0x1, 0xbc, 0x1, 0x0, 0x0, 0x78, 0x1, 0x7c, 0x1, 0x7a, 0x1, +0xc5, 0x1, 0xc5, 0x1, 0xc5, 0x1, 0x0, 0x0, 0x78, 0x1, 0x7a, 0x1, 0x73, 0x1, 0xc5, 0x1, 0xc5, 0x1, 0xc5, 0x1, +0x0, 0x0, 0x7c, 0x1, 0x7d, 0x1, 0x7b, 0x1, 0xc6, 0x1, 0xc6, 0x1, 0xc6, 0x1, 0x0, 0x0, 0x7c, 0x1, 0x7b, 0x1, +0x7a, 0x1, 0xc6, 0x1, 0xc6, 0x1, 0xc6, 0x1, 0x0, 0x0, 0x7d, 0x1, 0x7e, 0x1, 0x79, 0x1, 0xc7, 0x1, 0xc7, 0x1, +0xc7, 0x1, 0x0, 0x0, 0x7d, 0x1, 0x79, 0x1, 0x7b, 0x1, 0xc7, 0x1, 0xc7, 0x1, 0xc8, 0x1, 0x0, 0x0, 0x79, 0x1, +0x46, 0x1, 0x48, 0x1, 0xc1, 0x1, 0x83, 0x1, 0x85, 0x1, 0x0, 0x0, 0x7f, 0x1, 0x80, 0x1, 0x46, 0x1, 0xc9, 0x1, +0xca, 0x1, 0x89, 0x1, 0x0, 0x0, 0x7f, 0x1, 0x46, 0x1, 0x79, 0x1, 0xc9, 0x1, 0x89, 0x1, 0xc4, 0x1, 0x0, 0x0, +0x7e, 0x1, 0x81, 0x1, 0x7f, 0x1, 0xcb, 0x1, 0xcb, 0x1, 0xcb, 0x1, 0x0, 0x0, 0x7e, 0x1, 0x7f, 0x1, 0x79, 0x1, +0xcb, 0x1, 0xcb, 0x1, 0xcb, 0x1, 0x0, 0x0, 0x81, 0x1, 0x82, 0x1, 0x80, 0x1, 0xcc, 0x1, 0xcc, 0x1, 0xcc, 0x1, +0x0, 0x0, 0x81, 0x1, 0x80, 0x1, 0x7f, 0x1, 0xcc, 0x1, 0xcc, 0x1, 0xcc, 0x1, 0x0, 0x0, 0x82, 0x1, 0x4b, 0x1, +0x46, 0x1, 0xcd, 0x1, 0xcd, 0x1, 0xcd, 0x1, 0x0, 0x0, 0x82, 0x1, 0x46, 0x1, 0x80, 0x1, 0xcd, 0x1, 0xcd, 0x1, +0xcd, 0x1, 0x0, 0x0, 0xc0, 0x1, 0xc1, 0x1, 0xc2, 0x1, 0xce, 0x1, 0xcf, 0x1, 0xd0, 0x1, 0x0, 0x0, 0xc3, 0x1, +0xc4, 0x1, 0xc1, 0x1, 0xd1, 0x1, 0xd2, 0x1, 0xd3, 0x1, 0x0, 0x0, 0xc3, 0x1, 0xc1, 0x1, 0xc0, 0x1, 0xd1, 0x1, +0xd3, 0x1, 0xd4, 0x1, 0x0, 0x0, 0xc5, 0x1, 0xc6, 0x1, 0xc3, 0x1, 0xd5, 0x1, 0xd5, 0x1, 0xd5, 0x1, 0x0, 0x0, +0xc5, 0x1, 0xc3, 0x1, 0xc0, 0x1, 0xd5, 0x1, 0xd5, 0x1, 0xd5, 0x1, 0x0, 0x0, 0xc6, 0x1, 0xc7, 0x1, 0xc4, 0x1, +0xd6, 0x1, 0xd6, 0x1, 0xd6, 0x1, 0x0, 0x0, 0xc6, 0x1, 0xc4, 0x1, 0xc3, 0x1, 0xd6, 0x1, 0xd6, 0x1, 0xd6, 0x1, +0x0, 0x0, 0xc7, 0x1, 0xc8, 0x1, 0xc1, 0x1, 0xd7, 0x1, 0xd7, 0x1, 0xd7, 0x1, 0x0, 0x0, 0xc7, 0x1, 0xc1, 0x1, +0xc4, 0x1, 0xd7, 0x1, 0xd7, 0x1, 0xd7, 0x1, 0x0, 0x0, 0xc1, 0x1, 0xc9, 0x1, 0xc2, 0x1, 0xcf, 0x1, 0xd8, 0x1, +0xd0, 0x1, 0x0, 0x0, 0xca, 0x1, 0xcb, 0x1, 0xc9, 0x1, 0xd9, 0x1, 0xda, 0x1, 0xdb, 0x1, 0x0, 0x0, 0xca, 0x1, +0xc9, 0x1, 0xc1, 0x1, 0xd9, 0x1, 0xdb, 0x1, 0xd3, 0x1, 0x0, 0x0, 0xc8, 0x1, 0xcc, 0x1, 0xca, 0x1, 0xdc, 0x1, +0xdc, 0x1, 0xdc, 0x1, 0x0, 0x0, 0xc8, 0x1, 0xca, 0x1, 0xc1, 0x1, 0xdc, 0x1, 0xdc, 0x1, 0xdc, 0x1, 0x0, 0x0, +0xcc, 0x1, 0xcd, 0x1, 0xcb, 0x1, 0xdd, 0x1, 0xdd, 0x1, 0xdd, 0x1, 0x0, 0x0, 0xcc, 0x1, 0xcb, 0x1, 0xca, 0x1, +0xdd, 0x1, 0xdd, 0x1, 0xdd, 0x1, 0x0, 0x0, 0xcd, 0x1, 0xce, 0x1, 0xc9, 0x1, 0xde, 0x1, 0xde, 0x1, 0xde, 0x1, +0x0, 0x0, 0xcd, 0x1, 0xc9, 0x1, 0xcb, 0x1, 0xde, 0x1, 0xde, 0x1, 0xde, 0x1, 0x0, 0x0, 0xc9, 0x1, 0xcf, 0x1, +0xc2, 0x1, 0xd8, 0x1, 0xdf, 0x1, 0xd0, 0x1, 0x0, 0x0, 0xd0, 0x1, 0xd1, 0x1, 0xcf, 0x1, 0xe0, 0x1, 0xe1, 0x1, +0xe2, 0x1, 0x0, 0x0, 0xd0, 0x1, 0xcf, 0x1, 0xc9, 0x1, 0xe0, 0x1, 0xe2, 0x1, 0xdb, 0x1, 0x0, 0x0, 0xce, 0x1, +0xd2, 0x1, 0xd0, 0x1, 0xe3, 0x1, 0xe4, 0x1, 0xe3, 0x1, 0x0, 0x0, 0xce, 0x1, 0xd0, 0x1, 0xc9, 0x1, 0xe3, 0x1, +0xe3, 0x1, 0xe3, 0x1, 0x0, 0x0, 0xd2, 0x1, 0xd3, 0x1, 0xd1, 0x1, 0xe5, 0x1, 0xe5, 0x1, 0xe5, 0x1, 0x0, 0x0, +0xd2, 0x1, 0xd1, 0x1, 0xd0, 0x1, 0xe5, 0x1, 0xe5, 0x1, 0xe5, 0x1, 0x0, 0x0, 0xd3, 0x1, 0xd4, 0x1, 0xcf, 0x1, +0xe6, 0x1, 0xe6, 0x1, 0xe6, 0x1, 0x0, 0x0, 0xd3, 0x1, 0xcf, 0x1, 0xd1, 0x1, 0xe6, 0x1, 0xe6, 0x1, 0xe6, 0x1, +0x0, 0x0, 0xcf, 0x1, 0xd5, 0x1, 0xc2, 0x1, 0xdf, 0x1, 0xe7, 0x1, 0xd0, 0x1, 0x0, 0x0, 0xd6, 0x1, 0xd7, 0x1, +0xd5, 0x1, 0xe8, 0x1, 0xe9, 0x1, 0xea, 0x1, 0x0, 0x0, 0xd6, 0x1, 0xd5, 0x1, 0xcf, 0x1, 0xe8, 0x1, 0xea, 0x1, +0xe2, 0x1, 0x0, 0x0, 0xd4, 0x1, 0xd8, 0x1, 0xd6, 0x1, 0xeb, 0x1, 0xeb, 0x1, 0xeb, 0x1, 0x0, 0x0, 0xd4, 0x1, +0xd6, 0x1, 0xcf, 0x1, 0xeb, 0x1, 0xeb, 0x1, 0xeb, 0x1, 0x0, 0x0, 0xd8, 0x1, 0xd9, 0x1, 0xd7, 0x1, 0xec, 0x1, +0xec, 0x1, 0xec, 0x1, 0x0, 0x0, 0xd8, 0x1, 0xd7, 0x1, 0xd6, 0x1, 0xec, 0x1, 0xec, 0x1, 0xec, 0x1, 0x0, 0x0, +0xd9, 0x1, 0xda, 0x1, 0xd5, 0x1, 0xed, 0x1, 0xed, 0x1, 0xed, 0x1, 0x0, 0x0, 0xd9, 0x1, 0xd5, 0x1, 0xd7, 0x1, +0xed, 0x1, 0xed, 0x1, 0xee, 0x1, 0x0, 0x0, 0xd5, 0x1, 0xdb, 0x1, 0xc2, 0x1, 0xe7, 0x1, 0xef, 0x1, 0xd0, 0x1, +0x0, 0x0, 0xdc, 0x1, 0xdd, 0x1, 0xdb, 0x1, 0xf0, 0x1, 0xf1, 0x1, 0xf2, 0x1, 0x0, 0x0, 0xdc, 0x1, 0xdb, 0x1, +0xd5, 0x1, 0xf0, 0x1, 0xf2, 0x1, 0xea, 0x1, 0x0, 0x0, 0xda, 0x1, 0xde, 0x1, 0xdc, 0x1, 0xf3, 0x1, 0xf3, 0x1, +0xf3, 0x1, 0x0, 0x0, 0xda, 0x1, 0xdc, 0x1, 0xd5, 0x1, 0xf3, 0x1, 0xf3, 0x1, 0xf3, 0x1, 0x0, 0x0, 0xde, 0x1, +0xdf, 0x1, 0xdd, 0x1, 0xf4, 0x1, 0xf4, 0x1, 0xf4, 0x1, 0x0, 0x0, 0xde, 0x1, 0xdd, 0x1, 0xdc, 0x1, 0xf4, 0x1, +0xf4, 0x1, 0xf4, 0x1, 0x0, 0x0, 0xdf, 0x1, 0xe0, 0x1, 0xdb, 0x1, 0xf5, 0x1, 0xf5, 0x1, 0xf5, 0x1, 0x0, 0x0, +0xdf, 0x1, 0xdb, 0x1, 0xdd, 0x1, 0xf5, 0x1, 0xf5, 0x1, 0xf5, 0x1, 0x0, 0x0, 0xdb, 0x1, 0xe1, 0x1, 0xc2, 0x1, +0xef, 0x1, 0xf6, 0x1, 0xd0, 0x1, 0x0, 0x0, 0xe2, 0x1, 0xe3, 0x1, 0xe1, 0x1, 0xf7, 0x1, 0xf8, 0x1, 0xf9, 0x1, +0x0, 0x0, 0xe2, 0x1, 0xe1, 0x1, 0xdb, 0x1, 0xf7, 0x1, 0xf9, 0x1, 0xf2, 0x1, 0x0, 0x0, 0xe0, 0x1, 0xe4, 0x1, +0xe2, 0x1, 0xfa, 0x1, 0xfa, 0x1, 0xfa, 0x1, 0x0, 0x0, 0xe0, 0x1, 0xe2, 0x1, 0xdb, 0x1, 0xfa, 0x1, 0xfa, 0x1, +0xfa, 0x1, 0x0, 0x0, 0xe4, 0x1, 0xe5, 0x1, 0xe3, 0x1, 0xfb, 0x1, 0xfb, 0x1, 0xfb, 0x1, 0x0, 0x0, 0xe4, 0x1, +0xe3, 0x1, 0xe2, 0x1, 0xfb, 0x1, 0xfb, 0x1, 0xfb, 0x1, 0x0, 0x0, 0xe5, 0x1, 0xe6, 0x1, 0xe1, 0x1, 0xfc, 0x1, +0xfc, 0x1, 0xfc, 0x1, 0x0, 0x0, 0xe5, 0x1, 0xe1, 0x1, 0xe3, 0x1, 0xfc, 0x1, 0xfc, 0x1, 0xfc, 0x1, 0x0, 0x0, +0xe1, 0x1, 0xe7, 0x1, 0xc2, 0x1, 0xf6, 0x1, 0xfd, 0x1, 0xd0, 0x1, 0x0, 0x0, 0xe8, 0x1, 0xe9, 0x1, 0xe7, 0x1, +0xfe, 0x1, 0xff, 0x1, 0x0, 0x2, 0x0, 0x0, 0xe8, 0x1, 0xe7, 0x1, 0xe1, 0x1, 0xfe, 0x1, 0x0, 0x2, 0xf9, 0x1, +0x0, 0x0, 0xe6, 0x1, 0xea, 0x1, 0xe8, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x0, 0x0, 0xe6, 0x1, 0xe8, 0x1, +0xe1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x0, 0x0, 0xea, 0x1, 0xeb, 0x1, 0xe9, 0x1, 0x2, 0x2, 0x2, 0x2, +0x2, 0x2, 0x0, 0x0, 0xea, 0x1, 0xe9, 0x1, 0xe8, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0xeb, 0x1, +0xec, 0x1, 0xe7, 0x1, 0x3, 0x2, 0x3, 0x2, 0x3, 0x2, 0x0, 0x0, 0xeb, 0x1, 0xe7, 0x1, 0xe9, 0x1, 0x3, 0x2, +0x3, 0x2, 0x3, 0x2, 0x0, 0x0, 0xe7, 0x1, 0xed, 0x1, 0xc2, 0x1, 0xfd, 0x1, 0x4, 0x2, 0xd0, 0x1, 0x0, 0x0, +0xee, 0x1, 0xef, 0x1, 0xed, 0x1, 0x5, 0x2, 0x6, 0x2, 0x7, 0x2, 0x0, 0x0, 0xee, 0x1, 0xed, 0x1, 0xe7, 0x1, +0x5, 0x2, 0x7, 0x2, 0x0, 0x2, 0x0, 0x0, 0xec, 0x1, 0xf0, 0x1, 0xee, 0x1, 0x8, 0x2, 0x9, 0x2, 0x8, 0x2, +0x0, 0x0, 0xec, 0x1, 0xee, 0x1, 0xe7, 0x1, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x0, 0x0, 0xf0, 0x1, 0xf1, 0x1, +0xef, 0x1, 0xa, 0x2, 0xa, 0x2, 0xa, 0x2, 0x0, 0x0, 0xf0, 0x1, 0xef, 0x1, 0xee, 0x1, 0xa, 0x2, 0xa, 0x2, +0xa, 0x2, 0x0, 0x0, 0xf1, 0x1, 0xf2, 0x1, 0xed, 0x1, 0xb, 0x2, 0xb, 0x2, 0xb, 0x2, 0x0, 0x0, 0xf1, 0x1, +0xed, 0x1, 0xef, 0x1, 0xb, 0x2, 0xb, 0x2, 0xb, 0x2, 0x0, 0x0, 0xed, 0x1, 0xf3, 0x1, 0xc2, 0x1, 0x4, 0x2, +0xc, 0x2, 0xd0, 0x1, 0x0, 0x0, 0xf4, 0x1, 0xf5, 0x1, 0xf3, 0x1, 0xd, 0x2, 0xe, 0x2, 0xf, 0x2, 0x0, 0x0, +0xf4, 0x1, 0xf3, 0x1, 0xed, 0x1, 0xd, 0x2, 0xf, 0x2, 0x7, 0x2, 0x0, 0x0, 0xf2, 0x1, 0xf6, 0x1, 0xf4, 0x1, +0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x0, 0x0, 0xf2, 0x1, 0xf4, 0x1, 0xed, 0x1, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, +0x0, 0x0, 0xf6, 0x1, 0xf7, 0x1, 0xf5, 0x1, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x0, 0x0, 0xf6, 0x1, 0xf5, 0x1, +0xf4, 0x1, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x0, 0x0, 0xf7, 0x1, 0xf8, 0x1, 0xf3, 0x1, 0x12, 0x2, 0x12, 0x2, +0x12, 0x2, 0x0, 0x0, 0xf7, 0x1, 0xf3, 0x1, 0xf5, 0x1, 0x12, 0x2, 0x12, 0x2, 0x13, 0x2, 0x0, 0x0, 0xf3, 0x1, +0xc0, 0x1, 0xc2, 0x1, 0xc, 0x2, 0xce, 0x1, 0xd0, 0x1, 0x0, 0x0, 0xf9, 0x1, 0xfa, 0x1, 0xc0, 0x1, 0x14, 0x2, +0x15, 0x2, 0xd4, 0x1, 0x0, 0x0, 0xf9, 0x1, 0xc0, 0x1, 0xf3, 0x1, 0x14, 0x2, 0xd4, 0x1, 0xf, 0x2, 0x0, 0x0, +0xf8, 0x1, 0xfb, 0x1, 0xf9, 0x1, 0x16, 0x2, 0x16, 0x2, 0x16, 0x2, 0x0, 0x0, 0xf8, 0x1, 0xf9, 0x1, 0xf3, 0x1, +0x16, 0x2, 0x16, 0x2, 0x16, 0x2, 0x0, 0x0, 0xfb, 0x1, 0xfc, 0x1, 0xfa, 0x1, 0x17, 0x2, 0x17, 0x2, 0x17, 0x2, +0x0, 0x0, 0xfb, 0x1, 0xfa, 0x1, 0xf9, 0x1, 0x17, 0x2, 0x17, 0x2, 0x17, 0x2, 0x0, 0x0, 0xfc, 0x1, 0xc5, 0x1, +0xc0, 0x1, 0x18, 0x2, 0x18, 0x2, 0x18, 0x2, 0x0, 0x0, 0xfc, 0x1, 0xc0, 0x1, 0xfa, 0x1, 0x18, 0x2, 0x18, 0x2, +0x18, 0x2, 0x0, 0x0, 0xfd, 0x1, 0xfe, 0x1, 0xff, 0x1, 0x19, 0x2, 0x1a, 0x2, 0x1b, 0x2, 0x0, 0x0, 0x0, 0x2, +0x1, 0x2, 0xfe, 0x1, 0x1c, 0x2, 0x1d, 0x2, 0x1e, 0x2, 0x0, 0x0, 0x0, 0x2, 0xfe, 0x1, 0xfd, 0x1, 0x1c, 0x2, +0x1e, 0x2, 0x1f, 0x2, 0x0, 0x0, 0x2, 0x2, 0x3, 0x2, 0x0, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x0, 0x0, +0x2, 0x2, 0x0, 0x2, 0xfd, 0x1, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x0, 0x0, 0x3, 0x2, 0x4, 0x2, 0x1, 0x2, +0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x0, 0x0, 0x3, 0x2, 0x1, 0x2, 0x0, 0x2, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, +0x0, 0x0, 0x4, 0x2, 0x5, 0x2, 0xfe, 0x1, 0x22, 0x2, 0x22, 0x2, 0x22, 0x2, 0x0, 0x0, 0x4, 0x2, 0xfe, 0x1, +0x1, 0x2, 0x22, 0x2, 0x22, 0x2, 0x22, 0x2, 0x0, 0x0, 0xfe, 0x1, 0x6, 0x2, 0xff, 0x1, 0x1a, 0x2, 0x23, 0x2, +0x1b, 0x2, 0x0, 0x0, 0x7, 0x2, 0x8, 0x2, 0x6, 0x2, 0x24, 0x2, 0x25, 0x2, 0x26, 0x2, 0x0, 0x0, 0x7, 0x2, +0x6, 0x2, 0xfe, 0x1, 0x24, 0x2, 0x26, 0x2, 0x1e, 0x2, 0x0, 0x0, 0x5, 0x2, 0x9, 0x2, 0x7, 0x2, 0x27, 0x2, +0x28, 0x2, 0x27, 0x2, 0x0, 0x0, 0x5, 0x2, 0x7, 0x2, 0xfe, 0x1, 0x27, 0x2, 0x27, 0x2, 0x27, 0x2, 0x0, 0x0, +0x9, 0x2, 0xa, 0x2, 0x8, 0x2, 0x29, 0x2, 0x29, 0x2, 0x29, 0x2, 0x0, 0x0, 0x9, 0x2, 0x8, 0x2, 0x7, 0x2, +0x29, 0x2, 0x29, 0x2, 0x29, 0x2, 0x0, 0x0, 0xa, 0x2, 0xb, 0x2, 0x6, 0x2, 0x2a, 0x2, 0x2a, 0x2, 0x2a, 0x2, +0x0, 0x0, 0xa, 0x2, 0x6, 0x2, 0x8, 0x2, 0x2a, 0x2, 0x2a, 0x2, 0x2a, 0x2, 0x0, 0x0, 0x6, 0x2, 0xc, 0x2, +0xff, 0x1, 0x23, 0x2, 0x2b, 0x2, 0x1b, 0x2, 0x0, 0x0, 0xd, 0x2, 0xe, 0x2, 0xc, 0x2, 0x2c, 0x2, 0x2d, 0x2, +0x2e, 0x2, 0x0, 0x0, 0xd, 0x2, 0xc, 0x2, 0x6, 0x2, 0x2c, 0x2, 0x2e, 0x2, 0x26, 0x2, 0x0, 0x0, 0xb, 0x2, +0xf, 0x2, 0xd, 0x2, 0x2f, 0x2, 0x2f, 0x2, 0x2f, 0x2, 0x0, 0x0, 0xb, 0x2, 0xd, 0x2, 0x6, 0x2, 0x2f, 0x2, +0x2f, 0x2, 0x2f, 0x2, 0x0, 0x0, 0xf, 0x2, 0x10, 0x2, 0xe, 0x2, 0x30, 0x2, 0x30, 0x2, 0x30, 0x2, 0x0, 0x0, +0xf, 0x2, 0xe, 0x2, 0xd, 0x2, 0x30, 0x2, 0x30, 0x2, 0x30, 0x2, 0x0, 0x0, 0x10, 0x2, 0x11, 0x2, 0xc, 0x2, +0x31, 0x2, 0x31, 0x2, 0x31, 0x2, 0x0, 0x0, 0x10, 0x2, 0xc, 0x2, 0xe, 0x2, 0x31, 0x2, 0x31, 0x2, 0x32, 0x2, +0x0, 0x0, 0xc, 0x2, 0x12, 0x2, 0xff, 0x1, 0x2b, 0x2, 0x33, 0x2, 0x1b, 0x2, 0x0, 0x0, 0x13, 0x2, 0x14, 0x2, +0x12, 0x2, 0x34, 0x2, 0x35, 0x2, 0x36, 0x2, 0x0, 0x0, 0x13, 0x2, 0x12, 0x2, 0xc, 0x2, 0x34, 0x2, 0x36, 0x2, +0x2e, 0x2, 0x0, 0x0, 0x11, 0x2, 0x15, 0x2, 0x13, 0x2, 0x37, 0x2, 0x37, 0x2, 0x37, 0x2, 0x0, 0x0, 0x11, 0x2, +0x13, 0x2, 0xc, 0x2, 0x37, 0x2, 0x37, 0x2, 0x37, 0x2, 0x0, 0x0, 0x15, 0x2, 0x16, 0x2, 0x14, 0x2, 0x38, 0x2, +0x38, 0x2, 0x38, 0x2, 0x0, 0x0, 0x15, 0x2, 0x14, 0x2, 0x13, 0x2, 0x38, 0x2, 0x38, 0x2, 0x38, 0x2, 0x0, 0x0, +0x16, 0x2, 0x17, 0x2, 0x12, 0x2, 0x39, 0x2, 0x39, 0x2, 0x39, 0x2, 0x0, 0x0, 0x16, 0x2, 0x12, 0x2, 0x14, 0x2, +0x39, 0x2, 0x39, 0x2, 0x39, 0x2, 0x0, 0x0, 0x12, 0x2, 0x18, 0x2, 0xff, 0x1, 0x33, 0x2, 0x3a, 0x2, 0x1b, 0x2, +0x0, 0x0, 0x19, 0x2, 0x1a, 0x2, 0x18, 0x2, 0x3b, 0x2, 0x3c, 0x2, 0x3d, 0x2, 0x0, 0x0, 0x19, 0x2, 0x18, 0x2, +0x12, 0x2, 0x3b, 0x2, 0x3d, 0x2, 0x36, 0x2, 0x0, 0x0, 0x17, 0x2, 0x1b, 0x2, 0x19, 0x2, 0x3e, 0x2, 0x3e, 0x2, +0x3e, 0x2, 0x0, 0x0, 0x17, 0x2, 0x19, 0x2, 0x12, 0x2, 0x3e, 0x2, 0x3e, 0x2, 0x3e, 0x2, 0x0, 0x0, 0x1b, 0x2, +0x1c, 0x2, 0x1a, 0x2, 0x3f, 0x2, 0x3f, 0x2, 0x3f, 0x2, 0x0, 0x0, 0x1b, 0x2, 0x1a, 0x2, 0x19, 0x2, 0x3f, 0x2, +0x3f, 0x2, 0x3f, 0x2, 0x0, 0x0, 0x1c, 0x2, 0x1d, 0x2, 0x18, 0x2, 0x40, 0x2, 0x40, 0x2, 0x40, 0x2, 0x0, 0x0, +0x1c, 0x2, 0x18, 0x2, 0x1a, 0x2, 0x40, 0x2, 0x40, 0x2, 0x40, 0x2, 0x0, 0x0, 0x18, 0x2, 0x1e, 0x2, 0xff, 0x1, +0x3a, 0x2, 0x41, 0x2, 0x1b, 0x2, 0x0, 0x0, 0x1f, 0x2, 0x20, 0x2, 0x1e, 0x2, 0x42, 0x2, 0x43, 0x2, 0x44, 0x2, +0x0, 0x0, 0x1f, 0x2, 0x1e, 0x2, 0x18, 0x2, 0x42, 0x2, 0x44, 0x2, 0x3d, 0x2, 0x0, 0x0, 0x1d, 0x2, 0x21, 0x2, +0x1f, 0x2, 0x45, 0x2, 0x45, 0x2, 0x45, 0x2, 0x0, 0x0, 0x1d, 0x2, 0x1f, 0x2, 0x18, 0x2, 0x45, 0x2, 0x45, 0x2, +0x45, 0x2, 0x0, 0x0, 0x21, 0x2, 0x22, 0x2, 0x20, 0x2, 0x46, 0x2, 0x46, 0x2, 0x46, 0x2, 0x0, 0x0, 0x21, 0x2, +0x20, 0x2, 0x1f, 0x2, 0x46, 0x2, 0x46, 0x2, 0x46, 0x2, 0x0, 0x0, 0x22, 0x2, 0x23, 0x2, 0x1e, 0x2, 0x47, 0x2, +0x47, 0x2, 0x47, 0x2, 0x0, 0x0, 0x22, 0x2, 0x1e, 0x2, 0x20, 0x2, 0x47, 0x2, 0x47, 0x2, 0x47, 0x2, 0x0, 0x0, +0x1e, 0x2, 0x24, 0x2, 0xff, 0x1, 0x41, 0x2, 0x48, 0x2, 0x1b, 0x2, 0x0, 0x0, 0x25, 0x2, 0x26, 0x2, 0x24, 0x2, +0x49, 0x2, 0x4a, 0x2, 0x4b, 0x2, 0x0, 0x0, 0x25, 0x2, 0x24, 0x2, 0x1e, 0x2, 0x49, 0x2, 0x4b, 0x2, 0x44, 0x2, +0x0, 0x0, 0x23, 0x2, 0x27, 0x2, 0x25, 0x2, 0x4c, 0x2, 0x4d, 0x2, 0x4c, 0x2, 0x0, 0x0, 0x23, 0x2, 0x25, 0x2, +0x1e, 0x2, 0x4c, 0x2, 0x4c, 0x2, 0x4c, 0x2, 0x0, 0x0, 0x27, 0x2, 0x28, 0x2, 0x26, 0x2, 0x4e, 0x2, 0x4e, 0x2, +0x4e, 0x2, 0x0, 0x0, 0x27, 0x2, 0x26, 0x2, 0x25, 0x2, 0x4e, 0x2, 0x4e, 0x2, 0x4e, 0x2, 0x0, 0x0, 0x28, 0x2, +0x29, 0x2, 0x24, 0x2, 0x4f, 0x2, 0x4f, 0x2, 0x4f, 0x2, 0x0, 0x0, 0x28, 0x2, 0x24, 0x2, 0x26, 0x2, 0x4f, 0x2, +0x4f, 0x2, 0x4f, 0x2, 0x0, 0x0, 0x24, 0x2, 0x2a, 0x2, 0xff, 0x1, 0x48, 0x2, 0x50, 0x2, 0x1b, 0x2, 0x0, 0x0, +0x2b, 0x2, 0x2c, 0x2, 0x2a, 0x2, 0x51, 0x2, 0x52, 0x2, 0x53, 0x2, 0x0, 0x0, 0x2b, 0x2, 0x2a, 0x2, 0x24, 0x2, +0x51, 0x2, 0x53, 0x2, 0x4b, 0x2, 0x0, 0x0, 0x29, 0x2, 0x2d, 0x2, 0x2b, 0x2, 0x54, 0x2, 0x54, 0x2, 0x54, 0x2, +0x0, 0x0, 0x29, 0x2, 0x2b, 0x2, 0x24, 0x2, 0x54, 0x2, 0x54, 0x2, 0x54, 0x2, 0x0, 0x0, 0x2d, 0x2, 0x2e, 0x2, +0x2c, 0x2, 0x55, 0x2, 0x55, 0x2, 0x55, 0x2, 0x0, 0x0, 0x2d, 0x2, 0x2c, 0x2, 0x2b, 0x2, 0x55, 0x2, 0x55, 0x2, +0x55, 0x2, 0x0, 0x0, 0x2e, 0x2, 0x2f, 0x2, 0x2a, 0x2, 0x56, 0x2, 0x56, 0x2, 0x56, 0x2, 0x0, 0x0, 0x2e, 0x2, +0x2a, 0x2, 0x2c, 0x2, 0x56, 0x2, 0x56, 0x2, 0x57, 0x2, 0x0, 0x0, 0x2a, 0x2, 0x30, 0x2, 0xff, 0x1, 0x50, 0x2, +0x58, 0x2, 0x1b, 0x2, 0x0, 0x0, 0x31, 0x2, 0x32, 0x2, 0x30, 0x2, 0x59, 0x2, 0x5a, 0x2, 0x5b, 0x2, 0x0, 0x0, +0x31, 0x2, 0x30, 0x2, 0x2a, 0x2, 0x59, 0x2, 0x5b, 0x2, 0x53, 0x2, 0x0, 0x0, 0x2f, 0x2, 0x33, 0x2, 0x31, 0x2, +0x5c, 0x2, 0x5c, 0x2, 0x5c, 0x2, 0x0, 0x0, 0x2f, 0x2, 0x31, 0x2, 0x2a, 0x2, 0x5c, 0x2, 0x5c, 0x2, 0x5c, 0x2, +0x0, 0x0, 0x33, 0x2, 0x34, 0x2, 0x32, 0x2, 0x5d, 0x2, 0x5d, 0x2, 0x5d, 0x2, 0x0, 0x0, 0x33, 0x2, 0x32, 0x2, +0x31, 0x2, 0x5d, 0x2, 0x5d, 0x2, 0x5d, 0x2, 0x0, 0x0, 0x34, 0x2, 0x35, 0x2, 0x30, 0x2, 0x5e, 0x2, 0x5e, 0x2, +0x5e, 0x2, 0x0, 0x0, 0x34, 0x2, 0x30, 0x2, 0x32, 0x2, 0x5e, 0x2, 0x5e, 0x2, 0x5e, 0x2, 0x0, 0x0, 0x30, 0x2, +0xfd, 0x1, 0xff, 0x1, 0x58, 0x2, 0x19, 0x2, 0x1b, 0x2, 0x0, 0x0, 0x36, 0x2, 0x37, 0x2, 0xfd, 0x1, 0x5f, 0x2, +0x60, 0x2, 0x1f, 0x2, 0x0, 0x0, 0x36, 0x2, 0xfd, 0x1, 0x30, 0x2, 0x5f, 0x2, 0x1f, 0x2, 0x5b, 0x2, 0x0, 0x0, +0x35, 0x2, 0x38, 0x2, 0x36, 0x2, 0x61, 0x2, 0x61, 0x2, 0x61, 0x2, 0x0, 0x0, 0x35, 0x2, 0x36, 0x2, 0x30, 0x2, +0x61, 0x2, 0x61, 0x2, 0x61, 0x2, 0x0, 0x0, 0x38, 0x2, 0x39, 0x2, 0x37, 0x2, 0x62, 0x2, 0x62, 0x2, 0x62, 0x2, +0x0, 0x0, 0x38, 0x2, 0x37, 0x2, 0x36, 0x2, 0x62, 0x2, 0x62, 0x2, 0x62, 0x2, 0x0, 0x0, 0x39, 0x2, 0x2, 0x2, +0xfd, 0x1, 0x63, 0x2, 0x63, 0x2, 0x63, 0x2, 0x0, 0x0, 0x39, 0x2, 0xfd, 0x1, 0x37, 0x2, 0x63, 0x2, 0x63, 0x2, +0x63, 0x2, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0xff, 0x3, 0x0, 0x4, 0x0, 0x4, 0x0, 0x0, 0x3, 0x0, +0x1, 0x0, 0x0, 0x0, 0x1, 0x4, 0x0, 0x4, 0xff, 0x3, 0x0, 0x0, 0x4, 0x0, 0x3, 0x0, 0x0, 0x0, 0x2, 0x4, +0x1, 0x4, 0xff, 0x3, 0x0, 0x0, 0x5, 0x0, 0x3, 0x0, 0x4, 0x0, 0x3, 0x4, 0x1, 0x4, 0x2, 0x4, 0x0, 0x0, +0x6, 0x0, 0x5, 0x0, 0x4, 0x0, 0x4, 0x4, 0x3, 0x4, 0x2, 0x4, 0x0, 0x0, 0x7, 0x0, 0x5, 0x0, 0x6, 0x0, +0x5, 0x4, 0x3, 0x4, 0x4, 0x4, 0x0, 0x0, 0x8, 0x0, 0x7, 0x0, 0x6, 0x0, 0x6, 0x4, 0x5, 0x4, 0x4, 0x4, +0x0, 0x0, 0x9, 0x0, 0x7, 0x0, 0x8, 0x0, 0x7, 0x4, 0x5, 0x4, 0x6, 0x4, 0x0, 0x0, 0xa, 0x0, 0x9, 0x0, +0x8, 0x0, 0x8, 0x4, 0x7, 0x4, 0x6, 0x4, 0x0, 0x0, 0xb, 0x0, 0x9, 0x0, 0xa, 0x0, 0x9, 0x4, 0x7, 0x4, +0x8, 0x4, 0x0, 0x0, 0xc, 0x0, 0xb, 0x0, 0xa, 0x0, 0xa, 0x4, 0x9, 0x4, 0x8, 0x4, 0x0, 0x0, 0xd, 0x0, +0xb, 0x0, 0xc, 0x0, 0xa, 0x4, 0x9, 0x4, 0xa, 0x4, 0x0, 0x0, 0xe, 0x0, 0xf, 0x0, 0x10, 0x0, 0x0, 0x4, +0xff, 0x3, 0x0, 0x4, 0x0, 0x0, 0xe, 0x0, 0x11, 0x0, 0xf, 0x0, 0x0, 0x4, 0x1, 0x4, 0xff, 0x3, 0x0, 0x0, +0x11, 0x0, 0x12, 0x0, 0xf, 0x0, 0x1, 0x4, 0x2, 0x4, 0xff, 0x3, 0x0, 0x0, 0x11, 0x0, 0x13, 0x0, 0x12, 0x0, +0x1, 0x4, 0x3, 0x4, 0x2, 0x4, 0x0, 0x0, 0x13, 0x0, 0x14, 0x0, 0x12, 0x0, 0x3, 0x4, 0x4, 0x4, 0x2, 0x4, +0x0, 0x0, 0x13, 0x0, 0x15, 0x0, 0x14, 0x0, 0x3, 0x4, 0x5, 0x4, 0x4, 0x4, 0x0, 0x0, 0x15, 0x0, 0x16, 0x0, +0x14, 0x0, 0x5, 0x4, 0x6, 0x4, 0x4, 0x4, 0x0, 0x0, 0x15, 0x0, 0x17, 0x0, 0x16, 0x0, 0x5, 0x4, 0x7, 0x4, +0x6, 0x4, 0x0, 0x0, 0x17, 0x0, 0x18, 0x0, 0x16, 0x0, 0x7, 0x4, 0x8, 0x4, 0x6, 0x4, 0x0, 0x0, 0x17, 0x0, +0x19, 0x0, 0x18, 0x0, 0x7, 0x4, 0x9, 0x4, 0x8, 0x4, 0x0, 0x0, 0x19, 0x0, 0x1a, 0x0, 0x18, 0x0, 0x9, 0x4, +0xa, 0x4, 0x8, 0x4, 0x0, 0x0, 0x19, 0x0, 0x1b, 0x0, 0x1a, 0x0, 0x9, 0x4, 0xa, 0x4, 0xa, 0x4, 0x0, 0x0, +0x81, 0x5, 0x82, 0x5, 0x83, 0x5, 0x64, 0x2, 0x64, 0x2, 0x64, 0x2, 0x1, 0x0, 0x84, 0x5, 0x85, 0x5, 0x82, 0x5, +0x65, 0x2, 0x65, 0x2, 0x65, 0x2, 0x1, 0x0, 0x86, 0x5, 0x87, 0x5, 0x85, 0x5, 0x66, 0x2, 0x67, 0x2, 0x66, 0x2, +0x1, 0x0, 0x88, 0x5, 0x89, 0x5, 0x87, 0x5, 0x68, 0x2, 0x69, 0x2, 0x67, 0x2, 0x1, 0x0, 0x8a, 0x5, 0x8b, 0x5, +0x89, 0x5, 0x6a, 0x2, 0x6b, 0x2, 0x69, 0x2, 0x1, 0x0, 0x8c, 0x5, 0x8d, 0x5, 0x8b, 0x5, 0x6c, 0x2, 0x6d, 0x2, +0x6b, 0x2, 0x1, 0x0, 0x8e, 0x5, 0x8f, 0x5, 0x8d, 0x5, 0x6e, 0x2, 0x6f, 0x2, 0x6d, 0x2, 0x1, 0x0, 0x90, 0x5, +0x91, 0x5, 0x8f, 0x5, 0x70, 0x2, 0x71, 0x2, 0x6f, 0x2, 0x1, 0x0, 0x92, 0x5, 0x93, 0x5, 0x91, 0x5, 0x72, 0x2, +0x73, 0x2, 0x71, 0x2, 0x1, 0x0, 0x94, 0x5, 0x95, 0x5, 0x93, 0x5, 0x74, 0x2, 0x75, 0x2, 0x73, 0x2, 0x1, 0x0, +0x96, 0x5, 0x97, 0x5, 0x95, 0x5, 0x76, 0x2, 0x77, 0x2, 0x75, 0x2, 0x1, 0x0, 0x98, 0x5, 0x99, 0x5, 0x97, 0x5, +0x78, 0x2, 0x79, 0x2, 0x77, 0x2, 0x1, 0x0, 0x9a, 0x5, 0x9b, 0x5, 0x99, 0x5, 0x7a, 0x2, 0x7b, 0x2, 0x79, 0x2, +0x1, 0x0, 0x9c, 0x5, 0x9d, 0x5, 0x9b, 0x5, 0x7c, 0x2, 0x7d, 0x2, 0x7b, 0x2, 0x1, 0x0, 0x9e, 0x5, 0x9f, 0x5, +0x9d, 0x5, 0x7e, 0x2, 0x7f, 0x2, 0x7d, 0x2, 0x1, 0x0, 0xa0, 0x5, 0xa1, 0x5, 0x9f, 0x5, 0x80, 0x2, 0x81, 0x2, +0x7f, 0x2, 0x1, 0x0, 0xa2, 0x5, 0xa3, 0x5, 0xa1, 0x5, 0x82, 0x2, 0x83, 0x2, 0x81, 0x2, 0x1, 0x0, 0xa4, 0x5, +0xa5, 0x5, 0xa3, 0x5, 0x84, 0x2, 0x85, 0x2, 0x83, 0x2, 0x1, 0x0, 0xa6, 0x5, 0xa7, 0x5, 0xa5, 0x5, 0x86, 0x2, +0x87, 0x2, 0x85, 0x2, 0x1, 0x0, 0xa8, 0x5, 0xa9, 0x5, 0xa7, 0x5, 0x88, 0x2, 0x89, 0x2, 0x87, 0x2, 0x1, 0x0, +0xaa, 0x5, 0xab, 0x5, 0xa9, 0x5, 0x8a, 0x2, 0x8b, 0x2, 0x89, 0x2, 0x1, 0x0, 0xac, 0x5, 0xad, 0x5, 0xab, 0x5, +0x8c, 0x2, 0x8d, 0x2, 0x8b, 0x2, 0x1, 0x0, 0xae, 0x5, 0xaf, 0x5, 0xad, 0x5, 0x8e, 0x2, 0x8f, 0x2, 0x8d, 0x2, +0x1, 0x0, 0xb0, 0x5, 0xb1, 0x5, 0xaf, 0x5, 0x90, 0x2, 0x91, 0x2, 0x8f, 0x2, 0x1, 0x0, 0xb2, 0x5, 0xb3, 0x5, +0xb1, 0x5, 0x92, 0x2, 0x93, 0x2, 0x91, 0x2, 0x1, 0x0, 0xb4, 0x5, 0xb5, 0x5, 0xb3, 0x5, 0x94, 0x2, 0x95, 0x2, +0x93, 0x2, 0x1, 0x0, 0xb6, 0x5, 0xb7, 0x5, 0xb5, 0x5, 0x96, 0x2, 0x97, 0x2, 0x95, 0x2, 0x1, 0x0, 0xb8, 0x5, +0x83, 0x5, 0xb7, 0x5, 0x98, 0x2, 0x98, 0x2, 0x98, 0x2, 0x1, 0x0, 0xb9, 0x5, 0xba, 0x5, 0xbb, 0x5, 0x99, 0x2, +0x99, 0x2, 0x9a, 0x2, 0x1, 0x0, 0xbc, 0x5, 0xbd, 0x5, 0xba, 0x5, 0x9b, 0x2, 0x96, 0x2, 0x9c, 0x2, 0x1, 0x0, +0xbe, 0x5, 0xbf, 0x5, 0xbd, 0x5, 0x9d, 0x2, 0x9e, 0x2, 0x96, 0x2, 0x1, 0x0, 0xc0, 0x5, 0xc1, 0x5, 0xc2, 0x5, +0x9f, 0x2, 0xa0, 0x2, 0xa1, 0x2, 0x1, 0x0, 0xc0, 0x5, 0xc2, 0x5, 0xbf, 0x5, 0x9f, 0x2, 0xa1, 0x2, 0x9e, 0x2, +0x1, 0x0, 0xc3, 0x5, 0xc4, 0x5, 0xc2, 0x5, 0xa2, 0x2, 0xa3, 0x2, 0xa1, 0x2, 0x1, 0x0, 0xc5, 0x5, 0xc6, 0x5, +0xc4, 0x5, 0xa4, 0x2, 0xa5, 0x2, 0xa3, 0x2, 0x1, 0x0, 0xc7, 0x5, 0xc8, 0x5, 0xc6, 0x5, 0xa6, 0x2, 0xa7, 0x2, +0xa5, 0x2, 0x1, 0x0, 0xc9, 0x5, 0xca, 0x5, 0xc8, 0x5, 0xa8, 0x2, 0xa9, 0x2, 0xa7, 0x2, 0x1, 0x0, 0xca, 0x5, +0xcb, 0x5, 0xc8, 0x5, 0xa9, 0x2, 0xaa, 0x2, 0xa7, 0x2, 0x1, 0x0, 0xcc, 0x5, 0xcd, 0x5, 0xcb, 0x5, 0xab, 0x2, +0xac, 0x2, 0xaa, 0x2, 0x1, 0x0, 0xce, 0x5, 0xcf, 0x5, 0xd0, 0x5, 0xad, 0x2, 0xae, 0x2, 0xaf, 0x2, 0x1, 0x0, +0xce, 0x5, 0xd0, 0x5, 0xcd, 0x5, 0xad, 0x2, 0xaf, 0x2, 0xac, 0x2, 0x1, 0x0, 0xcf, 0x5, 0xd1, 0x5, 0xd0, 0x5, +0xae, 0x2, 0xb0, 0x2, 0xaf, 0x2, 0x1, 0x0, 0xd2, 0x5, 0xbb, 0x5, 0xd1, 0x5, 0xb1, 0x2, 0xb2, 0x2, 0xb0, 0x2, +0x1, 0x0, 0xd3, 0x5, 0xd4, 0x5, 0xd5, 0x5, 0xb3, 0x2, 0xb3, 0x2, 0xb4, 0x2, 0x1, 0x0, 0xd6, 0x5, 0xd7, 0x5, +0xd4, 0x5, 0xb5, 0x2, 0xb6, 0x2, 0xb7, 0x2, 0x1, 0x0, 0xd8, 0x5, 0xd9, 0x5, 0xda, 0x5, 0xb8, 0x2, 0xb9, 0x2, +0xba, 0x2, 0x1, 0x0, 0xd8, 0x5, 0xda, 0x5, 0xd7, 0x5, 0xb8, 0x2, 0xba, 0x2, 0xb6, 0x2, 0x1, 0x0, 0xd9, 0x5, +0xdb, 0x5, 0xda, 0x5, 0xb9, 0x2, 0xbb, 0x2, 0xba, 0x2, 0x1, 0x0, 0xdc, 0x5, 0xdd, 0x5, 0xdb, 0x5, 0xbc, 0x2, +0xbd, 0x2, 0xbb, 0x2, 0x1, 0x0, 0xde, 0x5, 0xdf, 0x5, 0xdd, 0x5, 0xbe, 0x2, 0xbf, 0x2, 0xbd, 0x2, 0x1, 0x0, +0xe0, 0x5, 0xe1, 0x5, 0xdf, 0x5, 0xc0, 0x2, 0xc1, 0x2, 0xbf, 0x2, 0x1, 0x0, 0xe2, 0x5, 0xe3, 0x5, 0xe1, 0x5, +0xc2, 0x2, 0xc3, 0x2, 0xc1, 0x2, 0x1, 0x0, 0xe4, 0x5, 0xe5, 0x5, 0xe3, 0x5, 0xc4, 0x2, 0xc5, 0x2, 0xc3, 0x2, +0x1, 0x0, 0xe6, 0x5, 0xe7, 0x5, 0xe5, 0x5, 0xc6, 0x2, 0xc7, 0x2, 0xc5, 0x2, 0x1, 0x0, 0xe8, 0x5, 0xe9, 0x5, +0xe7, 0x5, 0xc8, 0x2, 0xc9, 0x2, 0xc7, 0x2, 0x1, 0x0, 0xea, 0x5, 0xd5, 0x5, 0xe9, 0x5, 0xca, 0x2, 0xcb, 0x2, +0xc9, 0x2, 0x1, 0x0, 0xeb, 0x5, 0xec, 0x5, 0xed, 0x5, 0xcc, 0x2, 0xcc, 0x2, 0xcd, 0x2, 0x1, 0x0, 0xee, 0x5, +0xef, 0x5, 0xec, 0x5, 0xce, 0x2, 0xcf, 0x2, 0xd0, 0x2, 0x1, 0x0, 0xf0, 0x5, 0xf1, 0x5, 0xef, 0x5, 0xd1, 0x2, +0xd2, 0x2, 0xcf, 0x2, 0x1, 0x0, 0xf2, 0x5, 0xf3, 0x5, 0xf1, 0x5, 0xd3, 0x2, 0xd4, 0x2, 0xd2, 0x2, 0x1, 0x0, +0xf4, 0x5, 0xf5, 0x5, 0xf3, 0x5, 0xd5, 0x2, 0xd6, 0x2, 0xd4, 0x2, 0x1, 0x0, 0xf6, 0x5, 0xf7, 0x5, 0xf5, 0x5, +0xd7, 0x2, 0xd8, 0x2, 0xd6, 0x2, 0x1, 0x0, 0xf8, 0x5, 0xf9, 0x5, 0xf7, 0x5, 0xd9, 0x2, 0xda, 0x2, 0xd8, 0x2, +0x1, 0x0, 0xfa, 0x5, 0xfb, 0x5, 0xf9, 0x5, 0xdb, 0x2, 0xdc, 0x2, 0xda, 0x2, 0x1, 0x0, 0xfc, 0x5, 0xfd, 0x5, +0xfb, 0x5, 0xdd, 0x2, 0xde, 0x2, 0xdc, 0x2, 0x1, 0x0, 0xfe, 0x5, 0xff, 0x5, 0xfd, 0x5, 0xdf, 0x2, 0xe0, 0x2, +0xde, 0x2, 0x1, 0x0, 0x0, 0x6, 0x1, 0x6, 0xff, 0x5, 0xe1, 0x2, 0xe2, 0x2, 0xe0, 0x2, 0x1, 0x0, 0x2, 0x6, +0xed, 0x5, 0x1, 0x6, 0xe3, 0x2, 0xe4, 0x2, 0xe2, 0x2, 0x1, 0x0, 0x3, 0x6, 0x4, 0x6, 0x5, 0x6, 0xe5, 0x2, +0xe5, 0x2, 0xe6, 0x2, 0x1, 0x0, 0x6, 0x6, 0x7, 0x6, 0x4, 0x6, 0xe7, 0x2, 0xe8, 0x2, 0x76, 0x2, 0x1, 0x0, +0x8, 0x6, 0x9, 0x6, 0x7, 0x6, 0xe9, 0x2, 0xea, 0x2, 0xe8, 0x2, 0x1, 0x0, 0xa, 0x6, 0xb, 0x6, 0x9, 0x6, +0xeb, 0x2, 0xec, 0x2, 0xea, 0x2, 0x1, 0x0, 0xc, 0x6, 0xd, 0x6, 0xb, 0x6, 0xed, 0x2, 0xee, 0x2, 0xec, 0x2, +0x1, 0x0, 0xe, 0x6, 0xf, 0x6, 0xd, 0x6, 0xef, 0x2, 0xf0, 0x2, 0xee, 0x2, 0x1, 0x0, 0x10, 0x6, 0x11, 0x6, +0xf, 0x6, 0xf1, 0x2, 0xf2, 0x2, 0xf0, 0x2, 0x1, 0x0, 0x12, 0x6, 0x13, 0x6, 0x11, 0x6, 0xf3, 0x2, 0xf4, 0x2, +0xf2, 0x2, 0x1, 0x0, 0x14, 0x6, 0x15, 0x6, 0x13, 0x6, 0xf5, 0x2, 0xf6, 0x2, 0xf4, 0x2, 0x1, 0x0, 0x16, 0x6, +0x17, 0x6, 0x15, 0x6, 0xf7, 0x2, 0xf8, 0x2, 0xf6, 0x2, 0x1, 0x0, 0x18, 0x6, 0x19, 0x6, 0x17, 0x6, 0xf9, 0x2, +0xfa, 0x2, 0xf8, 0x2, 0x1, 0x0, 0x1a, 0x6, 0x5, 0x6, 0x19, 0x6, 0xfb, 0x2, 0xfc, 0x2, 0xfa, 0x2, 0x1, 0x0, +0x1b, 0x6, 0x1c, 0x6, 0x1d, 0x6, 0xfd, 0x2, 0xfd, 0x2, 0xfe, 0x2, 0x1, 0x0, 0x1e, 0x6, 0x1f, 0x6, 0x1c, 0x6, +0xff, 0x2, 0x0, 0x3, 0x1, 0x3, 0x1, 0x0, 0x20, 0x6, 0x21, 0x6, 0x1f, 0x6, 0x2, 0x3, 0x3, 0x3, 0x0, 0x3, +0x1, 0x0, 0x22, 0x6, 0x23, 0x6, 0x21, 0x6, 0x4, 0x3, 0x5, 0x3, 0x3, 0x3, 0x1, 0x0, 0x24, 0x6, 0x25, 0x6, +0x23, 0x6, 0x6, 0x3, 0x7, 0x3, 0x5, 0x3, 0x1, 0x0, 0x26, 0x6, 0x27, 0x6, 0x25, 0x6, 0x8, 0x3, 0x9, 0x3, +0x7, 0x3, 0x1, 0x0, 0x28, 0x6, 0x29, 0x6, 0x27, 0x6, 0xa, 0x3, 0xb, 0x3, 0x9, 0x3, 0x1, 0x0, 0x2a, 0x6, +0x2b, 0x6, 0x29, 0x6, 0xc, 0x3, 0xd, 0x3, 0xb, 0x3, 0x1, 0x0, 0x2c, 0x6, 0x2d, 0x6, 0x2b, 0x6, 0xe, 0x3, +0xf, 0x3, 0xd, 0x3, 0x1, 0x0, 0x2e, 0x6, 0x2f, 0x6, 0x2d, 0x6, 0x10, 0x3, 0x11, 0x3, 0xf, 0x3, 0x1, 0x0, +0x30, 0x6, 0x31, 0x6, 0x2f, 0x6, 0x12, 0x3, 0x13, 0x3, 0x11, 0x3, 0x1, 0x0, 0x32, 0x6, 0x1d, 0x6, 0x31, 0x6, +0x14, 0x3, 0x15, 0x3, 0x13, 0x3, 0x1, 0x0, 0xe3, 0x5, 0xed, 0x5, 0xec, 0x5, 0x16, 0x3, 0x17, 0x3, 0x18, 0x3, +0x1, 0x0, 0xab, 0x5, 0xfb, 0x5, 0x4, 0x6, 0x19, 0x3, 0x1a, 0x3, 0x1b, 0x3, 0x1, 0x0, 0x9f, 0x5, 0x13, 0x6, +0x1c, 0x6, 0x1c, 0x3, 0x1d, 0x3, 0x1e, 0x3, 0x1, 0x0, 0xc2, 0x5, 0x91, 0x5, 0x93, 0x5, 0x1f, 0x3, 0x20, 0x3, +0x21, 0x3, 0x1, 0x0, 0xdd, 0x5, 0x82, 0x5, 0x85, 0x5, 0x22, 0x3, 0x23, 0x3, 0x24, 0x3, 0x1, 0x0, 0x83, 0x5, +0xdd, 0x5, 0xdf, 0x5, 0x25, 0x3, 0x22, 0x3, 0x26, 0x3, 0x1, 0x0, 0x8f, 0x5, 0xc2, 0x5, 0xc4, 0x5, 0x27, 0x3, +0x1f, 0x3, 0x28, 0x3, 0x1, 0x0, 0xb7, 0x5, 0x83, 0x5, 0xe1, 0x5, 0x29, 0x3, 0x25, 0x3, 0x2a, 0x3, 0x1, 0x0, +0xbf, 0x5, 0xc2, 0x5, 0x93, 0x5, 0x2b, 0x3, 0x1f, 0x3, 0x21, 0x3, 0x1, 0x0, 0xdd, 0x5, 0x85, 0x5, 0x87, 0x5, +0x22, 0x3, 0x24, 0x3, 0x2c, 0x3, 0x1, 0x0, 0xdb, 0x5, 0xdd, 0x5, 0x87, 0x5, 0x2d, 0x3, 0x22, 0x3, 0x2c, 0x3, +0x1, 0x0, 0x8d, 0x5, 0x8f, 0x5, 0xc4, 0x5, 0x2e, 0x3, 0x27, 0x3, 0x28, 0x3, 0x1, 0x0, 0x8d, 0x5, 0xc4, 0x5, +0xc6, 0x5, 0x2e, 0x3, 0x28, 0x3, 0x2f, 0x3, 0x1, 0x0, 0x8b, 0x5, 0xc6, 0x5, 0xc8, 0x5, 0x30, 0x3, 0x2f, 0x3, +0x31, 0x3, 0x1, 0x0, 0x8b, 0x5, 0xc8, 0x5, 0xcb, 0x5, 0x30, 0x3, 0x31, 0x3, 0x32, 0x3, 0x1, 0x0, 0xb7, 0x5, +0xe1, 0x5, 0xe3, 0x5, 0x29, 0x3, 0x2a, 0x3, 0x16, 0x3, 0x1, 0x0, 0xdb, 0x5, 0x87, 0x5, 0x89, 0x5, 0x2d, 0x3, +0x2c, 0x3, 0x33, 0x3, 0x1, 0x0, 0xbd, 0x5, 0xbf, 0x5, 0x93, 0x5, 0x34, 0x3, 0x2b, 0x3, 0x21, 0x3, 0x1, 0x0, +0xda, 0x5, 0xdb, 0x5, 0x89, 0x5, 0x35, 0x3, 0x2d, 0x3, 0x33, 0x3, 0x1, 0x0, 0xd7, 0x5, 0xda, 0x5, 0x89, 0x5, +0x36, 0x3, 0x35, 0x3, 0x33, 0x3, 0x1, 0x0, 0xd4, 0x5, 0xd7, 0x5, 0x89, 0x5, 0x37, 0x3, 0x36, 0x3, 0x33, 0x3, +0x1, 0x0, 0x89, 0x5, 0x8b, 0x5, 0xcb, 0x5, 0x33, 0x3, 0x30, 0x3, 0x32, 0x3, 0x1, 0x0, 0xd4, 0x5, 0x89, 0x5, +0xcb, 0x5, 0x37, 0x3, 0x33, 0x3, 0x32, 0x3, 0x1, 0x0, 0xd5, 0x5, 0xcb, 0x5, 0xcd, 0x5, 0x17, 0x3, 0x32, 0x3, +0x17, 0x3, 0x1, 0x0, 0xba, 0x5, 0x93, 0x5, 0x95, 0x5, 0x38, 0x3, 0x21, 0x3, 0x39, 0x3, 0x1, 0x0, 0xb5, 0x5, +0xec, 0x5, 0xef, 0x5, 0x3a, 0x3, 0x18, 0x3, 0x3b, 0x3, 0x1, 0x0, 0xb3, 0x5, 0xef, 0x5, 0xf1, 0x5, 0x3c, 0x3, +0x3b, 0x3, 0x3d, 0x3, 0x1, 0x0, 0xb3, 0x5, 0xf1, 0x5, 0xf3, 0x5, 0x3c, 0x3, 0x3d, 0x3, 0x3e, 0x3, 0x1, 0x0, +0xb1, 0x5, 0xb3, 0x5, 0xf3, 0x5, 0x3f, 0x3, 0x3c, 0x3, 0x3e, 0x3, 0x1, 0x0, 0xb1, 0x5, 0xf3, 0x5, 0xf5, 0x5, +0x3f, 0x3, 0x3e, 0x3, 0x40, 0x3, 0x1, 0x0, 0xaf, 0x5, 0xb1, 0x5, 0xf5, 0x5, 0x41, 0x3, 0x3f, 0x3, 0x40, 0x3, +0x1, 0x0, 0xaf, 0x5, 0xf5, 0x5, 0xf7, 0x5, 0x41, 0x3, 0x40, 0x3, 0x42, 0x3, 0x1, 0x0, 0xad, 0x5, 0xaf, 0x5, +0xf7, 0x5, 0x43, 0x3, 0x41, 0x3, 0x42, 0x3, 0x1, 0x0, 0xad, 0x5, 0xf7, 0x5, 0xf9, 0x5, 0x43, 0x3, 0x42, 0x3, +0x44, 0x3, 0x1, 0x0, 0xab, 0x5, 0xad, 0x5, 0xfb, 0x5, 0x19, 0x3, 0x43, 0x3, 0x1a, 0x3, 0x1, 0x0, 0xa9, 0x5, +0x4, 0x6, 0x7, 0x6, 0x45, 0x3, 0x1b, 0x3, 0x46, 0x3, 0x1, 0x0, 0xa9, 0x5, 0x7, 0x6, 0x9, 0x6, 0x45, 0x3, +0x46, 0x3, 0x47, 0x3, 0x1, 0x0, 0xa9, 0x5, 0x9, 0x6, 0xb, 0x6, 0x45, 0x3, 0x47, 0x3, 0x48, 0x3, 0x1, 0x0, +0xa5, 0x5, 0xa7, 0x5, 0xd, 0x6, 0x49, 0x3, 0x4a, 0x3, 0x4b, 0x3, 0x1, 0x0, 0xa3, 0x5, 0xa5, 0x5, 0xf, 0x6, +0x4c, 0x3, 0x49, 0x3, 0x4d, 0x3, 0x1, 0x0, 0xa1, 0x5, 0xa3, 0x5, 0x11, 0x6, 0x4e, 0x3, 0x4c, 0x3, 0x4f, 0x3, +0x1, 0x0, 0xa1, 0x5, 0x11, 0x6, 0x13, 0x6, 0x4e, 0x3, 0x4f, 0x3, 0x1d, 0x3, 0x1, 0x0, 0x9f, 0x5, 0xa1, 0x5, +0x13, 0x6, 0x1c, 0x3, 0x4e, 0x3, 0x1d, 0x3, 0x1, 0x0, 0x9d, 0x5, 0x1c, 0x6, 0x1f, 0x6, 0x50, 0x3, 0x1e, 0x3, +0x51, 0x3, 0x1, 0x0, 0x9d, 0x5, 0x1f, 0x6, 0x21, 0x6, 0x50, 0x3, 0x51, 0x3, 0x52, 0x3, 0x1, 0x0, 0x9d, 0x5, +0x21, 0x6, 0x23, 0x6, 0x50, 0x3, 0x52, 0x3, 0x53, 0x3, 0x1, 0x0, 0x9b, 0x5, 0x9d, 0x5, 0x23, 0x6, 0x54, 0x3, +0x50, 0x3, 0x53, 0x3, 0x1, 0x0, 0x9b, 0x5, 0x23, 0x6, 0x25, 0x6, 0x54, 0x3, 0x53, 0x3, 0x55, 0x3, 0x1, 0x0, +0x99, 0x5, 0x9b, 0x5, 0x25, 0x6, 0x56, 0x3, 0x54, 0x3, 0x55, 0x3, 0x1, 0x0, 0x99, 0x5, 0x25, 0x6, 0x27, 0x6, +0x56, 0x3, 0x55, 0x3, 0x57, 0x3, 0x1, 0x0, 0x97, 0x5, 0x99, 0x5, 0x27, 0x6, 0x58, 0x3, 0x56, 0x3, 0x57, 0x3, +0x1, 0x0, 0x97, 0x5, 0x27, 0x6, 0x29, 0x6, 0x58, 0x3, 0x57, 0x3, 0x59, 0x3, 0x1, 0x0, 0x95, 0x5, 0x97, 0x5, +0x29, 0x6, 0x39, 0x3, 0x58, 0x3, 0x59, 0x3, 0x1, 0x0, 0x95, 0x5, 0x29, 0x6, 0x2b, 0x6, 0x39, 0x3, 0x59, 0x3, +0x5a, 0x3, 0x1, 0x0, 0xba, 0x5, 0x95, 0x5, 0x2b, 0x6, 0x38, 0x3, 0x39, 0x3, 0x5a, 0x3, 0x1, 0x0, 0xbb, 0x5, +0x2b, 0x6, 0x2d, 0x6, 0x17, 0x3, 0x5a, 0x3, 0x17, 0x3, 0x1, 0x0, 0x31, 0x6, 0x1d, 0x6, 0x17, 0x6, 0x17, 0x3, +0x17, 0x3, 0x5b, 0x3, 0x1, 0x0, 0x31, 0x6, 0xe9, 0x5, 0xd0, 0x5, 0x17, 0x3, 0x17, 0x3, 0x17, 0x3, 0x1, 0x0, +0x31, 0x6, 0x19, 0x6, 0xff, 0x5, 0x17, 0x3, 0x17, 0x3, 0x17, 0x3, 0x1, 0x0, 0x31, 0x6, 0x1, 0x6, 0xe7, 0x5, +0x17, 0x3, 0x17, 0x3, 0x17, 0x3, 0x1, 0x0, 0xd1, 0x5, 0xbb, 0x5, 0x2f, 0x6, 0x5b, 0x3, 0x17, 0x3, 0x5b, 0x3, +0x1, 0x0, 0x31, 0x6, 0x17, 0x6, 0x19, 0x6, 0x17, 0x3, 0x5b, 0x3, 0x17, 0x3, 0x1, 0x0, 0x31, 0x6, 0xff, 0x5, +0x1, 0x6, 0x17, 0x3, 0x17, 0x3, 0x17, 0x3, 0x1, 0x0, 0x31, 0x6, 0xe7, 0x5, 0xe9, 0x5, 0x17, 0x3, 0x17, 0x3, +0x17, 0x3, 0x1, 0x0, 0x31, 0x6, 0xd1, 0x5, 0x2f, 0x6, 0x17, 0x3, 0x5b, 0x3, 0x5b, 0x3, 0x1, 0x0, 0x81, 0x5, +0x84, 0x5, 0x82, 0x5, 0x64, 0x2, 0x64, 0x2, 0x64, 0x2, 0x1, 0x0, 0x84, 0x5, 0x86, 0x5, 0x85, 0x5, 0x65, 0x2, +0x65, 0x2, 0x65, 0x2, 0x1, 0x0, 0x86, 0x5, 0x88, 0x5, 0x87, 0x5, 0x66, 0x2, 0x68, 0x2, 0x67, 0x2, 0x1, 0x0, +0x88, 0x5, 0x8a, 0x5, 0x89, 0x5, 0x68, 0x2, 0x6a, 0x2, 0x69, 0x2, 0x1, 0x0, 0x8a, 0x5, 0x8c, 0x5, 0x8b, 0x5, +0x6a, 0x2, 0x6c, 0x2, 0x6b, 0x2, 0x1, 0x0, 0x8c, 0x5, 0x8e, 0x5, 0x8d, 0x5, 0x6c, 0x2, 0x6e, 0x2, 0x6d, 0x2, +0x1, 0x0, 0x8e, 0x5, 0x90, 0x5, 0x8f, 0x5, 0x6e, 0x2, 0x70, 0x2, 0x6f, 0x2, 0x1, 0x0, 0x90, 0x5, 0x92, 0x5, +0x91, 0x5, 0x70, 0x2, 0x72, 0x2, 0x71, 0x2, 0x1, 0x0, 0x92, 0x5, 0x94, 0x5, 0x93, 0x5, 0x72, 0x2, 0x74, 0x2, +0x73, 0x2, 0x1, 0x0, 0x94, 0x5, 0x96, 0x5, 0x95, 0x5, 0x74, 0x2, 0x76, 0x2, 0x75, 0x2, 0x1, 0x0, 0x96, 0x5, +0x98, 0x5, 0x97, 0x5, 0x76, 0x2, 0x78, 0x2, 0x77, 0x2, 0x1, 0x0, 0x98, 0x5, 0x9a, 0x5, 0x99, 0x5, 0x78, 0x2, +0x7a, 0x2, 0x79, 0x2, 0x1, 0x0, 0x9a, 0x5, 0x9c, 0x5, 0x9b, 0x5, 0x7a, 0x2, 0x7c, 0x2, 0x7b, 0x2, 0x1, 0x0, +0x9c, 0x5, 0x9e, 0x5, 0x9d, 0x5, 0x7c, 0x2, 0x7e, 0x2, 0x7d, 0x2, 0x1, 0x0, 0x9e, 0x5, 0xa0, 0x5, 0x9f, 0x5, +0x7e, 0x2, 0x80, 0x2, 0x7f, 0x2, 0x1, 0x0, 0xa0, 0x5, 0xa2, 0x5, 0xa1, 0x5, 0x80, 0x2, 0x82, 0x2, 0x81, 0x2, +0x1, 0x0, 0xa2, 0x5, 0xa4, 0x5, 0xa3, 0x5, 0x82, 0x2, 0x84, 0x2, 0x83, 0x2, 0x1, 0x0, 0xa4, 0x5, 0xa6, 0x5, +0xa5, 0x5, 0x84, 0x2, 0x86, 0x2, 0x85, 0x2, 0x1, 0x0, 0xa6, 0x5, 0xa8, 0x5, 0xa7, 0x5, 0x86, 0x2, 0x88, 0x2, +0x87, 0x2, 0x1, 0x0, 0xa8, 0x5, 0xaa, 0x5, 0xa9, 0x5, 0x88, 0x2, 0x8a, 0x2, 0x89, 0x2, 0x1, 0x0, 0xaa, 0x5, +0xac, 0x5, 0xab, 0x5, 0x8a, 0x2, 0x8c, 0x2, 0x8b, 0x2, 0x1, 0x0, 0xac, 0x5, 0xae, 0x5, 0xad, 0x5, 0x8c, 0x2, +0x8e, 0x2, 0x8d, 0x2, 0x1, 0x0, 0xae, 0x5, 0xb0, 0x5, 0xaf, 0x5, 0x8e, 0x2, 0x90, 0x2, 0x8f, 0x2, 0x1, 0x0, +0xb0, 0x5, 0xb2, 0x5, 0xb1, 0x5, 0x90, 0x2, 0x92, 0x2, 0x91, 0x2, 0x1, 0x0, 0xb2, 0x5, 0xb4, 0x5, 0xb3, 0x5, +0x92, 0x2, 0x94, 0x2, 0x93, 0x2, 0x1, 0x0, 0xb4, 0x5, 0xb6, 0x5, 0xb5, 0x5, 0x94, 0x2, 0x96, 0x2, 0x95, 0x2, +0x1, 0x0, 0xb6, 0x5, 0xb8, 0x5, 0xb7, 0x5, 0x96, 0x2, 0x97, 0x2, 0x97, 0x2, 0x1, 0x0, 0xb8, 0x5, 0x81, 0x5, +0x83, 0x5, 0x98, 0x2, 0x98, 0x2, 0x98, 0x2, 0x1, 0x0, 0xb9, 0x5, 0x33, 0x6, 0xba, 0x5, 0x99, 0x2, 0x5c, 0x3, +0x99, 0x2, 0x1, 0x0, 0x33, 0x6, 0x34, 0x6, 0xba, 0x5, 0x5d, 0x3, 0x5d, 0x3, 0x5d, 0x3, 0x1, 0x0, 0x34, 0x6, +0xbc, 0x5, 0xba, 0x5, 0x5e, 0x3, 0x9b, 0x2, 0x9c, 0x2, 0x1, 0x0, 0xbc, 0x5, 0xbe, 0x5, 0xbd, 0x5, 0x9b, 0x2, +0x9d, 0x2, 0x96, 0x2, 0x1, 0x0, 0xbe, 0x5, 0xc0, 0x5, 0xbf, 0x5, 0x9d, 0x2, 0x9f, 0x2, 0x9e, 0x2, 0x1, 0x0, +0xc1, 0x5, 0x35, 0x6, 0xc2, 0x5, 0xa0, 0x2, 0x5f, 0x3, 0xa1, 0x2, 0x1, 0x0, 0x35, 0x6, 0x36, 0x6, 0xc2, 0x5, +0x5f, 0x3, 0x60, 0x3, 0xa1, 0x2, 0x1, 0x0, 0x36, 0x6, 0xc3, 0x5, 0xc2, 0x5, 0x60, 0x3, 0xa2, 0x2, 0xa1, 0x2, +0x1, 0x0, 0xc3, 0x5, 0x37, 0x6, 0xc4, 0x5, 0xa2, 0x2, 0x61, 0x3, 0xa3, 0x2, 0x1, 0x0, 0x37, 0x6, 0x38, 0x6, +0xc4, 0x5, 0x61, 0x3, 0x62, 0x3, 0xa3, 0x2, 0x1, 0x0, 0x38, 0x6, 0x39, 0x6, 0xc4, 0x5, 0x62, 0x3, 0x63, 0x3, +0xa3, 0x2, 0x1, 0x0, 0x39, 0x6, 0x3a, 0x6, 0xc4, 0x5, 0x63, 0x3, 0x64, 0x3, 0xa3, 0x2, 0x1, 0x0, 0x3a, 0x6, +0xc5, 0x5, 0xc4, 0x5, 0x64, 0x3, 0xa4, 0x2, 0xa3, 0x2, 0x1, 0x0, 0xc5, 0x5, 0x3b, 0x6, 0xc6, 0x5, 0xa4, 0x2, +0x65, 0x3, 0xa5, 0x2, 0x1, 0x0, 0x3b, 0x6, 0x3c, 0x6, 0xc6, 0x5, 0x65, 0x3, 0x66, 0x3, 0xa5, 0x2, 0x1, 0x0, +0x3c, 0x6, 0x3d, 0x6, 0xc6, 0x5, 0x66, 0x3, 0x67, 0x3, 0xa5, 0x2, 0x1, 0x0, 0x3d, 0x6, 0xc7, 0x5, 0xc6, 0x5, +0x67, 0x3, 0xa6, 0x2, 0xa5, 0x2, 0x1, 0x0, 0xc7, 0x5, 0x3e, 0x6, 0xc8, 0x5, 0xa6, 0x2, 0x68, 0x3, 0xa7, 0x2, +0x1, 0x0, 0x3e, 0x6, 0xc9, 0x5, 0xc8, 0x5, 0x68, 0x3, 0xa8, 0x2, 0xa7, 0x2, 0x1, 0x0, 0xca, 0x5, 0x3f, 0x6, +0xcb, 0x5, 0xa9, 0x2, 0x69, 0x3, 0xaa, 0x2, 0x1, 0x0, 0x3f, 0x6, 0x40, 0x6, 0xcb, 0x5, 0x69, 0x3, 0x6a, 0x3, +0xaa, 0x2, 0x1, 0x0, 0x40, 0x6, 0x41, 0x6, 0xcb, 0x5, 0x6a, 0x3, 0xd0, 0x2, 0xaa, 0x2, 0x1, 0x0, 0x41, 0x6, +0x42, 0x6, 0xcb, 0x5, 0xd0, 0x2, 0x6b, 0x3, 0xaa, 0x2, 0x1, 0x0, 0x42, 0x6, 0xcc, 0x5, 0xcb, 0x5, 0x6b, 0x3, +0xab, 0x2, 0xaa, 0x2, 0x1, 0x0, 0xcc, 0x5, 0x43, 0x6, 0xcd, 0x5, 0xab, 0x2, 0x6c, 0x3, 0xac, 0x2, 0x1, 0x0, +0x43, 0x6, 0x44, 0x6, 0xcd, 0x5, 0x6c, 0x3, 0x6d, 0x3, 0xac, 0x2, 0x1, 0x0, 0x44, 0x6, 0xce, 0x5, 0xcd, 0x5, +0x6d, 0x3, 0xad, 0x2, 0xac, 0x2, 0x1, 0x0, 0xcf, 0x5, 0xd2, 0x5, 0xd1, 0x5, 0xae, 0x2, 0xb1, 0x2, 0xb0, 0x2, +0x1, 0x0, 0xd2, 0x5, 0x45, 0x6, 0xbb, 0x5, 0xb1, 0x2, 0x6e, 0x3, 0xb2, 0x2, 0x1, 0x0, 0x45, 0x6, 0x46, 0x6, +0xbb, 0x5, 0x6e, 0x3, 0x6f, 0x3, 0xb2, 0x2, 0x1, 0x0, 0x46, 0x6, 0xb9, 0x5, 0xbb, 0x5, 0x70, 0x3, 0x70, 0x3, +0x70, 0x3, 0x1, 0x0, 0xd3, 0x5, 0x47, 0x6, 0xd4, 0x5, 0xb3, 0x2, 0x71, 0x3, 0xb3, 0x2, 0x1, 0x0, 0x47, 0x6, +0x48, 0x6, 0xd4, 0x5, 0x72, 0x3, 0x72, 0x3, 0x72, 0x3, 0x1, 0x0, 0x48, 0x6, 0xd6, 0x5, 0xd4, 0x5, 0x73, 0x3, +0xb5, 0x2, 0xb7, 0x2, 0x1, 0x0, 0xd6, 0x5, 0xd8, 0x5, 0xd7, 0x5, 0xb5, 0x2, 0xb8, 0x2, 0xb6, 0x2, 0x1, 0x0, +0xd9, 0x5, 0x49, 0x6, 0xdb, 0x5, 0xb9, 0x2, 0x74, 0x3, 0xbb, 0x2, 0x1, 0x0, 0x49, 0x6, 0x4a, 0x6, 0xdb, 0x5, +0x74, 0x3, 0x75, 0x3, 0xbb, 0x2, 0x1, 0x0, 0x4a, 0x6, 0x4b, 0x6, 0xdb, 0x5, 0x75, 0x3, 0x76, 0x3, 0xbb, 0x2, +0x1, 0x0, 0x4b, 0x6, 0xdc, 0x5, 0xdb, 0x5, 0x76, 0x3, 0xbc, 0x2, 0xbb, 0x2, 0x1, 0x0, 0xdc, 0x5, 0x4c, 0x6, +0xdd, 0x5, 0xbc, 0x2, 0x77, 0x3, 0xbd, 0x2, 0x1, 0x0, 0x4c, 0x6, 0x4d, 0x6, 0xdd, 0x5, 0x77, 0x3, 0x78, 0x3, +0xbd, 0x2, 0x1, 0x0, 0x4d, 0x6, 0x4e, 0x6, 0xdd, 0x5, 0x78, 0x3, 0x79, 0x3, 0xbd, 0x2, 0x1, 0x0, 0x4e, 0x6, +0x4f, 0x6, 0xdd, 0x5, 0x79, 0x3, 0x7a, 0x3, 0xbd, 0x2, 0x1, 0x0, 0x4f, 0x6, 0xde, 0x5, 0xdd, 0x5, 0x7a, 0x3, +0xbe, 0x2, 0xbd, 0x2, 0x1, 0x0, 0xde, 0x5, 0x50, 0x6, 0xdf, 0x5, 0xbe, 0x2, 0x7b, 0x3, 0xbf, 0x2, 0x1, 0x0, +0x50, 0x6, 0x51, 0x6, 0xdf, 0x5, 0x7b, 0x3, 0x7c, 0x3, 0xbf, 0x2, 0x1, 0x0, 0x51, 0x6, 0x52, 0x6, 0xdf, 0x5, +0x7c, 0x3, 0x7d, 0x3, 0xbf, 0x2, 0x1, 0x0, 0x52, 0x6, 0xe0, 0x5, 0xdf, 0x5, 0x7d, 0x3, 0xc0, 0x2, 0xbf, 0x2, +0x1, 0x0, 0xe0, 0x5, 0x53, 0x6, 0xe1, 0x5, 0xc0, 0x2, 0x7e, 0x3, 0xc1, 0x2, 0x1, 0x0, 0x53, 0x6, 0x54, 0x6, +0xe1, 0x5, 0x7e, 0x3, 0x7f, 0x3, 0xc1, 0x2, 0x1, 0x0, 0x54, 0x6, 0xe2, 0x5, 0xe1, 0x5, 0x7f, 0x3, 0xc2, 0x2, +0xc1, 0x2, 0x1, 0x0, 0xe2, 0x5, 0x55, 0x6, 0xe3, 0x5, 0xc2, 0x2, 0x80, 0x3, 0xc3, 0x2, 0x1, 0x0, 0x55, 0x6, +0x56, 0x6, 0xe3, 0x5, 0x80, 0x3, 0x81, 0x3, 0xc3, 0x2, 0x1, 0x0, 0x56, 0x6, 0x57, 0x6, 0xe3, 0x5, 0x81, 0x3, +0x82, 0x3, 0xc3, 0x2, 0x1, 0x0, 0x57, 0x6, 0x58, 0x6, 0xe3, 0x5, 0x82, 0x3, 0x83, 0x3, 0xc3, 0x2, 0x1, 0x0, +0x58, 0x6, 0xe4, 0x5, 0xe3, 0x5, 0x83, 0x3, 0xc4, 0x2, 0xc3, 0x2, 0x1, 0x0, 0xe4, 0x5, 0x59, 0x6, 0xe5, 0x5, +0xc4, 0x2, 0x84, 0x3, 0xc5, 0x2, 0x1, 0x0, 0x59, 0x6, 0x5a, 0x6, 0xe5, 0x5, 0x84, 0x3, 0x85, 0x3, 0xc5, 0x2, +0x1, 0x0, 0x5a, 0x6, 0xe6, 0x5, 0xe5, 0x5, 0x85, 0x3, 0xc6, 0x2, 0xc5, 0x2, 0x1, 0x0, 0xe6, 0x5, 0xe8, 0x5, +0xe7, 0x5, 0xc6, 0x2, 0xc8, 0x2, 0xc7, 0x2, 0x1, 0x0, 0xe8, 0x5, 0xea, 0x5, 0xe9, 0x5, 0xc8, 0x2, 0xca, 0x2, +0xc9, 0x2, 0x1, 0x0, 0xea, 0x5, 0x5b, 0x6, 0xd5, 0x5, 0xca, 0x2, 0x86, 0x3, 0xcb, 0x2, 0x1, 0x0, 0x5b, 0x6, +0x5c, 0x6, 0xd5, 0x5, 0x86, 0x3, 0x87, 0x3, 0xcb, 0x2, 0x1, 0x0, 0x5c, 0x6, 0xd3, 0x5, 0xd5, 0x5, 0x88, 0x3, +0x88, 0x3, 0x88, 0x3, 0x1, 0x0, 0xeb, 0x5, 0x5d, 0x6, 0xec, 0x5, 0xcc, 0x2, 0x89, 0x3, 0xcc, 0x2, 0x1, 0x0, +0x5d, 0x6, 0x5e, 0x6, 0xec, 0x5, 0x8a, 0x3, 0x8a, 0x3, 0x8a, 0x3, 0x1, 0x0, 0x5e, 0x6, 0xee, 0x5, 0xec, 0x5, +0x8b, 0x3, 0xce, 0x2, 0xd0, 0x2, 0x1, 0x0, 0xee, 0x5, 0xf0, 0x5, 0xef, 0x5, 0xce, 0x2, 0xd1, 0x2, 0xcf, 0x2, +0x1, 0x0, 0xf0, 0x5, 0xf2, 0x5, 0xf1, 0x5, 0xd1, 0x2, 0xd3, 0x2, 0xd2, 0x2, 0x1, 0x0, 0xf2, 0x5, 0x5f, 0x6, +0xf3, 0x5, 0xd3, 0x2, 0x8c, 0x3, 0xd4, 0x2, 0x1, 0x0, 0x5f, 0x6, 0x60, 0x6, 0xf3, 0x5, 0x8c, 0x3, 0x8d, 0x3, +0xd4, 0x2, 0x1, 0x0, 0x60, 0x6, 0x61, 0x6, 0xf3, 0x5, 0x8d, 0x3, 0x8e, 0x3, 0xd4, 0x2, 0x1, 0x0, 0x61, 0x6, +0xf4, 0x5, 0xf3, 0x5, 0x8e, 0x3, 0xd5, 0x2, 0xd4, 0x2, 0x1, 0x0, 0xf4, 0x5, 0x62, 0x6, 0xf5, 0x5, 0xd5, 0x2, +0x8f, 0x3, 0xd6, 0x2, 0x1, 0x0, 0x62, 0x6, 0x63, 0x6, 0xf5, 0x5, 0x8f, 0x3, 0x90, 0x3, 0xd6, 0x2, 0x1, 0x0, +0x63, 0x6, 0x64, 0x6, 0xf5, 0x5, 0x90, 0x3, 0x91, 0x3, 0xd6, 0x2, 0x1, 0x0, 0x64, 0x6, 0x65, 0x6, 0xf5, 0x5, +0x91, 0x3, 0x92, 0x3, 0xd6, 0x2, 0x1, 0x0, 0x65, 0x6, 0xf6, 0x5, 0xf5, 0x5, 0x92, 0x3, 0xd7, 0x2, 0xd6, 0x2, +0x1, 0x0, 0xf6, 0x5, 0x66, 0x6, 0xf7, 0x5, 0xd7, 0x2, 0x93, 0x3, 0xd8, 0x2, 0x1, 0x0, 0x66, 0x6, 0x67, 0x6, +0xf7, 0x5, 0x93, 0x3, 0x94, 0x3, 0xd8, 0x2, 0x1, 0x0, 0x67, 0x6, 0x68, 0x6, 0xf7, 0x5, 0x94, 0x3, 0x95, 0x3, +0xd8, 0x2, 0x1, 0x0, 0x68, 0x6, 0xf8, 0x5, 0xf7, 0x5, 0x95, 0x3, 0xd9, 0x2, 0xd8, 0x2, 0x1, 0x0, 0xf8, 0x5, +0x69, 0x6, 0xf9, 0x5, 0xd9, 0x2, 0x96, 0x3, 0xda, 0x2, 0x1, 0x0, 0x69, 0x6, 0x6a, 0x6, 0xf9, 0x5, 0x96, 0x3, +0x97, 0x3, 0xda, 0x2, 0x1, 0x0, 0x6a, 0x6, 0xfa, 0x5, 0xf9, 0x5, 0x97, 0x3, 0xdb, 0x2, 0xda, 0x2, 0x1, 0x0, +0xfa, 0x5, 0x6b, 0x6, 0xfb, 0x5, 0xdb, 0x2, 0x98, 0x3, 0xdc, 0x2, 0x1, 0x0, 0x6b, 0x6, 0x6c, 0x6, 0xfb, 0x5, +0x98, 0x3, 0x99, 0x3, 0xdc, 0x2, 0x1, 0x0, 0x6c, 0x6, 0x6d, 0x6, 0xfb, 0x5, 0x99, 0x3, 0x9a, 0x3, 0xdc, 0x2, +0x1, 0x0, 0x6d, 0x6, 0x6e, 0x6, 0xfb, 0x5, 0x9a, 0x3, 0x9b, 0x3, 0xdc, 0x2, 0x1, 0x0, 0x6e, 0x6, 0xfc, 0x5, +0xfb, 0x5, 0x9b, 0x3, 0xdd, 0x2, 0xdc, 0x2, 0x1, 0x0, 0xfc, 0x5, 0x6f, 0x6, 0xfd, 0x5, 0xdd, 0x2, 0x9c, 0x3, +0xde, 0x2, 0x1, 0x0, 0x6f, 0x6, 0x70, 0x6, 0xfd, 0x5, 0x9c, 0x3, 0x9d, 0x3, 0xde, 0x2, 0x1, 0x0, 0x70, 0x6, +0xfe, 0x5, 0xfd, 0x5, 0x9d, 0x3, 0xdf, 0x2, 0xde, 0x2, 0x1, 0x0, 0xfe, 0x5, 0x0, 0x6, 0xff, 0x5, 0xdf, 0x2, +0xe1, 0x2, 0xe0, 0x2, 0x1, 0x0, 0x0, 0x6, 0x2, 0x6, 0x1, 0x6, 0xe1, 0x2, 0xe3, 0x2, 0xe2, 0x2, 0x1, 0x0, +0x2, 0x6, 0x71, 0x6, 0xed, 0x5, 0xe3, 0x2, 0x9e, 0x3, 0xe4, 0x2, 0x1, 0x0, 0x71, 0x6, 0x72, 0x6, 0xed, 0x5, +0x9e, 0x3, 0x9f, 0x3, 0xe4, 0x2, 0x1, 0x0, 0x72, 0x6, 0xeb, 0x5, 0xed, 0x5, 0xa0, 0x3, 0xa0, 0x3, 0xa0, 0x3, +0x1, 0x0, 0x3, 0x6, 0x73, 0x6, 0x4, 0x6, 0xe5, 0x2, 0xa1, 0x3, 0xe5, 0x2, 0x1, 0x0, 0x73, 0x6, 0x74, 0x6, +0x4, 0x6, 0xa2, 0x3, 0xa2, 0x3, 0xa2, 0x3, 0x1, 0x0, 0x74, 0x6, 0x6, 0x6, 0x4, 0x6, 0xa3, 0x3, 0xe7, 0x2, +0x76, 0x2, 0x1, 0x0, 0x6, 0x6, 0x8, 0x6, 0x7, 0x6, 0xe7, 0x2, 0xe9, 0x2, 0xe8, 0x2, 0x1, 0x0, 0x8, 0x6, +0xa, 0x6, 0x9, 0x6, 0xe9, 0x2, 0xeb, 0x2, 0xea, 0x2, 0x1, 0x0, 0xa, 0x6, 0x75, 0x6, 0xb, 0x6, 0xeb, 0x2, +0xa4, 0x3, 0xec, 0x2, 0x1, 0x0, 0x75, 0x6, 0x76, 0x6, 0xb, 0x6, 0xa4, 0x3, 0xa5, 0x3, 0xec, 0x2, 0x1, 0x0, +0x76, 0x6, 0x77, 0x6, 0xb, 0x6, 0xa5, 0x3, 0xa6, 0x3, 0xec, 0x2, 0x1, 0x0, 0x77, 0x6, 0xc, 0x6, 0xb, 0x6, +0xa6, 0x3, 0xed, 0x2, 0xec, 0x2, 0x1, 0x0, 0xc, 0x6, 0x78, 0x6, 0xd, 0x6, 0xed, 0x2, 0xa7, 0x3, 0xee, 0x2, +0x1, 0x0, 0x78, 0x6, 0x79, 0x6, 0xd, 0x6, 0xa7, 0x3, 0xa8, 0x3, 0xee, 0x2, 0x1, 0x0, 0x79, 0x6, 0x7a, 0x6, +0xd, 0x6, 0xa8, 0x3, 0xa9, 0x3, 0xee, 0x2, 0x1, 0x0, 0x7a, 0x6, 0x7b, 0x6, 0xd, 0x6, 0xa9, 0x3, 0xaa, 0x3, +0xee, 0x2, 0x1, 0x0, 0x7b, 0x6, 0xe, 0x6, 0xd, 0x6, 0xaa, 0x3, 0xef, 0x2, 0xee, 0x2, 0x1, 0x0, 0xe, 0x6, +0x7c, 0x6, 0xf, 0x6, 0xef, 0x2, 0xab, 0x3, 0xf0, 0x2, 0x1, 0x0, 0x7c, 0x6, 0x7d, 0x6, 0xf, 0x6, 0xab, 0x3, +0xac, 0x3, 0xf0, 0x2, 0x1, 0x0, 0x7d, 0x6, 0x7e, 0x6, 0xf, 0x6, 0xac, 0x3, 0xad, 0x3, 0xf0, 0x2, 0x1, 0x0, +0x7e, 0x6, 0x10, 0x6, 0xf, 0x6, 0xad, 0x3, 0xf1, 0x2, 0xf0, 0x2, 0x1, 0x0, 0x10, 0x6, 0x7f, 0x6, 0x11, 0x6, +0xf1, 0x2, 0xae, 0x3, 0xf2, 0x2, 0x1, 0x0, 0x7f, 0x6, 0x80, 0x6, 0x11, 0x6, 0xae, 0x3, 0xaf, 0x3, 0xf2, 0x2, +0x1, 0x0, 0x80, 0x6, 0x12, 0x6, 0x11, 0x6, 0xaf, 0x3, 0xf3, 0x2, 0xf2, 0x2, 0x1, 0x0, 0x12, 0x6, 0x81, 0x6, +0x13, 0x6, 0xf3, 0x2, 0xb0, 0x3, 0xf4, 0x2, 0x1, 0x0, 0x81, 0x6, 0x82, 0x6, 0x13, 0x6, 0xb0, 0x3, 0xb1, 0x3, +0xf4, 0x2, 0x1, 0x0, 0x82, 0x6, 0x83, 0x6, 0x13, 0x6, 0xb1, 0x3, 0x9c, 0x2, 0xf4, 0x2, 0x1, 0x0, 0x83, 0x6, +0x84, 0x6, 0x13, 0x6, 0x9c, 0x2, 0xb2, 0x3, 0xf4, 0x2, 0x1, 0x0, 0x84, 0x6, 0x14, 0x6, 0x13, 0x6, 0xb2, 0x3, +0xf5, 0x2, 0xf4, 0x2, 0x1, 0x0, 0x14, 0x6, 0x85, 0x6, 0x15, 0x6, 0xf5, 0x2, 0xb3, 0x3, 0xf6, 0x2, 0x1, 0x0, +0x85, 0x6, 0x86, 0x6, 0x15, 0x6, 0xb3, 0x3, 0xb4, 0x3, 0xf6, 0x2, 0x1, 0x0, 0x86, 0x6, 0x16, 0x6, 0x15, 0x6, +0xb4, 0x3, 0xf7, 0x2, 0xf6, 0x2, 0x1, 0x0, 0x16, 0x6, 0x18, 0x6, 0x17, 0x6, 0xf7, 0x2, 0xf9, 0x2, 0xf8, 0x2, +0x1, 0x0, 0x18, 0x6, 0x1a, 0x6, 0x19, 0x6, 0xf9, 0x2, 0xfb, 0x2, 0xfa, 0x2, 0x1, 0x0, 0x1a, 0x6, 0x87, 0x6, +0x5, 0x6, 0xfb, 0x2, 0xb5, 0x3, 0xfc, 0x2, 0x1, 0x0, 0x87, 0x6, 0x88, 0x6, 0x5, 0x6, 0xb5, 0x3, 0xb6, 0x3, +0xfc, 0x2, 0x1, 0x0, 0x88, 0x6, 0x3, 0x6, 0x5, 0x6, 0xb7, 0x3, 0xb7, 0x3, 0xb7, 0x3, 0x1, 0x0, 0x1b, 0x6, +0x89, 0x6, 0x1c, 0x6, 0xfd, 0x2, 0xb8, 0x3, 0xfd, 0x2, 0x1, 0x0, 0x89, 0x6, 0x8a, 0x6, 0x1c, 0x6, 0xb9, 0x3, +0xb9, 0x3, 0xb9, 0x3, 0x1, 0x0, 0x8a, 0x6, 0x1e, 0x6, 0x1c, 0x6, 0xba, 0x3, 0xff, 0x2, 0x1, 0x3, 0x1, 0x0, +0x1e, 0x6, 0x20, 0x6, 0x1f, 0x6, 0xff, 0x2, 0x2, 0x3, 0x0, 0x3, 0x1, 0x0, 0x20, 0x6, 0x22, 0x6, 0x21, 0x6, +0x2, 0x3, 0x4, 0x3, 0x3, 0x3, 0x1, 0x0, 0x22, 0x6, 0x8b, 0x6, 0x23, 0x6, 0x4, 0x3, 0xbb, 0x3, 0x5, 0x3, +0x1, 0x0, 0x8b, 0x6, 0x8c, 0x6, 0x23, 0x6, 0xbb, 0x3, 0xbc, 0x3, 0x5, 0x3, 0x1, 0x0, 0x8c, 0x6, 0x8d, 0x6, +0x23, 0x6, 0xbc, 0x3, 0xbd, 0x3, 0x5, 0x3, 0x1, 0x0, 0x8d, 0x6, 0x24, 0x6, 0x23, 0x6, 0xbd, 0x3, 0x6, 0x3, +0x5, 0x3, 0x1, 0x0, 0x24, 0x6, 0x8e, 0x6, 0x25, 0x6, 0x6, 0x3, 0xbe, 0x3, 0x7, 0x3, 0x1, 0x0, 0x8e, 0x6, +0x8f, 0x6, 0x25, 0x6, 0xbe, 0x3, 0xbf, 0x3, 0x7, 0x3, 0x1, 0x0, 0x8f, 0x6, 0x90, 0x6, 0x25, 0x6, 0xbf, 0x3, +0xc0, 0x3, 0x7, 0x3, 0x1, 0x0, 0x90, 0x6, 0x91, 0x6, 0x25, 0x6, 0xc0, 0x3, 0xc1, 0x3, 0x7, 0x3, 0x1, 0x0, +0x91, 0x6, 0x26, 0x6, 0x25, 0x6, 0xc1, 0x3, 0x8, 0x3, 0x7, 0x3, 0x1, 0x0, 0x26, 0x6, 0x92, 0x6, 0x27, 0x6, +0x8, 0x3, 0xc2, 0x3, 0x9, 0x3, 0x1, 0x0, 0x92, 0x6, 0x93, 0x6, 0x27, 0x6, 0xc2, 0x3, 0xc3, 0x3, 0x9, 0x3, +0x1, 0x0, 0x93, 0x6, 0x94, 0x6, 0x27, 0x6, 0xc3, 0x3, 0xc4, 0x3, 0x9, 0x3, 0x1, 0x0, 0x94, 0x6, 0x28, 0x6, +0x27, 0x6, 0xc4, 0x3, 0xa, 0x3, 0x9, 0x3, 0x1, 0x0, 0x28, 0x6, 0x95, 0x6, 0x29, 0x6, 0xa, 0x3, 0xc5, 0x3, +0xb, 0x3, 0x1, 0x0, 0x95, 0x6, 0x96, 0x6, 0x29, 0x6, 0xc5, 0x3, 0xe0, 0x2, 0xb, 0x3, 0x1, 0x0, 0x96, 0x6, +0x2a, 0x6, 0x29, 0x6, 0xe0, 0x2, 0xc, 0x3, 0xb, 0x3, 0x1, 0x0, 0x2a, 0x6, 0x97, 0x6, 0x2b, 0x6, 0xc, 0x3, +0xc6, 0x3, 0xd, 0x3, 0x1, 0x0, 0x97, 0x6, 0x98, 0x6, 0x2b, 0x6, 0xc6, 0x3, 0xc7, 0x3, 0xd, 0x3, 0x1, 0x0, +0x98, 0x6, 0x99, 0x6, 0x2b, 0x6, 0xc7, 0x3, 0xc8, 0x3, 0xd, 0x3, 0x1, 0x0, 0x99, 0x6, 0x9a, 0x6, 0x2b, 0x6, +0xc8, 0x3, 0xc9, 0x3, 0xd, 0x3, 0x1, 0x0, 0x9a, 0x6, 0x2c, 0x6, 0x2b, 0x6, 0xc9, 0x3, 0xe, 0x3, 0xd, 0x3, +0x1, 0x0, 0x2c, 0x6, 0x9b, 0x6, 0x2d, 0x6, 0xe, 0x3, 0xca, 0x3, 0xf, 0x3, 0x1, 0x0, 0x9b, 0x6, 0x9c, 0x6, +0x2d, 0x6, 0xca, 0x3, 0xcb, 0x3, 0xf, 0x3, 0x1, 0x0, 0x9c, 0x6, 0x2e, 0x6, 0x2d, 0x6, 0xcb, 0x3, 0x10, 0x3, +0xf, 0x3, 0x1, 0x0, 0x2e, 0x6, 0x30, 0x6, 0x2f, 0x6, 0x10, 0x3, 0x12, 0x3, 0x11, 0x3, 0x1, 0x0, 0x30, 0x6, +0x32, 0x6, 0x31, 0x6, 0x12, 0x3, 0x14, 0x3, 0x13, 0x3, 0x1, 0x0, 0x32, 0x6, 0x9d, 0x6, 0x1d, 0x6, 0x14, 0x3, +0xcc, 0x3, 0x15, 0x3, 0x1, 0x0, 0x9d, 0x6, 0x9e, 0x6, 0x1d, 0x6, 0xcc, 0x3, 0xcd, 0x3, 0x15, 0x3, 0x1, 0x0, +0x9e, 0x6, 0x1b, 0x6, 0x1d, 0x6, 0xce, 0x3, 0xce, 0x3, 0xce, 0x3, 0x1, 0x0, 0xed, 0x5, 0xe3, 0x5, 0xe5, 0x5, +0x17, 0x3, 0x16, 0x3, 0x17, 0x3, 0x1, 0x0, 0x5, 0x6, 0xfb, 0x5, 0xfd, 0x5, 0x17, 0x3, 0x1a, 0x3, 0x17, 0x3, +0x1, 0x0, 0xfb, 0x5, 0x5, 0x6, 0x4, 0x6, 0x1a, 0x3, 0x17, 0x3, 0x1b, 0x3, 0x1, 0x0, 0x1d, 0x6, 0x13, 0x6, +0x15, 0x6, 0x17, 0x3, 0x1d, 0x3, 0x17, 0x3, 0x1, 0x0, 0x13, 0x6, 0x1d, 0x6, 0x1c, 0x6, 0x1d, 0x3, 0x17, 0x3, +0x1e, 0x3, 0x1, 0x0, 0xc2, 0x5, 0x8f, 0x5, 0x91, 0x5, 0x1f, 0x3, 0x27, 0x3, 0x20, 0x3, 0x1, 0x0, 0xdd, 0x5, +0x83, 0x5, 0x82, 0x5, 0x22, 0x3, 0x25, 0x3, 0x23, 0x3, 0x1, 0x0, 0x83, 0x5, 0xdf, 0x5, 0xe1, 0x5, 0x25, 0x3, +0x26, 0x3, 0x2a, 0x3, 0x1, 0x0, 0x8b, 0x5, 0x8d, 0x5, 0xc6, 0x5, 0x30, 0x3, 0x2e, 0x3, 0x2f, 0x3, 0x1, 0x0, +0xb7, 0x5, 0xe3, 0x5, 0xec, 0x5, 0x29, 0x3, 0x16, 0x3, 0x18, 0x3, 0x1, 0x0, 0xb5, 0x5, 0xb7, 0x5, 0xec, 0x5, +0x3a, 0x3, 0x29, 0x3, 0x18, 0x3, 0x1, 0x0, 0xd5, 0x5, 0xd4, 0x5, 0xcb, 0x5, 0x17, 0x3, 0x37, 0x3, 0x32, 0x3, +0x1, 0x0, 0xba, 0x5, 0xbd, 0x5, 0x93, 0x5, 0x38, 0x3, 0x34, 0x3, 0x21, 0x3, 0x1, 0x0, 0xb3, 0x5, 0xb5, 0x5, +0xef, 0x5, 0x3c, 0x3, 0x3a, 0x3, 0x3b, 0x3, 0x1, 0x0, 0xad, 0x5, 0xf9, 0x5, 0xfb, 0x5, 0x43, 0x3, 0x44, 0x3, +0x1a, 0x3, 0x1, 0x0, 0xa9, 0x5, 0xab, 0x5, 0x4, 0x6, 0x45, 0x3, 0x19, 0x3, 0x1b, 0x3, 0x1, 0x0, 0xa7, 0x5, +0xa9, 0x5, 0xb, 0x6, 0x4a, 0x3, 0x45, 0x3, 0x48, 0x3, 0x1, 0x0, 0xa7, 0x5, 0xb, 0x6, 0xd, 0x6, 0x4a, 0x3, +0x48, 0x3, 0x4b, 0x3, 0x1, 0x0, 0xa5, 0x5, 0xd, 0x6, 0xf, 0x6, 0x49, 0x3, 0x4b, 0x3, 0x4d, 0x3, 0x1, 0x0, +0xa3, 0x5, 0xf, 0x6, 0x11, 0x6, 0x4c, 0x3, 0x4d, 0x3, 0x4f, 0x3, 0x1, 0x0, 0x9d, 0x5, 0x9f, 0x5, 0x1c, 0x6, +0x50, 0x3, 0x1c, 0x3, 0x1e, 0x3, 0x1, 0x0, 0xbb, 0x5, 0xba, 0x5, 0x2b, 0x6, 0x17, 0x3, 0x38, 0x3, 0x5a, 0x3, +0x1, 0x0, 0x1d, 0x6, 0x15, 0x6, 0x17, 0x6, 0x17, 0x3, 0x17, 0x3, 0x5b, 0x3, 0x1, 0x0, 0xd5, 0x5, 0xcd, 0x5, +0xd0, 0x5, 0x17, 0x3, 0x17, 0x3, 0x17, 0x3, 0x1, 0x0, 0xe9, 0x5, 0xd5, 0x5, 0xd0, 0x5, 0x17, 0x3, 0x17, 0x3, +0x17, 0x3, 0x1, 0x0, 0x5, 0x6, 0xfd, 0x5, 0xff, 0x5, 0x17, 0x3, 0x17, 0x3, 0x17, 0x3, 0x1, 0x0, 0x19, 0x6, +0x5, 0x6, 0xff, 0x5, 0x17, 0x3, 0x17, 0x3, 0x17, 0x3, 0x1, 0x0, 0xed, 0x5, 0xe5, 0x5, 0xe7, 0x5, 0x17, 0x3, +0x17, 0x3, 0x17, 0x3, 0x1, 0x0, 0x1, 0x6, 0xed, 0x5, 0xe7, 0x5, 0x17, 0x3, 0x17, 0x3, 0x17, 0x3, 0x1, 0x0, +0xbb, 0x5, 0x2d, 0x6, 0x2f, 0x6, 0x17, 0x3, 0x17, 0x3, 0x5b, 0x3, 0x1, 0x0, 0x31, 0x6, 0xd0, 0x5, 0xd1, 0x5, +0x17, 0x3, 0x17, 0x3, 0x5b, 0x3, 0x1, 0x0, 0x9f, 0x6, 0xa0, 0x6, 0xa1, 0x6, 0xcf, 0x3, 0xd0, 0x3, 0xd0, 0x3, +0x2, 0x0, 0xa2, 0x6, 0xa0, 0x6, 0x9f, 0x6, 0xd1, 0x3, 0xd0, 0x3, 0xcf, 0x3, 0x2, 0x0, 0xa3, 0x6, 0xa2, 0x6, +0x9f, 0x6, 0xd2, 0x3, 0xd1, 0x3, 0xcf, 0x3, 0x2, 0x0, 0xa4, 0x6, 0xa2, 0x6, 0xa3, 0x6, 0xd3, 0x3, 0xd1, 0x3, +0xd2, 0x3, 0x2, 0x0, 0xa5, 0x6, 0xa4, 0x6, 0xa3, 0x6, 0xd4, 0x3, 0xd3, 0x3, 0xd2, 0x3, 0x2, 0x0, 0xa6, 0x6, +0xa4, 0x6, 0xa5, 0x6, 0xd5, 0x3, 0xd3, 0x3, 0xd4, 0x3, 0x2, 0x0, 0xa7, 0x6, 0xa6, 0x6, 0xa5, 0x6, 0xd6, 0x3, +0xd5, 0x3, 0xd4, 0x3, 0x2, 0x0, 0xa8, 0x6, 0xa6, 0x6, 0xa7, 0x6, 0xd7, 0x3, 0xd5, 0x3, 0xd6, 0x3, 0x2, 0x0, +0xa9, 0x6, 0xa8, 0x6, 0xa7, 0x6, 0xd8, 0x3, 0xd7, 0x3, 0xd6, 0x3, 0x2, 0x0, 0xaa, 0x6, 0xa8, 0x6, 0xa9, 0x6, +0xd9, 0x3, 0xd7, 0x3, 0xd8, 0x3, 0x2, 0x0, 0xab, 0x6, 0xaa, 0x6, 0xa9, 0x6, 0xda, 0x3, 0xd9, 0x3, 0xd8, 0x3, +0x2, 0x0, 0xac, 0x6, 0xaa, 0x6, 0xab, 0x6, 0xda, 0x3, 0xd9, 0x3, 0xda, 0x3, 0x2, 0x0, 0xad, 0x6, 0xae, 0x6, +0xaf, 0x6, 0xdb, 0x3, 0xdc, 0x3, 0xdc, 0x3, 0x2, 0x0, 0xb0, 0x6, 0xae, 0x6, 0xad, 0x6, 0xdd, 0x3, 0xdc, 0x3, +0xdb, 0x3, 0x2, 0x0, 0xb1, 0x6, 0xb0, 0x6, 0xad, 0x6, 0xde, 0x3, 0xdd, 0x3, 0xdb, 0x3, 0x2, 0x0, 0xb2, 0x6, +0xb0, 0x6, 0xb1, 0x6, 0xdf, 0x3, 0xdd, 0x3, 0xde, 0x3, 0x2, 0x0, 0xb3, 0x6, 0xb2, 0x6, 0xb1, 0x6, 0xe0, 0x3, +0xdf, 0x3, 0xde, 0x3, 0x2, 0x0, 0xb4, 0x6, 0xb2, 0x6, 0xb3, 0x6, 0xe1, 0x3, 0xdf, 0x3, 0xe0, 0x3, 0x2, 0x0, +0xb5, 0x6, 0xb4, 0x6, 0xb3, 0x6, 0xe2, 0x3, 0xe1, 0x3, 0xe0, 0x3, 0x2, 0x0, 0xb6, 0x6, 0xb4, 0x6, 0xb5, 0x6, +0xe3, 0x3, 0xe1, 0x3, 0xe2, 0x3, 0x2, 0x0, 0xb7, 0x6, 0xb6, 0x6, 0xb5, 0x6, 0xe4, 0x3, 0xe3, 0x3, 0xe2, 0x3, +0x2, 0x0, 0xb8, 0x6, 0xb6, 0x6, 0xb7, 0x6, 0xe5, 0x3, 0xe3, 0x3, 0xe4, 0x3, 0x2, 0x0, 0xb9, 0x6, 0xb8, 0x6, +0xb7, 0x6, 0xe6, 0x3, 0xe5, 0x3, 0xe4, 0x3, 0x2, 0x0, 0xba, 0x6, 0xb8, 0x6, 0xb9, 0x6, 0xe6, 0x3, 0xe5, 0x3, +0xe6, 0x3, 0x2, 0x0, 0xbb, 0x6, 0xbc, 0x6, 0xbd, 0x6, 0xe7, 0x3, 0xe8, 0x3, 0xe7, 0x3, 0x2, 0x0, 0xbb, 0x6, +0xbe, 0x6, 0xbc, 0x6, 0xe7, 0x3, 0xe9, 0x3, 0xe8, 0x3, 0x2, 0x0, 0xbe, 0x6, 0xbf, 0x6, 0xbc, 0x6, 0xe9, 0x3, +0xea, 0x3, 0xe8, 0x3, 0x2, 0x0, 0xbe, 0x6, 0xc0, 0x6, 0xbf, 0x6, 0xe9, 0x3, 0xeb, 0x3, 0xea, 0x3, 0x2, 0x0, +0xc0, 0x6, 0xc1, 0x6, 0xbf, 0x6, 0xeb, 0x3, 0xec, 0x3, 0xea, 0x3, 0x2, 0x0, 0xc0, 0x6, 0xc2, 0x6, 0xc1, 0x6, +0xeb, 0x3, 0xed, 0x3, 0xec, 0x3, 0x2, 0x0, 0xc2, 0x6, 0xc3, 0x6, 0xc1, 0x6, 0xed, 0x3, 0xee, 0x3, 0xec, 0x3, +0x2, 0x0, 0xc2, 0x6, 0xc4, 0x6, 0xc3, 0x6, 0xed, 0x3, 0xef, 0x3, 0xee, 0x3, 0x2, 0x0, 0xc4, 0x6, 0xc5, 0x6, +0xc3, 0x6, 0xef, 0x3, 0xf0, 0x3, 0xee, 0x3, 0x2, 0x0, 0xc4, 0x6, 0xc6, 0x6, 0xc5, 0x6, 0xef, 0x3, 0xf1, 0x3, +0xf0, 0x3, 0x2, 0x0, 0xc6, 0x6, 0xc7, 0x6, 0xc5, 0x6, 0xf1, 0x3, 0xf2, 0x3, 0xf0, 0x3, 0x2, 0x0, 0xc6, 0x6, +0xc8, 0x6, 0xc7, 0x6, 0xf1, 0x3, 0xf2, 0x3, 0xf2, 0x3, 0x2, 0x0, 0xc9, 0x6, 0xca, 0x6, 0xcb, 0x6, 0xf3, 0x3, +0xf4, 0x3, 0xf3, 0x3, 0x2, 0x0, 0xc9, 0x6, 0xcc, 0x6, 0xca, 0x6, 0xf3, 0x3, 0xf5, 0x3, 0xf4, 0x3, 0x2, 0x0, +0xcc, 0x6, 0xcd, 0x6, 0xca, 0x6, 0xf5, 0x3, 0xf6, 0x3, 0xf4, 0x3, 0x2, 0x0, 0xcc, 0x6, 0xce, 0x6, 0xcd, 0x6, +0xf5, 0x3, 0xf7, 0x3, 0xf6, 0x3, 0x2, 0x0, 0xce, 0x6, 0xcf, 0x6, 0xcd, 0x6, 0xf7, 0x3, 0xf8, 0x3, 0xf6, 0x3, +0x2, 0x0, 0xce, 0x6, 0xd0, 0x6, 0xcf, 0x6, 0xf7, 0x3, 0xf9, 0x3, 0xf8, 0x3, 0x2, 0x0, 0xd0, 0x6, 0xd1, 0x6, +0xcf, 0x6, 0xf9, 0x3, 0xfa, 0x3, 0xf8, 0x3, 0x2, 0x0, 0xd0, 0x6, 0xd2, 0x6, 0xd1, 0x6, 0xf9, 0x3, 0xfb, 0x3, +0xfa, 0x3, 0x2, 0x0, 0xd2, 0x6, 0xd3, 0x6, 0xd1, 0x6, 0xfb, 0x3, 0xfc, 0x3, 0xfa, 0x3, 0x2, 0x0, 0xd2, 0x6, +0xd4, 0x6, 0xd3, 0x6, 0xfb, 0x3, 0xfd, 0x3, 0xfc, 0x3, 0x2, 0x0, 0xd4, 0x6, 0xd5, 0x6, 0xd3, 0x6, 0xfd, 0x3, +0xfe, 0x3, 0xfc, 0x3, 0x2, 0x0, 0xd4, 0x6, 0xd6, 0x6, 0xd5, 0x6, 0xfd, 0x3, 0xfe, 0x3, 0xfe, 0x3, 0x2, 0x0, +0x2c, 0x0, 0x2d, 0x0, 0x2e, 0x0, 0xc, 0x4, 0xc, 0x4, 0xc, 0x4, 0x2, 0x0, 0x2f, 0x0, 0x2e, 0x0, 0x2d, 0x0, +0xc, 0x4, 0xc, 0x4, 0xc, 0x4, 0x2, 0x0, 0x30, 0x0, 0x31, 0x0, 0x32, 0x0, 0xd, 0x4, 0xd, 0x4, 0xd, 0x4, +0x2, 0x0, 0x33, 0x0, 0x32, 0x0, 0x31, 0x0, 0xd, 0x4, 0xd, 0x4, 0xd, 0x4, 0x2, 0x0, 0x34, 0x0, 0x35, 0x0, +0x36, 0x0, 0xc, 0x4, 0xc, 0x4, 0xc, 0x4, 0x2, 0x0, 0x36, 0x0, 0x37, 0x0, 0x34, 0x0, 0xc, 0x4, 0xc, 0x4, +0xc, 0x4, 0x2, 0x0, 0x38, 0x0, 0x39, 0x0, 0x3a, 0x0, 0xe, 0x4, 0xe, 0x4, 0xe, 0x4, 0x2, 0x0, 0x3a, 0x0, +0x3b, 0x0, 0x38, 0x0, 0xe, 0x4, 0xe, 0x4, 0xe, 0x4, 0x2, 0x0, 0x1c, 0x0, 0x1d, 0x0, 0x1e, 0x0, 0xb, 0x4, +0xb, 0x4, 0xb, 0x4, 0x3, 0x0, 0x1f, 0x0, 0x20, 0x0, 0x21, 0x0, 0xc, 0x4, 0xc, 0x4, 0xc, 0x4, 0x3, 0x0, +0x1f, 0x0, 0x22, 0x0, 0x23, 0x0, 0xa, 0x4, 0xa, 0x4, 0xa, 0x4, 0x3, 0x0, 0x24, 0x0, 0x1f, 0x0, 0x1d, 0x0, +0xd, 0x4, 0xd, 0x4, 0xd, 0x4, 0x3, 0x0, 0x25, 0x0, 0x24, 0x0, 0x26, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, +0x3, 0x0, 0x22, 0x0, 0x25, 0x0, 0x27, 0x0, 0xe, 0x4, 0xe, 0x4, 0xe, 0x4, 0x3, 0x0, 0x23, 0x0, 0x27, 0x0, +0x1e, 0x0, 0xb, 0x4, 0xb, 0x4, 0xb, 0x4, 0x3, 0x0, 0x26, 0x0, 0x1d, 0x0, 0x1c, 0x0, 0xb, 0x4, 0xb, 0x4, +0xb, 0x4, 0x3, 0x0, 0x28, 0x0, 0x26, 0x0, 0x1c, 0x0, 0xb, 0x4, 0xb, 0x4, 0xb, 0x4, 0x3, 0x0, 0x1f, 0x0, +0x24, 0x0, 0x20, 0x0, 0xc, 0x4, 0xc, 0x4, 0xc, 0x4, 0x3, 0x0, 0x25, 0x0, 0x22, 0x0, 0x21, 0x0, 0xc, 0x4, +0xc, 0x4, 0xc, 0x4, 0x3, 0x0, 0x20, 0x0, 0x24, 0x0, 0x29, 0x0, 0xc, 0x4, 0xc, 0x4, 0xc, 0x4, 0x3, 0x0, +0x27, 0x0, 0x26, 0x0, 0x28, 0x0, 0xb, 0x4, 0xb, 0x4, 0xb, 0x4, 0x3, 0x0, 0x2a, 0x0, 0x27, 0x0, 0x28, 0x0, +0xb, 0x4, 0xb, 0x4, 0xb, 0x4, 0x3, 0x0, 0x24, 0x0, 0x25, 0x0, 0x29, 0x0, 0xc, 0x4, 0xc, 0x4, 0xc, 0x4, +0x3, 0x0, 0x29, 0x0, 0x25, 0x0, 0x2b, 0x0, 0xc, 0x4, 0xc, 0x4, 0xc, 0x4, 0x3, 0x0, 0x1e, 0x0, 0x27, 0x0, +0x2a, 0x0, 0xb, 0x4, 0xb, 0x4, 0xb, 0x4, 0x3, 0x0, 0x25, 0x0, 0x21, 0x0, 0x2b, 0x0, 0xc, 0x4, 0xc, 0x4, +0xc, 0x4, 0x3, 0x0, 0x2a, 0x0, 0x28, 0x0, 0x2b, 0x0, 0xf, 0x4, 0xf, 0x4, 0xf, 0x4, 0x3, 0x0, 0x21, 0x0, +0x1c, 0x0, 0x1e, 0x0, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x3, 0x0, 0x1e, 0x0, 0x2a, 0x0, 0x21, 0x0, 0x11, 0x4, +0x11, 0x4, 0x11, 0x4, 0x3, 0x0, 0x20, 0x0, 0x28, 0x0, 0x1c, 0x0, 0x12, 0x4, 0x12, 0x4, 0x12, 0x4, 0x3, 0x0, +0x21, 0x0, 0x20, 0x0, 0x1c, 0x0, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x3, 0x0, 0x29, 0x0, 0x2b, 0x0, 0x28, 0x0, +0xf, 0x4, 0xf, 0x4, 0xf, 0x4, 0x3, 0x0, 0x20, 0x0, 0x29, 0x0, 0x28, 0x0, 0x12, 0x4, 0x12, 0x4, 0x12, 0x4, +0x3, 0x0, 0x23, 0x0, 0x1e, 0x0, 0x1d, 0x0, 0xb, 0x4, 0xb, 0x4, 0xb, 0x4, 0x3, 0x0, 0x21, 0x0, 0x22, 0x0, +0x1f, 0x0, 0xc, 0x4, 0xc, 0x4, 0xc, 0x4, 0x3, 0x0, 0x23, 0x0, 0x1d, 0x0, 0x1f, 0x0, 0xa, 0x4, 0xa, 0x4, +0xa, 0x4, 0x3, 0x0, 0x1d, 0x0, 0x26, 0x0, 0x24, 0x0, 0xd, 0x4, 0xd, 0x4, 0xd, 0x4, 0x3, 0x0, 0x26, 0x0, +0x27, 0x0, 0x25, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x3, 0x0, 0x27, 0x0, 0x23, 0x0, 0x22, 0x0, 0xe, 0x4, +0xe, 0x4, 0xe, 0x4, 0x3, 0x0, 0x2b, 0x0, 0x21, 0x0, 0x2a, 0x0, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x3, 0x0, +0x3a, 0x2, 0x3b, 0x2, 0x3c, 0x2, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x4, 0x0, 0x3d, 0x2, 0x3a, 0x2, 0x3c, 0x2, +0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x4, 0x0, 0x3d, 0x2, 0x3c, 0x2, 0x3e, 0x2, 0x13, 0x4, 0x13, 0x4, 0x14, 0x4, +0x4, 0x0, 0x3d, 0x2, 0x3e, 0x2, 0x3f, 0x2, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0x4, 0x0, 0x40, 0x2, 0x41, 0x2, +0x42, 0x2, 0x13, 0x4, 0x15, 0x4, 0x13, 0x4, 0x4, 0x0, 0x43, 0x2, 0x40, 0x2, 0x42, 0x2, 0x15, 0x4, 0x13, 0x4, +0x13, 0x4, 0x4, 0x0, 0x3d, 0x2, 0x3f, 0x2, 0x44, 0x2, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0x4, 0x0, 0x3d, 0x2, +0x44, 0x2, 0x45, 0x2, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0x4, 0x0, 0x46, 0x2, 0x3d, 0x2, 0x45, 0x2, 0x16, 0x4, +0x13, 0x4, 0x14, 0x4, 0x4, 0x0, 0x46, 0x2, 0x45, 0x2, 0x47, 0x2, 0x16, 0x4, 0x14, 0x4, 0x17, 0x4, 0x4, 0x0, +0x48, 0x2, 0x46, 0x2, 0x47, 0x2, 0x18, 0x4, 0x16, 0x4, 0x17, 0x4, 0x4, 0x0, 0x49, 0x2, 0x48, 0x2, 0x47, 0x2, +0x19, 0x4, 0x18, 0x4, 0x17, 0x4, 0x4, 0x0, 0x4a, 0x2, 0x49, 0x2, 0x47, 0x2, 0x1a, 0x4, 0x19, 0x4, 0x17, 0x4, +0x4, 0x0, 0x4b, 0x2, 0x4a, 0x2, 0x47, 0x2, 0x1b, 0x4, 0x1a, 0x4, 0x17, 0x4, 0x4, 0x0, 0x4c, 0x2, 0x4b, 0x2, +0x47, 0x2, 0x1c, 0x4, 0x1b, 0x4, 0x17, 0x4, 0x4, 0x0, 0x4d, 0x2, 0x4c, 0x2, 0x47, 0x2, 0x1d, 0x4, 0x1c, 0x4, +0x17, 0x4, 0x4, 0x0, 0x4e, 0x2, 0x43, 0x2, 0x42, 0x2, 0x1e, 0x4, 0x15, 0x4, 0x13, 0x4, 0x4, 0x0, 0x4d, 0x2, +0x47, 0x2, 0x4f, 0x2, 0x1d, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, 0x50, 0x2, 0x4d, 0x2, 0x4f, 0x2, 0x1f, 0x4, +0x1d, 0x4, 0x17, 0x4, 0x4, 0x0, 0x51, 0x2, 0x50, 0x2, 0x4f, 0x2, 0x20, 0x4, 0x1f, 0x4, 0x17, 0x4, 0x4, 0x0, +0x52, 0x2, 0x51, 0x2, 0x4f, 0x2, 0x21, 0x4, 0x20, 0x4, 0x17, 0x4, 0x4, 0x0, 0x53, 0x2, 0x52, 0x2, 0x4f, 0x2, +0x22, 0x4, 0x21, 0x4, 0x17, 0x4, 0x4, 0x0, 0x54, 0x2, 0x53, 0x2, 0x4f, 0x2, 0x23, 0x4, 0x22, 0x4, 0x17, 0x4, +0x4, 0x0, 0x55, 0x2, 0x54, 0x2, 0x4f, 0x2, 0x1d, 0x4, 0x23, 0x4, 0x17, 0x4, 0x4, 0x0, 0x55, 0x2, 0x4f, 0x2, +0x56, 0x2, 0x1d, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, 0x57, 0x2, 0x55, 0x2, 0x56, 0x2, 0x24, 0x4, 0x1d, 0x4, +0x17, 0x4, 0x4, 0x0, 0x58, 0x2, 0x57, 0x2, 0x56, 0x2, 0x25, 0x4, 0x24, 0x4, 0x17, 0x4, 0x4, 0x0, 0x59, 0x2, +0x58, 0x2, 0x56, 0x2, 0x26, 0x4, 0x25, 0x4, 0x17, 0x4, 0x4, 0x0, 0x5a, 0x2, 0x59, 0x2, 0x56, 0x2, 0x27, 0x4, +0x26, 0x4, 0x17, 0x4, 0x4, 0x0, 0x5a, 0x2, 0x56, 0x2, 0x5b, 0x2, 0x27, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, +0x5c, 0x2, 0x5a, 0x2, 0x5b, 0x2, 0x28, 0x4, 0x27, 0x4, 0x17, 0x4, 0x4, 0x0, 0x5d, 0x2, 0x5c, 0x2, 0x5b, 0x2, +0x29, 0x4, 0x28, 0x4, 0x17, 0x4, 0x4, 0x0, 0x5e, 0x2, 0x5d, 0x2, 0x5b, 0x2, 0x27, 0x4, 0x29, 0x4, 0x17, 0x4, +0x4, 0x0, 0x4e, 0x2, 0x42, 0x2, 0x5f, 0x2, 0x1e, 0x4, 0x13, 0x4, 0x2a, 0x4, 0x4, 0x0, 0x5e, 0x2, 0x5b, 0x2, +0x60, 0x2, 0x27, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, 0x61, 0x2, 0x5e, 0x2, 0x60, 0x2, 0x2b, 0x4, 0x27, 0x4, +0x17, 0x4, 0x4, 0x0, 0x62, 0x2, 0x61, 0x2, 0x60, 0x2, 0x29, 0x4, 0x2b, 0x4, 0x17, 0x4, 0x4, 0x0, 0x63, 0x2, +0x62, 0x2, 0x60, 0x2, 0x27, 0x4, 0x29, 0x4, 0x17, 0x4, 0x4, 0x0, 0x63, 0x2, 0x60, 0x2, 0x64, 0x2, 0x27, 0x4, +0x17, 0x4, 0x17, 0x4, 0x4, 0x0, 0x65, 0x2, 0x63, 0x2, 0x64, 0x2, 0x2c, 0x4, 0x27, 0x4, 0x17, 0x4, 0x4, 0x0, +0x66, 0x2, 0x65, 0x2, 0x64, 0x2, 0x2d, 0x4, 0x2c, 0x4, 0x17, 0x4, 0x4, 0x0, 0x66, 0x2, 0x64, 0x2, 0x67, 0x2, +0x2d, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, 0x68, 0x2, 0x66, 0x2, 0x67, 0x2, 0x25, 0x4, 0x2d, 0x4, 0x17, 0x4, +0x4, 0x0, 0x69, 0x2, 0x68, 0x2, 0x67, 0x2, 0x2d, 0x4, 0x25, 0x4, 0x17, 0x4, 0x4, 0x0, 0x69, 0x2, 0x67, 0x2, +0x6a, 0x2, 0x2d, 0x4, 0x17, 0x4, 0x15, 0x4, 0x4, 0x0, 0x6b, 0x2, 0x69, 0x2, 0x6a, 0x2, 0x15, 0x4, 0x2d, 0x4, +0x15, 0x4, 0x4, 0x0, 0x6c, 0x2, 0x6b, 0x2, 0x6a, 0x2, 0x13, 0x4, 0x15, 0x4, 0x15, 0x4, 0x4, 0x0, 0x6c, 0x2, +0x6a, 0x2, 0x6d, 0x2, 0x13, 0x4, 0x15, 0x4, 0x17, 0x4, 0x4, 0x0, 0x6c, 0x2, 0x6d, 0x2, 0x6e, 0x2, 0x13, 0x4, +0x17, 0x4, 0x1e, 0x4, 0x4, 0x0, 0x6c, 0x2, 0x6e, 0x2, 0x6f, 0x2, 0x13, 0x4, 0x1e, 0x4, 0x2e, 0x4, 0x4, 0x0, +0x6c, 0x2, 0x6f, 0x2, 0x70, 0x2, 0x13, 0x4, 0x2e, 0x4, 0x15, 0x4, 0x4, 0x0, 0x6c, 0x2, 0x70, 0x2, 0x71, 0x2, +0x13, 0x4, 0x15, 0x4, 0x2f, 0x4, 0x4, 0x0, 0x72, 0x2, 0x6c, 0x2, 0x71, 0x2, 0x30, 0x4, 0x13, 0x4, 0x2f, 0x4, +0x4, 0x0, 0x73, 0x2, 0x72, 0x2, 0x71, 0x2, 0x31, 0x4, 0x30, 0x4, 0x2f, 0x4, 0x4, 0x0, 0x74, 0x2, 0x73, 0x2, +0x71, 0x2, 0x32, 0x4, 0x31, 0x4, 0x2f, 0x4, 0x4, 0x0, 0x75, 0x2, 0x4e, 0x2, 0x5f, 0x2, 0x1e, 0x4, 0x1e, 0x4, +0x2a, 0x4, 0x4, 0x0, 0x75, 0x2, 0x5f, 0x2, 0x76, 0x2, 0x1e, 0x4, 0x2a, 0x4, 0x30, 0x4, 0x4, 0x0, 0x75, 0x2, +0x76, 0x2, 0x77, 0x2, 0x1e, 0x4, 0x30, 0x4, 0x32, 0x4, 0x4, 0x0, 0x78, 0x2, 0x75, 0x2, 0x77, 0x2, 0x17, 0x4, +0x1e, 0x4, 0x32, 0x4, 0x4, 0x0, 0x78, 0x2, 0x77, 0x2, 0x79, 0x2, 0x17, 0x4, 0x32, 0x4, 0x17, 0x4, 0x4, 0x0, +0x7a, 0x2, 0x78, 0x2, 0x79, 0x2, 0x14, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, 0x7b, 0x2, 0x7a, 0x2, 0x79, 0x2, +0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x4, 0x0, 0x7b, 0x2, 0x79, 0x2, 0x7c, 0x2, 0x33, 0x4, 0x17, 0x4, 0x34, 0x4, +0x4, 0x0, 0x7d, 0x2, 0x7b, 0x2, 0x7c, 0x2, 0x14, 0x4, 0x33, 0x4, 0x34, 0x4, 0x4, 0x0, 0x7e, 0x2, 0x7d, 0x2, +0x7c, 0x2, 0x14, 0x4, 0x14, 0x4, 0x34, 0x4, 0x4, 0x0, 0x7f, 0x2, 0x7e, 0x2, 0x7c, 0x2, 0x17, 0x4, 0x14, 0x4, +0x34, 0x4, 0x4, 0x0, 0x7f, 0x2, 0x7c, 0x2, 0x80, 0x2, 0x17, 0x4, 0x34, 0x4, 0x17, 0x4, 0x4, 0x0, 0x81, 0x2, +0x7f, 0x2, 0x80, 0x2, 0x14, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, 0x82, 0x2, 0x81, 0x2, 0x80, 0x2, 0x17, 0x4, +0x14, 0x4, 0x17, 0x4, 0x4, 0x0, 0x82, 0x2, 0x80, 0x2, 0x83, 0x2, 0x17, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, +0x84, 0x2, 0x82, 0x2, 0x83, 0x2, 0x14, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, 0x85, 0x2, 0x84, 0x2, 0x83, 0x2, +0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x4, 0x0, 0x85, 0x2, 0x83, 0x2, 0x86, 0x2, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, +0x4, 0x0, 0x87, 0x2, 0x85, 0x2, 0x86, 0x2, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0x4, 0x0, 0x88, 0x2, 0x87, 0x2, +0x86, 0x2, 0x17, 0x4, 0x14, 0x4, 0x17, 0x4, 0x4, 0x0, 0x88, 0x2, 0x86, 0x2, 0x89, 0x2, 0x17, 0x4, 0x17, 0x4, +0x32, 0x4, 0x4, 0x0, 0x8a, 0x2, 0x88, 0x2, 0x89, 0x2, 0x17, 0x4, 0x17, 0x4, 0x32, 0x4, 0x4, 0x0, 0x8a, 0x2, +0x89, 0x2, 0x8b, 0x2, 0x17, 0x4, 0x32, 0x4, 0x32, 0x4, 0x4, 0x0, 0x8c, 0x2, 0x8a, 0x2, 0x8b, 0x2, 0x17, 0x4, +0x17, 0x4, 0x32, 0x4, 0x4, 0x0, 0x8c, 0x2, 0x8b, 0x2, 0x8d, 0x2, 0x17, 0x4, 0x32, 0x4, 0x32, 0x4, 0x4, 0x0, +0x8e, 0x2, 0x8c, 0x2, 0x8d, 0x2, 0x17, 0x4, 0x17, 0x4, 0x32, 0x4, 0x4, 0x0, 0x8e, 0x2, 0x8d, 0x2, 0x8f, 0x2, +0x17, 0x4, 0x32, 0x4, 0x32, 0x4, 0x4, 0x0, 0x90, 0x2, 0x8e, 0x2, 0x8f, 0x2, 0x33, 0x4, 0x17, 0x4, 0x32, 0x4, +0x4, 0x0, 0x90, 0x2, 0x8f, 0x2, 0x91, 0x2, 0x33, 0x4, 0x32, 0x4, 0x32, 0x4, 0x4, 0x0, 0x92, 0x2, 0x90, 0x2, +0x91, 0x2, 0x17, 0x4, 0x33, 0x4, 0x32, 0x4, 0x4, 0x0, 0x92, 0x2, 0x91, 0x2, 0x93, 0x2, 0x17, 0x4, 0x32, 0x4, +0x30, 0x4, 0x4, 0x0, 0x92, 0x2, 0x93, 0x2, 0x94, 0x2, 0x17, 0x4, 0x30, 0x4, 0x27, 0x4, 0x4, 0x0, 0x95, 0x2, +0x92, 0x2, 0x94, 0x2, 0x33, 0x4, 0x17, 0x4, 0x27, 0x4, 0x4, 0x0, 0x95, 0x2, 0x94, 0x2, 0x96, 0x2, 0x33, 0x4, +0x27, 0x4, 0x27, 0x4, 0x4, 0x0, 0x97, 0x2, 0x95, 0x2, 0x96, 0x2, 0x17, 0x4, 0x33, 0x4, 0x27, 0x4, 0x4, 0x0, +0x97, 0x2, 0x96, 0x2, 0x98, 0x2, 0x17, 0x4, 0x27, 0x4, 0x31, 0x4, 0x4, 0x0, 0x97, 0x2, 0x98, 0x2, 0x99, 0x2, +0x17, 0x4, 0x31, 0x4, 0x32, 0x4, 0x4, 0x0, 0x9a, 0x2, 0x97, 0x2, 0x99, 0x2, 0x17, 0x4, 0x17, 0x4, 0x32, 0x4, +0x4, 0x0, 0x9a, 0x2, 0x99, 0x2, 0x9b, 0x2, 0x17, 0x4, 0x32, 0x4, 0x30, 0x4, 0x4, 0x0, 0x9a, 0x2, 0x9b, 0x2, +0x9c, 0x2, 0x17, 0x4, 0x30, 0x4, 0x32, 0x4, 0x4, 0x0, 0x9d, 0x2, 0x9a, 0x2, 0x9c, 0x2, 0x17, 0x4, 0x17, 0x4, +0x32, 0x4, 0x4, 0x0, 0x9d, 0x2, 0x9c, 0x2, 0x9e, 0x2, 0x17, 0x4, 0x32, 0x4, 0x35, 0x4, 0x4, 0x0, 0x9d, 0x2, +0x9e, 0x2, 0x9f, 0x2, 0x17, 0x4, 0x35, 0x4, 0x32, 0x4, 0x4, 0x0, 0xa0, 0x2, 0x9d, 0x2, 0x9f, 0x2, 0x17, 0x4, +0x17, 0x4, 0x32, 0x4, 0x4, 0x0, 0xa0, 0x2, 0x9f, 0x2, 0xa1, 0x2, 0x17, 0x4, 0x32, 0x4, 0x32, 0x4, 0x4, 0x0, +0xa2, 0x2, 0xa0, 0x2, 0xa1, 0x2, 0x17, 0x4, 0x17, 0x4, 0x32, 0x4, 0x4, 0x0, 0xa2, 0x2, 0xa1, 0x2, 0xa3, 0x2, +0x17, 0x4, 0x32, 0x4, 0x30, 0x4, 0x4, 0x0, 0xa2, 0x2, 0xa3, 0x2, 0xa4, 0x2, 0x17, 0x4, 0x30, 0x4, 0x27, 0x4, +0x4, 0x0, 0xa5, 0x2, 0xa2, 0x2, 0xa4, 0x2, 0x33, 0x4, 0x17, 0x4, 0x27, 0x4, 0x4, 0x0, 0xa5, 0x2, 0xa4, 0x2, +0xa6, 0x2, 0x33, 0x4, 0x27, 0x4, 0x27, 0x4, 0x4, 0x0, 0xa7, 0x2, 0xa5, 0x2, 0xa6, 0x2, 0x33, 0x4, 0x33, 0x4, +0x27, 0x4, 0x4, 0x0, 0xa7, 0x2, 0xa6, 0x2, 0xa8, 0x2, 0x33, 0x4, 0x27, 0x4, 0x32, 0x4, 0x4, 0x0, 0xa9, 0x2, +0xa7, 0x2, 0xa8, 0x2, 0x13, 0x4, 0x33, 0x4, 0x32, 0x4, 0x4, 0x0, 0xa9, 0x2, 0xa8, 0x2, 0xaa, 0x2, 0x13, 0x4, +0x32, 0x4, 0x15, 0x4, 0x4, 0x0, 0xa9, 0x2, 0xaa, 0x2, 0xab, 0x2, 0x13, 0x4, 0x15, 0x4, 0x13, 0x4, 0x4, 0x0, +0xac, 0x2, 0xa9, 0x2, 0xab, 0x2, 0x17, 0x4, 0x13, 0x4, 0x13, 0x4, 0x4, 0x0, 0xad, 0x2, 0xac, 0x2, 0xab, 0x2, +0x15, 0x4, 0x17, 0x4, 0x13, 0x4, 0x4, 0x0, 0xae, 0x2, 0xad, 0x2, 0xab, 0x2, 0x15, 0x4, 0x15, 0x4, 0x13, 0x4, +0x4, 0x0, 0xae, 0x2, 0xab, 0x2, 0xaf, 0x2, 0x15, 0x4, 0x13, 0x4, 0x36, 0x4, 0x4, 0x0, 0xae, 0x2, 0xaf, 0x2, +0xb0, 0x2, 0x15, 0x4, 0x36, 0x4, 0x26, 0x4, 0x4, 0x0, 0xae, 0x2, 0xb0, 0x2, 0xb1, 0x2, 0x15, 0x4, 0x26, 0x4, +0x37, 0x4, 0x4, 0x0, 0xae, 0x2, 0xb1, 0x2, 0xb2, 0x2, 0x15, 0x4, 0x37, 0x4, 0x27, 0x4, 0x4, 0x0, 0x74, 0x2, +0x71, 0x2, 0xb3, 0x2, 0x32, 0x4, 0x2f, 0x4, 0x17, 0x4, 0x4, 0x0, 0xb4, 0x2, 0x74, 0x2, 0xb3, 0x2, 0x38, 0x4, +0x32, 0x4, 0x17, 0x4, 0x4, 0x0, 0xb5, 0x2, 0xae, 0x2, 0xb2, 0x2, 0x33, 0x4, 0x15, 0x4, 0x27, 0x4, 0x4, 0x0, +0xb5, 0x2, 0xb2, 0x2, 0xb6, 0x2, 0x33, 0x4, 0x27, 0x4, 0x27, 0x4, 0x4, 0x0, 0xb7, 0x2, 0xb5, 0x2, 0xb6, 0x2, +0x33, 0x4, 0x33, 0x4, 0x27, 0x4, 0x4, 0x0, 0xb7, 0x2, 0xb6, 0x2, 0xb8, 0x2, 0x33, 0x4, 0x27, 0x4, 0x17, 0x4, +0x4, 0x0, 0xb9, 0x2, 0xb7, 0x2, 0xb8, 0x2, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0x4, 0x0, 0xba, 0x2, 0xb9, 0x2, +0xb8, 0x2, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x4, 0x0, 0xba, 0x2, 0xb8, 0x2, 0xbb, 0x2, 0x33, 0x4, 0x17, 0x4, +0x34, 0x4, 0x4, 0x0, 0xbc, 0x2, 0xba, 0x2, 0xbb, 0x2, 0x14, 0x4, 0x33, 0x4, 0x34, 0x4, 0x4, 0x0, 0xbd, 0x2, +0xbc, 0x2, 0xbb, 0x2, 0x14, 0x4, 0x14, 0x4, 0x34, 0x4, 0x4, 0x0, 0xbe, 0x2, 0xbd, 0x2, 0xbb, 0x2, 0x17, 0x4, +0x14, 0x4, 0x34, 0x4, 0x4, 0x0, 0xbe, 0x2, 0xbb, 0x2, 0xbf, 0x2, 0x17, 0x4, 0x34, 0x4, 0x32, 0x4, 0x4, 0x0, +0xc0, 0x2, 0xbe, 0x2, 0xbf, 0x2, 0x17, 0x4, 0x17, 0x4, 0x32, 0x4, 0x4, 0x0, 0xc0, 0x2, 0xbf, 0x2, 0xc1, 0x2, +0x17, 0x4, 0x32, 0x4, 0x17, 0x4, 0x4, 0x0, 0xc2, 0x2, 0xc0, 0x2, 0xc1, 0x2, 0x14, 0x4, 0x17, 0x4, 0x17, 0x4, +0x4, 0x0, 0xc3, 0x2, 0xc2, 0x2, 0xc1, 0x2, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x4, 0x0, 0xc3, 0x2, 0xc1, 0x2, +0xc4, 0x2, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, 0x4, 0x0, 0xc5, 0x2, 0xc3, 0x2, 0xc4, 0x2, 0x14, 0x4, 0x33, 0x4, +0x17, 0x4, 0x4, 0x0, 0xc6, 0x2, 0xc5, 0x2, 0xc4, 0x2, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x4, 0x0, 0xc6, 0x2, +0xc4, 0x2, 0xc7, 0x2, 0x33, 0x4, 0x17, 0x4, 0x27, 0x4, 0x4, 0x0, 0xb3, 0x2, 0xc6, 0x2, 0xc7, 0x2, 0x17, 0x4, +0x33, 0x4, 0x27, 0x4, 0x4, 0x0, 0xb4, 0x2, 0xb3, 0x2, 0xc7, 0x2, 0x38, 0x4, 0x17, 0x4, 0x27, 0x4, 0x4, 0x0, +0x3c, 0x0, 0x3d, 0x0, 0x3e, 0x0, 0x61, 0x4, 0x62, 0x4, 0x63, 0x4, 0x4, 0x0, 0x3c, 0x0, 0x3e, 0x0, 0x3f, 0x0, +0x61, 0x4, 0x63, 0x4, 0x64, 0x4, 0x4, 0x0, 0x40, 0x0, 0x41, 0x0, 0x3c, 0x0, 0x65, 0x4, 0x66, 0x4, 0x61, 0x4, +0x4, 0x0, 0x42, 0x0, 0x40, 0x0, 0x3c, 0x0, 0x67, 0x4, 0x65, 0x4, 0x61, 0x4, 0x4, 0x0, 0x42, 0x0, 0x3c, 0x0, +0x3f, 0x0, 0x67, 0x4, 0x61, 0x4, 0x64, 0x4, 0x4, 0x0, 0x42, 0x0, 0x3f, 0x0, 0x43, 0x0, 0x67, 0x4, 0x64, 0x4, +0x66, 0x4, 0x4, 0x0, 0x44, 0x0, 0x45, 0x0, 0x46, 0x0, 0x68, 0x4, 0x65, 0x4, 0x63, 0x4, 0x4, 0x0, 0x44, 0x0, +0x46, 0x0, 0x47, 0x0, 0x68, 0x4, 0x63, 0x4, 0x61, 0x4, 0x4, 0x0, 0x48, 0x0, 0x44, 0x0, 0x47, 0x0, 0x65, 0x4, +0x68, 0x4, 0x61, 0x4, 0x4, 0x0, 0x49, 0x0, 0x48, 0x0, 0x47, 0x0, 0x61, 0x4, 0x65, 0x4, 0x61, 0x4, 0x4, 0x0, +0x49, 0x0, 0x47, 0x0, 0x4a, 0x0, 0x61, 0x4, 0x61, 0x4, 0x67, 0x4, 0x4, 0x0, 0x49, 0x0, 0x4a, 0x0, 0x4b, 0x0, +0x61, 0x4, 0x67, 0x4, 0x69, 0x4, 0x4, 0x0, 0x49, 0x0, 0x4b, 0x0, 0x4c, 0x0, 0x61, 0x4, 0x69, 0x4, 0x61, 0x4, +0x4, 0x0, 0x4d, 0x0, 0x49, 0x0, 0x4c, 0x0, 0x65, 0x4, 0x61, 0x4, 0x61, 0x4, 0x4, 0x0, 0x4e, 0x0, 0x4d, 0x0, +0x4c, 0x0, 0x64, 0x4, 0x65, 0x4, 0x61, 0x4, 0x4, 0x0, 0x4f, 0x0, 0x4e, 0x0, 0x4c, 0x0, 0x63, 0x4, 0x64, 0x4, +0x61, 0x4, 0x4, 0x0, 0x4f, 0x0, 0x4c, 0x0, 0x50, 0x0, 0x63, 0x4, 0x61, 0x4, 0x6a, 0x4, 0x4, 0x0, 0xc8, 0x2, +0xc9, 0x2, 0xca, 0x2, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x5, 0x0, 0xcb, 0x2, 0xc8, 0x2, 0xca, 0x2, 0x13, 0x4, +0x13, 0x4, 0x13, 0x4, 0x5, 0x0, 0xcb, 0x2, 0xca, 0x2, 0xcc, 0x2, 0x13, 0x4, 0x13, 0x4, 0x14, 0x4, 0x5, 0x0, +0xcb, 0x2, 0xcc, 0x2, 0xcd, 0x2, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0x5, 0x0, 0xce, 0x2, 0xcf, 0x2, 0xd0, 0x2, +0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x5, 0x0, 0xd1, 0x2, 0xce, 0x2, 0xd0, 0x2, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, +0x5, 0x0, 0xd2, 0x2, 0xd3, 0x2, 0xd4, 0x2, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x5, 0x0, 0xd5, 0x2, 0xd2, 0x2, +0xd4, 0x2, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x5, 0x0, 0xd5, 0x2, 0xd4, 0x2, 0xd6, 0x2, 0x13, 0x4, 0x13, 0x4, +0x39, 0x4, 0x5, 0x0, 0xcb, 0x2, 0xcd, 0x2, 0xd7, 0x2, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0x5, 0x0, 0xd5, 0x2, +0xd6, 0x2, 0xd8, 0x2, 0x13, 0x4, 0x39, 0x4, 0x39, 0x4, 0x5, 0x0, 0xd5, 0x2, 0xd8, 0x2, 0xd9, 0x2, 0x13, 0x4, +0x39, 0x4, 0x39, 0x4, 0x5, 0x0, 0xcb, 0x2, 0xd7, 0x2, 0xda, 0x2, 0x13, 0x4, 0x14, 0x4, 0x33, 0x4, 0x5, 0x0, +0xdb, 0x2, 0xcb, 0x2, 0xda, 0x2, 0x32, 0x4, 0x13, 0x4, 0x33, 0x4, 0x5, 0x0, 0xdb, 0x2, 0xda, 0x2, 0xdc, 0x2, +0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0x5, 0x0, 0xdd, 0x2, 0xdb, 0x2, 0xdc, 0x2, 0x31, 0x4, 0x32, 0x4, 0x17, 0x4, +0x5, 0x0, 0xde, 0x2, 0xdd, 0x2, 0xdc, 0x2, 0x32, 0x4, 0x31, 0x4, 0x17, 0x4, 0x5, 0x0, 0xd5, 0x2, 0xd9, 0x2, +0xdf, 0x2, 0x13, 0x4, 0x39, 0x4, 0x39, 0x4, 0x5, 0x0, 0xde, 0x2, 0xdc, 0x2, 0xe0, 0x2, 0x32, 0x4, 0x17, 0x4, +0x17, 0x4, 0x5, 0x0, 0xe1, 0x2, 0xde, 0x2, 0xe0, 0x2, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, 0x5, 0x0, 0xd5, 0x2, +0xdf, 0x2, 0xe2, 0x2, 0x13, 0x4, 0x39, 0x4, 0x39, 0x4, 0x5, 0x0, 0xe3, 0x2, 0xe1, 0x2, 0xe0, 0x2, 0x32, 0x4, +0x30, 0x4, 0x17, 0x4, 0x5, 0x0, 0xe3, 0x2, 0xe0, 0x2, 0xe4, 0x2, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x5, 0x0, +0xe5, 0x2, 0xe3, 0x2, 0xe4, 0x2, 0x35, 0x4, 0x32, 0x4, 0x17, 0x4, 0x5, 0x0, 0xd5, 0x2, 0xe2, 0x2, 0xe6, 0x2, +0x13, 0x4, 0x39, 0x4, 0x3a, 0x4, 0x5, 0x0, 0xe7, 0x2, 0xe5, 0x2, 0xe4, 0x2, 0x32, 0x4, 0x35, 0x4, 0x17, 0x4, +0x5, 0x0, 0xe7, 0x2, 0xe4, 0x2, 0xe8, 0x2, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x5, 0x0, 0xe9, 0x2, 0xe7, 0x2, +0xe8, 0x2, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0x5, 0x0, 0xe9, 0x2, 0xe8, 0x2, 0xea, 0x2, 0x32, 0x4, 0x17, 0x4, +0x17, 0x4, 0x5, 0x0, 0xeb, 0x2, 0xe9, 0x2, 0xea, 0x2, 0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, 0x5, 0x0, 0xec, 0x2, +0xeb, 0x2, 0xea, 0x2, 0x32, 0x4, 0x3b, 0x4, 0x17, 0x4, 0x5, 0x0, 0xd5, 0x2, 0xe6, 0x2, 0xed, 0x2, 0x13, 0x4, +0x3a, 0x4, 0x3a, 0x4, 0x5, 0x0, 0xec, 0x2, 0xea, 0x2, 0xee, 0x2, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x5, 0x0, +0xef, 0x2, 0xec, 0x2, 0xee, 0x2, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, 0x5, 0x0, 0xf0, 0x2, 0xef, 0x2, 0xee, 0x2, +0x32, 0x4, 0x30, 0x4, 0x17, 0x4, 0x5, 0x0, 0xf0, 0x2, 0xee, 0x2, 0xf1, 0x2, 0x32, 0x4, 0x17, 0x4, 0x33, 0x4, +0x5, 0x0, 0xf2, 0x2, 0xf0, 0x2, 0xf1, 0x2, 0x32, 0x4, 0x32, 0x4, 0x33, 0x4, 0x5, 0x0, 0xd5, 0x2, 0xed, 0x2, +0xf3, 0x2, 0x13, 0x4, 0x3a, 0x4, 0x3a, 0x4, 0x5, 0x0, 0xf2, 0x2, 0xf1, 0x2, 0xf4, 0x2, 0x32, 0x4, 0x33, 0x4, +0x3c, 0x4, 0x5, 0x0, 0xf5, 0x2, 0xf2, 0x2, 0xf4, 0x2, 0x17, 0x4, 0x32, 0x4, 0x3c, 0x4, 0x5, 0x0, 0xd0, 0x2, +0xf5, 0x2, 0xf4, 0x2, 0x13, 0x4, 0x17, 0x4, 0x3c, 0x4, 0x5, 0x0, 0xd0, 0x2, 0xf4, 0x2, 0xf6, 0x2, 0x13, 0x4, +0x3c, 0x4, 0x14, 0x4, 0x5, 0x0, 0xd0, 0x2, 0xf6, 0x2, 0xf7, 0x2, 0x13, 0x4, 0x14, 0x4, 0x1e, 0x4, 0x5, 0x0, +0xd0, 0x2, 0xf7, 0x2, 0xf8, 0x2, 0x13, 0x4, 0x1e, 0x4, 0x15, 0x4, 0x5, 0x0, 0xd1, 0x2, 0xd0, 0x2, 0xf8, 0x2, +0x13, 0x4, 0x13, 0x4, 0x15, 0x4, 0x5, 0x0, 0xd1, 0x2, 0xf8, 0x2, 0xf9, 0x2, 0x13, 0x4, 0x15, 0x4, 0x15, 0x4, +0x5, 0x0, 0xd1, 0x2, 0xf9, 0x2, 0xfa, 0x2, 0x13, 0x4, 0x15, 0x4, 0x15, 0x4, 0x5, 0x0, 0xfb, 0x2, 0xd1, 0x2, +0xfa, 0x2, 0x17, 0x4, 0x13, 0x4, 0x15, 0x4, 0x5, 0x0, 0xfc, 0x2, 0xfb, 0x2, 0xfa, 0x2, 0x3d, 0x4, 0x17, 0x4, +0x15, 0x4, 0x5, 0x0, 0xfd, 0x2, 0xfc, 0x2, 0xfa, 0x2, 0x3e, 0x4, 0x3d, 0x4, 0x15, 0x4, 0x5, 0x0, 0xfe, 0x2, +0xfd, 0x2, 0xfa, 0x2, 0x3f, 0x4, 0x3e, 0x4, 0x15, 0x4, 0x5, 0x0, 0xd5, 0x2, 0xf3, 0x2, 0xff, 0x2, 0x13, 0x4, +0x3a, 0x4, 0x40, 0x4, 0x5, 0x0, 0xd5, 0x2, 0xff, 0x2, 0x0, 0x3, 0x13, 0x4, 0x40, 0x4, 0x40, 0x4, 0x5, 0x0, +0x1, 0x3, 0xfe, 0x2, 0xfa, 0x2, 0x27, 0x4, 0x3f, 0x4, 0x15, 0x4, 0x5, 0x0, 0x1, 0x3, 0xfa, 0x2, 0x2, 0x3, +0x27, 0x4, 0x15, 0x4, 0x33, 0x4, 0x5, 0x0, 0x3, 0x3, 0x1, 0x3, 0x2, 0x3, 0x27, 0x4, 0x27, 0x4, 0x33, 0x4, +0x5, 0x0, 0x3, 0x3, 0x2, 0x3, 0x4, 0x3, 0x27, 0x4, 0x33, 0x4, 0x33, 0x4, 0x5, 0x0, 0x5, 0x3, 0x3, 0x3, +0x4, 0x3, 0x17, 0x4, 0x27, 0x4, 0x33, 0x4, 0x5, 0x0, 0x5, 0x3, 0x4, 0x3, 0x6, 0x3, 0x17, 0x4, 0x33, 0x4, +0x14, 0x4, 0x5, 0x0, 0x5, 0x3, 0x6, 0x3, 0x7, 0x3, 0x17, 0x4, 0x14, 0x4, 0x33, 0x4, 0x5, 0x0, 0x8, 0x3, +0x5, 0x3, 0x7, 0x3, 0x17, 0x4, 0x17, 0x4, 0x33, 0x4, 0x5, 0x0, 0x8, 0x3, 0x7, 0x3, 0x9, 0x3, 0x17, 0x4, +0x33, 0x4, 0x14, 0x4, 0x5, 0x0, 0x8, 0x3, 0x9, 0x3, 0xa, 0x3, 0x17, 0x4, 0x14, 0x4, 0x33, 0x4, 0x5, 0x0, +0xb, 0x3, 0x8, 0x3, 0xa, 0x3, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0x5, 0x0, 0xb, 0x3, 0xa, 0x3, 0xc, 0x3, +0x27, 0x4, 0x33, 0x4, 0x17, 0x4, 0x5, 0x0, 0xd, 0x3, 0xb, 0x3, 0xc, 0x3, 0x27, 0x4, 0x27, 0x4, 0x17, 0x4, +0x5, 0x0, 0xd, 0x3, 0xc, 0x3, 0xe, 0x3, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0x5, 0x0, 0xf, 0x3, 0xd, 0x3, +0xe, 0x3, 0x17, 0x4, 0x27, 0x4, 0x33, 0x4, 0x5, 0x0, 0xf, 0x3, 0xe, 0x3, 0x10, 0x3, 0x17, 0x4, 0x33, 0x4, +0x14, 0x4, 0x5, 0x0, 0xf, 0x3, 0x10, 0x3, 0x11, 0x3, 0x17, 0x4, 0x14, 0x4, 0x33, 0x4, 0x5, 0x0, 0x12, 0x3, +0xf, 0x3, 0x11, 0x3, 0x17, 0x4, 0x17, 0x4, 0x33, 0x4, 0x5, 0x0, 0x12, 0x3, 0x11, 0x3, 0x13, 0x3, 0x17, 0x4, +0x33, 0x4, 0x14, 0x4, 0x5, 0x0, 0x12, 0x3, 0x13, 0x3, 0x14, 0x3, 0x17, 0x4, 0x14, 0x4, 0x33, 0x4, 0x5, 0x0, +0x15, 0x3, 0x12, 0x3, 0x14, 0x3, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0x5, 0x0, 0x15, 0x3, 0x14, 0x3, 0x16, 0x3, +0x27, 0x4, 0x33, 0x4, 0x33, 0x4, 0x5, 0x0, 0x17, 0x3, 0x15, 0x3, 0x16, 0x3, 0x27, 0x4, 0x27, 0x4, 0x33, 0x4, +0x5, 0x0, 0x17, 0x3, 0x16, 0x3, 0xd5, 0x2, 0x27, 0x4, 0x33, 0x4, 0x13, 0x4, 0x5, 0x0, 0x18, 0x3, 0x17, 0x3, +0xd5, 0x2, 0x41, 0x4, 0x27, 0x4, 0x13, 0x4, 0x5, 0x0, 0x19, 0x3, 0x18, 0x3, 0xd5, 0x2, 0x42, 0x4, 0x41, 0x4, +0x13, 0x4, 0x5, 0x0, 0x1a, 0x3, 0x19, 0x3, 0xd5, 0x2, 0x42, 0x4, 0x42, 0x4, 0x13, 0x4, 0x5, 0x0, 0x1b, 0x3, +0x1a, 0x3, 0xd5, 0x2, 0x43, 0x4, 0x42, 0x4, 0x13, 0x4, 0x5, 0x0, 0x1b, 0x3, 0xd5, 0x2, 0x0, 0x3, 0x43, 0x4, +0x13, 0x4, 0x40, 0x4, 0x5, 0x0, 0x1c, 0x3, 0x1d, 0x3, 0x1e, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x6, 0x0, +0x1c, 0x3, 0x1e, 0x3, 0x1f, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x6, 0x0, 0x20, 0x3, 0x21, 0x3, 0x22, 0x3, +0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x6, 0x0, 0x20, 0x3, 0x22, 0x3, 0x23, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, +0x6, 0x0, 0x24, 0x3, 0x20, 0x3, 0x23, 0x3, 0x14, 0x4, 0x13, 0x4, 0x13, 0x4, 0x6, 0x0, 0x25, 0x3, 0x24, 0x3, +0x23, 0x3, 0x14, 0x4, 0x14, 0x4, 0x13, 0x4, 0x6, 0x0, 0x26, 0x3, 0x1c, 0x3, 0x1f, 0x3, 0x31, 0x4, 0x13, 0x4, +0x13, 0x4, 0x6, 0x0, 0x27, 0x3, 0x25, 0x3, 0x23, 0x3, 0x33, 0x4, 0x14, 0x4, 0x13, 0x4, 0x6, 0x0, 0x27, 0x3, +0x23, 0x3, 0x28, 0x3, 0x33, 0x4, 0x13, 0x4, 0x32, 0x4, 0x6, 0x0, 0x29, 0x3, 0x27, 0x3, 0x28, 0x3, 0x33, 0x4, +0x33, 0x4, 0x32, 0x4, 0x6, 0x0, 0x29, 0x3, 0x28, 0x3, 0x2a, 0x3, 0x33, 0x4, 0x32, 0x4, 0x32, 0x4, 0x6, 0x0, +0x2b, 0x3, 0x29, 0x3, 0x2a, 0x3, 0x17, 0x4, 0x33, 0x4, 0x32, 0x4, 0x6, 0x0, 0x2b, 0x3, 0x2a, 0x3, 0x2c, 0x3, +0x17, 0x4, 0x32, 0x4, 0x44, 0x4, 0x6, 0x0, 0x2b, 0x3, 0x2c, 0x3, 0x2d, 0x3, 0x17, 0x4, 0x44, 0x4, 0x32, 0x4, +0x6, 0x0, 0x2e, 0x3, 0x26, 0x3, 0x1f, 0x3, 0x45, 0x4, 0x31, 0x4, 0x13, 0x4, 0x6, 0x0, 0x2f, 0x3, 0x2b, 0x3, +0x2d, 0x3, 0x17, 0x4, 0x17, 0x4, 0x32, 0x4, 0x6, 0x0, 0x2f, 0x3, 0x2d, 0x3, 0x30, 0x3, 0x17, 0x4, 0x32, 0x4, +0x3b, 0x4, 0x6, 0x0, 0x2f, 0x3, 0x30, 0x3, 0x31, 0x3, 0x17, 0x4, 0x3b, 0x4, 0x32, 0x4, 0x6, 0x0, 0x32, 0x3, +0x2f, 0x3, 0x31, 0x3, 0x17, 0x4, 0x17, 0x4, 0x32, 0x4, 0x6, 0x0, 0x32, 0x3, 0x31, 0x3, 0x33, 0x3, 0x17, 0x4, +0x32, 0x4, 0x35, 0x4, 0x6, 0x0, 0x32, 0x3, 0x33, 0x3, 0x34, 0x3, 0x17, 0x4, 0x35, 0x4, 0x32, 0x4, 0x6, 0x0, +0x35, 0x3, 0x32, 0x3, 0x34, 0x3, 0x17, 0x4, 0x17, 0x4, 0x32, 0x4, 0x6, 0x0, 0x35, 0x3, 0x34, 0x3, 0x36, 0x3, +0x17, 0x4, 0x32, 0x4, 0x3b, 0x4, 0x6, 0x0, 0x35, 0x3, 0x36, 0x3, 0x37, 0x3, 0x17, 0x4, 0x3b, 0x4, 0x32, 0x4, +0x6, 0x0, 0x38, 0x3, 0x35, 0x3, 0x37, 0x3, 0x33, 0x4, 0x17, 0x4, 0x32, 0x4, 0x6, 0x0, 0x38, 0x3, 0x37, 0x3, +0x39, 0x3, 0x33, 0x4, 0x32, 0x4, 0x32, 0x4, 0x6, 0x0, 0x3a, 0x3, 0x38, 0x3, 0x39, 0x3, 0x17, 0x4, 0x33, 0x4, +0x32, 0x4, 0x6, 0x0, 0x3a, 0x3, 0x39, 0x3, 0x3b, 0x3, 0x17, 0x4, 0x32, 0x4, 0x30, 0x4, 0x6, 0x0, 0x3c, 0x3, +0x2e, 0x3, 0x1f, 0x3, 0x32, 0x4, 0x45, 0x4, 0x13, 0x4, 0x6, 0x0, 0x3a, 0x3, 0x3b, 0x3, 0x3d, 0x3, 0x17, 0x4, +0x30, 0x4, 0x32, 0x4, 0x6, 0x0, 0x3e, 0x3, 0x3a, 0x3, 0x3d, 0x3, 0x33, 0x4, 0x17, 0x4, 0x32, 0x4, 0x6, 0x0, +0x3e, 0x3, 0x3d, 0x3, 0x3f, 0x3, 0x33, 0x4, 0x32, 0x4, 0x15, 0x4, 0x6, 0x0, 0x40, 0x3, 0x3e, 0x3, 0x3f, 0x3, +0x15, 0x4, 0x33, 0x4, 0x15, 0x4, 0x6, 0x0, 0x40, 0x3, 0x3f, 0x3, 0x41, 0x3, 0x15, 0x4, 0x15, 0x4, 0x13, 0x4, +0x6, 0x0, 0x42, 0x3, 0x40, 0x3, 0x41, 0x3, 0x17, 0x4, 0x15, 0x4, 0x13, 0x4, 0x6, 0x0, 0x43, 0x3, 0x42, 0x3, +0x41, 0x3, 0x15, 0x4, 0x17, 0x4, 0x13, 0x4, 0x6, 0x0, 0x44, 0x3, 0x43, 0x3, 0x41, 0x3, 0x15, 0x4, 0x15, 0x4, +0x13, 0x4, 0x6, 0x0, 0x44, 0x3, 0x41, 0x3, 0x45, 0x3, 0x15, 0x4, 0x13, 0x4, 0x46, 0x4, 0x6, 0x0, 0x44, 0x3, +0x45, 0x3, 0x46, 0x3, 0x15, 0x4, 0x46, 0x4, 0x26, 0x4, 0x6, 0x0, 0x44, 0x3, 0x46, 0x3, 0x47, 0x3, 0x15, 0x4, +0x26, 0x4, 0x47, 0x4, 0x6, 0x0, 0x44, 0x3, 0x47, 0x3, 0x48, 0x3, 0x15, 0x4, 0x47, 0x4, 0x32, 0x4, 0x6, 0x0, +0x3c, 0x3, 0x1f, 0x3, 0x49, 0x3, 0x32, 0x4, 0x13, 0x4, 0x17, 0x4, 0x6, 0x0, 0x4a, 0x3, 0x3c, 0x3, 0x49, 0x3, +0x47, 0x4, 0x32, 0x4, 0x17, 0x4, 0x6, 0x0, 0x4b, 0x3, 0x44, 0x3, 0x48, 0x3, 0x17, 0x4, 0x15, 0x4, 0x32, 0x4, +0x6, 0x0, 0x4b, 0x3, 0x48, 0x3, 0x4c, 0x3, 0x17, 0x4, 0x32, 0x4, 0x27, 0x4, 0x6, 0x0, 0x4d, 0x3, 0x4b, 0x3, +0x4c, 0x3, 0x33, 0x4, 0x17, 0x4, 0x27, 0x4, 0x6, 0x0, 0x4d, 0x3, 0x4c, 0x3, 0x4e, 0x3, 0x33, 0x4, 0x27, 0x4, +0x17, 0x4, 0x6, 0x0, 0x4f, 0x3, 0x4d, 0x3, 0x4e, 0x3, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0x6, 0x0, 0x50, 0x3, +0x4f, 0x3, 0x4e, 0x3, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x6, 0x0, 0x50, 0x3, 0x4e, 0x3, 0x51, 0x3, 0x33, 0x4, +0x17, 0x4, 0x17, 0x4, 0x6, 0x0, 0x52, 0x3, 0x50, 0x3, 0x51, 0x3, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0x6, 0x0, +0x53, 0x3, 0x52, 0x3, 0x51, 0x3, 0x17, 0x4, 0x14, 0x4, 0x17, 0x4, 0x6, 0x0, 0x53, 0x3, 0x51, 0x3, 0x54, 0x3, +0x17, 0x4, 0x17, 0x4, 0x17, 0x4, 0x6, 0x0, 0x55, 0x3, 0x53, 0x3, 0x54, 0x3, 0x14, 0x4, 0x17, 0x4, 0x17, 0x4, +0x6, 0x0, 0x56, 0x3, 0x55, 0x3, 0x54, 0x3, 0x17, 0x4, 0x14, 0x4, 0x17, 0x4, 0x6, 0x0, 0x56, 0x3, 0x54, 0x3, +0x57, 0x3, 0x17, 0x4, 0x17, 0x4, 0x17, 0x4, 0x6, 0x0, 0x58, 0x3, 0x56, 0x3, 0x57, 0x3, 0x14, 0x4, 0x17, 0x4, +0x17, 0x4, 0x6, 0x0, 0x59, 0x3, 0x58, 0x3, 0x57, 0x3, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x6, 0x0, 0x59, 0x3, +0x57, 0x3, 0x5a, 0x3, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, 0x6, 0x0, 0x5b, 0x3, 0x59, 0x3, 0x5a, 0x3, 0x14, 0x4, +0x33, 0x4, 0x17, 0x4, 0x6, 0x0, 0x5c, 0x3, 0x5b, 0x3, 0x5a, 0x3, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x6, 0x0, +0x5c, 0x3, 0x5a, 0x3, 0x5d, 0x3, 0x33, 0x4, 0x17, 0x4, 0x27, 0x4, 0x6, 0x0, 0x49, 0x3, 0x5c, 0x3, 0x5d, 0x3, +0x17, 0x4, 0x33, 0x4, 0x27, 0x4, 0x6, 0x0, 0x4a, 0x3, 0x49, 0x3, 0x5d, 0x3, 0x47, 0x4, 0x17, 0x4, 0x27, 0x4, +0x6, 0x0, 0x5e, 0x3, 0x5f, 0x3, 0x60, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x7, 0x0, 0x61, 0x3, 0x5e, 0x3, +0x60, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x7, 0x0, 0x61, 0x3, 0x60, 0x3, 0x62, 0x3, 0x13, 0x4, 0x13, 0x4, +0x14, 0x4, 0x7, 0x0, 0x61, 0x3, 0x62, 0x3, 0x63, 0x3, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0x7, 0x0, 0x64, 0x3, +0x65, 0x3, 0x66, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x7, 0x0, 0x67, 0x3, 0x64, 0x3, 0x66, 0x3, 0x13, 0x4, +0x13, 0x4, 0x13, 0x4, 0x7, 0x0, 0x68, 0x3, 0x69, 0x3, 0x6a, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x7, 0x0, +0x6b, 0x3, 0x68, 0x3, 0x6a, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x7, 0x0, 0x6b, 0x3, 0x6a, 0x3, 0x6c, 0x3, +0x13, 0x4, 0x13, 0x4, 0x39, 0x4, 0x7, 0x0, 0x61, 0x3, 0x63, 0x3, 0x6d, 0x3, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, +0x7, 0x0, 0x6b, 0x3, 0x6c, 0x3, 0x6e, 0x3, 0x13, 0x4, 0x39, 0x4, 0x39, 0x4, 0x7, 0x0, 0x6b, 0x3, 0x6e, 0x3, +0x6f, 0x3, 0x13, 0x4, 0x39, 0x4, 0x39, 0x4, 0x7, 0x0, 0x61, 0x3, 0x6d, 0x3, 0x70, 0x3, 0x13, 0x4, 0x14, 0x4, +0x33, 0x4, 0x7, 0x0, 0x71, 0x3, 0x61, 0x3, 0x70, 0x3, 0x32, 0x4, 0x13, 0x4, 0x33, 0x4, 0x7, 0x0, 0x71, 0x3, +0x70, 0x3, 0x72, 0x3, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0x7, 0x0, 0x73, 0x3, 0x71, 0x3, 0x72, 0x3, 0x31, 0x4, +0x32, 0x4, 0x17, 0x4, 0x7, 0x0, 0x74, 0x3, 0x73, 0x3, 0x72, 0x3, 0x32, 0x4, 0x31, 0x4, 0x17, 0x4, 0x7, 0x0, +0x6b, 0x3, 0x6f, 0x3, 0x75, 0x3, 0x13, 0x4, 0x39, 0x4, 0x39, 0x4, 0x7, 0x0, 0x74, 0x3, 0x72, 0x3, 0x76, 0x3, +0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x7, 0x0, 0x77, 0x3, 0x74, 0x3, 0x76, 0x3, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, +0x7, 0x0, 0x6b, 0x3, 0x75, 0x3, 0x78, 0x3, 0x13, 0x4, 0x39, 0x4, 0x39, 0x4, 0x7, 0x0, 0x79, 0x3, 0x77, 0x3, +0x76, 0x3, 0x32, 0x4, 0x30, 0x4, 0x17, 0x4, 0x7, 0x0, 0x79, 0x3, 0x76, 0x3, 0x7a, 0x3, 0x32, 0x4, 0x17, 0x4, +0x17, 0x4, 0x7, 0x0, 0x7b, 0x3, 0x79, 0x3, 0x7a, 0x3, 0x35, 0x4, 0x32, 0x4, 0x17, 0x4, 0x7, 0x0, 0x6b, 0x3, +0x78, 0x3, 0x7c, 0x3, 0x13, 0x4, 0x39, 0x4, 0x3a, 0x4, 0x7, 0x0, 0x7d, 0x3, 0x7b, 0x3, 0x7a, 0x3, 0x32, 0x4, +0x35, 0x4, 0x17, 0x4, 0x7, 0x0, 0x7d, 0x3, 0x7a, 0x3, 0x7e, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x7, 0x0, +0x7f, 0x3, 0x7d, 0x3, 0x7e, 0x3, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0x7, 0x0, 0x7f, 0x3, 0x7e, 0x3, 0x80, 0x3, +0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x7, 0x0, 0x81, 0x3, 0x7f, 0x3, 0x80, 0x3, 0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, +0x7, 0x0, 0x82, 0x3, 0x81, 0x3, 0x80, 0x3, 0x32, 0x4, 0x3b, 0x4, 0x17, 0x4, 0x7, 0x0, 0x6b, 0x3, 0x7c, 0x3, +0x83, 0x3, 0x13, 0x4, 0x3a, 0x4, 0x3a, 0x4, 0x7, 0x0, 0x82, 0x3, 0x80, 0x3, 0x84, 0x3, 0x32, 0x4, 0x17, 0x4, +0x17, 0x4, 0x7, 0x0, 0x85, 0x3, 0x82, 0x3, 0x84, 0x3, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, 0x7, 0x0, 0x86, 0x3, +0x85, 0x3, 0x84, 0x3, 0x32, 0x4, 0x30, 0x4, 0x17, 0x4, 0x7, 0x0, 0x86, 0x3, 0x84, 0x3, 0x87, 0x3, 0x32, 0x4, +0x17, 0x4, 0x33, 0x4, 0x7, 0x0, 0x88, 0x3, 0x86, 0x3, 0x87, 0x3, 0x32, 0x4, 0x32, 0x4, 0x33, 0x4, 0x7, 0x0, +0x6b, 0x3, 0x83, 0x3, 0x89, 0x3, 0x13, 0x4, 0x3a, 0x4, 0x3a, 0x4, 0x7, 0x0, 0x88, 0x3, 0x87, 0x3, 0x8a, 0x3, +0x32, 0x4, 0x33, 0x4, 0x3c, 0x4, 0x7, 0x0, 0x8b, 0x3, 0x88, 0x3, 0x8a, 0x3, 0x17, 0x4, 0x32, 0x4, 0x3c, 0x4, +0x7, 0x0, 0x66, 0x3, 0x8b, 0x3, 0x8a, 0x3, 0x13, 0x4, 0x17, 0x4, 0x3c, 0x4, 0x7, 0x0, 0x66, 0x3, 0x8a, 0x3, +0x8c, 0x3, 0x13, 0x4, 0x3c, 0x4, 0x14, 0x4, 0x7, 0x0, 0x66, 0x3, 0x8c, 0x3, 0x8d, 0x3, 0x13, 0x4, 0x14, 0x4, +0x1e, 0x4, 0x7, 0x0, 0x66, 0x3, 0x8d, 0x3, 0x8e, 0x3, 0x13, 0x4, 0x1e, 0x4, 0x15, 0x4, 0x7, 0x0, 0x67, 0x3, +0x66, 0x3, 0x8e, 0x3, 0x13, 0x4, 0x13, 0x4, 0x15, 0x4, 0x7, 0x0, 0x67, 0x3, 0x8e, 0x3, 0x8f, 0x3, 0x13, 0x4, +0x15, 0x4, 0x15, 0x4, 0x7, 0x0, 0x67, 0x3, 0x8f, 0x3, 0x90, 0x3, 0x13, 0x4, 0x15, 0x4, 0x15, 0x4, 0x7, 0x0, +0x91, 0x3, 0x67, 0x3, 0x90, 0x3, 0x17, 0x4, 0x13, 0x4, 0x15, 0x4, 0x7, 0x0, 0x92, 0x3, 0x91, 0x3, 0x90, 0x3, +0x3d, 0x4, 0x17, 0x4, 0x15, 0x4, 0x7, 0x0, 0x93, 0x3, 0x92, 0x3, 0x90, 0x3, 0x3e, 0x4, 0x3d, 0x4, 0x15, 0x4, +0x7, 0x0, 0x94, 0x3, 0x93, 0x3, 0x90, 0x3, 0x3f, 0x4, 0x3e, 0x4, 0x15, 0x4, 0x7, 0x0, 0x6b, 0x3, 0x89, 0x3, +0x95, 0x3, 0x13, 0x4, 0x3a, 0x4, 0x40, 0x4, 0x7, 0x0, 0x6b, 0x3, 0x95, 0x3, 0x96, 0x3, 0x13, 0x4, 0x40, 0x4, +0x40, 0x4, 0x7, 0x0, 0x97, 0x3, 0x94, 0x3, 0x90, 0x3, 0x27, 0x4, 0x3f, 0x4, 0x15, 0x4, 0x7, 0x0, 0x97, 0x3, +0x90, 0x3, 0x98, 0x3, 0x27, 0x4, 0x15, 0x4, 0x33, 0x4, 0x7, 0x0, 0x99, 0x3, 0x97, 0x3, 0x98, 0x3, 0x27, 0x4, +0x27, 0x4, 0x33, 0x4, 0x7, 0x0, 0x99, 0x3, 0x98, 0x3, 0x9a, 0x3, 0x27, 0x4, 0x33, 0x4, 0x33, 0x4, 0x7, 0x0, +0x9b, 0x3, 0x99, 0x3, 0x9a, 0x3, 0x17, 0x4, 0x27, 0x4, 0x33, 0x4, 0x7, 0x0, 0x9b, 0x3, 0x9a, 0x3, 0x9c, 0x3, +0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0x7, 0x0, 0x9b, 0x3, 0x9c, 0x3, 0x9d, 0x3, 0x17, 0x4, 0x14, 0x4, 0x33, 0x4, +0x7, 0x0, 0x9e, 0x3, 0x9b, 0x3, 0x9d, 0x3, 0x17, 0x4, 0x17, 0x4, 0x33, 0x4, 0x7, 0x0, 0x9e, 0x3, 0x9d, 0x3, +0x9f, 0x3, 0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0x7, 0x0, 0x9e, 0x3, 0x9f, 0x3, 0xa0, 0x3, 0x17, 0x4, 0x14, 0x4, +0x33, 0x4, 0x7, 0x0, 0xa1, 0x3, 0x9e, 0x3, 0xa0, 0x3, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0x7, 0x0, 0xa1, 0x3, +0xa0, 0x3, 0xa2, 0x3, 0x27, 0x4, 0x33, 0x4, 0x17, 0x4, 0x7, 0x0, 0xa3, 0x3, 0xa1, 0x3, 0xa2, 0x3, 0x27, 0x4, +0x27, 0x4, 0x17, 0x4, 0x7, 0x0, 0xa3, 0x3, 0xa2, 0x3, 0xa4, 0x3, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0x7, 0x0, +0xa5, 0x3, 0xa3, 0x3, 0xa4, 0x3, 0x17, 0x4, 0x27, 0x4, 0x33, 0x4, 0x7, 0x0, 0xa5, 0x3, 0xa4, 0x3, 0xa6, 0x3, +0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0x7, 0x0, 0xa5, 0x3, 0xa6, 0x3, 0xa7, 0x3, 0x17, 0x4, 0x14, 0x4, 0x33, 0x4, +0x7, 0x0, 0xa8, 0x3, 0xa5, 0x3, 0xa7, 0x3, 0x17, 0x4, 0x17, 0x4, 0x33, 0x4, 0x7, 0x0, 0xa8, 0x3, 0xa7, 0x3, +0xa9, 0x3, 0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0x7, 0x0, 0xa8, 0x3, 0xa9, 0x3, 0xaa, 0x3, 0x17, 0x4, 0x14, 0x4, +0x33, 0x4, 0x7, 0x0, 0xab, 0x3, 0xa8, 0x3, 0xaa, 0x3, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0x7, 0x0, 0xab, 0x3, +0xaa, 0x3, 0xac, 0x3, 0x27, 0x4, 0x33, 0x4, 0x33, 0x4, 0x7, 0x0, 0xad, 0x3, 0xab, 0x3, 0xac, 0x3, 0x27, 0x4, +0x27, 0x4, 0x33, 0x4, 0x7, 0x0, 0xad, 0x3, 0xac, 0x3, 0x6b, 0x3, 0x27, 0x4, 0x33, 0x4, 0x13, 0x4, 0x7, 0x0, +0xae, 0x3, 0xad, 0x3, 0x6b, 0x3, 0x41, 0x4, 0x27, 0x4, 0x13, 0x4, 0x7, 0x0, 0xaf, 0x3, 0xae, 0x3, 0x6b, 0x3, +0x42, 0x4, 0x41, 0x4, 0x13, 0x4, 0x7, 0x0, 0xb0, 0x3, 0xaf, 0x3, 0x6b, 0x3, 0x42, 0x4, 0x42, 0x4, 0x13, 0x4, +0x7, 0x0, 0xb1, 0x3, 0xb0, 0x3, 0x6b, 0x3, 0x43, 0x4, 0x42, 0x4, 0x13, 0x4, 0x7, 0x0, 0xb1, 0x3, 0x6b, 0x3, +0x96, 0x3, 0x43, 0x4, 0x13, 0x4, 0x40, 0x4, 0x7, 0x0, 0xb2, 0x3, 0xb3, 0x3, 0xb4, 0x3, 0x13, 0x4, 0x13, 0x4, +0x13, 0x4, 0x8, 0x0, 0xb5, 0x3, 0xb2, 0x3, 0xb4, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x8, 0x0, 0xb5, 0x3, +0xb4, 0x3, 0xb6, 0x3, 0x13, 0x4, 0x13, 0x4, 0x14, 0x4, 0x8, 0x0, 0xb5, 0x3, 0xb6, 0x3, 0xb7, 0x3, 0x13, 0x4, +0x14, 0x4, 0x14, 0x4, 0x8, 0x0, 0xb8, 0x3, 0xb9, 0x3, 0xba, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x8, 0x0, +0xbb, 0x3, 0xb8, 0x3, 0xba, 0x3, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x8, 0x0, 0xbb, 0x3, 0xba, 0x3, 0xbc, 0x3, +0x13, 0x4, 0x13, 0x4, 0x14, 0x4, 0x8, 0x0, 0xbb, 0x3, 0xbc, 0x3, 0xbd, 0x3, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, +0x8, 0x0, 0xb5, 0x3, 0xb7, 0x3, 0xbe, 0x3, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0x8, 0x0, 0xbb, 0x3, 0xbd, 0x3, +0xbf, 0x3, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0x8, 0x0, 0xb5, 0x3, 0xbe, 0x3, 0xc0, 0x3, 0x13, 0x4, 0x14, 0x4, +0x33, 0x4, 0x8, 0x0, 0xc1, 0x3, 0xb5, 0x3, 0xc0, 0x3, 0x32, 0x4, 0x13, 0x4, 0x33, 0x4, 0x8, 0x0, 0xbb, 0x3, +0xbf, 0x3, 0xc2, 0x3, 0x13, 0x4, 0x14, 0x4, 0x17, 0x4, 0x8, 0x0, 0xc3, 0x3, 0xbb, 0x3, 0xc2, 0x3, 0x31, 0x4, +0x13, 0x4, 0x17, 0x4, 0x8, 0x0, 0xc4, 0x3, 0xc3, 0x3, 0xc2, 0x3, 0x27, 0x4, 0x31, 0x4, 0x17, 0x4, 0x8, 0x0, +0xc4, 0x3, 0xc2, 0x3, 0xc5, 0x3, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0x8, 0x0, 0xc6, 0x3, 0xc4, 0x3, 0xc5, 0x3, +0x32, 0x4, 0x27, 0x4, 0x33, 0x4, 0x8, 0x0, 0xc1, 0x3, 0xc0, 0x3, 0xc7, 0x3, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, +0x8, 0x0, 0xc8, 0x3, 0xc1, 0x3, 0xc7, 0x3, 0x31, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xc9, 0x3, 0xc8, 0x3, +0xc7, 0x3, 0x32, 0x4, 0x31, 0x4, 0x17, 0x4, 0x8, 0x0, 0xc9, 0x3, 0xc7, 0x3, 0xca, 0x3, 0x32, 0x4, 0x17, 0x4, +0x17, 0x4, 0x8, 0x0, 0xcb, 0x3, 0xc9, 0x3, 0xca, 0x3, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xc6, 0x3, +0xc5, 0x3, 0xcc, 0x3, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0x8, 0x0, 0xcd, 0x3, 0xc6, 0x3, 0xcc, 0x3, 0x31, 0x4, +0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xce, 0x3, 0xcd, 0x3, 0xcc, 0x3, 0x32, 0x4, 0x31, 0x4, 0x17, 0x4, 0x8, 0x0, +0xce, 0x3, 0xcc, 0x3, 0xcf, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd0, 0x3, 0xce, 0x3, 0xcf, 0x3, +0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd1, 0x3, 0xcb, 0x3, 0xca, 0x3, 0x32, 0x4, 0x30, 0x4, 0x17, 0x4, +0x8, 0x0, 0xd1, 0x3, 0xca, 0x3, 0xd2, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd3, 0x3, 0xd1, 0x3, +0xd2, 0x3, 0x35, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd4, 0x3, 0xd3, 0x3, 0xd2, 0x3, 0x32, 0x4, 0x35, 0x4, +0x17, 0x4, 0x8, 0x0, 0xd4, 0x3, 0xd2, 0x3, 0xd5, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd6, 0x3, +0xd4, 0x3, 0xd5, 0x3, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd7, 0x3, 0xd0, 0x3, 0xcf, 0x3, 0x32, 0x4, +0x3b, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd7, 0x3, 0xcf, 0x3, 0xd8, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, +0xd9, 0x3, 0xd7, 0x3, 0xd8, 0x3, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd6, 0x3, 0xd5, 0x3, 0xda, 0x3, +0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0xdb, 0x3, 0xd6, 0x3, 0xda, 0x3, 0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, +0x8, 0x0, 0xdc, 0x3, 0xdb, 0x3, 0xda, 0x3, 0x32, 0x4, 0x3b, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd9, 0x3, 0xd8, 0x3, +0xdd, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0xde, 0x3, 0xd9, 0x3, 0xdd, 0x3, 0x3b, 0x4, 0x32, 0x4, +0x17, 0x4, 0x8, 0x0, 0xdf, 0x3, 0xde, 0x3, 0xdd, 0x3, 0x32, 0x4, 0x3b, 0x4, 0x17, 0x4, 0x8, 0x0, 0xdc, 0x3, +0xda, 0x3, 0xe0, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0xe1, 0x3, 0xdc, 0x3, 0xe0, 0x3, 0x30, 0x4, +0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xdf, 0x3, 0xdd, 0x3, 0xe2, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, +0xe3, 0x3, 0xdf, 0x3, 0xe2, 0x3, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xe4, 0x3, 0xe3, 0x3, 0xe2, 0x3, +0x27, 0x4, 0x30, 0x4, 0x17, 0x4, 0x8, 0x0, 0xe4, 0x3, 0xe2, 0x3, 0xe5, 0x3, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, +0x8, 0x0, 0xe6, 0x3, 0xe4, 0x3, 0xe5, 0x3, 0x32, 0x4, 0x27, 0x4, 0x33, 0x4, 0x8, 0x0, 0xe7, 0x3, 0xe1, 0x3, +0xe0, 0x3, 0x32, 0x4, 0x30, 0x4, 0x17, 0x4, 0x8, 0x0, 0xe7, 0x3, 0xe0, 0x3, 0xe8, 0x3, 0x32, 0x4, 0x17, 0x4, +0x33, 0x4, 0x8, 0x0, 0xe9, 0x3, 0xe7, 0x3, 0xe8, 0x3, 0x32, 0x4, 0x32, 0x4, 0x33, 0x4, 0x8, 0x0, 0xe9, 0x3, +0xe8, 0x3, 0xea, 0x3, 0x32, 0x4, 0x33, 0x4, 0x33, 0x4, 0x8, 0x0, 0xeb, 0x3, 0xe9, 0x3, 0xea, 0x3, 0x32, 0x4, +0x32, 0x4, 0x33, 0x4, 0x8, 0x0, 0xe6, 0x3, 0xe5, 0x3, 0xec, 0x3, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0x8, 0x0, +0xed, 0x3, 0xe6, 0x3, 0xec, 0x3, 0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xee, 0x3, 0xed, 0x3, 0xec, 0x3, +0x32, 0x4, 0x3b, 0x4, 0x17, 0x4, 0x8, 0x0, 0xee, 0x3, 0xec, 0x3, 0xef, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, +0x8, 0x0, 0xf0, 0x3, 0xee, 0x3, 0xef, 0x3, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xf0, 0x3, 0xef, 0x3, +0xf1, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0xf2, 0x3, 0xf0, 0x3, 0xf1, 0x3, 0x32, 0x4, 0x32, 0x4, +0x17, 0x4, 0x8, 0x0, 0xeb, 0x3, 0xea, 0x3, 0xf3, 0x3, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0x8, 0x0, 0xf4, 0x3, +0xeb, 0x3, 0xf3, 0x3, 0x44, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xf5, 0x3, 0xf4, 0x3, 0xf3, 0x3, 0x32, 0x4, +0x44, 0x4, 0x17, 0x4, 0x8, 0x0, 0xf5, 0x3, 0xf3, 0x3, 0xf6, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, +0xf7, 0x3, 0xf5, 0x3, 0xf6, 0x3, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xf2, 0x3, 0xf1, 0x3, 0xf8, 0x3, +0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0xf9, 0x3, 0xf2, 0x3, 0xf8, 0x3, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, +0x8, 0x0, 0xf7, 0x3, 0xf6, 0x3, 0xfa, 0x3, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0xfb, 0x3, 0xf7, 0x3, +0xfa, 0x3, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, 0xf9, 0x3, 0xf8, 0x3, 0xfc, 0x3, 0x32, 0x4, 0x17, 0x4, +0x33, 0x4, 0x8, 0x0, 0xfd, 0x3, 0xf9, 0x3, 0xfc, 0x3, 0x17, 0x4, 0x32, 0x4, 0x33, 0x4, 0x8, 0x0, 0xfd, 0x3, +0xfc, 0x3, 0xfe, 0x3, 0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0x8, 0x0, 0xfd, 0x3, 0xfe, 0x3, 0xff, 0x3, 0x17, 0x4, +0x14, 0x4, 0x33, 0x4, 0x8, 0x0, 0x0, 0x4, 0xfd, 0x3, 0xff, 0x3, 0x17, 0x4, 0x17, 0x4, 0x33, 0x4, 0x8, 0x0, +0x0, 0x4, 0xff, 0x3, 0x1, 0x4, 0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0x8, 0x0, 0x0, 0x4, 0x1, 0x4, 0x2, 0x4, +0x17, 0x4, 0x14, 0x4, 0x17, 0x4, 0x8, 0x0, 0x3, 0x4, 0x0, 0x4, 0x2, 0x4, 0x17, 0x4, 0x17, 0x4, 0x17, 0x4, +0x8, 0x0, 0x3, 0x4, 0x2, 0x4, 0x4, 0x4, 0x17, 0x4, 0x17, 0x4, 0x14, 0x4, 0x8, 0x0, 0x3, 0x4, 0x4, 0x4, +0x5, 0x4, 0x17, 0x4, 0x14, 0x4, 0x17, 0x4, 0x8, 0x0, 0x6, 0x4, 0x3, 0x4, 0x5, 0x4, 0x34, 0x4, 0x17, 0x4, +0x17, 0x4, 0x8, 0x0, 0x6, 0x4, 0x5, 0x4, 0x7, 0x4, 0x34, 0x4, 0x17, 0x4, 0x14, 0x4, 0x8, 0x0, 0x6, 0x4, +0x7, 0x4, 0x8, 0x4, 0x34, 0x4, 0x14, 0x4, 0x14, 0x4, 0x8, 0x0, 0x6, 0x4, 0x8, 0x4, 0x9, 0x4, 0x34, 0x4, +0x14, 0x4, 0x33, 0x4, 0x8, 0x0, 0xa, 0x4, 0x6, 0x4, 0x9, 0x4, 0x17, 0x4, 0x34, 0x4, 0x33, 0x4, 0x8, 0x0, +0xa, 0x4, 0x9, 0x4, 0xb, 0x4, 0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0x8, 0x0, 0xa, 0x4, 0xb, 0x4, 0xc, 0x4, +0x17, 0x4, 0x14, 0x4, 0x17, 0x4, 0x8, 0x0, 0xd, 0x4, 0xa, 0x4, 0xc, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, +0x8, 0x0, 0xd, 0x4, 0xc, 0x4, 0xe, 0x4, 0x32, 0x4, 0x17, 0x4, 0x3c, 0x4, 0x8, 0x0, 0xf, 0x4, 0xd, 0x4, +0xe, 0x4, 0x1e, 0x4, 0x32, 0x4, 0x3c, 0x4, 0x8, 0x0, 0xf, 0x4, 0xe, 0x4, 0x10, 0x4, 0x1e, 0x4, 0x3c, 0x4, +0x15, 0x4, 0x8, 0x0, 0x11, 0x4, 0xf, 0x4, 0x10, 0x4, 0x38, 0x4, 0x1e, 0x4, 0x15, 0x4, 0x8, 0x0, 0x12, 0x4, +0x11, 0x4, 0x10, 0x4, 0x30, 0x4, 0x38, 0x4, 0x15, 0x4, 0x8, 0x0, 0x13, 0x4, 0x12, 0x4, 0x10, 0x4, 0x15, 0x4, +0x30, 0x4, 0x15, 0x4, 0x8, 0x0, 0x14, 0x4, 0x13, 0x4, 0x10, 0x4, 0x13, 0x4, 0x15, 0x4, 0x15, 0x4, 0x8, 0x0, +0x14, 0x4, 0x10, 0x4, 0x15, 0x4, 0x13, 0x4, 0x15, 0x4, 0x15, 0x4, 0x8, 0x0, 0x14, 0x4, 0x15, 0x4, 0x16, 0x4, +0x13, 0x4, 0x15, 0x4, 0x15, 0x4, 0x8, 0x0, 0x17, 0x4, 0x14, 0x4, 0x16, 0x4, 0x2e, 0x4, 0x13, 0x4, 0x15, 0x4, +0x8, 0x0, 0x18, 0x4, 0x17, 0x4, 0x16, 0x4, 0x2e, 0x4, 0x2e, 0x4, 0x15, 0x4, 0x8, 0x0, 0x18, 0x4, 0x16, 0x4, +0x19, 0x4, 0x2e, 0x4, 0x15, 0x4, 0x31, 0x4, 0x8, 0x0, 0x18, 0x4, 0x19, 0x4, 0x1a, 0x4, 0x2e, 0x4, 0x31, 0x4, +0x48, 0x4, 0x8, 0x0, 0x18, 0x4, 0x1a, 0x4, 0x1b, 0x4, 0x2e, 0x4, 0x48, 0x4, 0x32, 0x4, 0x8, 0x0, 0xfb, 0x3, +0xfa, 0x3, 0x1c, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0x1d, 0x4, 0x18, 0x4, 0x1b, 0x4, 0x33, 0x4, +0x2e, 0x4, 0x32, 0x4, 0x8, 0x0, 0x1d, 0x4, 0x1b, 0x4, 0x1e, 0x4, 0x33, 0x4, 0x32, 0x4, 0x17, 0x4, 0x8, 0x0, +0x1f, 0x4, 0x1d, 0x4, 0x1e, 0x4, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0x8, 0x0, 0x20, 0x4, 0x1f, 0x4, 0x1e, 0x4, +0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x8, 0x0, 0x20, 0x4, 0x1e, 0x4, 0x21, 0x4, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, +0x8, 0x0, 0x22, 0x4, 0x20, 0x4, 0x21, 0x4, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0x8, 0x0, 0x23, 0x4, 0x22, 0x4, +0x21, 0x4, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x8, 0x0, 0x23, 0x4, 0x21, 0x4, 0x24, 0x4, 0x33, 0x4, 0x17, 0x4, +0x34, 0x4, 0x8, 0x0, 0x25, 0x4, 0x23, 0x4, 0x24, 0x4, 0x14, 0x4, 0x33, 0x4, 0x34, 0x4, 0x8, 0x0, 0x26, 0x4, +0x25, 0x4, 0x24, 0x4, 0x14, 0x4, 0x14, 0x4, 0x34, 0x4, 0x8, 0x0, 0x27, 0x4, 0x26, 0x4, 0x24, 0x4, 0x17, 0x4, +0x14, 0x4, 0x34, 0x4, 0x8, 0x0, 0x27, 0x4, 0x24, 0x4, 0x28, 0x4, 0x17, 0x4, 0x34, 0x4, 0x17, 0x4, 0x8, 0x0, +0x29, 0x4, 0x27, 0x4, 0x28, 0x4, 0x14, 0x4, 0x17, 0x4, 0x17, 0x4, 0x8, 0x0, 0x2a, 0x4, 0x29, 0x4, 0x28, 0x4, +0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0x8, 0x0, 0x2a, 0x4, 0x28, 0x4, 0x2b, 0x4, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, +0x8, 0x0, 0x2c, 0x4, 0x2a, 0x4, 0x2b, 0x4, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0x8, 0x0, 0x1c, 0x4, 0x2c, 0x4, +0x2b, 0x4, 0x17, 0x4, 0x14, 0x4, 0x17, 0x4, 0x8, 0x0, 0x1c, 0x4, 0x2b, 0x4, 0x2d, 0x4, 0x17, 0x4, 0x17, 0x4, +0x31, 0x4, 0x8, 0x0, 0xfb, 0x3, 0x1c, 0x4, 0x2d, 0x4, 0x32, 0x4, 0x17, 0x4, 0x31, 0x4, 0x8, 0x0, 0x2e, 0x4, +0x2f, 0x4, 0x30, 0x4, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0x9, 0x0, 0x2e, 0x4, 0x30, 0x4, 0x31, 0x4, 0x13, 0x4, +0x13, 0x4, 0x13, 0x4, 0x9, 0x0, 0x32, 0x4, 0x33, 0x4, 0x34, 0x4, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0xa, 0x0, +0x35, 0x4, 0x32, 0x4, 0x34, 0x4, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0xa, 0x0, 0x35, 0x4, 0x34, 0x4, 0x36, 0x4, +0x13, 0x4, 0x13, 0x4, 0x14, 0x4, 0xa, 0x0, 0x35, 0x4, 0x36, 0x4, 0x37, 0x4, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, +0xa, 0x0, 0x38, 0x4, 0x39, 0x4, 0x3a, 0x4, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0xa, 0x0, 0x3b, 0x4, 0x38, 0x4, +0x3a, 0x4, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0xa, 0x0, 0x3b, 0x4, 0x3a, 0x4, 0x3c, 0x4, 0x13, 0x4, 0x13, 0x4, +0x14, 0x4, 0xa, 0x0, 0x3b, 0x4, 0x3c, 0x4, 0x3d, 0x4, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0xa, 0x0, 0x35, 0x4, +0x37, 0x4, 0x3e, 0x4, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0xa, 0x0, 0x3b, 0x4, 0x3d, 0x4, 0x3f, 0x4, 0x13, 0x4, +0x14, 0x4, 0x14, 0x4, 0xa, 0x0, 0x35, 0x4, 0x3e, 0x4, 0x40, 0x4, 0x13, 0x4, 0x14, 0x4, 0x33, 0x4, 0xa, 0x0, +0x41, 0x4, 0x35, 0x4, 0x40, 0x4, 0x32, 0x4, 0x13, 0x4, 0x33, 0x4, 0xa, 0x0, 0x3b, 0x4, 0x3f, 0x4, 0x42, 0x4, +0x13, 0x4, 0x14, 0x4, 0x17, 0x4, 0xa, 0x0, 0x43, 0x4, 0x3b, 0x4, 0x42, 0x4, 0x31, 0x4, 0x13, 0x4, 0x17, 0x4, +0xa, 0x0, 0x44, 0x4, 0x43, 0x4, 0x42, 0x4, 0x27, 0x4, 0x31, 0x4, 0x17, 0x4, 0xa, 0x0, 0x44, 0x4, 0x42, 0x4, +0x45, 0x4, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0xa, 0x0, 0x46, 0x4, 0x44, 0x4, 0x45, 0x4, 0x32, 0x4, 0x27, 0x4, +0x33, 0x4, 0xa, 0x0, 0x41, 0x4, 0x40, 0x4, 0x47, 0x4, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0xa, 0x0, 0x48, 0x4, +0x41, 0x4, 0x47, 0x4, 0x31, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x49, 0x4, 0x48, 0x4, 0x47, 0x4, 0x32, 0x4, +0x31, 0x4, 0x17, 0x4, 0xa, 0x0, 0x49, 0x4, 0x47, 0x4, 0x4a, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, +0x4b, 0x4, 0x49, 0x4, 0x4a, 0x4, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x46, 0x4, 0x45, 0x4, 0x4c, 0x4, +0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0xa, 0x0, 0x4d, 0x4, 0x46, 0x4, 0x4c, 0x4, 0x31, 0x4, 0x32, 0x4, 0x17, 0x4, +0xa, 0x0, 0x4e, 0x4, 0x4d, 0x4, 0x4c, 0x4, 0x32, 0x4, 0x31, 0x4, 0x17, 0x4, 0xa, 0x0, 0x4e, 0x4, 0x4c, 0x4, +0x4f, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x50, 0x4, 0x4e, 0x4, 0x4f, 0x4, 0x3b, 0x4, 0x32, 0x4, +0x17, 0x4, 0xa, 0x0, 0x51, 0x4, 0x4b, 0x4, 0x4a, 0x4, 0x32, 0x4, 0x30, 0x4, 0x17, 0x4, 0xa, 0x0, 0x51, 0x4, +0x4a, 0x4, 0x52, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x53, 0x4, 0x51, 0x4, 0x52, 0x4, 0x35, 0x4, +0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x54, 0x4, 0x53, 0x4, 0x52, 0x4, 0x32, 0x4, 0x35, 0x4, 0x17, 0x4, 0xa, 0x0, +0x54, 0x4, 0x52, 0x4, 0x55, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x56, 0x4, 0x54, 0x4, 0x55, 0x4, +0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x57, 0x4, 0x50, 0x4, 0x4f, 0x4, 0x32, 0x4, 0x3b, 0x4, 0x17, 0x4, +0xa, 0x0, 0x57, 0x4, 0x4f, 0x4, 0x58, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x59, 0x4, 0x57, 0x4, +0x58, 0x4, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x56, 0x4, 0x55, 0x4, 0x5a, 0x4, 0x32, 0x4, 0x17, 0x4, +0x17, 0x4, 0xa, 0x0, 0x5b, 0x4, 0x56, 0x4, 0x5a, 0x4, 0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x5c, 0x4, +0x5b, 0x4, 0x5a, 0x4, 0x32, 0x4, 0x3b, 0x4, 0x17, 0x4, 0xa, 0x0, 0x59, 0x4, 0x58, 0x4, 0x5d, 0x4, 0x32, 0x4, +0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x5e, 0x4, 0x59, 0x4, 0x5d, 0x4, 0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, +0x5f, 0x4, 0x5e, 0x4, 0x5d, 0x4, 0x32, 0x4, 0x3b, 0x4, 0x17, 0x4, 0xa, 0x0, 0x5c, 0x4, 0x5a, 0x4, 0x60, 0x4, +0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x61, 0x4, 0x5c, 0x4, 0x60, 0x4, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, +0xa, 0x0, 0x5f, 0x4, 0x5d, 0x4, 0x62, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x63, 0x4, 0x5f, 0x4, +0x62, 0x4, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x64, 0x4, 0x63, 0x4, 0x62, 0x4, 0x27, 0x4, 0x30, 0x4, +0x17, 0x4, 0xa, 0x0, 0x64, 0x4, 0x62, 0x4, 0x65, 0x4, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0xa, 0x0, 0x66, 0x4, +0x64, 0x4, 0x65, 0x4, 0x32, 0x4, 0x27, 0x4, 0x33, 0x4, 0xa, 0x0, 0x67, 0x4, 0x61, 0x4, 0x60, 0x4, 0x32, 0x4, +0x30, 0x4, 0x17, 0x4, 0xa, 0x0, 0x67, 0x4, 0x60, 0x4, 0x68, 0x4, 0x32, 0x4, 0x17, 0x4, 0x33, 0x4, 0xa, 0x0, +0x69, 0x4, 0x67, 0x4, 0x68, 0x4, 0x32, 0x4, 0x32, 0x4, 0x33, 0x4, 0xa, 0x0, 0x69, 0x4, 0x68, 0x4, 0x6a, 0x4, +0x32, 0x4, 0x33, 0x4, 0x33, 0x4, 0xa, 0x0, 0x6b, 0x4, 0x69, 0x4, 0x6a, 0x4, 0x32, 0x4, 0x32, 0x4, 0x33, 0x4, +0xa, 0x0, 0x66, 0x4, 0x65, 0x4, 0x6c, 0x4, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0xa, 0x0, 0x6d, 0x4, 0x66, 0x4, +0x6c, 0x4, 0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x6e, 0x4, 0x6d, 0x4, 0x6c, 0x4, 0x32, 0x4, 0x3b, 0x4, +0x17, 0x4, 0xa, 0x0, 0x6e, 0x4, 0x6c, 0x4, 0x6f, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x70, 0x4, +0x6e, 0x4, 0x6f, 0x4, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x70, 0x4, 0x6f, 0x4, 0x71, 0x4, 0x32, 0x4, +0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x72, 0x4, 0x70, 0x4, 0x71, 0x4, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, +0x6b, 0x4, 0x6a, 0x4, 0x73, 0x4, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0xa, 0x0, 0x74, 0x4, 0x6b, 0x4, 0x73, 0x4, +0x44, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x75, 0x4, 0x74, 0x4, 0x73, 0x4, 0x32, 0x4, 0x44, 0x4, 0x17, 0x4, +0xa, 0x0, 0x75, 0x4, 0x73, 0x4, 0x76, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x77, 0x4, 0x75, 0x4, +0x76, 0x4, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x72, 0x4, 0x71, 0x4, 0x78, 0x4, 0x32, 0x4, 0x17, 0x4, +0x17, 0x4, 0xa, 0x0, 0x79, 0x4, 0x72, 0x4, 0x78, 0x4, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x77, 0x4, +0x76, 0x4, 0x7a, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x7b, 0x4, 0x77, 0x4, 0x7a, 0x4, 0x32, 0x4, +0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x79, 0x4, 0x78, 0x4, 0x7c, 0x4, 0x32, 0x4, 0x17, 0x4, 0x33, 0x4, 0xa, 0x0, +0x7d, 0x4, 0x79, 0x4, 0x7c, 0x4, 0x17, 0x4, 0x32, 0x4, 0x33, 0x4, 0xa, 0x0, 0x7d, 0x4, 0x7c, 0x4, 0x7e, 0x4, +0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0xa, 0x0, 0x7d, 0x4, 0x7e, 0x4, 0x7f, 0x4, 0x17, 0x4, 0x14, 0x4, 0x33, 0x4, +0xa, 0x0, 0x80, 0x4, 0x7d, 0x4, 0x7f, 0x4, 0x17, 0x4, 0x17, 0x4, 0x33, 0x4, 0xa, 0x0, 0x80, 0x4, 0x7f, 0x4, +0x81, 0x4, 0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0xa, 0x0, 0x80, 0x4, 0x81, 0x4, 0x82, 0x4, 0x17, 0x4, 0x14, 0x4, +0x17, 0x4, 0xa, 0x0, 0x83, 0x4, 0x80, 0x4, 0x82, 0x4, 0x17, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x83, 0x4, +0x82, 0x4, 0x84, 0x4, 0x17, 0x4, 0x17, 0x4, 0x14, 0x4, 0xa, 0x0, 0x83, 0x4, 0x84, 0x4, 0x85, 0x4, 0x17, 0x4, +0x14, 0x4, 0x17, 0x4, 0xa, 0x0, 0x86, 0x4, 0x83, 0x4, 0x85, 0x4, 0x34, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, +0x86, 0x4, 0x85, 0x4, 0x87, 0x4, 0x34, 0x4, 0x17, 0x4, 0x14, 0x4, 0xa, 0x0, 0x86, 0x4, 0x87, 0x4, 0x88, 0x4, +0x34, 0x4, 0x14, 0x4, 0x14, 0x4, 0xa, 0x0, 0x86, 0x4, 0x88, 0x4, 0x89, 0x4, 0x34, 0x4, 0x14, 0x4, 0x33, 0x4, +0xa, 0x0, 0x8a, 0x4, 0x86, 0x4, 0x89, 0x4, 0x17, 0x4, 0x34, 0x4, 0x33, 0x4, 0xa, 0x0, 0x8a, 0x4, 0x89, 0x4, +0x8b, 0x4, 0x17, 0x4, 0x33, 0x4, 0x14, 0x4, 0xa, 0x0, 0x8a, 0x4, 0x8b, 0x4, 0x8c, 0x4, 0x17, 0x4, 0x14, 0x4, +0x17, 0x4, 0xa, 0x0, 0x8d, 0x4, 0x8a, 0x4, 0x8c, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x8d, 0x4, +0x8c, 0x4, 0x8e, 0x4, 0x32, 0x4, 0x17, 0x4, 0x3c, 0x4, 0xa, 0x0, 0x8f, 0x4, 0x8d, 0x4, 0x8e, 0x4, 0x1e, 0x4, +0x32, 0x4, 0x3c, 0x4, 0xa, 0x0, 0x8f, 0x4, 0x8e, 0x4, 0x90, 0x4, 0x1e, 0x4, 0x3c, 0x4, 0x15, 0x4, 0xa, 0x0, +0x91, 0x4, 0x8f, 0x4, 0x90, 0x4, 0x38, 0x4, 0x1e, 0x4, 0x15, 0x4, 0xa, 0x0, 0x92, 0x4, 0x91, 0x4, 0x90, 0x4, +0x30, 0x4, 0x38, 0x4, 0x15, 0x4, 0xa, 0x0, 0x93, 0x4, 0x92, 0x4, 0x90, 0x4, 0x15, 0x4, 0x30, 0x4, 0x15, 0x4, +0xa, 0x0, 0x94, 0x4, 0x93, 0x4, 0x90, 0x4, 0x13, 0x4, 0x15, 0x4, 0x15, 0x4, 0xa, 0x0, 0x94, 0x4, 0x90, 0x4, +0x95, 0x4, 0x13, 0x4, 0x15, 0x4, 0x15, 0x4, 0xa, 0x0, 0x94, 0x4, 0x95, 0x4, 0x96, 0x4, 0x13, 0x4, 0x15, 0x4, +0x15, 0x4, 0xa, 0x0, 0x97, 0x4, 0x94, 0x4, 0x96, 0x4, 0x2e, 0x4, 0x13, 0x4, 0x15, 0x4, 0xa, 0x0, 0x98, 0x4, +0x97, 0x4, 0x96, 0x4, 0x2e, 0x4, 0x2e, 0x4, 0x15, 0x4, 0xa, 0x0, 0x98, 0x4, 0x96, 0x4, 0x99, 0x4, 0x2e, 0x4, +0x15, 0x4, 0x31, 0x4, 0xa, 0x0, 0x98, 0x4, 0x99, 0x4, 0x9a, 0x4, 0x2e, 0x4, 0x31, 0x4, 0x48, 0x4, 0xa, 0x0, +0x98, 0x4, 0x9a, 0x4, 0x9b, 0x4, 0x2e, 0x4, 0x48, 0x4, 0x32, 0x4, 0xa, 0x0, 0x7b, 0x4, 0x7a, 0x4, 0x9c, 0x4, +0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0x9d, 0x4, 0x98, 0x4, 0x9b, 0x4, 0x33, 0x4, 0x2e, 0x4, 0x32, 0x4, +0xa, 0x0, 0x9d, 0x4, 0x9b, 0x4, 0x9e, 0x4, 0x33, 0x4, 0x32, 0x4, 0x17, 0x4, 0xa, 0x0, 0x9f, 0x4, 0x9d, 0x4, +0x9e, 0x4, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0xa, 0x0, 0xa0, 0x4, 0x9f, 0x4, 0x9e, 0x4, 0x33, 0x4, 0x14, 0x4, +0x17, 0x4, 0xa, 0x0, 0xa0, 0x4, 0x9e, 0x4, 0xa1, 0x4, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0xa2, 0x4, +0xa0, 0x4, 0xa1, 0x4, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0xa, 0x0, 0xa3, 0x4, 0xa2, 0x4, 0xa1, 0x4, 0x33, 0x4, +0x14, 0x4, 0x17, 0x4, 0xa, 0x0, 0xa3, 0x4, 0xa1, 0x4, 0xa4, 0x4, 0x33, 0x4, 0x17, 0x4, 0x34, 0x4, 0xa, 0x0, +0xa5, 0x4, 0xa3, 0x4, 0xa4, 0x4, 0x14, 0x4, 0x33, 0x4, 0x34, 0x4, 0xa, 0x0, 0xa6, 0x4, 0xa5, 0x4, 0xa4, 0x4, +0x14, 0x4, 0x14, 0x4, 0x34, 0x4, 0xa, 0x0, 0xa7, 0x4, 0xa6, 0x4, 0xa4, 0x4, 0x17, 0x4, 0x14, 0x4, 0x34, 0x4, +0xa, 0x0, 0xa7, 0x4, 0xa4, 0x4, 0xa8, 0x4, 0x17, 0x4, 0x34, 0x4, 0x17, 0x4, 0xa, 0x0, 0xa9, 0x4, 0xa7, 0x4, +0xa8, 0x4, 0x14, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0xaa, 0x4, 0xa9, 0x4, 0xa8, 0x4, 0x33, 0x4, 0x14, 0x4, +0x17, 0x4, 0xa, 0x0, 0xaa, 0x4, 0xa8, 0x4, 0xab, 0x4, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, 0xa, 0x0, 0xac, 0x4, +0xaa, 0x4, 0xab, 0x4, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0xa, 0x0, 0x9c, 0x4, 0xac, 0x4, 0xab, 0x4, 0x17, 0x4, +0x14, 0x4, 0x17, 0x4, 0xa, 0x0, 0x9c, 0x4, 0xab, 0x4, 0xad, 0x4, 0x17, 0x4, 0x17, 0x4, 0x31, 0x4, 0xa, 0x0, +0x7b, 0x4, 0x9c, 0x4, 0xad, 0x4, 0x32, 0x4, 0x17, 0x4, 0x31, 0x4, 0xa, 0x0, 0xae, 0x4, 0xaf, 0x4, 0xb0, 0x4, +0x13, 0x4, 0x15, 0x4, 0x13, 0x4, 0xb, 0x0, 0xb1, 0x4, 0xae, 0x4, 0xb0, 0x4, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, +0xb, 0x0, 0xb1, 0x4, 0xb0, 0x4, 0xb2, 0x4, 0x13, 0x4, 0x13, 0x4, 0x15, 0x4, 0xb, 0x0, 0xb1, 0x4, 0xb2, 0x4, +0xb3, 0x4, 0x13, 0x4, 0x15, 0x4, 0x3c, 0x4, 0xb, 0x0, 0xb1, 0x4, 0xb3, 0x4, 0xb4, 0x4, 0x13, 0x4, 0x3c, 0x4, +0x14, 0x4, 0xb, 0x0, 0xb1, 0x4, 0xb4, 0x4, 0xb5, 0x4, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0xb, 0x0, 0xb6, 0x4, +0xb7, 0x4, 0xb8, 0x4, 0x13, 0x4, 0x15, 0x4, 0x13, 0x4, 0xb, 0x0, 0xb9, 0x4, 0xb6, 0x4, 0xb8, 0x4, 0x15, 0x4, +0x13, 0x4, 0x13, 0x4, 0xb, 0x0, 0xba, 0x4, 0xbb, 0x4, 0xbc, 0x4, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0xb, 0x0, +0xbd, 0x4, 0xba, 0x4, 0xbc, 0x4, 0x49, 0x4, 0x13, 0x4, 0x13, 0x4, 0xb, 0x0, 0xbe, 0x4, 0xbd, 0x4, 0xbc, 0x4, +0x4a, 0x4, 0x49, 0x4, 0x13, 0x4, 0xb, 0x0, 0xbf, 0x4, 0xbe, 0x4, 0xbc, 0x4, 0x4b, 0x4, 0x4a, 0x4, 0x13, 0x4, +0xb, 0x0, 0xc0, 0x4, 0xbf, 0x4, 0xbc, 0x4, 0x4c, 0x4, 0x4b, 0x4, 0x13, 0x4, 0xb, 0x0, 0xc1, 0x4, 0xc0, 0x4, +0xbc, 0x4, 0x16, 0x4, 0x4c, 0x4, 0x13, 0x4, 0xb, 0x0, 0xc2, 0x4, 0xc1, 0x4, 0xbc, 0x4, 0x27, 0x4, 0x16, 0x4, +0x13, 0x4, 0xb, 0x0, 0xc3, 0x4, 0xc2, 0x4, 0xbc, 0x4, 0x2e, 0x4, 0x27, 0x4, 0x13, 0x4, 0xb, 0x0, 0xc4, 0x4, +0xc3, 0x4, 0xbc, 0x4, 0x15, 0x4, 0x2e, 0x4, 0x13, 0x4, 0xb, 0x0, 0xc5, 0x4, 0xc4, 0x4, 0xbc, 0x4, 0x15, 0x4, +0x15, 0x4, 0x13, 0x4, 0xb, 0x0, 0xb1, 0x4, 0xb5, 0x4, 0xc6, 0x4, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0xb, 0x0, +0xc7, 0x4, 0xc5, 0x4, 0xbc, 0x4, 0x2e, 0x4, 0x15, 0x4, 0x13, 0x4, 0xb, 0x0, 0xc7, 0x4, 0xbc, 0x4, 0xc8, 0x4, +0x2e, 0x4, 0x13, 0x4, 0x30, 0x4, 0xb, 0x0, 0xb9, 0x4, 0xb8, 0x4, 0xc9, 0x4, 0x15, 0x4, 0x13, 0x4, 0x35, 0x4, +0xb, 0x0, 0xb1, 0x4, 0xc6, 0x4, 0xca, 0x4, 0x13, 0x4, 0x14, 0x4, 0x17, 0x4, 0xb, 0x0, 0xcb, 0x4, 0xb1, 0x4, +0xca, 0x4, 0x31, 0x4, 0x13, 0x4, 0x17, 0x4, 0xb, 0x0, 0xcc, 0x4, 0xcb, 0x4, 0xca, 0x4, 0x27, 0x4, 0x31, 0x4, +0x17, 0x4, 0xb, 0x0, 0xcc, 0x4, 0xca, 0x4, 0xcd, 0x4, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0xb, 0x0, 0xce, 0x4, +0xcc, 0x4, 0xcd, 0x4, 0x32, 0x4, 0x27, 0x4, 0x33, 0x4, 0xb, 0x0, 0xce, 0x4, 0xcd, 0x4, 0xcf, 0x4, 0x32, 0x4, +0x33, 0x4, 0x17, 0x4, 0xb, 0x0, 0xd0, 0x4, 0xce, 0x4, 0xcf, 0x4, 0x31, 0x4, 0x32, 0x4, 0x17, 0x4, 0xb, 0x0, +0xd1, 0x4, 0xd0, 0x4, 0xcf, 0x4, 0x32, 0x4, 0x31, 0x4, 0x17, 0x4, 0xb, 0x0, 0xd1, 0x4, 0xcf, 0x4, 0xd2, 0x4, +0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xb, 0x0, 0xd3, 0x4, 0xd1, 0x4, 0xd2, 0x4, 0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, +0xb, 0x0, 0xc7, 0x4, 0xc8, 0x4, 0xd4, 0x4, 0x2e, 0x4, 0x30, 0x4, 0x31, 0x4, 0xb, 0x0, 0xb9, 0x4, 0xc9, 0x4, +0xd5, 0x4, 0x15, 0x4, 0x35, 0x4, 0x30, 0x4, 0xb, 0x0, 0xd6, 0x4, 0xd3, 0x4, 0xd2, 0x4, 0x32, 0x4, 0x3b, 0x4, +0x17, 0x4, 0xb, 0x0, 0xd6, 0x4, 0xd2, 0x4, 0xd7, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xb, 0x0, 0xd8, 0x4, +0xd6, 0x4, 0xd7, 0x4, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0xb, 0x0, 0xd8, 0x4, 0xd7, 0x4, 0xd9, 0x4, 0x32, 0x4, +0x17, 0x4, 0x17, 0x4, 0xb, 0x0, 0xda, 0x4, 0xd8, 0x4, 0xd9, 0x4, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, 0xb, 0x0, +0xdb, 0x4, 0xda, 0x4, 0xd9, 0x4, 0x32, 0x4, 0x30, 0x4, 0x17, 0x4, 0xb, 0x0, 0xdb, 0x4, 0xd9, 0x4, 0xdc, 0x4, +0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xb, 0x0, 0xdd, 0x4, 0xdb, 0x4, 0xdc, 0x4, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, +0xb, 0x0, 0xde, 0x4, 0xdd, 0x4, 0xdc, 0x4, 0x27, 0x4, 0x30, 0x4, 0x17, 0x4, 0xb, 0x0, 0xde, 0x4, 0xdc, 0x4, +0xdf, 0x4, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0xb, 0x0, 0xe0, 0x4, 0xde, 0x4, 0xdf, 0x4, 0x32, 0x4, 0x27, 0x4, +0x33, 0x4, 0xb, 0x0, 0xe0, 0x4, 0xdf, 0x4, 0xe1, 0x4, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0xb, 0x0, 0xe2, 0x4, +0xe0, 0x4, 0xe1, 0x4, 0x30, 0x4, 0x32, 0x4, 0x17, 0x4, 0xb, 0x0, 0xe3, 0x4, 0xe2, 0x4, 0xe1, 0x4, 0x32, 0x4, +0x30, 0x4, 0x17, 0x4, 0xb, 0x0, 0xe3, 0x4, 0xe1, 0x4, 0xe4, 0x4, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xb, 0x0, +0xe5, 0x4, 0xe3, 0x4, 0xe4, 0x4, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0xb, 0x0, 0xe5, 0x4, 0xe4, 0x4, 0xe6, 0x4, +0x32, 0x4, 0x17, 0x4, 0x2a, 0x4, 0xb, 0x0, 0xe7, 0x4, 0xe5, 0x4, 0xe6, 0x4, 0x4d, 0x4, 0x32, 0x4, 0x2a, 0x4, +0xb, 0x0, 0xc7, 0x4, 0xd4, 0x4, 0xe8, 0x4, 0x2e, 0x4, 0x31, 0x4, 0x17, 0x4, 0xb, 0x0, 0xe9, 0x4, 0xc7, 0x4, +0xe8, 0x4, 0x14, 0x4, 0x2e, 0x4, 0x17, 0x4, 0xb, 0x0, 0xb9, 0x4, 0xd5, 0x4, 0xea, 0x4, 0x15, 0x4, 0x30, 0x4, +0x4e, 0x4, 0xb, 0x0, 0xeb, 0x4, 0xe9, 0x4, 0xe8, 0x4, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0xb, 0x0, 0xeb, 0x4, +0xe8, 0x4, 0xec, 0x4, 0x33, 0x4, 0x17, 0x4, 0x27, 0x4, 0xb, 0x0, 0xed, 0x4, 0xeb, 0x4, 0xec, 0x4, 0x33, 0x4, +0x33, 0x4, 0x27, 0x4, 0xb, 0x0, 0xed, 0x4, 0xec, 0x4, 0xee, 0x4, 0x33, 0x4, 0x27, 0x4, 0x34, 0x4, 0xb, 0x0, +0xef, 0x4, 0xed, 0x4, 0xee, 0x4, 0x14, 0x4, 0x33, 0x4, 0x34, 0x4, 0xb, 0x0, 0xf0, 0x4, 0xef, 0x4, 0xee, 0x4, +0x14, 0x4, 0x14, 0x4, 0x34, 0x4, 0xb, 0x0, 0xf1, 0x4, 0xf0, 0x4, 0xee, 0x4, 0x33, 0x4, 0x14, 0x4, 0x34, 0x4, +0xb, 0x0, 0xf1, 0x4, 0xee, 0x4, 0xf2, 0x4, 0x33, 0x4, 0x34, 0x4, 0x17, 0x4, 0xb, 0x0, 0xf3, 0x4, 0xf1, 0x4, +0xf2, 0x4, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0xb, 0x0, 0xf4, 0x4, 0xf3, 0x4, 0xf2, 0x4, 0x33, 0x4, 0x14, 0x4, +0x17, 0x4, 0xb, 0x0, 0xf4, 0x4, 0xf2, 0x4, 0xf5, 0x4, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, 0xb, 0x0, 0xf6, 0x4, +0xf4, 0x4, 0xf5, 0x4, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0xb, 0x0, 0xf7, 0x4, 0xf6, 0x4, 0xf5, 0x4, 0x33, 0x4, +0x14, 0x4, 0x17, 0x4, 0xb, 0x0, 0xf7, 0x4, 0xf5, 0x4, 0xf8, 0x4, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, 0xb, 0x0, +0xf9, 0x4, 0xf7, 0x4, 0xf8, 0x4, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0xb, 0x0, 0xfa, 0x4, 0xf9, 0x4, 0xf8, 0x4, +0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0xb, 0x0, 0xfa, 0x4, 0xf8, 0x4, 0xfb, 0x4, 0x33, 0x4, 0x17, 0x4, 0x27, 0x4, +0xb, 0x0, 0xfc, 0x4, 0xfa, 0x4, 0xfb, 0x4, 0x33, 0x4, 0x33, 0x4, 0x27, 0x4, 0xb, 0x0, 0xfc, 0x4, 0xfb, 0x4, +0xfd, 0x4, 0x33, 0x4, 0x27, 0x4, 0x27, 0x4, 0xb, 0x0, 0xfe, 0x4, 0xfc, 0x4, 0xfd, 0x4, 0x4f, 0x4, 0x33, 0x4, +0x27, 0x4, 0xb, 0x0, 0xfe, 0x4, 0xfd, 0x4, 0xff, 0x4, 0x4f, 0x4, 0x27, 0x4, 0x4c, 0x4, 0xb, 0x0, 0x0, 0x5, +0xfe, 0x4, 0xff, 0x4, 0x50, 0x4, 0x4f, 0x4, 0x4c, 0x4, 0xb, 0x0, 0x0, 0x5, 0xff, 0x4, 0x1, 0x5, 0x50, 0x4, +0x4c, 0x4, 0x2d, 0x4, 0xb, 0x0, 0x2, 0x5, 0x0, 0x5, 0x1, 0x5, 0x51, 0x4, 0x50, 0x4, 0x2d, 0x4, 0xb, 0x0, +0x3, 0x5, 0x2, 0x5, 0x1, 0x5, 0x50, 0x4, 0x51, 0x4, 0x2d, 0x4, 0xb, 0x0, 0x3, 0x5, 0x1, 0x5, 0x4, 0x5, +0x50, 0x4, 0x2d, 0x4, 0x2d, 0x4, 0xb, 0x0, 0x5, 0x5, 0x3, 0x5, 0x4, 0x5, 0x51, 0x4, 0x50, 0x4, 0x2d, 0x4, +0xb, 0x0, 0x6, 0x5, 0x5, 0x5, 0x4, 0x5, 0x50, 0x4, 0x51, 0x4, 0x2d, 0x4, 0xb, 0x0, 0x6, 0x5, 0x4, 0x5, +0x7, 0x5, 0x50, 0x4, 0x2d, 0x4, 0x2d, 0x4, 0xb, 0x0, 0x8, 0x5, 0x6, 0x5, 0x7, 0x5, 0x51, 0x4, 0x50, 0x4, +0x2d, 0x4, 0xb, 0x0, 0x9, 0x5, 0x8, 0x5, 0x7, 0x5, 0x50, 0x4, 0x51, 0x4, 0x2d, 0x4, 0xb, 0x0, 0x9, 0x5, +0x7, 0x5, 0xa, 0x5, 0x50, 0x4, 0x2d, 0x4, 0x4c, 0x4, 0xb, 0x0, 0xb, 0x5, 0x9, 0x5, 0xa, 0x5, 0x50, 0x4, +0x50, 0x4, 0x4c, 0x4, 0xb, 0x0, 0xb, 0x5, 0xa, 0x5, 0xc, 0x5, 0x50, 0x4, 0x4c, 0x4, 0x2d, 0x4, 0xb, 0x0, +0xd, 0x5, 0xb, 0x5, 0xc, 0x5, 0x52, 0x4, 0x50, 0x4, 0x2d, 0x4, 0xb, 0x0, 0xe, 0x5, 0xd, 0x5, 0xc, 0x5, +0x50, 0x4, 0x52, 0x4, 0x2d, 0x4, 0xb, 0x0, 0xe, 0x5, 0xc, 0x5, 0xf, 0x5, 0x50, 0x4, 0x2d, 0x4, 0x4c, 0x4, +0xb, 0x0, 0x10, 0x5, 0xe, 0x5, 0xf, 0x5, 0x50, 0x4, 0x50, 0x4, 0x4c, 0x4, 0xb, 0x0, 0x10, 0x5, 0xf, 0x5, +0x11, 0x5, 0x50, 0x4, 0x4c, 0x4, 0x2d, 0x4, 0xb, 0x0, 0x12, 0x5, 0x10, 0x5, 0x11, 0x5, 0x52, 0x4, 0x50, 0x4, +0x2d, 0x4, 0xb, 0x0, 0x13, 0x5, 0x12, 0x5, 0x11, 0x5, 0x50, 0x4, 0x52, 0x4, 0x2d, 0x4, 0xb, 0x0, 0x13, 0x5, +0x11, 0x5, 0x14, 0x5, 0x50, 0x4, 0x2d, 0x4, 0x4c, 0x4, 0xb, 0x0, 0x15, 0x5, 0x13, 0x5, 0x14, 0x5, 0x2f, 0x4, +0x50, 0x4, 0x4c, 0x4, 0xb, 0x0, 0x15, 0x5, 0x14, 0x5, 0x16, 0x5, 0x2f, 0x4, 0x4c, 0x4, 0x3b, 0x4, 0xb, 0x0, +0x15, 0x5, 0x16, 0x5, 0x17, 0x5, 0x2f, 0x4, 0x3b, 0x4, 0x2e, 0x4, 0xb, 0x0, 0xe7, 0x4, 0xe6, 0x4, 0x18, 0x5, +0x4d, 0x4, 0x2a, 0x4, 0x16, 0x4, 0xb, 0x0, 0x19, 0x5, 0xe7, 0x4, 0x18, 0x5, 0x2a, 0x4, 0x4d, 0x4, 0x16, 0x4, +0xb, 0x0, 0x19, 0x5, 0x18, 0x5, 0x1a, 0x5, 0x2a, 0x4, 0x16, 0x4, 0x4d, 0x4, 0xb, 0x0, 0x19, 0x5, 0x1a, 0x5, +0x1b, 0x5, 0x2a, 0x4, 0x4d, 0x4, 0x4d, 0x4, 0xb, 0x0, 0x19, 0x5, 0x1b, 0x5, 0x1c, 0x5, 0x2a, 0x4, 0x4d, 0x4, +0x16, 0x4, 0xb, 0x0, 0x1d, 0x5, 0x19, 0x5, 0x1c, 0x5, 0x17, 0x4, 0x2a, 0x4, 0x16, 0x4, 0xb, 0x0, 0x1d, 0x5, +0x1c, 0x5, 0x1e, 0x5, 0x17, 0x4, 0x16, 0x4, 0x4d, 0x4, 0xb, 0x0, 0x1d, 0x5, 0x1e, 0x5, 0x1f, 0x5, 0x17, 0x4, +0x4d, 0x4, 0x4d, 0x4, 0xb, 0x0, 0x1d, 0x5, 0x1f, 0x5, 0x20, 0x5, 0x17, 0x4, 0x4d, 0x4, 0x4c, 0x4, 0xb, 0x0, +0x1d, 0x5, 0x20, 0x5, 0x21, 0x5, 0x17, 0x4, 0x4c, 0x4, 0x16, 0x4, 0xb, 0x0, 0x22, 0x5, 0x1d, 0x5, 0x21, 0x5, +0x2a, 0x4, 0x17, 0x4, 0x16, 0x4, 0xb, 0x0, 0x22, 0x5, 0x21, 0x5, 0x23, 0x5, 0x2a, 0x4, 0x16, 0x4, 0x4c, 0x4, +0xb, 0x0, 0x22, 0x5, 0x23, 0x5, 0x24, 0x5, 0x2a, 0x4, 0x4c, 0x4, 0x4c, 0x4, 0xb, 0x0, 0x22, 0x5, 0x24, 0x5, +0x25, 0x5, 0x2a, 0x4, 0x4c, 0x4, 0x16, 0x4, 0xb, 0x0, 0x26, 0x5, 0x22, 0x5, 0x25, 0x5, 0x15, 0x4, 0x2a, 0x4, +0x16, 0x4, 0xb, 0x0, 0x26, 0x5, 0x25, 0x5, 0x27, 0x5, 0x15, 0x4, 0x16, 0x4, 0x4c, 0x4, 0xb, 0x0, 0x26, 0x5, +0x27, 0x5, 0x28, 0x5, 0x15, 0x4, 0x4c, 0x4, 0x4c, 0x4, 0xb, 0x0, 0x26, 0x5, 0x28, 0x5, 0x15, 0x5, 0x15, 0x4, +0x4c, 0x4, 0x2f, 0x4, 0xb, 0x0, 0x26, 0x5, 0x15, 0x5, 0x17, 0x5, 0x15, 0x4, 0x2f, 0x4, 0x2e, 0x4, 0xb, 0x0, +0x26, 0x5, 0x17, 0x5, 0x29, 0x5, 0x15, 0x4, 0x2e, 0x4, 0x30, 0x4, 0xb, 0x0, 0x26, 0x5, 0x29, 0x5, 0x2a, 0x5, +0x15, 0x4, 0x30, 0x4, 0x4e, 0x4, 0xb, 0x0, 0x2b, 0x5, 0x26, 0x5, 0x2a, 0x5, 0x4d, 0x4, 0x15, 0x4, 0x4e, 0x4, +0xb, 0x0, 0x2b, 0x5, 0x2a, 0x5, 0x2c, 0x5, 0x4d, 0x4, 0x4e, 0x4, 0x3b, 0x4, 0xb, 0x0, 0x2b, 0x5, 0x2c, 0x5, +0x2d, 0x5, 0x4d, 0x4, 0x3b, 0x4, 0x4e, 0x4, 0xb, 0x0, 0x2e, 0x5, 0x2b, 0x5, 0x2d, 0x5, 0x53, 0x4, 0x4d, 0x4, +0x4e, 0x4, 0xb, 0x0, 0x2e, 0x5, 0x2d, 0x5, 0x2f, 0x5, 0x53, 0x4, 0x4e, 0x4, 0x4e, 0x4, 0xb, 0x0, 0x30, 0x5, +0x2e, 0x5, 0x2f, 0x5, 0x54, 0x4, 0x53, 0x4, 0x4e, 0x4, 0xb, 0x0, 0x30, 0x5, 0x2f, 0x5, 0x31, 0x5, 0x54, 0x4, +0x4e, 0x4, 0x55, 0x4, 0xb, 0x0, 0xea, 0x4, 0x30, 0x5, 0x31, 0x5, 0x4e, 0x4, 0x54, 0x4, 0x55, 0x4, 0xb, 0x0, +0xb9, 0x4, 0xea, 0x4, 0x31, 0x5, 0x15, 0x4, 0x4e, 0x4, 0x55, 0x4, 0xb, 0x0, 0x32, 0x5, 0x33, 0x5, 0x34, 0x5, +0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0xc, 0x0, 0x32, 0x5, 0x34, 0x5, 0x35, 0x5, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, +0xc, 0x0, 0x34, 0x5, 0x33, 0x5, 0x36, 0x5, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0xc, 0x0, 0x37, 0x5, 0x34, 0x5, +0x36, 0x5, 0x13, 0x4, 0x13, 0x4, 0x13, 0x4, 0xc, 0x0, 0x38, 0x5, 0x32, 0x5, 0x35, 0x5, 0x13, 0x4, 0x13, 0x4, +0x13, 0x4, 0xc, 0x0, 0x38, 0x5, 0x35, 0x5, 0x39, 0x5, 0x13, 0x4, 0x13, 0x4, 0x15, 0x4, 0xc, 0x0, 0x37, 0x5, +0x36, 0x5, 0x3a, 0x5, 0x13, 0x4, 0x13, 0x4, 0x14, 0x4, 0xc, 0x0, 0x37, 0x5, 0x3a, 0x5, 0x3b, 0x5, 0x13, 0x4, +0x14, 0x4, 0x14, 0x4, 0xc, 0x0, 0x38, 0x5, 0x39, 0x5, 0x3c, 0x5, 0x13, 0x4, 0x15, 0x4, 0x56, 0x4, 0xc, 0x0, +0x37, 0x5, 0x3b, 0x5, 0x3d, 0x5, 0x13, 0x4, 0x14, 0x4, 0x14, 0x4, 0xc, 0x0, 0x38, 0x5, 0x3c, 0x5, 0x3e, 0x5, +0x13, 0x4, 0x56, 0x4, 0x57, 0x4, 0xc, 0x0, 0x38, 0x5, 0x3e, 0x5, 0x3f, 0x5, 0x13, 0x4, 0x57, 0x4, 0x58, 0x4, +0xc, 0x0, 0x37, 0x5, 0x3d, 0x5, 0x40, 0x5, 0x13, 0x4, 0x14, 0x4, 0x17, 0x4, 0xc, 0x0, 0x41, 0x5, 0x37, 0x5, +0x40, 0x5, 0x31, 0x4, 0x13, 0x4, 0x17, 0x4, 0xc, 0x0, 0x42, 0x5, 0x41, 0x5, 0x40, 0x5, 0x27, 0x4, 0x31, 0x4, +0x17, 0x4, 0xc, 0x0, 0x42, 0x5, 0x40, 0x5, 0x43, 0x5, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0xc, 0x0, 0x44, 0x5, +0x42, 0x5, 0x43, 0x5, 0x32, 0x4, 0x27, 0x4, 0x33, 0x4, 0xc, 0x0, 0x38, 0x5, 0x3f, 0x5, 0x45, 0x5, 0x13, 0x4, +0x58, 0x4, 0x59, 0x4, 0xc, 0x0, 0x38, 0x5, 0x45, 0x5, 0x46, 0x5, 0x13, 0x4, 0x59, 0x4, 0x5a, 0x4, 0xc, 0x0, +0x44, 0x5, 0x43, 0x5, 0x47, 0x5, 0x32, 0x4, 0x33, 0x4, 0x17, 0x4, 0xc, 0x0, 0x48, 0x5, 0x44, 0x5, 0x47, 0x5, +0x31, 0x4, 0x32, 0x4, 0x17, 0x4, 0xc, 0x0, 0x49, 0x5, 0x48, 0x5, 0x47, 0x5, 0x32, 0x4, 0x31, 0x4, 0x17, 0x4, +0xc, 0x0, 0x49, 0x5, 0x47, 0x5, 0x4a, 0x5, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xc, 0x0, 0x4b, 0x5, 0x49, 0x5, +0x4a, 0x5, 0x3b, 0x4, 0x32, 0x4, 0x17, 0x4, 0xc, 0x0, 0x38, 0x5, 0x46, 0x5, 0x4c, 0x5, 0x13, 0x4, 0x5a, 0x4, +0x5b, 0x4, 0xc, 0x0, 0x38, 0x5, 0x4c, 0x5, 0x4d, 0x5, 0x13, 0x4, 0x5b, 0x4, 0x5c, 0x4, 0xc, 0x0, 0x38, 0x5, +0x4d, 0x5, 0x4e, 0x5, 0x13, 0x4, 0x5c, 0x4, 0x5b, 0x4, 0xc, 0x0, 0x38, 0x5, 0x4e, 0x5, 0x4f, 0x5, 0x13, 0x4, +0x5b, 0x4, 0x5a, 0x4, 0xc, 0x0, 0x38, 0x5, 0x4f, 0x5, 0x50, 0x5, 0x13, 0x4, 0x5a, 0x4, 0x59, 0x4, 0xc, 0x0, +0x38, 0x5, 0x50, 0x5, 0x51, 0x5, 0x13, 0x4, 0x59, 0x4, 0x58, 0x4, 0xc, 0x0, 0x38, 0x5, 0x51, 0x5, 0x52, 0x5, +0x13, 0x4, 0x58, 0x4, 0x5d, 0x4, 0xc, 0x0, 0x38, 0x5, 0x52, 0x5, 0x53, 0x5, 0x13, 0x4, 0x5d, 0x4, 0x5e, 0x4, +0xc, 0x0, 0x38, 0x5, 0x53, 0x5, 0x54, 0x5, 0x13, 0x4, 0x5e, 0x4, 0x5f, 0x4, 0xc, 0x0, 0x55, 0x5, 0x4b, 0x5, +0x4a, 0x5, 0x32, 0x4, 0x3b, 0x4, 0x17, 0x4, 0xc, 0x0, 0x55, 0x5, 0x4a, 0x5, 0x56, 0x5, 0x32, 0x4, 0x17, 0x4, +0x17, 0x4, 0xc, 0x0, 0x57, 0x5, 0x55, 0x5, 0x56, 0x5, 0x32, 0x4, 0x32, 0x4, 0x17, 0x4, 0xc, 0x0, 0x57, 0x5, +0x56, 0x5, 0x58, 0x5, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xc, 0x0, 0x59, 0x5, 0x57, 0x5, 0x58, 0x5, 0x30, 0x4, +0x32, 0x4, 0x17, 0x4, 0xc, 0x0, 0x5a, 0x5, 0x59, 0x5, 0x58, 0x5, 0x32, 0x4, 0x30, 0x4, 0x17, 0x4, 0xc, 0x0, +0x5a, 0x5, 0x58, 0x5, 0x5b, 0x5, 0x32, 0x4, 0x17, 0x4, 0x17, 0x4, 0xc, 0x0, 0x51, 0x0, 0x5a, 0x5, 0x5b, 0x5, +0x60, 0x4, 0x32, 0x4, 0x17, 0x4, 0xc, 0x0, 0x5c, 0x5, 0x51, 0x0, 0x5b, 0x5, 0x27, 0x4, 0x60, 0x4, 0x17, 0x4, +0xc, 0x0, 0x5c, 0x5, 0x5b, 0x5, 0x5d, 0x5, 0x27, 0x4, 0x17, 0x4, 0x33, 0x4, 0xc, 0x0, 0x5e, 0x5, 0x5c, 0x5, +0x5d, 0x5, 0x32, 0x4, 0x27, 0x4, 0x33, 0x4, 0xc, 0x0, 0x5e, 0x5, 0x5d, 0x5, 0x5f, 0x5, 0x32, 0x4, 0x33, 0x4, +0x15, 0x4, 0xc, 0x0, 0x60, 0x5, 0x5e, 0x5, 0x5f, 0x5, 0x15, 0x4, 0x32, 0x4, 0x15, 0x4, 0xc, 0x0, 0x61, 0x5, +0x60, 0x5, 0x5f, 0x5, 0x13, 0x4, 0x15, 0x4, 0x15, 0x4, 0xc, 0x0, 0x61, 0x5, 0x5f, 0x5, 0x62, 0x5, 0x13, 0x4, +0x15, 0x4, 0x17, 0x4, 0xc, 0x0, 0x61, 0x5, 0x62, 0x5, 0x63, 0x5, 0x13, 0x4, 0x17, 0x4, 0x2e, 0x4, 0xc, 0x0, +0x61, 0x5, 0x63, 0x5, 0x64, 0x5, 0x13, 0x4, 0x2e, 0x4, 0x15, 0x4, 0xc, 0x0, 0x61, 0x5, 0x64, 0x5, 0x65, 0x5, +0x13, 0x4, 0x15, 0x4, 0x2e, 0x4, 0xc, 0x0, 0x61, 0x5, 0x65, 0x5, 0x66, 0x5, 0x13, 0x4, 0x2e, 0x4, 0x34, 0x4, +0xc, 0x0, 0x67, 0x5, 0x61, 0x5, 0x66, 0x5, 0x37, 0x4, 0x13, 0x4, 0x34, 0x4, 0xc, 0x0, 0x68, 0x5, 0x67, 0x5, +0x66, 0x5, 0x4a, 0x4, 0x37, 0x4, 0x34, 0x4, 0xc, 0x0, 0x69, 0x5, 0x68, 0x5, 0x66, 0x5, 0x27, 0x4, 0x4a, 0x4, +0x34, 0x4, 0xc, 0x0, 0x38, 0x5, 0x54, 0x5, 0x6a, 0x5, 0x13, 0x4, 0x5f, 0x4, 0x27, 0x4, 0xc, 0x0, 0x69, 0x5, +0x66, 0x5, 0x6b, 0x5, 0x27, 0x4, 0x34, 0x4, 0x17, 0x4, 0xc, 0x0, 0x6c, 0x5, 0x69, 0x5, 0x6b, 0x5, 0x3d, 0x4, +0x27, 0x4, 0x17, 0x4, 0xc, 0x0, 0x6d, 0x5, 0x38, 0x5, 0x6a, 0x5, 0x17, 0x4, 0x13, 0x4, 0x27, 0x4, 0xc, 0x0, +0x6d, 0x5, 0x6a, 0x5, 0x6e, 0x5, 0x17, 0x4, 0x27, 0x4, 0x27, 0x4, 0xc, 0x0, 0x6f, 0x5, 0x6d, 0x5, 0x6e, 0x5, +0x33, 0x4, 0x17, 0x4, 0x27, 0x4, 0xc, 0x0, 0x6f, 0x5, 0x6e, 0x5, 0x70, 0x5, 0x33, 0x4, 0x27, 0x4, 0x17, 0x4, +0xc, 0x0, 0x71, 0x5, 0x6f, 0x5, 0x70, 0x5, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0xc, 0x0, 0x72, 0x5, 0x71, 0x5, +0x70, 0x5, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, 0xc, 0x0, 0x72, 0x5, 0x70, 0x5, 0x73, 0x5, 0x33, 0x4, 0x17, 0x4, +0x17, 0x4, 0xc, 0x0, 0x74, 0x5, 0x72, 0x5, 0x73, 0x5, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0xc, 0x0, 0x75, 0x5, +0x74, 0x5, 0x73, 0x5, 0x17, 0x4, 0x14, 0x4, 0x17, 0x4, 0xc, 0x0, 0x75, 0x5, 0x73, 0x5, 0x76, 0x5, 0x17, 0x4, +0x17, 0x4, 0x32, 0x4, 0xc, 0x0, 0x77, 0x5, 0x75, 0x5, 0x76, 0x5, 0x17, 0x4, 0x17, 0x4, 0x32, 0x4, 0xc, 0x0, +0x77, 0x5, 0x76, 0x5, 0x78, 0x5, 0x17, 0x4, 0x32, 0x4, 0x17, 0x4, 0xc, 0x0, 0x79, 0x5, 0x77, 0x5, 0x78, 0x5, +0x14, 0x4, 0x17, 0x4, 0x17, 0x4, 0xc, 0x0, 0x7a, 0x5, 0x79, 0x5, 0x78, 0x5, 0x33, 0x4, 0x14, 0x4, 0x17, 0x4, +0xc, 0x0, 0x7a, 0x5, 0x78, 0x5, 0x7b, 0x5, 0x33, 0x4, 0x17, 0x4, 0x17, 0x4, 0xc, 0x0, 0x7c, 0x5, 0x7a, 0x5, +0x7b, 0x5, 0x14, 0x4, 0x33, 0x4, 0x17, 0x4, 0xc, 0x0, 0x7d, 0x5, 0x7c, 0x5, 0x7b, 0x5, 0x33, 0x4, 0x14, 0x4, +0x17, 0x4, 0xc, 0x0, 0x7d, 0x5, 0x7b, 0x5, 0x7e, 0x5, 0x33, 0x4, 0x17, 0x4, 0x27, 0x4, 0xc, 0x0, 0x7f, 0x5, +0x7d, 0x5, 0x7e, 0x5, 0x33, 0x4, 0x33, 0x4, 0x27, 0x4, 0xc, 0x0, 0x7f, 0x5, 0x7e, 0x5, 0x80, 0x5, 0x33, 0x4, +0x27, 0x4, 0x27, 0x4, 0xc, 0x0, 0x6b, 0x5, 0x7f, 0x5, 0x80, 0x5, 0x17, 0x4, 0x33, 0x4, 0x27, 0x4, 0xc, 0x0, +0x6c, 0x5, 0x6b, 0x5, 0x80, 0x5, 0x3d, 0x4, 0x17, 0x4, 0x27, 0x4, 0xc, 0x0, 0x47, 0x65, 0x42, 0x6d, 0x40, 0x9, +0x1, 0x0, 0x77, 0x2d, 0x21, 0x20, 0x32, 0x0, 0x26, 0x25, 0x37, 0x0, 0x2c, 0x2b, 0x3f, 0x0, 0x19, 0x18, 0x23, 0x0, +0x29, 0x27, 0x3b, 0x0, 0x1e, 0x1d, 0x27, 0x0, 0x3a, 0x37, 0x4a, 0x0, 0x44, 0x41, 0x53, 0x0, 0x35, 0x31, 0x44, 0x0, +0xf, 0xe, 0x13, 0x0, 0x23, 0x20, 0x2b, 0x0, 0x2a, 0x25, 0x34, 0x0, 0x2f, 0x29, 0x38, 0x0, 0x34, 0x2d, 0x3d, 0x0, +0x3d, 0x34, 0x40, 0x0, 0x3, 0x1, 0x3, 0x0, 0x5, 0x3, 0x5, 0x0, 0x78, 0x6f, 0x72, 0x0, 0xdf, 0xcb, 0xc3, 0x0, +0x1, 0x3, 0x3, 0x0, 0x1c, 0x3a, 0x56, 0x0, 0x1e, 0x30, 0x40, 0x0, 0x1a, 0x2e, 0x42, 0x0, 0xb, 0x1d, 0x32, 0x0, +0xb, 0x19, 0x2a, 0x0, 0x13, 0x25, 0x3a, 0x0, 0xf, 0x1d, 0x2e, 0x0, 0xb, 0x15, 0x21, 0x0, 0x1e, 0x33, 0x4c, 0x0, +0x24, 0x3a, 0x55, 0x0, 0x12, 0x1d, 0x2a, 0x0, 0x25, 0x37, 0x4c, 0x0, 0x17, 0x22, 0x2f, 0x0, 0x1c, 0x29, 0x38, 0x0, +0x9, 0x1b, 0x33, 0x0, 0x12, 0x25, 0x3e, 0x0, 0x17, 0x2e, 0x4b, 0x0, 0xe, 0x1a, 0x2a, 0x0, 0x1b, 0x2e, 0x46, 0x0, +0x12, 0x1e, 0x2e, 0x0, 0xf, 0x19, 0x26, 0x0, 0x21, 0x36, 0x51, 0x0, 0x1e, 0x2f, 0x46, 0x0, 0x1f, 0x2e, 0x42, 0x0, +0x23, 0x32, 0x46, 0x0, 0xb, 0x1e, 0x3a, 0x0, 0x12, 0x2c, 0x51, 0x0, 0xb, 0x19, 0x2e, 0x0, 0x12, 0x29, 0x4a, 0x0, +0xe, 0x1e, 0x36, 0x0, 0x12, 0x26, 0x42, 0x0, 0x16, 0x2e, 0x50, 0x0, 0x18, 0x31, 0x56, 0x0, 0xe, 0x1d, 0x32, 0x0, +0x22, 0x40, 0x6d, 0x0, 0x12, 0x22, 0x3a, 0x0, 0x20, 0x3b, 0x60, 0x0, 0xa, 0x12, 0x1d, 0x0, 0x1a, 0x2e, 0x4a, 0x0, +0x16, 0x26, 0x3e, 0x0, 0x12, 0x1f, 0x32, 0x0, 0x3, 0x5, 0x8, 0x0, 0x18, 0x28, 0x3e, 0x0, 0x25, 0x3c, 0x5e, 0x0, +0x1a, 0x2a, 0x42, 0x0, 0x17, 0x25, 0x3a, 0x0, 0xe, 0x16, 0x22, 0x0, 0x1c, 0x2a, 0x3e, 0x0, 0x12, 0x1a, 0x26, 0x0, +0xc, 0x11, 0x18, 0x0, 0x16, 0x1e, 0x29, 0x0, 0xb, 0x1c, 0x36, 0x0, 0xb, 0x1a, 0x32, 0x0, 0x12, 0x29, 0x4f, 0x0, +0xf, 0x21, 0x3d, 0x0, 0x12, 0x26, 0x46, 0x0, 0xa, 0x15, 0x26, 0x0, 0x16, 0x2a, 0x4a, 0x0, 0x1a, 0x2e, 0x4e, 0x0, +0x17, 0x29, 0x45, 0x0, 0x1d, 0x32, 0x54, 0x0, 0x21, 0x36, 0x57, 0x0, 0x15, 0x22, 0x36, 0x0, 0x2c, 0x43, 0x69, 0x0, +0x7, 0x14, 0x2a, 0x0, 0x7, 0x12, 0x25, 0x0, 0xa, 0x16, 0x2a, 0x0, 0xe, 0x1e, 0x3a, 0x0, 0x17, 0x31, 0x5e, 0x0, +0x15, 0x2c, 0x56, 0x0, 0x12, 0x26, 0x4a, 0x0, 0x12, 0x22, 0x3e, 0x0, 0x6, 0xb, 0x14, 0x0, 0xe, 0x1a, 0x2e, 0x0, +0x1d, 0x34, 0x5b, 0x0, 0x16, 0x26, 0x42, 0x0, 0x9, 0xf, 0x1a, 0x0, 0x8, 0xd, 0x16, 0x0, 0x26, 0x3d, 0x66, 0x0, +0x1a, 0x2a, 0x46, 0x0, 0x1e, 0x2e, 0x4a, 0x0, 0x21, 0x32, 0x51, 0x0, 0x1a, 0x26, 0x3a, 0x0, 0xd, 0x13, 0x1d, 0x0, +0x23, 0x32, 0x4c, 0x0, 0x26, 0x36, 0x51, 0x0, 0x2d, 0x3f, 0x5f, 0x0, 0x35, 0x49, 0x6b, 0x0, 0x8, 0xb, 0x10, 0x0, +0x2d, 0x3c, 0x55, 0x0, 0xe, 0x22, 0x48, 0x0, 0xc, 0x1d, 0x3e, 0x0, 0x14, 0x2c, 0x5c, 0x0, 0xa, 0x16, 0x2e, 0x0, +0x12, 0x26, 0x4e, 0x0, 0x6, 0xd, 0x1a, 0x0, 0x11, 0x22, 0x42, 0x0, 0x16, 0x2a, 0x4f, 0x0, 0xe, 0x1a, 0x32, 0x0, +0xa, 0x12, 0x22, 0x0, 0x16, 0x26, 0x46, 0x0, 0x1b, 0x2e, 0x53, 0x0, 0x12, 0x1e, 0x36, 0x0, 0x1a, 0x2a, 0x4a, 0x0, +0xe, 0x16, 0x26, 0x0, 0x23, 0x37, 0x5c, 0x0, 0x1e, 0x2f, 0x4f, 0x0, 0x16, 0x22, 0x3a, 0x0, 0x1a, 0x26, 0x3e, 0x0, +0x12, 0x1a, 0x2a, 0x0, 0x27, 0x37, 0x57, 0x0, 0x1e, 0x2a, 0x42, 0x0, 0x2a, 0x3a, 0x5a, 0x0, 0xb, 0x1a, 0x3a, 0x0, +0xe, 0x1e, 0x3f, 0x0, 0x1a, 0x33, 0x68, 0x0, 0x12, 0x22, 0x46, 0x0, 0xa, 0x13, 0x26, 0x0, 0x8, 0xf, 0x1e, 0x0, +0x16, 0x26, 0x4a, 0x0, 0x1a, 0x2a, 0x4e, 0x0, 0x16, 0x23, 0x3e, 0x0, 0x21, 0x32, 0x57, 0x0, 0x1d, 0x2a, 0x46, 0x0, +0x16, 0x1f, 0x32, 0x0, 0x22, 0x2d, 0x45, 0x0, 0x44, 0x55, 0x7b, 0x0, 0x11, 0x15, 0x1e, 0x0, 0x43, 0x4f, 0x68, 0x0, +0x6b, 0x76, 0x8d, 0x0, 0xc, 0x1d, 0x48, 0x0, 0xf, 0x21, 0x4e, 0x0, 0x11, 0x26, 0x56, 0x0, 0xa, 0x16, 0x32, 0x0, +0xb, 0x18, 0x36, 0x0, 0xd, 0x1b, 0x3e, 0x0, 0xf, 0x1f, 0x44, 0x0, 0x13, 0x26, 0x53, 0x0, 0x11, 0x22, 0x4a, 0x0, +0xe, 0x1a, 0x36, 0x0, 0x16, 0x27, 0x4f, 0x0, 0x12, 0x1f, 0x3f, 0x0, 0x18, 0x29, 0x53, 0x0, 0x12, 0x1e, 0x3a, 0x0, +0x16, 0x23, 0x42, 0x0, 0xe, 0x16, 0x2a, 0x0, 0xd, 0x13, 0x22, 0x0, 0x1a, 0x26, 0x43, 0x0, 0x12, 0x1a, 0x2e, 0x0, +0x1e, 0x2b, 0x4a, 0x0, 0x16, 0x1d, 0x2e, 0x0, 0x2b, 0x36, 0x52, 0x0, 0xe, 0x20, 0x52, 0x0, 0xb, 0x19, 0x40, 0x0, +0xa, 0x13, 0x2a, 0x0, 0xe, 0x1a, 0x3a, 0x0, 0x1b, 0x2d, 0x5c, 0x0, 0xe, 0x17, 0x2e, 0x0, 0x5, 0x8, 0x10, 0x0, +0x23, 0x2e, 0x4b, 0x0, 0x4b, 0x61, 0x9f, 0x0, 0x26, 0x32, 0x51, 0x0, 0x1b, 0x22, 0x36, 0x0, 0x1f, 0x26, 0x3a, 0x0, +0x5e, 0x66, 0x7d, 0x0, 0xb, 0x1d, 0x55, 0x0, 0xf, 0x22, 0x5d, 0x0, 0x8, 0x11, 0x2e, 0x0, 0x10, 0x1c, 0x41, 0x0, +0x15, 0x23, 0x4e, 0x0, 0xe, 0x17, 0x32, 0x0, 0x17, 0x23, 0x4a, 0x0, 0x16, 0x22, 0x46, 0x0, 0x12, 0x1b, 0x36, 0x0, +0x4, 0x6, 0xc, 0x0, 0x2, 0x3, 0x6, 0x0, 0x2b, 0x40, 0x7d, 0x0, 0x15, 0x1e, 0x3a, 0x0, 0x12, 0x1a, 0x32, 0x0, +0x1b, 0x26, 0x48, 0x0, 0x35, 0x4a, 0x8b, 0x0, 0x21, 0x2e, 0x54, 0x0, 0x16, 0x1e, 0x36, 0x0, 0x1a, 0x22, 0x3a, 0x0, +0x1e, 0x26, 0x3f, 0x0, 0x2b, 0x33, 0x4d, 0x0, 0x3a, 0x43, 0x5d, 0x0, 0x8e, 0x92, 0x9e, 0x0, 0xb, 0x20, 0x6c, 0x0, +0xa, 0x15, 0x3b, 0x0, 0x11, 0x1a, 0x3a, 0x0, 0xd, 0x13, 0x29, 0x0, 0x16, 0x1f, 0x3e, 0x0, 0x1f, 0x2a, 0x4e, 0x0, +0x1a, 0x22, 0x3f, 0x0, 0x27, 0x31, 0x56, 0x0, 0x24, 0x2a, 0x3f, 0x0, 0x9, 0x12, 0x34, 0x0, 0x11, 0x17, 0x30, 0x0, +0xe, 0x13, 0x26, 0x0, 0x15, 0x1b, 0x32, 0x0, 0x12, 0x17, 0x2b, 0x0, 0x12, 0x16, 0x25, 0x0, 0x29, 0x2f, 0x48, 0x0, +0x31, 0x37, 0x4f, 0x0, 0x36, 0x3c, 0x55, 0x0, 0x15, 0x1b, 0x39, 0x0, 0x1a, 0x1f, 0x38, 0x0, 0x16, 0x1a, 0x2e, 0x0, +0x15, 0x1b, 0x3e, 0x0, 0x21, 0x27, 0x49, 0x0, 0x22, 0x27, 0x43, 0x0, 0x1a, 0x1e, 0x33, 0x0, 0x16, 0x19, 0x2a, 0x0, +0x2e, 0x32, 0x48, 0x0, 0x1f, 0x23, 0x3f, 0x0, 0x53, 0x56, 0x69, 0x0, 0x18, 0x1b, 0x35, 0x0, 0x1f, 0x22, 0x39, 0x0, +0x23, 0x25, 0x3c, 0x0, 0x28, 0x2a, 0x44, 0x0, 0x1, 0x2, 0x15, 0x0, 0x1b, 0x1c, 0x2e, 0x0, 0x3, 0x5, 0x44, 0x0, +0x2, 0x3, 0x28, 0x0, 0x2, 0x3, 0x1d, 0x0, 0x2, 0x3, 0x38, 0x0, 0x4, 0x5, 0x4f, 0x0, 0x1, 0x1, 0x3, 0x0, +0x5, 0x5, 0x8, 0x0, 0x23, 0x23, 0x36, 0x0, 0x8, 0x8, 0xc, 0x0, 0x2d, 0x2d, 0x42, 0x0, 0x3, 0x3, 0x3, 0x0, +0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x13, 0xc2, 0x60, 0x39, 0x5d, 0x3b, 0x80, 0x52, 0x40, 0x68, 0x29, 0x7d, 0x7e, 0x63, 0x76, +0xd3, 0x8a, 0x5c, 0x39, 0x5c, 0xc2, 0x5c, 0x6c, 0x6c, 0x6c, 0x6c, 0xf9, 0x10, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xf8, 0xfe, 0xf8, 0x3d, 0xc3, 0xc3, 0xc3, 0xc3, 0x3d, 0xc3, 0xc3, 0xc3, 0x3d, 0x3d, 0xf9, 0xf, 0xf8, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x13, 0x13, 0x3d, 0x61, 0x44, 0x52, 0x4f, 0x3a, 0x3a, 0x40, +0x41, 0x50, 0x82, 0x1d, 0x3f, 0x65, 0x5f, 0x5b, 0x71, 0xbb, 0x4c, 0xb7, 0xfa, 0x44, 0xde, 0xa6, 0xd3, 0xe9, 0xf2, 0xf2, +0x93, 0x5c, 0x73, 0x61, 0x73, 0x73, 0x5c, 0xb2, 0x5c, 0x8a, 0x55, 0xf5, 0x8a, 0x55, 0xbb, 0xae, 0x8a, 0xf1, 0x5c, 0x60, +0x60, 0x61, 0x9, 0x6c, 0x3d, 0x3d, 0xc3, 0x3d, 0x3d, 0xf9, 0xfd, 0xfe, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0x10, 0xfb, 0x45, +0x27, 0x43, 0x1c, 0x34, 0x7e, 0x51, 0x65, 0x69, 0x7e, 0x5e, 0x65, 0x7d, 0x7d, 0x1c, 0x4d, 0x4a, 0x2f, 0x3b, 0x43, 0xea, +0x6, 0x6, 0xb6, 0xc1, 0xb1, 0x80, 0x6, 0x6, 0xdf, 0xd6, 0x5a, 0xa0, 0x9e, 0x86, 0xd4, 0xd6, 0xbc, 0x96, 0xad, 0x96, +0xad, 0x96, 0xac, 0x9d, 0xad, 0xbb, 0x71, 0x71, 0xb1, 0xdd, 0xde, 0x93, 0x60, 0x73, 0x8a, 0x89, 0x77, 0x67, 0x5c, 0x6c, +0xb2, 0xb2, 0x3d, 0x13, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0x13, 0x3d, 0x45, 0x44, 0x3c, 0x1f, 0x1d, 0x34, 0x51, 0x50, 0x64, 0x26, 0x1c, 0x65, 0x79, 0x3a, 0x3f, +0x53, 0x7e, 0x4f, 0x23, 0x41, 0x37, 0x91, 0xd8, 0xe0, 0xd8, 0x90, 0x76, 0xc5, 0x57, 0xf0, 0x7, 0xe0, 0xa7, 0x8d, 0x74, +0x57, 0xa3, 0x8b, 0xbf, 0xb9, 0xb9, 0xad, 0x70, 0x96, 0x96, 0xac, 0x97, 0x85, 0x85, 0xbd, 0xbd, 0xe5, 0xca, 0xb1, 0xf2, +0xf2, 0xda, 0xaf, 0x9c, 0x9e, 0x9c, 0xbe, 0xbe, 0xca, 0xda, 0x73, 0xc2, 0x13, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc3, 0xb2, 0x93, 0x20, 0xea, 0x1c, 0x4e, 0x50, 0x24, 0x5f, +0x64, 0x26, 0x78, 0x3e, 0x64, 0x4f, 0x4f, 0x51, 0x7d, 0x7e, 0x5f, 0x4f, 0x78, 0x5f, 0x80, 0x91, 0xa9, 0xe5, 0xda, 0xb1, +0xa7, 0xc5, 0xcc, 0xce, 0xe0, 0xb3, 0xe1, 0xc9, 0x57, 0xc1, 0xaf, 0x96, 0xb9, 0x96, 0xb9, 0x9d, 0x96, 0xd1, 0x72, 0x85, +0x71, 0x9a, 0x4d, 0x8c, 0x7b, 0xc7, 0xc6, 0xcb, 0xee, 0xe3, 0xc1, 0x88, 0x5e, 0xb0, 0x9e, 0xbd, 0x9e, 0xd1, 0xbb, 0x55, +0xc2, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xf9, 0x9, 0x5, +0x21, 0x2b, 0x6d, 0x6d, 0x34, 0x3a, 0x29, 0x65, 0x7e, 0x3a, 0x3a, 0x63, 0x3b, 0x4f, 0x78, 0x33, 0x5e, 0x4f, 0x4f, 0x4f, +0x5f, 0x40, 0x8d, 0x5b, 0xa1, 0x9a, 0x9f, 0x9f, 0x4e, 0xa7, 0x80, 0xe1, 0xe1, 0xb5, 0x6a, 0x82, 0xa3, 0x9f, 0x9e, 0xac, +0xad, 0xb9, 0x96, 0x96, 0x96, 0x85, 0x85, 0x9a, 0x54, 0x99, 0xa4, 0xc7, 0x8d, 0xa7, 0xa4, 0xc1, 0xbc, 0xd2, 0x9b, 0xac, +0x98, 0xbd, 0x9d, 0x97, 0xad, 0xd9, 0xbb, 0xd3, 0x8a, 0xb2, 0xc3, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0x13, 0xc2, 0x45, 0x0, 0x2, 0x6, 0xe1, 0x16, 0x1c, 0x50, 0x3b, 0x51, 0x3f, 0x29, 0x1c, 0x15, 0x16, +0x4f, 0x8d, 0x78, 0x30, 0x24, 0x4d, 0x4d, 0x4f, 0x26, 0x8f, 0x5f, 0x9f, 0x2f, 0xbe, 0x9b, 0xbc, 0xa2, 0xd7, 0x69, 0xc9, +0xce, 0xd7, 0xd7, 0xe1, 0xc7, 0xc9, 0xd5, 0x97, 0x9b, 0xad, 0x9b, 0x9c, 0x9c, 0x85, 0x22, 0x48, 0x56, 0x71, 0x31, 0xcc, +0xb3, 0xc0, 0xbc, 0xbd, 0x96, 0x99, 0x9d, 0x70, 0xbc, 0x9c, 0xbc, 0x96, 0xd9, 0xbb, 0x55, 0x66, 0xaa, 0x60, 0x61, 0x3d, +0x13, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc3, 0xc2, 0x60, 0x20, 0x2c, 0xea, 0x2c, 0xe0, 0x2c, 0x1c, +0x1c, 0x59, 0x62, 0x7e, 0x2a, 0x1c, 0x15, 0x26, 0x50, 0x5f, 0x33, 0x79, 0x3a, 0x1c, 0x32, 0x63, 0x40, 0xa7, 0xa9, 0x57, +0x48, 0x71, 0x9b, 0x9e, 0xd5, 0xce, 0xec, 0xe1, 0xce, 0x94, 0xd7, 0xab, 0xd5, 0xb0, 0xd5, 0xa2, 0x96, 0x6f, 0x9c, 0x9c, +0x9b, 0x85, 0x47, 0x99, 0xbb, 0x48, 0x31, 0xcb, 0xa7, 0x9b, 0x9a, 0x9b, 0x96, 0x85, 0x9d, 0x9d, 0x55, 0x9b, 0x88, 0x9a, +0x55, 0x48, 0x1a, 0x2, 0x8, 0x1, 0x3, 0x8a, 0xb2, 0xc2, 0x10, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xf, 0xc2, 0x61, 0x42, +0x1e, 0x52, 0x2c, 0xcd, 0x1f, 0xe0, 0x1f, 0x68, 0x79, 0x50, 0x5e, 0x3a, 0x26, 0x16, 0x43, 0x1f, 0x3f, 0x51, 0x34, 0x1c, +0x40, 0x32, 0x78, 0x8d, 0x7f, 0x8d, 0x83, 0x7f, 0x9f, 0xa1, 0x9c, 0xa4, 0xcd, 0xce, 0x94, 0xec, 0x94, 0xec, 0x94, 0xc9, +0x84, 0xe6, 0xc7, 0xb0, 0xa2, 0x86, 0x9e, 0x97, 0x6f, 0x9b, 0x57, 0x57, 0x99, 0x48, 0x31, 0x57, 0xaf, 0x48, 0x99, 0x31, +0x9c, 0xbc, 0xbc, 0x96, 0x99, 0x99, 0x9f, 0x54, 0x55, 0x47, 0x91, 0xd8, 0xd, 0xfc, 0x20, 0xa5, 0x77, 0x39, 0x45, 0xfb, +0xf, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0x13, 0xb2, 0x39, 0x3c, 0x7f, 0x26, 0xb5, 0xce, 0xe0, 0xea, 0x2c, 0x69, 0x2a, 0x50, 0x4e, 0x50, 0x7d, +0x1c, 0x29, 0x29, 0x1d, 0x53, 0x3f, 0x1d, 0x4e, 0x3b, 0xc5, 0x5a, 0xa1, 0x80, 0xc7, 0xa7, 0x80, 0xa4, 0xc0, 0xa4, 0xcd, +0x7, 0xb8, 0xec, 0x7, 0xce, 0xb8, 0xb8, 0xec, 0x94, 0xb3, 0xd5, 0xc9, 0xb0, 0x9d, 0x9e, 0x72, 0x8b, 0x57, 0x9b, 0x57, +0x9f, 0x31, 0x48, 0x71, 0x99, 0x54, 0x71, 0xa4, 0xe6, 0xc0, 0xc5, 0x9b, 0x9a, 0x71, 0x54, 0x71, 0x56, 0x76, 0xe7, 0x91, +0xea, 0xcb, 0xdd, 0xa5, 0xca, 0xb1, 0xf2, 0xa, 0x9, 0xf, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x60, 0x28, 0x63, 0x7d, 0x82, 0x82, 0x6d, 0xcd, +0xe0, 0xab, 0x69, 0xb6, 0x7e, 0x3f, 0x65, 0x82, 0x6d, 0x6d, 0x3f, 0x6b, 0x6b, 0x6b, 0x94, 0xab, 0x40, 0x43, 0x64, 0x68, +0x6d, 0xb3, 0x5f, 0x8d, 0xa1, 0x8f, 0x7e, 0xe1, 0x7, 0xec, 0xec, 0xec, 0xec, 0xb8, 0x92, 0xec, 0xe1, 0xcd, 0x8e, 0x65, +0x65, 0x4d, 0x5a, 0x5a, 0x88, 0x9b, 0x48, 0x9a, 0x9a, 0x71, 0x99, 0x54, 0x71, 0xae, 0x71, 0x7a, 0xdf, 0xcd, 0xb3, 0xe5, +0x9a, 0x54, 0x71, 0x54, 0x71, 0xc1, 0x7f, 0xcd, 0xc9, 0xaf, 0x99, 0x55, 0x40, 0x7a, 0xaa, 0x6, 0xa, 0x9, 0xf9, 0xf8, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, +0x61, 0x25, 0x4f, 0x62, 0x82, 0x6a, 0x64, 0x2b, 0xcd, 0x6d, 0xab, 0x41, 0xcc, 0x53, 0x6b, 0xce, 0xec, 0x92, 0x94, 0xb8, +0x92, 0x92, 0x94, 0xec, 0x94, 0xe1, 0xe1, 0xab, 0xe1, 0x7, 0x6d, 0x68, 0x64, 0xb3, 0xe0, 0x7, 0xec, 0xec, 0x11, 0xb8, +0x11, 0x95, 0xec, 0xec, 0x7, 0xa9, 0xd7, 0x82, 0xb3, 0x64, 0x68, 0x83, 0x80, 0x57, 0x48, 0x9f, 0x71, 0x71, 0x54, 0x56, +0x54, 0xae, 0x71, 0x31, 0x8, 0x94, 0xe0, 0xc7, 0x99, 0x71, 0x22, 0x99, 0x99, 0x57, 0x8d, 0xa3, 0xbc, 0xd9, 0xd1, 0x71, +0xd8, 0x2, 0xb6, 0xd, 0x8, 0x3, 0x9, 0xfb, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x61, 0x5d, 0xa2, 0x7d, 0x64, 0x7e, 0x40, 0x1c, 0xe1, 0x94, 0xce, 0x7e, +0xe1, 0x6b, 0xce, 0xec, 0xcf, 0x6b, 0xb8, 0x95, 0x95, 0x92, 0xb8, 0x11, 0x95, 0xb8, 0x7, 0xe1, 0x94, 0xce, 0xe1, 0xcd, +0x6d, 0xce, 0x6d, 0x6d, 0xec, 0xec, 0xec, 0x11, 0xec, 0x94, 0x94, 0x7, 0xfc, 0x2c, 0xab, 0x6a, 0x69, 0xab, 0x82, 0xcd, +0x91, 0x7f, 0x8d, 0xdc, 0xa8, 0x9a, 0x2f, 0x71, 0x99, 0xbb, 0x47, 0x5b, 0xdf, 0x7, 0xe1, 0xe6, 0x88, 0x85, 0x9a, 0x99, +0x76, 0x76, 0xc1, 0x57, 0x47, 0x54, 0x37, 0xa7, 0xdf, 0x8, 0x6, 0x8, 0x8, 0x0, 0xe9, 0x45, 0xfb, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x6c, 0x39, 0x1a, 0x3a, 0x34, +0x64, 0x7e, 0x7b, 0x26, 0x6a, 0xce, 0x6b, 0x6b, 0x94, 0x94, 0x94, 0x11, 0x95, 0xec, 0x95, 0x95, 0xcf, 0x95, 0x95, 0xcf, +0xb8, 0xb8, 0xec, 0xec, 0x94, 0x94, 0x94, 0xe0, 0x6d, 0x94, 0xec, 0xce, 0x6b, 0x6b, 0x94, 0x92, 0xec, 0x92, 0x6b, 0xce, +0xea, 0xe0, 0xab, 0xe1, 0x6a, 0x6d, 0x6a, 0xab, 0x2c, 0xd8, 0x83, 0x80, 0x66, 0xa3, 0x99, 0x2f, 0x71, 0x71, 0x86, 0xa4, +0x91, 0x94, 0xce, 0xd7, 0xbd, 0xad, 0x9c, 0xa4, 0xd4, 0xb7, 0x7a, 0x48, 0x99, 0x71, 0x9f, 0xb3, 0xe7, 0xe1, 0x8, 0x8, +0xd, 0xc, 0x5, 0x0, 0x3, 0x9, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xf8, 0xc3, 0x5c, 0x28, 0x52, 0x41, 0x26, 0x4e, 0x8e, 0x1c, 0x1c, 0x15, 0x6d, 0x6d, 0x6d, 0x6a, 0xce, 0xec, 0xb8, 0xb8, +0x11, 0x92, 0x95, 0x95, 0x95, 0x95, 0x95, 0xb4, 0xb8, 0x95, 0xb8, 0xb8, 0x94, 0x94, 0xce, 0x94, 0x6b, 0xec, 0x95, 0x92, +0x6b, 0x53, 0x62, 0x53, 0x38, 0x14, 0x6a, 0x6a, 0xe1, 0xe0, 0xe1, 0xe1, 0xe1, 0xe0, 0xce, 0x1f, 0xab, 0x1f, 0x8f, 0x80, +0x66, 0x8d, 0x6e, 0x96, 0x74, 0x8b, 0x79, 0xc7, 0xe6, 0x6, 0xe1, 0xe6, 0xbd, 0x9b, 0xd5, 0xc9, 0xcd, 0xea, 0xc5, 0xaf, +0x9a, 0xbe, 0x47, 0xb6, 0xe1, 0x7, 0xe, 0x8, 0x4, 0xe, 0xc, 0xd, 0xb, 0x3, 0xfb, 0xf, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0x13, 0xc3, 0x3d, 0x3d, 0xfb, 0x61, 0x44, 0x40, 0x68, 0x1d, 0x2a, 0x79, 0x36, 0x50, 0x26, 0x16, +0x16, 0x1d, 0x84, 0xce, 0xb8, 0x11, 0xec, 0xec, 0x95, 0x92, 0xb4, 0xb8, 0xb8, 0x95, 0x95, 0x92, 0xb8, 0x92, 0xb8, 0xb8, +0x94, 0x6b, 0x94, 0x94, 0x6b, 0x94, 0x94, 0x6b, 0x6b, 0x6b, 0x36, 0x38, 0x38, 0x34, 0x5e, 0x51, 0xd7, 0x6d, 0xcd, 0xe1, +0xe1, 0x69, 0xe0, 0xe0, 0xcd, 0x68, 0xa7, 0x7f, 0x80, 0xcc, 0xc7, 0x78, 0x49, 0x58, 0x9d, 0xbd, 0xd5, 0xd5, 0xe0, 0xe6, +0xe5, 0xbd, 0xa2, 0xa2, 0xd7, 0xb5, 0xc9, 0xd5, 0xbf, 0xaf, 0x57, 0x52, 0xea, 0x6, 0xf0, 0x2, 0x0, 0xb, 0xd, 0xfc, +0x4, 0xe9, 0x45, 0xc2, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc3, 0xc2, 0x5c, 0x8a, 0x67, 0x42, 0x90, 0x43, 0x2a, +0x3f, 0x62, 0x50, 0x36, 0x62, 0x5e, 0x3a, 0x3a, 0x1c, 0x2a, 0x1d, 0x6d, 0xec, 0x95, 0x11, 0xec, 0x95, 0x95, 0xb8, 0x92, +0x95, 0x95, 0x92, 0xb8, 0x95, 0x92, 0x92, 0x6b, 0x6b, 0x6b, 0x92, 0x6b, 0x6b, 0x53, 0x6b, 0x6b, 0x92, 0x36, 0xc4, 0x6b, +0x62, 0x14, 0x34, 0x34, 0x84, 0x8e, 0x7e, 0x91, 0xab, 0x6d, 0xab, 0x82, 0x69, 0xa9, 0x64, 0x80, 0xcb, 0x8f, 0xa4, 0x88, +0x98, 0x87, 0xb0, 0xd5, 0xa9, 0xc0, 0xf0, 0xf0, 0xc0, 0xbd, 0x98, 0xb0, 0xb0, 0xa2, 0xb0, 0x62, 0xb0, 0xbd, 0xad, 0xa3, +0xe7, 0xe1, 0xfc, 0x4, 0xe8, 0x1, 0x4, 0x4, 0xf2, 0xe4, 0xdb, 0x61, 0x3d, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0xb2, +0x77, 0xc5, 0x80, 0x52, 0x7f, 0x64, 0xb5, 0x65, 0x62, 0x53, 0x51, 0x62, 0x5e, 0x1c, 0x62, 0x1c, 0x64, 0x4e, 0x69, 0x6a, +0xce, 0x11, 0x95, 0xb8, 0x95, 0xb8, 0xb8, 0x92, 0x95, 0xb8, 0xc4, 0xb8, 0xb4, 0xb8, 0xc4, 0x53, 0x92, 0x53, 0x92, 0x92, +0x94, 0x53, 0x53, 0x53, 0x36, 0x53, 0x6b, 0x36, 0x62, 0x38, 0x7d, 0x51, 0xe1, 0x6d, 0xab, 0xa9, 0x50, 0x29, 0x3f, 0x65, +0x82, 0x50, 0x7b, 0xa7, 0xd6, 0x8d, 0x4a, 0x9c, 0x6e, 0x9d, 0xa2, 0x75, 0xd5, 0xe5, 0xc9, 0xf0, 0xd6, 0xd4, 0x72, 0x87, +0x87, 0x9d, 0xb0, 0xb0, 0xac, 0xad, 0x96, 0x99, 0x90, 0x1, 0xef, 0xfc, 0xee, 0xe3, 0xe8, 0xf2, 0x81, 0xdb, 0xa6, 0x60, +0xc2, 0x13, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc2, 0x77, 0x76, 0xa4, 0x26, 0x40, 0x43, 0x2a, 0x65, 0x65, 0x82, 0x6d, 0x6a, 0x69, +0x53, 0x51, 0x2a, 0x2c, 0x2b, 0x7a, 0x8f, 0xce, 0xb8, 0x95, 0x95, 0x95, 0x92, 0x92, 0xb4, 0xb8, 0x92, 0x92, 0x92, 0x92, +0x6b, 0x6b, 0x36, 0xc4, 0x6b, 0x92, 0xc8, 0x92, 0x36, 0x38, 0x36, 0x36, 0x36, 0x53, 0x36, 0x38, 0x38, 0x58, 0x36, 0x62, +0x7d, 0xb5, 0xb5, 0x7e, 0x8c, 0x79, 0x29, 0x65, 0x7e, 0x7e, 0x8e, 0xa0, 0x8b, 0xa4, 0x57, 0x6f, 0x6e, 0x9d, 0x9b, 0x85, +0x86, 0xc0, 0xe5, 0xbf, 0xbc, 0xbc, 0xac, 0x70, 0xb0, 0xba, 0xac, 0x96, 0xd1, 0x9a, 0x76, 0x99, 0xa5, 0xe3, 0xe3, 0xe3, +0xe8, 0xef, 0x1, 0xf2, 0xa8, 0x77, 0xdb, 0x77, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x61, 0x7a, 0x78, 0x8f, 0x2a, 0x2a, +0x16, 0x26, 0x7e, 0xb3, 0x29, 0x51, 0x6a, 0x29, 0x7d, 0x62, 0xb5, 0x1f, 0x68, 0x51, 0x7e, 0xe1, 0xb8, 0x95, 0x95, 0xb8, +0x92, 0xb8, 0x92, 0x92, 0x92, 0x6a, 0x53, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x38, 0x14, 0x14, 0x1d, +0x14, 0x38, 0x38, 0x38, 0x38, 0x62, 0x58, 0x7d, 0x7e, 0x8f, 0x7e, 0x5e, 0x5e, 0x33, 0x2e, 0x1c, 0x34, 0x75, 0x34, 0xd5, +0x8e, 0xc9, 0x4b, 0x4b, 0x6e, 0x9d, 0x86, 0x99, 0x9b, 0x9c, 0xa2, 0x96, 0xd9, 0x9d, 0x87, 0xbc, 0xc0, 0x9c, 0x96, 0xd1, +0xbb, 0x54, 0x83, 0xee, 0xa5, 0xa8, 0xe9, 0xc6, 0xe8, 0xe8, 0xfa, 0x1, 0xde, 0xa6, 0xdb, 0x77, 0x5c, 0xf, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0x3d, 0xb2, 0x42, 0xa7, 0x8c, 0x40, 0x26, 0x16, 0x16, 0x1c, 0x65, 0xb5, 0x5e, 0x62, 0x3f, 0x7e, 0x65, 0x69, 0x51, 0x7d, +0x51, 0x50, 0xa9, 0xe1, 0xec, 0x95, 0x95, 0x94, 0x94, 0x94, 0x92, 0x53, 0x6a, 0x3f, 0x14, 0x3f, 0x3f, 0x36, 0x36, 0x36, +0x38, 0x38, 0x36, 0x36, 0x14, 0x50, 0x50, 0x1d, 0x38, 0x38, 0x14, 0x38, 0x38, 0x36, 0x5e, 0x8e, 0x5e, 0x8e, 0x8c, 0x58, +0x87, 0x34, 0x2e, 0x2e, 0x70, 0x87, 0x8e, 0x50, 0x8c, 0x5a, 0x33, 0x5e, 0x75, 0x9c, 0x9a, 0x9a, 0x6f, 0x85, 0x9b, 0x96, +0x9a, 0x9d, 0x9d, 0x55, 0x9b, 0x9e, 0x9f, 0x55, 0x9f, 0x3c, 0xea, 0x6, 0x2, 0x5, 0x76, 0xbe, 0xcb, 0xfc, 0x8, 0xc, +0xf2, 0xaa, 0xde, 0xa6, 0x5c, 0xf, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xb2, 0x7c, 0x27, 0x37, 0x63, 0x51, 0x1c, 0x29, 0x1c, 0xb3, 0x69, 0x50, +0x50, 0x50, 0xb3, 0x3b, 0x7e, 0x1d, 0x29, 0x7d, 0x7e, 0x40, 0x63, 0xce, 0xb8, 0xb8, 0x92, 0x94, 0x94, 0x6b, 0x53, 0x1d, +0x53, 0x14, 0x14, 0x3f, 0x38, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x14, 0x14, 0x1c, 0x2a, 0x90, 0x28, 0x37, 0x50, 0x34, +0x34, 0x33, 0x1a, 0xa8, 0x7a, 0xc0, 0x8c, 0x58, 0x58, 0x58, 0x2e, 0x30, 0x2e, 0x2e, 0x59, 0x74, 0x74, 0x6e, 0x6e, 0xb0, +0x49, 0x5a, 0x9f, 0x85, 0x6f, 0x85, 0x99, 0x96, 0xd1, 0x9b, 0x96, 0xd9, 0x9a, 0x47, 0x54, 0x55, 0x31, 0x68, 0xdf, 0x6, +0x8, 0xb6, 0x76, 0xbe, 0x7f, 0xea, 0x7, 0xe, 0x4, 0xe8, 0xde, 0xde, 0xb2, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x60, 0x7f, 0xa7, 0x3b, +0x63, 0x65, 0x2a, 0x3e, 0x63, 0x64, 0x7e, 0x3a, 0x50, 0x7e, 0x7e, 0x63, 0x50, 0x29, 0x84, 0x62, 0x51, 0x63, 0x4f, 0xa9, +0x6b, 0x92, 0x94, 0x94, 0x94, 0x6a, 0x3f, 0x51, 0x38, 0x14, 0x53, 0x53, 0x53, 0x53, 0x36, 0x53, 0x14, 0x24, 0x17, 0x28, +0x60, 0x45, 0x45, 0x13, 0xfe, 0x1a, 0x34, 0x34, 0x30, 0x3c, 0x6c, 0xb2, 0x5c, 0x60, 0x60, 0x39, 0x18, 0x18, 0x31, 0x32, +0x30, 0x2e, 0x4b, 0x74, 0x9c, 0x6e, 0x96, 0x98, 0x9e, 0x9c, 0x9b, 0x96, 0x6e, 0x96, 0x85, 0xbc, 0x96, 0x99, 0xd1, 0x99, +0x71, 0x71, 0x56, 0x56, 0x76, 0xcc, 0xdf, 0xe0, 0xe7, 0xc6, 0xda, 0x8d, 0xa3, 0xdf, 0x7, 0xe1, 0x2, 0xf2, 0xe9, 0xde, +0x9, 0x3d, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0x3d, 0x42, 0x7f, 0xa7, 0x5f, 0x5f, 0x8f, 0x3e, 0x80, 0x80, 0xa9, 0x5e, 0x79, 0x65, 0x1c, 0x69, 0x50, +0x5e, 0xc9, 0x7d, 0x6a, 0x68, 0x7e, 0x4f, 0x1d, 0xce, 0x94, 0x94, 0x94, 0x6a, 0x6a, 0x3f, 0x1d, 0x3f, 0x38, 0x38, 0x6b, +0x53, 0x38, 0x16, 0x1a, 0x1b, 0x39, 0x45, 0x60, 0x60, 0x60, 0x39, 0xc2, 0xc2, 0x3c, 0x24, 0x33, 0x33, 0x31, 0x5c, 0x5c, +0x60, 0xd3, 0x55, 0x8a, 0x55, 0x73, 0x73, 0x8a, 0x77, 0x7a, 0x5b, 0xa1, 0x6f, 0x97, 0x97, 0x97, 0x49, 0x9e, 0x9c, 0xad, +0x6f, 0x9d, 0x96, 0xd1, 0xd1, 0xd1, 0x47, 0x99, 0x54, 0x54, 0x54, 0xae, 0x76, 0xca, 0xea, 0xc9, 0xaf, 0x9a, 0x54, 0x64, +0x8d, 0xfa, 0x94, 0x7, 0xd, 0xef, 0x1, 0xf2, 0xde, 0x61, 0xc3, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x3d, 0xa6, 0x41, 0x3b, 0x5f, 0x43, 0x40, 0x8d, 0x8d, +0x5f, 0x3a, 0x7b, 0x7e, 0x8f, 0x40, 0x8f, 0x1c, 0x4d, 0x4f, 0x3f, 0x53, 0x7d, 0x63, 0x7e, 0x84, 0x6a, 0x6b, 0x6b, 0x53, +0x3f, 0x3f, 0x3f, 0x14, 0x53, 0x53, 0x38, 0x14, 0x19, 0x1b, 0x73, 0x39, 0x39, 0x8a, 0x1b, 0x42, 0x28, 0x25, 0x81, 0x6c, +0x61, 0x1a, 0x4b, 0x34, 0x33, 0x76, 0xb2, 0x5c, 0x8a, 0x56, 0x56, 0x2f, 0x71, 0x54, 0x55, 0x39, 0x8a, 0x8a, 0x60, 0x77, +0x76, 0x97, 0xac, 0x6e, 0x6e, 0x6e, 0x9e, 0x85, 0x6f, 0x9e, 0x9d, 0x96, 0x6f, 0x97, 0x9f, 0x55, 0x54, 0x2f, 0x99, 0x71, +0x47, 0x37, 0x7a, 0x9b, 0xbb, 0xd9, 0x2f, 0xdf, 0xea, 0xb7, 0xe, 0x7, 0xb, 0xfa, 0xef, 0xdf, 0x0, 0xdb, 0xb2, 0x3d, +0xc3, 0x13, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf, +0x61, 0x90, 0x3e, 0x2c, 0x1c, 0x3b, 0x78, 0x4d, 0x8d, 0x7e, 0x63, 0x7e, 0x3a, 0x4d, 0x3e, 0x63, 0x4f, 0x4f, 0x5e, 0x38, +0x50, 0x1c, 0x51, 0x1d, 0x6a, 0x6a, 0x6b, 0x6b, 0x3f, 0x3f, 0x14, 0x38, 0x3f, 0x16, 0x1a, 0x39, 0x61, 0x39, 0x1b, 0x55, +0x1b, 0x18, 0x25, 0x25, 0x5d, 0x5d, 0x56, 0xb2, 0x8a, 0x31, 0x30, 0x75, 0x4b, 0x5d, 0x5c, 0x5c, 0x8a, 0x9f, 0x47, 0x71, +0x71, 0x22, 0x22, 0x56, 0x4c, 0x4c, 0x77, 0x8a, 0x73, 0x54, 0x85, 0x6e, 0x49, 0x74, 0x74, 0x86, 0x6f, 0x9e, 0xb0, 0x9d, +0x9c, 0x96, 0x6f, 0x56, 0x71, 0x54, 0x54, 0x71, 0x48, 0x48, 0x47, 0x48, 0x55, 0x37, 0x83, 0xea, 0x6, 0x7, 0x6, 0x6, +0x4, 0xee, 0xee, 0xef, 0xfa, 0xe9, 0x5c, 0x5c, 0x5c, 0xc2, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc2, 0x45, 0x66, 0x6d, 0x1f, 0x16, 0x4f, 0x3b, 0x52, 0x65, 0x3f, 0x65, +0x3a, 0x2a, 0x26, 0x5f, 0x3b, 0x5f, 0x4d, 0x38, 0x5e, 0x51, 0x51, 0x1d, 0x6b, 0xce, 0xce, 0x1d, 0x6a, 0x38, 0x38, 0x24, +0x25, 0x1b, 0x1b, 0x39, 0x1b, 0x1b, 0x18, 0x2f, 0x17, 0x35, 0x76, 0x76, 0x5d, 0x37, 0xd3, 0x6c, 0x8a, 0x31, 0x4d, 0x24, +0x32, 0x1a, 0x5c, 0x5c, 0x61, 0x76, 0x2d, 0x2f, 0x22, 0x71, 0x71, 0x2f, 0x71, 0x56, 0x77, 0x55, 0x55, 0x55, 0x55, 0x99, +0x6f, 0x49, 0x49, 0x2d, 0x6e, 0x72, 0x72, 0x9d, 0x96, 0x97, 0x86, 0x48, 0x54, 0x56, 0x2f, 0x5d, 0x2f, 0x71, 0x71, 0x54, +0xae, 0x48, 0xdf, 0x91, 0x7, 0x6, 0x6, 0x6, 0x8, 0x0, 0xd8, 0x2, 0xc, 0x93, 0xa6, 0x77, 0x77, 0x73, 0xc2, 0xf8, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0x67, 0x6d, 0x1c, +0x2c, 0x43, 0x3b, 0x40, 0x5f, 0x62, 0x51, 0x1c, 0x29, 0x15, 0x16, 0x3a, 0x3b, 0x64, 0x34, 0x3f, 0x53, 0x3f, 0x53, 0xce, +0x6b, 0x6a, 0x29, 0x1d, 0x14, 0x3a, 0x35, 0x39, 0x39, 0x1b, 0x73, 0x1b, 0x17, 0x22, 0x2f, 0x17, 0x4a, 0x37, 0x76, 0xb1, +0x18, 0xa1, 0xa5, 0x5c, 0x8a, 0x17, 0x75, 0x33, 0x33, 0x37, 0x5c, 0x5c, 0x73, 0x54, 0x9f, 0x22, 0x22, 0x71, 0x71, 0x2f, +0x48, 0x56, 0x4c, 0x55, 0x55, 0x55, 0x55, 0x54, 0x8a, 0x99, 0x74, 0x74, 0x6e, 0x72, 0x74, 0x9c, 0x6f, 0x6f, 0x48, 0x22, +0x54, 0x54, 0x56, 0x55, 0x54, 0x56, 0x71, 0x56, 0x56, 0x48, 0x80, 0x7, 0xec, 0x6, 0x6, 0xd, 0x6, 0xd, 0xe, 0x8, +0x4, 0xf2, 0xe4, 0xa8, 0xdd, 0xd3, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0x13, 0xf, 0x13, 0xc3, 0x5c, 0x2c, 0x1d, 0x1d, 0x3f, 0x29, 0x64, 0x4e, 0x5e, 0x5e, 0x3a, 0x2a, 0x16, 0x15, 0x1c, 0x7d, +0x50, 0x38, 0x53, 0x53, 0x53, 0x53, 0x6b, 0x53, 0x6a, 0x82, 0x3f, 0x50, 0x7a, 0x39, 0x45, 0x1b, 0x55, 0x4c, 0x18, 0x17, +0x17, 0x48, 0x22, 0x22, 0xa1, 0x4a, 0x5a, 0x76, 0xc1, 0x31, 0x7c, 0x60, 0x39, 0x47, 0x49, 0x24, 0x5e, 0x31, 0x5c, 0x6c, +0x5c, 0x54, 0x48, 0x2f, 0x2f, 0x2f, 0x22, 0x5d, 0x56, 0x56, 0x89, 0x55, 0x89, 0x89, 0x55, 0x56, 0x54, 0x54, 0x54, 0x76, +0x74, 0x72, 0x5a, 0x4a, 0x86, 0x2d, 0x48, 0x2f, 0x99, 0x71, 0x55, 0x55, 0x54, 0x54, 0x54, 0x71, 0xbb, 0x57, 0x80, 0x6, +0x7, 0x8, 0x8, 0x0, 0xc, 0xe, 0x8, 0xfc, 0xee, 0xe8, 0xe8, 0xdd, 0x76, 0xb1, 0x73, 0x3d, 0xf8, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc3, 0xc2, 0xb2, 0x5c, 0x60, 0x41, 0x2a, 0x40, 0x1c, 0x29, 0x1d, 0x65, 0x79, +0x79, 0x51, 0x7e, 0x3a, 0x1c, 0x15, 0x1c, 0x6a, 0x53, 0x53, 0x6b, 0x6b, 0x6b, 0x6b, 0x84, 0x6a, 0x69, 0x29, 0x65, 0x25, +0x60, 0x39, 0x73, 0x39, 0x18, 0x1a, 0x17, 0x3c, 0x31, 0x17, 0x6f, 0x22, 0x74, 0xbc, 0xa0, 0xa4, 0x4d, 0xa2, 0xa4, 0x2f, +0x4c, 0x99, 0x49, 0x34, 0x4b, 0x48, 0x5c, 0xb2, 0x5c, 0x9a, 0x6e, 0x88, 0x76, 0xb1, 0x5d, 0x48, 0x47, 0x48, 0x71, 0x56, +0x56, 0x18, 0x18, 0x22, 0x54, 0x54, 0x4c, 0x89, 0x4c, 0x74, 0x5a, 0x86, 0x72, 0x5a, 0x4a, 0x35, 0x71, 0x99, 0x4c, 0x76, +0x71, 0x54, 0x71, 0x54, 0x99, 0x31, 0xcc, 0x7, 0xec, 0x6, 0xfc, 0xee, 0x4, 0xfc, 0xfc, 0xb6, 0xed, 0xc6, 0xdc, 0x71, +0x9a, 0x71, 0x8a, 0xc2, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0x3d, 0x61, 0xa6, 0x81, 0x27, 0x3c, +0x80, 0xc5, 0x78, 0x4f, 0x5f, 0x68, 0x43, 0x50, 0x51, 0x4e, 0x3f, 0x1c, 0x64, 0x50, 0x1d, 0x6b, 0x6b, 0x6a, 0x14, 0x6b, +0x53, 0x14, 0x3f, 0x3f, 0x82, 0x43, 0x42, 0x60, 0x60, 0x60, 0x39, 0x42, 0x3c, 0x17, 0x32, 0x23, 0x4a, 0x2d, 0x2d, 0x9c, +0x34, 0x59, 0x75, 0x8c, 0x4e, 0x38, 0x79, 0x3c, 0x4c, 0x31, 0x49, 0x4b, 0x6e, 0x31, 0x5c, 0x5c, 0x5c, 0x5a, 0x49, 0x88, +0x59, 0x75, 0x78, 0x74, 0x57, 0x48, 0x22, 0x48, 0x48, 0x47, 0x22, 0x22, 0x2f, 0x54, 0x56, 0x56, 0x55, 0x55, 0x57, 0x23, +0x30, 0x4b, 0x57, 0x76, 0x47, 0x2d, 0x31, 0x48, 0x48, 0x55, 0x56, 0x54, 0x31, 0xd6, 0x7f, 0xfc, 0x7, 0x8, 0xe, 0xef, +0xef, 0xee, 0x0, 0xa8, 0x7c, 0xdd, 0x71, 0xb1, 0x56, 0x56, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xf8, 0x3d, 0x5c, 0x25, 0x52, 0x3e, 0x5f, 0x37, 0x8d, 0x9c, 0xbc, 0x88, 0x31, 0x3e, 0x90, 0x83, 0x53, 0x51, 0x64, 0x2c, +0x1f, 0x6d, 0x53, 0x53, 0x6b, 0x53, 0x3f, 0x38, 0x14, 0x1c, 0x50, 0x7d, 0x83, 0x67, 0x45, 0x60, 0x60, 0x1b, 0x25, 0x1a, +0x3c, 0x31, 0x30, 0x74, 0x4a, 0x4b, 0x49, 0x49, 0x59, 0x58, 0x33, 0x7b, 0x3a, 0x34, 0x50, 0x3b, 0x4c, 0x76, 0x72, 0x49, +0x6e, 0x9f, 0x5c, 0xc2, 0x8a, 0x58, 0x59, 0x72, 0x2e, 0x58, 0x70, 0x49, 0x5a, 0x6e, 0x2d, 0x4a, 0x2d, 0x47, 0x22, 0x22, +0x22, 0x22, 0x18, 0x4c, 0x8a, 0x8a, 0x77, 0x18, 0x37, 0x37, 0x4a, 0x4a, 0x4a, 0x48, 0x57, 0x35, 0x2f, 0x2f, 0x31, 0x37, +0x57, 0x7f, 0x41, 0xd, 0x7, 0x6, 0xef, 0xee, 0xf0, 0x2, 0xe8, 0xc6, 0x77, 0xa5, 0xb1, 0xb1, 0xa5, 0x60, 0xc2, 0x13, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x13, 0x6c, 0x28, 0x43, 0x68, 0x26, 0x23, 0x75, 0xaf, 0x9a, 0x9b, 0x76, +0x9f, 0x57, 0xc6, 0xb6, 0x62, 0x36, 0xb5, 0x1f, 0x6a, 0x6b, 0x53, 0x34, 0x14, 0x6b, 0x36, 0x33, 0x24, 0x34, 0x50, 0x41, +0x42, 0x60, 0x39, 0x45, 0x39, 0x25, 0x3c, 0x19, 0x17, 0x17, 0x2e, 0x2e, 0x74, 0x75, 0x58, 0x2e, 0x59, 0x70, 0x59, 0x4d, +0xa2, 0x34, 0x79, 0x37, 0x4c, 0x56, 0x30, 0x34, 0x74, 0x18, 0x5c, 0x5c, 0x99, 0x59, 0x2e, 0x70, 0x2e, 0x87, 0x70, 0x32, +0x49, 0x2e, 0x72, 0x4b, 0x2d, 0x2d, 0x48, 0x22, 0x22, 0x54, 0x18, 0x56, 0x55, 0x56, 0x55, 0x8a, 0x18, 0x37, 0x31, 0x31, +0x4a, 0x31, 0x48, 0x47, 0x7f, 0x76, 0x17, 0x1f, 0x7a, 0x7a, 0xea, 0xe7, 0x8, 0xe, 0xee, 0x0, 0xee, 0x4, 0x1, 0x67, +0x77, 0xae, 0xa5, 0xd3, 0x8a, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x3d, 0x45, 0x46, 0x1f, +0x1d, 0x2c, 0x78, 0x74, 0xd1, 0xd1, 0xd2, 0x76, 0xb1, 0x96, 0x76, 0xb6, 0x82, 0x84, 0x82, 0x6a, 0x6b, 0x6b, 0x36, 0x33, +0x14, 0x53, 0x62, 0x33, 0x33, 0x34, 0x3c, 0x67, 0x39, 0x39, 0x39, 0xa6, 0x7c, 0x5d, 0x35, 0x32, 0x4a, 0x57, 0x75, 0x59, +0x59, 0x75, 0x65, 0x34, 0x58, 0x58, 0x59, 0x2e, 0x58, 0x58, 0x59, 0x74, 0xa5, 0x4c, 0x55, 0x56, 0x4c, 0x77, 0x5c, 0x73, +0x6e, 0x30, 0x70, 0x87, 0x70, 0x70, 0x49, 0x5a, 0x49, 0x6e, 0x6e, 0x59, 0x32, 0x6e, 0x31, 0x17, 0x2f, 0x18, 0xb1, 0x2f, +0x2f, 0x56, 0x56, 0x8a, 0x77, 0x18, 0x35, 0x86, 0x57, 0x57, 0x99, 0x47, 0x50, 0x4a, 0x47, 0x69, 0x80, 0x6, 0x7, 0x41, +0xdf, 0x6, 0xe, 0xc, 0x6, 0xd, 0xb, 0xde, 0xe4, 0xde, 0xda, 0x76, 0x7c, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0x44, 0x21, 0x2c, 0x15, 0x2b, 0x5f, 0xba, 0xac, 0xbc, 0xbe, 0xd3, 0x76, 0xa1, 0x9f, 0x3c, +0x8e, 0x82, 0x1d, 0xce, 0x92, 0x94, 0x3f, 0x38, 0x53, 0x3f, 0x14, 0x14, 0x29, 0x3c, 0x39, 0x39, 0x39, 0x42, 0x25, 0x5d, +0x1a, 0x37, 0x37, 0x32, 0x4d, 0x49, 0x59, 0x59, 0x58, 0x7b, 0x4e, 0x34, 0x34, 0x70, 0x34, 0x33, 0x2e, 0x58, 0x58, 0x5a, +0x56, 0x55, 0x55, 0x56, 0x8a, 0x73, 0x61, 0x55, 0x5a, 0x30, 0x49, 0x59, 0x2e, 0x2e, 0x49, 0x6e, 0x2e, 0x70, 0x2e, 0x74, +0x4b, 0x49, 0x32, 0x23, 0x47, 0x9f, 0x48, 0x2f, 0x2f, 0x71, 0x56, 0x77, 0x55, 0x55, 0x56, 0x4b, 0x31, 0x57, 0x31, 0x57, +0x7b, 0x33, 0x64, 0xcd, 0x2, 0x8, 0xea, 0x8, 0x2, 0xc, 0xe, 0xd, 0x6, 0xfc, 0xd, 0x0, 0xa8, 0xa8, 0xe3, 0xd4, +0xb1, 0x8a, 0xc2, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x6c, 0x46, 0x43, 0x43, 0x84, 0x50, 0xbf, 0xac, +0x97, 0x85, 0x89, 0x56, 0x7a, 0x8b, 0x8b, 0x37, 0x26, 0x6a, 0x1d, 0xce, 0x92, 0x94, 0x1d, 0x6b, 0x53, 0x1d, 0x14, 0x38, +0x21, 0x60, 0x39, 0x42, 0x28, 0x3c, 0x31, 0x3c, 0x7a, 0x3c, 0x5f, 0x33, 0x33, 0x59, 0x59, 0x58, 0x34, 0x3a, 0x4e, 0x75, +0x2e, 0x59, 0x49, 0x49, 0x59, 0x59, 0x9d, 0x72, 0xc1, 0x54, 0x47, 0x2e, 0x56, 0x55, 0x35, 0x6e, 0x98, 0x2e, 0x5a, 0x6e, +0x30, 0x70, 0x70, 0x2e, 0x6e, 0x49, 0x2e, 0x5a, 0x30, 0x32, 0x30, 0x24, 0x4b, 0x86, 0x18, 0x2f, 0x76, 0x31, 0x18, 0x4c, +0x55, 0x55, 0x4c, 0x2f, 0x23, 0x4a, 0x57, 0x74, 0x4b, 0x29, 0x84, 0x66, 0x41, 0xb6, 0x99, 0xb7, 0x1, 0xe4, 0x8, 0x8, +0x7, 0xd, 0xfc, 0xef, 0xe8, 0xb1, 0xc6, 0x76, 0x71, 0xbb, 0x73, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, +0x6c, 0x1a, 0x40, 0x41, 0x7e, 0x79, 0x5a, 0xbc, 0xbb, 0x99, 0xae, 0x9f, 0xa7, 0x5f, 0x78, 0x40, 0x2c, 0x6d, 0x6a, 0x53, +0x94, 0xce, 0x14, 0x1d, 0x14, 0x34, 0x38, 0x4f, 0x39, 0x60, 0x39, 0x42, 0x27, 0x25, 0x3c, 0x19, 0x37, 0x19, 0x50, 0x14, +0x34, 0x34, 0x2e, 0x59, 0x59, 0x59, 0x59, 0x59, 0x33, 0x33, 0x2e, 0x75, 0x2e, 0x49, 0x5a, 0x98, 0x87, 0x98, 0x5a, 0x75, +0xd3, 0x9f, 0x8c, 0x58, 0x59, 0x30, 0x5a, 0x2e, 0x2e, 0x72, 0x98, 0x2e, 0x2e, 0x6e, 0x30, 0x30, 0x4b, 0x74, 0x4b, 0x33, +0x4d, 0x23, 0x31, 0x48, 0x6f, 0xa3, 0x76, 0x56, 0x4c, 0x4c, 0x56, 0x8a, 0x31, 0x9c, 0x9c, 0x4a, 0x32, 0x65, 0x8e, 0x31, +0x56, 0x76, 0x54, 0xc6, 0xb6, 0xed, 0xef, 0x4, 0xa, 0x0, 0x2, 0xe8, 0xa8, 0xa5, 0x71, 0x9a, 0xda, 0xa3, 0x8a, 0xc3, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xfb, 0x27, 0x64, 0x3a, 0x7b, 0xa4, 0xaf, 0xae, 0xd9, 0x99, 0x74, 0x74, +0xa3, 0x5f, 0x37, 0x2a, 0xce, 0x94, 0xce, 0xce, 0x1d, 0xce, 0x6d, 0x14, 0x38, 0x14, 0x26, 0x1b, 0x45, 0x39, 0x45, 0x42, +0x1a, 0x3c, 0x52, 0x5f, 0x63, 0x24, 0x14, 0x34, 0x58, 0x34, 0x49, 0x58, 0x58, 0x58, 0x33, 0x30, 0x4d, 0x4d, 0x4d, 0x4e, +0x34, 0x59, 0x58, 0x70, 0x87, 0x74, 0x9c, 0xa2, 0x18, 0x31, 0x23, 0xa2, 0x70, 0x5a, 0x6e, 0x72, 0x70, 0x30, 0x32, 0x6e, +0x30, 0x30, 0x32, 0x30, 0x30, 0x32, 0x5b, 0xc7, 0x3b, 0x5f, 0x32, 0x37, 0x57, 0x76, 0x76, 0x71, 0x56, 0xb1, 0x18, 0x4c, +0x55, 0x86, 0x2e, 0x4a, 0x30, 0x1c, 0x24, 0x4a, 0x35, 0x90, 0xd, 0xf0, 0xd6, 0x7f, 0xed, 0x0, 0xa, 0x5, 0xe9, 0xdb, +0xa8, 0xbb, 0xbe, 0x99, 0x9f, 0xc7, 0xbe, 0xb2, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf, 0x6c, 0xdd, 0x64, 0x7e, +0x78, 0xa1, 0x9a, 0x71, 0x9c, 0x97, 0x75, 0x8b, 0x5b, 0x5b, 0x5f, 0x1f, 0x7, 0x94, 0x7, 0x6d, 0x6d, 0x2a, 0x29, 0x38, +0x38, 0x1c, 0x1e, 0x45, 0x39, 0x1b, 0x28, 0x3c, 0x19, 0x37, 0x57, 0x24, 0x5e, 0x14, 0x58, 0x34, 0x14, 0x34, 0x30, 0x32, +0x32, 0x74, 0x32, 0x75, 0x24, 0x75, 0x79, 0x79, 0x5e, 0xb0, 0x59, 0x70, 0x30, 0x5a, 0x74, 0x78, 0xdb, 0x4a, 0x4d, 0x74, +0x5a, 0x49, 0x4b, 0x49, 0x58, 0x4b, 0x6e, 0x2e, 0x6e, 0x32, 0x32, 0x4f, 0x24, 0x5f, 0x52, 0x8d, 0x4f, 0x3b, 0x37, 0x32, +0x31, 0x76, 0x2f, 0x48, 0x71, 0x18, 0x5d, 0xb1, 0x4c, 0x55, 0x74, 0x32, 0x32, 0x24, 0x63, 0x8d, 0x26, 0xef, 0x6, 0x8, +0xeb, 0xb6, 0xea, 0xee, 0xf2, 0xe9, 0xa5, 0xdd, 0x99, 0x71, 0x99, 0x76, 0xbe, 0xd2, 0xbe, 0x73, 0xc3, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xf8, 0x3d, 0x60, 0xa8, 0x7f, 0x5f, 0x8b, 0x74, 0x85, 0x9a, 0xa2, 0x5a, 0x4d, 0x75, 0x7b, 0x50, 0x3a, 0x1d, +0x1d, 0xce, 0xe0, 0x6, 0xe1, 0x2c, 0x14, 0x38, 0x14, 0x52, 0x39, 0x39, 0x39, 0x1b, 0x1a, 0x3e, 0x3b, 0x5b, 0x4a, 0x33, +0x50, 0x34, 0x33, 0x33, 0x59, 0x30, 0x4a, 0x22, 0xf7, 0xf3, 0xf3, 0x32, 0x4d, 0x4d, 0x5e, 0x79, 0xa2, 0x59, 0xba, 0xb0, +0x79, 0x49, 0x88, 0xa0, 0x7c, 0x31, 0x8b, 0x72, 0x98, 0x4b, 0x4b, 0xa2, 0x4d, 0x30, 0x30, 0x6e, 0x32, 0x32, 0x23, 0x4b, +0x4b, 0x32, 0x19, 0x8d, 0x37, 0xa4, 0x4b, 0x74, 0x78, 0xa3, 0x48, 0x85, 0x76, 0x76, 0x35, 0x18, 0x4c, 0x55, 0x18, 0x4b, +0x30, 0x4b, 0x63, 0x7e, 0xe6, 0xfc, 0x2, 0xc, 0x4, 0x6, 0x7, 0xcb, 0xef, 0xe8, 0xdd, 0xa5, 0x71, 0xae, 0x54, 0x4c, +0xd3, 0x71, 0x99, 0x55, 0xb2, 0xfe, 0xfe, 0xf8, 0xf8, 0xf8, 0xc3, 0x60, 0x1e, 0x3c, 0x76, 0x57, 0x86, 0x57, 0x9f, 0x9e, +0x59, 0xc9, 0xc9, 0x8e, 0x4e, 0x65, 0x2a, 0x83, 0x2b, 0x1f, 0x1f, 0x2c, 0x1f, 0xea, 0x1d, 0x29, 0x4f, 0x39, 0x67, 0x67, +0x39, 0x25, 0x1a, 0x52, 0x3e, 0x3a, 0x33, 0x50, 0x50, 0x14, 0x4f, 0x24, 0x4d, 0x37, 0x85, 0xf7, 0xf4, 0xf4, 0xf3, 0xf6, +0x4d, 0x30, 0x2e, 0x4d, 0x49, 0x87, 0x70, 0x58, 0xb0, 0x78, 0xa1, 0x78, 0xa6, 0x76, 0x8b, 0xa0, 0x59, 0x70, 0x5a, 0x4b, +0x30, 0x59, 0x30, 0x32, 0x2e, 0x6e, 0x30, 0x30, 0x4b, 0x8d, 0x23, 0x8d, 0x8d, 0x78, 0x59, 0x32, 0x5f, 0x8d, 0x57, 0x9f, +0x76, 0x5d, 0x35, 0x54, 0x4c, 0x4c, 0x8a, 0x47, 0x30, 0x4d, 0x4e, 0x82, 0x82, 0xcd, 0xef, 0x1, 0x4, 0x2, 0xea, 0xfc, +0x1, 0xe4, 0xdd, 0xd3, 0xae, 0x56, 0xae, 0x54, 0xae, 0x99, 0x99, 0xdd, 0x67, 0xf, 0xf8, 0x3d, 0xc2, 0x13, 0x6c, 0x42, +0x52, 0x35, 0x9f, 0x6f, 0x86, 0x57, 0x88, 0x9d, 0x4d, 0x64, 0x2a, 0x6a, 0x7d, 0x64, 0x2c, 0x2a, 0x91, 0xe0, 0xe0, 0xea, +0xe1, 0xe0, 0x1f, 0xcd, 0x44, 0x39, 0x67, 0x67, 0x28, 0x27, 0x3c, 0x37, 0x5f, 0x65, 0x51, 0x50, 0x14, 0x4e, 0x4d, 0x78, +0x4f, 0x4f, 0xf7, 0xf4, 0x54, 0x19, 0xd1, 0xf3, 0x71, 0x5f, 0x34, 0x79, 0xb0, 0x87, 0x87, 0xa2, 0x7b, 0x8d, 0x7a, 0xa4, +0x7c, 0x76, 0x5f, 0x4d, 0x75, 0x59, 0x75, 0x32, 0x33, 0x4b, 0x4b, 0x30, 0x2e, 0x30, 0x30, 0x75, 0x23, 0xa4, 0xa4, 0x5b, +0x8d, 0x23, 0x4d, 0x4d, 0x5b, 0x78, 0x9c, 0x9f, 0x4a, 0x31, 0x76, 0x56, 0x56, 0x54, 0x55, 0x77, 0x4a, 0x30, 0x7b, 0x7b, +0x8f, 0x91, 0x91, 0x2, 0x20, 0xaa, 0xbe, 0xb6, 0x0, 0xa8, 0xa8, 0xb1, 0x9a, 0x9a, 0xd3, 0x56, 0xbe, 0xbe, 0x71, 0xa5, +0x7c, 0x9, 0xc2, 0x73, 0x55, 0xc3, 0x5c, 0x1e, 0x37, 0x86, 0x47, 0x47, 0x57, 0x88, 0xa0, 0x8b, 0x3a, 0x68, 0xb3, 0x3f, +0x3f, 0x69, 0xab, 0x29, 0x3f, 0xce, 0xe1, 0x6, 0xea, 0xd8, 0xab, 0xb6, 0x45, 0x39, 0x45, 0xde, 0x3c, 0x7a, 0x52, 0x3b, +0x4d, 0x4d, 0x1c, 0x4e, 0x4e, 0x4d, 0x37, 0x76, 0xd1, 0xbc, 0xad, 0xf6, 0x18, 0x31, 0xf3, 0xf6, 0x55, 0x4d, 0x30, 0x32, +0x70, 0xc4, 0x87, 0xa0, 0x63, 0x3b, 0x3c, 0x8d, 0x5d, 0xa1, 0x5b, 0x78, 0x33, 0x32, 0x24, 0x4d, 0x4b, 0x32, 0x4d, 0x2e, +0x30, 0x30, 0x32, 0x23, 0x4d, 0x32, 0x23, 0x37, 0x23, 0x5b, 0x32, 0x5b, 0x5b, 0x4b, 0x5a, 0x31, 0x74, 0x57, 0x31, 0x2f, +0x18, 0x18, 0x55, 0x8a, 0x22, 0x5b, 0x5f, 0x3b, 0x40, 0x91, 0xe7, 0xe7, 0xf2, 0xa8, 0xae, 0xc6, 0xdc, 0xda, 0xbe, 0x99, +0x99, 0x56, 0x56, 0xd9, 0x99, 0x48, 0xd2, 0xd2, 0xc1, 0x39, 0x73, 0x54, 0x99, 0xc2, 0x60, 0x76, 0xa1, 0x86, 0x2d, 0x86, +0x59, 0x5a, 0xa0, 0x79, 0x3f, 0xab, 0xab, 0x69, 0x69, 0x29, 0x82, 0x82, 0x6d, 0xe0, 0x1f, 0xe0, 0x2c, 0x1f, 0x83, 0x60, +0x60, 0x45, 0x93, 0xaa, 0x52, 0x35, 0x8d, 0x4f, 0x34, 0x3a, 0x2a, 0x3a, 0x33, 0x4a, 0xb1, 0xf3, 0xf6, 0xf3, 0xd9, 0xf3, +0xf6, 0xf6, 0xf6, 0x73, 0x57, 0x34, 0x74, 0x74, 0xb0, 0x87, 0x70, 0xa0, 0xd5, 0x63, 0x35, 0x23, 0x56, 0x76, 0x4b, 0x30, +0x4d, 0x75, 0x34, 0x34, 0x32, 0x32, 0x75, 0x30, 0x33, 0x4d, 0x5f, 0x32, 0x4b, 0x3e, 0x4d, 0x78, 0x78, 0x32, 0x5a, 0x4b, +0x5b, 0x5b, 0x35, 0x4a, 0x2d, 0x37, 0x31, 0x9a, 0x71, 0x4c, 0x56, 0x4c, 0x8a, 0x5b, 0x32, 0x3b, 0x40, 0xe7, 0xb3, 0x8f, +0xca, 0xb6, 0xc, 0xf0, 0xca, 0xdc, 0xb1, 0x77, 0xb1, 0x56, 0x99, 0x99, 0x9a, 0x76, 0xe5, 0xc6, 0xdd, 0xde, 0xd3, 0xb1, +0xa5, 0xb2, 0xa6, 0xc1, 0x4a, 0x86, 0x9c, 0x49, 0x58, 0x59, 0x4d, 0x69, 0x82, 0x1f, 0x1f, 0x1d, 0x53, 0x38, 0x69, 0x69, +0x64, 0x29, 0x1f, 0xea, 0xd8, 0x2c, 0xaa, 0x61, 0x60, 0x45, 0xde, 0x27, 0x3c, 0x7a, 0x3e, 0x26, 0x16, 0x1c, 0x15, 0x2a, +0x3e, 0x31, 0xf6, 0xf6, 0xf1, 0xf6, 0xf7, 0xf6, 0xf6, 0xf4, 0x61, 0x74, 0x49, 0x30, 0x4b, 0x4b, 0x8c, 0x7b, 0x8d, 0x5f, +0x8c, 0xa4, 0x7a, 0x63, 0xdb, 0x76, 0x78, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x32, 0x74, 0x5a, 0x4b, 0x5a, 0x32, 0x5b, 0x4b, +0x32, 0x52, 0x63, 0x7b, 0x4d, 0x63, 0x8c, 0x4b, 0x30, 0x32, 0x4a, 0x74, 0x31, 0x4a, 0x74, 0x48, 0x54, 0x56, 0x56, 0x55, +0x8a, 0x71, 0x4b, 0x23, 0xa7, 0x40, 0x8f, 0x7b, 0xd6, 0x0, 0x2, 0xf0, 0xe3, 0xa8, 0x9f, 0x56, 0x7c, 0xa5, 0xb1, 0xa5, +0xb1, 0xb1, 0xdb, 0xdd, 0xa5, 0xa5, 0xb1, 0xda, 0xb1, 0x60, 0xb1, 0xc1, 0x86, 0x4b, 0x49, 0x49, 0x49, 0x34, 0x4d, 0x65, +0x29, 0x7d, 0x38, 0x69, 0x7d, 0x7e, 0x82, 0x69, 0x29, 0x68, 0x2c, 0x2c, 0x1f, 0xd8, 0x67, 0x61, 0x60, 0x60, 0x42, 0x5d, +0x27, 0x20, 0x3e, 0x1c, 0x15, 0x2c, 0x2a, 0x43, 0x1e, 0x7a, 0xd9, 0xc3, 0xf6, 0xf5, 0xf5, 0xf4, 0x77, 0x5d, 0x4f, 0x30, +0x4b, 0x49, 0x30, 0x32, 0x4d, 0x5f, 0x52, 0x78, 0xa2, 0x78, 0x31, 0x8d, 0x4c, 0x7a, 0x4d, 0x4b, 0x4d, 0x4d, 0x5f, 0x5f, +0x32, 0x23, 0x32, 0x23, 0x4b, 0x4b, 0x32, 0xa4, 0x4d, 0x23, 0x3b, 0x32, 0x78, 0x3b, 0x3b, 0x37, 0x75, 0x5a, 0x37, 0x30, +0x32, 0x74, 0x57, 0xbe, 0x6f, 0x9a, 0x56, 0x55, 0x56, 0x77, 0x8d, 0x32, 0x7f, 0xa9, 0xd5, 0xa7, 0x8d, 0x0, 0xf2, 0xdd, +0xdc, 0xb1, 0xbe, 0xb1, 0x56, 0xda, 0xb1, 0xda, 0xa5, 0x89, 0xae, 0xa5, 0xa5, 0xae, 0xb1, 0x9a, 0xb1, 0x77, 0x7a, 0x8b, +0x2e, 0x70, 0x97, 0x49, 0x30, 0x9e, 0x5a, 0x65, 0x1f, 0x1d, 0x1d, 0xe0, 0x2a, 0x3a, 0x1d, 0x29, 0x1c, 0x69, 0x2c, 0x1f, +0x64, 0x20, 0x61, 0x5c, 0x60, 0x42, 0x7c, 0xa5, 0x27, 0x52, 0x15, 0x2c, 0x2b, 0x2a, 0x26, 0x21, 0xd3, 0xf4, 0x42, 0xbe, +0xf5, 0xf5, 0xf6, 0xf5, 0x1a, 0x63, 0x50, 0x32, 0x4a, 0x4b, 0x32, 0xa2, 0xa0, 0x4e, 0x5b, 0x8d, 0x8d, 0x5d, 0x88, 0x8b, +0x1b, 0x7c, 0x31, 0xa5, 0x8d, 0x4f, 0x24, 0x7e, 0x75, 0x32, 0x74, 0x5b, 0x4b, 0x30, 0x74, 0x78, 0x5e, 0x4d, 0x3b, 0x7b, +0x78, 0x3a, 0x3b, 0x3c, 0x59, 0x70, 0x86, 0x74, 0x49, 0x4b, 0x35, 0x4b, 0x98, 0x9a, 0xae, 0x56, 0x56, 0x8a, 0x1a, 0x32, +0x23, 0xa7, 0x80, 0x7f, 0x94, 0x94, 0xb1, 0xdc, 0xe4, 0xb1, 0xdb, 0x4c, 0xa5, 0x71, 0xbe, 0xb1, 0xda, 0xda, 0xb1, 0xa6, +0x4c, 0x54, 0x99, 0xbe, 0xbe, 0x5d, 0x8b, 0x75, 0x79, 0x2e, 0x49, 0x72, 0x70, 0x9d, 0x4d, 0x26, 0x1f, 0xe1, 0x6d, 0x6d, +0x2a, 0x3f, 0x6a, 0x29, 0x29, 0x1d, 0x29, 0x1c, 0x63, 0x39, 0x60, 0x61, 0x61, 0x27, 0x90, 0xca, 0x7f, 0x2a, 0x15, 0x1f, +0x2c, 0x26, 0x43, 0x46, 0xf6, 0xf1, 0xf5, 0x96, 0x8a, 0xf4, 0xf1, 0x18, 0x3e, 0x26, 0xa9, 0xa0, 0x75, 0x4b, 0x74, 0x4b, +0x24, 0xc6, 0x7a, 0x4c, 0x77, 0x48, 0xd3, 0xb1, 0x7c, 0x4c, 0x56, 0x77, 0x77, 0x4c, 0x19, 0x50, 0x4d, 0x32, 0xa4, 0x74, +0x5b, 0x32, 0x32, 0x4f, 0x32, 0x30, 0x8b, 0x78, 0x32, 0xa4, 0x8d, 0x5f, 0x32, 0x72, 0x4b, 0x30, 0x70, 0x34, 0x4b, 0x4a, +0x4a, 0x71, 0x55, 0x56, 0x4c, 0x1b, 0x8a, 0x32, 0x4b, 0x37, 0x8d, 0x86, 0xab, 0x6, 0x71, 0xda, 0xda, 0xa5, 0x77, 0x89, +0xae, 0xbb, 0xbe, 0x71, 0xc1, 0xc1, 0xb1, 0xdd, 0x71, 0xbb, 0x99, 0x5d, 0xbe, 0x7a, 0x4e, 0x33, 0x49, 0x79, 0x75, 0x6e, +0x72, 0xa0, 0x4f, 0x40, 0x15, 0x1f, 0x1d, 0x2c, 0x1c, 0x6a, 0x51, 0x1d, 0x14, 0x1c, 0x1c, 0x4e, 0x35, 0x61, 0x60, 0x61, +0x39, 0x81, 0x1e, 0x90, 0xd6, 0x8f, 0x2b, 0x64, 0x63, 0x16, 0x20, 0xd1, 0xf6, 0xc2, 0xf6, 0xf6, 0xf4, 0x8a, 0xbe, 0x4e, +0x3a, 0x63, 0x4f, 0xa2, 0x75, 0x49, 0x74, 0x7a, 0x7c, 0x18, 0x7c, 0x25, 0x56, 0x35, 0x4c, 0x77, 0x4c, 0x4c, 0x4c, 0x89, +0x55, 0x56, 0x1b, 0x4c, 0x5d, 0x4f, 0x8d, 0x5b, 0x5b, 0x23, 0x4b, 0x4d, 0x74, 0x49, 0x74, 0x5b, 0x31, 0x5f, 0x5b, 0x5f, +0x52, 0x4b, 0x2e, 0x6e, 0x4b, 0x34, 0x5a, 0x31, 0x35, 0x2f, 0x2f, 0x18, 0x2f, 0x1b, 0x8a, 0x31, 0x32, 0x37, 0xa7, 0x8f, +0xa1, 0xa4, 0xe4, 0xe8, 0xa5, 0xd3, 0xe9, 0xb1, 0x99, 0x71, 0x99, 0x76, 0x9a, 0xbe, 0xa5, 0x56, 0x71, 0x71, 0x54, 0x4c, +0x89, 0x37, 0x79, 0x4d, 0x4e, 0x8e, 0xb0, 0x8b, 0x8c, 0xd5, 0x83, 0x40, 0x2c, 0x2a, 0x51, 0x51, 0x84, 0x3f, 0x29, 0x14, +0x14, 0x29, 0x26, 0x1c, 0x18, 0x5c, 0x5c, 0x73, 0x7c, 0x7a, 0xe8, 0x90, 0x7b, 0x7e, 0x40, 0x63, 0x3b, 0x41, 0x1e, 0xf6, +0xf5, 0xf5, 0xf1, 0xf4, 0xf4, 0x25, 0x79, 0xb0, 0x4f, 0x19, 0x8d, 0x79, 0x31, 0x31, 0x57, 0x57, 0xa5, 0xa5, 0x4c, 0x1b, +0x2f, 0x4c, 0x7c, 0x4c, 0x4c, 0x4c, 0x4c, 0x18, 0x56, 0x7c, 0x77, 0x39, 0x39, 0x18, 0xa3, 0x4d, 0x4b, 0x23, 0x32, 0x30, +0x72, 0x30, 0x4b, 0x5b, 0x32, 0x4b, 0x37, 0x3a, 0xb0, 0x72, 0x72, 0x4b, 0x23, 0x75, 0x59, 0x5b, 0x4a, 0x76, 0x47, 0x57, +0x47, 0x4c, 0x39, 0x2f, 0x32, 0x3b, 0x40, 0xef, 0xcc, 0xc1, 0xdc, 0xdc, 0xda, 0xdc, 0xaa, 0xc6, 0x71, 0x71, 0x89, 0x4c, +0xae, 0x71, 0xa5, 0xd3, 0xae, 0x56, 0xae, 0x54, 0xae, 0xca, 0x4f, 0x30, 0xd7, 0xc9, 0xa2, 0x78, 0x7b, 0x64, 0x40, 0x40, +0x64, 0x51, 0x65, 0x84, 0x6d, 0x6d, 0x1d, 0x1d, 0x1c, 0x14, 0x50, 0x24, 0x39, 0x5c, 0x5c, 0x60, 0x4c, 0x27, 0xb6, 0xcc, +0x7e, 0x63, 0x63, 0xa7, 0x3b, 0x40, 0x52, 0xf6, 0xf4, 0x39, 0xf5, 0xf4, 0xf1, 0x3c, 0x79, 0x78, 0xa7, 0x5b, 0xa4, 0x24, +0x1a, 0x35, 0x48, 0x31, 0x18, 0xb1, 0x5d, 0x4c, 0x4c, 0x1b, 0x89, 0x25, 0x4c, 0x55, 0x77, 0x55, 0xae, 0x77, 0x1b, 0x1b, +0x77, 0x39, 0x77, 0x35, 0x32, 0x4f, 0x4d, 0x74, 0x9d, 0x30, 0x32, 0x37, 0x88, 0xb0, 0x75, 0x7f, 0x75, 0x8b, 0x72, 0x88, +0x6e, 0x4a, 0x4d, 0x74, 0x74, 0x47, 0x17, 0x4a, 0x9f, 0x2f, 0x71, 0x89, 0x31, 0x5b, 0x80, 0x66, 0xee, 0xd6, 0xca, 0xca, +0xb7, 0x0, 0x81, 0xb1, 0x56, 0xb1, 0x54, 0xae, 0xb1, 0x9a, 0xb1, 0xb1, 0x9a, 0x9a, 0xd3, 0x56, 0xb1, 0xca, 0x5f, 0x4d, +0x3a, 0xc9, 0x9d, 0x78, 0xa7, 0x2a, 0x1c, 0x16, 0x26, 0x79, 0x65, 0x69, 0x1d, 0x6b, 0x14, 0x1c, 0x1f, 0x1c, 0x50, 0x31, +0x5c, 0x61, 0x61, 0x1b, 0x1b, 0x7a, 0x3e, 0xcc, 0x91, 0xa7, 0x40, 0x63, 0x3b, 0x43, 0x43, 0xd9, 0xf6, 0xf6, 0xf6, 0xf4, +0x77, 0x19, 0x23, 0x37, 0x4f, 0x4f, 0x1a, 0x35, 0x17, 0x17, 0x31, 0x5d, 0x25, 0xb1, 0x7a, 0x18, 0x77, 0x4c, 0x89, 0x56, +0x56, 0x77, 0x4c, 0x89, 0x56, 0x89, 0x77, 0x77, 0x39, 0x8a, 0x8a, 0x39, 0x5d, 0x4b, 0x4b, 0x4a, 0x5b, 0x34, 0xb0, 0x5b, +0xa3, 0xb0, 0x4d, 0x78, 0x75, 0x5a, 0x59, 0x72, 0x9e, 0x4b, 0x49, 0x74, 0x5b, 0x31, 0x48, 0x47, 0x48, 0x48, 0x2f, 0x8a, +0x56, 0x5b, 0x7f, 0x8d, 0xc7, 0xa7, 0x90, 0xee, 0xe7, 0xb6, 0x81, 0x71, 0x9a, 0xb1, 0x4c, 0x71, 0xb1, 0xbe, 0x71, 0x99, +0x99, 0x56, 0x56, 0xd9, 0x9a, 0x3c, 0x8f, 0x8d, 0x8b, 0x8c, 0x79, 0x8c, 0x63, 0x26, 0x16, 0x15, 0x1c, 0x7e, 0x68, 0x50, +0x38, 0x62, 0x50, 0x16, 0x26, 0x29, 0x24, 0x28, 0x5c, 0x61, 0x60, 0x42, 0x35, 0x37, 0x41, 0x69, 0x7e, 0xb3, 0xa9, 0x68, +0x64, 0x43, 0x8f, 0x2a, 0xcb, 0xbb, 0xf5, 0x73, 0x31, 0x4d, 0x4f, 0x5f, 0x24, 0x23, 0x31, 0x31, 0x35, 0x2f, 0x54, 0x76, +0x25, 0xdb, 0x89, 0x18, 0x2f, 0x35, 0x7a, 0xa4, 0x86, 0x31, 0x31, 0x18, 0x4c, 0x77, 0x39, 0x77, 0x39, 0x39, 0x39, 0x60, +0x8a, 0x76, 0x30, 0x4b, 0x9c, 0x49, 0x59, 0x30, 0x5b, 0xa4, 0x19, 0x3b, 0x37, 0x4a, 0x9e, 0x9c, 0x32, 0x4d, 0x4b, 0x4b, +0x4b, 0x57, 0x76, 0x48, 0x2f, 0x71, 0x54, 0x4c, 0x56, 0x7a, 0x5b, 0x5b, 0xc7, 0xc7, 0xca, 0x66, 0x8f, 0xc5, 0xdc, 0xdc, +0xdc, 0xb1, 0xbb, 0xd9, 0x2f, 0xbe, 0x71, 0x77, 0x71, 0x56, 0x99, 0x99, 0x9a, 0x5d, 0x8d, 0xe7, 0x80, 0xa7, 0x63, 0x24, +0x3a, 0x3a, 0x1c, 0x16, 0x1c, 0x69, 0x65, 0x50, 0x62, 0xd7, 0x3a, 0x26, 0x3a, 0x16, 0x26, 0x77, 0x5c, 0x61, 0x1b, 0x18, +0x76, 0x1a, 0x43, 0x29, 0x51, 0xa9, 0x91, 0xb3, 0x91, 0xcc, 0x64, 0x8f, 0x40, 0x3e, 0x52, 0x23, 0x8b, 0x32, 0x4f, 0x4f, +0x37, 0x31, 0x31, 0x31, 0x2f, 0x15, 0x95, 0xfa, 0x54, 0x25, 0xb1, 0x7a, 0x4d, 0x5f, 0x8b, 0x4d, 0x4b, 0x32, 0x4b, 0x4b, +0x4a, 0x2f, 0x77, 0x39, 0x8a, 0x8a, 0x77, 0x8a, 0x8a, 0x55, 0x57, 0x9c, 0x9e, 0x74, 0x74, 0x74, 0x37, 0x37, 0x74, 0x32, +0x8c, 0x74, 0xa1, 0x2e, 0x30, 0x32, 0x32, 0x23, 0x5b, 0xa4, 0x57, 0x17, 0x22, 0x22, 0x2f, 0x2f, 0x48, 0x57, 0x57, 0x31, +0x74, 0xa4, 0x90, 0xe3, 0x8d, 0xa3, 0xda, 0x76, 0xc6, 0xbe, 0x99, 0x9a, 0xbe, 0xbe, 0xb1, 0xa6, 0xa5, 0xae, 0x71, 0xa5, +0x71, 0x27, 0x8d, 0x8d, 0x8d, 0xa7, 0x8d, 0x63, 0x7d, 0x1c, 0x64, 0x7e, 0xb3, 0x65, 0x65, 0x50, 0x4e, 0x3a, 0x4e, 0x32, +0x4f, 0x32, 0x37, 0x73, 0x5c, 0x61, 0x77, 0x25, 0x31, 0x37, 0x64, 0x50, 0x3a, 0x7e, 0x3a, 0x2a, 0x83, 0x43, 0xcc, 0x3e, +0x41, 0x3b, 0x5f, 0x3b, 0x4d, 0x5f, 0x4f, 0x40, 0x3c, 0x5d, 0x17, 0x17, 0x55, 0xb8, 0x12, 0xcf, 0x7a, 0x76, 0x7f, 0x7f, +0x5f, 0x58, 0x5a, 0x57, 0x4a, 0x2d, 0x32, 0x74, 0x4b, 0x5b, 0x31, 0x77, 0x39, 0x60, 0x77, 0x39, 0x8a, 0x73, 0x55, 0x49, +0x2e, 0x86, 0x37, 0x74, 0x32, 0x5b, 0x75, 0x5a, 0x59, 0x6e, 0xa1, 0x33, 0x2e, 0x74, 0x23, 0x37, 0x5b, 0x49, 0x4a, 0x76, +0x71, 0x85, 0x2d, 0x2f, 0x2f, 0x57, 0x4a, 0x37, 0xd4, 0x7f, 0xca, 0xc5, 0x9f, 0xb1, 0x56, 0x56, 0xb1, 0xda, 0xb1, 0x71, +0xbe, 0xd3, 0xa5, 0xa5, 0xb1, 0xa5, 0xd3, 0xa5, 0x77, 0x90, 0x63, 0xa4, 0x8d, 0xa7, 0x5f, 0x4f, 0x26, 0x83, 0x43, 0x3e, +0xa9, 0x79, 0x3a, 0x50, 0x50, 0x65, 0x4e, 0x4f, 0x4f, 0x24, 0x31, 0x5c, 0xb2, 0x73, 0x39, 0x25, 0x57, 0x74, 0x3a, 0x4e, +0x4f, 0x3a, 0x3a, 0x64, 0x64, 0x3e, 0x3e, 0x4f, 0x4f, 0x8d, 0x32, 0x4d, 0x4d, 0x3b, 0x4f, 0x19, 0x1a, 0x5d, 0x25, 0x1a, +0x17, 0x28, 0xcf, 0x12, 0xcf, 0x40, 0x31, 0x7a, 0x40, 0x6a, 0x92, 0x92, 0xce, 0x6d, 0x82, 0x4f, 0x4a, 0x23, 0x37, 0x7a, +0x4c, 0x73, 0x8a, 0x73, 0x73, 0x8a, 0x8a, 0x31, 0x74, 0x9e, 0x4a, 0x4b, 0x37, 0x78, 0x31, 0x5a, 0x59, 0xba, 0x70, 0x74, +0x74, 0x4b, 0x6e, 0xa0, 0x78, 0x5a, 0x4a, 0x2d, 0x2f, 0x2d, 0x2d, 0x71, 0x89, 0x48, 0x4b, 0x4b, 0x37, 0x3c, 0x57, 0x9f, +0xc1, 0xa5, 0xa5, 0x99, 0x76, 0xaa, 0xa8, 0xda, 0xa5, 0xd3, 0xae, 0xbe, 0x48, 0xb1, 0xda, 0x89, 0x61, 0x52, 0x3a, 0x79, +0x5f, 0x3b, 0x5f, 0x40, 0x63, 0x3b, 0x7f, 0x5f, 0x4e, 0x50, 0x50, 0x50, 0x50, 0x8f, 0x4d, 0x8c, 0xc9, 0x63, 0x25, 0xb2, +0x5c, 0x60, 0xa6, 0x25, 0x57, 0x32, 0x7e, 0x3a, 0x4f, 0x26, 0x4e, 0x7b, 0x4f, 0x7b, 0x40, 0x4f, 0x4f, 0x37, 0x4f, 0x4f, +0x4f, 0x5f, 0x4f, 0x52, 0x28, 0x25, 0x25, 0x25, 0x1a, 0x18, 0x55, 0x11, 0x12, 0x11, 0x7a, 0xce, 0xb8, 0xb8, 0xb4, 0x92, +0xb4, 0x92, 0x92, 0x94, 0xdf, 0x18, 0x31, 0x37, 0x37, 0x8a, 0x5c, 0x5c, 0x73, 0x73, 0x5c, 0x55, 0x9c, 0x4a, 0x31, 0x35, +0x74, 0x88, 0x31, 0x74, 0x98, 0x70, 0x58, 0x72, 0x74, 0x6e, 0x9e, 0x4b, 0x78, 0xa4, 0x57, 0x57, 0x47, 0x9c, 0x2d, 0x54, +0x8a, 0x2f, 0x74, 0x57, 0x37, 0x31, 0x35, 0x76, 0xbe, 0xbe, 0x76, 0xd2, 0xc6, 0xc6, 0xda, 0xda, 0xa5, 0xa5, 0xae, 0x48, +0x99, 0xbe, 0xe2, 0xd3, 0x60, 0x52, 0x63, 0x3a, 0x64, 0x3b, 0x43, 0x2b, 0x3b, 0x5f, 0x5f, 0x5f, 0x7b, 0x5f, 0xa9, 0x51, +0x1c, 0x4f, 0x7b, 0x8c, 0xa9, 0xa7, 0x42, 0xb2, 0x5c, 0x39, 0x42, 0x28, 0x9f, 0x5f, 0x8f, 0x2b, 0x64, 0x4f, 0x3a, 0x5f, +0x40, 0x26, 0x78, 0x5f, 0x4f, 0x19, 0x19, 0x41, 0x41, 0x3b, 0x3e, 0xaa, 0xa8, 0x28, 0x25, 0x5d, 0x25, 0x5d, 0x31, 0x31, +0xec, 0xec, 0xec, 0x95, 0xb4, 0x92, 0x92, 0x94, 0x6b, 0xc4, 0xc8, 0x94, 0xec, 0x68, 0x71, 0xc1, 0xa3, 0xd3, 0x73, 0x5c, +0x5c, 0x73, 0x73, 0x8a, 0x6f, 0x49, 0x74, 0x31, 0x4b, 0x88, 0x5d, 0x9f, 0x96, 0x9e, 0x59, 0x4b, 0x4f, 0x4b, 0x6e, 0x31, +0x76, 0xa5, 0x76, 0x9f, 0x86, 0x9c, 0x57, 0x2f, 0x4c, 0x2f, 0x4a, 0x57, 0x5b, 0x7a, 0x76, 0x5d, 0xbe, 0x71, 0xb1, 0xc6, +0xc6, 0xca, 0xc6, 0xc6, 0xb1, 0x71, 0x71, 0xd9, 0x76, 0x76, 0x9f, 0xb1, 0x77, 0x20, 0x43, 0x15, 0x2b, 0x91, 0x1d, 0x29, +0x3e, 0x4d, 0x4f, 0x7f, 0x51, 0x29, 0x7e, 0x38, 0x7b, 0x3a, 0xd5, 0x5f, 0x7e, 0x83, 0xa6, 0x5c, 0x73, 0x67, 0x42, 0x5d, +0x1a, 0x7f, 0x43, 0x43, 0x83, 0x63, 0x4f, 0x4f, 0x3e, 0x26, 0x63, 0x3b, 0x19, 0x3e, 0x3b, 0x3e, 0x19, 0x52, 0x52, 0x27, +0xa5, 0x1a, 0x25, 0x5d, 0x25, 0x25, 0x41, 0x52, 0x46, 0x7, 0x95, 0xb4, 0xc8, 0xc8, 0xce, 0xe1, 0x53, 0xc8, 0xc8, 0xc8, +0x92, 0xb8, 0xdf, 0x76, 0x37, 0x5d, 0x73, 0x73, 0x5c, 0x73, 0x55, 0x8a, 0x55, 0x98, 0x9d, 0x86, 0x4a, 0xa0, 0xa3, 0x5d, +0x31, 0x72, 0x74, 0x32, 0x5b, 0x76, 0xd3, 0x56, 0x77, 0x4c, 0xbe, 0x9f, 0x5d, 0x56, 0xbe, 0x35, 0x2f, 0x2f, 0x57, 0xa1, +0x5b, 0x35, 0x2f, 0xbe, 0x76, 0xda, 0xdb, 0xa8, 0xa8, 0xdc, 0xe4, 0xc6, 0xda, 0xbe, 0x71, 0x71, 0x18, 0x5d, 0xb1, 0xb1, +0x7c, 0x1e, 0x43, 0x2c, 0x15, 0x15, 0x2c, 0x2c, 0x43, 0x3b, 0x41, 0x7f, 0x8e, 0x62, 0x65, 0x8c, 0x75, 0x8c, 0x8c, 0x8c, +0x8f, 0x26, 0x60, 0xc2, 0xc2, 0x6c, 0x5c, 0x61, 0x61, 0x67, 0x44, 0x20, 0x20, 0x3c, 0x27, 0x52, 0x40, 0x40, 0x3b, 0x19, +0x52, 0x7f, 0x8d, 0x3e, 0x43, 0x16, 0x21, 0x44, 0x28, 0x28, 0x3c, 0x25, 0x42, 0x1a, 0x19, 0x8d, 0x69, 0xb8, 0xb8, 0xc8, +0xc8, 0xc8, 0x62, 0xc4, 0xc8, 0xc8, 0xc8, 0xc4, 0x92, 0xec, 0x92, 0xc5, 0x76, 0xc1, 0x89, 0x5c, 0x73, 0x8a, 0x8a, 0x8a, +0x55, 0x97, 0x49, 0x76, 0x76, 0xa3, 0x31, 0x5d, 0xa1, 0x97, 0x74, 0x76, 0x77, 0x39, 0x77, 0x4c, 0x89, 0xdb, 0xb1, 0x76, +0x18, 0x4c, 0xb1, 0x57, 0x71, 0x56, 0x31, 0x7a, 0x7a, 0x25, 0x56, 0x76, 0xa5, 0xb1, 0xdd, 0xda, 0xdc, 0xaa, 0xe8, 0xdd, +0xb1, 0xae, 0x56, 0xb1, 0x5d, 0x35, 0x7a, 0xbe, 0xb1, 0x25, 0x21, 0x1f, 0x1f, 0x2c, 0x2c, 0x69, 0x40, 0x40, 0x3a, 0x79, +0x62, 0x79, 0xa9, 0x78, 0x5f, 0x78, 0x8b, 0x8c, 0x64, 0x3e, 0xc3, 0xf8, 0x3d, 0xb2, 0x6c, 0x6c, 0x6c, 0x60, 0x61, 0x61, +0x61, 0x61, 0x61, 0x39, 0x37, 0x4f, 0x3b, 0x52, 0x52, 0x3b, 0x3b, 0x66, 0x43, 0x43, 0x41, 0x28, 0x1b, 0x42, 0x44, 0xa6, +0x7c, 0x3c, 0x26, 0x24, 0x94, 0xec, 0x92, 0xc8, 0xc8, 0xc4, 0x62, 0x62, 0xc8, 0xc8, 0xc8, 0xb4, 0x92, 0xb4, 0xb4, 0xe0, +0x76, 0xa3, 0x31, 0x5c, 0x73, 0x73, 0x73, 0x73, 0xbb, 0x4b, 0xa4, 0x31, 0xbe, 0xda, 0x86, 0x9e, 0x97, 0x72, 0x32, 0x5d, +0x77, 0x60, 0x73, 0x5c, 0x61, 0x61, 0x61, 0x61, 0x61, 0x73, 0x73, 0x55, 0x8a, 0x60, 0x31, 0x5b, 0xa1, 0x76, 0xdd, 0xb1, +0xb1, 0xca, 0xc6, 0xbe, 0xb6, 0xee, 0xe8, 0xdb, 0x56, 0x99, 0x76, 0x7a, 0x76, 0x7a, 0x5f, 0xc1, 0xb1, 0x28, 0x52, 0x2a, +0x2a, 0x3e, 0x91, 0x53, 0x62, 0x3f, 0x4e, 0x79, 0x5e, 0x50, 0xa9, 0x5f, 0x78, 0xc7, 0x7b, 0xa7, 0x5f, 0x5f, 0x25, 0x7c, +0x25, 0x25, 0x28, 0x44, 0x81, 0x25, 0x25, 0x1e, 0x1e, 0x39, 0x6c, 0x60, 0x3c, 0x8d, 0x3c, 0x27, 0x3c, 0x3c, 0x27, 0x52, +0x3e, 0x20, 0x20, 0x28, 0x42, 0x93, 0x42, 0x42, 0x18, 0x5f, 0x3a, 0x4f, 0xec, 0x92, 0xce, 0xc8, 0xc8, 0xc8, 0x6a, 0xe1, +0x62, 0xc8, 0xc8, 0xc8, 0xb4, 0xb4, 0xb4, 0x92, 0xbe, 0x5b, 0x5d, 0x61, 0x73, 0x5c, 0x73, 0x73, 0x8a, 0x5d, 0x5f, 0x5a, +0x9f, 0xb1, 0x9c, 0x88, 0xbc, 0x37, 0x4a, 0x1a, 0xd3, 0x56, 0x7a, 0x7a, 0xa4, 0x37, 0x7a, 0x7a, 0x37, 0x3c, 0xc6, 0xc1, +0x7a, 0xa5, 0x5d, 0x5b, 0xa3, 0x76, 0xb1, 0x56, 0x52, 0x37, 0xc1, 0xc1, 0x7a, 0xef, 0x90, 0x4c, 0xb1, 0x71, 0x1a, 0x7f, +0x5b, 0xa3, 0x8d, 0xa3, 0xa5, 0x81, 0x27, 0x3e, 0x7e, 0x3e, 0x7b, 0x79, 0x7d, 0x29, 0x26, 0x26, 0x3a, 0x8e, 0x3a, 0x4f, +0x8d, 0x63, 0x7b, 0xa7, 0x7f, 0x5f, 0xa4, 0x5b, 0x37, 0x8d, 0x7f, 0x7f, 0x7f, 0x3b, 0x3e, 0x7f, 0x7f, 0x42, 0x61, 0x76, +0x31, 0x3c, 0x3c, 0x27, 0x3c, 0x3e, 0x27, 0x27, 0x3b, 0x23, 0x31, 0x3c, 0x42, 0xa6, 0xa6, 0xa6, 0x52, 0x63, 0x37, 0xa4, +0xb8, 0xec, 0x6b, 0xc4, 0xc8, 0xc4, 0xc4, 0x6b, 0xc4, 0xc4, 0xc8, 0x92, 0xb4, 0xb4, 0xb4, 0x92, 0xb1, 0x57, 0x9f, 0x55, +0x8a, 0x73, 0x5c, 0x73, 0x71, 0x48, 0x7a, 0xbf, 0x76, 0xb1, 0x9f, 0x9f, 0x7a, 0xa5, 0x76, 0x31, 0x56, 0x76, 0x34, 0x4e, +0x50, 0x50, 0x4e, 0x79, 0x79, 0xa9, 0x8c, 0x4e, 0x4e, 0x7a, 0xc5, 0xa4, 0x25, 0x7c, 0xdd, 0xb1, 0xa1, 0xa1, 0x8d, 0xd4, +0xc1, 0xcc, 0xcb, 0xdb, 0x4c, 0xc6, 0x31, 0x4a, 0x74, 0x74, 0xa3, 0x37, 0xd3, 0x42, 0x1e, 0x27, 0x83, 0x29, 0x50, 0x83, +0x1c, 0x29, 0x3a, 0x26, 0x2b, 0x87, 0x62, 0x3e, 0x8d, 0x78, 0x8d, 0x40, 0x40, 0x8b, 0x72, 0x37, 0x7f, 0x5b, 0x23, 0x37, +0x19, 0x3c, 0x52, 0x3c, 0x7a, 0x42, 0x60, 0x37, 0x3b, 0x19, 0x3b, 0x3b, 0x7b, 0x62, 0x3e, 0x52, 0x75, 0x75, 0x3b, 0x3c, +0x1b, 0x39, 0x7c, 0x7c, 0x1a, 0x19, 0x7a, 0x7f, 0x92, 0x6b, 0xc8, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xce, 0xc4, 0xc8, 0xc8, +0xb4, 0xb4, 0xb4, 0xb4, 0xa3, 0x86, 0xa1, 0x55, 0x73, 0x55, 0x8a, 0x60, 0x37, 0x4d, 0x78, 0x7e, 0x7f, 0x8d, 0x8d, 0x37, +0xa3, 0x31, 0x57, 0x32, 0x2f, 0x76, 0x33, 0x79, 0x4e, 0x7e, 0x24, 0x4d, 0xa9, 0x3a, 0x3a, 0x4e, 0x75, 0x7a, 0x31, 0x88, +0xa8, 0x76, 0x76, 0xbe, 0x86, 0x2a, 0x37, 0x66, 0x76, 0xca, 0xdc, 0x56, 0x28, 0xda, 0x5d, 0x37, 0x8d, 0xa4, 0xa3, 0x5d, +0xdb, 0x28, 0x81, 0xca, 0x80, 0x64, 0x66, 0xb3, 0x2c, 0x64, 0x7e, 0x24, 0x5e, 0x36, 0x5e, 0x3a, 0x5f, 0x78, 0x3b, 0x4f, +0x24, 0x32, 0x4b, 0x3b, 0x3b, 0x7a, 0x23, 0x4f, 0x8d, 0x3e, 0x3c, 0x19, 0x3b, 0x42, 0x61, 0x39, 0x67, 0x4c, 0x4c, 0x18, +0xa5, 0xa5, 0x7c, 0x42, 0x7c, 0xa5, 0xa6, 0x45, 0x1b, 0x7c, 0x7c, 0x1b, 0x25, 0x23, 0x31, 0x41, 0xec, 0x92, 0xc8, 0xc4, +0xc4, 0xc4, 0xc4, 0xc4, 0x6b, 0xc8, 0xc8, 0xb4, 0xb4, 0xb4, 0xb4, 0xc8, 0xa1, 0x88, 0x5b, 0x8a, 0x8a, 0x55, 0x8a, 0x60, +0x1b, 0x37, 0x35, 0xc1, 0xa5, 0x7c, 0x18, 0x4c, 0x4c, 0x7c, 0xdb, 0x77, 0x4c, 0x31, 0x59, 0x5e, 0x5e, 0x50, 0x50, 0x50, +0x79, 0x4e, 0x50, 0x4e, 0x79, 0x37, 0xb1, 0x35, 0x1a, 0x7a, 0x76, 0x9a, 0xa1, 0x8f, 0xcb, 0xee, 0xb7, 0xe3, 0xc1, 0xa8, +0x5d, 0xc6, 0x7a, 0xc5, 0x80, 0xa4, 0x7a, 0x56, 0xdb, 0x7c, 0x52, 0x90, 0xdc, 0x90, 0xa9, 0x65, 0x65, 0xa9, 0x50, 0x8c, +0x8e, 0x36, 0x7e, 0x65, 0x34, 0x8b, 0x5f, 0x30, 0x5f, 0x37, 0x1b, 0x1b, 0x42, 0x1b, 0x7c, 0x7c, 0x42, 0x7c, 0x1b, 0x42, +0x4c, 0x60, 0x61, 0x39, 0x3c, 0x8d, 0x5f, 0x23, 0x8d, 0x37, 0x52, 0x3c, 0x27, 0x3c, 0x3b, 0x1b, 0x39, 0x42, 0xa6, 0x1b, +0x42, 0x3c, 0x37, 0x7a, 0x92, 0x92, 0xc8, 0xc4, 0xc4, 0xc4, 0x62, 0xc4, 0xc4, 0xc8, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0x6b, +0x9a, 0x5a, 0x5b, 0x39, 0x8a, 0x55, 0x55, 0x61, 0x8a, 0x32, 0xa2, 0xa2, 0x5a, 0xa1, 0x88, 0x4b, 0x8b, 0x5f, 0x37, 0x5d, +0x56, 0x56, 0x9f, 0x31, 0x35, 0x31, 0x27, 0x1a, 0x25, 0x5d, 0x35, 0x5d, 0x18, 0x8a, 0x5d, 0x35, 0xa8, 0x25, 0xb1, 0x76, +0x37, 0x40, 0xe7, 0xd8, 0xf0, 0xcc, 0xca, 0x52, 0xca, 0x3b, 0xc5, 0x8d, 0x7f, 0xc5, 0xc6, 0xb1, 0x7c, 0x1e, 0x52, 0x90, +0xdd, 0x81, 0x2b, 0x91, 0x68, 0x69, 0x7e, 0x5f, 0xb5, 0x82, 0x53, 0xa9, 0x7b, 0x79, 0xa4, 0x74, 0x4d, 0x4b, 0x5c, 0xc2, +0x3d, 0xc2, 0xc2, 0x3d, 0xc2, 0xc2, 0xc2, 0xc2, 0x3d, 0xc2, 0xc2, 0x39, 0x52, 0x4f, 0x5f, 0x4f, 0x37, 0x3c, 0x3c, 0x3c, +0x7f, 0x3c, 0x90, 0x28, 0x39, 0x67, 0x39, 0xa6, 0x39, 0x35, 0x7a, 0xdd, 0xe1, 0xb4, 0xc8, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, +0xc4, 0xc8, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xa9, 0x85, 0x4a, 0x3c, 0x8a, 0x60, 0x77, 0x56, 0x73, 0x1b, 0x4d, 0xb0, 0xa0, +0x75, 0x5a, 0x88, 0x88, 0x8b, 0x79, 0xa0, 0x9a, 0x73, 0xb2, 0x5c, 0xc2, 0xb2, 0xb2, 0xc2, 0x3d, 0x3d, 0xc3, 0xc3, 0xf8, +0xfe, 0x3d, 0x31, 0x37, 0x7a, 0xa8, 0x76, 0x8d, 0xa3, 0x8d, 0x8f, 0xd8, 0xd8, 0xee, 0xca, 0xc5, 0x8d, 0x8d, 0x7a, 0x31, +0x37, 0x1a, 0xd3, 0xda, 0xa6, 0x46, 0x20, 0x1e, 0x25, 0x90, 0xaa, 0xcc, 0x2c, 0x84, 0x64, 0x5f, 0x64, 0x82, 0xc4, 0x51, +0x65, 0x4f, 0x78, 0x30, 0x4d, 0x3b, 0x61, 0x5c, 0x5c, 0x5c, 0x6c, 0x6c, 0x6c, 0xc2, 0xb2, 0x5c, 0x5c, 0x39, 0x28, 0x52, +0x41, 0x40, 0x3e, 0x19, 0x5f, 0x5f, 0x27, 0x1a, 0x3c, 0x1a, 0x28, 0x42, 0x60, 0x39, 0x1b, 0xa6, 0x39, 0x2f, 0x5b, 0x37, +0xcb, 0x92, 0xb8, 0x92, 0x92, 0xc8, 0xc4, 0xc8, 0xc8, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xc4, 0x56, 0x9f, 0x31, 0x56, 0x39, +0x8a, 0x39, 0x8a, 0x39, 0x18, 0x8c, 0x4d, 0xa4, 0xa2, 0x5a, 0x88, 0xa1, 0x8b, 0xa2, 0x72, 0x98, 0xad, 0x99, 0x54, 0x54, +0x73, 0x5c, 0xb2, 0x5c, 0x61, 0x60, 0x60, 0x8a, 0x4c, 0x71, 0x37, 0x7a, 0x3c, 0xc1, 0xd2, 0x40, 0x7f, 0xa1, 0x84, 0xe1, +0xeb, 0xb6, 0xca, 0x7a, 0xc5, 0x7a, 0xa3, 0x57, 0x76, 0xb1, 0xa6, 0x61, 0xf, 0x42, 0x1e, 0x25, 0xa8, 0x41, 0xb6, 0xd8, +0xab, 0x1f, 0x26, 0x79, 0x65, 0x84, 0x3f, 0x69, 0x8e, 0x4d, 0x5f, 0x78, 0x78, 0x3b, 0x60, 0xb2, 0x60, 0x39, 0x1b, 0x42, +0x28, 0x28, 0x3c, 0x19, 0x41, 0x3e, 0x3e, 0x66, 0x3e, 0x3e, 0x26, 0x3b, 0x19, 0x37, 0x7a, 0x27, 0x3c, 0x3c, 0x3c, 0x28, +0x61, 0x60, 0x39, 0x42, 0x42, 0x77, 0x37, 0x23, 0x57, 0xf0, 0x92, 0xb4, 0x92, 0x92, 0xc8, 0xc8, 0xc8, 0xb4, 0xb4, 0xb4, +0xb4, 0xb4, 0x66, 0x31, 0x31, 0x4b, 0x4c, 0x60, 0x8a, 0x8a, 0x77, 0x8a, 0x31, 0x4f, 0x4b, 0x72, 0x72, 0x4b, 0x4a, 0x74, +0x86, 0x86, 0x74, 0x6e, 0x6e, 0x98, 0x59, 0x9d, 0x98, 0x88, 0x5b, 0x4b, 0x78, 0x7a, 0x48, 0x2f, 0x2f, 0x48, 0x4a, 0x7a, +0xa3, 0x9f, 0x76, 0xcc, 0xdf, 0x68, 0xe6, 0xe0, 0xc7, 0xcb, 0xa1, 0x76, 0x7f, 0x7a, 0x7a, 0x9f, 0x18, 0x89, 0xb2, 0xf8, +0xfe, 0x1b, 0x28, 0x1e, 0x27, 0x7f, 0x83, 0x21, 0x41, 0x2a, 0x65, 0xa0, 0x7b, 0x62, 0x53, 0x29, 0x4e, 0x59, 0x8b, 0x4d, +0x4f, 0x3e, 0x7c, 0xc2, 0x60, 0x1b, 0x4c, 0x7c, 0x1e, 0x3c, 0x3e, 0x63, 0x4f, 0x3b, 0x63, 0x3e, 0x41, 0x3b, 0x23, 0x19, +0x52, 0x3c, 0x3c, 0x52, 0x52, 0x25, 0xa8, 0x81, 0x61, 0x60, 0x60, 0x39, 0x1b, 0x1b, 0x18, 0x19, 0x3c, 0x35, 0xdf, 0x92, +0xb8, 0x92, 0xc8, 0xc8, 0xb4, 0xb4, 0xb4, 0xb4, 0xc8, 0xe, 0xe, 0x35, 0x6f, 0xbe, 0x60, 0x73, 0x73, 0x73, 0x8a, 0x55, +0x6e, 0x30, 0xa4, 0x4b, 0xbf, 0x74, 0x9c, 0x9c, 0x97, 0x9c, 0x96, 0x86, 0x6e, 0x5a, 0x98, 0x98, 0x98, 0x4b, 0x75, 0x4b, +0x74, 0x31, 0x5d, 0x2f, 0x56, 0x22, 0x74, 0xa3, 0x88, 0xa1, 0x8d, 0x83, 0xf0, 0xea, 0xea, 0xd5, 0xc0, 0xb0, 0xc0, 0xa3, +0xc5, 0xca, 0xa8, 0xb1, 0x56, 0x55, 0xb2, 0x13, 0xfe, 0x1b, 0x27, 0x3c, 0x7f, 0x90, 0x40, 0x41, 0x8d, 0x3e, 0x64, 0x4f, +0x4f, 0x51, 0x62, 0x82, 0x4d, 0x75, 0xa0, 0x5f, 0x5f, 0x4f, 0x27, 0xb2, 0x73, 0x67, 0x7c, 0x25, 0x1a, 0x27, 0x52, 0x3a, +0x4e, 0x3b, 0x63, 0x40, 0x41, 0x3b, 0x3c, 0x52, 0x3c, 0x3c, 0x52, 0x52, 0xc6, 0x81, 0xa8, 0x1e, 0x39, 0x61, 0x60, 0x60, +0x77, 0x1b, 0x1b, 0x1a, 0x23, 0x23, 0x37, 0xeb, 0xce, 0x92, 0xb4, 0xb4, 0xb4, 0xb4, 0xc8, 0x6a, 0x46, 0xc, 0x11, 0x11, +0x3c, 0x73, 0x8a, 0x8a, 0x73, 0x60, 0x8a, 0x48, 0x72, 0x9d, 0x9d, 0x31, 0x57, 0x6e, 0x98, 0x6e, 0x72, 0x97, 0x96, 0x70, +0x9d, 0x9c, 0x5a, 0x9d, 0x9e, 0x74, 0x75, 0x78, 0x57, 0x35, 0xa5, 0x56, 0x56, 0x22, 0x4a, 0x57, 0x76, 0x57, 0xd6, 0xa7, +0xe7, 0xdf, 0xe0, 0xf0, 0xe7, 0xc9, 0xc9, 0xa7, 0xcb, 0xca, 0xdc, 0xb1, 0xd3, 0x89, 0xb2, 0x13, 0xfe, 0x7c, 0x3b, 0x40, +0x40, 0x40, 0x1c, 0x4f, 0x63, 0x16, 0x3b, 0x4f, 0x78, 0x34, 0x36, 0x24, 0x32, 0x4d, 0x9d, 0x74, 0xa3, 0x4d, 0x41, 0xc2, +0x5c, 0x39, 0x28, 0x28, 0x81, 0xaa, 0x52, 0x26, 0x63, 0x4f, 0x3a, 0x3e, 0x41, 0x41, 0x3e, 0x3c, 0x3c, 0x52, 0x3c, 0x8d, +0x5f, 0x3c, 0x27, 0x1e, 0x28, 0x61, 0x60, 0x60, 0x60, 0x39, 0x39, 0x39, 0x7a, 0x7a, 0x3c, 0x35, 0xbe, 0xd4, 0xef, 0xe6, +0xc9, 0xc7, 0x27, 0xbe, 0x57, 0x27, 0xec, 0x12, 0x11, 0x73, 0x73, 0x8a, 0x73, 0x8a, 0x8a, 0x48, 0x23, 0x72, 0x97, 0x9d, +0x5a, 0x5a, 0x9e, 0x98, 0x98, 0x9c, 0x6e, 0xd0, 0x70, 0x72, 0x5a, 0x9e, 0x98, 0x5a, 0x59, 0x8b, 0x76, 0x76, 0x56, 0x56, +0x71, 0x17, 0x31, 0x57, 0x31, 0xc1, 0xa4, 0xcd, 0xea, 0xf0, 0xd7, 0xe6, 0xe6, 0xc0, 0xc0, 0xe2, 0xb6, 0xdc, 0xb1, 0xb1, +0xb1, 0x89, 0x3d, 0xfe, 0xfe, 0x3c, 0x7b, 0x7e, 0x7e, 0xa9, 0x1c, 0x1c, 0x15, 0x16, 0x4f, 0x8d, 0x3b, 0x5f, 0x24, 0x32, +0x5a, 0x72, 0x97, 0xa1, 0xa4, 0x8d, 0x41, 0x6c, 0x5c, 0x39, 0x28, 0x25, 0xdd, 0x44, 0x20, 0x2c, 0x79, 0x4d, 0xa4, 0x8d, +0x7f, 0x7f, 0x65, 0x41, 0x52, 0x8d, 0x7f, 0x3b, 0x5f, 0x52, 0x3c, 0x1e, 0x1e, 0x42, 0x39, 0x39, 0x39, 0x61, 0x60, 0x39, +0x39, 0x7c, 0x1a, 0x76, 0x7a, 0xb1, 0x5d, 0x42, 0x7c, 0x4c, 0xa8, 0x7a, 0x78, 0x76, 0x8a, 0x7, 0xcf, 0x11, 0x45, 0x73, +0x77, 0x39, 0x55, 0x4a, 0x74, 0x88, 0x4d, 0x49, 0xa0, 0x98, 0x97, 0xac, 0xac, 0x6e, 0x9e, 0x88, 0x6e, 0x6e, 0x72, 0x9e, +0x6e, 0x88, 0xa0, 0x88, 0xc6, 0x25, 0x56, 0x56, 0x99, 0x47, 0x6f, 0x4a, 0xd2, 0x9f, 0xa1, 0xb3, 0xd8, 0xa7, 0xd7, 0xd6, +0xd2, 0xe5, 0xe2, 0xca, 0xa8, 0xa5, 0xb1, 0xbe, 0xaf, 0xdb, 0xfe, 0xfe, 0xfe, 0x44, 0x5f, 0x62, 0x7e, 0x1c, 0x2a, 0x1c, +0x15, 0x26, 0x79, 0x7f, 0x8f, 0x4d, 0xc5, 0x37, 0x86, 0x97, 0x9b, 0xa1, 0xc0, 0xa3, 0x3c, 0x61, 0x6c, 0x67, 0x1b, 0xa6, +0x7c, 0x81, 0x52, 0x80, 0x40, 0xa4, 0x7a, 0x78, 0x80, 0x3b, 0x5f, 0x41, 0x41, 0x52, 0x3b, 0x3c, 0x7f, 0x27, 0x27, 0x1e, +0x1e, 0x27, 0x1b, 0x60, 0xa6, 0x60, 0x61, 0x61, 0x61, 0x61, 0x73, 0xa5, 0xb1, 0x28, 0x7a, 0xa8, 0xa8, 0x7a, 0x7a, 0xc6, +0x5d, 0x39, 0x5c, 0x6c, 0xec, 0x11, 0x61, 0x73, 0x73, 0x4c, 0x57, 0x5a, 0x9e, 0x6e, 0x9d, 0x72, 0x9d, 0x70, 0xba, 0x70, +0x97, 0x98, 0x70, 0x75, 0x4b, 0x97, 0x6e, 0x4a, 0x57, 0x74, 0x4b, 0x74, 0x9f, 0x2f, 0x56, 0x71, 0x2f, 0x2d, 0x6e, 0x96, +0x6e, 0x86, 0xa4, 0x91, 0xb5, 0xe6, 0xc7, 0xbc, 0x78, 0x63, 0x7a, 0xc6, 0xb1, 0x5d, 0x76, 0x47, 0x9b, 0x5c, 0xfe, 0xfe, +0xfe, 0x25, 0xb0, 0x36, 0x5e, 0x16, 0x26, 0x16, 0x15, 0x1f, 0x51, 0x63, 0x63, 0x63, 0xa4, 0xd4, 0x4a, 0x6e, 0x97, 0xa1, +0xaf, 0x9c, 0x5f, 0x42, 0x5c, 0x39, 0x1b, 0x39, 0x42, 0x81, 0x90, 0x3e, 0x80, 0x79, 0x5f, 0x3b, 0x5f, 0x5f, 0x40, 0x8f, +0x7f, 0x52, 0x52, 0x66, 0x3b, 0x3b, 0x52, 0x27, 0x1e, 0x3c, 0x25, 0x60, 0x45, 0x61, 0x5c, 0x61, 0x6c, 0x5c, 0x5c, 0x6c, +0x5c, 0x60, 0xa6, 0xb1, 0xa8, 0xa8, 0x1b, 0x39, 0x61, 0x61, 0x60, 0x61, 0x6c, 0x5c, 0x73, 0x60, 0x8a, 0x4b, 0x5a, 0x72, +0x72, 0x72, 0x70, 0x74, 0x99, 0xd1, 0xad, 0x70, 0x72, 0x72, 0x98, 0x70, 0x4d, 0x5a, 0x5a, 0x72, 0x97, 0x75, 0xd5, 0xa3, +0x9a, 0x71, 0x56, 0x2f, 0x47, 0x98, 0x97, 0x6e, 0x96, 0x98, 0xbc, 0xeb, 0xd7, 0x87, 0xd5, 0xb0, 0xd7, 0xa2, 0x4a, 0xc5, +0xc1, 0x9f, 0x47, 0x6f, 0x48, 0xc3, 0xfe, 0xfe, 0xfe, 0x56, 0x38, 0x5e, 0x50, 0x7d, 0x1c, 0x29, 0x1c, 0x26, 0x7e, 0x50, +0x4f, 0x4e, 0x8c, 0xa4, 0x74, 0x9c, 0x9e, 0x8b, 0x78, 0x8b, 0x5f, 0x3c, 0xb2, 0x61, 0x42, 0x7c, 0x7c, 0x7c, 0x81, 0x7f, +0x4f, 0x79, 0x4e, 0x3b, 0x3e, 0x3e, 0x40, 0x5f, 0x8d, 0x41, 0x4f, 0x5f, 0xa7, 0x63, 0x63, 0x37, 0x41, 0x66, 0x27, 0x28, +0x61, 0x61, 0x61, 0x39, 0x61, 0x6c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x73, 0x8a, 0x61, 0x60, 0x8a, 0x8a, 0x8a, 0x77, 0x8a, +0x8a, 0x8a, 0x73, 0x8a, 0xaf, 0x98, 0x72, 0x49, 0x49, 0x49, 0x72, 0x76, 0xf3, 0xf7, 0xf3, 0xf7, 0x9e, 0x49, 0x59, 0x70, +0x9d, 0x98, 0x6e, 0x96, 0xa2, 0x87, 0x5e, 0xd2, 0x9a, 0x99, 0x99, 0x99, 0x96, 0x97, 0x97, 0x96, 0x96, 0x9c, 0xbc, 0xa1, +0xbf, 0xb0, 0xa2, 0xb0, 0xb0, 0xa2, 0xa1, 0x9b, 0x9b, 0x85, 0x48, 0x9f, 0x71, 0xc3, 0xfe, 0xfe, 0xfe, 0xde, 0x7e, 0x62, +0x65, 0x51, 0x2c, 0x40, 0x23, 0x23, 0x51, 0x79, 0x34, 0x5e, 0x8b, 0x86, 0xbc, 0x6e, 0x98, 0x8b, 0x3b, 0x8c, 0x78, 0x37, +0x5c, 0x61, 0x45, 0x1b, 0x56, 0x28, 0x25, 0x27, 0x40, 0x43, 0x68, 0x40, 0x2b, 0x1f, 0x26, 0x19, 0x33, 0x19, 0x7b, 0x7e, +0x65, 0x64, 0x66, 0x3b, 0x2b, 0x15, 0x20, 0x41, 0x1e, 0x39, 0x60, 0x60, 0x61, 0x5c, 0x60, 0x8a, 0x73, 0x61, 0x61, 0x61, +0x60, 0x61, 0x77, 0x61, 0x5c, 0x73, 0x73, 0x73, 0x8a, 0x73, 0xae, 0x86, 0x49, 0x9d, 0x49, 0x75, 0x72, 0x98, 0x4a, 0xf3, +0xf7, 0xb2, 0xf4, 0xf7, 0xf3, 0x88, 0x87, 0x9d, 0x72, 0x98, 0x9b, 0x96, 0xc4, 0x87, 0xbd, 0x9c, 0x9a, 0xd1, 0x9a, 0x85, +0xac, 0xba, 0x96, 0x96, 0x9c, 0x85, 0x97, 0xac, 0xbc, 0xba, 0xa2, 0x97, 0xba, 0xb9, 0x96, 0x9b, 0xbc, 0x9a, 0xd1, 0xbe, +0x89, 0xb2, 0xf8, 0xfe, 0xfe, 0x67, 0xb6, 0x53, 0x62, 0x64, 0x2c, 0x2c, 0x40, 0xa7, 0x29, 0xc9, 0x36, 0x79, 0x4b, 0x57, +0x6f, 0x6f, 0x6e, 0x57, 0xc5, 0xc5, 0xa0, 0x5b, 0x60, 0x5c, 0x39, 0x39, 0x7c, 0x7c, 0x5d, 0x3c, 0x21, 0xd8, 0x15, 0xd8, +0x1f, 0x69, 0x2a, 0x4f, 0x5f, 0x52, 0x3e, 0x62, 0x84, 0x6a, 0x63, 0x41, 0x43, 0x3e, 0x3e, 0x3e, 0x7f, 0x27, 0x42, 0x67, +0x60, 0x61, 0x77, 0xa6, 0x73, 0x8a, 0x60, 0x61, 0x60, 0xa6, 0x89, 0x8a, 0x73, 0x61, 0x8a, 0x73, 0x8a, 0x55, 0x4b, 0x70, +0x34, 0x59, 0x58, 0x72, 0xa0, 0x98, 0x9b, 0xf7, 0xf1, 0xf5, 0x55, 0xf6, 0xf6, 0x9f, 0x87, 0x72, 0x98, 0x58, 0x96, 0x98, +0x36, 0xb0, 0x97, 0x88, 0xad, 0xad, 0xd1, 0x96, 0x70, 0xd0, 0xba, 0x96, 0x6f, 0xbc, 0xba, 0x96, 0xa2, 0x9e, 0xba, 0xba, +0xba, 0x96, 0x9c, 0x9b, 0x99, 0x99, 0x71, 0xa5, 0xae, 0x8a, 0xc3, 0xfe, 0xfe, 0x61, 0xb6, 0x3f, 0x62, 0x1d, 0x82, 0x65, +0x3f, 0x79, 0x65, 0x29, 0x1d, 0x26, 0x78, 0x6e, 0x6f, 0xad, 0x86, 0x86, 0x31, 0x37, 0x5f, 0xa4, 0x28, 0x6c, 0x60, 0x77, +0x77, 0x42, 0x25, 0x3c, 0x52, 0xd8, 0x1f, 0x2c, 0x15, 0x2c, 0x2b, 0x41, 0x40, 0x5f, 0x79, 0x62, 0x65, 0x82, 0xa7, 0x26, +0x3b, 0x23, 0x3b, 0x3e, 0x41, 0x64, 0x43, 0x1e, 0x77, 0x61, 0x56, 0xa5, 0x42, 0x67, 0x39, 0x61, 0x39, 0x77, 0xd3, 0x77, +0x8a, 0x73, 0x77, 0x55, 0x86, 0x6e, 0x72, 0x5a, 0x49, 0x70, 0x59, 0x9d, 0x6e, 0x6e, 0x96, 0xf7, 0xf4, 0xf3, 0xf1, 0xf6, +0xf5, 0x9c, 0x58, 0xb0, 0x98, 0x59, 0x97, 0x87, 0x70, 0x9c, 0xbc, 0x9e, 0xad, 0xad, 0xd1, 0xba, 0x70, 0xac, 0xd0, 0xba, +0xac, 0x96, 0xd2, 0xd1, 0x87, 0xe5, 0xad, 0x96, 0xad, 0x85, 0xad, 0x9f, 0x89, 0xae, 0x71, 0x71, 0x99, 0xae, 0x3d, 0xfe, +0xfe, 0x6c, 0x1e, 0x82, 0x82, 0x65, 0x8e, 0x50, 0x64, 0x3b, 0x40, 0x51, 0x7e, 0xa9, 0x4b, 0x9c, 0x9c, 0x85, 0x4a, 0x9b, +0xa3, 0x4b, 0x78, 0x8d, 0x3c, 0x61, 0x5c, 0x77, 0xa6, 0x42, 0x44, 0x1e, 0x20, 0x15, 0x1f, 0x2b, 0x2b, 0x84, 0x7d, 0x29, +0x7e, 0x79, 0x5e, 0x5e, 0x64, 0x3a, 0x26, 0x50, 0x4f, 0x63, 0x40, 0x3e, 0x3e, 0x3e, 0x41, 0x41, 0x8d, 0x37, 0x7a, 0x81, +0x28, 0xa6, 0x42, 0x5d, 0x4c, 0x8a, 0x77, 0x39, 0x89, 0x4a, 0x9d, 0x5a, 0x49, 0x98, 0x70, 0x9d, 0x70, 0x70, 0x70, 0x70, +0x85, 0xad, 0xf6, 0xf4, 0xf3, 0xf1, 0xf4, 0xf6, 0xbb, 0xa0, 0x59, 0x9d, 0x98, 0x98, 0xba, 0x70, 0xac, 0x97, 0xbc, 0xad, +0xad, 0xd1, 0xd1, 0xba, 0xb9, 0xd0, 0xd0, 0xd0, 0xd0, 0xb9, 0xba, 0x98, 0xad, 0xad, 0xbe, 0xbb, 0x99, 0x9a, 0xbe, 0xbe, +0xdb, 0xdb, 0xd3, 0xae, 0xb1, 0x77, 0x3d, 0xfe, 0xfe, 0x3d, 0x42, 0x29, 0x62, 0x29, 0x64, 0x64, 0x5f, 0x4f, 0x32, 0x8b, +0xa4, 0x8d, 0x88, 0xbc, 0x31, 0x86, 0x6f, 0x97, 0x59, 0x59, 0xc1, 0x3b, 0x19, 0x28, 0x5c, 0x39, 0xa6, 0x1b, 0x28, 0x90, +0x90, 0x66, 0x26, 0x26, 0x41, 0x8e, 0x62, 0x62, 0x29, 0x3a, 0x29, 0x5e, 0x7e, 0x7e, 0x64, 0x1c, 0x1c, 0x15, 0x16, 0x4f, +0x19, 0xcc, 0x19, 0x52, 0x5f, 0x87, 0x3f, 0x2c, 0x66, 0x46, 0x46, 0x91, 0x90, 0x7a, 0xc1, 0x37, 0x8b, 0x34, 0x58, 0x58, +0x98, 0x98, 0x75, 0x58, 0x59, 0x75, 0x87, 0x97, 0xad, 0xf7, 0xf5, 0xf4, 0x48, 0xf4, 0xf6, 0xf4, 0xa0, 0xb0, 0xbd, 0x9e, +0x70, 0x9d, 0x87, 0x98, 0x9d, 0x9e, 0x99, 0x99, 0xad, 0xd1, 0x96, 0xb9, 0xb9, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xc4, 0xba, +0xbc, 0xaf, 0x71, 0x56, 0xb1, 0xbe, 0xb1, 0xd3, 0xdd, 0xb1, 0xda, 0xd3, 0xa5, 0x8a, 0xc3, 0xfe, 0xfe, 0xc3, 0x60, 0x3a, +0x7d, 0x3a, 0x1c, 0x69, 0x7b, 0x5f, 0x37, 0x5b, 0x88, 0xc0, 0xa1, 0x9f, 0x9a, 0x57, 0x86, 0x9b, 0x75, 0x79, 0xa3, 0x8d, +0x41, 0x41, 0x60, 0x60, 0x67, 0xa6, 0x42, 0x25, 0x1e, 0x27, 0x40, 0x64, 0x1c, 0x4e, 0x7e, 0x51, 0x29, 0x2a, 0x26, 0x3a, +0x62, 0x7e, 0x1c, 0x2a, 0x1c, 0x15, 0x26, 0x79, 0x7f, 0x68, 0x50, 0xa7, 0x38, 0x36, 0x7d, 0x6d, 0x1f, 0x16, 0xb6, 0x2c, +0xca, 0x8f, 0x7d, 0x4f, 0x79, 0x50, 0x33, 0x34, 0x58, 0x58, 0x79, 0x34, 0x34, 0xb0, 0x75, 0x9b, 0xf7, 0xf1, 0xf4, 0xf4, +0x73, 0xad, 0xf4, 0xd9, 0x87, 0x87, 0xa2, 0x59, 0xb0, 0x98, 0x87, 0x70, 0x98, 0xbc, 0xda, 0x9a, 0xd1, 0xd1, 0xd1, 0x6e, +0xac, 0xd0, 0xd0, 0xd0, 0xb9, 0xd0, 0xd0, 0x70, 0xc0, 0x76, 0x56, 0xbe, 0xb1, 0xb1, 0x4c, 0xd3, 0x56, 0xbe, 0xb1, 0xda, +0xd3, 0x5c, 0xf8, 0xfe, 0xfe, 0x13, 0xb2, 0x5f, 0x36, 0x4d, 0x50, 0x1c, 0x3a, 0x7f, 0x7f, 0x52, 0xe5, 0x7a, 0x71, 0xb1, +0x71, 0x71, 0x9a, 0xaf, 0x4a, 0x57, 0x57, 0xa1, 0x5f, 0x4d, 0xb1, 0x5c, 0x39, 0x67, 0x42, 0x1e, 0x28, 0x3c, 0xca, 0xb3, +0x1c, 0x43, 0x2c, 0x68, 0x1d, 0x3f, 0x64, 0x87, 0x36, 0x5e, 0x16, 0x26, 0x16, 0x15, 0x1f, 0x51, 0x63, 0x26, 0x7e, 0x38, +0x36, 0x87, 0x79, 0x6d, 0x1d, 0x1f, 0x91, 0x6a, 0x3c, 0x43, 0x3f, 0x1d, 0x51, 0x7d, 0x51, 0x51, 0x29, 0x69, 0x51, 0x8c, +0x75, 0xa1, 0xd1, 0xd1, 0xf7, 0xf3, 0xf6, 0xf1, 0xf6, 0xf6, 0x74, 0x98, 0x87, 0xa2, 0x75, 0x59, 0x9d, 0x87, 0x9d, 0x9e, +0x9d, 0x57, 0x2f, 0x71, 0xad, 0xad, 0x96, 0x96, 0x96, 0xac, 0xb9, 0x70, 0xbd, 0xd5, 0xd5, 0xc7, 0xca, 0xc6, 0x99, 0x99, +0xb1, 0xa5, 0xa5, 0xae, 0x71, 0x76, 0x99, 0xc1, 0xb1, 0xb2, 0xf8, 0xfe, 0xfe, 0xfe, 0x3d, 0x18, 0x3b, 0x7e, 0x50, 0x50, +0x26, 0x80, 0x80, 0xee, 0xc6, 0xb1, 0x99, 0xb1, 0x56, 0xae, 0x71, 0x99, 0x76, 0x37, 0xa4, 0x7a, 0x7f, 0x8b, 0xa2, 0x8a, +0x60, 0xde, 0xa5, 0x25, 0x1a, 0x90, 0x52, 0xcb, 0xcc, 0x64, 0xb3, 0x64, 0x36, 0x53, 0x34, 0x36, 0x5e, 0x50, 0x7d, 0x1c, +0x29, 0x1c, 0x26, 0x7e, 0x50, 0x4f, 0x29, 0xc4, 0xb0, 0x7d, 0x79, 0x3f, 0x6d, 0x15, 0xd8, 0x6a, 0xb6, 0x43, 0x50, 0x53, +0x3f, 0x38, 0x50, 0x7e, 0x65, 0x65, 0x68, 0x43, 0xc5, 0xf3, 0xf3, 0xf3, 0xd9, 0xf7, 0xf4, 0xf3, 0xf6, 0xf5, 0x6e, 0x87, +0x58, 0xb0, 0xa2, 0x59, 0x59, 0x70, 0x85, 0x9c, 0x9e, 0x4a, 0x71, 0x71, 0xaf, 0x86, 0x6f, 0x85, 0x72, 0x98, 0x9e, 0xe6, +0xe0, 0xfc, 0xfc, 0xef, 0xee, 0xee, 0xbe, 0x9a, 0xb1, 0xda, 0x56, 0xd9, 0x71, 0x99, 0x76, 0xbe, 0x89, 0xc2, 0xfe, 0xfe, +0xfe, 0xfe, 0x13, 0x61, 0x35, 0x3a, 0x33, 0x4e, 0x63, 0xe3, 0xe7, 0xcc, 0xdc, 0xa8, 0xda, 0xbe, 0x56, 0x71, 0xbe, 0x56, +0x76, 0xa3, 0x78, 0x7f, 0xa7, 0xa2, 0x70, 0x7a, 0x6c, 0x67, 0x25, 0x7c, 0x3c, 0x41, 0xaa, 0xa5, 0x41, 0x68, 0xb5, 0x68, +0x62, 0x53, 0x7d, 0x3f, 0x62, 0x7e, 0x51, 0x2c, 0x40, 0x23, 0x23, 0x51, 0x79, 0x34, 0x38, 0x62, 0x5e, 0x79, 0x7e, 0x1f, +0xce, 0x1c, 0x21, 0xce, 0x66, 0x1c, 0x6a, 0x3f, 0x82, 0x79, 0x50, 0x29, 0x8e, 0x51, 0x91, 0xa8, 0xf3, 0xf3, 0xf5, 0xf6, +0xf3, 0x99, 0xf6, 0xf4, 0xf5, 0x30, 0x58, 0x87, 0x87, 0xb0, 0xb0, 0x87, 0xa0, 0xa1, 0xbd, 0xad, 0xbd, 0x57, 0x71, 0x99, +0xbe, 0xa3, 0x57, 0x9c, 0xac, 0x72, 0x74, 0xd6, 0x6, 0xea, 0x2, 0xfa, 0xf2, 0x1, 0xe8, 0xc6, 0xb1, 0xa5, 0x71, 0x56, +0x71, 0x55, 0x4c, 0x89, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc2, 0x4c, 0x37, 0x4b, 0x8b, 0x8d, 0xb6, 0xa7, 0xa4, +0xdc, 0xa8, 0xca, 0xc6, 0x71, 0xd9, 0x9a, 0x89, 0xbe, 0xa3, 0x8d, 0x78, 0x5e, 0xb0, 0x8c, 0x63, 0x93, 0x67, 0x7c, 0x44, +0x20, 0x20, 0x27, 0xa5, 0xb6, 0x66, 0x91, 0x69, 0x6b, 0x64, 0xb5, 0x68, 0x53, 0x62, 0x64, 0x2c, 0x2c, 0x40, 0xa7, 0x29, +0x65, 0x36, 0x38, 0x58, 0x4e, 0x29, 0x7e, 0x19, 0x69, 0x68, 0x66, 0x6a, 0x21, 0x2a, 0x3f, 0x6a, 0x65, 0x7e, 0x7d, 0x82, +0x69, 0x82, 0x2c, 0xd9, 0xf4, 0xf5, 0xa8, 0x27, 0xf3, 0xf6, 0x5f, 0x8b, 0x4d, 0x58, 0x87, 0xba, 0x87, 0x87, 0xb0, 0x87, +0xa0, 0xbc, 0x9f, 0x85, 0xbc, 0x9f, 0x71, 0x9b, 0x9e, 0xa4, 0x5b, 0x87, 0x98, 0xac, 0x9b, 0xc1, 0xdf, 0xf0, 0xfc, 0xef, +0xee, 0xe8, 0xf2, 0xe4, 0xa5, 0xa5, 0x56, 0x56, 0xb1, 0x56, 0x4c, 0x8a, 0x5c, 0xc3, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0x3d, +0x8a, 0x76, 0x37, 0x78, 0xcb, 0xca, 0xc5, 0x9f, 0xb1, 0x71, 0xb1, 0xb1, 0x71, 0x56, 0xbe, 0xb1, 0x71, 0xa4, 0x4f, 0x78, +0x3b, 0xa7, 0x80, 0x3e, 0x43, 0x67, 0x67, 0x28, 0x1e, 0x1e, 0x5d, 0x3c, 0x90, 0xb6, 0xcd, 0x6d, 0x69, 0x69, 0x84, 0xab, +0x53, 0x62, 0x1d, 0x82, 0x65, 0x3f, 0x79, 0x65, 0x65, 0x84, 0x1f, 0x4e, 0x38, 0x7d, 0x3f, 0x3f, 0x51, 0x64, 0x43, 0xab, +0xb6, 0x43, 0x29, 0x51, 0x7e, 0x51, 0x3f, 0x82, 0x68, 0x2c, 0xcd, 0xe5, 0xf3, 0x89, 0xe4, 0xd1, 0xf6, 0xf4, 0x9a, 0x58, +0x33, 0x49, 0x87, 0x70, 0x87, 0xc4, 0xc4, 0x87, 0x9e, 0x86, 0xd9, 0x9b, 0x9f, 0x76, 0x9a, 0xac, 0x97, 0xa4, 0x5a, 0x70, +0x6e, 0x97, 0x9b, 0x71, 0xaa, 0xee, 0xef, 0xee, 0xcb, 0xef, 0xe8, 0xdc, 0xa8, 0xa8, 0x99, 0x85, 0x5d, 0x7a, 0x8d, 0x1e, +0x60, 0x3d, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0x13, 0x61, 0x31, 0x37, 0xc5, 0x7a, 0xa3, 0xc1, 0xbe, 0xa5, 0xae, 0x56, 0x71, +0xae, 0xb1, 0xb1, 0x56, 0x56, 0x4a, 0xa4, 0x78, 0xa7, 0x41, 0x66, 0x7f, 0x50, 0x27, 0x45, 0x45, 0x28, 0x25, 0x25, 0x27, +0x83, 0xb6, 0x2b, 0x1f, 0xab, 0x62, 0x82, 0x82, 0x62, 0x82, 0x65, 0x8e, 0x50, 0x64, 0x3e, 0x40, 0x29, 0x50, 0x3f, 0x3f, +0x51, 0x1f, 0x1d, 0x53, 0x84, 0x64, 0x8d, 0x65, 0x81, 0x19, 0xc9, 0x38, 0x50, 0x29, 0x69, 0xb5, 0xcd, 0xb3, 0x68, 0xcd, +0xbc, 0xf6, 0xf6, 0xf6, 0xf5, 0x55, 0x5a, 0x58, 0x2e, 0x79, 0x58, 0x2e, 0xba, 0xc4, 0x87, 0xa0, 0x97, 0x96, 0xad, 0xaf, +0x9f, 0x7c, 0x9f, 0x9c, 0xbc, 0x9e, 0x59, 0x72, 0x49, 0x74, 0x37, 0xb1, 0xa8, 0x90, 0xdc, 0xe8, 0xe8, 0xee, 0x0, 0xe8, +0xbe, 0xbe, 0x9a, 0xbe, 0x31, 0x52, 0x41, 0x52, 0x52, 0x8a, 0x3d, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xc2, 0x56, 0x57, 0x37, +0x35, 0x31, 0x9f, 0xbe, 0xdd, 0x99, 0x85, 0x71, 0x71, 0xb1, 0xd3, 0x56, 0x9a, 0x9f, 0x2f, 0x5b, 0x4d, 0x3c, 0xa9, 0x63, +0x4f, 0x64, 0x7c, 0x1b, 0x1b, 0x42, 0x7c, 0xa5, 0x66, 0x21, 0x44, 0x91, 0xce, 0x6a, 0x64, 0x69, 0x53, 0x62, 0x29, 0x64, +0x64, 0x5f, 0x4f, 0x5f, 0x7b, 0xa2, 0x7d, 0xc8, 0x3f, 0x24, 0x1d, 0x1f, 0x29, 0x7e, 0x40, 0x65, 0xaa, 0x5b, 0x7d, 0x5e, +0x8e, 0x38, 0x7e, 0xb5, 0x1f, 0xab, 0x69, 0x6a, 0x53, 0xd2, 0xf4, 0xf1, 0x71, 0x59, 0x5e, 0x58, 0x75, 0xa2, 0xb0, 0x98, +0x58, 0x70, 0x6e, 0xbc, 0xba, 0xba, 0xac, 0xb1, 0xd3, 0xa5, 0x5b, 0xbd, 0x88, 0x96, 0x97, 0xba, 0x98, 0x6f, 0xc5, 0xc5, +0x90, 0xe4, 0xda, 0xc1, 0xee, 0x1, 0x4, 0xe4, 0xb1, 0xd3, 0xa5, 0x31, 0x7a, 0x41, 0x80, 0x3c, 0x52, 0x56, 0x5c, 0x13, +0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x73, 0x35, 0x37, 0x76, 0x76, 0xb1, 0xbe, 0x71, 0x9a, 0xbb, 0x56, 0x71, 0x99, 0xb1, 0x9f, +0x86, 0x9a, 0x2f, 0xa3, 0x7b, 0x7f, 0x63, 0x4f, 0x2b, 0x64, 0xa7, 0x39, 0x1b, 0x28, 0x42, 0x7c, 0x43, 0xb6, 0xaa, 0x83, +0x82, 0x69, 0x69, 0x7d, 0x36, 0x62, 0x3a, 0x1c, 0x69, 0x7b, 0x5f, 0x3b, 0x4f, 0x5e, 0x14, 0x62, 0x1d, 0x7e, 0x3f, 0x1c, +0x6a, 0x29, 0x83, 0x6a, 0xca, 0x63, 0x50, 0x34, 0x7d, 0x3f, 0xc9, 0xb5, 0xb3, 0xab, 0x91, 0xb5, 0x82, 0xcc, 0x91, 0x43, +0x4d, 0x75, 0x30, 0x8c, 0x75, 0xb0, 0x58, 0x58, 0x59, 0x74, 0xa3, 0xaf, 0x97, 0xad, 0x9a, 0x99, 0xae, 0x7a, 0x5b, 0xa0, +0x88, 0x31, 0x9c, 0x97, 0xad, 0x4a, 0x8d, 0x97, 0x8f, 0x91, 0xc5, 0xbe, 0xdf, 0x8, 0xfc, 0xb1, 0xae, 0x7c, 0xaa, 0x5f, +0x5b, 0x66, 0x7d, 0x3e, 0x5f, 0x2f, 0xb2, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xb2, 0x56, 0x37, 0x76, 0x2f, 0xbe, 0xbe, +0x89, 0xae, 0xb1, 0x71, 0x99, 0x99, 0xbe, 0x9b, 0x86, 0x9a, 0x4a, 0x48, 0x57, 0x78, 0x3e, 0x7f, 0x43, 0x91, 0x64, 0x3c, +0x42, 0x42, 0x28, 0x28, 0x21, 0x2b, 0xe7, 0xa9, 0x51, 0x26, 0x64, 0x50, 0x36, 0x36, 0x4d, 0x50, 0x65, 0x3a, 0x4f, 0x4f, +0x3a, 0x7b, 0x5e, 0x14, 0x29, 0x3b, 0x64, 0x26, 0x29, 0x68, 0x2b, 0x82, 0x3c, 0xa7, 0x5e, 0x38, 0x53, 0x3f, 0x82, 0xb3, +0xb5, 0x68, 0xb3, 0x80, 0xcc, 0x3b, 0x91, 0x64, 0xb0, 0x59, 0x98, 0xa2, 0xb0, 0x87, 0xb0, 0x58, 0x59, 0x57, 0xc1, 0xbc, +0xd1, 0xbb, 0xd9, 0x71, 0x9f, 0x8d, 0x4f, 0xa4, 0x76, 0xa3, 0x57, 0x2d, 0x47, 0x57, 0x9c, 0xb9, 0x3f, 0x51, 0x7f, 0x8d, +0x80, 0xea, 0x91, 0xc6, 0x56, 0x18, 0x52, 0x1c, 0x7e, 0x40, 0x1c, 0x3a, 0x5f, 0x60, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0x3d, 0x73, 0x18, 0xa5, 0xbe, 0xbe, 0xbe, 0xdb, 0xdb, 0xd3, 0xae, 0xae, 0xb1, 0x9f, 0x86, 0x9c, 0x9e, 0xa3, 0x5d, +0x7a, 0x78, 0x5f, 0xc6, 0x7a, 0x3e, 0x3a, 0x43, 0x52, 0x42, 0x28, 0x46, 0x46, 0x3e, 0xa9, 0x4e, 0x40, 0x7e, 0x64, 0x7e, +0x38, 0x50, 0x50, 0x50, 0x50, 0x3a, 0x50, 0x24, 0x3a, 0x50, 0x3a, 0x79, 0x7d, 0x23, 0x7b, 0x40, 0x66, 0x20, 0x21, 0x82, +0x27, 0x76, 0xa4, 0xc9, 0x38, 0x7d, 0x82, 0x82, 0x2a, 0x2c, 0x2c, 0xcc, 0x66, 0x7b, 0x8f, 0x7b, 0xa2, 0x87, 0x70, 0x98, +0x36, 0x87, 0x49, 0x98, 0x72, 0x5a, 0xaf, 0xaf, 0xb1, 0xbb, 0xad, 0x9e, 0xa0, 0xa3, 0xc5, 0xa3, 0x9a, 0x97, 0x9c, 0x48, +0x22, 0x85, 0xb9, 0xba, 0x5e, 0x7e, 0x68, 0x8f, 0x7f, 0xea, 0xdf, 0xa5, 0x5d, 0x7f, 0x3b, 0x3a, 0x7e, 0x79, 0x40, 0x50, +0x52, 0xc2, 0x13, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc2, 0x61, 0x60, 0xd3, 0xa5, 0xd3, 0xdd, 0xb1, 0xda, 0xae, +0xa5, 0xa5, 0xee, 0xc7, 0xc7, 0x8d, 0xc5, 0xc5, 0x7a, 0xc6, 0xca, 0xc5, 0xa7, 0x7f, 0x8f, 0x7e, 0x16, 0x3c, 0x1b, 0x93, +0x46, 0x2a, 0x7e, 0x8d, 0xca, 0x7f, 0x3b, 0x5f, 0x34, 0x40, 0x7e, 0x34, 0x24, 0x7e, 0x1c, 0x4f, 0x8d, 0x78, 0x4f, 0x8f, +0x4f, 0x3a, 0x8d, 0x81, 0x28, 0x3c, 0x90, 0xb6, 0x27, 0x7a, 0x8a, 0x35, 0x38, 0x5e, 0x4e, 0x65, 0xcd, 0xab, 0xb5, 0x83, +0x8f, 0x8f, 0x7e, 0x7d, 0x79, 0xb0, 0x87, 0xb0, 0x58, 0x59, 0x9e, 0x9c, 0x5a, 0x49, 0x9e, 0x57, 0x99, 0xbc, 0x59, 0x88, +0x4d, 0x5a, 0xc0, 0x9f, 0xd0, 0x97, 0x9b, 0x85, 0x9b, 0x85, 0x99, 0xb9, 0xba, 0x6b, 0x64, 0xcd, 0x7a, 0xd8, 0xb7, 0x25, +0xaa, 0x7a, 0x37, 0x3a, 0x51, 0x34, 0x4e, 0x4d, 0x60, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x3d, +0xb2, 0x61, 0x77, 0xd3, 0x56, 0xbe, 0xb1, 0xda, 0xa5, 0x77, 0xdc, 0xe6, 0xa9, 0xeb, 0xd6, 0x8d, 0xc1, 0xb1, 0xb6, 0xcc, +0xb3, 0xcb, 0x8d, 0x40, 0x40, 0x43, 0x46, 0x44, 0xfa, 0x41, 0x26, 0x7f, 0x27, 0x90, 0x3b, 0x31, 0x5f, 0x23, 0x5b, 0x34, +0x4e, 0x64, 0x2a, 0x3b, 0x63, 0x64, 0x4e, 0x1c, 0x66, 0x40, 0x3c, 0x28, 0x7c, 0x7a, 0x3e, 0x40, 0x8f, 0x52, 0x61, 0x7c, +0x79, 0x34, 0x24, 0x65, 0x68, 0xdf, 0xcc, 0x43, 0x64, 0xb3, 0xc9, 0x8c, 0x8c, 0x59, 0xb0, 0x36, 0xa2, 0x6e, 0x4a, 0x86, +0x2d, 0xbc, 0xa1, 0x85, 0x9f, 0x9c, 0xbd, 0x88, 0x5b, 0xa4, 0x4f, 0xc1, 0xba, 0x9f, 0x57, 0x6f, 0x57, 0x31, 0x96, 0xb9, +0x70, 0x6a, 0xcd, 0x6, 0x6, 0xf0, 0xcb, 0x7a, 0x90, 0x41, 0x80, 0x64, 0x29, 0x7d, 0x7d, 0x5d, 0xb2, 0xf8, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x13, 0xb2, 0x77, 0xae, 0x71, 0x76, 0x99, 0xc1, 0xc1, 0xdb, 0xe4, 0xcc, +0xd6, 0xc5, 0xca, 0x7a, 0xc1, 0xa8, 0xb6, 0xf0, 0xe7, 0xcc, 0x52, 0x7a, 0x41, 0x40, 0x43, 0x2b, 0x20, 0x27, 0xa8, 0xa8, +0xdc, 0x90, 0x52, 0xa3, 0xa7, 0x7f, 0x23, 0x34, 0x3a, 0x40, 0x51, 0x51, 0x82, 0x43, 0x2b, 0x62, 0x64, 0x29, 0x3e, 0x52, +0x25, 0x41, 0x84, 0x3f, 0x3f, 0x2b, 0x61, 0x39, 0x4f, 0xb0, 0x50, 0x68, 0xcd, 0xcd, 0xb3, 0xe7, 0x91, 0x64, 0x7b, 0x4e, +0x79, 0x8c, 0x7b, 0xd7, 0x78, 0xa3, 0x86, 0x9c, 0x2d, 0x86, 0x86, 0xaf, 0x9c, 0xb0, 0xa2, 0x8b, 0x76, 0x57, 0x5b, 0xa3, +0x7a, 0x7a, 0x31, 0x6f, 0x4a, 0x57, 0x6e, 0x6e, 0x64, 0x84, 0xce, 0x7, 0x7, 0xe0, 0xcc, 0x26, 0xa7, 0x51, 0x64, 0x50, +0x68, 0x29, 0x41, 0x61, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc2, 0x8a, 0x71, +0x99, 0x99, 0x76, 0xbe, 0xc1, 0xa8, 0xe9, 0xe8, 0xe7, 0xe7, 0x7a, 0xc6, 0xa5, 0xdc, 0xee, 0xee, 0x66, 0xcc, 0x66, 0xb6, +0xdf, 0x29, 0x40, 0xa9, 0x83, 0x27, 0xa5, 0xa8, 0xdc, 0x81, 0xb1, 0x3c, 0x27, 0x7a, 0x37, 0x40, 0x40, 0x3e, 0x83, 0x64, +0x1c, 0x2b, 0x8f, 0x8e, 0x38, 0x7e, 0x41, 0x41, 0xaa, 0x43, 0x6a, 0x53, 0x3f, 0xa7, 0x60, 0x5c, 0x63, 0x1c, 0x50, 0x64, +0xcd, 0xdf, 0x91, 0xb3, 0xb3, 0x65, 0xd5, 0x50, 0x4e, 0x4d, 0x78, 0xd4, 0x8d, 0x4b, 0x6e, 0x2d, 0x2d, 0x2d, 0x57, 0x88, +0xbd, 0x9e, 0x4b, 0x31, 0x31, 0x4a, 0x5b, 0xc1, 0x8d, 0x37, 0x5b, 0x9c, 0x97, 0xd2, 0x88, 0x5e, 0x4b, 0xa9, 0xe0, 0x7, +0x7, 0xea, 0xcc, 0x7e, 0x7e, 0x65, 0x3b, 0x3b, 0x64, 0x41, 0x42, 0xb2, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc2, 0xa6, 0xb1, 0x71, 0x4c, 0x56, 0xa5, 0xda, 0xf2, 0xe4, 0xdc, 0xcb, 0xcc, 0x8d, 0xa5, +0x7c, 0xca, 0xcb, 0xe8, 0x46, 0x90, 0x66, 0xb7, 0x91, 0x64, 0x63, 0x65, 0xb5, 0x51, 0x8f, 0xdd, 0x81, 0x1e, 0x1a, 0x25, +0x90, 0x35, 0x35, 0x66, 0x80, 0xcc, 0x66, 0x80, 0x66, 0x66, 0x69, 0x53, 0x7d, 0xa7, 0x52, 0x52, 0x46, 0xb7, 0x6a, 0x53, +0x53, 0x5f, 0x61, 0x61, 0x3e, 0x51, 0x4e, 0x68, 0xab, 0xb3, 0xb3, 0x82, 0x69, 0x68, 0xa9, 0x63, 0xa4, 0xa1, 0xa4, 0xc5, +0xa3, 0x88, 0x88, 0x86, 0x22, 0x86, 0x4b, 0xa0, 0x49, 0x59, 0x7b, 0x23, 0x5b, 0x5b, 0x5b, 0x5d, 0x37, 0x78, 0x7b, 0x59, +0xbc, 0x74, 0x47, 0x6a, 0x7e, 0xa4, 0xec, 0x11, 0xd, 0x2, 0xb7, 0x41, 0x64, 0x3e, 0x5f, 0x5f, 0xa3, 0xd3, 0x5c, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc2, 0x39, 0xb1, 0x76, 0x56, 0x56, 0x71, +0xe2, 0xb6, 0xf2, 0xe8, 0xcb, 0xe7, 0xe3, 0xa5, 0xa8, 0x90, 0xcb, 0xe8, 0xde, 0x5d, 0xdf, 0x91, 0xdf, 0x91, 0x7d, 0xd7, +0xb5, 0x7d, 0x62, 0xa9, 0x27, 0x25, 0x1a, 0xc5, 0x52, 0x7a, 0x37, 0x41, 0x90, 0x66, 0xcc, 0x8d, 0x83, 0xb7, 0x91, 0x84, +0xa9, 0x27, 0x80, 0x66, 0x27, 0x43, 0x84, 0x53, 0x53, 0x40, 0x61, 0x6c, 0x7a, 0x7e, 0x64, 0x7e, 0x65, 0xb5, 0x69, 0xb3, +0x91, 0x8f, 0x5f, 0x41, 0x7f, 0xc1, 0xa3, 0x7a, 0xc1, 0x86, 0x74, 0x85, 0x9c, 0x70, 0x59, 0x8b, 0x5a, 0x59, 0x7b, 0x52, +0x3e, 0x8d, 0x52, 0x3c, 0x3b, 0x7e, 0x1d, 0xc9, 0xa3, 0xa1, 0x4a, 0x6d, 0x94, 0xce, 0x7, 0xec, 0x2, 0x2, 0xb6, 0x3c, +0x83, 0x40, 0x4f, 0x19, 0x3c, 0x39, 0xb2, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0x3d, 0x8a, 0xb1, 0x5d, 0xb1, 0x76, 0xdc, 0xca, 0xfa, 0xfa, 0xfa, 0xd8, 0xeb, 0xb7, 0xca, 0x81, 0xe8, 0xee, 0xb6, +0xb6, 0xcb, 0x8f, 0x43, 0xf0, 0xe0, 0xb5, 0xb5, 0x84, 0x65, 0xb5, 0x84, 0x64, 0x3c, 0x5d, 0xb1, 0xa5, 0x1a, 0x7a, 0x41, +0x7f, 0xb6, 0xca, 0xd5, 0xcc, 0x66, 0xd6, 0xd5, 0x8f, 0x90, 0x52, 0x52, 0x90, 0x26, 0x84, 0x62, 0x62, 0x5f, 0x61, 0x5c, +0x81, 0xb3, 0x51, 0x4f, 0x63, 0xb3, 0x91, 0xee, 0xb6, 0x52, 0x7f, 0x37, 0x37, 0x7a, 0x7a, 0xc1, 0xc1, 0x57, 0x4a, 0x5a, +0x5a, 0x2e, 0x70, 0x79, 0x4b, 0x88, 0x8b, 0x8f, 0x40, 0x40, 0x3a, 0x4d, 0x33, 0x63, 0x7e, 0x40, 0x8d, 0x4f, 0x68, 0xe1, +0x7, 0xec, 0x7, 0x6, 0xfc, 0xea, 0xfa, 0xb6, 0xcc, 0x83, 0x5f, 0x37, 0x25, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x3d, 0x61, 0x4c, 0x97, 0xad, 0x9a, 0x7a, 0xe8, 0xe9, 0xfa, 0x0, +0xd8, 0xe8, 0xcc, 0xe3, 0xc6, 0xdd, 0xef, 0xea, 0xe8, 0xa8, 0xa9, 0xe0, 0xc9, 0xb5, 0xb3, 0x6a, 0xce, 0xe1, 0x6d, 0x68, +0x29, 0x3a, 0x78, 0x35, 0xa5, 0x27, 0x37, 0x7f, 0xca, 0x90, 0x41, 0xd6, 0xaa, 0xe3, 0x8f, 0xa7, 0xa7, 0x3c, 0x41, 0x52, +0x90, 0x66, 0x6a, 0x53, 0x62, 0x3e, 0x61, 0x6c, 0xca, 0xa9, 0xb3, 0xa9, 0x78, 0x80, 0xcb, 0x52, 0x41, 0xdc, 0x7f, 0x7a, +0x31, 0xa3, 0x7a, 0xc1, 0xc1, 0x74, 0x49, 0x5a, 0x59, 0x5a, 0x2e, 0x49, 0x9c, 0x9d, 0xc7, 0x7b, 0x7d, 0x3f, 0x4e, 0x4e, +0x4e, 0x4d, 0x4f, 0x5f, 0x5b, 0x5b, 0x7e, 0x6d, 0xce, 0xec, 0xec, 0x7, 0xe, 0x6, 0xe0, 0xdf, 0xfc, 0x83, 0xb7, 0x5d, +0x60, 0xc2, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x5c, 0xa5, +0x96, 0xad, 0x97, 0x76, 0xc1, 0xc1, 0xee, 0xee, 0xe3, 0xe8, 0xee, 0xca, 0xdc, 0x81, 0xe8, 0xb7, 0xee, 0xcb, 0x80, 0xcc, +0xe1, 0xdf, 0x6d, 0xe1, 0x94, 0xe0, 0x8, 0x82, 0x7b, 0x3a, 0x51, 0x79, 0x35, 0x81, 0x81, 0x81, 0xa8, 0xdc, 0x7f, 0x90, +0xb6, 0x80, 0x8d, 0xa7, 0xca, 0x7a, 0x3e, 0x52, 0x1e, 0x52, 0x6a, 0x6a, 0x6b, 0x2a, 0x5c, 0xfb, 0xcb, 0xd6, 0xa7, 0x7b, +0x78, 0x3c, 0xe8, 0x90, 0xa8, 0xa8, 0xc1, 0x76, 0x7a, 0x7a, 0xc6, 0x8d, 0x8b, 0x75, 0x59, 0x49, 0x72, 0x72, 0x49, 0x9c, +0x9c, 0x86, 0x7a, 0x3b, 0x64, 0x29, 0x3a, 0x16, 0x4f, 0x8c, 0x4f, 0x5f, 0x7f, 0x23, 0x64, 0x94, 0xec, 0x7, 0x7, 0x8, +0x6, 0x4, 0xb, 0x0, 0x2, 0xef, 0xe4, 0x8a, 0xc2, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xb2, 0x89, 0x9f, 0x96, 0x96, 0x96, 0x97, 0x9b, 0xc1, 0xdc, 0x3, 0xdd, 0xa8, 0xb1, +0xc6, 0xc6, 0xb1, 0x52, 0xf0, 0xea, 0x2, 0xfa, 0x1, 0xb7, 0xea, 0xe0, 0xce, 0xe0, 0xab, 0xb5, 0xa9, 0xd7, 0x50, 0x7e, +0x4f, 0x63, 0xb6, 0xe9, 0xaa, 0xa5, 0x7a, 0xca, 0xca, 0xe3, 0x7f, 0x52, 0xcb, 0xdc, 0xaa, 0x20, 0x1e, 0xb6, 0x6a, 0x53, +0x84, 0x83, 0x5c, 0x6c, 0xe4, 0xca, 0xa8, 0xc1, 0x1a, 0x81, 0x20, 0xaa, 0xaa, 0x7c, 0x18, 0x2f, 0x31, 0x23, 0x63, 0x7b, +0x33, 0x33, 0x34, 0x2e, 0x6e, 0x9d, 0x70, 0xa2, 0x74, 0x5b, 0x7f, 0x7f, 0x3e, 0x2a, 0x1c, 0x1c, 0x16, 0x38, 0x5e, 0x4f, +0x3b, 0x5f, 0x7e, 0x94, 0x7, 0xe0, 0x7, 0xfc, 0xed, 0xe8, 0xa, 0xa, 0xe9, 0xde, 0xa6, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc2, 0x61, 0xae, 0x96, 0x96, 0xb9, +0xba, 0x9c, 0xc5, 0x90, 0xe9, 0xdd, 0xb1, 0xd3, 0x76, 0xc1, 0x5d, 0xb7, 0x8, 0x2, 0xc, 0xef, 0xfa, 0xf2, 0xcb, 0xdf, +0xe0, 0x6d, 0x91, 0xd7, 0x82, 0x6a, 0xc9, 0xb3, 0x7b, 0x79, 0x84, 0xd8, 0xcc, 0x81, 0x25, 0x25, 0xdc, 0xca, 0xb6, 0x90, +0x27, 0xc6, 0x1a, 0x27, 0x28, 0x3c, 0x84, 0x6d, 0x7d, 0x40, 0x6c, 0x6c, 0xdc, 0x25, 0x28, 0x4c, 0x4c, 0x7c, 0x81, 0xe4, +0x81, 0x7c, 0x7c, 0x31, 0x4f, 0x79, 0x79, 0x79, 0x79, 0x30, 0x75, 0xb0, 0xa0, 0x74, 0x8b, 0x78, 0x5f, 0x3b, 0x41, 0x3e, +0x40, 0x65, 0x3f, 0x51, 0x5e, 0x36, 0x5e, 0x4e, 0x26, 0x4d, 0x8f, 0xce, 0x94, 0x6, 0xea, 0xef, 0xd8, 0xfc, 0xe8, 0xf2, +0xdd, 0xdd, 0x8a, 0xc2, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xf8, 0xc2, 0xbb, 0xd1, 0x96, 0x9c, 0xac, 0x97, 0xcb, 0xa8, 0xdc, 0xa8, 0xa5, 0x5d, 0x7a, 0xb7, 0xd8, 0xb7, +0x8, 0xfc, 0xfa, 0xee, 0xdf, 0x4, 0xe8, 0xee, 0xfa, 0xe0, 0xe1, 0x82, 0xc9, 0x7d, 0xe6, 0xdf, 0xb5, 0xa9, 0xcd, 0xce, +0xab, 0x65, 0xa7, 0x80, 0x27, 0x81, 0x25, 0xdc, 0x81, 0xa8, 0x27, 0x27, 0x42, 0x52, 0x51, 0x84, 0x7d, 0x80, 0xc3, 0xb2, +0xda, 0x90, 0xdd, 0x7c, 0x56, 0x7c, 0xde, 0xe8, 0xf2, 0xc1, 0x4d, 0x79, 0x79, 0x8c, 0x24, 0x4e, 0x8b, 0x4e, 0x8e, 0x8e, +0xa2, 0x8c, 0xc9, 0xb3, 0x40, 0x4f, 0x3e, 0x3e, 0x3e, 0x16, 0x51, 0x5e, 0x8e, 0x62, 0x3a, 0x50, 0x51, 0xb3, 0x8f, 0xe1, +0x7, 0x7, 0x8, 0x2, 0x7, 0xea, 0xe8, 0xef, 0xe4, 0x77, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x73, 0xd1, 0x96, 0x9c, 0xb9, 0x86, 0x5b, 0xc6, +0xdc, 0xc6, 0xb1, 0x7a, 0x66, 0xee, 0xf0, 0xd8, 0xd8, 0x2, 0xee, 0x0, 0xee, 0x4, 0x0, 0xe9, 0x4, 0x4, 0xfc, 0xb3, +0x7b, 0xd7, 0xd7, 0xab, 0xd7, 0xa9, 0xdf, 0xe0, 0xfc, 0xfc, 0xb5, 0xc9, 0x65, 0x80, 0x80, 0x7f, 0x52, 0x28, 0x25, 0xa8, +0x4c, 0x3c, 0x7d, 0x7d, 0xc9, 0xca, 0xfe, 0xb2, 0xa8, 0xca, 0xa8, 0x4c, 0x57, 0x8d, 0xcb, 0x83, 0x66, 0xd4, 0x8b, 0x8e, +0x50, 0x8c, 0x7b, 0x63, 0x30, 0x64, 0xb5, 0xa2, 0x9e, 0xa4, 0x63, 0x64, 0x16, 0x43, 0x4f, 0x3b, 0x3e, 0x43, 0x3e, 0xa9, +0x8e, 0x7d, 0x7d, 0xc7, 0x40, 0x2c, 0x91, 0xe0, 0xe0, 0x2, 0x1, 0x4, 0xfc, 0xfc, 0x2, 0xe8, 0xde, 0x60, 0x3d, 0xf8, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, +0xb2, 0x8a, 0xd9, 0x96, 0xad, 0x85, 0x9f, 0x76, 0xa8, 0xda, 0xb1, 0x76, 0xcc, 0x2c, 0xfc, 0x1, 0xef, 0x8, 0xd, 0xd, +0x6, 0x2, 0x0, 0xaa, 0xd8, 0xd8, 0xcd, 0xee, 0xca, 0xb3, 0x82, 0x82, 0x8c, 0xa7, 0xf0, 0xea, 0xfc, 0xf0, 0xf0, 0xcc, +0x91, 0x8f, 0x8f, 0x8f, 0xa9, 0x83, 0x4f, 0x40, 0x5f, 0x23, 0x7e, 0x65, 0x65, 0xe3, 0x44, 0x27, 0xda, 0xa7, 0xb0, 0x5b, +0xc5, 0xc7, 0xd6, 0xca, 0x64, 0x7f, 0x76, 0x7f, 0x78, 0x63, 0x4f, 0x63, 0x4f, 0x32, 0x79, 0xa2, 0x9d, 0x7b, 0x2a, 0x26, +0x2a, 0x16, 0x50, 0x78, 0x41, 0x82, 0x40, 0x64, 0x5e, 0x8c, 0x8e, 0x4e, 0xb3, 0x2a, 0x68, 0x91, 0x91, 0xfc, 0x1, 0x20, +0xc1, 0x76, 0xef, 0xe4, 0xa6, 0xb2, 0x13, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0xf5, 0xd1, 0xac, 0x6e, 0x85, 0x76, 0x76, 0x9f, 0xaf, 0x9f, 0x48, +0xd8, 0x6, 0x2, 0xfc, 0xef, 0x4, 0xe, 0xd, 0x8, 0x4, 0xfa, 0x0, 0x4, 0xfc, 0xdf, 0xf0, 0xb7, 0xa9, 0xb5, 0xb5, +0xa7, 0x8d, 0xcd, 0xdf, 0xf0, 0xdf, 0xcd, 0xcd, 0xcc, 0xf0, 0xcd, 0xb5, 0xe0, 0xce, 0xcd, 0x1c, 0x82, 0xb3, 0x2a, 0xdf, +0x91, 0xb3, 0xcd, 0xb3, 0xe3, 0xc9, 0xd7, 0x7b, 0xbd, 0xc7, 0xeb, 0xb6, 0xeb, 0xd6, 0x8d, 0xa3, 0x8d, 0x4d, 0x8d, 0x5f, +0x83, 0xa7, 0xc7, 0x7e, 0x8e, 0x4d, 0x40, 0x3a, 0x3e, 0x15, 0x1d, 0x7e, 0x8d, 0x4f, 0xa4, 0x75, 0x88, 0x88, 0x7b, 0x64, +0x82, 0x7e, 0x65, 0x8f, 0xd8, 0xe7, 0xb6, 0xe4, 0x56, 0xb1, 0xe4, 0xdb, 0x5c, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xb2, 0xbb, 0x96, +0x96, 0x6f, 0xaf, 0x9b, 0x48, 0x9a, 0x47, 0x35, 0xd8, 0x7, 0x6, 0xf0, 0xfa, 0xf2, 0x8, 0x8, 0x6, 0xb6, 0xed, 0xb6, +0x2, 0x6, 0x6, 0x2, 0xd, 0x4, 0xd8, 0xd6, 0xd6, 0xa3, 0xe6, 0xcd, 0xb3, 0xc9, 0xc9, 0xc9, 0xd6, 0xd8, 0xe7, 0xcd, +0xd7, 0xce, 0x91, 0x63, 0xb3, 0xb3, 0x91, 0xcd, 0x8f, 0x8f, 0xea, 0x8, 0xeb, 0xf0, 0xd5, 0xc0, 0xc0, 0xee, 0xe8, 0xe3, +0xeb, 0xa7, 0xc7, 0xa7, 0xcb, 0xa7, 0xc5, 0x3c, 0x8d, 0xcc, 0x8d, 0xa7, 0x4d, 0x50, 0x51, 0x1c, 0x29, 0x26, 0x26, 0x4f, +0x37, 0x5d, 0xa3, 0xd2, 0xb1, 0xa3, 0xa9, 0x1c, 0x7e, 0x7e, 0x40, 0x8f, 0x91, 0xb3, 0x8d, 0x90, 0xfa, 0x1, 0xdd, 0x61, +0x3d, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x13, 0xf1, 0xd9, 0xad, 0x6f, 0x9c, 0x9b, 0x9a, 0x99, 0x76, 0x7a, 0xef, 0x7, 0xe1, 0x6, +0xfc, 0xef, 0xef, 0xfa, 0xe8, 0xdd, 0xa8, 0x0, 0x6, 0x7, 0xe1, 0x2, 0xc, 0x1, 0xeb, 0xe6, 0xeb, 0xd6, 0xd6, 0xcd, +0x6a, 0xd7, 0xe7, 0xc7, 0xa7, 0xe7, 0xeb, 0xe6, 0xb3, 0xdf, 0xe6, 0x4f, 0x91, 0xb3, 0x83, 0xe6, 0x91, 0x8f, 0xef, 0xeb, +0xd6, 0xeb, 0xd6, 0xe2, 0xd6, 0xe3, 0xeb, 0xb3, 0xc7, 0xa9, 0xc7, 0xeb, 0x80, 0xe3, 0x52, 0x52, 0xd6, 0x8d, 0x8f, 0x78, +0x4e, 0x65, 0x29, 0x2b, 0x3b, 0x5b, 0x8d, 0x7f, 0x76, 0x71, 0xbe, 0xbe, 0xda, 0xc5, 0x5f, 0x64, 0x26, 0x65, 0x26, 0xa7, +0xa7, 0xc7, 0xa4, 0xe9, 0x3, 0x3, 0x9, 0xc3, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0xb2, 0xbb, 0x9a, 0x85, 0xaf, +0x99, 0x9a, 0x7a, 0xcb, 0x41, 0x7, 0x7, 0xc, 0x1, 0xeb, 0xf0, 0xfa, 0xe3, 0xa5, 0x7c, 0x0, 0x8, 0xef, 0xfa, 0x1, +0xc, 0x4, 0xef, 0xef, 0xef, 0xcc, 0xe3, 0xed, 0xf2, 0xed, 0xe3, 0xd6, 0xd6, 0xe7, 0xcc, 0x91, 0xf0, 0xb3, 0x91, 0xa7, +0xb3, 0x8f, 0x8f, 0x91, 0xb5, 0xb3, 0xe6, 0xe6, 0xd5, 0xc7, 0xe2, 0xd2, 0xca, 0xd6, 0xc9, 0xc9, 0xa4, 0xd4, 0xc7, 0xa7, +0xd6, 0xa1, 0x7a, 0x32, 0x7f, 0xe7, 0xa7, 0x80, 0x79, 0xa9, 0x91, 0x26, 0x7f, 0xc1, 0xd2, 0xa8, 0x99, 0x71, 0x99, 0xb1, +0x9f, 0xa1, 0x5e, 0x4d, 0x4f, 0x69, 0x4f, 0xa7, 0xa9, 0xa7, 0xa8, 0x61, 0xfb, 0xc3, 0x13, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xf8, 0x13, 0xf1, 0x8a, 0x55, 0x55, 0x76, 0x35, 0x31, 0x37, 0xfc, 0xd, 0x7, 0x2, 0xee, 0xee, 0xd8, 0xfa, +0xf2, 0x77, 0xdd, 0xe8, 0xee, 0xb, 0xc, 0xe, 0xd, 0xb, 0xef, 0xe7, 0xe7, 0xe7, 0xe5, 0xe7, 0xdf, 0xef, 0xcb, 0x78, +0xd5, 0xc7, 0xa9, 0xf0, 0x8, 0xce, 0xe0, 0xb3, 0xb3, 0x83, 0xc7, 0xdf, 0xe7, 0x8f, 0xc7, 0xe6, 0xd6, 0xeb, 0xd6, 0xbd, +0xc0, 0xc5, 0x8d, 0xa3, 0x7a, 0xc1, 0x35, 0xe3, 0xd6, 0x49, 0x57, 0xa4, 0xa4, 0x7f, 0xeb, 0xcc, 0x8f, 0x7b, 0x8f, 0x7f, +0x4a, 0x76, 0x76, 0xb1, 0x71, 0x71, 0x54, 0x4c, 0xb1, 0x31, 0x4e, 0x8c, 0x4e, 0x4e, 0x24, 0x4f, 0x3b, 0xaa, 0x45, 0x9, +0xf, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0x3d, 0xc2, 0xb2, 0x81, 0x41, 0x7f, 0x6, +0xdf, 0x80, 0x8, 0xd, 0x0, 0x4, 0x2, 0xd, 0x3, 0xde, 0xe9, 0x4, 0xef, 0x1, 0xee, 0xc, 0xc, 0x8, 0xee, 0xef, +0xf0, 0xeb, 0xd6, 0xe7, 0xf0, 0xe6, 0xb5, 0xe6, 0xdf, 0xd8, 0xf0, 0x4, 0x2, 0xfc, 0x1, 0xb6, 0xee, 0xee, 0xcb, 0xb6, +0xee, 0xcc, 0xe2, 0xc1, 0xe2, 0xd6, 0xa8, 0xa7, 0xc7, 0x8d, 0xca, 0x25, 0x18, 0x76, 0x37, 0xa4, 0xc7, 0x8b, 0x37, 0x31, +0x7f, 0xee, 0xe3, 0x66, 0xc7, 0x8b, 0xa4, 0xd2, 0x76, 0xb1, 0xa5, 0xa5, 0x54, 0x56, 0xae, 0x54, 0x56, 0x74, 0x4d, 0x26, +0x50, 0x4b, 0x4f, 0x37, 0xa5, 0x61, 0x3d, 0xf, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xf8, 0xf8, 0xc3, 0x60, 0xe8, 0x2, 0x7, 0xea, 0x2, 0x8, 0x6, 0xd, 0xe, 0x8, 0xd, 0x0, 0xaa, 0xf2, 0x2, +0xea, 0x2, 0xee, 0x5, 0xc, 0xc, 0xdc, 0x0, 0x0, 0xee, 0xeb, 0xe5, 0xd2, 0xa9, 0x6a, 0xe0, 0x6, 0x7, 0xe0, 0xb7, +0x66, 0xee, 0xb6, 0xe8, 0xfa, 0xcb, 0x27, 0xaa, 0x4, 0xe7, 0xe3, 0xe9, 0xf2, 0xc5, 0xa5, 0xe2, 0xa4, 0x7f, 0x90, 0xa8, +0x7a, 0x5f, 0x8c, 0x78, 0xa7, 0xc7, 0x8d, 0xdc, 0xb6, 0xd6, 0x8c, 0xc7, 0xa7, 0xc7, 0x5a, 0x88, 0xa3, 0xda, 0x7c, 0xc6, +0x85, 0x9a, 0xd3, 0x56, 0xbe, 0xc1, 0x37, 0x3b, 0x5b, 0x31, 0x25, 0x77, 0xb2, 0x3d, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xb2, 0x93, 0x1, 0xb7, 0xee, 0x8, 0x0, 0xb, +0xe, 0x6, 0x6, 0xfc, 0xef, 0xee, 0xdd, 0xb, 0x6, 0xe, 0x4, 0xf2, 0x5, 0xc, 0x3, 0x3, 0xf2, 0xee, 0xe3, 0xa3, +0x4d, 0x4d, 0x69, 0xe1, 0x7, 0x7, 0xea, 0x83, 0xa9, 0x8f, 0xe7, 0xfa, 0xee, 0x90, 0xa8, 0xdc, 0xee, 0xca, 0xed, 0xed, +0xed, 0xc1, 0x7a, 0xc1, 0x8d, 0x4f, 0x80, 0xc5, 0x79, 0x5e, 0x79, 0x74, 0xc0, 0xa3, 0xc6, 0x7a, 0xe8, 0xa4, 0xe6, 0xe6, +0xf0, 0xe6, 0xa2, 0x9e, 0x88, 0x9e, 0xd2, 0xd2, 0xbe, 0x71, 0xa5, 0xbb, 0x71, 0x2f, 0x76, 0x7c, 0x77, 0x39, 0x5c, 0x3d, +0xf, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xc3, 0xb2, 0x1b, 0x71, 0x99, 0xef, 0xe4, 0x4, 0xfc, 0x8, 0xb, 0x8, 0xd8, 0xfa, 0xf2, 0xfa, 0x2, 0xc, 0xfa, 0x5, +0xa, 0x1, 0xfa, 0xb6, 0xd4, 0xc5, 0xc6, 0xa3, 0x51, 0x4b, 0xd6, 0x94, 0x7, 0x6, 0xea, 0xb7, 0x63, 0x7e, 0xcc, 0x0, +0x0, 0xf2, 0x90, 0xeb, 0xee, 0x81, 0xbe, 0xd2, 0xc1, 0xbe, 0x7a, 0xd4, 0x32, 0x5f, 0x3b, 0x8d, 0xd4, 0x78, 0x4d, 0x74, +0x74, 0x5b, 0x37, 0xa3, 0xd4, 0xc7, 0xe6, 0xe6, 0xf0, 0xe7, 0x9e, 0x9c, 0x9c, 0x9e, 0x9d, 0x9f, 0xda, 0x5d, 0xb1, 0x71, +0xae, 0x8a, 0x73, 0x5c, 0xc2, 0x3d, 0x13, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xc3, 0x5c, 0xa6, 0xed, 0xca, 0xcb, 0xed, 0xe3, 0xa, 0x5, 0xf2, +0xf2, 0xdd, 0xa8, 0xe8, 0xc6, 0x1a, 0xa, 0x90, 0x90, 0x7a, 0xa7, 0xa7, 0x74, 0xe2, 0x86, 0x31, 0x84, 0xce, 0xdf, 0x94, +0x11, 0xd, 0x4, 0xb7, 0x52, 0x91, 0x80, 0x90, 0x1, 0xa, 0xe8, 0x0, 0xe8, 0xdc, 0xa5, 0xc6, 0xe2, 0x76, 0x76, 0xa3, +0x31, 0x37, 0x5f, 0x8d, 0x37, 0x37, 0x5a, 0x4b, 0x5b, 0x78, 0x8d, 0x31, 0xa4, 0xd5, 0xe6, 0xe7, 0xef, 0xc0, 0x88, 0x4a, +0x86, 0xbd, 0xbd, 0x9b, 0x76, 0xb1, 0xa5, 0x89, 0x61, 0xc2, 0xc3, 0x13, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x13, 0xc2, 0x3, +0xd, 0xe7, 0xd6, 0x7f, 0xef, 0x5, 0xa, 0xdd, 0xdd, 0xa5, 0x71, 0x99, 0xc6, 0x90, 0xb6, 0x3b, 0x7f, 0x4d, 0xa9, 0x40, +0x7f, 0x7a, 0x5f, 0x4f, 0xe1, 0x94, 0xec, 0x6, 0x6, 0x8, 0xea, 0x0, 0x3c, 0x43, 0xcb, 0x3c, 0x0, 0x0, 0xe8, 0xa8, +0xc1, 0xa8, 0xc6, 0xa1, 0xe5, 0xda, 0xd2, 0xc1, 0x8d, 0x4b, 0x74, 0x8d, 0x50, 0xa0, 0x88, 0x4d, 0x5b, 0x37, 0xa7, 0xa7, +0xa4, 0xc7, 0xe7, 0xed, 0xdc, 0xd4, 0x74, 0x74, 0x86, 0xa0, 0xc7, 0xa3, 0xb1, 0x77, 0x8a, 0x73, 0xc2, 0xf8, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xc3, 0x6c, 0x5, 0x0, 0xef, 0x8, 0xdf, 0xca, 0x0, 0xdd, 0xdd, 0x71, 0x99, 0x71, +0x56, 0xa8, 0xca, 0x5f, 0x33, 0x8c, 0x4f, 0xa7, 0x8d, 0x37, 0x5f, 0xb5, 0xab, 0xe1, 0xec, 0xec, 0x7, 0xc, 0x6, 0xfc, +0xd8, 0xcc, 0xb6, 0x27, 0xf2, 0xb6, 0xcb, 0xaa, 0x90, 0xdc, 0xc6, 0x71, 0x9f, 0x9f, 0xa3, 0xc6, 0x7a, 0xbf, 0xb0, 0x8d, +0x5f, 0x75, 0xa7, 0xd6, 0x52, 0x7a, 0xd6, 0x8d, 0x8d, 0xcc, 0xee, 0xe3, 0xca, 0x7a, 0xd4, 0x74, 0x6e, 0xd6, 0xa6, 0x5c, +0x5c, 0xb2, 0xb2, 0x3d, 0xc3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xf9, 0x9, 0x3, 0x4, 0x6, +0xea, 0xef, 0xee, 0xe4, 0xa5, 0xae, 0x4c, 0x71, 0x54, 0xae, 0x5d, 0x5b, 0x40, 0x3a, 0x4d, 0x5f, 0xa4, 0x37, 0x5b, 0x63, +0xce, 0xce, 0x7, 0xec, 0x6, 0x6, 0x8, 0x2, 0xd8, 0x2, 0xee, 0x90, 0xaa, 0xe8, 0x7f, 0x7a, 0x52, 0xc5, 0xa3, 0x76, +0x9f, 0x31, 0xa4, 0xd6, 0xa7, 0xc7, 0xa2, 0x5f, 0x4d, 0x75, 0x4b, 0xa4, 0x7a, 0x7f, 0xcb, 0xa7, 0xa7, 0x7a, 0x7a, 0xc5, +0xc1, 0xa3, 0xa4, 0x76, 0x39, 0xc3, 0xfe, 0x13, 0xc3, 0xc3, 0xc3, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xf8, 0x3d, 0x9, 0x3, 0xb6, 0xee, 0x2, 0xf2, 0xdd, 0xdd, 0xae, 0x9a, 0x71, 0x89, 0x56, 0xbe, 0xc1, +0x52, 0x52, 0x8c, 0x7b, 0x5f, 0x8d, 0x37, 0x5f, 0xe0, 0xe0, 0xfc, 0x6, 0x4, 0x2, 0xe8, 0xa, 0x0, 0xe8, 0x90, 0x3c, +0xdc, 0xc5, 0xd6, 0x5f, 0xd6, 0xd4, 0xd4, 0x8d, 0xa4, 0x74, 0xa4, 0x8d, 0xc7, 0x5f, 0x37, 0x3b, 0x8d, 0x7a, 0x88, 0x88, +0x57, 0x5f, 0x8d, 0xa7, 0xa7, 0xd6, 0x7f, 0x8d, 0xc6, 0xca, 0x39, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf, 0xf9, 0xb2, 0x73, 0x89, 0xf2, 0xdd, 0xda, +0xbe, 0x9a, 0x99, 0x71, 0xae, 0x99, 0x48, 0xbe, 0xbe, 0xc5, 0x8c, 0x8c, 0x5f, 0x52, 0x37, 0x57, 0x8d, 0x7f, 0xe3, 0xb7, +0xeb, 0xe3, 0xb7, 0x0, 0x0, 0xca, 0x37, 0x37, 0x5f, 0x78, 0x88, 0xa7, 0xa7, 0x40, 0x8d, 0x3b, 0xa7, 0x78, 0x8d, 0xa7, +0x37, 0x7a, 0x37, 0x74, 0x78, 0x4d, 0xa1, 0x5a, 0x32, 0xa4, 0x5f, 0x8d, 0x5b, 0x37, 0x8d, 0xca, 0x6c, 0xf, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xf8, 0x3d, 0xc2, 0x5c, 0x60, 0xa6, 0x89, 0x55, 0xae, 0x71, 0xb1, 0x71, 0xd1, 0x9a, 0x57, 0xd4, 0xc6, 0xca, 0xc6, +0x37, 0x7a, 0x9f, 0xbe, 0x9a, 0x76, 0x76, 0xe4, 0xe8, 0xfc, 0xdf, 0x5b, 0x80, 0xa7, 0xa7, 0x8d, 0x7b, 0x79, 0xa2, 0x7b, +0x40, 0x3e, 0x7f, 0x16, 0x65, 0xa9, 0x80, 0x3a, 0x8d, 0x37, 0xa4, 0x49, 0xa0, 0x9d, 0x9c, 0x32, 0x33, 0x4a, 0x7a, 0x76, +0x7a, 0x3c, 0x60, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xf9, 0xc2, 0xc2, 0xb2, 0x6c, 0x73, 0xa6, 0xae, +0x71, 0x71, 0x76, 0xb1, 0xc6, 0xa5, 0xd3, 0x7c, 0xa5, 0x71, 0x71, 0xb1, 0xb1, 0xb1, 0xd3, 0xdc, 0xfa, 0xea, 0xd8, 0xc7, +0x8d, 0x37, 0x80, 0xcc, 0xd6, 0x7b, 0x50, 0x4e, 0x3a, 0x3a, 0x43, 0x16, 0x1c, 0x3a, 0x37, 0xca, 0x37, 0xa4, 0x7a, 0x74, +0x49, 0xba, 0x70, 0x5a, 0x2f, 0x56, 0x89, 0x8a, 0x61, 0xc2, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xf, 0xf8, 0x13, 0xc3, 0x3d, 0x5c, 0x73, 0x77, 0xa6, 0xd3, 0x89, 0x7c, 0xb1, 0xa5, 0xae, 0x71, 0xb1, 0x56, 0xb1, +0xb1, 0xa5, 0xa8, 0xaa, 0xb6, 0xee, 0xcb, 0xcb, 0x52, 0x3c, 0xd6, 0x8d, 0xc7, 0x5f, 0x7b, 0x51, 0x7d, 0x40, 0x63, 0x5f, +0x5f, 0xa4, 0xa3, 0xb1, 0xc6, 0x86, 0x57, 0x37, 0x97, 0x98, 0x98, 0x85, 0x73, 0xb2, 0xc2, 0x3d, 0xc3, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0xf8, 0x3d, 0xc2, 0x5c, 0x8a, 0xa5, +0xd3, 0xdb, 0xd3, 0xae, 0x54, 0xd3, 0x71, 0x71, 0xa5, 0xa5, 0xc6, 0xdc, 0xa8, 0x9f, 0xc5, 0x7f, 0x7a, 0x8d, 0xd6, 0xa7, +0x83, 0x5f, 0x50, 0x3a, 0x64, 0x2a, 0x52, 0x9f, 0xa3, 0xdc, 0xbe, 0x99, 0x9a, 0xa1, 0x76, 0xa5, 0x48, 0x99, 0x56, 0x61, +0x3d, 0x13, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0x3d, 0x61, 0x77, 0xdb, 0x4c, 0xbb, 0x55, 0x8a, 0x77, 0xbb, 0x9a, 0xb1, 0xa5, 0xb1, 0xa8, +0x81, 0x81, 0xa8, 0x57, 0x76, 0x37, 0x52, 0xd6, 0xeb, 0x80, 0x8c, 0xa9, 0x64, 0x66, 0x8d, 0x31, 0xc1, 0x5d, 0x99, 0x71, +0x56, 0xb1, 0x5d, 0x73, 0x5c, 0x5c, 0xc2, 0x13, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf8, 0x3d, 0xb2, 0x60, 0x77, 0x55, 0x73, +0xb2, 0x73, 0x55, 0xd3, 0x56, 0xae, 0x8a, 0x61, 0x5c, 0x9, 0x45, 0x39, 0x73, 0xa6, 0xb1, 0xdd, 0xf2, 0xe8, 0xd6, 0xc7, +0x78, 0xa3, 0x76, 0xb1, 0xb1, 0xb1, 0x89, 0x55, 0x73, 0x5c, 0xb2, 0x3d, 0xc3, 0xc3, 0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xf8, 0xc3, 0xc2, 0xc2, 0xc2, 0x3d, 0xc3, 0xc2, 0xb2, 0x61, 0x73, 0x5c, 0xc2, 0x3d, 0xf, 0xf8, 0xf, 0xc3, +0x3d, 0xc2, 0xb2, 0x9, 0x60, 0xa6, 0x25, 0x57, 0xa3, 0x57, 0x76, 0xa5, 0xa6, 0x77, 0x8a, 0x5c, 0x3d, 0xc3, 0xf8, 0xf8, +0xf8, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf, 0x47, 0x65, 0x42, 0x6d, 0x40, 0x9, +0x1, 0x0, 0x66, 0x2d, 0x3d, 0x3c, 0x52, 0x0, 0x20, 0x1f, 0x34, 0x0, 0x1d, 0x1c, 0x2d, 0x0, 0x26, 0x25, 0x37, 0x0, +0x24, 0x23, 0x34, 0x0, 0x27, 0x26, 0x38, 0x0, 0x22, 0x21, 0x30, 0x0, 0x2a, 0x29, 0x3b, 0x0, 0x30, 0x2f, 0x43, 0x0, +0x26, 0x25, 0x34, 0x0, 0x2d, 0x2c, 0x3c, 0x0, 0x2a, 0x29, 0x38, 0x0, 0x38, 0x37, 0x46, 0x0, 0x2c, 0x2a, 0x45, 0x0, +0x1c, 0x1b, 0x29, 0x0, 0x18, 0x17, 0x22, 0x0, 0x1e, 0x1d, 0x2a, 0x0, 0x1a, 0x19, 0x24, 0x0, 0x1e, 0x1d, 0x29, 0x0, +0x1c, 0x1b, 0x26, 0x0, 0x24, 0x23, 0x31, 0x0, 0x22, 0x21, 0x2e, 0x0, 0x26, 0x25, 0x33, 0x0, 0x22, 0x21, 0x2d, 0x0, +0x25, 0x24, 0x31, 0x0, 0x20, 0x1f, 0x2a, 0x0, 0x2a, 0x29, 0x37, 0x0, 0x27, 0x26, 0x33, 0x0, 0x24, 0x23, 0x2e, 0x0, +0x2b, 0x2a, 0x37, 0x0, 0x28, 0x27, 0x33, 0x0, 0x26, 0x25, 0x30, 0x0, 0x27, 0x26, 0x31, 0x0, 0x30, 0x2f, 0x3c, 0x0, +0x2b, 0x2a, 0x35, 0x0, 0x2f, 0x2e, 0x39, 0x0, 0x23, 0x21, 0x33, 0x0, 0x1a, 0x19, 0x22, 0x0, 0x1e, 0x1d, 0x26, 0x0, +0x22, 0x21, 0x2b, 0x0, 0x29, 0x28, 0x32, 0x0, 0x2c, 0x2b, 0x35, 0x0, 0x2e, 0x2d, 0x37, 0x0, 0x29, 0x27, 0x37, 0x0, +0x1a, 0x19, 0x21, 0x0, 0x3d, 0x3b, 0x4c, 0x0, 0x22, 0x21, 0x29, 0x0, 0x23, 0x22, 0x2a, 0x0, 0x26, 0x25, 0x2d, 0x0, +0x20, 0x1e, 0x2c, 0x0, 0x39, 0x36, 0x4a, 0x0, 0x2d, 0x2b, 0x39, 0x0, 0x2a, 0x28, 0x35, 0x0, 0x33, 0x31, 0x3e, 0x0, +0x1e, 0x1d, 0x24, 0x0, 0x21, 0x20, 0x26, 0x0, 0x2c, 0x2a, 0x34, 0x0, 0x39, 0x36, 0x43, 0x0, 0x18, 0x17, 0x1a, 0x0, +0x2b, 0x2a, 0x2d, 0x0, 0x25, 0x22, 0x2a, 0x0, 0x29, 0x26, 0x2d, 0x0, 0x43, 0x4b, 0x56, 0x0, 0xd, 0x12, 0x1b, 0x0, +0x17, 0x1a, 0x20, 0x0, 0x1a, 0x20, 0x2d, 0x0, 0x14, 0x18, 0x21, 0x0, 0x1d, 0x22, 0x2d, 0x0, 0x1a, 0x21, 0x31, 0x0, +0x21, 0x27, 0x35, 0x0, 0x22, 0x26, 0x30, 0x0, 0x1b, 0x1e, 0x25, 0x0, 0x37, 0x45, 0x6b, 0x0, 0x16, 0x1b, 0x29, 0x0, +0x22, 0x29, 0x3d, 0x0, 0x14, 0x18, 0x23, 0x0, 0x1f, 0x25, 0x35, 0x0, 0x22, 0x28, 0x39, 0x0, 0x1d, 0x22, 0x2f, 0x0, +0x12, 0x15, 0x1d, 0x0, 0x21, 0x26, 0x33, 0x0, 0x17, 0x1a, 0x22, 0x0, 0x23, 0x27, 0x32, 0x0, 0x10, 0x15, 0x25, 0x0, +0x18, 0x1d, 0x2c, 0x0, 0x16, 0x1a, 0x26, 0x0, 0x27, 0x2c, 0x3b, 0x0, 0x19, 0x1c, 0x25, 0x0, 0x11, 0x13, 0x19, 0x0, +0x1b, 0x1e, 0x27, 0x0, 0x21, 0x26, 0x37, 0x0, 0x27, 0x2c, 0x3d, 0x0, 0x19, 0x1c, 0x27, 0x0, 0x18, 0x1b, 0x25, 0x0, +0x1b, 0x1e, 0x29, 0x0, 0x1d, 0x20, 0x2b, 0x0, 0x14, 0x16, 0x1d, 0x0, 0x1f, 0x22, 0x2c, 0x0, 0x25, 0x2c, 0x49, 0x0, +0x24, 0x2a, 0x43, 0x0, 0x1c, 0x20, 0x2f, 0x0, 0x1f, 0x23, 0x33, 0x0, 0x21, 0x25, 0x36, 0x0, 0x23, 0x27, 0x37, 0x0, +0x1b, 0x1e, 0x2a, 0x0, 0x25, 0x29, 0x39, 0x0, 0x20, 0x22, 0x2a, 0x0, 0x11, 0x12, 0x16, 0x0, 0x19, 0x1a, 0x1e, 0x0, +0x19, 0x1c, 0x2b, 0x0, 0x19, 0x1c, 0x29, 0x0, 0x1d, 0x20, 0x2d, 0x0, 0x21, 0x24, 0x33, 0x0, 0x1f, 0x22, 0x2f, 0x0, +0x23, 0x26, 0x35, 0x0, 0x21, 0x24, 0x31, 0x0, 0x13, 0x14, 0x19, 0x0, 0x16, 0x17, 0x1c, 0x0, 0x1a, 0x1b, 0x20, 0x0, +0x22, 0x26, 0x3d, 0x0, 0x1c, 0x1f, 0x2f, 0x0, 0x21, 0x24, 0x34, 0x0, 0x24, 0x27, 0x38, 0x0, 0x19, 0x1b, 0x26, 0x0, +0x1d, 0x1f, 0x2b, 0x0, 0x1b, 0x1d, 0x28, 0x0, 0x2a, 0x2d, 0x3e, 0x0, 0x28, 0x2b, 0x3b, 0x0, 0x21, 0x23, 0x2f, 0x0, +0x17, 0x18, 0x1e, 0x0, 0x1f, 0x24, 0x45, 0x0, 0x1b, 0x1e, 0x31, 0x0, 0x1e, 0x21, 0x34, 0x0, 0x22, 0x25, 0x39, 0x0, +0x26, 0x29, 0x3d, 0x0, 0x19, 0x1b, 0x28, 0x0, 0x1b, 0x1d, 0x2a, 0x0, 0x2e, 0x31, 0x47, 0x0, 0x2a, 0x2d, 0x41, 0x0, +0x1f, 0x21, 0x30, 0x0, 0x21, 0x23, 0x32, 0x0, 0x1d, 0x1f, 0x2c, 0x0, 0x26, 0x28, 0x36, 0x0, 0x14, 0x15, 0x1c, 0x0, +0x29, 0x2b, 0x39, 0x0, 0x16, 0x17, 0x1e, 0x0, 0x18, 0x19, 0x20, 0x0, 0x19, 0x1a, 0x21, 0x0, 0x1b, 0x1c, 0x23, 0x0, +0x1d, 0x1e, 0x25, 0x0, 0x1f, 0x20, 0x27, 0x0, 0x24, 0x27, 0x43, 0x0, 0x28, 0x2b, 0x45, 0x0, 0x1b, 0x1d, 0x2d, 0x0, +0x2a, 0x2d, 0x45, 0x0, 0x21, 0x23, 0x35, 0x0, 0x14, 0x15, 0x1e, 0x0, 0x25, 0x27, 0x37, 0x0, 0x15, 0x16, 0x1f, 0x0, +0x27, 0x29, 0x39, 0x0, 0x18, 0x19, 0x22, 0x0, 0x19, 0x1a, 0x23, 0x0, 0x1a, 0x1b, 0x24, 0x0, 0x17, 0x18, 0x20, 0x0, +0x1b, 0x1c, 0x25, 0x0, 0x1e, 0x1f, 0x28, 0x0, 0x1d, 0x1e, 0x26, 0x0, 0x24, 0x25, 0x2e, 0x0, 0x23, 0x24, 0x2c, 0x0, +0x26, 0x2a, 0x52, 0x0, 0x21, 0x23, 0x3c, 0x0, 0x2b, 0x2e, 0x4b, 0x0, 0x2f, 0x32, 0x51, 0x0, 0x23, 0x25, 0x3b, 0x0, +0x25, 0x27, 0x3d, 0x0, 0x28, 0x2a, 0x41, 0x0, 0x34, 0x37, 0x54, 0x0, 0x25, 0x27, 0x3b, 0x0, 0x15, 0x16, 0x21, 0x0, +0x17, 0x18, 0x23, 0x0, 0x1c, 0x1d, 0x2a, 0x0, 0x32, 0x34, 0x4a, 0x0, 0x1b, 0x1c, 0x27, 0x0, 0x20, 0x21, 0x2e, 0x0, +0x1f, 0x20, 0x2c, 0x0, 0x22, 0x23, 0x30, 0x0, 0x1d, 0x1e, 0x29, 0x0, 0x23, 0x24, 0x31, 0x0, 0x1e, 0x1f, 0x2a, 0x0, +0x24, 0x25, 0x32, 0x0, 0x25, 0x26, 0x33, 0x0, 0x22, 0x23, 0x2f, 0x0, 0x21, 0x22, 0x2d, 0x0, 0x1f, 0x20, 0x2a, 0x0, +0x28, 0x29, 0x36, 0x0, 0x29, 0x2a, 0x37, 0x0, 0x23, 0x24, 0x2f, 0x0, 0x25, 0x26, 0x31, 0x0, 0x2c, 0x2d, 0x3a, 0x0, +0x27, 0x28, 0x33, 0x0, 0x2b, 0x2c, 0x37, 0x0, 0x1e, 0x20, 0x3c, 0x0, 0x1c, 0x1d, 0x2e, 0x0, 0x20, 0x21, 0x33, 0x0, +0x1e, 0x1f, 0x2f, 0x0, 0x23, 0x24, 0x36, 0x0, 0x24, 0x25, 0x36, 0x0, 0x29, 0x2a, 0x3d, 0x0, 0x23, 0x24, 0x34, 0x0, +0x1f, 0x20, 0x2e, 0x0, 0x28, 0x29, 0x3b, 0x0, 0x26, 0x27, 0x38, 0x0, 0x22, 0x23, 0x32, 0x0, 0x21, 0x22, 0x30, 0x0, +0x24, 0x25, 0x34, 0x0, 0x23, 0x24, 0x32, 0x0, 0x26, 0x27, 0x36, 0x0, 0x2e, 0x2f, 0x41, 0x0, 0x28, 0x29, 0x38, 0x0, +0x25, 0x26, 0x34, 0x0, 0x2b, 0x2c, 0x3a, 0x0, 0x21, 0x22, 0x38, 0x0, 0x2d, 0x2e, 0x46, 0x0, 0x36, 0x37, 0x4c, 0x0, +0x24, 0x24, 0x39, 0x0, 0x19, 0x19, 0x26, 0x0, 0x27, 0x27, 0x3b, 0x0, 0x19, 0x19, 0x25, 0x0, 0x2c, 0x2c, 0x41, 0x0, +0x21, 0x21, 0x30, 0x0, 0x1f, 0x1f, 0x2c, 0x0, 0x1b, 0x1b, 0x26, 0x0, 0x1d, 0x1d, 0x28, 0x0, 0x2b, 0x2b, 0x3b, 0x0, +0x27, 0x27, 0x35, 0x0, 0x1a, 0x1a, 0x23, 0x0, 0x21, 0x21, 0x2c, 0x0, 0x2e, 0x2e, 0x3d, 0x0, 0x28, 0x28, 0x35, 0x0, +0x1c, 0x1c, 0x25, 0x0, 0x33, 0x33, 0x43, 0x0, 0x30, 0x30, 0x3f, 0x0, 0x20, 0x20, 0x2a, 0x0, 0x1d, 0x1d, 0x26, 0x0, +0x2b, 0x2b, 0x38, 0x0, 0x1e, 0x1e, 0x27, 0x0, 0x29, 0x29, 0x35, 0x0, 0x23, 0x23, 0x2d, 0x0, 0x20, 0x20, 0x29, 0x0, +0x15, 0x15, 0x19, 0x0, 0x1c, 0x1c, 0x21, 0x0, 0x1d, 0x1d, 0x22, 0x0, 0x1f, 0x1f, 0x24, 0x0, 0x23, 0x23, 0x28, 0x0, +0x26, 0x26, 0x2a, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x63, 0x62, 0x63, 0x5b, 0x4d, 0xae, 0x70, 0x73, 0x5f, 0x5e, 0x41, +0x78, 0x99, 0x43, 0x6e, 0x5c, 0x7d, 0xb8, 0xbd, 0x99, 0x55, 0x7c, 0x6f, 0x64, 0x71, 0xb7, 0x61, 0x99, 0x8d, 0x68, 0x70, +0x17, 0xc0, 0x7d, 0x88, 0x68, 0xf8, 0x92, 0xe7, 0xb8, 0x9, 0x5f, 0xec, 0xb8, 0xdb, 0x8, 0xbd, 0xbc, 0x1f, 0x14, 0xc0, +0x9f, 0x8a, 0xed, 0xb5, 0xb0, 0xd9, 0xd9, 0xed, 0x90, 0xcf, 0x9, 0xd9, 0xe9, 0x69, 0x4a, 0x63, 0x45, 0x70, 0x66, 0x5f, +0x57, 0x7d, 0x55, 0x55, 0x54, 0x55, 0xb3, 0x88, 0xb3, 0x5c, 0xb8, 0x71, 0x84, 0x68, 0x5e, 0x68, 0x7c, 0x5c, 0x57, 0x57, +0x7b, 0x6e, 0xbb, 0xb5, 0xd0, 0x5b, 0x49, 0x51, 0xbc, 0x94, 0xa0, 0x92, 0x11, 0x12, 0x59, 0x5c, 0x6f, 0xd1, 0x8e, 0x5e, +0xf2, 0xf7, 0x46, 0xa4, 0xa5, 0xd1, 0x8d, 0x9d, 0xbd, 0x9, 0xc2, 0x72, 0x85, 0x9f, 0xd6, 0x7f, 0xcf, 0x4a, 0x4d, 0x4d, +0x45, 0x7a, 0x65, 0x64, 0x55, 0xb3, 0x55, 0x49, 0x55, 0x55, 0x5d, 0x64, 0x5c, 0x57, 0x5e, 0x5d, 0xba, 0x7d, 0x5d, 0xb3, +0x57, 0x5e, 0x88, 0x5f, 0x57, 0x5e, 0xb8, 0x1b, 0x5f, 0xb8, 0xb3, 0x40, 0x47, 0x92, 0xf8, 0xa5, 0xc0, 0xa4, 0xb3, 0x61, +0x5e, 0x5d, 0xbc, 0x73, 0x7c, 0x96, 0x20, 0xf5, 0xbf, 0x9, 0x80, 0xbb, 0xbb, 0xbd, 0xda, 0x79, 0x77, 0x63, 0x7f, 0x4, +0x9b, 0x62, 0x62, 0x63, 0x69, 0x7a, 0x65, 0x41, 0x55, 0xb3, 0x55, 0x55, 0x4b, 0x5c, 0x5c, 0x5c, 0x57, 0x57, 0x5e, 0x7c, +0x5e, 0x5c, 0x5d, 0xb3, 0x5d, 0x88, 0x99, 0x47, 0xa2, 0x7c, 0xbb, 0x2c, 0x93, 0x51, 0x51, 0x60, 0x51, 0x6a, 0xa7, 0xe2, +0xbd, 0xa5, 0x7d, 0x59, 0x59, 0xba, 0xf3, 0xbf, 0xb9, 0xbf, 0x18, 0xc8, 0xed, 0xd3, 0x28, 0x20, 0xe6, 0xee, 0xb, 0x4, +0x79, 0x86, 0xd8, 0x7a, 0x9b, 0x62, 0x62, 0x56, 0x4d, 0x4c, 0x44, 0x54, 0x55, 0x55, 0x49, 0x6e, 0x5c, 0x68, 0x5c, 0x5f, +0xa5, 0x5d, 0x5d, 0x8d, 0x44, 0x55, 0xb3, 0x57, 0x49, 0x99, 0x41, 0x57, 0xa5, 0xa8, 0x5d, 0x91, 0xeb, 0x93, 0x57, 0x51, +0xa4, 0xa7, 0x61, 0x67, 0x7b, 0x93, 0xbf, 0xc4, 0xe3, 0xb7, 0x61, 0x1c, 0xf2, 0xbf, 0xb9, 0xbd, 0x0, 0x9a, 0x1d, 0xed, +0x86, 0x9, 0x8a, 0x7a, 0xd0, 0xb1, 0x85, 0x86, 0x86, 0x56, 0x45, 0x67, 0x66, 0x85, 0x44, 0x49, 0x87, 0x55, 0x55, 0x6f, +0x59, 0x5d, 0x88, 0xba, 0x7b, 0x42, 0x5f, 0x88, 0x6e, 0x6d, 0xb3, 0x5d, 0x99, 0x84, 0x65, 0xc0, 0x92, 0xa1, 0x9c, 0x51, +0xef, 0xeb, 0x94, 0xba, 0x47, 0x37, 0x74, 0x60, 0x51, 0x12, 0xf8, 0xf7, 0xbf, 0xd5, 0xb7, 0xbf, 0x14, 0xc0, 0xba, 0x15, +0x8a, 0xaf, 0x9f, 0x89, 0xb0, 0x86, 0x7a, 0xd3, 0x72, 0x7f, 0x7a, 0x69, 0xe4, 0x5a, 0x4c, 0x65, 0x7a, 0x5a, 0x64, 0x41, +0x5c, 0x5c, 0x5c, 0x5e, 0x5c, 0x5c, 0x59, 0xf3, 0x13, 0x7b, 0xb7, 0x5e, 0xb3, 0x5c, 0x59, 0x5d, 0x7c, 0x88, 0x7b, 0xa4, +0x47, 0x40, 0x93, 0xef, 0xa3, 0xa6, 0x1c, 0x8, 0xec, 0x95, 0x94, 0xa4, 0x7b, 0x1c, 0x26, 0x96, 0x61, 0xdb, 0xd0, 0x9d, +0x70, 0x16, 0x1a, 0xbe, 0xbf, 0x7e, 0xcf, 0xd9, 0x97, 0x66, 0x7e, 0xd8, 0xe5, 0x8b, 0x6f, 0x9f, 0x9d, 0x45, 0x70, 0x65, +0x72, 0x72, 0x67, 0x65, 0x68, 0x55, 0x54, 0x6d, 0x99, 0x6d, 0x7b, 0xa5, 0xef, 0xb8, 0x5c, 0x5c, 0x47, 0xa1, 0x7d, 0xd1, +0xd5, 0xd7, 0x61, 0x51, 0xa5, 0x36, 0x40, 0x27, 0xa1, 0x94, 0x11, 0x26, 0x40, 0xfb, 0x25, 0xba, 0x11, 0x96, 0x14, 0xb5, +0xed, 0x9, 0xd2, 0xd8, 0xd6, 0xbf, 0xf6, 0xee, 0xc7, 0xce, 0xce, 0xb, 0xd4, 0x70, 0xf0, 0x90, 0xc0, 0xd1, 0x70, 0x7, +0x9f, 0x73, 0x5f, 0x65, 0x4c, 0x5a, 0x79, 0x4e, 0x43, 0x41, 0x41, 0x49, 0x54, 0x64, 0xa4, 0xeb, 0xe8, 0xa2, 0xba, 0x59, +0x76, 0x92, 0xb6, 0xb8, 0xb8, 0xb7, 0x1b, 0xa6, 0xbb, 0xa7, 0x96, 0xf5, 0xef, 0x5d, 0x6f, 0x40, 0x96, 0xef, 0x4e, 0x41, +0xf3, 0xc5, 0x9, 0x9a, 0x72, 0x17, 0xc0, 0x17, 0xa4, 0xf8, 0x1f, 0x28, 0x21, 0x8e, 0xea, 0x16, 0xcd, 0xb1, 0x9d, 0xee, +0x15, 0x16, 0xa, 0xb5, 0xd9, 0x4c, 0x8d, 0x4e, 0x4c, 0x85, 0x70, 0x6f, 0x68, 0x43, 0x68, 0x41, 0x49, 0x42, 0x60, 0xb2, +0x5e, 0x58, 0x60, 0x40, 0x75, 0x8f, 0xa4, 0x40, 0x47, 0x47, 0x80, 0x2f, 0x96, 0x6a, 0x95, 0xa2, 0x94, 0x7d, 0x87, 0xa1, +0xa8, 0xc1, 0xaf, 0x62, 0x80, 0xc4, 0xc2, 0x61, 0xbf, 0xc5, 0xf7, 0xee, 0xf2, 0x7f, 0x8a, 0xd9, 0x9f, 0x9f, 0x16, 0x27, +0xb9, 0xe9, 0xf7, 0x1b, 0x1b, 0xa7, 0xc, 0xb0, 0x7, 0x4a, 0x4c, 0x4c, 0x45, 0x41, 0x71, 0x8b, 0x6e, 0x43, 0x68, 0x68, +0x49, 0x4b, 0x9e, 0x55, 0x58, 0x6b, 0x4f, 0x81, 0x75, 0x94, 0x94, 0x47, 0xb8, 0x47, 0xf8, 0x92, 0x94, 0xa3, 0x25, 0xa1, +0xb6, 0x5d, 0x57, 0x59, 0xf8, 0xa8, 0x8c, 0x4d, 0xbf, 0x80, 0xf4, 0x1b, 0xea, 0x20, 0xec, 0x18, 0x1a, 0xcf, 0x9a, 0x89, +0x9d, 0xbf, 0xbd, 0x1e, 0x90, 0x80, 0x38, 0x23, 0xd3, 0x8c, 0x7e, 0x89, 0xbd, 0x46, 0x64, 0x41, 0x43, 0x68, 0x88, 0x71, +0x6f, 0x43, 0x41, 0x64, 0x7d, 0x61, 0xa1, 0x91, 0x74, 0x40, 0x60, 0x94, 0x6c, 0x76, 0x40, 0x87, 0xd5, 0x4f, 0x60, 0x40, +0x6a, 0x93, 0x96, 0x13, 0xba, 0xa5, 0x51, 0xa3, 0x30, 0x96, 0x89, 0x9a, 0x4, 0x7d, 0xba, 0xbf, 0x16, 0x12, 0xb8, 0x17, +0xea, 0x21, 0x1a, 0x79, 0xb7, 0xb4, 0xe5, 0xbf, 0xd7, 0xf6, 0x23, 0xf0, 0xaf, 0x5, 0xbb, 0x33, 0xdc, 0xc0, 0x41, 0x54, +0x68, 0x6f, 0x6e, 0x43, 0x73, 0x68, 0x68, 0x5e, 0x47, 0xeb, 0x81, 0x40, 0x91, 0x60, 0x40, 0x76, 0xf9, 0x60, 0x42, 0xa3, +0x25, 0x91, 0x40, 0x40, 0x96, 0xf8, 0x2f, 0xa1, 0x93, 0xef, 0xef, 0x57, 0xa4, 0xe8, 0x8a, 0xb5, 0x5f, 0x19, 0xb9, 0xbf, +0x2e, 0xbf, 0xb7, 0x18, 0xdb, 0x8, 0x7e, 0x7, 0xd4, 0x72, 0xce, 0xb9, 0x4, 0x9d, 0x2b, 0x8, 0xcf, 0x9, 0x1a, 0x1d, +0xc6, 0x73, 0x41, 0x49, 0x4e, 0x8b, 0x68, 0x59, 0x5e, 0x59, 0x57, 0xa5, 0xa5, 0x81, 0xa3, 0x8f, 0x81, 0x9c, 0x4f, 0x58, +0x74, 0x93, 0x47, 0xfc, 0x3b, 0x1e, 0x59, 0x95, 0xfe, 0x2f, 0xf8, 0x95, 0x6a, 0x28, 0x30, 0x46, 0x7c, 0xc1, 0x1f, 0x22, +0x46, 0xd1, 0x18, 0x9d, 0x72, 0x22, 0x1d, 0x20, 0xf6, 0x9d, 0x9b, 0x79, 0x9, 0x19, 0xd4, 0x9f, 0xe2, 0xdd, 0xcc, 0x9, +0x4, 0xf1, 0xed, 0x16, 0x9, 0x43, 0x83, 0x49, 0xc1, 0x79, 0x61, 0x5e, 0x5e, 0x47, 0x47, 0xef, 0x95, 0x93, 0x7b, 0x75, +0x76, 0xbc, 0x14, 0x93, 0xa1, 0xb9, 0xf5, 0x37, 0x3d, 0x20, 0xa8, 0x94, 0x8d, 0x59, 0x40, 0x81, 0xa5, 0xa7, 0xc7, 0xb5, +0xd9, 0x19, 0xb8, 0xbe, 0x8e, 0x1b, 0x1d, 0xab, 0x48, 0x4d, 0x20, 0xf1, 0x9d, 0x3, 0xd0, 0x64, 0xf7, 0x9d, 0xce, 0x70, +0x8e, 0xcd, 0x9b, 0xce, 0x9d, 0xb, 0x29, 0x39, 0xec, 0x80, 0x99, 0x6d, 0x5f, 0x7a, 0x43, 0x71, 0x8b, 0x59, 0x59, 0x8d, +0x59, 0x8d, 0x71, 0x6c, 0x3a, 0xef, 0xa6, 0x95, 0xc1, 0xd4, 0x17, 0x76, 0x96, 0x47, 0x76, 0xfb, 0x47, 0x37, 0x30, 0x81, +0xeb, 0x7b, 0x61, 0xcf, 0xc6, 0x34, 0xd9, 0x50, 0x6a, 0x96, 0x20, 0x98, 0x62, 0x78, 0x12, 0x16, 0xd4, 0xce, 0x5, 0x31, +0x5, 0xd9, 0xe9, 0x4, 0x8e, 0x9d, 0xce, 0x6f, 0x9, 0x27, 0x20, 0x21, 0x14, 0x80, 0xb8, 0x88, 0x8b, 0x72, 0xb9, 0x71, +0x68, 0xb8, 0x8d, 0x7d, 0xc0, 0x9, 0xf8, 0x76, 0x36, 0x2c, 0xa2, 0xfa, 0xa6, 0x11, 0x6c, 0x76, 0xa4, 0x40, 0xfc, 0x36, +0xfe, 0xfe, 0xfb, 0x75, 0x40, 0x61, 0x27, 0xf2, 0xf2, 0xbf, 0x22, 0x1c, 0x92, 0xb8, 0xd9, 0xb9, 0xcd, 0x73, 0xd4, 0x24, +0xce, 0x69, 0x6, 0x1d, 0xb5, 0x7a, 0xbf, 0x1f, 0xbd, 0x9d, 0x4, 0x8e, 0x67, 0x16, 0xe6, 0xb4, 0xa, 0xa5, 0xa6, 0xc0, +0xb7, 0x68, 0xb8, 0xb9, 0x5e, 0x15, 0xd1, 0x47, 0xf2, 0xec, 0x76, 0xa4, 0xd3, 0xb3, 0x93, 0xb2, 0x6e, 0x93, 0x81, 0x74, +0x92, 0xa2, 0x57, 0x4a, 0x5b, 0x73, 0x2e, 0xfe, 0xf5, 0xf3, 0xe8, 0xe7, 0x52, 0x8e, 0x19, 0xc4, 0xe8, 0x8b, 0x98, 0xb1, +0xb, 0xbd, 0x9d, 0x70, 0x9f, 0xa, 0x20, 0x2a, 0xdc, 0xd5, 0x28, 0x1c, 0xd7, 0xed, 0xcf, 0x7e, 0xc2, 0xdb, 0x79, 0xd8, +0x35, 0x2f, 0x95, 0xa1, 0x57, 0xa6, 0xef, 0x26, 0xb8, 0x8d, 0xa2, 0x96, 0x14, 0xa2, 0x92, 0x9e, 0xd0, 0xcf, 0xb8, 0x5c, +0xb7, 0x40, 0x47, 0x93, 0x94, 0x51, 0x5e, 0x9a, 0x63, 0xd1, 0x30, 0x30, 0x19, 0x9, 0xbf, 0xa5, 0xa7, 0xb8, 0x1b, 0xf7, +0xbb, 0xc2, 0xd7, 0xd4, 0xd4, 0xc7, 0xc6, 0xed, 0xdc, 0x1d, 0x28, 0xf8, 0x89, 0xb5, 0x18, 0xe9, 0xce, 0xd2, 0xce, 0x67, +0xce, 0xbf, 0x71, 0xc2, 0x23, 0x2f, 0x27, 0xe8, 0xe8, 0xef, 0xa6, 0x95, 0xbf, 0xd5, 0xe3, 0x94, 0x93, 0xb2, 0x8f, 0xb6, +0x4, 0x21, 0xa2, 0x31, 0x22, 0xc4, 0x2f, 0x2e, 0x36, 0xa5, 0x36, 0x2e, 0x59, 0x27, 0x36, 0xb6, 0x73, 0x1f, 0x1c, 0xec, +0x18, 0x6d, 0x6f, 0x1e, 0xa5, 0x30, 0x28, 0x16, 0x83, 0x79, 0xf4, 0x18, 0x9, 0xb7, 0xd8, 0xe6, 0xb5, 0xc, 0xd0, 0xcd, +0x24, 0x7a, 0xcc, 0x6f, 0x8b, 0xe5, 0x2f, 0x1f, 0x35, 0x17, 0xe8, 0xa2, 0xa1, 0x7d, 0xa5, 0x94, 0x10, 0x59, 0x73, 0xb6, +0xfb, 0xa0, 0x99, 0x6f, 0xf, 0x92, 0xeb, 0x12, 0x8f, 0x8f, 0x96, 0xcc, 0xb6, 0x12, 0x20, 0x30, 0x96, 0x30, 0xeb, 0xa5, +0xee, 0xf2, 0xf7, 0x1c, 0x8b, 0x63, 0x84, 0x1a, 0x80, 0xb9, 0xed, 0xdc, 0xd6, 0x79, 0x8e, 0xec, 0x5e, 0x5, 0x90, 0xc6, +0x29, 0xc8, 0xf6, 0x90, 0x3, 0x4, 0xe2, 0x9, 0x38, 0xbb, 0xe4, 0xb5, 0x35, 0xa5, 0x12, 0xa5, 0x81, 0x36, 0xef, 0xe8, +0xe8, 0x68, 0x5c, 0x13, 0xfa, 0x94, 0xce, 0xa5, 0x94, 0x75, 0x93, 0xd1, 0xb6, 0x91, 0x92, 0x5c, 0x7c, 0xf4, 0x17, 0x6a, +0xa5, 0x11, 0xf2, 0x23, 0x1c, 0xef, 0xec, 0x1f, 0x1d, 0x8b, 0xe5, 0x1f, 0xbf, 0xd4, 0xd6, 0xc2, 0x1b, 0xcc, 0xd5, 0x14, +0xbd, 0x9, 0xea, 0xa8, 0x3d, 0x16, 0x33, 0xc8, 0x9, 0xe6, 0x16, 0x14, 0xee, 0xf4, 0x8, 0xf0, 0xf1, 0x96, 0x27, 0xf3, +0xfa, 0x76, 0xf3, 0xec, 0x8d, 0xe0, 0x13, 0xfa, 0x76, 0x27, 0x37, 0x3b, 0xfd, 0x81, 0x91, 0x93, 0x92, 0xf8, 0xa2, 0x2e, +0x96, 0x28, 0xa8, 0xba, 0xcb, 0xaf, 0x5f, 0x34, 0x31, 0x18, 0xbf, 0xbe, 0x7a, 0x84, 0x6f, 0x52, 0x73, 0xd7, 0x6, 0x1b, +0xdb, 0x97, 0xaf, 0x14, 0x61, 0x14, 0xe9, 0xbd, 0x6, 0xe5, 0x24, 0x31, 0x15, 0x19, 0xbf, 0x1f, 0xb, 0x1d, 0x23, 0xa7, +0x20, 0x26, 0x96, 0xf3, 0x96, 0xfc, 0x2f, 0x37, 0x95, 0xef, 0x76, 0xfb, 0x6b, 0xfc, 0xfc, 0x2e, 0xa6, 0x25, 0x76, 0x6c, +0xfa, 0x81, 0x13, 0xa2, 0xef, 0xf3, 0xf8, 0x26, 0xa4, 0xd1, 0x6f, 0x1b, 0xed, 0x5c, 0xc4, 0xc4, 0x8c, 0x7a, 0xd5, 0x14, +0xd5, 0x46, 0x1c, 0xea, 0xd0, 0x3, 0xd9, 0xea, 0x9, 0x2b, 0x17, 0x3, 0xcc, 0x6d, 0xce, 0xa, 0x17, 0x12, 0xe6, 0x14, +0x89, 0x7f, 0x29, 0x35, 0xc2, 0x94, 0x6c, 0x60, 0xfa, 0x36, 0x92, 0x26, 0x76, 0x6c, 0xe6, 0xf2, 0x75, 0xfe, 0x76, 0xa1, +0xa6, 0xa3, 0xa3, 0x96, 0x30, 0xf8, 0xb2, 0x94, 0x26, 0xf5, 0xf8, 0xf8, 0x1c, 0xa6, 0xbd, 0x2f, 0xc3, 0xbf, 0x61, 0xc4, +0x14, 0x29, 0xc2, 0x14, 0x19, 0x17, 0x4, 0xce, 0x7f, 0xdc, 0xf4, 0x9, 0x8d, 0xd3, 0x2, 0x3, 0xaf, 0x1, 0xb8, 0xbf, +0x26, 0x30, 0x14, 0x5, 0xbd, 0x20, 0x35, 0xf0, 0xf0, 0x6c, 0x3a, 0x91, 0x3a, 0x3a, 0x25, 0x19, 0x76, 0xfc, 0x25, 0x7d, +0xd3, 0xf8, 0x3a, 0x58, 0x60, 0xf5, 0x25, 0x19, 0x19, 0x95, 0x96, 0xe8, 0x7b, 0x27, 0x2f, 0x18, 0xe, 0x31, 0xea, 0xc0, +0x27, 0x1c, 0xec, 0x1d, 0xf1, 0x4, 0xb9, 0x80, 0xec, 0x14, 0xcd, 0xd8, 0xf4, 0x1e, 0x18, 0xe5, 0xd5, 0x79, 0x7a, 0xd4, +0xd1, 0x24, 0xd4, 0x69, 0x78, 0x86, 0x9f, 0x4, 0x80, 0xc4, 0xf1, 0x4, 0xf0, 0x3a, 0x75, 0x94, 0xfa, 0x94, 0x74, 0x76, +0x27, 0xfc, 0xf9, 0x40, 0x5d, 0x81, 0x76, 0x81, 0x20, 0xfa, 0x92, 0x2e, 0x27, 0xec, 0xf3, 0xb2, 0x12, 0x96, 0xe8, 0x8b, +0xe9, 0xf7, 0x2f, 0x13, 0x16, 0xbf, 0xf2, 0x1c, 0xd2, 0xac, 0xdd, 0x7d, 0x1b, 0xe5, 0xcf, 0x33, 0xea, 0xb9, 0x4, 0xbf, +0xb9, 0xcc, 0xb7, 0x6, 0xd1, 0x4, 0x8b, 0x31, 0xe4, 0x9a, 0xcb, 0x34, 0x1e, 0x38, 0xf0, 0xad, 0xb0, 0x3a, 0x81, 0x6c, +0x3a, 0x92, 0x75, 0x76, 0xfa, 0x2e, 0xfc, 0xfb, 0x51, 0xf3, 0xef, 0x92, 0x37, 0x81, 0xa5, 0x27, 0x26, 0x27, 0xb7, 0xef, +0xfa, 0xa2, 0xbc, 0x12, 0xc4, 0x36, 0xf3, 0x19, 0x17, 0x12, 0x19, 0x21, 0x8d, 0xcd, 0x8a, 0x8e, 0x18, 0x9f, 0x9a, 0x9d, +0xd4, 0x6f, 0xe0, 0x9d, 0xb9, 0xf2, 0xbf, 0x33, 0x14, 0xdd, 0x84, 0x9, 0x9, 0x4, 0x12, 0x27, 0x19, 0x28, 0x16, 0xe9, +0x9f, 0xa2, 0x93, 0x81, 0x74, 0x95, 0x37, 0x74, 0xf9, 0xa6, 0xfc, 0xfb, 0xa4, 0xf2, 0x81, 0x57, 0xf, 0xa4, 0x2f, 0x2e, +0x37, 0x30, 0xa6, 0x95, 0x2c, 0x13, 0x6, 0x1c, 0xc0, 0x14, 0xb8, 0x17, 0xf7, 0x14, 0x14, 0xb9, 0xb8, 0xa5, 0x9, 0x9d, +0xb7, 0xc2, 0xc3, 0xd1, 0x80, 0xb7, 0xdb, 0xb7, 0x9, 0x1f, 0x1d, 0x90, 0x10, 0xd, 0x9a, 0x9a, 0xaf, 0xe5, 0xec, 0x15, +0x3, 0xcf, 0xb1, 0x4, 0xda, 0xbd, 0x76, 0xf9, 0x81, 0xf2, 0x1c, 0x60, 0x8f, 0x91, 0x94, 0xfb, 0x36, 0x2f, 0x76, 0x91, +0x81, 0xa6, 0xf2, 0x2e, 0x26, 0x96, 0xa2, 0x2f, 0x2f, 0x9b, 0xcb, 0xa5, 0xf2, 0x7, 0xcd, 0xc0, 0x1c, 0xf2, 0xbd, 0x71, +0x80, 0x5f, 0xb8, 0x9d, 0xca, 0xba, 0xed, 0xcd, 0x8c, 0xb8, 0xd7, 0xbd, 0x24, 0x6, 0xb, 0xcf, 0xab, 0x99, 0x1a, 0xae, +0xe0, 0x31, 0xf, 0xb2, 0xde, 0xab, 0xdd, 0xe4, 0xf0, 0xfb, 0x6c, 0x3a, 0xf9, 0x75, 0x96, 0x14, 0x12, 0x91, 0x6c, 0xfb, +0x3d, 0xfc, 0x75, 0x6c, 0x94, 0x2f, 0xba, 0x2f, 0x27, 0x92, 0x7d, 0x22, 0xa8, 0x6, 0xcc, 0xf8, 0x93, 0xc2, 0xf1, 0xd4, +0xb9, 0x1b, 0x7e, 0x85, 0xd5, 0xec, 0x19, 0x98, 0xab, 0x6, 0xb9, 0xc3, 0x8b, 0xc9, 0x4, 0xbd, 0x15, 0x35, 0xea, 0xb1, +0xaf, 0x9b, 0x99, 0x11, 0x17, 0x31, 0x6, 0x24, 0xcc, 0x7a, 0xca, 0xcf, 0xb5, 0xf9, 0xf8, 0x94, 0x92, 0x6b, 0xf9, 0x75, +0x40, 0xfa, 0x3d, 0x30, 0xfe, 0xfd, 0xfa, 0x81, 0x81, 0x64, 0x87, 0x2e, 0xef, 0xa1, 0x80, 0xb8, 0xc4, 0x6a, 0x5f, 0xc0, +0x7c, 0x19, 0xcb, 0xa9, 0x9b, 0xa, 0x8, 0xce, 0xb8, 0xe5, 0x6, 0xd2, 0x7a, 0xc3, 0xea, 0x14, 0x83, 0x62, 0xd4, 0xd5, +0x15, 0x1f, 0xbd, 0x8b, 0x4e, 0x11, 0x99, 0x57, 0x6a, 0x9, 0x78, 0xb8, 0x79, 0x85, 0xdd, 0x9b, 0x86, 0xa3, 0xe3, 0x4, +0x1c, 0x76, 0x6c, 0x74, 0x76, 0x6c, 0x3d, 0x2e, 0x60, 0xfa, 0xfc, 0x60, 0x51, 0x2f, 0x2f, 0xf8, 0x81, 0x8f, 0x47, 0xa2, +0xf2, 0xbd, 0x84, 0xcc, 0x5e, 0xc0, 0xb7, 0x97, 0x4, 0x28, 0xc2, 0xa, 0xe, 0x8c, 0xb9, 0x1b, 0x85, 0x77, 0xd5, 0x9, +0xce, 0x24, 0x9, 0x4, 0x12, 0x3, 0xcf, 0x31, 0x8b, 0xd1, 0x14, 0x8b, 0xcd, 0xb7, 0xe, 0xe, 0x6f, 0x98, 0x62, 0x8b, +0x16, 0xa4, 0xa5, 0x14, 0x2c, 0x81, 0x1f, 0x81, 0x74, 0xfd, 0xfa, 0x3f, 0x53, 0xba, 0x47, 0xa5, 0x96, 0x37, 0x2f, 0x92, +0x94, 0xa4, 0xc1, 0x59, 0x93, 0x10, 0x1, 0x14, 0xe6, 0x6f, 0xec, 0x27, 0x7, 0xea, 0xf4, 0x18, 0x6f, 0x71, 0xb8, 0xd8, +0x97, 0x86, 0xc6, 0xd7, 0x79, 0x5, 0x17, 0x12, 0x10, 0xd4, 0xe5, 0x1a, 0x6, 0x4, 0x78, 0x63, 0x9a, 0xe, 0xcc, 0x4d, +0xca, 0xac, 0xb0, 0x97, 0x24, 0xa2, 0xef, 0xf5, 0x76, 0x93, 0x6a, 0x60, 0xa6, 0x93, 0x40, 0x47, 0x57, 0x59, 0xe8, 0x26, +0x94, 0xeb, 0x94, 0x9e, 0xa2, 0xf7, 0x17, 0xa2, 0xa4, 0x1e, 0xbe, 0x15, 0xc4, 0xea, 0xb8, 0xb7, 0xdb, 0xf6, 0xbd, 0x8e, +0xe9, 0x9, 0xd4, 0x4, 0xd8, 0xc2, 0x21, 0xd8, 0x79, 0x16, 0x16, 0xb8, 0xb7, 0x17, 0x15, 0x2b, 0xe5, 0x6f, 0x99, 0x84, +0xcb, 0xa5, 0x88, 0x84, 0xe0, 0xd, 0xaf, 0xab, 0xad, 0x26, 0xf3, 0x2f, 0xfc, 0xf8, 0xe6, 0x8f, 0x26, 0x9e, 0x40, 0x93, +0x47, 0xa2, 0xa3, 0xa4, 0x13, 0x99, 0x54, 0x87, 0xba, 0x94, 0x96, 0x1c, 0xba, 0xa7, 0xc0, 0xe6, 0xf7, 0x28, 0xc5, 0xd8, +0x79, 0x8e, 0x1e, 0x16, 0xb, 0x20, 0xbe, 0x9, 0xbd, 0x73, 0x2b, 0x2b, 0xd4, 0x4, 0xd8, 0x17, 0x12, 0xf3, 0xe8, 0x10, +0xd1, 0xcd, 0x9d, 0x6f, 0x78, 0x8d, 0x15, 0x79, 0xaf, 0xac, 0x9a, 0xd, 0x85, 0xef, 0x6c, 0xfb, 0xfb, 0x2e, 0xec, 0x81, +0x3a, 0xa3, 0x5d, 0x58, 0x9e, 0xeb, 0xa0, 0xa4, 0xa2, 0xd1, 0x64, 0xb3, 0x5d, 0x73, 0x20, 0x1c, 0x19, 0x30, 0x1c, 0x61, +0x8b, 0x85, 0x8e, 0xd6, 0x78, 0xad, 0x1b, 0xb9, 0x9f, 0x2b, 0xb8, 0xa, 0x8e, 0xd0, 0xd5, 0x15, 0x14, 0xed, 0x4, 0x12, +0xd7, 0x24, 0xe8, 0x12, 0x14, 0x4, 0xcd, 0x78, 0xad, 0xcb, 0xe8, 0xa4, 0x24, 0xb0, 0x89, 0xcd, 0x7a, 0xc0, 0x92, 0x81, +0x94, 0x92, 0xa0, 0x17, 0x26, 0xa1, 0x9e, 0x4f, 0x47, 0xf, 0xb6, 0xe8, 0x25, 0xa6, 0xb3, 0x55, 0xb2, 0x7c, 0xf2, 0xe8, +0x27, 0x30, 0x18, 0xec, 0x6f, 0x9, 0x88, 0xd0, 0x90, 0x80, 0x97, 0x97, 0x8c, 0xcd, 0x72, 0x1d, 0xbd, 0x1c, 0xec, 0x7c, +0xe5, 0x9d, 0x16, 0xb7, 0xd9, 0xcd, 0xe8, 0x1f, 0x13, 0x11, 0x1, 0xca, 0x9b, 0xd2, 0x2b, 0x1b, 0x1d, 0x7f, 0x7f, 0xcb, +0x86, 0xb7, 0xef, 0x93, 0xef, 0x36, 0x57, 0xb, 0x12, 0x60, 0xa2, 0x94, 0x94, 0xa4, 0x12, 0xa2, 0x93, 0xa1, 0x6f, 0x62, +0x6d, 0xba, 0x6, 0x80, 0xeb, 0xb9, 0x14, 0xbf, 0xba, 0x20, 0x7c, 0x6, 0xc2, 0xda, 0x77, 0xdd, 0x90, 0x72, 0xbf, 0x1a, +0xd8, 0xb8, 0xbd, 0x15, 0xe5, 0x6, 0x14, 0xb4, 0xcc, 0xb4, 0xef, 0x17, 0x6, 0x21, 0xa, 0xe, 0x7, 0xd8, 0x4, 0xd4, +0x78, 0x7, 0x8, 0x8a, 0x85, 0x40, 0x94, 0xeb, 0xeb, 0x1f, 0x16, 0xf1, 0x14, 0x88, 0xa3, 0xa4, 0xa2, 0x17, 0x1c, 0xec, +0x94, 0x25, 0x5e, 0xcb, 0x5e, 0xf7, 0x10, 0x10, 0x19, 0x79, 0x78, 0x12, 0xe, 0xc2, 0xbf, 0xb7, 0xbd, 0xee, 0xbe, 0x80, +0xbd, 0xe9, 0x21, 0xdc, 0xb, 0xd0, 0x6, 0x31, 0xdb, 0xd0, 0xb7, 0xe6, 0xe7, 0xe, 0xe, 0xe7, 0x4, 0x0, 0x9, 0x2b, +0xf0, 0xd2, 0xa, 0xe0, 0xae, 0xb5, 0x8e, 0xce, 0xd2, 0x95, 0x76, 0xf8, 0x15, 0x16, 0x1d, 0x17, 0xbd, 0xd5, 0x51, 0x9c, +0x9c, 0xf2, 0x30, 0xa6, 0xcc, 0x79, 0xa6, 0x13, 0xf2, 0xef, 0x19, 0x19, 0x73, 0x68, 0x5f, 0xe, 0xe5, 0x14, 0x1c, 0xb8, +0x14, 0x1f, 0x1c, 0xe, 0x80, 0x90, 0x7f, 0xe4, 0xc0, 0x6, 0x8c, 0xd0, 0x4, 0xcb, 0x10, 0x19, 0xcd, 0xca, 0x2, 0xe7, +0x10, 0x14, 0xe0, 0xab, 0x10, 0x9d, 0x17, 0xe1, 0xcb, 0x2b, 0x9f, 0x9b, 0xb, 0xef, 0x26, 0x36, 0xbf, 0xda, 0xe6, 0x6, +0x79, 0xd5, 0xa1, 0xa1, 0xeb, 0xf3, 0xba, 0x7b, 0xc9, 0x77, 0x13, 0xe6, 0x12, 0xef, 0x1c, 0x2c, 0x11, 0x27, 0x27, 0x10, +0x10, 0xb9, 0xf8, 0x23, 0x18, 0xc2, 0x1e, 0xbf, 0x69, 0x64, 0xad, 0xb1, 0xb9, 0x79, 0x79, 0xcd, 0xd6, 0xb1, 0xe6, 0xcd, +0x9a, 0x78, 0xd3, 0x31, 0xb3, 0x15, 0x8a, 0x62, 0x16, 0xba, 0x87, 0xb4, 0x8d, 0xb1, 0xae, 0x8, 0xf0, 0xf8, 0xef, 0xa6, +0x2f, 0x17, 0xe5, 0x6f, 0x78, 0x47, 0xa5, 0xb6, 0x36, 0xef, 0x7c, 0xe, 0x6f, 0xcc, 0xe7, 0x12, 0xa2, 0x81, 0x2c, 0x95, +0x19, 0xe8, 0x19, 0x17, 0x14, 0x8e, 0x8d, 0xf4, 0x86, 0xcb, 0x1c, 0x34, 0xa, 0x8b, 0x9d, 0x8e, 0x4, 0xdb, 0x8e, 0xa, +0x33, 0x7, 0x7a, 0xb5, 0xac, 0xcb, 0x9, 0x31, 0xe, 0x1b, 0x98, 0x97, 0x34, 0xee, 0x4d, 0x85, 0x70, 0xcf, 0x3, 0x80, +0x66, 0x15, 0xef, 0xa5, 0x93, 0x4f, 0x5c, 0x25, 0xf3, 0x47, 0x95, 0xa2, 0x96, 0xa6, 0xe, 0xb4, 0xa2, 0xba, 0xa4, 0xa3, +0x14, 0xe, 0x7d, 0xe8, 0xec, 0x12, 0x19, 0x1c, 0x34, 0x2b, 0xce, 0x7c, 0xae, 0x14, 0x6, 0xd0, 0xed, 0xd3, 0xd8, 0x7f, +0x7f, 0xd8, 0xdb, 0xea, 0xdb, 0x7f, 0x85, 0xaf, 0xad, 0xdb, 0xb7, 0x5d, 0x8d, 0x6e, 0x77, 0xaa, 0x1e, 0xdf, 0x0, 0x77, +0xae, 0x85, 0xb, 0xe6, 0x9d, 0xe5, 0xa2, 0xef, 0x51, 0x44, 0x5d, 0x93, 0xef, 0x92, 0x92, 0xa3, 0xb2, 0x5c, 0xa2, 0x59, +0x17, 0xb7, 0xba, 0xba, 0xb8, 0xb8, 0xb6, 0xa5, 0x18, 0xba, 0xbc, 0x12, 0x6, 0x14, 0xea, 0xf2, 0xcf, 0x8a, 0xb9, 0xd3, +0x9f, 0x79, 0xdc, 0xd9, 0x69, 0xd5, 0x8c, 0x72, 0x9d, 0x79, 0x89, 0x86, 0xe7, 0x7d, 0xb3, 0x5c, 0xb8, 0xaa, 0x77, 0xe, +0x14, 0xf0, 0xd9, 0x7a, 0xaf, 0x1, 0xd1, 0xed, 0xb, 0x25, 0x2c, 0xeb, 0xa1, 0x4c, 0xb2, 0xa1, 0xeb, 0x93, 0xa1, 0xa3, +0x2c, 0xa5, 0xf5, 0xf, 0xa5, 0x6, 0x47, 0x11, 0x9c, 0xe8, 0x27, 0xe8, 0xf7, 0xb7, 0x14, 0xf2, 0x6f, 0x18, 0x16, 0xd6, +0x7a, 0x7a, 0xd5, 0xa, 0x7e, 0x9d, 0x7f, 0x34, 0x9d, 0xcf, 0x9, 0x1a, 0xd8, 0x7f, 0xb0, 0x9a, 0x12, 0x7b, 0x5e, 0x93, +0x8d, 0xaf, 0xe2, 0x31, 0xb3, 0x24, 0x4, 0xec, 0xb, 0xcf, 0x3, 0xde, 0xaf, 0x93, 0x94, 0xa1, 0xef, 0x81, 0xa1, 0xa4, +0xa1, 0xc0, 0x1c, 0xa6, 0x94, 0x11, 0xa8, 0xf8, 0xef, 0x92, 0x11, 0xba, 0xb4, 0x10, 0xf2, 0x20, 0x27, 0xe6, 0x15, 0x15, +0x80, 0xea, 0xb9, 0x9d, 0x1b, 0x15, 0xd1, 0xd2, 0xd8, 0x56, 0x5b, 0x1a, 0xb, 0x90, 0xd8, 0x8e, 0xf1, 0xb5, 0x5b, 0x8a, +0x43, 0x80, 0x57, 0xee, 0x86, 0x6d, 0x17, 0x5, 0xe9, 0x7, 0x2b, 0xbf, 0xf2, 0x1e, 0x16, 0xe4, 0x8a, 0x94, 0xa2, 0xa4, +0xa5, 0x94, 0xf5, 0xa6, 0x47, 0xb4, 0x8d, 0x92, 0x81, 0xb3, 0xe7, 0xb6, 0x17, 0xf8, 0xe7, 0x19, 0x7b, 0xbf, 0x19, 0x17, +0x1f, 0xd4, 0xbe, 0x14, 0x14, 0xe6, 0xb8, 0x1f, 0x1b, 0xdd, 0x3, 0x9b, 0xcc, 0xce, 0x71, 0xdb, 0x9d, 0x8e, 0xd0, 0x8e, +0xdf, 0x89, 0xab, 0x7e, 0x7e, 0xd6, 0xb6, 0x12, 0x7, 0xf7, 0xa0, 0xa, 0x32, 0x7, 0xe2, 0xb7, 0x1c, 0x33, 0x1d, 0x21, +0xf0, 0x7b, 0xa5, 0xb3, 0x59, 0xa4, 0xc1, 0xa5, 0xa5, 0xb4, 0x83, 0x4b, 0x58, 0x5e, 0xb3, 0xa1, 0xb8, 0xa4, 0xb6, 0xf7, +0xf8, 0xa5, 0xd5, 0xb8, 0x61, 0x8c, 0x14, 0xd7, 0x6f, 0x73, 0xb7, 0x20, 0xf1, 0xac, 0xad, 0xe9, 0x72, 0x52, 0x70, 0x80, +0x80, 0xd3, 0xc4, 0xda, 0xd9, 0x8, 0x7e, 0x1f, 0xbd, 0x8e, 0x7c, 0xf3, 0x1a, 0xec, 0x12, 0x33, 0x33, 0x31, 0xcd, 0x4, +0x30, 0xc, 0xe9, 0x30, 0x23, 0xe8, 0xf2, 0x59, 0x5c, 0x57, 0x7b, 0x68, 0xa5, 0x93, 0xe1, 0x11, 0xa3, 0x51, 0x51, 0xb6, +0x7c, 0xb3, 0xa0, 0xba, 0xbc, 0xec, 0x7c, 0xba, 0x10, 0x71, 0xf2, 0xb8, 0x68, 0x4e, 0xbb, 0x1f, 0xf4, 0xcf, 0x86, 0x67, +0x73, 0x9d, 0x7a, 0x9d, 0x1e, 0xce, 0x7e, 0xe9, 0x8e, 0x7f, 0xb9, 0xf6, 0x1f, 0x18, 0xf4, 0x27, 0xd7, 0x7c, 0x14, 0x33, +0x33, 0x14, 0xde, 0xd9, 0x16, 0x9f, 0xee, 0x1c, 0x34, 0xba, 0xf3, 0x6e, 0xcc, 0xb3, 0x55, 0x55, 0x94, 0xa5, 0xa2, 0xef, +0x9e, 0xb2, 0x5d, 0x19, 0x11, 0x5c, 0x8d, 0x55, 0xba, 0xec, 0xc4, 0xc4, 0x6, 0xb2, 0xf7, 0xbf, 0xc4, 0xbf, 0xb7, 0xb7, +0xea, 0xdb, 0x65, 0x67, 0x7f, 0x67, 0x71, 0xda, 0xf1, 0x7a, 0x9f, 0xbd, 0xdc, 0x7e, 0xc7, 0xc5, 0xf0, 0xea, 0x34, 0x17, +0x80, 0x7d, 0xf5, 0x16, 0xed, 0x18, 0x9f, 0xd8, 0xc2, 0xdb, 0x1b, 0x20, 0x28, 0x14, 0x27, 0x99, 0x85, 0x6f, 0x7b, 0x59, +0xa6, 0x59, 0x9e, 0xa2, 0xb3, 0x4b, 0x12, 0x19, 0x25, 0x84, 0x82, 0x83, 0xa1, 0xf7, 0x7d, 0x5f, 0xb8, 0xb9, 0xcd, 0xd1, +0x9, 0xc2, 0x6f, 0x69, 0x2b, 0xc2, 0xd8, 0xbb, 0xdb, 0x70, 0x88, 0xda, 0x72, 0xbd, 0x90, 0x7f, 0xb5, 0xa, 0x17, 0xf7, +0xbd, 0x61, 0xd7, 0xbf, 0x11, 0xa5, 0x17, 0x35, 0xe4, 0x18, 0x6, 0x14, 0x1b, 0xed, 0xc3, 0x28, 0x23, 0xbb, 0xbf, 0x6e, +0x6e, 0x7d, 0xa2, 0x87, 0xb4, 0x47, 0xb3, 0xb2, 0xe3, 0xa0, 0xa2, 0xb7, 0x13, 0x87, 0xaa, 0xce, 0xf2, 0x1c, 0xa6, 0xc4, +0xa4, 0x73, 0x79, 0x8a, 0xaf, 0x7e, 0x67, 0x50, 0xc5, 0xa7, 0xa8, 0xdb, 0xc2, 0x8e, 0x8b, 0x9f, 0x28, 0xbf, 0xa, 0xb5, +0xf0, 0x35, 0x14, 0x21, 0x6a, 0xbd, 0xc7, 0x6, 0x21, 0xe5, 0x7, 0xe9, 0x4, 0x35, 0x35, 0x16, 0xea, 0xed, 0x1c, 0x1e, +0xf0, 0x65, 0x7c, 0x5d, 0x7c, 0x5d, 0x51, 0x6e, 0x99, 0x9e, 0x9e, 0x49, 0x55, 0xa3, 0xb3, 0x55, 0x5c, 0xf2, 0xf5, 0xba, +0xf2, 0x27, 0x61, 0xbb, 0xa2, 0x80, 0x14, 0xd5, 0x7a, 0xda, 0xf7, 0x72, 0x4e, 0xa5, 0x1e, 0x21, 0x90, 0xc6, 0xd8, 0x56, +0xb, 0xee, 0xc2, 0xea, 0xed, 0x90, 0xa5, 0x20, 0xec, 0xea, 0xa, 0xb7, 0x1b, 0x5, 0xab, 0xe0, 0x35, 0xc, 0xa, 0x33, +0x1e, 0x1e, 0x18, 0x3c, 0x29, 0x8a, 0x61, 0xb9, 0xb7, 0x71, 0x43, 0x7b, 0x99, 0xb2, 0xa3, 0x9e, 0x55, 0xb3, 0xc1, 0xb2, +0x87, 0xc0, 0xa5, 0x7c, 0xba, 0x1f, 0x61, 0xd5, 0xc0, 0xc4, 0x9d, 0xea, 0x1b, 0xc5, 0xc0, 0x7f, 0xce, 0xbd, 0xc7, 0xc2, +0xc8, 0x21, 0x9f, 0x69, 0xae, 0x7f, 0x21, 0x1d, 0xc6, 0xf1, 0xec, 0x1f, 0x1a, 0x16, 0xb7, 0xe8, 0x20, 0x18, 0x89, 0xb0, +0x8, 0xf1, 0x4, 0x21, 0x33, 0x2a, 0x1f, 0x36, 0x30, 0x49, 0x57, 0xc5, 0xa4, 0xb9, 0x43, 0x5d, 0x57, 0xa1, 0x81, 0x25, +0xa0, 0xa4, 0xb8, 0x7d, 0x87, 0xe, 0xa5, 0x59, 0xb8, 0x27, 0xe5, 0xb7, 0x59, 0x71, 0x79, 0xbd, 0xa8, 0x52, 0x50, 0x5a, +0x67, 0x90, 0xa, 0x69, 0x21, 0x1d, 0xdb, 0xcd, 0xde, 0x7e, 0xc6, 0xed, 0xbd, 0xb1, 0xae, 0xcf, 0x20, 0x1f, 0x17, 0x16, +0x1a, 0x5, 0xb0, 0xac, 0x32, 0xf1, 0x1b, 0x28, 0x21, 0x20, 0x28, 0x1b, 0x18, 0x6d, 0x88, 0x61, 0xbc, 0xbf, 0x6a, 0x25, +0x58, 0x9e, 0x91, 0x60, 0x9c, 0xa3, 0xe6, 0xe5, 0xbd, 0xb4, 0x47, 0xb7, 0x17, 0x2f, 0x99, 0xae, 0x88, 0x7c, 0xc0, 0xc5, +0xbe, 0xbd, 0xc5, 0x5a, 0x86, 0x7e, 0x72, 0xc, 0x39, 0xc3, 0xc6, 0xdc, 0x9f, 0xea, 0x1d, 0x1d, 0xd6, 0xb1, 0xaf, 0x90, +0xc7, 0x1a, 0x4, 0xa, 0xa, 0xcf, 0x9a, 0xb0, 0xe4, 0x23, 0xee, 0xea, 0x29, 0x27, 0x34, 0xf1, 0x5, 0xc0, 0xe, 0x8d, +0x61, 0x7b, 0x71, 0x81, 0x8f, 0xb3, 0x60, 0xa1, 0xa0, 0x9e, 0xb3, 0x71, 0xd7, 0xb8, 0xa5, 0xb2, 0x1f, 0x1c, 0x99, 0x4d, +0x8b, 0xc0, 0xc0, 0x59, 0x46, 0xc2, 0x46, 0x7a, 0xbd, 0x27, 0xbe, 0x2d, 0x21, 0x73, 0x9d, 0xee, 0xea, 0x50, 0xdc, 0x14, +0xc6, 0xc7, 0xbf, 0x23, 0x22, 0xed, 0xcf, 0x1d, 0xf4, 0xe9, 0xed, 0x8, 0xbb, 0x20, 0x16, 0x18, 0xc4, 0x1c, 0x1f, 0xc5, +0xc7, 0x83, 0x77, 0x45, 0x57, 0xb8, 0x5f, 0x75, 0x60, 0x60, 0xb3, 0xa4, 0xef, 0x9e, 0x4f, 0x5f, 0xa4, 0xa6, 0x1c, 0x5e, +0x73, 0xb9, 0x5c, 0x7d, 0x57, 0xc0, 0x67, 0x86, 0x43, 0xc0, 0x7f, 0x56, 0xbd, 0x8e, 0xc3, 0xd8, 0xe4, 0xc6, 0xb9, 0xea, +0x72, 0x69, 0xd8, 0x16, 0xa, 0xd9, 0xf1, 0x35, 0x23, 0x35, 0xc6, 0x28, 0x38, 0x21, 0xf1, 0xf1, 0x28, 0x29, 0x20, 0xa7, +0x17, 0x1e, 0x1c, 0x19, 0x70, 0x63, 0xab, 0x9d, 0xb6, 0x7c, 0xa6, 0x94, 0xf, 0x91, 0x13, 0xb8, 0x94, 0xb6, 0xb4, 0xe3, +0xe7, 0x1c, 0x61, 0x4e, 0x7a, 0x5f, 0x7c, 0xd4, 0x43, 0x71, 0x85, 0x62, 0x78, 0x5f, 0x67, 0x69, 0xdb, 0xb1, 0x9a, 0xcd, +0xc3, 0x22, 0x1b, 0xea, 0x90, 0x9f, 0xd8, 0xea, 0xa, 0x89, 0xf0, 0xf0, 0xc6, 0xed, 0x21, 0x22, 0x21, 0x21, 0x1a, 0x0, +0x1d, 0x29, 0x30, 0x6a, 0x2f, 0x30, 0x30, 0x19, 0xee, 0x72, 0x43, 0xec, 0xc5, 0x47, 0xa2, 0xa3, 0xef, 0x40, 0x51, 0xa4, +0x93, 0x59, 0x59, 0x5d, 0xb8, 0xc4, 0xc0, 0x44, 0x77, 0xc0, 0xc2, 0xba, 0x9d, 0x50, 0x65, 0xaf, 0x5c, 0xb7, 0x73, 0x50, +0x69, 0x7e, 0x98, 0x86, 0x8e, 0xda, 0x9f, 0x7e, 0xd9, 0xcf, 0xa, 0xed, 0x7, 0x8, 0xea, 0xc6, 0x33, 0x1d, 0x35, 0x29, +0x23, 0x23, 0x23, 0x33, 0xf4, 0x20, 0x2f, 0x2e, 0xc3, 0xa, 0x22, 0x3d, 0x30, 0x5c, 0xb7, 0xc1, 0x61, 0x59, 0x93, 0x92, +0xfa, 0x60, 0x55, 0x67, 0x7c, 0x60, 0x5d, 0x6f, 0x61, 0x6f, 0xd1, 0x83, 0x53, 0x5c, 0xf7, 0xf3, 0xdb, 0xbd, 0x61, 0xbb, +0x70, 0xaf, 0x56, 0xc7, 0xdc, 0x7e, 0x90, 0x8e, 0x80, 0x8e, 0x56, 0x7e, 0xd9, 0x7e, 0x8e, 0xa, 0xf0, 0xf1, 0x1e, 0xbb, +0x7e, 0x23, 0x21, 0x21, 0x35, 0x38, 0xc8, 0xc6, 0xa, 0x28, 0x1f, 0x37, 0xb5, 0xdf, 0xa, 0x3c, 0x3d, 0x54, 0x6d, 0x99, +0xd5, 0x5c, 0x94, 0x36, 0x94, 0x7b, 0x99, 0x86, 0x4e, 0x51, 0x6e, 0x55, 0x5d, 0x5a, 0x67, 0xec, 0xbf, 0x68, 0xd5, 0xbb, +0x17, 0xbd, 0x95, 0x80, 0x69, 0x50, 0x5b, 0xc6, 0xbb, 0x56, 0x69, 0x8e, 0x80, 0x50, 0xc3, 0x1b, 0xf1, 0xb, 0xdc, 0xd9, +0xf0, 0xf4, 0xed, 0xf1, 0xdf, 0xf1, 0x2a, 0x33, 0xa, 0x1d, 0x23, 0x3d, 0xfd, 0x30, 0xc8, 0x3c, 0xc2, 0x1c, 0x20, 0x29, +0x1f, 0x50, 0xb7, 0x43, 0x6e, 0x59, 0x57, 0xa1, 0xe8, 0xa4, 0x59, 0xce, 0xb7, 0x55, 0x55, 0x5c, 0x5e, 0x61, 0xd8, 0x73, +0xba, 0x6f, 0x71, 0x5f, 0x4e, 0x7a, 0x71, 0x50, 0xbb, 0xc3, 0x3e, 0xd9, 0x7f, 0x56, 0x9a, 0x56, 0x5b, 0x7f, 0x7f, 0xf4, +0xc3, 0xd9, 0xc6, 0xa, 0xf0, 0xf1, 0xf0, 0x35, 0xa, 0xf0, 0xf0, 0x29, 0x90, 0xdf, 0x35, 0x21, 0x3d, 0x2a, 0x21, 0x1e, +0x23, 0x3c, 0x3c, 0x22, 0x34, 0xf, 0x47, 0x65, 0x42, 0x6d, 0x40, 0x9, 0x1, 0x0, 0x77, 0x2d, 0x12, 0x11, 0x34, 0x0, +0x16, 0x14, 0x34, 0x0, 0xd, 0xa, 0x34, 0x0, 0x19, 0x18, 0x26, 0x0, 0x9, 0x7, 0x19, 0x0, 0xf, 0xe, 0x15, 0x0, +0x9, 0x7, 0x11, 0x0, 0x57, 0x56, 0x59, 0x0, 0x4e, 0x48, 0x59, 0x0, 0x16, 0x14, 0x19, 0x0, 0x12, 0x11, 0x11, 0x0, +0x41, 0x33, 0x2f, 0x0, 0x38, 0x29, 0x22, 0x0, 0x32, 0x22, 0x19, 0x0, 0x25, 0x14, 0x8, 0x0, 0x16, 0xa, 0x0, 0x0, +0xf, 0x7, 0x0, 0x0, 0x1c, 0xe, 0x0, 0x0, 0x6, 0x3, 0x0, 0x0, 0x1f, 0x11, 0x0, 0x0, 0x2b, 0x1f, 0xd, 0x0, +0x4e, 0x59, 0x59, 0x0, 0x51, 0x59, 0x59, 0x0, 0x54, 0x59, 0x59, 0x0, 0x57, 0x59, 0x59, 0x0, 0x41, 0x48, 0x49, 0x0, +0x0, 0xe, 0x11, 0x0, 0x0, 0x1c, 0x26, 0x0, 0x0, 0x1f, 0x2b, 0x0, 0x0, 0x11, 0x19, 0x0, 0x0, 0x1c, 0x2f, 0x0, +0x0, 0x11, 0x22, 0x0, 0x6, 0x7, 0x8, 0x0, 0x47, 0x4f, 0x59, 0x0, 0x0, 0x3, 0x8, 0x0, 0x41, 0x48, 0x59, 0x0, +0x3e, 0x45, 0x59, 0x0, 0x2b, 0x30, 0x45, 0x0, 0x3b, 0x41, 0x59, 0x0, 0xf, 0x11, 0x1e, 0x0, 0x12, 0x14, 0x26, 0x0, +0x2b, 0x30, 0x59, 0x0, 0x19, 0x1c, 0x34, 0x0, 0x35, 0x37, 0x51, 0x0, 0x16, 0x18, 0x40, 0x0, 0x2b, 0x2d, 0x4d, 0x0, +0xf, 0x11, 0x40, 0x0, 0x9, 0xa, 0x26, 0x0, 0x28, 0x29, 0x45, 0x0, 0x0, 0x0, 0x11, 0x0, 0x3, 0x3, 0x26, 0x0, +0x3, 0x3, 0x1e, 0x0, 0x1c, 0x1c, 0x4d, 0x0, 0x1c, 0x1c, 0x40, 0x0, 0x22, 0x22, 0x4d, 0x0, 0x28, 0x29, 0x56, 0x0, +0x25, 0x25, 0x4d, 0x0, 0x22, 0x22, 0x45, 0x0, 0x1f, 0x1f, 0x3c, 0x0, 0x25, 0x25, 0x40, 0x0, 0x1f, 0x1f, 0x34, 0x0, +0x1f, 0x1f, 0x2b, 0x0, 0x59, 0x59, 0x59, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, +0x0, 0x5, 0xa, 0x5, 0xa, 0xa, 0x9, 0xa, 0x5, 0xa, 0x28, 0xa, 0x9, 0x9, 0x5, 0x9, 0x3, 0x3d, 0x9, 0x3d, +0xa, 0x5, 0x9, 0x3, 0x3, 0x3d, 0x3d, 0x3b, 0x2b, 0x24, 0x17, 0x17, 0x21, 0x17, 0x16, 0x16, 0x15, 0x18, 0x17, 0x3e, +0x2b, 0x25, 0x21, 0x17, 0x2b, 0x38, 0x27, 0x36, 0x24, 0x17, 0x18, 0x2b, 0x2b, 0x2b, 0x17, 0x18, 0x17, 0x19, 0x10, 0xe, +0x19, 0x17, 0x17, 0x24, 0xe, 0x19, 0x2b, 0x24, 0x17, 0x17, 0x24, 0x3d, 0x19, 0x24, 0x19, 0x18, 0x19, 0x24, 0x2b, 0x2b, +0x19, 0x25, 0x30, 0xb, 0x2b, 0x19, 0x2b, 0x2b, 0x25, 0x25, 0x25, 0x25, 0x25, 0xb, 0x25, 0x30, 0x25, 0x25, 0x25, 0x3d, +0x3d, 0x3d, 0x30, 0x3d, 0x3d, 0x9, 0x3, 0x3d, 0x9, 0x9, 0x9, 0x3d, 0x3, 0x3d, 0x9, 0x3, 0x3, 0xa, 0x9, 0x9, +0x9, 0x9, 0xa, 0x9, 0x3, 0x3, 0x9, 0x9, 0x3d, 0xa, 0x5, 0xa, 0x9, 0x9, 0x9, 0x3, 0xa, 0x5, 0x9, 0x3d, +0x3, 0x3, 0x3d, 0x9, 0x3, 0x3d, 0x9, 0x9, 0xa, 0x5, 0x28, 0x9, 0x9, 0x27, 0x5, 0x6, 0x6, 0x6, 0x6, 0x4, +0x28, 0x5, 0x2a, 0x3b, 0x2d, 0x2b, 0x24, 0x24, 0x17, 0x24, 0x24, 0x17, 0x17, 0x24, 0x38, 0x29, 0x17, 0x16, 0x17, 0x21, +0x25, 0x24, 0x16, 0x17, 0x17, 0x24, 0x2b, 0x2b, 0x24, 0x24, 0x18, 0x17, 0x24, 0x30, 0x19, 0x17, 0x18, 0x24, 0x18, 0x2b, +0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x19, 0x2b, 0x19, 0x2b, 0x25, 0x19, 0x25, 0x2b, 0x19, 0x24, 0xb, 0x2b, 0x25, 0xb, +0x25, 0x25, 0x25, 0xb, 0x3d, 0x30, 0x3d, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, 0x3d, 0x9, 0x30, 0x3d, 0x9, +0x3d, 0x30, 0xc, 0x3d, 0x3, 0x3d, 0x9, 0x3, 0x9, 0x9, 0x3, 0x9, 0x9, 0x9, 0x9, 0x9, 0x3d, 0x9, 0xa, 0x3, +0x3, 0x3, 0x3d, 0x3d, 0xa, 0x5, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, 0x5, 0x5, 0x5, 0x6, +0x6, 0x20, 0x20, 0x6, 0x6, 0x28, 0x27, 0x2a, 0x3, 0x28, 0x2a, 0x28, 0x2c, 0x1a, 0x27, 0x28, 0x2a, 0x3b, 0x2b, 0x25, +0x25, 0x3a, 0x3b, 0x2b, 0x2d, 0x2b, 0x30, 0x25, 0x28, 0x3c, 0x2b, 0x2b, 0x19, 0x2b, 0xe, 0x3d, 0x19, 0x7, 0x24, 0x24, +0xc, 0xa, 0x25, 0x19, 0x24, 0x24, 0x19, 0xe, 0x24, 0x2b, 0x19, 0x19, 0x2b, 0x19, 0x2b, 0x19, 0x25, 0x25, 0x19, 0x25, +0x2b, 0x25, 0x2b, 0x19, 0x25, 0x25, 0x25, 0x25, 0x30, 0xd, 0x25, 0x3d, 0x3d, 0x9, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, +0xd, 0x25, 0xd, 0x3d, 0x30, 0xb, 0x3d, 0x3b, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0xa, 0x9, 0x9, 0x30, 0x9, 0x9, 0x9, +0x3d, 0x3, 0x9, 0x3d, 0xa, 0x9, 0x9, 0x9, 0x9, 0x9, 0x3, 0x9, 0xa, 0x3, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, +0x9, 0x3d, 0x3d, 0x9, 0xa, 0xa, 0x5, 0x20, 0x5, 0x6, 0x6, 0x6, 0x27, 0x6, 0x27, 0x5, 0x2a, 0x28, 0x28, 0x27, +0x28, 0x2a, 0x28, 0x25, 0x38, 0x25, 0x2b, 0x30, 0x3, 0x2a, 0x2a, 0x28, 0x28, 0x1a, 0x6, 0x27, 0x2a, 0x2a, 0x2a, 0x3d, +0x25, 0x3d, 0x9, 0xd, 0x3, 0x3d, 0xb, 0x2b, 0x25, 0xd, 0x30, 0xb, 0x2b, 0x2b, 0x25, 0xa, 0x3b, 0x3d, 0x9, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0xa, 0x3, 0x3d, 0x3d, 0xe, 0x9, 0x3d, 0x3d, 0x9, 0xa, 0x6, 0xf, 0x6, 0xf, 0x5, +0xa, 0x9, 0x20, 0x5, 0x9, 0x5, 0xa, 0x6, 0xa, 0x3, 0x3, 0x3d, 0x9, 0xa, 0x9, 0x3, 0xa, 0x20, 0x3, 0xa, +0xa, 0x5, 0xa, 0x6, 0x6, 0x10, 0x5, 0x10, 0x5, 0x20, 0x6, 0xa, 0x5, 0x3, 0xa, 0x9, 0x9, 0xa, 0x3, 0x3d, +0x3, 0x3d, 0x3, 0x3, 0x3d, 0x9, 0x3, 0x3d, 0x9, 0x3d, 0x3d, 0x25, 0xa, 0x5, 0x9, 0x3, 0x3d, 0x3d, 0x3, 0x3d, +0x3d, 0x3b, 0x25, 0x25, 0x3c, 0x2a, 0x3, 0x2a, 0x2a, 0x38, 0x3a, 0x30, 0x25, 0x2a, 0x3c, 0x25, 0x3a, 0x2a, 0x2a, 0x28, +0x2a, 0x27, 0x27, 0x0, 0x28, 0x28, 0x2a, 0x28, 0x9, 0x14, 0x3d, 0x3b, 0xe, 0x3d, 0xa, 0x3d, 0xe, 0xa, 0x3d, 0x3d, +0x3, 0xd, 0x9, 0x12, 0xf, 0x3f, 0x10, 0x3f, 0x12, 0x12, 0x12, 0x12, 0x10, 0x3f, 0x12, 0x12, 0x12, 0x9, 0x10, 0x6, +0x12, 0x10, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x20, 0x12, 0x12, 0x3f, 0x3f, 0x3f, 0x12, 0x20, 0x12, 0x12, 0x3f, 0x3f, +0x12, 0x12, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x22, 0x3f, 0x3f, 0x12, 0x3f, 0x12, 0x3f, 0x12, 0x12, 0x12, 0x12, 0x20, +0x12, 0x9, 0x3, 0x9, 0xa, 0x5, 0x20, 0x20, 0x5, 0xa, 0x20, 0x9, 0x20, 0xa, 0x3, 0x3d, 0x28, 0x3d, 0x3d, 0x3d, +0x5, 0x5, 0x3, 0x3f, 0x3f, 0x22, 0x3f, 0x3f, 0x22, 0x3f, 0x31, 0x27, 0x33, 0x20, 0x3f, 0x3f, 0x31, 0x1f, 0x2c, 0x31, +0x31, 0x31, 0x33, 0x2f, 0x31, 0x33, 0x31, 0x3f, 0x22, 0x3f, 0x3f, 0x20, 0x3f, 0x22, 0x31, 0x20, 0x9, 0x10, 0x12, 0xf, +0xf, 0xf, 0xa, 0x5, 0xf, 0x10, 0x12, 0xf, 0x3f, 0x9, 0x3f, 0x10, 0xa, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, +0x12, 0x20, 0x10, 0x9, 0x9, 0xa, 0x6, 0x5, 0x12, 0x6, 0x12, 0x12, 0x6, 0x5, 0x10, 0x6, 0xf, 0x5, 0xa, 0x20, +0xf, 0x6, 0xa, 0x9, 0xa, 0x10, 0x12, 0xa, 0x6, 0x9, 0x20, 0x20, 0x3f, 0x12, 0x6, 0x20, 0x6, 0x20, 0x3f, 0x12, +0x12, 0x20, 0x20, 0x20, 0x10, 0x3f, 0x3, 0x9, 0x20, 0x3d, 0x9, 0x3, 0x9, 0x3d, 0x20, 0x20, 0xa, 0x5, 0xa, 0x9, +0xa, 0x9, 0x9, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0xa, 0x9, 0x28, 0x6, 0x20, 0x20, 0x6, 0x20, 0x22, 0x6, 0x2f, 0x5, +0x27, 0x27, 0x22, 0x20, 0x6, 0x2f, 0x28, 0x1f, 0x28, 0x31, 0x2e, 0x1f, 0x33, 0x6, 0x6, 0x33, 0x20, 0x6, 0x4, 0x20, +0x20, 0x22, 0x4, 0x5, 0x9, 0x3d, 0x10, 0x10, 0xe, 0x5, 0x5, 0x11, 0x20, 0x10, 0xf, 0x5, 0x13, 0xa, 0xa, 0xf, +0x10, 0xf, 0x20, 0x9, 0x12, 0xa, 0x12, 0x3d, 0x3d, 0xf, 0x6, 0xa, 0x12, 0x10, 0x6, 0x9, 0xa, 0x3, 0x3d, 0x9, +0x9, 0x3, 0x9, 0xa, 0x3d, 0x9, 0x9, 0x10, 0xa, 0x5, 0x9, 0x9, 0x3, 0x5, 0x5, 0x3, 0x9, 0x3, 0x9, 0x20, +0x22, 0x5, 0xa, 0xa, 0x9, 0xa, 0x22, 0x20, 0x9, 0x5, 0x9, 0xe, 0xa, 0x12, 0x30, 0x25, 0x9, 0x3d, 0x9, 0x3d, +0x9, 0x3d, 0xa, 0x5, 0x9, 0x3, 0x3, 0x9, 0x9, 0x28, 0x3d, 0x3b, 0x3d, 0x25, 0x3d, 0x3d, 0x5, 0x27, 0x5, 0x6, +0x20, 0x5, 0x5, 0x6, 0x6, 0x6, 0x27, 0x27, 0x28, 0x27, 0x4, 0x4, 0x2a, 0x28, 0x28, 0x2a, 0x0, 0x0, 0x27, 0x2a, +0x2f, 0x2a, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2a, 0x6, 0x2f, 0x27, 0x3d, 0x3d, 0x3d, 0xe, 0xa, 0x3b, 0xd, 0x3d, 0x14, +0x6, 0x10, 0x3d, 0xe, 0x3, 0x3d, 0xa, 0x12, 0x9, 0x3, 0x9, 0x9, 0xa, 0x6, 0xa, 0x30, 0x30, 0x9, 0x10, 0x12, +0xa, 0x3d, 0x6, 0x12, 0x5, 0x20, 0x10, 0x5, 0x5, 0xa, 0x3, 0x9, 0x3, 0x9, 0x3d, 0xa, 0x20, 0x3d, 0x9, 0x3, +0x9, 0x10, 0x20, 0x9, 0xa, 0x9, 0x9, 0x20, 0x20, 0x20, 0x5, 0x3d, 0x9, 0x5, 0x12, 0x20, 0x20, 0x3d, 0xa, 0x3d, +0x20, 0x10, 0x30, 0xc, 0x6, 0x3d, 0x3, 0x9, 0x3d, 0x3d, 0xa, 0x6, 0x3, 0x9, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, +0x25, 0x25, 0xd, 0x3d, 0x9, 0x5, 0x28, 0x5, 0x20, 0x6, 0x5, 0x5, 0x20, 0x31, 0x9, 0x27, 0x28, 0x27, 0x20, 0x33, +0x28, 0x28, 0x27, 0x2f, 0x4, 0x20, 0x2, 0x2f, 0x28, 0x2c, 0x33, 0x2a, 0x28, 0x27, 0x2a, 0x28, 0x6, 0x33, 0x27, 0x3d, +0xd, 0x3d, 0x11, 0x9, 0xd, 0x3d, 0x9, 0x3d, 0x10, 0xd, 0xa, 0x3, 0x3d, 0x14, 0x3, 0x10, 0x5, 0x11, 0x3d, 0xa, +0x9, 0x9, 0xa, 0x25, 0xc, 0xa, 0x3, 0x3d, 0x19, 0x2b, 0x3, 0x5, 0x20, 0x6, 0x9, 0x3, 0x3f, 0x20, 0x12, 0x3d, +0x3d, 0x3d, 0x3d, 0x20, 0x10, 0x3d, 0x3d, 0x3d, 0x3d, 0x5, 0xa, 0x3d, 0x3d, 0x3d, 0x3d, 0x12, 0x6, 0x9, 0x9, 0x3d, +0x9, 0x9, 0x12, 0x6, 0x9, 0x9, 0x3d, 0x9, 0xa, 0x10, 0x2b, 0x3b, 0x9, 0x3d, 0x9, 0x3d, 0x9, 0x3d, 0x5, 0xa, +0x3, 0x9, 0x9, 0x3d, 0x30, 0x3d, 0x3c, 0x25, 0x3d, 0x3b, 0x3d, 0x3d, 0x9, 0x5, 0x3, 0x22, 0x5, 0x5, 0x27, 0x9, +0x20, 0x20, 0x28, 0x3, 0x3d, 0x28, 0x5, 0x6, 0x3d, 0x2a, 0x2a, 0x27, 0x1a, 0x4, 0x27, 0x28, 0x2a, 0x2a, 0x3, 0x33, +0x35, 0x3c, 0x3a, 0x2a, 0x1a, 0x5, 0x2a, 0x25, 0x3d, 0x3d, 0x3d, 0xe, 0x25, 0xc, 0xc, 0x9, 0xa, 0xa, 0x9, 0x14, +0xd, 0x3d, 0x9, 0x12, 0xf, 0x3, 0x3d, 0x3d, 0x3d, 0x12, 0x12, 0x2b, 0x2b, 0x9, 0xd, 0x3d, 0x24, 0x2b, 0x3d, 0x3d, +0x3f, 0x3f, 0x12, 0x9, 0x12, 0x3f, 0x12, 0x25, 0x30, 0xb, 0x3d, 0x5, 0x5, 0x3d, 0x30, 0xc, 0x3b, 0xa, 0x9, 0x3d, +0x25, 0x3d, 0x3d, 0x9, 0x6, 0x9, 0x3d, 0x3d, 0xc, 0x9, 0x20, 0xa, 0x3d, 0x3d, 0xd, 0x9, 0x5, 0xa, 0x17, 0x19, +0x3d, 0x3d, 0x3d, 0x9, 0x3d, 0x3d, 0xa, 0x5, 0x3, 0x25, 0x25, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, +0xa, 0x5, 0x3, 0x12, 0x9, 0x27, 0x9, 0x27, 0x20, 0x6, 0x9, 0x2a, 0x3c, 0x3c, 0x1a, 0x28, 0x2a, 0x3b, 0x3a, 0x25, +0x34, 0x33, 0x28, 0x2a, 0x2a, 0x28, 0x27, 0x20, 0x25, 0x3b, 0x3b, 0x3b, 0x28, 0x2f, 0x2a, 0x3b, 0x25, 0xb, 0x9, 0x3d, +0xc, 0x25, 0x3d, 0x25, 0xe, 0xa, 0x3d, 0x25, 0x3b, 0x3d, 0xd, 0x6, 0x9, 0x30, 0x3d, 0xd, 0x3d, 0xa, 0xa, 0x17, +0x19, 0x3b, 0x3d, 0xa, 0x3d, 0xc, 0x3d, 0x3, 0x30, 0x25, 0x3b, 0x25, 0x3d, 0x25, 0x3d, 0x30, 0xc, 0x3b, 0x3d, 0x20, +0x3, 0x3d, 0x25, 0x25, 0x3d, 0x20, 0xa, 0x3c, 0x25, 0x25, 0x14, 0x6, 0xa, 0x9, 0x3d, 0x3d, 0x3d, 0x3, 0x20, 0x20, +0x3d, 0x3d, 0x3d, 0x3d, 0x10, 0x20, 0x24, 0x19, 0x3, 0x3d, 0x3d, 0x30, 0x3d, 0x3d, 0xa, 0x5, 0x3d, 0x3d, 0x25, 0x3d, +0x3d, 0x3b, 0x3d, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x5, 0xa, 0x28, 0x5, 0x27, 0x28, 0x3, 0x9, 0x20, 0x27, 0x3, 0x2a, +0x3b, 0x28, 0x20, 0x6, 0x3d, 0x25, 0x35, 0x34, 0x1a, 0x27, 0x28, 0x2a, 0x2a, 0x3, 0x28, 0x3d, 0x3b, 0x3a, 0x25, 0x3c, +0x1a, 0x9, 0x3c, 0x3b, 0x25, 0x3d, 0x5, 0xe, 0x25, 0x2b, 0xc, 0x3, 0xf, 0x9, 0xd, 0xc, 0xc, 0x3d, 0x3, 0x10, +0x5, 0x14, 0x3d, 0x3d, 0x3, 0xf, 0x20, 0x24, 0x24, 0x3d, 0xe, 0x5, 0x10, 0x3, 0x3, 0x20, 0x2b, 0xb, 0x25, 0x25, +0x2b, 0x2b, 0x2b, 0x3d, 0x25, 0x9, 0x20, 0x5, 0xa, 0x3d, 0x3d, 0x9, 0x5, 0x20, 0x9, 0x3d, 0x3d, 0x9, 0x10, 0x6, +0x20, 0x3, 0xd, 0x3d, 0xa, 0x12, 0x12, 0x5, 0x9, 0xd, 0x5, 0x12, 0xf, 0x10, 0x19, 0x2b, 0x9, 0x3d, 0x3d, 0x3d, +0x30, 0x3d, 0xa, 0xa, 0x3d, 0x9, 0x3d, 0x3b, 0x3d, 0x3d, 0x3c, 0x3c, 0x25, 0x3d, 0x3d, 0x30, 0xa, 0x6, 0x9, 0x28, +0x5, 0x9, 0x6, 0x20, 0x20, 0x6, 0x3, 0x3d, 0x27, 0x27, 0x4, 0x28, 0x2a, 0x3d, 0x28, 0x33, 0x4, 0x6, 0x28, 0x3, +0x3, 0x1a, 0x20, 0x3b, 0x3d, 0x3b, 0x28, 0x20, 0x27, 0x5, 0x3, 0x3, 0x3, 0x20, 0x20, 0x3d, 0x3d, 0xc, 0x28, 0x20, +0x9, 0xa, 0x3d, 0x3d, 0x3d, 0xa, 0xf, 0x6, 0x5, 0x3d, 0x3b, 0x13, 0x20, 0x20, 0x10, 0x24, 0x19, 0x3d, 0x9, 0x5, +0x6, 0x9, 0x6, 0x3, 0x24, 0x24, 0x24, 0x19, 0x19, 0x24, 0x2b, 0x30, 0x25, 0x3d, 0x12, 0x20, 0x3, 0x3d, 0x30, 0xa, +0x20, 0x5, 0x3, 0x3d, 0x25, 0x3d, 0xa, 0xf, 0x5, 0x3d, 0x3d, 0xd, 0x5, 0x12, 0xa, 0x5, 0x3d, 0x30, 0x9, 0x12, +0x20, 0x20, 0x24, 0x19, 0x3d, 0x3b, 0xd, 0x3d, 0x3d, 0x30, 0x20, 0x27, 0x3d, 0x5, 0x3, 0x3d, 0x25, 0x3d, 0x3c, 0x2d, +0x25, 0x3b, 0x3d, 0x30, 0xa, 0x6, 0x3, 0x3, 0x9, 0x3, 0x5, 0x22, 0x20, 0x27, 0x3d, 0x2a, 0x27, 0x1a, 0x6, 0x28, +0x3c, 0x25, 0x28, 0x1a, 0x20, 0x4, 0x2a, 0x2a, 0x28, 0x20, 0x20, 0x25, 0x3b, 0x3a, 0x28, 0x20, 0x20, 0x27, 0x2a, 0x3d, +0x9, 0x20, 0x5, 0x9, 0x25, 0x25, 0x3d, 0x10, 0xa, 0xa, 0x3d, 0x3d, 0x3d, 0x10, 0x10, 0xa, 0xa, 0x3d, 0x3d, 0x3d, +0x12, 0x10, 0x10, 0x24, 0x24, 0xc, 0x17, 0x17, 0x18, 0x24, 0x18, 0x24, 0x19, 0x24, 0x24, 0x24, 0x2b, 0x2b, 0x19, 0x25, +0x25, 0x3d, 0x20, 0x6, 0x9, 0x25, 0xc, 0x3, 0x20, 0x20, 0x3d, 0x25, 0x25, 0xd, 0x12, 0x10, 0x5, 0x3d, 0x25, 0x3d, +0x5, 0xf, 0x10, 0x9, 0x3, 0xd, 0x3d, 0x10, 0x12, 0x20, 0x19, 0x24, 0x3d, 0x30, 0x3d, 0x3d, 0x3d, 0xc, 0x5, 0x6, +0x3d, 0x3b, 0x3b, 0x25, 0x3d, 0x3b, 0x25, 0x2d, 0x2b, 0x3d, 0x3d, 0x3d, 0xa, 0x1a, 0x28, 0x3d, 0x28, 0x3, 0x5, 0x22, +0x20, 0x27, 0x3c, 0x3c, 0x3, 0x33, 0x6, 0x9, 0x3b, 0x3a, 0x2a, 0x12, 0x20, 0x27, 0x3c, 0x2d, 0x3c, 0x20, 0x20, 0x38, +0x39, 0x2b, 0x3a, 0x20, 0x20, 0x3, 0x3b, 0x25, 0x3d, 0x6, 0x20, 0x3d, 0x25, 0x25, 0x3d, 0x20, 0x6, 0x9, 0xc, 0x25, +0xc, 0xa, 0xa, 0xa, 0x9, 0x9, 0x3d, 0x3d, 0x12, 0x20, 0x20, 0x24, 0x24, 0x3d, 0x17, 0x24, 0x3d, 0x25, 0x25, 0x25, +0x3d, 0x3d, 0x3d, 0x2b, 0xa, 0x9, 0x2b, 0x19, 0x25, 0x30, 0x12, 0x1a, 0x9, 0x25, 0x3b, 0x9, 0x6, 0x5, 0x3d, 0x2b, +0x25, 0x3d, 0xa, 0x5, 0x5, 0x3d, 0xb, 0x3b, 0x20, 0xa, 0x5, 0xe, 0x3d, 0x25, 0x3d, 0xf, 0xa, 0xa, 0x24, 0x24, +0x3d, 0x30, 0x3d, 0x3d, 0x9, 0x3, 0x5, 0xa, 0x3, 0x3d, 0x25, 0x3d, 0x25, 0x25, 0x2b, 0x29, 0x24, 0x3d, 0x3d, 0x3d, +0x6, 0x5, 0x27, 0x3, 0x3d, 0x3, 0x27, 0x20, 0x20, 0x27, 0x3b, 0x2d, 0x2a, 0x1a, 0x6, 0x2a, 0x25, 0x3b, 0x2a, 0x6, +0x1a, 0x5, 0x3, 0x25, 0x2a, 0x20, 0x2a, 0x17, 0x36, 0x3b, 0x3b, 0x1a, 0x6, 0x28, 0x3b, 0x25, 0x3d, 0x6, 0x27, 0x3d, +0x2b, 0x25, 0x3d, 0x20, 0x9, 0xa, 0x25, 0x25, 0x25, 0x10, 0xa, 0x20, 0x3, 0x3d, 0xc, 0x3d, 0xa, 0x5, 0xf, 0x24, +0x18, 0x3d, 0x17, 0x24, 0x25, 0x24, 0x24, 0x2b, 0x2b, 0x19, 0x2b, 0x19, 0x2b, 0x25, 0x2b, 0x21, 0x2b, 0x25, 0x20, 0x5, +0x3d, 0x25, 0x25, 0x25, 0x10, 0xa, 0x3d, 0x19, 0x2b, 0xd, 0x5, 0x10, 0x9, 0x3d, 0x25, 0x25, 0xf, 0xa, 0x10, 0x9, +0x3b, 0xb, 0x3d, 0x5, 0xa, 0x12, 0x18, 0x19, 0x3d, 0x3d, 0x3d, 0x9, 0xa, 0x5, 0x20, 0x6, 0x3d, 0x28, 0x27, 0x28, +0x2f, 0x28, 0x25, 0x2b, 0x24, 0x3, 0x3, 0x3c, 0x27, 0x1a, 0x3, 0x3d, 0x3c, 0x3d, 0x28, 0x1a, 0x6, 0x3, 0x25, 0x25, +0x3b, 0x6, 0x5, 0x3d, 0x2b, 0x25, 0x2a, 0x1f, 0x6, 0x28, 0x3c, 0x3c, 0x25, 0x4, 0x20, 0x2d, 0x37, 0x25, 0x3c, 0x1a, +0x27, 0x3, 0x25, 0x25, 0x25, 0x5, 0xa, 0x3, 0x2b, 0x25, 0x3d, 0x5, 0x6, 0x3, 0x3b, 0x2b, 0xb, 0x9, 0x5, 0xa, +0xa, 0x3b, 0x25, 0x3d, 0x20, 0x6, 0x22, 0x24, 0x24, 0x3d, 0x24, 0x17, 0x25, 0x18, 0x2b, 0x3d, 0x2b, 0x30, 0x2b, 0x3, +0xa, 0x9, 0x2b, 0x17, 0x24, 0x3d, 0x20, 0x5, 0x3, 0x25, 0x2b, 0x30, 0x20, 0x9, 0x3b, 0x2b, 0x25, 0x25, 0x20, 0xa, +0x3, 0x25, 0xb, 0x25, 0xa, 0xa, 0x5, 0x13, 0x2b, 0x30, 0xc, 0xa, 0x6, 0xa, 0x24, 0x24, 0x3d, 0x3, 0xa, 0xa, +0x6, 0x6, 0x20, 0x20, 0x28, 0x4, 0x27, 0x28, 0x3d, 0x1c, 0x24, 0x24, 0x2b, 0x28, 0x27, 0x3d, 0x27, 0x5, 0x6, 0x3, +0x3c, 0x3d, 0x3, 0x20, 0x6, 0x3, 0x25, 0x2d, 0x3a, 0x20, 0x28, 0x3d, 0x29, 0x3b, 0x3a, 0x4, 0x4, 0x28, 0x3c, 0x3b, +0x25, 0x1a, 0x6, 0x3c, 0x29, 0x37, 0x3c, 0x20, 0xa, 0x3d, 0x2d, 0x25, 0x25, 0x5, 0x3, 0x3d, 0x24, 0x25, 0x25, 0x20, +0x6, 0x3, 0x25, 0xb, 0x25, 0x9, 0x10, 0x9, 0xa, 0x2b, 0xc, 0x2a, 0xa, 0x5, 0x6, 0x18, 0x24, 0x3d, 0x19, 0x17, +0x17, 0x30, 0x2b, 0x19, 0x8, 0x2b, 0x19, 0x25, 0x25, 0x3d, 0x17, 0x2b, 0x24, 0x25, 0x6, 0x9, 0x3, 0x25, 0x25, 0x3d, +0x20, 0x3, 0x3b, 0x24, 0x25, 0xc, 0x20, 0xa, 0x9, 0xb, 0x25, 0x25, 0x3d, 0x10, 0x9, 0x3d, 0x3d, 0xb, 0x3d, 0x9, +0x10, 0x5, 0x18, 0x19, 0x3d, 0x9, 0x5, 0x5, 0x20, 0x12, 0x22, 0x28, 0x27, 0x27, 0x28, 0x27, 0x1c, 0x8, 0x24, 0x23, +0x24, 0x2f, 0x27, 0x28, 0x1a, 0x5, 0x6, 0x25, 0x3b, 0x3d, 0x3, 0x20, 0x6, 0x28, 0x25, 0x2b, 0x3c, 0x20, 0x28, 0x3b, +0x24, 0x25, 0x2a, 0x1d, 0x27, 0x27, 0x3b, 0x3b, 0x3c, 0x28, 0x20, 0x21, 0x24, 0x24, 0x38, 0x20, 0x28, 0x3d, 0x25, 0x2b, +0x25, 0x20, 0x9, 0x30, 0x19, 0x25, 0x25, 0x6, 0x5, 0x3, 0x25, 0x25, 0x25, 0x3d, 0x20, 0x9, 0x3, 0x30, 0x25, 0xc, +0x5, 0x20, 0x5, 0x24, 0x24, 0x3d, 0x24, 0x17, 0x3d, 0x12, 0x3, 0x24, 0x19, 0x3d, 0x3b, 0x2b, 0x3d, 0x3d, 0x17, 0x21, +0x24, 0x2b, 0x6, 0x9, 0x3, 0x2b, 0x25, 0x25, 0xa, 0x9, 0x3d, 0x19, 0x2b, 0x3b, 0x5, 0xa, 0x3, 0x30, 0xb, 0x25, +0x5, 0xa, 0xa, 0x9, 0xb, 0x25, 0x25, 0x20, 0xa, 0x10, 0x24, 0x24, 0x3d, 0x9, 0x27, 0x20, 0x22, 0x3f, 0x12, 0x27, +0x27, 0x27, 0x27, 0x28, 0x3d, 0x17, 0x24, 0x23, 0x24, 0x2a, 0x1b, 0x3d, 0x3d, 0x27, 0x5, 0x3c, 0x3b, 0x3c, 0x3d, 0x20, +0x5, 0x3, 0x25, 0x2b, 0x25, 0x4, 0x28, 0x3c, 0x24, 0x3b, 0x2a, 0x27, 0x6, 0x28, 0x3c, 0x3b, 0x3a, 0xa, 0x5, 0x26, +0x24, 0x26, 0x25, 0x27, 0x28, 0x28, 0x2b, 0x2b, 0x25, 0xa, 0x3, 0x30, 0x24, 0x25, 0x3d, 0x9, 0x28, 0x3, 0x30, 0x25, +0x2b, 0xa, 0xa, 0xa, 0x3, 0x25, 0x25, 0x3b, 0x20, 0x6, 0x20, 0x24, 0x24, 0x3, 0x17, 0x17, 0x2b, 0x2b, 0x2b, 0x19, +0x24, 0x25, 0x25, 0x2b, 0x25, 0x3c, 0x16, 0x17, 0x24, 0x2b, 0xa, 0x28, 0x3b, 0x2b, 0x2b, 0x25, 0xa, 0x3, 0x3b, 0x24, +0x19, 0x30, 0xf, 0x9, 0x9, 0x3d, 0x25, 0xc, 0x3d, 0xf, 0x3, 0x3d, 0x25, 0x25, 0xc, 0x9, 0xf, 0x5, 0x18, 0x24, +0x3d, 0x9, 0x5, 0x20, 0x12, 0x22, 0x12, 0x27, 0x27, 0x27, 0x28, 0x28, 0x3d, 0x16, 0x18, 0x24, 0x24, 0x3b, 0x3, 0x3, +0x3d, 0x5, 0x27, 0x3b, 0x3b, 0x3c, 0x3, 0x20, 0x5, 0x28, 0x25, 0x24, 0x2d, 0x5, 0x3, 0x3c, 0x24, 0x2b, 0x25, 0x1a, +0x28, 0x3, 0x3b, 0x3a, 0x3c, 0x27, 0x1a, 0x16, 0x17, 0x21, 0x2b, 0x1d, 0x9, 0x3d, 0x2b, 0x17, 0x2b, 0x9, 0x3, 0x3d, +0x18, 0x25, 0x25, 0x6, 0x3, 0x9, 0x3b, 0xb, 0x25, 0x9, 0x6, 0x3, 0x3, 0x30, 0x25, 0xc, 0x6, 0x6, 0x5, 0x17, +0x24, 0x3d, 0x3e, 0x17, 0x24, 0x17, 0x2b, 0x18, 0x16, 0x25, 0x3e, 0x21, 0x25, 0x3d, 0x17, 0x16, 0x17, 0x2b, 0x6, 0x9, +0x3, 0x25, 0x25, 0x2b, 0xa, 0x27, 0x3d, 0x2b, 0x2b, 0x25, 0x5, 0x5, 0x9, 0x3d, 0x2b, 0x25, 0x9, 0xa, 0x9, 0x9, +0xc, 0x2b, 0x3d, 0xa, 0xa, 0x6, 0x24, 0x19, 0x3d, 0x3, 0x5, 0x12, 0x22, 0x3f, 0x22, 0x5, 0x4, 0x28, 0x3, 0x3d, +0x2a, 0x17, 0x26, 0x24, 0x26, 0x3c, 0x9, 0x6, 0xa, 0x27, 0x5, 0x25, 0x3c, 0x25, 0x9, 0x6, 0x27, 0x3, 0x2b, 0x24, +0x25, 0x1d, 0x28, 0x3d, 0x2b, 0x2d, 0x3b, 0x27, 0x28, 0x27, 0x3d, 0x3b, 0x3b, 0x27, 0x6, 0x17, 0x26, 0x17, 0x2b, 0x5, +0x28, 0x3, 0x24, 0x24, 0x19, 0x9, 0x3d, 0x30, 0x19, 0x24, 0x25, 0xa, 0x27, 0x3, 0x3b, 0x2b, 0x25, 0x3, 0xa, 0x9, +0x3d, 0x25, 0x25, 0x30, 0x6, 0xa, 0x1a, 0x19, 0x24, 0x3d, 0x2b, 0x17, 0x3d, 0x9, 0x3d, 0x24, 0x17, 0x9, 0x24, 0x25, +0x9, 0x2b, 0x17, 0x23, 0x17, 0x25, 0xa, 0x27, 0x3d, 0x2b, 0x24, 0x2b, 0x6, 0xa, 0x25, 0x2b, 0x2b, 0x25, 0x9, 0x9, +0x3, 0x3d, 0xb, 0x25, 0xa, 0xa, 0x9, 0x3, 0x3b, 0x25, 0x3d, 0xa, 0x20, 0x10, 0x18, 0x24, 0xd, 0x28, 0x5, 0x20, +0x12, 0x22, 0x12, 0x5, 0x4, 0x27, 0x27, 0x28, 0x28, 0x24, 0x24, 0x21, 0x24, 0x3, 0x3d, 0x3d, 0x4, 0x27, 0x27, 0x3b, +0x3d, 0x3c, 0x3d, 0x1a, 0x5, 0x3, 0x2d, 0x24, 0x24, 0x6, 0x27, 0x3d, 0x2b, 0x2b, 0x25, 0x2f, 0x27, 0x27, 0x2a, 0x25, +0x3b, 0x6, 0x5, 0x21, 0x16, 0x17, 0x2d, 0x5, 0x28, 0x3, 0x24, 0x24, 0x2b, 0x5, 0x3, 0x3d, 0x2b, 0x2b, 0x25, 0xa, +0x9, 0x3, 0x3b, 0x2b, 0x2b, 0xa, 0x5, 0x6, 0x3, 0x3d, 0x25, 0x3d, 0xa, 0x6, 0x27, 0x21, 0x24, 0x3b, 0x2b, 0x17, +0x2b, 0x2b, 0x25, 0x3, 0x2b, 0x2b, 0x25, 0x2b, 0x2b, 0x24, 0x24, 0x17, 0x17, 0x25, 0x20, 0x9, 0x3, 0x25, 0x25, 0x2b, +0x20, 0x3b, 0x3d, 0x24, 0x2b, 0x25, 0x20, 0x5, 0x9, 0x30, 0x3d, 0x3d, 0xa, 0x5, 0x9, 0x9, 0xc, 0x25, 0x3d, 0xa, +0x6, 0x6, 0x24, 0x24, 0x9, 0x3, 0x6, 0x20, 0x22, 0x12, 0x22, 0x28, 0x5, 0x4, 0x28, 0x2a, 0x2a, 0x24, 0x21, 0x2b, +0x24, 0x3d, 0x3b, 0x3d, 0xa, 0x5, 0x6, 0x3c, 0x3c, 0x3c, 0x28, 0x20, 0x5, 0x28, 0x25, 0x24, 0x25, 0x1a, 0x9, 0x2a, +0x2b, 0x2b, 0x2a, 0x5, 0x5, 0x27, 0x3d, 0x3c, 0x3d, 0x5, 0x1d, 0x24, 0x24, 0x24, 0x25, 0x20, 0x28, 0x3d, 0x2b, 0x24, +0x19, 0x9, 0x9, 0x30, 0x24, 0x25, 0x25, 0x20, 0x3, 0x3d, 0x3d, 0x25, 0x3d, 0xa, 0x6, 0x9, 0x3, 0x2b, 0x25, 0x3d, +0x5, 0x20, 0x5, 0x17, 0x24, 0x3, 0x24, 0x24, 0x25, 0x19, 0x24, 0x3d, 0x3d, 0x2b, 0x2b, 0x2b, 0x25, 0x25, 0x24, 0x17, +0x24, 0x25, 0x6, 0x28, 0xa, 0x25, 0x25, 0x3b, 0x5, 0x3d, 0x3d, 0x2b, 0x25, 0x9, 0x5, 0xa, 0x28, 0x3d, 0x25, 0x25, +0xe, 0x5, 0x5, 0x3d, 0x25, 0x25, 0xd, 0x5, 0x6, 0x20, 0x19, 0x24, 0x3d, 0x3, 0xa, 0x1a, 0x20, 0x20, 0x22, 0x3, +0x27, 0x27, 0x27, 0x28, 0x3d, 0x24, 0x24, 0x24, 0x29, 0x3d, 0x3d, 0x25, 0x10, 0x6, 0x5, 0x3c, 0x3c, 0x3d, 0x3, 0x20, +0xa, 0x27, 0x3b, 0x3b, 0x3b, 0x20, 0x5, 0x3c, 0x2b, 0x25, 0x28, 0x20, 0x5, 0x27, 0x3c, 0x3c, 0x3a, 0x27, 0x6, 0x24, +0x26, 0x24, 0x2b, 0x20, 0x28, 0x2a, 0x25, 0x2b, 0x2b, 0x3, 0x5, 0x3c, 0x19, 0x25, 0x3, 0x5, 0x27, 0x3, 0x30, 0x25, +0x25, 0x9, 0x6, 0x6, 0x3d, 0x3c, 0x25, 0x3b, 0xa, 0x1a, 0x6, 0x24, 0x17, 0x3, 0x17, 0x2b, 0x5, 0x3, 0x9, 0x28, +0x3, 0x9, 0x9, 0x2a, 0x27, 0x9, 0x24, 0x24, 0x24, 0x2b, 0x6, 0x27, 0x28, 0x3b, 0x25, 0x3d, 0x20, 0x5, 0x3d, 0x25, +0x3c, 0x3d, 0x20, 0x6, 0x9, 0x3d, 0x25, 0x3d, 0x9, 0x20, 0x20, 0x5, 0x3d, 0x25, 0x3d, 0x20, 0x20, 0x20, 0x24, 0x18, +0x3, 0x3, 0x27, 0x5, 0x6, 0x6, 0x20, 0x20, 0x28, 0x27, 0x4, 0x27, 0x3, 0x3a, 0x2b, 0x2b, 0x2b, 0x3d, 0x25, 0x3d, +0xa, 0x6, 0x5, 0x3d, 0x3d, 0x3c, 0x28, 0x20, 0x6, 0x5, 0x3b, 0x3b, 0x3d, 0x1d, 0x5, 0x3c, 0x29, 0x3b, 0x2a, 0x20, +0x6, 0x27, 0x3a, 0x3b, 0x3d, 0x5, 0x1a, 0x24, 0x26, 0x24, 0x3b, 0x4, 0x5, 0x28, 0x2b, 0x24, 0x30, 0x20, 0x3d, 0x3d, +0x24, 0x25, 0x3d, 0x3, 0x5, 0x3d, 0x3d, 0x25, 0x3d, 0xa, 0x20, 0x6, 0x3, 0x3b, 0x3b, 0x3d, 0x5, 0x6, 0x28, 0x24, +0x24, 0x3d, 0x17, 0x25, 0x3d, 0x25, 0x25, 0x25, 0x3d, 0x3b, 0x3d, 0x3d, 0x3d, 0x3d, 0x30, 0x24, 0x19, 0x3b, 0x6, 0x20, +0x3d, 0x25, 0x25, 0x3d, 0x20, 0x5, 0x3, 0x25, 0x3b, 0x9, 0x6, 0x20, 0xa, 0x3d, 0x25, 0x25, 0x9, 0xf, 0x6, 0xa, +0x30, 0x3d, 0x3d, 0x20, 0x5, 0x20, 0x19, 0x2b, 0x3d, 0x3, 0x28, 0x27, 0x3, 0x5, 0x20, 0x20, 0x3d, 0x2a, 0x28, 0x27, +0x2a, 0x3d, 0x25, 0x2b, 0x2b, 0x3d, 0x3d, 0x30, 0xa, 0xa, 0x27, 0x9, 0x2a, 0x28, 0x5, 0x20, 0x20, 0x28, 0x25, 0x3a, +0x2a, 0x6, 0x2f, 0x3c, 0x2b, 0x3b, 0x2a, 0x6, 0x20, 0x27, 0x3c, 0x3b, 0x25, 0x28, 0x20, 0x3b, 0x24, 0x2b, 0x3c, 0x6, +0x1a, 0x3c, 0x2b, 0x2b, 0x3b, 0x20, 0x6, 0x3b, 0x2b, 0x30, 0x3d, 0x5, 0x5, 0x28, 0x3b, 0x25, 0x25, 0x5, 0x20, 0x4, +0x28, 0x2b, 0x3d, 0x3d, 0x20, 0x4, 0x28, 0x24, 0x24, 0x3b, 0x21, 0x24, 0x25, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x24, +0x25, 0x25, 0x2b, 0x24, 0x25, 0x3d, 0x20, 0x20, 0x3, 0x3b, 0x3b, 0x3d, 0x20, 0x6, 0x3d, 0x3b, 0x3d, 0x3, 0x20, 0x6, +0x5, 0x3c, 0x3b, 0x3d, 0x5, 0x20, 0x6, 0x5, 0x3d, 0x3d, 0x3d, 0x20, 0x20, 0x12, 0x24, 0x24, 0x3, 0x3d, 0x3d, 0x28, +0x28, 0x3, 0x6, 0x5, 0x3d, 0x3b, 0x3b, 0x25, 0x25, 0x3c, 0x2d, 0x2d, 0x25, 0x3d, 0x3b, 0x3d, 0xa, 0xa, 0x28, 0x3, +0x3d, 0x3, 0x5, 0x22, 0x20, 0x27, 0x3d, 0x3c, 0x3a, 0x1a, 0x6, 0x2a, 0x25, 0x2a, 0x28, 0x1e, 0x2, 0x27, 0x3c, 0x2a, +0x3c, 0x1d, 0x4, 0x2b, 0x24, 0x2b, 0x3c, 0x1a, 0x4, 0x2a, 0x2b, 0x2b, 0x25, 0x6, 0x4, 0x3c, 0x2b, 0x25, 0x3d, 0x6, +0x6, 0x27, 0x3b, 0x25, 0x25, 0x6, 0x27, 0x4, 0x2a, 0x3c, 0x3d, 0x3d, 0x20, 0x6, 0x4, 0x24, 0x24, 0x3c, 0x24, 0x24, +0x17, 0x24, 0x24, 0x17, 0x24, 0x24, 0x17, 0x24, 0x2b, 0x2b, 0x2b, 0x25, 0x25, 0x3c, 0x20, 0x5, 0x2a, 0x3d, 0x3d, 0x9, +0x20, 0x27, 0x9, 0x25, 0x25, 0x3d, 0x20, 0x6, 0x9, 0x3d, 0x25, 0x3d, 0x20, 0x5, 0x6, 0xa, 0x9, 0x3b, 0x3d, 0x20, +0x20, 0x20, 0x24, 0x19, 0x9, 0x3, 0x28, 0x3d, 0x3, 0x3d, 0x5, 0x27, 0x3b, 0x24, 0x24, 0x3b, 0x25, 0x3b, 0x25, 0x2b, +0x3b, 0x3d, 0x3b, 0x3d, 0xa, 0x5, 0xa, 0x28, 0x28, 0x27, 0x5, 0x6, 0x20, 0x27, 0x3a, 0x39, 0x27, 0x20, 0x6, 0x2a, +0x25, 0x2a, 0x3d, 0x31, 0x6, 0x5, 0x2a, 0x3c, 0x2a, 0x6, 0x20, 0x2b, 0x2b, 0x25, 0x3a, 0x27, 0x27, 0x3, 0x3b, 0x25, +0x3d, 0x28, 0x6, 0x3, 0x25, 0x25, 0x3b, 0x20, 0x3c, 0x3b, 0x25, 0x2b, 0x3d, 0x5, 0x3, 0x27, 0x3, 0x3b, 0x3d, 0x3d, +0x31, 0x6, 0x20, 0x17, 0x24, 0x3, 0x24, 0x24, 0x25, 0x24, 0x2b, 0x2b, 0x2b, 0x25, 0x24, 0x24, 0x2b, 0x2b, 0x24, 0x3b, +0x25, 0x3d, 0x6, 0x6, 0x3, 0x3d, 0x3d, 0x3b, 0x5, 0x20, 0x28, 0x25, 0x3c, 0x3d, 0x20, 0x6, 0x4, 0x3, 0x30, 0x30, +0x20, 0x20, 0x12, 0x5, 0x3d, 0x3d, 0x3d, 0x10, 0x22, 0x10, 0x24, 0x2b, 0x3, 0x3, 0x28, 0x2a, 0x2a, 0x2a, 0x5, 0x4, +0x3c, 0x2a, 0x3a, 0x3a, 0x3a, 0x25, 0x3b, 0x25, 0x3b, 0x3d, 0x3d, 0x3d, 0xa, 0x27, 0x5, 0x3d, 0x27, 0x28, 0x5, 0x22, +0x22, 0x27, 0x3, 0x2a, 0x2a, 0x22, 0x6, 0x28, 0x3a, 0x2a, 0x35, 0x1a, 0x6, 0x1a, 0x3, 0x2a, 0x3c, 0x1a, 0x2f, 0x2b, +0x25, 0x2b, 0x3c, 0x33, 0x33, 0x2a, 0x3b, 0x25, 0x3c, 0x20, 0x28, 0x3c, 0x3b, 0x3c, 0x3d, 0x1d, 0x6, 0x28, 0x3b, 0x3b, +0x3d, 0x6, 0x20, 0x4, 0x3, 0x2a, 0x3c, 0x3c, 0x6, 0x33, 0x6, 0x24, 0x2b, 0x3d, 0x3c, 0x3b, 0x27, 0x3, 0x3, 0x3, +0x5, 0x3, 0x2b, 0x25, 0x25, 0x25, 0x30, 0x3b, 0x25, 0x3, 0x20, 0x6, 0x5, 0x30, 0x3d, 0x3, 0x20, 0x20, 0x5, 0x3, +0x3d, 0x3d, 0x20, 0x20, 0x6, 0x3d, 0x3, 0x9, 0x20, 0x20, 0x20, 0x9, 0x28, 0x3d, 0x20, 0x20, 0x6, 0x12, 0x24, 0x2b, +0x3d, 0x3, 0x28, 0x28, 0x28, 0x2a, 0x5, 0x27, 0x2a, 0x27, 0x27, 0x2a, 0x3b, 0x2d, 0x3b, 0x25, 0x2a, 0x3c, 0x3d, 0x30, +0xa, 0x5, 0x9, 0x27, 0x27, 0x28, 0x5, 0x22, 0x20, 0x4, 0x2a, 0x28, 0x27, 0x20, 0x31, 0x27, 0x2a, 0x3c, 0x27, 0x1a, +0x20, 0x20, 0x28, 0x3d, 0x28, 0x6, 0x2f, 0x25, 0x3b, 0x2b, 0x3b, 0x33, 0x27, 0x27, 0x3b, 0x3b, 0x3b, 0x31, 0x2f, 0x3c, +0x3b, 0x3b, 0x2a, 0x33, 0x6, 0x9, 0x3c, 0x3d, 0x28, 0x5, 0x28, 0x6, 0x3, 0x30, 0x3b, 0x27, 0x4, 0x6, 0x2f, 0x2b, +0x24, 0x3d, 0x2a, 0x3d, 0x3d, 0x3, 0x27, 0x5, 0x28, 0x9, 0x2b, 0x2b, 0x25, 0x25, 0x25, 0x3, 0x3b, 0x3d, 0x9, 0x22, +0x5, 0x3d, 0x3, 0x3, 0x5, 0x6, 0x9, 0x3b, 0x3d, 0x9, 0x20, 0x20, 0x3, 0x3b, 0x3d, 0x3d, 0x6, 0x6, 0x12, 0x3, +0x3d, 0x3d, 0x3, 0x12, 0xf, 0x20, 0x24, 0x19, 0x3d, 0x27, 0x28, 0x28, 0x2a, 0x3a, 0x27, 0x27, 0x25, 0x2a, 0x28, 0x27, +0x3a, 0x25, 0x25, 0x25, 0x3b, 0x3d, 0x25, 0x25, 0x20, 0xa, 0x3, 0x27, 0x6, 0x28, 0x6, 0x20, 0x22, 0x5, 0x2a, 0x28, +0x27, 0x20, 0x1a, 0x27, 0x3d, 0x2a, 0x28, 0x1a, 0x22, 0x6, 0x27, 0x28, 0x2a, 0x1a, 0x6, 0x3b, 0x3c, 0x2b, 0x3c, 0x27, +0x20, 0x27, 0x25, 0x3c, 0x3a, 0x28, 0x28, 0x39, 0x25, 0x3b, 0x3d, 0x4, 0x1d, 0x28, 0x30, 0x3d, 0x3c, 0x2a, 0x4, 0x6, +0x27, 0x3, 0x3, 0xa, 0x2a, 0x20, 0x20, 0x2b, 0x24, 0x3d, 0x28, 0x9, 0x28, 0x9, 0x6, 0x28, 0x9, 0x28, 0x25, 0x3c, +0x3c, 0x3d, 0x25, 0x3b, 0x3c, 0x25, 0x3d, 0x6, 0x3, 0x3d, 0x3b, 0x3d, 0x3d, 0x20, 0x27, 0x25, 0x25, 0x30, 0x3, 0x20, +0x5, 0x9, 0x3d, 0x3d, 0x3d, 0x27, 0x6, 0x6, 0x3d, 0x25, 0x3d, 0x9, 0x20, 0x9, 0x24, 0x24, 0x3d, 0x27, 0x27, 0x2a, +0x28, 0x2a, 0x4, 0x4, 0x2a, 0x2a, 0x3a, 0x3b, 0x25, 0x25, 0x35, 0x3b, 0x3a, 0x3b, 0x3b, 0x3d, 0x5, 0x9, 0x28, 0x3, +0x28, 0x28, 0x9, 0x27, 0x22, 0x28, 0x3a, 0x39, 0x3a, 0x28, 0x4, 0x5, 0x3a, 0x3b, 0x2a, 0x27, 0x4, 0x6, 0x28, 0x2a, +0x2a, 0x2a, 0x2, 0x3b, 0x25, 0x3c, 0x3b, 0x3b, 0x1f, 0x3, 0x3a, 0x25, 0x3b, 0x3b, 0x1a, 0x28, 0x3b, 0x25, 0x3b, 0x3d, +0x6, 0x3, 0x3c, 0x3b, 0x3c, 0x3c, 0x28, 0x20, 0x27, 0x2a, 0x3d, 0x28, 0x27, 0x20, 0x20, 0x24, 0x2d, 0x27, 0x3d, 0x27, +0x20, 0x20, 0x9, 0x3c, 0xa, 0x20, 0x27, 0x27, 0x27, 0x9, 0x27, 0x3, 0x9, 0x3d, 0x3, 0x6, 0x5, 0x27, 0x9, 0x3, +0x3, 0x20, 0x6, 0x3d, 0x3d, 0x3d, 0x9, 0x20, 0x5, 0x2a, 0x9, 0x3, 0x3d, 0x9, 0x20, 0x5, 0xa, 0x9, 0x3, 0x3, +0x20, 0x6, 0x19, 0x25, 0x9, 0x27, 0x27, 0x28, 0x28, 0x2a, 0x27, 0x27, 0x3a, 0x1b, 0x3, 0x2a, 0x2a, 0x2a, 0x3a, 0x3b, +0x2a, 0x3d, 0x25, 0x25, 0xa, 0x27, 0x5, 0x5, 0x27, 0x5, 0x27, 0x27, 0x6, 0x5, 0x27, 0x3, 0x3a, 0x2a, 0x1a, 0x6, +0x2a, 0x3d, 0x2a, 0x27, 0x2f, 0x1a, 0x27, 0x27, 0x28, 0x2a, 0x28, 0x28, 0x3a, 0x2a, 0x3b, 0x2a, 0x28, 0x1, 0x2a, 0x3b, +0x3a, 0x3b, 0x27, 0x28, 0x3c, 0x3b, 0x30, 0x28, 0x27, 0x20, 0x28, 0x3, 0x3d, 0x3c, 0x27, 0x22, 0x6, 0x28, 0x3d, 0x3, +0x9, 0x20, 0x22, 0x3d, 0x3a, 0x27, 0x3c, 0x27, 0x1a, 0x6, 0x3b, 0x3d, 0x6, 0x6, 0x3f, 0x3f, 0x12, 0x20, 0x3f, 0x3, +0x3, 0x3, 0x28, 0x12, 0x20, 0x27, 0x3d, 0x3b, 0x3, 0x20, 0x6, 0x9, 0x9, 0x3, 0x3, 0x20, 0x6, 0x5, 0x3, 0x3c, +0x3, 0x9, 0x12, 0x5, 0x3d, 0x3d, 0x3, 0xa, 0x20, 0x20, 0x30, 0xc, 0x5, 0x28, 0x3, 0x28, 0x28, 0x28, 0x4, 0x20, +0x28, 0x27, 0x27, 0x28, 0x27, 0x28, 0x3d, 0x2a, 0x2a, 0x3d, 0x3d, 0x3b, 0xa, 0x5, 0x28, 0x20, 0x5, 0x27, 0x5, 0x6, +0x33, 0x6, 0x27, 0x28, 0x28, 0x27, 0x20, 0x2f, 0x28, 0x28, 0x27, 0x28, 0x33, 0x6, 0x2, 0x2a, 0x28, 0x27, 0x4, 0x31, +0x2a, 0x3c, 0x2a, 0x3b, 0x2, 0x2a, 0x3a, 0x3c, 0x3b, 0x3c, 0x1d, 0x4, 0x3c, 0x28, 0x3d, 0x3c, 0x6, 0x28, 0x3, 0x27, +0x3, 0x2a, 0x27, 0x33, 0x27, 0x9, 0x28, 0x30, 0x28, 0x20, 0x22, 0x3b, 0x3b, 0x6, 0x2b, 0x3d, 0x6, 0x20, 0x28, 0x6, +0x9, 0x6, 0x3f, 0x20, 0x28, 0x28, 0xa, 0x27, 0x28, 0x9, 0x27, 0x20, 0x22, 0xa, 0x27, 0x3, 0x28, 0x20, 0x6, 0x28, +0x9, 0x25, 0x5, 0x20, 0x22, 0x5, 0x9, 0x5, 0x3, 0x20, 0x6, 0x5, 0x3, 0x5, 0x3d, 0x5, 0x6, 0x20, 0x25, 0x25, +0xa, 0x28, 0x27, 0x3d, 0x28, 0x2a, 0x5, 0x1a, 0x5, 0x1a, 0x6, 0x1a, 0x22, 0x20, 0x28, 0x2a, 0x27, 0x3c, 0x3d, 0x25, +0x5, 0x5, 0x3, 0x5, 0x27, 0x6, 0x6, 0x5, 0x20, 0x20, 0x6, 0x27, 0x28, 0x28, 0x1e, 0x6, 0x3, 0x28, 0x2a, 0x2, +0x20, 0x32, 0x28, 0x28, 0x27, 0x28, 0x2f, 0x28, 0x2a, 0x2a, 0x3a, 0x35, 0x3b, 0x33, 0x39, 0x2a, 0x3c, 0x2a, 0x3, 0x4, +0x3c, 0x3, 0x3b, 0x3, 0x4, 0x33, 0x3, 0x2a, 0x27, 0x3b, 0x28, 0x20, 0x6, 0x28, 0x28, 0x2a, 0x27, 0x6, 0x20, 0x3c, +0x3c, 0x28, 0x25, 0x3, 0x6, 0x20, 0x3f, 0x20, 0x3, 0x3f, 0x20, 0x3f, 0x20, 0x6, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x22, 0x20, 0x20, 0x5, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6, 0x20, 0x20, 0x3f, 0x27, 0x20, 0x27, 0x5, 0x6, 0x3f, 0x6, +0x5, 0x9, 0x20, 0x12, 0x6, 0x3f, 0x9, 0x3, 0x5, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, +0x2a, 0x27, 0x28, 0x3c, 0x27, 0x3c, 0x3d, 0x25, 0xa, 0x5, 0x3, 0x20, 0x20, 0x6, 0x4, 0x6, 0x22, 0x31, 0x20, 0x20, +0x2f, 0x6, 0x20, 0x20, 0x1a, 0x4, 0x1f, 0x6, 0x1a, 0x3f, 0x33, 0x6, 0x2, 0x2f, 0x2, 0x2a, 0x4, 0x33, 0x0, 0x28, +0x0, 0x27, 0x2f, 0x3b, 0x27, 0x2f, 0x2f, 0x4, 0x2a, 0x2a, 0x2a, 0x27, 0x6, 0x33, 0x6, 0x20, 0x4, 0x1a, 0x4, 0x3f, +0x22, 0x6, 0x28, 0x27, 0x4, 0x20, 0x3f, 0x1a, 0x3, 0x27, 0x27, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x31, 0x22, 0x31, 0x3f, +0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x22, 0x3f, 0x3f, 0x31, 0x3f, 0x3f, 0x3f, 0x3f, +0x3f, 0x3f, 0x3f, 0x3f, 0x20, 0x20, 0x20, 0x6, 0x6, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x12, 0x20, 0x20, 0x27, 0x27, 0x4, +0x27, 0x27, 0x27, 0x28, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x3c, 0x25, 0x3b, 0xa, 0x6, 0x28, 0x27, +0x3, 0x3, 0x3, 0x28, 0x3d, 0x2a, 0x2a, 0x3, 0x3d, 0x28, 0x3c, 0x38, 0x2a, 0x3c, 0x3a, 0x38, 0x3b, 0x29, 0x2d, 0x3, +0x25, 0x39, 0x3a, 0x2a, 0x38, 0x28, 0x2a, 0x3b, 0x3, 0x2a, 0x30, 0x30, 0x27, 0x28, 0x3, 0x3c, 0x28, 0x28, 0x27, 0x4, +0x28, 0x3b, 0x3, 0x3c, 0x3, 0x3c, 0x3d, 0x5, 0x3d, 0x3d, 0x25, 0x30, 0x3b, 0x28, 0x3d, 0x3d, 0x25, 0x3b, 0x3b, 0x3, +0x3, 0x3, 0x3, 0x3, 0x28, 0x5, 0xa, 0x27, 0x28, 0x9, 0x3, 0x28, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, 0x3d, 0x28, +0x9, 0x3, 0x3d, 0x3d, 0x28, 0x28, 0x28, 0x28, 0x3, 0x9, 0x28, 0x9, 0x9, 0x3, 0x9, 0x3, 0x9, 0x3, 0xa, 0x9, +0x3, 0x9, 0x3, 0x9, 0x5, 0x5, 0x6, 0x27, 0x27, 0x28, 0x3, 0x27, 0x1b, 0x28, 0x28, 0x28, 0x1b, 0x27, 0x28, 0x28, +0x3c, 0x3d, 0x2a, 0x3c, 0x5, 0x5, 0x9, 0x20, 0x6, 0x20, 0x6, 0x5, 0x5, 0x28, 0x3, 0x2a, 0x3, 0x39, 0x3, 0x2a, +0x2a, 0x28, 0x27, 0x3c, 0x3a, 0x38, 0x3a, 0x2d, 0x2d, 0x27, 0x2d, 0x39, 0x2a, 0x2a, 0x1, 0x38, 0x2a, 0x39, 0x3c, 0x3c, +0x28, 0x3c, 0x3c, 0x30, 0x25, 0x2b, 0x25, 0x24, 0x3b, 0x2a, 0x3d, 0x24, 0x3b, 0x24, 0x25, 0x3c, 0x2b, 0x25, 0x25, 0x25, +0x2b, 0x2b, 0x2b, 0x2b, 0x25, 0x2b, 0x2b, 0x2b, 0x2b, 0x24, 0x3b, 0x25, 0x3d, 0x2a, 0x28, 0x3d, 0x25, 0x3d, 0x3c, 0x3c, +0x3b, 0x3b, 0x3b, 0x2b, 0x3b, 0x3b, 0x25, 0x3d, 0x3b, 0x3b, 0x25, 0x3b, 0x25, 0x25, 0x25, 0x3b, 0x25, 0x3d, 0x3c, 0x25, +0x30, 0x25, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0x3, 0x3d, 0x3d, 0x3d, 0x6, 0x6, 0x4, 0x27, 0x27, 0x28, 0x4, +0x2c, 0x27, 0x28, 0x27, 0x2a, 0x3, 0x28, 0x3d, 0x28, 0x3d, 0x2a, 0x3c, 0x5, 0x6, 0x3, 0x20, 0x6, 0x6, 0x5, 0x33, +0x6, 0x1f, 0x3c, 0x3c, 0x25, 0x3d, 0x1, 0x28, 0x27, 0x2a, 0x28, 0x3c, 0x1, 0x30, 0x39, 0x39, 0x30, 0x3c, 0x2a, 0x3b, +0x2b, 0x24, 0x24, 0x2b, 0x28, 0x2b, 0x24, 0x24, 0x24, 0x2b, 0x28, 0x3c, 0x2b, 0x25, 0x24, 0x24, 0x25, 0x5, 0x3c, 0x2b, +0x24, 0x2b, 0x2a, 0x20, 0x24, 0x2b, 0x2b, 0x2b, 0x25, 0x3b, 0x24, 0x25, 0x25, 0x2b, 0x3b, 0x25, 0x24, 0x25, 0x25, 0x2b, +0x25, 0x3b, 0x9, 0x3, 0x3, 0x3d, 0x3, 0x3d, 0x3, 0x3, 0x9, 0x3, 0x3, 0x3, 0x27, 0x3b, 0x3b, 0x3b, 0x3d, 0x3b, +0x2b, 0x38, 0x3d, 0x3, 0x3, 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x30, 0x3d, 0x30, 0x9, 0x3d, 0x3d, 0x3b, 0x3d, 0x3d, +0x9, 0x6, 0x4, 0x1a, 0x27, 0x27, 0x5, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x3d, 0x2a, 0x2a, +0x6, 0xa, 0x27, 0x22, 0x20, 0x6, 0x5, 0x6, 0x27, 0x3d, 0x6, 0x3d, 0x3a, 0x3c, 0x3d, 0x30, 0x25, 0x2b, 0x26, 0x17, +0x17, 0x16, 0x24, 0x24, 0x2b, 0x30, 0x2f, 0x25, 0x2b, 0x21, 0x17, 0x2b, 0x2a, 0x25, 0x21, 0x24, 0x17, 0x25, 0x3c, 0x3c, +0x2b, 0x24, 0x2b, 0x24, 0x30, 0x6, 0x3c, 0x24, 0x2b, 0x24, 0x25, 0x5, 0x2b, 0x2b, 0x25, 0x3c, 0x25, 0x2b, 0x2b, 0x2b, +0x2b, 0x2b, 0x2b, 0x25, 0x25, 0x3b, 0x3b, 0x2b, 0x2b, 0x3b, 0x3b, 0x25, 0x25, 0x25, 0x9, 0x3, 0x3d, 0x3d, 0x3, 0x3, +0x3, 0x3, 0x3d, 0x3d, 0x3, 0x3d, 0x3, 0x3d, 0x3c, 0x3d, 0x3d, 0x27, 0x3, 0x28, 0x3d, 0x3, 0x3d, 0x3, 0x3, 0x3, +0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x30, 0x20, 0x4, 0x27, 0x5, 0x27, 0x4, 0x28, 0x2f, 0x1d, 0x27, 0x28, +0x27, 0x27, 0x27, 0x27, 0x27, 0x3d, 0x28, 0x2a, 0x6, 0x5, 0x27, 0x5, 0x28, 0x28, 0x3, 0x3d, 0x2b, 0x24, 0x17, 0x18, +0x3e, 0x3e, 0x3e, 0x3e, 0x17, 0x18, 0x3e, 0x3e, 0x3e, 0x18, 0x24, 0x17, 0x16, 0x25, 0x35, 0x25, 0x24, 0x18, 0x17, 0x24, +0x3c, 0x3b, 0x17, 0x17, 0x24, 0x24, 0x3b, 0x28, 0x2b, 0x24, 0x24, 0x24, 0x3b, 0x3d, 0x3b, 0x25, 0x24, 0x24, 0x2d, 0x28, +0x2b, 0x24, 0x2b, 0x25, 0x2b, 0x2b, 0x2b, 0x2b, 0x24, 0x3c, 0x3c, 0x25, 0x3b, 0x2b, 0x3b, 0x25, 0x3d, 0x3d, 0x25, 0x25, +0x25, 0x25, 0x30, 0x25, 0x25, 0x3, 0x3, 0x3d, 0x3, 0x3, 0x28, 0x3d, 0x3, 0x27, 0x9, 0x28, 0x9, 0x27, 0x3d, 0x28, +0x3d, 0x28, 0x9, 0x3d, 0x3d, 0x3d, 0x3d, 0xa, 0x3, 0x3d, 0x3, 0x9, 0x9, 0x3d, 0x3d, 0x3d, 0x9, 0x5, 0xa, 0x5, +0xa, 0xa, 0x9, 0xa, 0x5, 0xa, 0x28, 0xa, 0x9, 0x9, 0x5, 0x9, 0x3, 0x3d, 0x9, 0x3d, 0xa, 0x5, 0x9, 0x3, +0x3, 0x3d, 0x3d, 0x3b, 0x2b, 0x24, 0x17, 0x17, 0x21, 0x17, 0x16, 0x16, 0x15, 0x18, 0x17, 0x3e, 0x2b, 0x25, 0x21, 0x17, +0x2b, 0x38, 0x27, 0x36, 0x24, 0x17, 0x18, 0x2b, 0x2b, 0x2b, 0x17, 0x18, 0x17, 0x19, 0x10, 0xe, 0x19, 0x17, 0x17, 0x24, +0xe, 0x19, 0x2b, 0x24, 0x17, 0x17, 0x24, 0x3d, 0x19, 0x24, 0x19, 0x18, 0x19, 0x24, 0x2b, 0x2b, 0x19, 0x25, 0x30, 0xb, +0x2b, 0x19, 0x2b, 0x2b, 0x25, 0x25, 0x25, 0x25, 0x25, 0xb, 0x25, 0x30, 0x25, 0x25, 0x25, 0x3d, 0x3d, 0x3d, 0x30, 0x3d, +0x3d, 0x9, 0x3, 0x3d, 0x9, 0x9, 0x9, 0x3d, 0x3, 0x3d, 0x9, 0x3, 0x3, 0xa, 0x9, 0x9, 0x9, 0x9, 0xa, 0x9, +0x3, 0x3, 0x9, 0x9, 0x3d, 0xa, 0x5, 0xa, 0x9, 0x9, 0x9, 0x3, 0xa, 0x5, 0x9, 0x3d, 0x3, 0x3, 0x3d, 0x9, +0x3, 0x3d, 0x9, 0x9, 0xa, 0x5, 0x28, 0x9, 0x9, 0x27, 0x5, 0x6, 0x6, 0x6, 0x6, 0x4, 0x28, 0x5, 0x2a, 0x3b, +0x2d, 0x2b, 0x24, 0x24, 0x17, 0x24, 0x24, 0x17, 0x17, 0x24, 0x38, 0x29, 0x17, 0x16, 0x17, 0x21, 0x25, 0x24, 0x16, 0x17, +0x17, 0x24, 0x2b, 0x2b, 0x24, 0x24, 0x18, 0x17, 0x24, 0x30, 0x19, 0x17, 0x18, 0x24, 0x18, 0x2b, 0x18, 0x24, 0x24, 0x24, +0x24, 0x24, 0x19, 0x2b, 0x19, 0x2b, 0x25, 0x19, 0x25, 0x2b, 0x19, 0x24, 0xb, 0x2b, 0x25, 0xb, 0x25, 0x25, 0x25, 0xb, +0x3d, 0x30, 0x3d, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, 0x3d, 0x9, 0x30, 0x3d, 0x9, 0x3d, 0x30, 0xc, 0x3d, +0x3, 0x3d, 0x9, 0x3, 0x9, 0x9, 0x3, 0x9, 0x9, 0x9, 0x9, 0x9, 0x3d, 0x9, 0xa, 0x3, 0x3, 0x3, 0x3d, 0x3d, +0xa, 0x5, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, 0x5, 0x5, 0x5, 0x6, 0x6, 0x20, 0x20, 0x6, +0x6, 0x28, 0x27, 0x2a, 0x3, 0x28, 0x2a, 0x28, 0x2c, 0x1a, 0x27, 0x28, 0x2a, 0x3b, 0x2b, 0x25, 0x25, 0x3a, 0x3b, 0x2b, +0x2d, 0x2b, 0x30, 0x25, 0x28, 0x3c, 0x2b, 0x2b, 0x19, 0x2b, 0xe, 0x3d, 0x19, 0x7, 0x24, 0x24, 0xc, 0xa, 0x25, 0x19, +0x24, 0x24, 0x19, 0xe, 0x24, 0x2b, 0x19, 0x19, 0x2b, 0x19, 0x2b, 0x19, 0x25, 0x25, 0x19, 0x25, 0x2b, 0x25, 0x2b, 0x19, +0x25, 0x25, 0x25, 0x25, 0x30, 0xd, 0x25, 0x3d, 0x3d, 0x9, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0xd, 0x25, 0xd, 0x3d, +0x30, 0xb, 0x3d, 0x3b, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0xa, 0x9, 0x9, 0x30, 0x9, 0x9, 0x9, 0x3d, 0x3, 0x9, 0x3d, +0xa, 0x9, 0x9, 0x9, 0x9, 0x9, 0x3, 0x9, 0xa, 0x3, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, +0xa, 0xa, 0x5, 0x20, 0x5, 0x6, 0x6, 0x6, 0x27, 0x6, 0x27, 0x5, 0x2a, 0x28, 0x28, 0x27, 0x28, 0x2a, 0x28, 0x25, +0x38, 0x25, 0x2b, 0x30, 0x3, 0x2a, 0x2a, 0x28, 0x28, 0x1a, 0x6, 0x27, 0x2a, 0x2a, 0x2a, 0x3d, 0x25, 0x3d, 0x9, 0xd, +0x3, 0x3d, 0xb, 0x2b, 0x25, 0xd, 0x30, 0xb, 0x2b, 0x2b, 0x25, 0xa, 0x3b, 0x3d, 0x9, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, +0x3d, 0xa, 0x3, 0x3d, 0x3d, 0xe, 0x9, 0x3d, 0x3d, 0x9, 0xa, 0x6, 0xf, 0x6, 0xf, 0x5, 0xa, 0x9, 0x20, 0x5, +0x9, 0x5, 0xa, 0x6, 0xa, 0x3, 0x3, 0x3d, 0x9, 0xa, 0x9, 0x3, 0xa, 0x20, 0x3, 0xa, 0xa, 0x5, 0xa, 0x6, +0x6, 0x10, 0x5, 0x10, 0x5, 0x20, 0x6, 0xa, 0x5, 0x3, 0xa, 0x9, 0x9, 0xa, 0x3, 0x3d, 0x3, 0x3d, 0x3, 0x3, +0x3d, 0x9, 0x3, 0x3d, 0x9, 0x3d, 0x3d, 0x25, 0xa, 0x5, 0x9, 0x3, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, 0x3b, 0x25, 0x25, +0x3c, 0x2a, 0x3, 0x2a, 0x2a, 0x38, 0x3a, 0x30, 0x25, 0x2a, 0x3c, 0x25, 0x3a, 0x2a, 0x2a, 0x28, 0x2a, 0x27, 0x27, 0x0, +0x28, 0x28, 0x2a, 0x28, 0x9, 0x14, 0x3d, 0x3b, 0xe, 0x3d, 0xa, 0x3d, 0xe, 0xa, 0x3d, 0x3d, 0x3, 0xd, 0x9, 0x12, +0xf, 0x3f, 0x10, 0x3f, 0x12, 0x12, 0x12, 0x12, 0x10, 0x3f, 0x12, 0x12, 0x12, 0x9, 0x10, 0x6, 0x12, 0x10, 0x12, 0x12, +0x12, 0x12, 0x12, 0x12, 0x20, 0x12, 0x12, 0x3f, 0x3f, 0x3f, 0x12, 0x20, 0x12, 0x12, 0x3f, 0x3f, 0x12, 0x12, 0x3f, 0x3f, +0x3f, 0x3f, 0x3f, 0x3f, 0x22, 0x3f, 0x3f, 0x12, 0x3f, 0x12, 0x3f, 0x12, 0x12, 0x12, 0x12, 0x20, 0x12, 0x9, 0x3, 0x9, +0xa, 0x5, 0x20, 0x20, 0x5, 0xa, 0x20, 0x9, 0x20, 0xa, 0x3, 0x3d, 0x28, 0x3d, 0x3d, 0x3d, 0x5, 0x5, 0x3, 0x3f, +0x3f, 0x22, 0x3f, 0x3f, 0x22, 0x3f, 0x31, 0x27, 0x33, 0x20, 0x3f, 0x3f, 0x31, 0x1f, 0x2c, 0x31, 0x31, 0x31, 0x33, 0x2f, +0x31, 0x33, 0x31, 0x3f, 0x22, 0x3f, 0x3f, 0x20, 0x3f, 0x22, 0x31, 0x20, 0x9, 0x10, 0x12, 0xf, 0xf, 0xf, 0xa, 0x5, +0xf, 0x10, 0x12, 0xf, 0x3f, 0x9, 0x3f, 0x10, 0xa, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x20, 0x10, 0x9, +0x9, 0xa, 0x6, 0x5, 0x12, 0x6, 0x12, 0x12, 0x6, 0x5, 0x10, 0x6, 0xf, 0x5, 0xa, 0x20, 0xf, 0x6, 0xa, 0x9, +0xa, 0x10, 0x12, 0xa, 0x6, 0x9, 0x20, 0x20, 0x3f, 0x12, 0x6, 0x20, 0x6, 0x20, 0x3f, 0x12, 0x12, 0x20, 0x20, 0x20, +0x10, 0x3f, 0x3, 0x9, 0x20, 0x3d, 0x9, 0x3, 0x9, 0x3d, 0x20, 0x20, 0xa, 0x5, 0xa, 0x9, 0xa, 0x9, 0x9, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0xa, 0x9, 0x28, 0x6, 0x20, 0x20, 0x6, 0x20, 0x22, 0x6, 0x2f, 0x5, 0x27, 0x27, 0x22, 0x20, +0x6, 0x2f, 0x28, 0x1f, 0x28, 0x31, 0x2e, 0x1f, 0x33, 0x6, 0x6, 0x33, 0x20, 0x6, 0x4, 0x20, 0x20, 0x22, 0x4, 0x5, +0x9, 0x3d, 0x10, 0x10, 0xe, 0x5, 0x5, 0x11, 0x20, 0x10, 0xf, 0x5, 0x13, 0xa, 0xa, 0xf, 0x10, 0xf, 0x20, 0x9, +0x12, 0xa, 0x12, 0x3d, 0x3d, 0xf, 0x6, 0xa, 0x12, 0x10, 0x6, 0x9, 0xa, 0x3, 0x3d, 0x9, 0x9, 0x3, 0x9, 0xa, +0x3d, 0x9, 0x9, 0x10, 0xa, 0x5, 0x9, 0x9, 0x3, 0x5, 0x5, 0x3, 0x9, 0x3, 0x9, 0x20, 0x22, 0x5, 0xa, 0xa, +0x9, 0xa, 0x22, 0x20, 0x9, 0x5, 0x9, 0xe, 0xa, 0x12, 0x30, 0x25, 0x9, 0x3d, 0x9, 0x3d, 0x9, 0x3d, 0xa, 0x5, +0x9, 0x3, 0x3, 0x9, 0x9, 0x28, 0x3d, 0x3b, 0x3d, 0x25, 0x3d, 0x3d, 0x5, 0x27, 0x5, 0x6, 0x20, 0x5, 0x5, 0x6, +0x6, 0x6, 0x27, 0x27, 0x28, 0x27, 0x4, 0x4, 0x2a, 0x28, 0x28, 0x2a, 0x0, 0x0, 0x27, 0x2a, 0x2f, 0x2a, 0x28, 0x28, +0x28, 0x2a, 0x28, 0x2a, 0x6, 0x2f, 0x27, 0x3d, 0x3d, 0x3d, 0xe, 0xa, 0x3b, 0xd, 0x3d, 0x14, 0x6, 0x10, 0x3d, 0xe, +0x3, 0x3d, 0xa, 0x12, 0x9, 0x3, 0x9, 0x9, 0xa, 0x6, 0xa, 0x30, 0x30, 0x9, 0x10, 0x12, 0xa, 0x3d, 0x6, 0x12, +0x5, 0x20, 0x10, 0x5, 0x5, 0xa, 0x3, 0x9, 0x3, 0x9, 0x3d, 0xa, 0x20, 0x3d, 0x9, 0x3, 0x9, 0x10, 0x20, 0x9, +0xa, 0x9, 0x9, 0x20, 0x20, 0x20, 0x5, 0x3d, 0x9, 0x5, 0x12, 0x20, 0x20, 0x3d, 0xa, 0x3d, 0x20, 0x10, 0x30, 0xc, +0x6, 0x3d, 0x3, 0x9, 0x3d, 0x3d, 0xa, 0x6, 0x3, 0x9, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, 0x25, 0x25, 0xd, 0x3d, +0x9, 0x5, 0x28, 0x5, 0x20, 0x6, 0x5, 0x5, 0x20, 0x31, 0x9, 0x27, 0x28, 0x27, 0x20, 0x33, 0x28, 0x28, 0x27, 0x2f, +0x4, 0x20, 0x2, 0x2f, 0x28, 0x2c, 0x33, 0x2a, 0x28, 0x27, 0x2a, 0x28, 0x6, 0x33, 0x27, 0x3d, 0xd, 0x3d, 0x11, 0x9, +0xd, 0x3d, 0x9, 0x3d, 0x10, 0xd, 0xa, 0x3, 0x3d, 0x14, 0x3, 0x10, 0x5, 0x11, 0x3d, 0xa, 0x9, 0x9, 0xa, 0x25, +0xc, 0xa, 0x3, 0x3d, 0x19, 0x2b, 0x3, 0x5, 0x20, 0x6, 0x9, 0x3, 0x3f, 0x20, 0x12, 0x3d, 0x3d, 0x3d, 0x3d, 0x20, +0x10, 0x3d, 0x3d, 0x3d, 0x3d, 0x5, 0xa, 0x3d, 0x3d, 0x3d, 0x3d, 0x12, 0x6, 0x9, 0x9, 0x3d, 0x9, 0x9, 0x12, 0x6, +0x9, 0x9, 0x3d, 0x9, 0xa, 0x10, 0x2b, 0x3b, 0x9, 0x3d, 0x9, 0x3d, 0x9, 0x3d, 0x5, 0xa, 0x3, 0x9, 0x9, 0x3d, +0x30, 0x3d, 0x3c, 0x25, 0x3d, 0x3b, 0x3d, 0x3d, 0x9, 0x5, 0x3, 0x22, 0x5, 0x5, 0x27, 0x9, 0x20, 0x20, 0x28, 0x3, +0x3d, 0x28, 0x5, 0x6, 0x3d, 0x2a, 0x2a, 0x27, 0x1a, 0x4, 0x27, 0x28, 0x2a, 0x2a, 0x3, 0x33, 0x35, 0x3c, 0x3a, 0x2a, +0x1a, 0x5, 0x2a, 0x25, 0x3d, 0x3d, 0x3d, 0xe, 0x25, 0xc, 0xc, 0x9, 0xa, 0xa, 0x9, 0x14, 0xd, 0x3d, 0x9, 0x12, +0xf, 0x3, 0x3d, 0x3d, 0x3d, 0x12, 0x12, 0x2b, 0x2b, 0x9, 0xd, 0x3d, 0x24, 0x2b, 0x3d, 0x3d, 0x3f, 0x3f, 0x12, 0x9, +0x12, 0x3f, 0x12, 0x25, 0x30, 0xb, 0x3d, 0x5, 0x5, 0x3d, 0x30, 0xc, 0x3b, 0xa, 0x9, 0x3d, 0x25, 0x3d, 0x3d, 0x9, +0x6, 0x9, 0x3d, 0x3d, 0xc, 0x9, 0x20, 0xa, 0x3d, 0x3d, 0xd, 0x9, 0x5, 0xa, 0x17, 0x19, 0x3d, 0x3d, 0x3d, 0x9, +0x3d, 0x3d, 0xa, 0x5, 0x3, 0x25, 0x25, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0xa, 0x5, 0x3, 0x12, +0x9, 0x27, 0x9, 0x27, 0x20, 0x6, 0x9, 0x2a, 0x3c, 0x3c, 0x1a, 0x28, 0x2a, 0x3b, 0x3a, 0x25, 0x34, 0x33, 0x28, 0x2a, +0x2a, 0x28, 0x27, 0x20, 0x25, 0x3b, 0x3b, 0x3b, 0x28, 0x2f, 0x2a, 0x3b, 0x25, 0xb, 0x9, 0x3d, 0xc, 0x25, 0x3d, 0x25, +0xe, 0xa, 0x3d, 0x25, 0x3b, 0x3d, 0xd, 0x6, 0x9, 0x30, 0x3d, 0xd, 0x3d, 0xa, 0xa, 0x17, 0x19, 0x3b, 0x3d, 0xa, +0x3d, 0xc, 0x3d, 0x3, 0x30, 0x25, 0x3b, 0x25, 0x3d, 0x25, 0x3d, 0x30, 0xc, 0x3b, 0x3d, 0x20, 0x3, 0x3d, 0x25, 0x25, +0x3d, 0x20, 0xa, 0x3c, 0x25, 0x25, 0x14, 0x6, 0xa, 0x9, 0x3d, 0x3d, 0x3d, 0x3, 0x20, 0x20, 0x3d, 0x3d, 0x3d, 0x3d, +0x10, 0x20, 0x24, 0x19, 0x3, 0x3d, 0x3d, 0x30, 0x3d, 0x3d, 0xa, 0x5, 0x3d, 0x3d, 0x25, 0x3d, 0x3d, 0x3b, 0x3d, 0x3c, +0x3c, 0x3d, 0x3d, 0x3d, 0x5, 0xa, 0x28, 0x5, 0x27, 0x28, 0x3, 0x9, 0x20, 0x27, 0x3, 0x2a, 0x3b, 0x28, 0x20, 0x6, +0x3d, 0x25, 0x35, 0x34, 0x1a, 0x27, 0x28, 0x2a, 0x2a, 0x3, 0x28, 0x3d, 0x3b, 0x3a, 0x25, 0x3c, 0x1a, 0x9, 0x3c, 0x3b, +0x25, 0x3d, 0x5, 0xe, 0x25, 0x2b, 0xc, 0x3, 0xf, 0x9, 0xd, 0xc, 0xc, 0x3d, 0x3, 0x10, 0x5, 0x14, 0x3d, 0x3d, +0x3, 0xf, 0x20, 0x24, 0x24, 0x3d, 0xe, 0x5, 0x10, 0x3, 0x3, 0x20, 0x2b, 0xb, 0x25, 0x25, 0x2b, 0x2b, 0x2b, 0x3d, +0x25, 0x9, 0x20, 0x5, 0xa, 0x3d, 0x3d, 0x9, 0x5, 0x20, 0x9, 0x3d, 0x3d, 0x9, 0x10, 0x6, 0x20, 0x3, 0xd, 0x3d, +0xa, 0x12, 0x12, 0x5, 0x9, 0xd, 0x5, 0x12, 0xf, 0x10, 0x19, 0x2b, 0x9, 0x3d, 0x3d, 0x3d, 0x30, 0x3d, 0xa, 0xa, +0x3d, 0x9, 0x3d, 0x3b, 0x3d, 0x3d, 0x3c, 0x3c, 0x25, 0x3d, 0x3d, 0x30, 0xa, 0x6, 0x9, 0x28, 0x5, 0x9, 0x6, 0x20, +0x20, 0x6, 0x3, 0x3d, 0x27, 0x27, 0x4, 0x28, 0x2a, 0x3d, 0x28, 0x33, 0x4, 0x6, 0x28, 0x3, 0x3, 0x1a, 0x20, 0x3b, +0x3d, 0x3b, 0x28, 0x20, 0x27, 0x5, 0x3, 0x3, 0x3, 0x20, 0x20, 0x3d, 0x3d, 0xc, 0x28, 0x20, 0x9, 0xa, 0x3d, 0x3d, +0x3d, 0xa, 0xf, 0x6, 0x5, 0x3d, 0x3b, 0x13, 0x20, 0x20, 0x10, 0x24, 0x19, 0x3d, 0x9, 0x5, 0x6, 0x9, 0x6, 0x3, +0x24, 0x24, 0x24, 0x19, 0x19, 0x24, 0x2b, 0x30, 0x25, 0x3d, 0x12, 0x20, 0x3, 0x3d, 0x30, 0xa, 0x20, 0x5, 0x3, 0x3d, +0x25, 0x3d, 0xa, 0xf, 0x5, 0x3d, 0x3d, 0xd, 0x5, 0x12, 0xa, 0x5, 0x3d, 0x30, 0x9, 0x12, 0x20, 0x20, 0x24, 0x19, +0x3d, 0x3b, 0xd, 0x3d, 0x3d, 0x30, 0x20, 0x27, 0x3d, 0x5, 0x3, 0x3d, 0x25, 0x3d, 0x3c, 0x2d, 0x25, 0x3b, 0x3d, 0x30, +0xa, 0x6, 0x3, 0x3, 0x9, 0x3, 0x5, 0x22, 0x20, 0x27, 0x3d, 0x2a, 0x27, 0x1a, 0x6, 0x28, 0x3c, 0x25, 0x28, 0x1a, +0x20, 0x4, 0x2a, 0x2a, 0x28, 0x20, 0x20, 0x25, 0x3b, 0x3a, 0x28, 0x20, 0x20, 0x27, 0x2a, 0x3d, 0x9, 0x20, 0x5, 0x9, +0x25, 0x25, 0x3d, 0x10, 0xa, 0xa, 0x3d, 0x3d, 0x3d, 0x10, 0x10, 0xa, 0xa, 0x3d, 0x3d, 0x3d, 0x12, 0x10, 0x10, 0x24, +0x24, 0xc, 0x17, 0x17, 0x18, 0x24, 0x18, 0x24, 0x19, 0x24, 0x24, 0x24, 0x2b, 0x2b, 0x19, 0x25, 0x25, 0x3d, 0x20, 0x6, +0x9, 0x25, 0xc, 0x3, 0x20, 0x20, 0x3d, 0x25, 0x25, 0xd, 0x12, 0x10, 0x5, 0x3d, 0x25, 0x3d, 0x5, 0xf, 0x10, 0x9, +0x3, 0xd, 0x3d, 0x10, 0x12, 0x20, 0x19, 0x24, 0x3d, 0x30, 0x3d, 0x3d, 0x3d, 0xc, 0x5, 0x6, 0x3d, 0x3b, 0x3b, 0x25, +0x3d, 0x3b, 0x25, 0x2d, 0x2b, 0x3d, 0x3d, 0x3d, 0xa, 0x1a, 0x28, 0x3d, 0x28, 0x3, 0x5, 0x22, 0x20, 0x27, 0x3c, 0x3c, +0x3, 0x33, 0x6, 0x9, 0x3b, 0x3a, 0x2a, 0x12, 0x20, 0x27, 0x3c, 0x2d, 0x3c, 0x20, 0x20, 0x38, 0x39, 0x2b, 0x3a, 0x20, +0x20, 0x3, 0x3b, 0x25, 0x3d, 0x6, 0x20, 0x3d, 0x25, 0x25, 0x3d, 0x20, 0x6, 0x9, 0xc, 0x25, 0xc, 0xa, 0xa, 0xa, +0x9, 0x9, 0x3d, 0x3d, 0x12, 0x20, 0x20, 0x24, 0x24, 0x3d, 0x17, 0x24, 0x3d, 0x25, 0x25, 0x25, 0x3d, 0x3d, 0x3d, 0x2b, +0xa, 0x9, 0x2b, 0x19, 0x25, 0x30, 0x12, 0x1a, 0x9, 0x25, 0x3b, 0x9, 0x6, 0x5, 0x3d, 0x2b, 0x25, 0x3d, 0xa, 0x5, +0x5, 0x3d, 0xb, 0x3b, 0x20, 0xa, 0x5, 0xe, 0x3d, 0x25, 0x3d, 0xf, 0xa, 0xa, 0x24, 0x24, 0x3d, 0x30, 0x3d, 0x3d, +0x9, 0x3, 0x5, 0xa, 0x3, 0x3d, 0x25, 0x3d, 0x25, 0x25, 0x2b, 0x29, 0x24, 0x3d, 0x3d, 0x3d, 0x6, 0x5, 0x27, 0x3, +0x3d, 0x3, 0x27, 0x20, 0x20, 0x27, 0x3b, 0x2d, 0x2a, 0x1a, 0x6, 0x2a, 0x25, 0x3b, 0x2a, 0x6, 0x1a, 0x5, 0x3, 0x25, +0x2a, 0x20, 0x2a, 0x17, 0x36, 0x3b, 0x3b, 0x1a, 0x6, 0x28, 0x3b, 0x25, 0x3d, 0x6, 0x27, 0x3d, 0x2b, 0x25, 0x3d, 0x20, +0x9, 0xa, 0x25, 0x25, 0x25, 0x10, 0xa, 0x20, 0x3, 0x3d, 0xc, 0x3d, 0xa, 0x5, 0xf, 0x24, 0x18, 0x3d, 0x17, 0x24, +0x25, 0x24, 0x24, 0x2b, 0x2b, 0x19, 0x2b, 0x19, 0x2b, 0x25, 0x2b, 0x21, 0x2b, 0x25, 0x20, 0x5, 0x3d, 0x25, 0x25, 0x25, +0x10, 0xa, 0x3d, 0x19, 0x2b, 0xd, 0x5, 0x10, 0x9, 0x3d, 0x25, 0x25, 0xf, 0xa, 0x10, 0x9, 0x3b, 0xb, 0x3d, 0x5, +0xa, 0x12, 0x18, 0x19, 0x3d, 0x3d, 0x3d, 0x9, 0xa, 0x5, 0x20, 0x6, 0x3d, 0x28, 0x27, 0x28, 0x2f, 0x28, 0x25, 0x2b, +0x24, 0x3, 0x3, 0x3c, 0x27, 0x1a, 0x3, 0x3d, 0x3c, 0x3d, 0x28, 0x1a, 0x6, 0x3, 0x25, 0x25, 0x3b, 0x6, 0x5, 0x3d, +0x2b, 0x25, 0x2a, 0x1f, 0x6, 0x28, 0x3c, 0x3c, 0x25, 0x4, 0x20, 0x2d, 0x37, 0x25, 0x3c, 0x1a, 0x27, 0x3, 0x25, 0x25, +0x25, 0x5, 0xa, 0x3, 0x2b, 0x25, 0x3d, 0x5, 0x6, 0x3, 0x3b, 0x2b, 0xb, 0x9, 0x5, 0xa, 0xa, 0x3b, 0x25, 0x3d, +0x20, 0x6, 0x22, 0x24, 0x24, 0x3d, 0x24, 0x17, 0x25, 0x18, 0x2b, 0x3d, 0x2b, 0x30, 0x2b, 0x3, 0xa, 0x9, 0x2b, 0x17, +0x24, 0x3d, 0x20, 0x5, 0x3, 0x25, 0x2b, 0x30, 0x20, 0x9, 0x3b, 0x2b, 0x25, 0x25, 0x20, 0xa, 0x3, 0x25, 0xb, 0x25, +0xa, 0xa, 0x5, 0x13, 0x2b, 0x30, 0xc, 0xa, 0x6, 0xa, 0x24, 0x24, 0x3d, 0x3, 0xa, 0xa, 0x6, 0x6, 0x20, 0x20, +0x28, 0x4, 0x27, 0x28, 0x3d, 0x1c, 0x24, 0x24, 0x2b, 0x28, 0x27, 0x3d, 0x27, 0x5, 0x6, 0x3, 0x3c, 0x3d, 0x3, 0x20, +0x6, 0x3, 0x25, 0x2d, 0x3a, 0x20, 0x28, 0x3d, 0x29, 0x3b, 0x3a, 0x4, 0x4, 0x28, 0x3c, 0x3b, 0x25, 0x1a, 0x6, 0x3c, +0x29, 0x37, 0x3c, 0x20, 0xa, 0x3d, 0x2d, 0x25, 0x25, 0x5, 0x3, 0x3d, 0x24, 0x25, 0x25, 0x20, 0x6, 0x3, 0x25, 0xb, +0x25, 0x9, 0x10, 0x9, 0xa, 0x2b, 0xc, 0x2a, 0xa, 0x5, 0x6, 0x18, 0x24, 0x3d, 0x19, 0x17, 0x17, 0x30, 0x2b, 0x19, +0x8, 0x2b, 0x19, 0x25, 0x25, 0x3d, 0x17, 0x2b, 0x24, 0x25, 0x6, 0x9, 0x3, 0x25, 0x25, 0x3d, 0x20, 0x3, 0x3b, 0x24, +0x25, 0xc, 0x20, 0xa, 0x9, 0xb, 0x25, 0x25, 0x3d, 0x10, 0x9, 0x3d, 0x3d, 0xb, 0x3d, 0x9, 0x10, 0x5, 0x18, 0x19, +0x3d, 0x9, 0x5, 0x5, 0x20, 0x12, 0x22, 0x28, 0x27, 0x27, 0x28, 0x27, 0x1c, 0x8, 0x24, 0x23, 0x24, 0x2f, 0x27, 0x28, +0x1a, 0x5, 0x6, 0x25, 0x3b, 0x3d, 0x3, 0x20, 0x6, 0x28, 0x25, 0x2b, 0x3c, 0x20, 0x28, 0x3b, 0x24, 0x25, 0x2a, 0x1d, +0x27, 0x27, 0x3b, 0x3b, 0x3c, 0x28, 0x20, 0x21, 0x24, 0x24, 0x38, 0x20, 0x28, 0x3d, 0x25, 0x2b, 0x25, 0x20, 0x9, 0x30, +0x19, 0x25, 0x25, 0x6, 0x5, 0x3, 0x25, 0x25, 0x25, 0x3d, 0x20, 0x9, 0x3, 0x30, 0x25, 0xc, 0x5, 0x20, 0x5, 0x24, +0x24, 0x3d, 0x24, 0x17, 0x3d, 0x12, 0x3, 0x24, 0x19, 0x3d, 0x3b, 0x2b, 0x3d, 0x3d, 0x17, 0x21, 0x24, 0x2b, 0x6, 0x9, +0x3, 0x2b, 0x25, 0x25, 0xa, 0x9, 0x3d, 0x19, 0x2b, 0x3b, 0x5, 0xa, 0x3, 0x30, 0xb, 0x25, 0x5, 0xa, 0xa, 0x9, +0xb, 0x25, 0x25, 0x20, 0xa, 0x10, 0x24, 0x24, 0x3d, 0x9, 0x27, 0x20, 0x22, 0x3f, 0x12, 0x27, 0x27, 0x27, 0x27, 0x28, +0x3d, 0x17, 0x24, 0x23, 0x24, 0x2a, 0x1b, 0x3d, 0x3d, 0x27, 0x5, 0x3c, 0x3b, 0x3c, 0x3d, 0x20, 0x5, 0x3, 0x25, 0x2b, +0x25, 0x4, 0x28, 0x3c, 0x24, 0x3b, 0x2a, 0x27, 0x6, 0x28, 0x3c, 0x3b, 0x3a, 0xa, 0x5, 0x26, 0x24, 0x26, 0x25, 0x27, +0x28, 0x28, 0x2b, 0x2b, 0x25, 0xa, 0x3, 0x30, 0x24, 0x25, 0x3d, 0x9, 0x28, 0x3, 0x30, 0x25, 0x2b, 0xa, 0xa, 0xa, +0x3, 0x25, 0x25, 0x3b, 0x20, 0x6, 0x20, 0x24, 0x24, 0x3, 0x17, 0x17, 0x2b, 0x2b, 0x2b, 0x19, 0x24, 0x25, 0x25, 0x2b, +0x25, 0x3c, 0x16, 0x17, 0x24, 0x2b, 0xa, 0x28, 0x3b, 0x2b, 0x2b, 0x25, 0xa, 0x3, 0x3b, 0x24, 0x19, 0x30, 0xf, 0x9, +0x9, 0x3d, 0x25, 0xc, 0x3d, 0xf, 0x3, 0x3d, 0x25, 0x25, 0xc, 0x9, 0xf, 0x5, 0x18, 0x24, 0x3d, 0x9, 0x5, 0x20, +0x12, 0x22, 0x12, 0x27, 0x27, 0x27, 0x28, 0x28, 0x3d, 0x16, 0x18, 0x24, 0x24, 0x3b, 0x3, 0x3, 0x3d, 0x5, 0x27, 0x3b, +0x3b, 0x3c, 0x3, 0x20, 0x5, 0x28, 0x25, 0x24, 0x2d, 0x5, 0x3, 0x3c, 0x24, 0x2b, 0x25, 0x1a, 0x28, 0x3, 0x3b, 0x3a, +0x3c, 0x27, 0x1a, 0x16, 0x17, 0x21, 0x2b, 0x1d, 0x9, 0x3d, 0x2b, 0x17, 0x2b, 0x9, 0x3, 0x3d, 0x18, 0x25, 0x25, 0x6, +0x3, 0x9, 0x3b, 0xb, 0x25, 0x9, 0x6, 0x3, 0x3, 0x30, 0x25, 0xc, 0x6, 0x6, 0x5, 0x17, 0x24, 0x3d, 0x3e, 0x17, +0x24, 0x17, 0x2b, 0x18, 0x16, 0x25, 0x3e, 0x21, 0x25, 0x3d, 0x17, 0x16, 0x17, 0x2b, 0x6, 0x9, 0x3, 0x25, 0x25, 0x2b, +0xa, 0x27, 0x3d, 0x2b, 0x2b, 0x25, 0x5, 0x5, 0x9, 0x3d, 0x2b, 0x25, 0x9, 0xa, 0x9, 0x9, 0xc, 0x2b, 0x3d, 0xa, +0xa, 0x6, 0x24, 0x19, 0x3d, 0x3, 0x5, 0x12, 0x22, 0x3f, 0x22, 0x5, 0x4, 0x28, 0x3, 0x3d, 0x2a, 0x17, 0x26, 0x24, +0x26, 0x3c, 0x9, 0x6, 0xa, 0x27, 0x5, 0x25, 0x3c, 0x25, 0x9, 0x6, 0x27, 0x3, 0x2b, 0x24, 0x25, 0x1d, 0x28, 0x3d, +0x2b, 0x2d, 0x3b, 0x27, 0x28, 0x27, 0x3d, 0x3b, 0x3b, 0x27, 0x6, 0x17, 0x26, 0x17, 0x2b, 0x5, 0x28, 0x3, 0x24, 0x24, +0x19, 0x9, 0x3d, 0x30, 0x19, 0x24, 0x25, 0xa, 0x27, 0x3, 0x3b, 0x2b, 0x25, 0x3, 0xa, 0x9, 0x3d, 0x25, 0x25, 0x30, +0x6, 0xa, 0x1a, 0x19, 0x24, 0x3d, 0x2b, 0x17, 0x3d, 0x9, 0x3d, 0x24, 0x17, 0x9, 0x24, 0x25, 0x9, 0x2b, 0x17, 0x23, +0x17, 0x25, 0xa, 0x27, 0x3d, 0x2b, 0x24, 0x2b, 0x6, 0xa, 0x25, 0x2b, 0x2b, 0x25, 0x9, 0x9, 0x3, 0x3d, 0xb, 0x25, +0xa, 0xa, 0x9, 0x3, 0x3b, 0x25, 0x3d, 0xa, 0x20, 0x10, 0x18, 0x24, 0xd, 0x28, 0x5, 0x20, 0x12, 0x22, 0x12, 0x5, +0x4, 0x27, 0x27, 0x28, 0x28, 0x24, 0x24, 0x21, 0x24, 0x3, 0x3d, 0x3d, 0x4, 0x27, 0x27, 0x3b, 0x3d, 0x3c, 0x3d, 0x1a, +0x5, 0x3, 0x2d, 0x24, 0x24, 0x6, 0x27, 0x3d, 0x2b, 0x2b, 0x25, 0x2f, 0x27, 0x27, 0x2a, 0x25, 0x3b, 0x6, 0x5, 0x21, +0x16, 0x17, 0x2d, 0x5, 0x28, 0x3, 0x24, 0x24, 0x2b, 0x5, 0x3, 0x3d, 0x2b, 0x2b, 0x25, 0xa, 0x9, 0x3, 0x3b, 0x2b, +0x2b, 0xa, 0x5, 0x6, 0x3, 0x3d, 0x25, 0x3d, 0xa, 0x6, 0x27, 0x21, 0x24, 0x3b, 0x2b, 0x17, 0x2b, 0x2b, 0x25, 0x3, +0x2b, 0x2b, 0x25, 0x2b, 0x2b, 0x24, 0x24, 0x17, 0x17, 0x25, 0x20, 0x9, 0x3, 0x25, 0x25, 0x2b, 0x20, 0x3b, 0x3d, 0x24, +0x2b, 0x25, 0x20, 0x5, 0x9, 0x30, 0x3d, 0x3d, 0xa, 0x5, 0x9, 0x9, 0xc, 0x25, 0x3d, 0xa, 0x6, 0x6, 0x24, 0x24, +0x9, 0x3, 0x6, 0x20, 0x22, 0x12, 0x22, 0x28, 0x5, 0x4, 0x28, 0x2a, 0x2a, 0x24, 0x21, 0x2b, 0x24, 0x3d, 0x3b, 0x3d, +0xa, 0x5, 0x6, 0x3c, 0x3c, 0x3c, 0x28, 0x20, 0x5, 0x28, 0x25, 0x24, 0x25, 0x1a, 0x9, 0x2a, 0x2b, 0x2b, 0x2a, 0x5, +0x5, 0x27, 0x3d, 0x3c, 0x3d, 0x5, 0x1d, 0x24, 0x24, 0x24, 0x25, 0x20, 0x28, 0x3d, 0x2b, 0x24, 0x19, 0x9, 0x9, 0x30, +0x24, 0x25, 0x25, 0x20, 0x3, 0x3d, 0x3d, 0x25, 0x3d, 0xa, 0x6, 0x9, 0x3, 0x2b, 0x25, 0x3d, 0x5, 0x20, 0x5, 0x17, +0x24, 0x3, 0x24, 0x24, 0x25, 0x19, 0x24, 0x3d, 0x3d, 0x2b, 0x2b, 0x2b, 0x25, 0x25, 0x24, 0x17, 0x24, 0x25, 0x6, 0x28, +0xa, 0x25, 0x25, 0x3b, 0x5, 0x3d, 0x3d, 0x2b, 0x25, 0x9, 0x5, 0xa, 0x28, 0x3d, 0x25, 0x25, 0xe, 0x5, 0x5, 0x3d, +0x25, 0x25, 0xd, 0x5, 0x6, 0x20, 0x19, 0x24, 0x3d, 0x3, 0xa, 0x1a, 0x20, 0x20, 0x22, 0x3, 0x27, 0x27, 0x27, 0x28, +0x3d, 0x24, 0x24, 0x24, 0x29, 0x3d, 0x3d, 0x25, 0x10, 0x6, 0x5, 0x3c, 0x3c, 0x3d, 0x3, 0x20, 0xa, 0x27, 0x3b, 0x3b, +0x3b, 0x20, 0x5, 0x3c, 0x2b, 0x25, 0x28, 0x20, 0x5, 0x27, 0x3c, 0x3c, 0x3a, 0x27, 0x6, 0x24, 0x26, 0x24, 0x2b, 0x20, +0x28, 0x2a, 0x25, 0x2b, 0x2b, 0x3, 0x5, 0x3c, 0x19, 0x25, 0x3, 0x5, 0x27, 0x3, 0x30, 0x25, 0x25, 0x9, 0x6, 0x6, +0x3d, 0x3c, 0x25, 0x3b, 0xa, 0x1a, 0x6, 0x24, 0x17, 0x3, 0x17, 0x2b, 0x5, 0x3, 0x9, 0x28, 0x3, 0x9, 0x9, 0x2a, +0x27, 0x9, 0x24, 0x24, 0x24, 0x2b, 0x6, 0x27, 0x28, 0x3b, 0x25, 0x3d, 0x20, 0x5, 0x3d, 0x25, 0x3c, 0x3d, 0x20, 0x6, +0x9, 0x3d, 0x25, 0x3d, 0x9, 0x20, 0x20, 0x5, 0x3d, 0x25, 0x3d, 0x20, 0x20, 0x20, 0x24, 0x18, 0x3, 0x3, 0x27, 0x5, +0x6, 0x6, 0x20, 0x20, 0x28, 0x27, 0x4, 0x27, 0x3, 0x3a, 0x2b, 0x2b, 0x2b, 0x3d, 0x25, 0x3d, 0xa, 0x6, 0x5, 0x3d, +0x3d, 0x3c, 0x28, 0x20, 0x6, 0x5, 0x3b, 0x3b, 0x3d, 0x1d, 0x5, 0x3c, 0x29, 0x3b, 0x2a, 0x20, 0x6, 0x27, 0x3a, 0x3b, +0x3d, 0x5, 0x1a, 0x24, 0x26, 0x24, 0x3b, 0x4, 0x5, 0x28, 0x2b, 0x24, 0x30, 0x20, 0x3d, 0x3d, 0x24, 0x25, 0x3d, 0x3, +0x5, 0x3d, 0x3d, 0x25, 0x3d, 0xa, 0x20, 0x6, 0x3, 0x3b, 0x3b, 0x3d, 0x5, 0x6, 0x28, 0x24, 0x24, 0x3d, 0x17, 0x25, +0x3d, 0x25, 0x25, 0x25, 0x3d, 0x3b, 0x3d, 0x3d, 0x3d, 0x3d, 0x30, 0x24, 0x19, 0x3b, 0x6, 0x20, 0x3d, 0x25, 0x25, 0x3d, +0x20, 0x5, 0x3, 0x25, 0x3b, 0x9, 0x6, 0x20, 0xa, 0x3d, 0x25, 0x25, 0x9, 0xf, 0x6, 0xa, 0x30, 0x3d, 0x3d, 0x20, +0x5, 0x20, 0x19, 0x2b, 0x3d, 0x3, 0x28, 0x27, 0x3, 0x5, 0x20, 0x20, 0x3d, 0x2a, 0x28, 0x27, 0x2a, 0x3d, 0x25, 0x2b, +0x2b, 0x3d, 0x3d, 0x30, 0xa, 0xa, 0x27, 0x9, 0x2a, 0x28, 0x5, 0x20, 0x20, 0x28, 0x25, 0x3a, 0x2a, 0x6, 0x2f, 0x3c, +0x2b, 0x3b, 0x2a, 0x6, 0x20, 0x27, 0x3c, 0x3b, 0x25, 0x28, 0x20, 0x3b, 0x24, 0x2b, 0x3c, 0x6, 0x1a, 0x3c, 0x2b, 0x2b, +0x3b, 0x20, 0x6, 0x3b, 0x2b, 0x30, 0x3d, 0x5, 0x5, 0x28, 0x3b, 0x25, 0x25, 0x5, 0x20, 0x4, 0x28, 0x2b, 0x3d, 0x3d, +0x20, 0x4, 0x28, 0x24, 0x24, 0x3b, 0x21, 0x24, 0x25, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x24, 0x25, 0x25, 0x2b, 0x24, +0x25, 0x3d, 0x20, 0x20, 0x3, 0x3b, 0x3b, 0x3d, 0x20, 0x6, 0x3d, 0x3b, 0x3d, 0x3, 0x20, 0x6, 0x5, 0x3c, 0x3b, 0x3d, +0x5, 0x20, 0x6, 0x5, 0x3d, 0x3d, 0x3d, 0x20, 0x20, 0x12, 0x24, 0x24, 0x3, 0x3d, 0x3d, 0x28, 0x28, 0x3, 0x6, 0x5, +0x3d, 0x3b, 0x3b, 0x25, 0x25, 0x3c, 0x2d, 0x2d, 0x25, 0x3d, 0x3b, 0x3d, 0xa, 0xa, 0x28, 0x3, 0x3d, 0x3, 0x5, 0x22, +0x20, 0x27, 0x3d, 0x3c, 0x3a, 0x1a, 0x6, 0x2a, 0x25, 0x2a, 0x28, 0x1e, 0x2, 0x27, 0x3c, 0x2a, 0x3c, 0x1d, 0x4, 0x2b, +0x24, 0x2b, 0x3c, 0x1a, 0x4, 0x2a, 0x2b, 0x2b, 0x25, 0x6, 0x4, 0x3c, 0x2b, 0x25, 0x3d, 0x6, 0x6, 0x27, 0x3b, 0x25, +0x25, 0x6, 0x27, 0x4, 0x2a, 0x3c, 0x3d, 0x3d, 0x20, 0x6, 0x4, 0x24, 0x24, 0x3c, 0x24, 0x24, 0x17, 0x24, 0x24, 0x17, +0x24, 0x24, 0x17, 0x24, 0x2b, 0x2b, 0x2b, 0x25, 0x25, 0x3c, 0x20, 0x5, 0x2a, 0x3d, 0x3d, 0x9, 0x20, 0x27, 0x9, 0x25, +0x25, 0x3d, 0x20, 0x6, 0x9, 0x3d, 0x25, 0x3d, 0x20, 0x5, 0x6, 0xa, 0x9, 0x3b, 0x3d, 0x20, 0x20, 0x20, 0x24, 0x19, +0x9, 0x3, 0x28, 0x3d, 0x3, 0x3d, 0x5, 0x27, 0x3b, 0x24, 0x24, 0x3b, 0x25, 0x3b, 0x25, 0x2b, 0x3b, 0x3d, 0x3b, 0x3d, +0xa, 0x5, 0xa, 0x28, 0x28, 0x27, 0x5, 0x6, 0x20, 0x27, 0x3a, 0x39, 0x27, 0x20, 0x6, 0x2a, 0x25, 0x2a, 0x3d, 0x31, +0x6, 0x5, 0x2a, 0x3c, 0x2a, 0x6, 0x20, 0x2b, 0x2b, 0x25, 0x3a, 0x27, 0x27, 0x3, 0x3b, 0x25, 0x3d, 0x28, 0x6, 0x3, +0x25, 0x25, 0x3b, 0x20, 0x3c, 0x3b, 0x25, 0x2b, 0x3d, 0x5, 0x3, 0x27, 0x3, 0x3b, 0x3d, 0x3d, 0x31, 0x6, 0x20, 0x17, +0x24, 0x3, 0x24, 0x24, 0x25, 0x24, 0x2b, 0x2b, 0x2b, 0x25, 0x24, 0x24, 0x2b, 0x2b, 0x24, 0x3b, 0x25, 0x3d, 0x6, 0x6, +0x3, 0x3d, 0x3d, 0x3b, 0x5, 0x20, 0x28, 0x25, 0x3c, 0x3d, 0x20, 0x6, 0x4, 0x3, 0x30, 0x30, 0x20, 0x20, 0x12, 0x5, +0x3d, 0x3d, 0x3d, 0x10, 0x22, 0x10, 0x24, 0x2b, 0x3, 0x3, 0x28, 0x2a, 0x2a, 0x2a, 0x5, 0x4, 0x3c, 0x2a, 0x3a, 0x3a, +0x3a, 0x25, 0x3b, 0x25, 0x3b, 0x3d, 0x3d, 0x3d, 0xa, 0x27, 0x5, 0x3d, 0x27, 0x28, 0x5, 0x22, 0x22, 0x27, 0x3, 0x2a, +0x2a, 0x22, 0x6, 0x28, 0x3a, 0x2a, 0x35, 0x1a, 0x6, 0x1a, 0x3, 0x2a, 0x3c, 0x1a, 0x2f, 0x2b, 0x25, 0x2b, 0x3c, 0x33, +0x33, 0x2a, 0x3b, 0x25, 0x3c, 0x20, 0x28, 0x3c, 0x3b, 0x3c, 0x3d, 0x1d, 0x6, 0x28, 0x3b, 0x3b, 0x3d, 0x6, 0x20, 0x4, +0x3, 0x2a, 0x3c, 0x3c, 0x6, 0x33, 0x6, 0x24, 0x2b, 0x3d, 0x3c, 0x3b, 0x27, 0x3, 0x3, 0x3, 0x5, 0x3, 0x2b, 0x25, +0x25, 0x25, 0x30, 0x3b, 0x25, 0x3, 0x20, 0x6, 0x5, 0x30, 0x3d, 0x3, 0x20, 0x20, 0x5, 0x3, 0x3d, 0x3d, 0x20, 0x20, +0x6, 0x3d, 0x3, 0x9, 0x20, 0x20, 0x20, 0x9, 0x28, 0x3d, 0x20, 0x20, 0x6, 0x12, 0x24, 0x2b, 0x3d, 0x3, 0x28, 0x28, +0x28, 0x2a, 0x5, 0x27, 0x2a, 0x27, 0x27, 0x2a, 0x3b, 0x2d, 0x3b, 0x25, 0x2a, 0x3c, 0x3d, 0x30, 0xa, 0x5, 0x9, 0x27, +0x27, 0x28, 0x5, 0x22, 0x20, 0x4, 0x2a, 0x28, 0x27, 0x20, 0x31, 0x27, 0x2a, 0x3c, 0x27, 0x1a, 0x20, 0x20, 0x28, 0x3d, +0x28, 0x6, 0x2f, 0x25, 0x3b, 0x2b, 0x3b, 0x33, 0x27, 0x27, 0x3b, 0x3b, 0x3b, 0x31, 0x2f, 0x3c, 0x3b, 0x3b, 0x2a, 0x33, +0x6, 0x9, 0x3c, 0x3d, 0x28, 0x5, 0x28, 0x6, 0x3, 0x30, 0x3b, 0x27, 0x4, 0x6, 0x2f, 0x2b, 0x24, 0x3d, 0x2a, 0x3d, +0x3d, 0x3, 0x27, 0x5, 0x28, 0x9, 0x2b, 0x2b, 0x25, 0x25, 0x25, 0x3, 0x3b, 0x3d, 0x9, 0x22, 0x5, 0x3d, 0x3, 0x3, +0x5, 0x6, 0x9, 0x3b, 0x3d, 0x9, 0x20, 0x20, 0x3, 0x3b, 0x3d, 0x3d, 0x6, 0x6, 0x12, 0x3, 0x3d, 0x3d, 0x3, 0x12, +0xf, 0x20, 0x24, 0x19, 0x3d, 0x27, 0x28, 0x28, 0x2a, 0x3a, 0x27, 0x27, 0x25, 0x2a, 0x28, 0x27, 0x3a, 0x25, 0x25, 0x25, +0x3b, 0x3d, 0x25, 0x25, 0x20, 0xa, 0x3, 0x27, 0x6, 0x28, 0x6, 0x20, 0x22, 0x5, 0x2a, 0x28, 0x27, 0x20, 0x1a, 0x27, +0x3d, 0x2a, 0x28, 0x1a, 0x22, 0x6, 0x27, 0x28, 0x2a, 0x1a, 0x6, 0x3b, 0x3c, 0x2b, 0x3c, 0x27, 0x20, 0x27, 0x25, 0x3c, +0x3a, 0x28, 0x28, 0x39, 0x25, 0x3b, 0x3d, 0x4, 0x1d, 0x28, 0x30, 0x3d, 0x3c, 0x2a, 0x4, 0x6, 0x27, 0x3, 0x3, 0xa, +0x2a, 0x20, 0x20, 0x2b, 0x24, 0x3d, 0x28, 0x9, 0x28, 0x9, 0x6, 0x28, 0x9, 0x28, 0x25, 0x3c, 0x3c, 0x3d, 0x25, 0x3b, +0x3c, 0x25, 0x3d, 0x6, 0x3, 0x3d, 0x3b, 0x3d, 0x3d, 0x20, 0x27, 0x25, 0x25, 0x30, 0x3, 0x20, 0x5, 0x9, 0x3d, 0x3d, +0x3d, 0x27, 0x6, 0x6, 0x3d, 0x25, 0x3d, 0x9, 0x20, 0x9, 0x24, 0x24, 0x3d, 0x27, 0x27, 0x2a, 0x28, 0x2a, 0x4, 0x4, +0x2a, 0x2a, 0x3a, 0x3b, 0x25, 0x25, 0x35, 0x3b, 0x3a, 0x3b, 0x3b, 0x3d, 0x5, 0x9, 0x28, 0x3, 0x28, 0x28, 0x9, 0x27, +0x22, 0x28, 0x3a, 0x39, 0x3a, 0x28, 0x4, 0x5, 0x3a, 0x3b, 0x2a, 0x27, 0x4, 0x6, 0x28, 0x2a, 0x2a, 0x2a, 0x2, 0x3b, +0x25, 0x3c, 0x3b, 0x3b, 0x1f, 0x3, 0x3a, 0x25, 0x3b, 0x3b, 0x1a, 0x28, 0x3b, 0x25, 0x3b, 0x3d, 0x6, 0x3, 0x3c, 0x3b, +0x3c, 0x3c, 0x28, 0x20, 0x27, 0x2a, 0x3d, 0x28, 0x27, 0x20, 0x20, 0x24, 0x2d, 0x27, 0x3d, 0x27, 0x20, 0x20, 0x9, 0x3c, +0xa, 0x20, 0x27, 0x27, 0x27, 0x9, 0x27, 0x3, 0x9, 0x3d, 0x3, 0x6, 0x5, 0x27, 0x9, 0x3, 0x3, 0x20, 0x6, 0x3d, +0x3d, 0x3d, 0x9, 0x20, 0x5, 0x2a, 0x9, 0x3, 0x3d, 0x9, 0x20, 0x5, 0xa, 0x9, 0x3, 0x3, 0x20, 0x6, 0x19, 0x25, +0x9, 0x27, 0x27, 0x28, 0x28, 0x2a, 0x27, 0x27, 0x3a, 0x1b, 0x3, 0x2a, 0x2a, 0x2a, 0x3a, 0x3b, 0x2a, 0x3d, 0x25, 0x25, +0xa, 0x27, 0x5, 0x5, 0x27, 0x5, 0x27, 0x27, 0x6, 0x5, 0x27, 0x3, 0x3a, 0x2a, 0x1a, 0x6, 0x2a, 0x3d, 0x2a, 0x27, +0x2f, 0x1a, 0x27, 0x27, 0x28, 0x2a, 0x28, 0x28, 0x3a, 0x2a, 0x3b, 0x2a, 0x28, 0x1, 0x2a, 0x3b, 0x3a, 0x3b, 0x27, 0x28, +0x3c, 0x3b, 0x30, 0x28, 0x27, 0x20, 0x28, 0x3, 0x3d, 0x3c, 0x27, 0x22, 0x6, 0x28, 0x3d, 0x3, 0x9, 0x20, 0x22, 0x3d, +0x3a, 0x27, 0x3c, 0x27, 0x1a, 0x6, 0x3b, 0x3d, 0x6, 0x6, 0x3f, 0x3f, 0x12, 0x20, 0x3f, 0x3, 0x3, 0x3, 0x28, 0x12, +0x20, 0x27, 0x3d, 0x3b, 0x3, 0x20, 0x6, 0x9, 0x9, 0x3, 0x3, 0x20, 0x6, 0x5, 0x3, 0x3c, 0x3, 0x9, 0x12, 0x5, +0x3d, 0x3d, 0x3, 0xa, 0x20, 0x20, 0x30, 0xc, 0x5, 0x28, 0x3, 0x28, 0x28, 0x28, 0x4, 0x20, 0x28, 0x27, 0x27, 0x28, +0x27, 0x28, 0x3d, 0x2a, 0x2a, 0x3d, 0x3d, 0x3b, 0xa, 0x5, 0x28, 0x20, 0x5, 0x27, 0x5, 0x6, 0x33, 0x6, 0x27, 0x28, +0x28, 0x27, 0x20, 0x2f, 0x28, 0x28, 0x27, 0x28, 0x33, 0x6, 0x2, 0x2a, 0x28, 0x27, 0x4, 0x31, 0x2a, 0x3c, 0x2a, 0x3b, +0x2, 0x2a, 0x3a, 0x3c, 0x3b, 0x3c, 0x1d, 0x4, 0x3c, 0x28, 0x3d, 0x3c, 0x6, 0x28, 0x3, 0x27, 0x3, 0x2a, 0x27, 0x33, +0x27, 0x9, 0x28, 0x30, 0x28, 0x20, 0x22, 0x3b, 0x3b, 0x6, 0x2b, 0x3d, 0x6, 0x20, 0x28, 0x6, 0x9, 0x6, 0x3f, 0x20, +0x28, 0x28, 0xa, 0x27, 0x28, 0x9, 0x27, 0x20, 0x22, 0xa, 0x27, 0x3, 0x28, 0x20, 0x6, 0x28, 0x9, 0x25, 0x5, 0x20, +0x22, 0x5, 0x9, 0x5, 0x3, 0x20, 0x6, 0x5, 0x3, 0x5, 0x3d, 0x5, 0x6, 0x20, 0x25, 0x25, 0xa, 0x28, 0x27, 0x3d, +0x28, 0x2a, 0x5, 0x1a, 0x5, 0x1a, 0x6, 0x1a, 0x22, 0x20, 0x28, 0x2a, 0x27, 0x3c, 0x3d, 0x25, 0x5, 0x5, 0x3, 0x5, +0x27, 0x6, 0x6, 0x5, 0x20, 0x20, 0x6, 0x27, 0x28, 0x28, 0x1e, 0x6, 0x3, 0x28, 0x2a, 0x2, 0x20, 0x32, 0x28, 0x28, +0x27, 0x28, 0x2f, 0x28, 0x2a, 0x2a, 0x3a, 0x35, 0x3b, 0x33, 0x39, 0x2a, 0x3c, 0x2a, 0x3, 0x4, 0x3c, 0x3, 0x3b, 0x3, +0x4, 0x33, 0x3, 0x2a, 0x27, 0x3b, 0x28, 0x20, 0x6, 0x28, 0x28, 0x2a, 0x27, 0x6, 0x20, 0x3c, 0x3c, 0x28, 0x25, 0x3, +0x6, 0x20, 0x3f, 0x20, 0x3, 0x3f, 0x20, 0x3f, 0x20, 0x6, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x5, +0x20, 0x20, 0x20, 0x20, 0x20, 0x6, 0x20, 0x20, 0x3f, 0x27, 0x20, 0x27, 0x5, 0x6, 0x3f, 0x6, 0x5, 0x9, 0x20, 0x12, +0x6, 0x3f, 0x9, 0x3, 0x5, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x28, 0x3c, +0x27, 0x3c, 0x3d, 0x25, 0xa, 0x5, 0x3, 0x20, 0x20, 0x6, 0x4, 0x6, 0x22, 0x31, 0x20, 0x20, 0x2f, 0x6, 0x20, 0x20, +0x1a, 0x4, 0x1f, 0x6, 0x1a, 0x3f, 0x33, 0x6, 0x2, 0x2f, 0x2, 0x2a, 0x4, 0x33, 0x0, 0x28, 0x0, 0x27, 0x2f, 0x3b, +0x27, 0x2f, 0x2f, 0x4, 0x2a, 0x2a, 0x2a, 0x27, 0x6, 0x33, 0x6, 0x20, 0x4, 0x1a, 0x4, 0x3f, 0x22, 0x6, 0x28, 0x27, +0x4, 0x20, 0x3f, 0x1a, 0x3, 0x27, 0x27, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x31, 0x22, 0x31, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, +0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x22, 0x3f, 0x3f, 0x31, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, +0x20, 0x20, 0x20, 0x6, 0x6, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x12, 0x20, 0x20, 0x27, 0x27, 0x4, 0x27, 0x27, 0x27, 0x28, +0x2a, 0x28, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x3c, 0x25, 0x3b, 0xa, 0x6, 0x28, 0x27, 0x3, 0x3, 0x3, 0x28, +0x3d, 0x2a, 0x2a, 0x3, 0x3d, 0x28, 0x3c, 0x38, 0x2a, 0x3c, 0x3a, 0x38, 0x3b, 0x29, 0x2d, 0x3, 0x25, 0x39, 0x3a, 0x2a, +0x38, 0x28, 0x2a, 0x3b, 0x3, 0x2a, 0x30, 0x30, 0x27, 0x28, 0x3, 0x3c, 0x28, 0x28, 0x27, 0x4, 0x28, 0x3b, 0x3, 0x3c, +0x3, 0x3c, 0x3d, 0x5, 0x3d, 0x3d, 0x25, 0x30, 0x3b, 0x28, 0x3d, 0x3d, 0x25, 0x3b, 0x3b, 0x3, 0x3, 0x3, 0x3, 0x3, +0x28, 0x5, 0xa, 0x27, 0x28, 0x9, 0x3, 0x28, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, 0x3d, 0x28, 0x9, 0x3, 0x3d, 0x3d, +0x28, 0x28, 0x28, 0x28, 0x3, 0x9, 0x28, 0x9, 0x9, 0x3, 0x9, 0x3, 0x9, 0x3, 0xa, 0x9, 0x3, 0x9, 0x3, 0x9, +0x5, 0x5, 0x6, 0x27, 0x27, 0x28, 0x3, 0x27, 0x1b, 0x28, 0x28, 0x28, 0x1b, 0x27, 0x28, 0x28, 0x3c, 0x3d, 0x2a, 0x3c, +0x5, 0x5, 0x9, 0x20, 0x6, 0x20, 0x6, 0x5, 0x5, 0x28, 0x3, 0x2a, 0x3, 0x39, 0x3, 0x2a, 0x2a, 0x28, 0x27, 0x3c, +0x3a, 0x38, 0x3a, 0x2d, 0x2d, 0x27, 0x2d, 0x39, 0x2a, 0x2a, 0x1, 0x38, 0x2a, 0x39, 0x3c, 0x3c, 0x28, 0x3c, 0x3c, 0x30, +0x25, 0x2b, 0x25, 0x24, 0x3b, 0x2a, 0x3d, 0x24, 0x3b, 0x24, 0x25, 0x3c, 0x2b, 0x25, 0x25, 0x25, 0x2b, 0x2b, 0x2b, 0x2b, +0x25, 0x2b, 0x2b, 0x2b, 0x2b, 0x24, 0x3b, 0x25, 0x3d, 0x2a, 0x28, 0x3d, 0x25, 0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x2b, +0x3b, 0x3b, 0x25, 0x3d, 0x3b, 0x3b, 0x25, 0x3b, 0x25, 0x25, 0x25, 0x3b, 0x25, 0x3d, 0x3c, 0x25, 0x30, 0x25, 0x3d, 0x3d, +0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0x3, 0x3d, 0x3d, 0x3d, 0x6, 0x6, 0x4, 0x27, 0x27, 0x28, 0x4, 0x2c, 0x27, 0x28, 0x27, +0x2a, 0x3, 0x28, 0x3d, 0x28, 0x3d, 0x2a, 0x3c, 0x5, 0x6, 0x3, 0x20, 0x6, 0x6, 0x5, 0x33, 0x6, 0x1f, 0x3c, 0x3c, +0x25, 0x3d, 0x1, 0x28, 0x27, 0x2a, 0x28, 0x3c, 0x1, 0x30, 0x39, 0x39, 0x30, 0x3c, 0x2a, 0x3b, 0x2b, 0x24, 0x24, 0x2b, +0x28, 0x2b, 0x24, 0x24, 0x24, 0x2b, 0x28, 0x3c, 0x2b, 0x25, 0x24, 0x24, 0x25, 0x5, 0x3c, 0x2b, 0x24, 0x2b, 0x2a, 0x20, +0x24, 0x2b, 0x2b, 0x2b, 0x25, 0x3b, 0x24, 0x25, 0x25, 0x2b, 0x3b, 0x25, 0x24, 0x25, 0x25, 0x2b, 0x25, 0x3b, 0x9, 0x3, +0x3, 0x3d, 0x3, 0x3d, 0x3, 0x3, 0x9, 0x3, 0x3, 0x3, 0x27, 0x3b, 0x3b, 0x3b, 0x3d, 0x3b, 0x2b, 0x38, 0x3d, 0x3, +0x3, 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x30, 0x3d, 0x30, 0x9, 0x3d, 0x3d, 0x3b, 0x3d, 0x3d, 0x9, 0x6, 0x4, 0x1a, +0x27, 0x27, 0x5, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x3d, 0x2a, 0x2a, 0x6, 0xa, 0x27, 0x22, +0x20, 0x6, 0x5, 0x6, 0x27, 0x3d, 0x6, 0x3d, 0x3a, 0x3c, 0x3d, 0x30, 0x25, 0x2b, 0x26, 0x17, 0x17, 0x16, 0x24, 0x24, +0x2b, 0x30, 0x2f, 0x25, 0x2b, 0x21, 0x17, 0x2b, 0x2a, 0x25, 0x21, 0x24, 0x17, 0x25, 0x3c, 0x3c, 0x2b, 0x24, 0x2b, 0x24, +0x30, 0x6, 0x3c, 0x24, 0x2b, 0x24, 0x25, 0x5, 0x2b, 0x2b, 0x25, 0x3c, 0x25, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x25, +0x25, 0x3b, 0x3b, 0x2b, 0x2b, 0x3b, 0x3b, 0x25, 0x25, 0x25, 0x9, 0x3, 0x3d, 0x3d, 0x3, 0x3, 0x3, 0x3, 0x3d, 0x3d, +0x3, 0x3d, 0x3, 0x3d, 0x3c, 0x3d, 0x3d, 0x27, 0x3, 0x28, 0x3d, 0x3, 0x3d, 0x3, 0x3, 0x3, 0x3d, 0x3d, 0x3d, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0x30, 0x20, 0x4, 0x27, 0x5, 0x27, 0x4, 0x28, 0x2f, 0x1d, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, +0x27, 0x3d, 0x28, 0x2a, 0x6, 0x5, 0x27, 0x5, 0x28, 0x28, 0x3, 0x3d, 0x2b, 0x24, 0x17, 0x18, 0x3e, 0x3e, 0x3e, 0x3e, +0x17, 0x18, 0x3e, 0x3e, 0x3e, 0x18, 0x24, 0x17, 0x16, 0x25, 0x35, 0x25, 0x24, 0x18, 0x17, 0x24, 0x3c, 0x3b, 0x17, 0x17, +0x24, 0x24, 0x3b, 0x28, 0x2b, 0x24, 0x24, 0x24, 0x3b, 0x3d, 0x3b, 0x25, 0x24, 0x24, 0x2d, 0x28, 0x2b, 0x24, 0x2b, 0x25, +0x2b, 0x2b, 0x2b, 0x2b, 0x24, 0x3c, 0x3c, 0x25, 0x3b, 0x2b, 0x3b, 0x25, 0x3d, 0x3d, 0x25, 0x25, 0x25, 0x25, 0x30, 0x25, +0x25, 0x3, 0x3, 0x3d, 0x3, 0x3, 0x28, 0x3d, 0x3, 0x27, 0x9, 0x28, 0x9, 0x27, 0x3d, 0x28, 0x3d, 0x28, 0x9, 0x3d, +0x3d, 0x3d, 0x3d, 0xa, 0x3, 0x3d, 0x3, 0x9, 0x9, 0x3d, 0x3d, 0x3d, 0x9, 0x27, 0x28, 0x2a, 0x2f, 0x28, 0x2a, 0x28, +0x2a, 0x2a, 0x2a, 0x28, 0x2a, 0x2a, 0x3d, 0x3, 0x3d, 0x1c, 0x3c, 0x3a, 0x27, 0x20, 0x28, 0x3d, 0x3, 0x3, 0x3, 0x9, +0x3d, 0x25, 0x2b, 0x24, 0x2d, 0x25, 0x24, 0x2b, 0x2b, 0x2d, 0x25, 0x2d, 0x2d, 0x25, 0x2b, 0x24, 0x2b, 0x24, 0x24, 0x24, +0x24, 0x24, 0x2b, 0x25, 0x2b, 0x24, 0x2b, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x2b, 0x24, 0x21, +0x24, 0x17, 0x24, 0x2d, 0x24, 0x24, 0x24, 0x24, 0x2b, 0x24, 0x24, 0x24, 0x2b, 0x24, 0x2b, 0x24, 0x25, 0x25, 0x2b, 0x25, +0x3b, 0x25, 0x3b, 0x2b, 0x25, 0x25, 0x2b, 0x2b, 0x25, 0x25, 0x25, 0x25, 0x2b, 0x25, 0x3b, 0x3b, 0x3d, 0x3, 0x3b, 0x3c, +0x3d, 0x25, 0x3b, 0x25, 0x30, 0x25, 0x2b, 0x25, 0x30, 0x3b, 0x30, 0x30, 0x25, 0x25, 0x25, 0x3d, 0x3b, 0x3b, 0x25, 0x3b, +0x25, 0x5, 0xa, 0x5, 0xa, 0xa, 0x9, 0xa, 0x5, 0xa, 0x28, 0xa, 0x9, 0x9, 0x5, 0x9, 0x3, 0x3d, 0x9, 0x3d, +0xa, 0x5, 0x9, 0x3, 0x3, 0x3d, 0x3d, 0x3b, 0x2b, 0x24, 0x17, 0x17, 0x21, 0x17, 0x16, 0x16, 0x15, 0x18, 0x17, 0x3e, +0x2b, 0x25, 0x21, 0x17, 0x2b, 0x38, 0x27, 0x36, 0x24, 0x17, 0x18, 0x2b, 0x2b, 0x2b, 0x17, 0x18, 0x17, 0x19, 0x10, 0xe, +0x19, 0x17, 0x17, 0x24, 0xe, 0x19, 0x2b, 0x24, 0x17, 0x17, 0x24, 0x3d, 0x19, 0x24, 0x19, 0x18, 0x19, 0x24, 0x2b, 0x2b, +0x19, 0x25, 0x30, 0xb, 0x2b, 0x19, 0x2b, 0x2b, 0x25, 0x25, 0x25, 0x25, 0x25, 0xb, 0x25, 0x30, 0x25, 0x25, 0x25, 0x3d, +0x3d, 0x3d, 0x30, 0x3d, 0x3d, 0x9, 0x3, 0x3d, 0x9, 0x9, 0x9, 0x3d, 0x3, 0x3d, 0x9, 0x3, 0x3, 0xa, 0x9, 0x9, +0x9, 0x9, 0xa, 0x9, 0x3, 0x3, 0x9, 0x9, 0x3d, 0xa, 0x5, 0xa, 0x9, 0x9, 0x9, 0x3, 0xa, 0x5, 0x9, 0x3d, +0x3, 0x3, 0x3d, 0x9, 0x3, 0x3d, 0x9, 0x9, 0xa, 0x5, 0x28, 0x9, 0x9, 0x27, 0x5, 0x6, 0x6, 0x6, 0x6, 0x4, +0x28, 0x5, 0x2a, 0x3b, 0x2d, 0x2b, 0x24, 0x24, 0x17, 0x24, 0x24, 0x17, 0x17, 0x24, 0x38, 0x29, 0x17, 0x16, 0x17, 0x21, +0x25, 0x24, 0x16, 0x17, 0x17, 0x24, 0x2b, 0x2b, 0x24, 0x24, 0x18, 0x17, 0x24, 0x30, 0x19, 0x17, 0x18, 0x24, 0x18, 0x2b, +0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x19, 0x2b, 0x19, 0x2b, 0x25, 0x19, 0x25, 0x2b, 0x19, 0x24, 0xb, 0x2b, 0x25, 0xb, +0x25, 0x25, 0x25, 0xb, 0x3d, 0x30, 0x3d, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, 0x3d, 0x9, 0x30, 0x3d, 0x9, +0x3d, 0x30, 0xc, 0x3d, 0x3, 0x3d, 0x9, 0x3, 0x9, 0x9, 0x3, 0x9, 0x9, 0x9, 0x9, 0x9, 0x3d, 0x9, 0xa, 0x3, +0x3, 0x3, 0x3d, 0x3d, 0xa, 0x5, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, 0x5, 0x5, 0x5, 0x6, +0x6, 0x20, 0x20, 0x6, 0x6, 0x28, 0x27, 0x2a, 0x3, 0x28, 0x2a, 0x28, 0x2c, 0x1a, 0x27, 0x28, 0x2a, 0x3b, 0x2b, 0x25, +0x25, 0x3a, 0x3b, 0x2b, 0x2d, 0x2b, 0x30, 0x25, 0x28, 0x3c, 0x2b, 0x2b, 0x19, 0x2b, 0xe, 0x3d, 0x19, 0x7, 0x24, 0x24, +0xc, 0xa, 0x25, 0x19, 0x24, 0x24, 0x19, 0xe, 0x24, 0x2b, 0x19, 0x19, 0x2b, 0x19, 0x2b, 0x19, 0x25, 0x25, 0x19, 0x25, +0x2b, 0x25, 0x2b, 0x19, 0x25, 0x25, 0x25, 0x25, 0x30, 0xd, 0x25, 0x3d, 0x3d, 0x9, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, +0xd, 0x25, 0xd, 0x3d, 0x30, 0xb, 0x3d, 0x3b, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0xa, 0x9, 0x9, 0x30, 0x9, 0x9, 0x9, +0x3d, 0x3, 0x9, 0x3d, 0xa, 0x9, 0x9, 0x9, 0x9, 0x9, 0x3, 0x9, 0xa, 0x3, 0x3d, 0x9, 0x9, 0x3d, 0x3d, 0x9, +0x9, 0x3d, 0x3d, 0x9, 0xa, 0xa, 0x5, 0x20, 0x5, 0x6, 0x6, 0x6, 0x27, 0x6, 0x27, 0x5, 0x2a, 0x28, 0x28, 0x27, +0x28, 0x2a, 0x28, 0x25, 0x38, 0x25, 0x2b, 0x30, 0x3, 0x2a, 0x2a, 0x28, 0x28, 0x1a, 0x6, 0x27, 0x2a, 0x2a, 0x2a, 0x3d, +0x25, 0x3d, 0x9, 0xd, 0x3, 0x3d, 0xb, 0x2b, 0x25, 0xd, 0x30, 0xb, 0x2b, 0x2b, 0x25, 0xa, 0x3b, 0x3d, 0x9, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0xa, 0x3, 0x3d, 0x3d, 0xe, 0x9, 0x3d, 0x3d, 0x9, 0xa, 0x6, 0xf, 0x6, 0xf, 0x5, +0xa, 0x9, 0x20, 0x5, 0x9, 0x5, 0xa, 0x6, 0xa, 0x3, 0x3, 0x3d, 0x9, 0xa, 0x9, 0x3, 0xa, 0x20, 0x3, 0xa, +0xa, 0x5, 0xa, 0x6, 0x6, 0x10, 0x5, 0x10, 0x5, 0x20, 0x6, 0xa, 0x5, 0x3, 0xa, 0x9, 0x9, 0xa, 0x3, 0x3d, +0x3, 0x3d, 0x3, 0x3, 0x3d, 0x9, 0x3, 0x3d, 0x9, 0x3d, 0x3d, 0x25, 0xa, 0x5, 0x9, 0x3, 0x3d, 0x3d, 0x3, 0x3d, +0x3d, 0x3b, 0x25, 0x25, 0x3c, 0x2a, 0x3, 0x2a, 0x2a, 0x38, 0x3a, 0x30, 0x25, 0x2a, 0x3c, 0x25, 0x3a, 0x2a, 0x2a, 0x28, +0x2a, 0x27, 0x27, 0x0, 0x28, 0x28, 0x2a, 0x28, 0x9, 0x14, 0x3d, 0x3b, 0xe, 0x3d, 0xa, 0x3d, 0xe, 0xa, 0x3d, 0x3d, +0x3, 0xd, 0x9, 0x12, 0xf, 0x3f, 0x10, 0x3f, 0x12, 0x12, 0x12, 0x12, 0x10, 0x3f, 0x12, 0x12, 0x12, 0x9, 0x10, 0x6, +0x12, 0x10, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x20, 0x12, 0x12, 0x3f, 0x3f, 0x3f, 0x12, 0x20, 0x12, 0x12, 0x3f, 0x3f, +0x12, 0x12, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x22, 0x3f, 0x3f, 0x12, 0x3f, 0x12, 0x3f, 0x12, 0x12, 0x12, 0x12, 0x20, +0x12, 0x9, 0x3, 0x9, 0xa, 0x5, 0x20, 0x20, 0x5, 0xa, 0x20, 0x9, 0x20, 0xa, 0x3, 0x3d, 0x28, 0x3d, 0x3d, 0x3d, +0x5, 0x5, 0x3, 0x3f, 0x3f, 0x22, 0x3f, 0x3f, 0x22, 0x3f, 0x31, 0x27, 0x33, 0x20, 0x3f, 0x3f, 0x31, 0x1f, 0x2c, 0x31, +0x31, 0x31, 0x33, 0x2f, 0x31, 0x33, 0x31, 0x3f, 0x22, 0x3f, 0x3f, 0x20, 0x3f, 0x22, 0x31, 0x20, 0x9, 0x10, 0x12, 0xf, +0xf, 0xf, 0xa, 0x5, 0xf, 0x10, 0x12, 0xf, 0x3f, 0x9, 0x3f, 0x10, 0xa, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, +0x12, 0x20, 0x10, 0x9, 0x9, 0xa, 0x6, 0x5, 0x12, 0x6, 0x12, 0x12, 0x6, 0x5, 0x10, 0x6, 0xf, 0x5, 0xa, 0x20, +0xf, 0x6, 0xa, 0x9, 0xa, 0x10, 0x12, 0xa, 0x6, 0x9, 0x20, 0x20, 0x3f, 0x12, 0x6, 0x20, 0x6, 0x20, 0x3f, 0x12, +0x12, 0x20, 0x20, 0x20, 0x10, 0x3f, 0x3, 0x9, 0x20, 0x3d, 0x9, 0x3, 0x9, 0x3d, 0x20, 0x20, 0xa, 0x5, 0xa, 0x9, +0xa, 0x9, 0x9, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0xa, 0x9, 0x28, 0x6, 0x20, 0x20, 0x6, 0x20, 0x22, 0x6, 0x2f, 0x5, +0x27, 0x27, 0x22, 0x20, 0x6, 0x2f, 0x28, 0x1f, 0x28, 0x31, 0x2e, 0x1f, 0x33, 0x6, 0x6, 0x33, 0x20, 0x6, 0x4, 0x20, +0x20, 0x22, 0x4, 0x5, 0x9, 0x3d, 0x10, 0x10, 0xe, 0x5, 0x5, 0x11, 0x20, 0x10, 0xf, 0x5, 0x13, 0xa, 0xa, 0xf, +0x10, 0xf, 0x20, 0x9, 0x12, 0xa, 0x12, 0x3d, 0x3d, 0xf, 0x6, 0xa, 0x12, 0x10, 0x6, 0x9, 0xa, 0x3, 0x3d, 0x9, +0x9, 0x3, 0x9, 0xa, 0x3d, 0x9, 0x9, 0x10, 0xa, 0x5, 0x9, 0x9, 0x3, 0x5, 0x5, 0x3, 0x9, 0x3, 0x9, 0x20, +0x22, 0x5, 0xa, 0xa, 0x9, 0xa, 0x22, 0x20, 0x9, 0x5, 0x9, 0xe, 0xa, 0x12, 0x30, 0x25, 0x9, 0x3d, 0x9, 0x3d, +0x9, 0x3d, 0xa, 0x5, 0x9, 0x3, 0x3, 0x9, 0x9, 0x28, 0x3d, 0x3b, 0x3d, 0x25, 0x3d, 0x3d, 0x5, 0x27, 0x5, 0x6, +0x20, 0x5, 0x5, 0x6, 0x6, 0x6, 0x27, 0x27, 0x28, 0x27, 0x4, 0x4, 0x2a, 0x28, 0x28, 0x2a, 0x0, 0x0, 0x27, 0x2a, +0x2f, 0x2a, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2a, 0x6, 0x2f, 0x27, 0x3d, 0x3d, 0x3d, 0xe, 0xa, 0x3b, 0xd, 0x3d, 0x14, +0x6, 0x10, 0x3d, 0xe, 0x3, 0x3d, 0xa, 0x12, 0x9, 0x3, 0x9, 0x9, 0xa, 0x6, 0xa, 0x30, 0x30, 0x9, 0x10, 0x12, +0xa, 0x3d, 0x6, 0x12, 0x5, 0x20, 0x10, 0x5, 0x5, 0xa, 0x3, 0x9, 0x3, 0x9, 0x3d, 0xa, 0x20, 0x3d, 0x9, 0x3, +0x9, 0x10, 0x20, 0x9, 0xa, 0x9, 0x9, 0x20, 0x20, 0x20, 0x5, 0x3d, 0x9, 0x5, 0x12, 0x20, 0x20, 0x3d, 0xa, 0x3d, +0x20, 0x10, 0x30, 0xc, 0x6, 0x3d, 0x3, 0x9, 0x3d, 0x3d, 0xa, 0x6, 0x3, 0x9, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, +0x25, 0x25, 0xd, 0x3d, 0x9, 0x5, 0x28, 0x5, 0x20, 0x6, 0x5, 0x5, 0x20, 0x31, 0x9, 0x27, 0x28, 0x27, 0x20, 0x33, +0x28, 0x28, 0x27, 0x2f, 0x4, 0x20, 0x2, 0x2f, 0x28, 0x2c, 0x33, 0x2a, 0x28, 0x27, 0x2a, 0x28, 0x6, 0x33, 0x27, 0x3d, +0xd, 0x3d, 0x11, 0x9, 0xd, 0x3d, 0x9, 0x3d, 0x10, 0xd, 0xa, 0x3, 0x3d, 0x14, 0x3, 0x10, 0x5, 0x11, 0x3d, 0xa, +0x9, 0x9, 0xa, 0x25, 0xc, 0xa, 0x3, 0x3d, 0x19, 0x2b, 0x3, 0x5, 0x20, 0x6, 0x9, 0x3, 0x3f, 0x20, 0x12, 0x3d, +0x3d, 0x3d, 0x3d, 0x20, 0x10, 0x3d, 0x3d, 0x3d, 0x3d, 0x5, 0xa, 0x3d, 0x3d, 0x3d, 0x3d, 0x12, 0x6, 0x9, 0x9, 0x3d, +0x9, 0x9, 0x12, 0x6, 0x9, 0x9, 0x3d, 0x9, 0xa, 0x10, 0x2b, 0x3b, 0x9, 0x3d, 0x9, 0x3d, 0x9, 0x3d, 0x5, 0xa, +0x3, 0x9, 0x9, 0x3d, 0x30, 0x3d, 0x3c, 0x25, 0x3d, 0x3b, 0x3d, 0x3d, 0x9, 0x5, 0x3, 0x22, 0x5, 0x5, 0x27, 0x9, +0x20, 0x20, 0x28, 0x3, 0x3d, 0x28, 0x5, 0x6, 0x3d, 0x2a, 0x2a, 0x27, 0x1a, 0x4, 0x27, 0x28, 0x2a, 0x2a, 0x3, 0x33, +0x35, 0x3c, 0x3a, 0x2a, 0x1a, 0x5, 0x2a, 0x25, 0x3d, 0x3d, 0x3d, 0xe, 0x25, 0xc, 0xc, 0x9, 0xa, 0xa, 0x9, 0x14, +0xd, 0x3d, 0x9, 0x12, 0xf, 0x3, 0x3d, 0x3d, 0x3d, 0x12, 0x12, 0x2b, 0x2b, 0x9, 0xd, 0x3d, 0x24, 0x2b, 0x3d, 0x3d, +0x3f, 0x3f, 0x12, 0x9, 0x12, 0x3f, 0x12, 0x25, 0x30, 0xb, 0x3d, 0x5, 0x5, 0x3d, 0x30, 0xc, 0x3b, 0xa, 0x9, 0x3d, +0x25, 0x3d, 0x3d, 0x9, 0x6, 0x9, 0x3d, 0x3d, 0xc, 0x9, 0x20, 0xa, 0x3d, 0x3d, 0xd, 0x9, 0x5, 0xa, 0x17, 0x19, +0x3d, 0x3d, 0x3d, 0x9, 0x3d, 0x3d, 0xa, 0x5, 0x3, 0x25, 0x25, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, +0xa, 0x5, 0x3, 0x12, 0x9, 0x27, 0x9, 0x27, 0x20, 0x6, 0x9, 0x2a, 0x3c, 0x3c, 0x1a, 0x28, 0x2a, 0x3b, 0x3a, 0x25, +0x34, 0x33, 0x28, 0x2a, 0x2a, 0x28, 0x27, 0x20, 0x25, 0x3b, 0x3b, 0x3b, 0x28, 0x2f, 0x2a, 0x3b, 0x25, 0xb, 0x9, 0x3d, +0xc, 0x25, 0x3d, 0x25, 0xe, 0xa, 0x3d, 0x25, 0x3b, 0x3d, 0xd, 0x6, 0x9, 0x30, 0x3d, 0xd, 0x3d, 0xa, 0xa, 0x17, +0x19, 0x3b, 0x3d, 0xa, 0x3d, 0xc, 0x3d, 0x3, 0x30, 0x25, 0x3b, 0x25, 0x3d, 0x25, 0x3d, 0x30, 0xc, 0x3b, 0x3d, 0x20, +0x3, 0x3d, 0x25, 0x25, 0x3d, 0x20, 0xa, 0x3c, 0x25, 0x25, 0x14, 0x6, 0xa, 0x9, 0x3d, 0x3d, 0x3d, 0x3, 0x20, 0x20, +0x3d, 0x3d, 0x3d, 0x3d, 0x10, 0x20, 0x24, 0x19, 0x3, 0x3d, 0x3d, 0x30, 0x3d, 0x3d, 0xa, 0x5, 0x3d, 0x3d, 0x25, 0x3d, +0x3d, 0x3b, 0x3d, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x5, 0xa, 0x28, 0x5, 0x27, 0x28, 0x3, 0x9, 0x20, 0x27, 0x3, 0x2a, +0x3b, 0x28, 0x20, 0x6, 0x3d, 0x25, 0x35, 0x34, 0x1a, 0x27, 0x28, 0x2a, 0x2a, 0x3, 0x28, 0x3d, 0x3b, 0x3a, 0x25, 0x3c, +0x1a, 0x9, 0x3c, 0x3b, 0x25, 0x3d, 0x5, 0xe, 0x25, 0x2b, 0xc, 0x3, 0xf, 0x9, 0xd, 0xc, 0xc, 0x3d, 0x3, 0x10, +0x5, 0x14, 0x3d, 0x3d, 0x3, 0xf, 0x20, 0x24, 0x24, 0x3d, 0xe, 0x5, 0x10, 0x3, 0x3, 0x20, 0x2b, 0xb, 0x25, 0x25, +0x2b, 0x2b, 0x2b, 0x3d, 0x25, 0x9, 0x20, 0x5, 0xa, 0x3d, 0x3d, 0x9, 0x5, 0x20, 0x9, 0x3d, 0x3d, 0x9, 0x10, 0x6, +0x20, 0x3, 0xd, 0x3d, 0xa, 0x12, 0x12, 0x5, 0x9, 0xd, 0x5, 0x12, 0xf, 0x10, 0x19, 0x2b, 0x9, 0x3d, 0x3d, 0x3d, +0x30, 0x3d, 0xa, 0xa, 0x3d, 0x9, 0x3d, 0x3b, 0x3d, 0x3d, 0x3c, 0x3c, 0x25, 0x3d, 0x3d, 0x30, 0xa, 0x6, 0x9, 0x28, +0x5, 0x9, 0x6, 0x20, 0x20, 0x6, 0x3, 0x3d, 0x27, 0x27, 0x4, 0x28, 0x2a, 0x3d, 0x28, 0x33, 0x4, 0x6, 0x28, 0x3, +0x3, 0x1a, 0x20, 0x3b, 0x3d, 0x3b, 0x28, 0x20, 0x27, 0x5, 0x3, 0x3, 0x3, 0x20, 0x20, 0x3d, 0x3d, 0xc, 0x28, 0x20, +0x9, 0xa, 0x3d, 0x3d, 0x3d, 0xa, 0xf, 0x6, 0x5, 0x3d, 0x3b, 0x13, 0x20, 0x20, 0x10, 0x24, 0x19, 0x3d, 0x9, 0x5, +0x6, 0x9, 0x6, 0x3, 0x24, 0x24, 0x24, 0x19, 0x19, 0x24, 0x2b, 0x30, 0x25, 0x3d, 0x12, 0x20, 0x3, 0x3d, 0x30, 0xa, +0x20, 0x5, 0x3, 0x3d, 0x25, 0x3d, 0xa, 0xf, 0x5, 0x3d, 0x3d, 0xd, 0x5, 0x12, 0xa, 0x5, 0x3d, 0x30, 0x9, 0x12, +0x20, 0x20, 0x24, 0x19, 0x3d, 0x3b, 0xd, 0x3d, 0x3d, 0x30, 0x20, 0x27, 0x3d, 0x5, 0x3, 0x3d, 0x25, 0x3d, 0x3c, 0x2d, +0x25, 0x3b, 0x3d, 0x30, 0xa, 0x6, 0x3, 0x3, 0x9, 0x3, 0x5, 0x22, 0x20, 0x27, 0x3d, 0x2a, 0x27, 0x1a, 0x6, 0x28, +0x3c, 0x25, 0x28, 0x1a, 0x20, 0x4, 0x2a, 0x2a, 0x28, 0x20, 0x20, 0x25, 0x3b, 0x3a, 0x28, 0x20, 0x20, 0x27, 0x2a, 0x3d, +0x9, 0x20, 0x5, 0x9, 0x25, 0x25, 0x3d, 0x10, 0xa, 0xa, 0x3d, 0x3d, 0x3d, 0x10, 0x10, 0xa, 0xa, 0x3d, 0x3d, 0x3d, +0x12, 0x10, 0x10, 0x24, 0x24, 0xc, 0x17, 0x17, 0x18, 0x24, 0x18, 0x24, 0x19, 0x24, 0x24, 0x24, 0x2b, 0x2b, 0x19, 0x25, +0x25, 0x3d, 0x20, 0x6, 0x9, 0x25, 0xc, 0x3, 0x20, 0x20, 0x3d, 0x25, 0x25, 0xd, 0x12, 0x10, 0x5, 0x3d, 0x25, 0x3d, +0x5, 0xf, 0x10, 0x9, 0x3, 0xd, 0x3d, 0x10, 0x12, 0x20, 0x19, 0x24, 0x3d, 0x30, 0x3d, 0x3d, 0x3d, 0xc, 0x5, 0x6, +0x3d, 0x3b, 0x3b, 0x25, 0x3d, 0x3b, 0x25, 0x2d, 0x2b, 0x3d, 0x3d, 0x3d, 0xa, 0x1a, 0x28, 0x3d, 0x28, 0x3, 0x5, 0x22, +0x20, 0x27, 0x3c, 0x3c, 0x3, 0x33, 0x6, 0x9, 0x3b, 0x3a, 0x2a, 0x12, 0x20, 0x27, 0x3c, 0x2d, 0x3c, 0x20, 0x20, 0x38, +0x39, 0x2b, 0x3a, 0x20, 0x20, 0x3, 0x3b, 0x25, 0x3d, 0x6, 0x20, 0x3d, 0x25, 0x25, 0x3d, 0x20, 0x6, 0x9, 0xc, 0x25, +0xc, 0xa, 0xa, 0xa, 0x9, 0x9, 0x3d, 0x3d, 0x12, 0x20, 0x20, 0x24, 0x24, 0x3d, 0x17, 0x24, 0x3d, 0x25, 0x25, 0x25, +0x3d, 0x3d, 0x3d, 0x2b, 0xa, 0x9, 0x2b, 0x19, 0x25, 0x30, 0x12, 0x1a, 0x9, 0x25, 0x3b, 0x9, 0x6, 0x5, 0x3d, 0x2b, +0x25, 0x3d, 0xa, 0x5, 0x5, 0x3d, 0xb, 0x3b, 0x20, 0xa, 0x5, 0xe, 0x3d, 0x25, 0x3d, 0xf, 0xa, 0xa, 0x24, 0x24, +0x3d, 0x30, 0x3d, 0x3d, 0x9, 0x3, 0x5, 0xa, 0x3, 0x3d, 0x25, 0x3d, 0x25, 0x25, 0x2b, 0x29, 0x24, 0x3d, 0x3d, 0x3d, +0x6, 0x5, 0x27, 0x3, 0x3d, 0x3, 0x27, 0x20, 0x20, 0x27, 0x3b, 0x2d, 0x2a, 0x1a, 0x6, 0x2a, 0x25, 0x3b, 0x2a, 0x6, +0x1a, 0x5, 0x3, 0x25, 0x2a, 0x20, 0x2a, 0x17, 0x36, 0x3b, 0x3b, 0x1a, 0x6, 0x28, 0x3b, 0x25, 0x3d, 0x6, 0x27, 0x3d, +0x2b, 0x25, 0x3d, 0x20, 0x9, 0xa, 0x25, 0x25, 0x25, 0x10, 0xa, 0x20, 0x3, 0x3d, 0xc, 0x3d, 0xa, 0x5, 0xf, 0x24, +0x18, 0x3d, 0x17, 0x24, 0x25, 0x24, 0x24, 0x2b, 0x2b, 0x19, 0x2b, 0x19, 0x2b, 0x25, 0x2b, 0x21, 0x2b, 0x25, 0x20, 0x5, +0x3d, 0x25, 0x25, 0x25, 0x10, 0xa, 0x3d, 0x19, 0x2b, 0xd, 0x5, 0x10, 0x9, 0x3d, 0x25, 0x25, 0xf, 0xa, 0x10, 0x9, +0x3b, 0xb, 0x3d, 0x5, 0xa, 0x12, 0x18, 0x19, 0x3d, 0x3d, 0x3d, 0x9, 0xa, 0x5, 0x20, 0x6, 0x3d, 0x28, 0x27, 0x28, +0x2f, 0x28, 0x25, 0x2b, 0x24, 0x3, 0x3, 0x3c, 0x27, 0x1a, 0x3, 0x3d, 0x3c, 0x3d, 0x28, 0x1a, 0x6, 0x3, 0x25, 0x25, +0x3b, 0x6, 0x5, 0x3d, 0x2b, 0x25, 0x2a, 0x1f, 0x6, 0x28, 0x3c, 0x3c, 0x25, 0x4, 0x20, 0x2d, 0x37, 0x25, 0x3c, 0x1a, +0x27, 0x3, 0x25, 0x25, 0x25, 0x5, 0xa, 0x3, 0x2b, 0x25, 0x3d, 0x5, 0x6, 0x3, 0x3b, 0x2b, 0xb, 0x9, 0x5, 0xa, +0xa, 0x3b, 0x25, 0x3d, 0x20, 0x6, 0x22, 0x24, 0x24, 0x3d, 0x24, 0x17, 0x25, 0x18, 0x2b, 0x3d, 0x2b, 0x30, 0x2b, 0x3, +0xa, 0x9, 0x2b, 0x17, 0x24, 0x3d, 0x20, 0x5, 0x3, 0x25, 0x2b, 0x30, 0x20, 0x9, 0x3b, 0x2b, 0x25, 0x25, 0x20, 0xa, +0x3, 0x25, 0xb, 0x25, 0xa, 0xa, 0x5, 0x13, 0x2b, 0x30, 0xc, 0xa, 0x6, 0xa, 0x24, 0x24, 0x3d, 0x3, 0xa, 0xa, +0x6, 0x6, 0x20, 0x20, 0x28, 0x4, 0x27, 0x28, 0x3d, 0x1c, 0x24, 0x24, 0x2b, 0x28, 0x27, 0x3d, 0x27, 0x5, 0x6, 0x3, +0x3c, 0x3d, 0x3, 0x20, 0x6, 0x3, 0x25, 0x2d, 0x3a, 0x20, 0x28, 0x3d, 0x29, 0x3b, 0x3a, 0x4, 0x4, 0x28, 0x3c, 0x3b, +0x25, 0x1a, 0x6, 0x3c, 0x29, 0x37, 0x3c, 0x20, 0xa, 0x3d, 0x2d, 0x25, 0x25, 0x5, 0x3, 0x3d, 0x24, 0x25, 0x25, 0x20, +0x6, 0x3, 0x25, 0xb, 0x25, 0x9, 0x10, 0x9, 0xa, 0x2b, 0xc, 0x2a, 0xa, 0x5, 0x6, 0x18, 0x24, 0x3d, 0x19, 0x17, +0x17, 0x30, 0x2b, 0x19, 0x8, 0x2b, 0x19, 0x25, 0x25, 0x3d, 0x17, 0x2b, 0x24, 0x25, 0x6, 0x9, 0x3, 0x25, 0x25, 0x3d, +0x20, 0x3, 0x3b, 0x24, 0x25, 0xc, 0x20, 0xa, 0x9, 0xb, 0x25, 0x25, 0x3d, 0x10, 0x9, 0x3d, 0x3d, 0xb, 0x3d, 0x9, +0x10, 0x5, 0x18, 0x19, 0x3d, 0x9, 0x5, 0x5, 0x20, 0x12, 0x22, 0x28, 0x27, 0x27, 0x28, 0x27, 0x1c, 0x8, 0x24, 0x23, +0x24, 0x2f, 0x27, 0x28, 0x1a, 0x5, 0x6, 0x25, 0x3b, 0x3d, 0x3, 0x20, 0x6, 0x28, 0x25, 0x2b, 0x3c, 0x20, 0x28, 0x3b, +0x24, 0x25, 0x2a, 0x1d, 0x27, 0x27, 0x3b, 0x3b, 0x3c, 0x28, 0x20, 0x21, 0x24, 0x24, 0x38, 0x20, 0x28, 0x3d, 0x25, 0x2b, +0x25, 0x20, 0x9, 0x30, 0x19, 0x25, 0x25, 0x6, 0x5, 0x3, 0x25, 0x25, 0x25, 0x3d, 0x20, 0x9, 0x3, 0x30, 0x25, 0xc, +0x5, 0x20, 0x5, 0x24, 0x24, 0x3d, 0x24, 0x17, 0x3d, 0x12, 0x3, 0x24, 0x19, 0x3d, 0x3b, 0x2b, 0x3d, 0x3d, 0x17, 0x21, +0x24, 0x2b, 0x6, 0x9, 0x3, 0x2b, 0x25, 0x25, 0xa, 0x9, 0x3d, 0x19, 0x2b, 0x3b, 0x5, 0xa, 0x3, 0x30, 0xb, 0x25, +0x5, 0xa, 0xa, 0x9, 0xb, 0x25, 0x25, 0x20, 0xa, 0x10, 0x24, 0x24, 0x3d, 0x9, 0x27, 0x20, 0x22, 0x3f, 0x12, 0x27, +0x27, 0x27, 0x27, 0x28, 0x3d, 0x17, 0x24, 0x23, 0x24, 0x2a, 0x1b, 0x3d, 0x3d, 0x27, 0x5, 0x3c, 0x3b, 0x3c, 0x3d, 0x20, +0x5, 0x3, 0x25, 0x2b, 0x25, 0x4, 0x28, 0x3c, 0x24, 0x3b, 0x2a, 0x27, 0x6, 0x28, 0x3c, 0x3b, 0x3a, 0xa, 0x5, 0x26, +0x24, 0x26, 0x25, 0x27, 0x28, 0x28, 0x2b, 0x2b, 0x25, 0xa, 0x3, 0x30, 0x24, 0x25, 0x3d, 0x9, 0x28, 0x3, 0x30, 0x25, +0x2b, 0xa, 0xa, 0xa, 0x3, 0x25, 0x25, 0x3b, 0x20, 0x6, 0x20, 0x24, 0x24, 0x3, 0x17, 0x17, 0x2b, 0x2b, 0x2b, 0x19, +0x24, 0x25, 0x25, 0x2b, 0x25, 0x3c, 0x16, 0x17, 0x24, 0x2b, 0xa, 0x28, 0x3b, 0x2b, 0x2b, 0x25, 0xa, 0x3, 0x3b, 0x24, +0x19, 0x30, 0xf, 0x9, 0x9, 0x3d, 0x25, 0xc, 0x3d, 0xf, 0x3, 0x3d, 0x25, 0x25, 0xc, 0x9, 0xf, 0x5, 0x18, 0x24, +0x3d, 0x9, 0x5, 0x20, 0x12, 0x22, 0x12, 0x27, 0x27, 0x27, 0x28, 0x28, 0x3d, 0x16, 0x18, 0x24, 0x24, 0x3b, 0x3, 0x3, +0x3d, 0x5, 0x27, 0x3b, 0x3b, 0x3c, 0x3, 0x20, 0x5, 0x28, 0x25, 0x24, 0x2d, 0x5, 0x3, 0x3c, 0x24, 0x2b, 0x25, 0x1a, +0x28, 0x3, 0x3b, 0x3a, 0x3c, 0x27, 0x1a, 0x16, 0x17, 0x21, 0x2b, 0x1d, 0x9, 0x3d, 0x2b, 0x17, 0x2b, 0x9, 0x3, 0x3d, +0x18, 0x25, 0x25, 0x6, 0x3, 0x9, 0x3b, 0xb, 0x25, 0x9, 0x6, 0x3, 0x3, 0x30, 0x25, 0xc, 0x6, 0x6, 0x5, 0x17, +0x24, 0x3d, 0x3e, 0x17, 0x24, 0x17, 0x2b, 0x18, 0x16, 0x25, 0x3e, 0x21, 0x25, 0x3d, 0x17, 0x16, 0x17, 0x2b, 0x6, 0x9, +0x3, 0x25, 0x25, 0x2b, 0xa, 0x27, 0x3d, 0x2b, 0x2b, 0x25, 0x5, 0x5, 0x9, 0x3d, 0x2b, 0x25, 0x9, 0xa, 0x9, 0x9, +0xc, 0x2b, 0x3d, 0xa, 0xa, 0x6, 0x24, 0x19, 0x3d, 0x3, 0x5, 0x12, 0x22, 0x3f, 0x22, 0x5, 0x4, 0x28, 0x3, 0x3d, +0x2a, 0x17, 0x26, 0x24, 0x26, 0x3c, 0x9, 0x6, 0xa, 0x27, 0x5, 0x25, 0x3c, 0x25, 0x9, 0x6, 0x27, 0x3, 0x2b, 0x24, +0x25, 0x1d, 0x28, 0x3d, 0x2b, 0x2d, 0x3b, 0x27, 0x28, 0x27, 0x3d, 0x3b, 0x3b, 0x27, 0x6, 0x17, 0x26, 0x17, 0x2b, 0x5, +0x28, 0x3, 0x24, 0x24, 0x19, 0x9, 0x3d, 0x30, 0x19, 0x24, 0x25, 0xa, 0x27, 0x3, 0x3b, 0x2b, 0x25, 0x3, 0xa, 0x9, +0x3d, 0x25, 0x25, 0x30, 0x6, 0xa, 0x1a, 0x19, 0x24, 0x3d, 0x2b, 0x17, 0x3d, 0x9, 0x3d, 0x24, 0x17, 0x9, 0x24, 0x25, +0x9, 0x2b, 0x17, 0x23, 0x17, 0x25, 0xa, 0x27, 0x3d, 0x2b, 0x24, 0x2b, 0x6, 0xa, 0x25, 0x2b, 0x2b, 0x25, 0x9, 0x9, +0x3, 0x3d, 0xb, 0x25, 0xa, 0xa, 0x9, 0x3, 0x3b, 0x25, 0x3d, 0xa, 0x20, 0x10, 0x18, 0x24, 0xd, 0x28, 0x5, 0x20, +0x12, 0x22, 0x12, 0x5, 0x4, 0x27, 0x27, 0x28, 0x28, 0x24, 0x24, 0x21, 0x24, 0x3, 0x3d, 0x3d, 0x4, 0x27, 0x27, 0x3b, +0x3d, 0x3c, 0x3d, 0x1a, 0x5, 0x3, 0x2d, 0x24, 0x24, 0x6, 0x27, 0x3d, 0x2b, 0x2b, 0x25, 0x2f, 0x27, 0x27, 0x2a, 0x25, +0x3b, 0x6, 0x5, 0x21, 0x16, 0x17, 0x2d, 0x5, 0x28, 0x3, 0x24, 0x24, 0x2b, 0x5, 0x3, 0x3d, 0x2b, 0x2b, 0x25, 0xa, +0x9, 0x3, 0x3b, 0x2b, 0x2b, 0xa, 0x5, 0x6, 0x3, 0x3d, 0x25, 0x3d, 0xa, 0x6, 0x27, 0x21, 0x24, 0x3b, 0x2b, 0x17, +0x2b, 0x2b, 0x25, 0x3, 0x2b, 0x2b, 0x25, 0x2b, 0x2b, 0x24, 0x24, 0x17, 0x17, 0x25, 0x20, 0x9, 0x3, 0x25, 0x25, 0x2b, +0x20, 0x3b, 0x3d, 0x24, 0x2b, 0x25, 0x20, 0x5, 0x9, 0x30, 0x3d, 0x3d, 0xa, 0x5, 0x9, 0x9, 0xc, 0x25, 0x3d, 0xa, +0x6, 0x6, 0x24, 0x24, 0x9, 0x3, 0x6, 0x20, 0x22, 0x12, 0x22, 0x28, 0x5, 0x4, 0x28, 0x2a, 0x2a, 0x24, 0x21, 0x2b, +0x24, 0x3d, 0x3b, 0x3d, 0xa, 0x5, 0x6, 0x3c, 0x3c, 0x3c, 0x28, 0x20, 0x5, 0x28, 0x25, 0x24, 0x25, 0x1a, 0x9, 0x2a, +0x2b, 0x2b, 0x2a, 0x5, 0x5, 0x27, 0x3d, 0x3c, 0x3d, 0x5, 0x1d, 0x24, 0x24, 0x24, 0x25, 0x20, 0x28, 0x3d, 0x2b, 0x24, +0x19, 0x9, 0x9, 0x30, 0x24, 0x25, 0x25, 0x20, 0x3, 0x3d, 0x3d, 0x25, 0x3d, 0xa, 0x6, 0x9, 0x3, 0x2b, 0x25, 0x3d, +0x5, 0x20, 0x5, 0x17, 0x24, 0x3, 0x24, 0x24, 0x25, 0x19, 0x24, 0x3d, 0x3d, 0x2b, 0x2b, 0x2b, 0x25, 0x25, 0x24, 0x17, +0x24, 0x25, 0x6, 0x28, 0xa, 0x25, 0x25, 0x3b, 0x5, 0x3d, 0x3d, 0x2b, 0x25, 0x9, 0x5, 0xa, 0x28, 0x3d, 0x25, 0x25, +0xe, 0x5, 0x5, 0x3d, 0x25, 0x25, 0xd, 0x5, 0x6, 0x20, 0x19, 0x24, 0x3d, 0x3, 0xa, 0x1a, 0x20, 0x20, 0x22, 0x3, +0x27, 0x27, 0x27, 0x28, 0x3d, 0x24, 0x24, 0x24, 0x29, 0x3d, 0x3d, 0x25, 0x10, 0x6, 0x5, 0x3c, 0x3c, 0x3d, 0x3, 0x20, +0xa, 0x27, 0x3b, 0x3b, 0x3b, 0x20, 0x5, 0x3c, 0x2b, 0x25, 0x28, 0x20, 0x5, 0x27, 0x3c, 0x3c, 0x3a, 0x27, 0x6, 0x24, +0x26, 0x24, 0x2b, 0x20, 0x28, 0x2a, 0x25, 0x2b, 0x2b, 0x3, 0x5, 0x3c, 0x19, 0x25, 0x3, 0x5, 0x27, 0x3, 0x30, 0x25, +0x25, 0x9, 0x6, 0x6, 0x3d, 0x3c, 0x25, 0x3b, 0xa, 0x1a, 0x6, 0x24, 0x17, 0x3, 0x17, 0x2b, 0x5, 0x3, 0x9, 0x28, +0x3, 0x9, 0x9, 0x2a, 0x27, 0x9, 0x24, 0x24, 0x24, 0x2b, 0x6, 0x27, 0x28, 0x3b, 0x25, 0x3d, 0x20, 0x5, 0x3d, 0x25, +0x3c, 0x3d, 0x20, 0x6, 0x9, 0x3d, 0x25, 0x3d, 0x9, 0x20, 0x20, 0x5, 0x3d, 0x25, 0x3d, 0x20, 0x20, 0x20, 0x24, 0x18, +0x3, 0x3, 0x27, 0x5, 0x6, 0x6, 0x20, 0x20, 0x28, 0x27, 0x4, 0x27, 0x3, 0x3a, 0x2b, 0x2b, 0x2b, 0x3d, 0x25, 0x3d, +0xa, 0x6, 0x5, 0x3d, 0x3d, 0x3c, 0x28, 0x20, 0x6, 0x5, 0x3b, 0x3b, 0x3d, 0x1d, 0x5, 0x3c, 0x29, 0x3b, 0x2a, 0x20, +0x6, 0x27, 0x3a, 0x3b, 0x3d, 0x5, 0x1a, 0x24, 0x26, 0x24, 0x3b, 0x4, 0x5, 0x28, 0x2b, 0x24, 0x30, 0x20, 0x3d, 0x3d, +0x24, 0x25, 0x3d, 0x3, 0x5, 0x3d, 0x3d, 0x25, 0x3d, 0xa, 0x20, 0x6, 0x3, 0x3b, 0x3b, 0x3d, 0x5, 0x6, 0x28, 0x24, +0x24, 0x3d, 0x17, 0x25, 0x3d, 0x25, 0x25, 0x25, 0x3d, 0x3b, 0x3d, 0x3d, 0x3d, 0x3d, 0x30, 0x24, 0x19, 0x3b, 0x6, 0x20, +0x3d, 0x25, 0x25, 0x3d, 0x20, 0x5, 0x3, 0x25, 0x3b, 0x9, 0x6, 0x20, 0xa, 0x3d, 0x25, 0x25, 0x9, 0xf, 0x6, 0xa, +0x30, 0x3d, 0x3d, 0x20, 0x5, 0x20, 0x19, 0x2b, 0x3d, 0x3, 0x28, 0x27, 0x3, 0x5, 0x20, 0x20, 0x3d, 0x2a, 0x28, 0x27, +0x2a, 0x3d, 0x25, 0x2b, 0x2b, 0x3d, 0x3d, 0x30, 0xa, 0xa, 0x27, 0x9, 0x2a, 0x28, 0x5, 0x20, 0x20, 0x28, 0x25, 0x3a, +0x2a, 0x6, 0x2f, 0x3c, 0x2b, 0x3b, 0x2a, 0x6, 0x20, 0x27, 0x3c, 0x3b, 0x25, 0x28, 0x20, 0x3b, 0x24, 0x2b, 0x3c, 0x6, +0x1a, 0x3c, 0x2b, 0x2b, 0x3b, 0x20, 0x6, 0x3b, 0x2b, 0x30, 0x3d, 0x5, 0x5, 0x28, 0x3b, 0x25, 0x25, 0x5, 0x20, 0x4, +0x28, 0x2b, 0x3d, 0x3d, 0x20, 0x4, 0x28, 0x24, 0x24, 0x3b, 0x21, 0x24, 0x25, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x24, +0x25, 0x25, 0x2b, 0x24, 0x25, 0x3d, 0x20, 0x20, 0x3, 0x3b, 0x3b, 0x3d, 0x20, 0x6, 0x3d, 0x3b, 0x3d, 0x3, 0x20, 0x6, +0x5, 0x3c, 0x3b, 0x3d, 0x5, 0x20, 0x6, 0x5, 0x3d, 0x3d, 0x3d, 0x20, 0x20, 0x12, 0x24, 0x24, 0x3, 0x3d, 0x3d, 0x28, +0x28, 0x3, 0x6, 0x5, 0x3d, 0x3b, 0x3b, 0x25, 0x25, 0x3c, 0x2d, 0x2d, 0x25, 0x3d, 0x3b, 0x3d, 0xa, 0xa, 0x28, 0x3, +0x3d, 0x3, 0x5, 0x22, 0x20, 0x27, 0x3d, 0x3c, 0x3a, 0x1a, 0x6, 0x2a, 0x25, 0x2a, 0x28, 0x1e, 0x2, 0x27, 0x3c, 0x2a, +0x3c, 0x1d, 0x4, 0x2b, 0x24, 0x2b, 0x3c, 0x1a, 0x4, 0x2a, 0x2b, 0x2b, 0x25, 0x6, 0x4, 0x3c, 0x2b, 0x25, 0x3d, 0x6, +0x6, 0x27, 0x3b, 0x25, 0x25, 0x6, 0x27, 0x4, 0x2a, 0x3c, 0x3d, 0x3d, 0x20, 0x6, 0x4, 0x24, 0x24, 0x3c, 0x24, 0x24, +0x17, 0x24, 0x24, 0x17, 0x24, 0x24, 0x17, 0x24, 0x2b, 0x2b, 0x2b, 0x25, 0x25, 0x3c, 0x20, 0x5, 0x2a, 0x3d, 0x3d, 0x9, +0x20, 0x27, 0x9, 0x25, 0x25, 0x3d, 0x20, 0x6, 0x9, 0x3d, 0x25, 0x3d, 0x20, 0x5, 0x6, 0xa, 0x9, 0x3b, 0x3d, 0x20, +0x20, 0x20, 0x24, 0x19, 0x9, 0x3, 0x28, 0x3d, 0x3, 0x3d, 0x5, 0x27, 0x3b, 0x24, 0x24, 0x3b, 0x25, 0x3b, 0x25, 0x2b, +0x3b, 0x3d, 0x3b, 0x3d, 0xa, 0x5, 0xa, 0x28, 0x28, 0x27, 0x5, 0x6, 0x20, 0x27, 0x3a, 0x39, 0x27, 0x20, 0x6, 0x2a, +0x25, 0x2a, 0x3d, 0x31, 0x6, 0x5, 0x2a, 0x3c, 0x2a, 0x6, 0x20, 0x2b, 0x2b, 0x25, 0x3a, 0x27, 0x27, 0x3, 0x3b, 0x25, +0x3d, 0x28, 0x6, 0x3, 0x25, 0x25, 0x3b, 0x20, 0x3c, 0x3b, 0x25, 0x2b, 0x3d, 0x5, 0x3, 0x27, 0x3, 0x3b, 0x3d, 0x3d, +0x31, 0x6, 0x20, 0x17, 0x24, 0x3, 0x24, 0x24, 0x25, 0x24, 0x2b, 0x2b, 0x2b, 0x25, 0x24, 0x24, 0x2b, 0x2b, 0x24, 0x3b, +0x25, 0x3d, 0x6, 0x6, 0x3, 0x3d, 0x3d, 0x3b, 0x5, 0x20, 0x28, 0x25, 0x3c, 0x3d, 0x20, 0x6, 0x4, 0x3, 0x30, 0x30, +0x20, 0x20, 0x12, 0x5, 0x3d, 0x3d, 0x3d, 0x10, 0x22, 0x10, 0x24, 0x2b, 0x3, 0x3, 0x28, 0x2a, 0x2a, 0x2a, 0x5, 0x4, +0x3c, 0x2a, 0x3a, 0x3a, 0x3a, 0x25, 0x3b, 0x25, 0x3b, 0x3d, 0x3d, 0x3d, 0xa, 0x27, 0x5, 0x3d, 0x27, 0x28, 0x5, 0x22, +0x22, 0x27, 0x3, 0x2a, 0x2a, 0x22, 0x6, 0x28, 0x3a, 0x2a, 0x35, 0x1a, 0x6, 0x1a, 0x3, 0x2a, 0x3c, 0x1a, 0x2f, 0x2b, +0x25, 0x2b, 0x3c, 0x33, 0x33, 0x2a, 0x3b, 0x25, 0x3c, 0x20, 0x28, 0x3c, 0x3b, 0x3c, 0x3d, 0x1d, 0x6, 0x28, 0x3b, 0x3b, +0x3d, 0x6, 0x20, 0x4, 0x3, 0x2a, 0x3c, 0x3c, 0x6, 0x33, 0x6, 0x24, 0x2b, 0x3d, 0x3c, 0x3b, 0x27, 0x3, 0x3, 0x3, +0x5, 0x3, 0x2b, 0x25, 0x25, 0x25, 0x30, 0x3b, 0x25, 0x3, 0x20, 0x6, 0x5, 0x30, 0x3d, 0x3, 0x20, 0x20, 0x5, 0x3, +0x3d, 0x3d, 0x20, 0x20, 0x6, 0x3d, 0x3, 0x9, 0x20, 0x20, 0x20, 0x9, 0x28, 0x3d, 0x20, 0x20, 0x6, 0x12, 0x24, 0x2b, +0x3d, 0x3, 0x28, 0x28, 0x28, 0x2a, 0x5, 0x27, 0x2a, 0x27, 0x27, 0x2a, 0x3b, 0x2d, 0x3b, 0x25, 0x2a, 0x3c, 0x3d, 0x30, +0xa, 0x5, 0x9, 0x27, 0x27, 0x28, 0x5, 0x22, 0x20, 0x4, 0x2a, 0x28, 0x27, 0x20, 0x31, 0x27, 0x2a, 0x3c, 0x27, 0x1a, +0x20, 0x20, 0x28, 0x3d, 0x28, 0x6, 0x2f, 0x25, 0x3b, 0x2b, 0x3b, 0x33, 0x27, 0x27, 0x3b, 0x3b, 0x3b, 0x31, 0x2f, 0x3c, +0x3b, 0x3b, 0x2a, 0x33, 0x6, 0x9, 0x3c, 0x3d, 0x28, 0x5, 0x28, 0x6, 0x3, 0x30, 0x3b, 0x27, 0x4, 0x6, 0x2f, 0x2b, +0x24, 0x3d, 0x2a, 0x3d, 0x3d, 0x3, 0x27, 0x5, 0x28, 0x9, 0x2b, 0x2b, 0x25, 0x25, 0x25, 0x3, 0x3b, 0x3d, 0x9, 0x22, +0x5, 0x3d, 0x3, 0x3, 0x5, 0x6, 0x9, 0x3b, 0x3d, 0x9, 0x20, 0x20, 0x3, 0x3b, 0x3d, 0x3d, 0x6, 0x6, 0x12, 0x3, +0x3d, 0x3d, 0x3, 0x12, 0xf, 0x20, 0x24, 0x19, 0x3d, 0x27, 0x28, 0x28, 0x2a, 0x3a, 0x27, 0x27, 0x25, 0x2a, 0x28, 0x27, +0x3a, 0x25, 0x25, 0x25, 0x3b, 0x3d, 0x25, 0x25, 0x20, 0xa, 0x3, 0x27, 0x6, 0x28, 0x6, 0x20, 0x22, 0x5, 0x2a, 0x28, +0x27, 0x20, 0x1a, 0x27, 0x3d, 0x2a, 0x28, 0x1a, 0x22, 0x6, 0x27, 0x28, 0x2a, 0x1a, 0x6, 0x3b, 0x3c, 0x2b, 0x3c, 0x27, +0x20, 0x27, 0x25, 0x3c, 0x3a, 0x28, 0x28, 0x39, 0x25, 0x3b, 0x3d, 0x4, 0x1d, 0x28, 0x30, 0x3d, 0x3c, 0x2a, 0x4, 0x6, +0x27, 0x3, 0x3, 0xa, 0x2a, 0x20, 0x20, 0x2b, 0x24, 0x3d, 0x28, 0x9, 0x28, 0x9, 0x6, 0x28, 0x9, 0x28, 0x25, 0x3c, +0x3c, 0x3d, 0x25, 0x3b, 0x3c, 0x25, 0x3d, 0x6, 0x3, 0x3d, 0x3b, 0x3d, 0x3d, 0x20, 0x27, 0x25, 0x25, 0x30, 0x3, 0x20, +0x5, 0x9, 0x3d, 0x3d, 0x3d, 0x27, 0x6, 0x6, 0x3d, 0x25, 0x3d, 0x9, 0x20, 0x9, 0x24, 0x24, 0x3d, 0x27, 0x27, 0x2a, +0x28, 0x2a, 0x4, 0x4, 0x2a, 0x2a, 0x3a, 0x3b, 0x25, 0x25, 0x35, 0x3b, 0x3a, 0x3b, 0x3b, 0x3d, 0x5, 0x9, 0x28, 0x3, +0x28, 0x28, 0x9, 0x27, 0x22, 0x28, 0x3a, 0x39, 0x3a, 0x28, 0x4, 0x5, 0x3a, 0x3b, 0x2a, 0x27, 0x4, 0x6, 0x28, 0x2a, +0x2a, 0x2a, 0x2, 0x3b, 0x25, 0x3c, 0x3b, 0x3b, 0x1f, 0x3, 0x3a, 0x25, 0x3b, 0x3b, 0x1a, 0x28, 0x3b, 0x25, 0x3b, 0x3d, +0x6, 0x3, 0x3c, 0x3b, 0x3c, 0x3c, 0x28, 0x20, 0x27, 0x2a, 0x3d, 0x28, 0x27, 0x20, 0x20, 0x24, 0x2d, 0x27, 0x3d, 0x27, +0x20, 0x20, 0x9, 0x3c, 0xa, 0x20, 0x27, 0x27, 0x27, 0x9, 0x27, 0x3, 0x9, 0x3d, 0x3, 0x6, 0x5, 0x27, 0x9, 0x3, +0x3, 0x20, 0x6, 0x3d, 0x3d, 0x3d, 0x9, 0x20, 0x5, 0x2a, 0x9, 0x3, 0x3d, 0x9, 0x20, 0x5, 0xa, 0x9, 0x3, 0x3, +0x20, 0x6, 0x19, 0x25, 0x9, 0x27, 0x27, 0x28, 0x28, 0x2a, 0x27, 0x27, 0x3a, 0x1b, 0x3, 0x2a, 0x2a, 0x2a, 0x3a, 0x3b, +0x2a, 0x3d, 0x25, 0x25, 0xa, 0x27, 0x5, 0x5, 0x27, 0x5, 0x27, 0x27, 0x6, 0x5, 0x27, 0x3, 0x3a, 0x2a, 0x1a, 0x6, +0x2a, 0x3d, 0x2a, 0x27, 0x2f, 0x1a, 0x27, 0x27, 0x28, 0x2a, 0x28, 0x28, 0x3a, 0x2a, 0x3b, 0x2a, 0x28, 0x1, 0x2a, 0x3b, +0x3a, 0x3b, 0x27, 0x28, 0x3c, 0x3b, 0x30, 0x28, 0x27, 0x20, 0x28, 0x3, 0x3d, 0x3c, 0x27, 0x22, 0x6, 0x28, 0x3d, 0x3, +0x9, 0x20, 0x22, 0x3d, 0x3a, 0x27, 0x3c, 0x27, 0x1a, 0x6, 0x3b, 0x3d, 0x6, 0x6, 0x3f, 0x3f, 0x12, 0x20, 0x3f, 0x3, +0x3, 0x3, 0x28, 0x12, 0x20, 0x27, 0x3d, 0x3b, 0x3, 0x20, 0x6, 0x9, 0x9, 0x3, 0x3, 0x20, 0x6, 0x5, 0x3, 0x3c, +0x3, 0x9, 0x12, 0x5, 0x3d, 0x3d, 0x3, 0xa, 0x20, 0x20, 0x30, 0xc, 0x5, 0x28, 0x3, 0x28, 0x28, 0x28, 0x4, 0x20, +0x28, 0x27, 0x27, 0x28, 0x27, 0x28, 0x3d, 0x2a, 0x2a, 0x3d, 0x3d, 0x3b, 0xa, 0x5, 0x28, 0x20, 0x5, 0x27, 0x5, 0x6, +0x33, 0x6, 0x27, 0x28, 0x28, 0x27, 0x20, 0x2f, 0x28, 0x28, 0x27, 0x28, 0x33, 0x6, 0x2, 0x2a, 0x28, 0x27, 0x4, 0x31, +0x2a, 0x3c, 0x2a, 0x3b, 0x2, 0x2a, 0x3a, 0x3c, 0x3b, 0x3c, 0x1d, 0x4, 0x3c, 0x28, 0x3d, 0x3c, 0x6, 0x28, 0x3, 0x27, +0x3, 0x2a, 0x27, 0x33, 0x27, 0x9, 0x28, 0x30, 0x28, 0x20, 0x22, 0x3b, 0x3b, 0x6, 0x2b, 0x3d, 0x6, 0x20, 0x28, 0x6, +0x9, 0x6, 0x3f, 0x20, 0x28, 0x28, 0xa, 0x27, 0x28, 0x9, 0x27, 0x20, 0x22, 0xa, 0x27, 0x3, 0x28, 0x20, 0x6, 0x28, +0x9, 0x25, 0x5, 0x20, 0x22, 0x5, 0x9, 0x5, 0x3, 0x20, 0x6, 0x5, 0x3, 0x5, 0x3d, 0x5, 0x6, 0x20, 0x25, 0x25, +0xa, 0x28, 0x27, 0x3d, 0x28, 0x2a, 0x5, 0x1a, 0x5, 0x1a, 0x6, 0x1a, 0x22, 0x20, 0x28, 0x2a, 0x27, 0x3c, 0x3d, 0x25, +0x5, 0x5, 0x3, 0x5, 0x27, 0x6, 0x6, 0x5, 0x20, 0x20, 0x6, 0x27, 0x28, 0x28, 0x1e, 0x6, 0x3, 0x28, 0x2a, 0x2, +0x20, 0x32, 0x28, 0x28, 0x27, 0x28, 0x2f, 0x28, 0x2a, 0x2a, 0x3a, 0x35, 0x3b, 0x33, 0x39, 0x2a, 0x3c, 0x2a, 0x3, 0x4, +0x3c, 0x3, 0x3b, 0x3, 0x4, 0x33, 0x3, 0x2a, 0x27, 0x3b, 0x28, 0x20, 0x6, 0x28, 0x28, 0x2a, 0x27, 0x6, 0x20, 0x3c, +0x3c, 0x28, 0x25, 0x3, 0x6, 0x20, 0x3f, 0x20, 0x3, 0x3f, 0x20, 0x3f, 0x20, 0x6, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x22, 0x20, 0x20, 0x5, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6, 0x20, 0x20, 0x3f, 0x27, 0x20, 0x27, 0x5, 0x6, 0x3f, 0x6, +0x5, 0x9, 0x20, 0x12, 0x6, 0x3f, 0x9, 0x3, 0x5, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, +0x2a, 0x27, 0x28, 0x3c, 0x27, 0x3c, 0x3d, 0x25, 0xa, 0x5, 0x3, 0x20, 0x20, 0x6, 0x4, 0x6, 0x22, 0x31, 0x20, 0x20, +0x2f, 0x6, 0x20, 0x20, 0x1a, 0x4, 0x1f, 0x6, 0x1a, 0x3f, 0x33, 0x6, 0x2, 0x2f, 0x2, 0x2a, 0x4, 0x33, 0x0, 0x28, +0x0, 0x27, 0x2f, 0x3b, 0x27, 0x2f, 0x2f, 0x4, 0x2a, 0x2a, 0x2a, 0x27, 0x6, 0x33, 0x6, 0x20, 0x4, 0x1a, 0x4, 0x3f, +0x22, 0x6, 0x28, 0x27, 0x4, 0x20, 0x3f, 0x1a, 0x3, 0x27, 0x27, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x31, 0x22, 0x31, 0x3f, +0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x22, 0x3f, 0x3f, 0x31, 0x3f, 0x3f, 0x3f, 0x3f, +0x3f, 0x3f, 0x3f, 0x3f, 0x20, 0x20, 0x20, 0x6, 0x6, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x12, 0x20, 0x20, 0x27, 0x27, 0x4, +0x27, 0x27, 0x27, 0x28, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x3c, 0x25, 0x3b, 0xa, 0x6, 0x28, 0x27, +0x3, 0x3, 0x3, 0x28, 0x3d, 0x2a, 0x2a, 0x3, 0x3d, 0x28, 0x3c, 0x38, 0x2a, 0x3c, 0x3a, 0x38, 0x3b, 0x29, 0x2d, 0x3, +0x25, 0x39, 0x3a, 0x2a, 0x38, 0x28, 0x2a, 0x3b, 0x3, 0x2a, 0x30, 0x30, 0x27, 0x28, 0x3, 0x3c, 0x28, 0x28, 0x27, 0x4, +0x28, 0x3b, 0x3, 0x3c, 0x3, 0x3c, 0x3d, 0x5, 0x3d, 0x3d, 0x25, 0x30, 0x3b, 0x28, 0x3d, 0x3d, 0x25, 0x3b, 0x3b, 0x3, +0x3, 0x3, 0x3, 0x3, 0x28, 0x5, 0xa, 0x27, 0x28, 0x9, 0x3, 0x28, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0x3d, 0x3d, 0x28, +0x9, 0x3, 0x3d, 0x3d, 0x28, 0x28, 0x28, 0x28, 0x3, 0x9, 0x28, 0x9, 0x9, 0x3, 0x9, 0x3, 0x9, 0x3, 0xa, 0x9, +0x3, 0x9, 0x3, 0x9, 0x5, 0x5, 0x6, 0x27, 0x27, 0x28, 0x3, 0x27, 0x1b, 0x28, 0x28, 0x28, 0x1b, 0x27, 0x28, 0x28, +0x3c, 0x3d, 0x2a, 0x3c, 0x5, 0x5, 0x9, 0x20, 0x6, 0x20, 0x6, 0x5, 0x5, 0x28, 0x3, 0x2a, 0x3, 0x39, 0x3, 0x2a, +0x2a, 0x28, 0x27, 0x3c, 0x3a, 0x38, 0x3a, 0x2d, 0x2d, 0x27, 0x2d, 0x39, 0x2a, 0x2a, 0x1, 0x38, 0x2a, 0x39, 0x3c, 0x3c, +0x28, 0x3c, 0x3c, 0x30, 0x25, 0x2b, 0x25, 0x24, 0x3b, 0x2a, 0x3d, 0x24, 0x3b, 0x24, 0x25, 0x3c, 0x2b, 0x25, 0x25, 0x25, +0x2b, 0x2b, 0x2b, 0x2b, 0x25, 0x2b, 0x2b, 0x2b, 0x2b, 0x24, 0x3b, 0x25, 0x3d, 0x2a, 0x28, 0x3d, 0x25, 0x3d, 0x3c, 0x3c, +0x3b, 0x3b, 0x3b, 0x2b, 0x3b, 0x3b, 0x25, 0x3d, 0x3b, 0x3b, 0x25, 0x3b, 0x25, 0x25, 0x25, 0x3b, 0x25, 0x3d, 0x3c, 0x25, +0x30, 0x25, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3, 0x3d, 0x3, 0x3d, 0x3d, 0x3d, 0x6, 0x6, 0x4, 0x27, 0x27, 0x28, 0x4, +0x2c, 0x27, 0x28, 0x27, 0x2a, 0x3, 0x28, 0x3d, 0x28, 0x3d, 0x2a, 0x3c, 0x5, 0x6, 0x3, 0x20, 0x6, 0x6, 0x5, 0x33, +0x6, 0x1f, 0x3c, 0x3c, 0x25, 0x3d, 0x1, 0x28, 0x27, 0x2a, 0x28, 0x3c, 0x1, 0x30, 0x39, 0x39, 0x30, 0x3c, 0x2a, 0x3b, +0x2b, 0x24, 0x24, 0x2b, 0x28, 0x2b, 0x24, 0x24, 0x24, 0x2b, 0x28, 0x3c, 0x2b, 0x25, 0x24, 0x24, 0x25, 0x5, 0x3c, 0x2b, +0x24, 0x2b, 0x2a, 0x20, 0x24, 0x2b, 0x2b, 0x2b, 0x25, 0x3b, 0x24, 0x25, 0x25, 0x2b, 0x3b, 0x25, 0x24, 0x25, 0x25, 0x2b, +0x25, 0x3b, 0x9, 0x3, 0x3, 0x3d, 0x3, 0x3d, 0x3, 0x3, 0x9, 0x3, 0x3, 0x3, 0x27, 0x3b, 0x3b, 0x3b, 0x3d, 0x3b, +0x2b, 0x38, 0x3d, 0x3, 0x3, 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x30, 0x3d, 0x30, 0x9, 0x3d, 0x3d, 0x3b, 0x3d, 0x3d, +0x9, 0x6, 0x4, 0x1a, 0x27, 0x27, 0x5, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x27, 0x28, 0x28, 0x28, 0x3d, 0x2a, 0x2a, +0x6, 0xa, 0x27, 0x22, 0x20, 0x6, 0x5, 0x6, 0x27, 0x3d, 0x6, 0x3d, 0x3a, 0x3c, 0x3d, 0x30, 0x25, 0x2b, 0x26, 0x17, +0x17, 0x16, 0x24, 0x24, 0x2b, 0x30, 0x2f, 0x25, 0x2b, 0x21, 0x17, 0x2b, 0x2a, 0x25, 0x21, 0x24, 0x17, 0x25, 0x3c, 0x3c, +0x2b, 0x24, 0x2b, 0x24, 0x30, 0x6, 0x3c, 0x24, 0x2b, 0x24, 0x25, 0x5, 0x2b, 0x2b, 0x25, 0x3c, 0x25, 0x2b, 0x2b, 0x2b, +0x2b, 0x2b, 0x2b, 0x25, 0x25, 0x3b, 0x3b, 0x2b, 0x2b, 0x3b, 0x3b, 0x25, 0x25, 0x25, 0x9, 0x3, 0x3d, 0x3d, 0x3, 0x3, +0x3, 0x3, 0x3d, 0x3d, 0x3, 0x3d, 0x3, 0x3d, 0x3c, 0x3d, 0x3d, 0x27, 0x3, 0x28, 0x3d, 0x3, 0x3d, 0x3, 0x3, 0x3, +0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x30, 0x20, 0x4, 0x27, 0x5, 0x27, 0x4, 0x28, 0x2f, 0x1d, 0x27, 0x28, +0x27, 0x27, 0x27, 0x27, 0x27, 0x3d, 0x28, 0x2a, 0x6, 0x5, 0x27, 0x5, 0x28, 0x28, 0x3, 0x3d, 0x2b, 0x24, 0x17, 0x18, +0x3e, 0x3e, 0x3e, 0x3e, 0x17, 0x18, 0x3e, 0x3e, 0x3e, 0x18, 0x24, 0x17, 0x16, 0x25, 0x35, 0x25, 0x24, 0x18, 0x17, 0x24, +0x3c, 0x3b, 0x17, 0x17, 0x24, 0x24, 0x3b, 0x28, 0x2b, 0x24, 0x24, 0x24, 0x3b, 0x3d, 0x3b, 0x25, 0x24, 0x24, 0x2d, 0x28, +0x2b, 0x24, 0x2b, 0x25, 0x2b, 0x2b, 0x2b, 0x2b, 0x24, 0x3c, 0x3c, 0x25, 0x3b, 0x2b, 0x3b, 0x25, 0x3d, 0x3d, 0x25, 0x25, +0x25, 0x25, 0x30, 0x25, 0x25, 0x3, 0x3, 0x3d, 0x3, 0x3, 0x28, 0x3d, 0x3, 0x27, 0x9, 0x28, 0x9, 0x27, 0x3d, 0x28, +0x3d, 0x28, 0x9, 0x3d, 0x3d, 0x3d, 0x3d, 0xa, 0x3, 0x3d, 0x3, 0x9, 0x9, 0x3d, 0x3d, 0x3d, 0x9, 0x27, 0x28, 0x2a, +0x2f, 0x28, 0x2a, 0x28, 0x2a, 0x2a, 0x2a, 0x28, 0x2a, 0x2a, 0x3d, 0x3, 0x3d, 0x1c, 0x3c, 0x3a, 0x27, 0x20, 0x28, 0x3d, +0x3, 0x3, 0x3, 0x9, 0x3d, 0x25, 0x2b, 0x24, 0x2d, 0x25, 0x24, 0x2b, 0x2b, 0x2d, 0x25, 0x2d, 0x2d, 0x25, 0x2b, 0x24, +0x2b, 0x24, 0x24, 0x24, 0x24, 0x24, 0x2b, 0x25, 0x2b, 0x24, 0x2b, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, +0x24, 0x2b, 0x24, 0x21, 0x24, 0x17, 0x24, 0x2d, 0x24, 0x24, 0x24, 0x24, 0x2b, 0x24, 0x24, 0x24, 0x2b, 0x24, 0x2b, 0x24, +0x25, 0x25, 0x2b, 0x25, 0x3b, 0x25, 0x3b, 0x2b, 0x25, 0x25, 0x2b, 0x2b, 0x25, 0x25, 0x25, 0x25, 0x2b, 0x25, 0x3b, 0x3b, +0x3d, 0x3, 0x3b, 0x3c, 0x3d, 0x25, 0x3b, 0x25, 0x30, 0x25, 0x2b, 0x25, 0x30, 0x3b, 0x30, 0x30, 0x25, 0x25, 0x25, 0x3d, +0x3b, 0x3b, 0x25, 0x3b, 0x25, 0xf, 0x47, 0x65, 0x42, 0x6d, 0x40, 0x9, 0x1, 0x0, 0x44, 0x2d, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x47, 0x65, +0x42, 0x6d, 0x40, 0x9, 0x1, 0x0, 0x44, 0x2d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x44, 0x54, 0x30, 0x31, 0x49, 0x1, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x42, +0x69, 0x74, 0x6d, 0x61, 0x70, 0x73, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x31, +0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x5, 0x0, 0x0, 0x91, 0x19, +0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x33, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x5, 0x0, 0x0, 0x85, 0x14, 0x2, 0x0, +0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x32, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x44, 0x0, 0x0, 0x79, 0xd0, 0x1, 0x0, 0x0, 0x0, +0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x14, 0x0, 0x0, 0x6d, 0xbc, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, +0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x44, 0x0, 0x0, 0x61, 0x78, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x47, 0x65, 0x6f, 0x6d, 0x65, 0x74, +0x72, 0x79, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x78, 0x1, 0x0, 0x18, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4d, +0x54, 0x4e, 0x42, 0xf0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x2, 0x47, 0x65, 0x6e, 0x33, 0x64, 0x31, 0x35, 0x0, 0x50, +0x0, 0x0, 0x0, 0xa6, 0x55, 0x62, 0xb4, 0x2, 0x0, 0x0, 0x0, 0x53, 0x42, 0x4b, 0x42, 0x50, 0x0, 0x0, 0x0, 0xaa, +0x3, 0x0, 0x0, 0x40, 0x1, 0x0, 0x0, 0x45, 0x1, 0x0, 0x0, 0x4c, 0x1, 0x0, 0x0, 0x55, 0x1, 0x0, 0x0, 0x5e, +0x1, 0x0, 0x0, 0x67, 0x1, 0x0, 0x0, 0x6f, 0x1, 0x0, 0x0, 0x77, 0x1, 0x0, 0x0, 0x7f, 0x1, 0x0, 0x0, 0x87, +0x1, 0x0, 0x0, 0x8f, 0x1, 0x0, 0x0, 0x97, 0x1, 0x0, 0x0, 0x9f, 0x1, 0x0, 0x0, 0xa7, 0x1, 0x0, 0x0, 0xaf, +0x1, 0x0, 0x0, 0xb7, 0x1, 0x0, 0x0, 0xbf, 0x1, 0x0, 0x0, 0xc7, 0x1, 0x0, 0x0, 0xcf, 0x1, 0x0, 0x0, 0xd7, +0x1, 0x0, 0x0, 0xdf, 0x1, 0x0, 0x0, 0xe7, 0x1, 0x0, 0x0, 0xef, 0x1, 0x0, 0x0, 0xf7, 0x1, 0x0, 0x0, 0xff, +0x1, 0x0, 0x0, 0x7, 0x2, 0x0, 0x0, 0xf, 0x2, 0x0, 0x0, 0x17, 0x2, 0x0, 0x0, 0x1f, 0x2, 0x0, 0x0, 0x27, +0x2, 0x0, 0x0, 0x30, 0x2, 0x0, 0x0, 0x39, 0x2, 0x0, 0x0, 0x42, 0x2, 0x0, 0x0, 0x49, 0x2, 0x0, 0x0, 0x51, +0x2, 0x0, 0x0, 0x59, 0x2, 0x0, 0x0, 0x60, 0x2, 0x0, 0x0, 0x68, 0x2, 0x0, 0x0, 0x6f, 0x2, 0x0, 0x0, 0x76, +0x2, 0x0, 0x0, 0x7e, 0x2, 0x0, 0x0, 0x85, 0x2, 0x0, 0x0, 0x8c, 0x2, 0x0, 0x0, 0x94, 0x2, 0x0, 0x0, 0x9b, +0x2, 0x0, 0x0, 0xa2, 0x2, 0x0, 0x0, 0xaa, 0x2, 0x0, 0x0, 0xb1, 0x2, 0x0, 0x0, 0xb8, 0x2, 0x0, 0x0, 0xc0, +0x2, 0x0, 0x0, 0xc7, 0x2, 0x0, 0x0, 0xce, 0x2, 0x0, 0x0, 0xd6, 0x2, 0x0, 0x0, 0xdd, 0x2, 0x0, 0x0, 0xe4, +0x2, 0x0, 0x0, 0xec, 0x2, 0x0, 0x0, 0xf3, 0x2, 0x0, 0x0, 0xfb, 0x2, 0x0, 0x0, 0x4, 0x3, 0x0, 0x0, 0xb, +0x3, 0x0, 0x0, 0x12, 0x3, 0x0, 0x0, 0x19, 0x3, 0x0, 0x0, 0x20, 0x3, 0x0, 0x0, 0x28, 0x3, 0x0, 0x0, 0x2f, +0x3, 0x0, 0x0, 0x3b, 0x3, 0x0, 0x0, 0x43, 0x3, 0x0, 0x0, 0x4a, 0x3, 0x0, 0x0, 0x55, 0x3, 0x0, 0x0, 0x5d, +0x3, 0x0, 0x0, 0x64, 0x3, 0x0, 0x0, 0x6b, 0x3, 0x0, 0x0, 0x73, 0x3, 0x0, 0x0, 0x7a, 0x3, 0x0, 0x0, 0x81, +0x3, 0x0, 0x0, 0x89, 0x3, 0x0, 0x0, 0x90, 0x3, 0x0, 0x0, 0x96, 0x3, 0x0, 0x0, 0x9d, 0x3, 0x0, 0x0, 0xa3, +0x3, 0x0, 0x0, 0x52, 0x4f, 0x4f, 0x54, 0x0, 0x4c, 0x49, 0x4e, 0x4b, 0x54, 0x4f, 0x0, 0x43, 0x4f, 0x52, 0x4f, 0x4e, +0x41, 0x30, 0x31, 0x0, 0x43, 0x52, 0x5f, 0x45, 0x46, 0x30, 0x31, 0x41, 0x0, 0x43, 0x52, 0x5f, 0x45, 0x46, 0x30, 0x31, +0x42, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x31, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x32, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x30, 0x33, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x34, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, +0x35, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x36, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x37, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x30, 0x38, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x30, 0x39, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, +0x30, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x31, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x32, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x31, 0x33, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x34, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, +0x35, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x36, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x37, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x31, 0x38, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x31, 0x39, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x32, +0x30, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x32, 0x31, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x32, 0x32, 0x0, 0x4c, 0x49, +0x47, 0x48, 0x54, 0x32, 0x33, 0x0, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x32, 0x34, 0x0, 0x43, 0x4f, 0x52, 0x4f, 0x4e, 0x41, +0x30, 0x32, 0x0, 0x43, 0x46, 0x5f, 0x45, 0x46, 0x30, 0x32, 0x41, 0x0, 0x43, 0x52, 0x5f, 0x45, 0x46, 0x30, 0x32, 0x42, +0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x31, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x31, 0x42, 0x0, 0x47, 0x45, 0x41, 0x52, +0x30, 0x31, 0x43, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x32, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x32, 0x42, 0x0, 0x42, +0x4f, 0x4e, 0x45, 0x30, 0x33, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x33, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x33, 0x42, +0x0, 0x42, 0x4f, 0x4e, 0x45, 0x30, 0x36, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x34, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, +0x34, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x30, 0x39, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x35, 0x0, 0x47, 0x45, 0x41, +0x52, 0x30, 0x35, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x31, 0x32, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x36, 0x0, 0x47, +0x45, 0x41, 0x52, 0x30, 0x36, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x31, 0x35, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x37, +0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x37, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x31, 0x38, 0x0, 0x47, 0x45, 0x41, 0x52, +0x30, 0x38, 0x0, 0x47, 0x45, 0x41, 0x52, 0x30, 0x38, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x31, 0x0, 0x47, 0x45, +0x4e, 0x45, 0x53, 0x49, 0x53, 0x0, 0x47, 0x45, 0x4e, 0x45, 0x53, 0x49, 0x53, 0x42, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x30, +0x37, 0x0, 0x43, 0x4f, 0x52, 0x4f, 0x4e, 0x41, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x31, 0x36, 0x0, 0x42, 0x4f, 0x4e, 0x45, +0x30, 0x31, 0x0, 0x42, 0x49, 0x47, 0x47, 0x45, 0x41, 0x52, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x31, 0x30, 0x0, 0x53, 0x4d, +0x5f, 0x4c, 0x45, 0x46, 0x54, 0x50, 0x53, 0x54, 0x4e, 0x0, 0x4c, 0x5f, 0x43, 0x59, 0x4c, 0x30, 0x32, 0x0, 0x42, 0x4f, +0x4e, 0x45, 0x32, 0x32, 0x0, 0x4c, 0x45, 0x46, 0x54, 0x50, 0x49, 0x53, 0x54, 0x4f, 0x4e, 0x0, 0x4c, 0x5f, 0x43, 0x59, +0x4c, 0x30, 0x31, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x35, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x36, 0x0, 0x52, 0x5f, +0x43, 0x59, 0x4c, 0x30, 0x32, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x38, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x39, 0x0, +0x52, 0x5f, 0x43, 0x59, 0x4c, 0x30, 0x31, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x33, 0x31, 0x0, 0x41, 0x52, 0x43, 0x30, 0x32, +0x0, 0x42, 0x4f, 0x4e, 0x45, 0x33, 0x33, 0x0, 0x41, 0x52, 0x43, 0x30, 0x31, 0x0, 0x42, 0x4f, 0x4e, 0x45, 0x32, 0x33, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x86, 0xb5, 0x0, 0x0, 0x0, 0x0, 0x7, 0xef, 0xc3, 0x3e, 0x0, 0x0, 0x0, +0x0, 0x66, 0x83, 0x6c, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x86, 0x35, 0x0, 0x0, 0x0, +0x0, 0x7, 0xef, 0xc3, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x66, 0x83, 0x6c, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0xbd, 0x37, 0x86, 0xb5, 0x0, 0x0, 0x0, 0x0, 0x7, 0xef, 0xc3, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x66, 0x83, 0x6c, +0xbf, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x86, 0x35, 0x0, 0x0, 0x0, 0x0, 0x7, 0xef, 0xc3, +0x3e, 0x0, 0x0, 0x0, 0x0, 0x66, 0x83, 0x6c, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x88, 0x8, 0x3d, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0xbd, 0x37, 0x86, 0x35, 0x0, 0x0, 0x0, 0x0, 0xa, 0xf6, 0x7f, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf7, 0x8e, +0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xbf, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x44, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x88, 0x8, 0x3d, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x86, 0xb5, 0x0, 0x0, 0x0, 0x0, 0xa, 0xf6, 0x7f, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf7, 0x8e, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x2f, 0x88, 0x8, 0x3d, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x86, +0x35, 0x0, 0x0, 0x0, 0x0, 0xa, 0xf6, 0x7f, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf7, 0x8e, 0xbc, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x88, 0x8, 0x3d, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x86, 0xb5, 0x0, 0x0, 0x0, 0x0, 0xa, 0xf6, 0x7f, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x7f, 0xf7, 0x8e, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9d, 0x46, 0x5a, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x6e, 0xc2, 0x5, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x2, 0x1, 0x10, 0x8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x20, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x88, 0x8, 0x3d, 0x2f, 0x88, 0x88, 0x3d, 0x47, 0xcc, 0xcc, 0x3d, 0x2f, 0x88, 0x8, +0x3e, 0x3b, 0xaa, 0x2a, 0x3e, 0x47, 0xcc, 0x4c, 0x3e, 0x52, 0xee, 0x6e, 0x3e, 0x2f, 0x88, 0x88, 0x3e, 0x35, 0x99, 0x99, +0x3e, 0x3b, 0xaa, 0xaa, 0x3e, 0x41, 0xbb, 0xbb, 0x3e, 0x47, 0xcc, 0xcc, 0x3e, 0x4c, 0xdd, 0xdd, 0x3e, 0x52, 0xee, 0xee, +0x3e, 0x58, 0xff, 0xff, 0x3e, 0x2f, 0x88, 0x8, 0x3f, 0xb2, 0x10, 0x11, 0x3f, 0x35, 0x99, 0x19, 0x3f, 0xb8, 0x21, 0x22, +0x3f, 0x3b, 0xaa, 0x2a, 0x3f, 0xbe, 0x32, 0x33, 0x3f, 0x41, 0xbb, 0x3b, 0x3f, 0xc4, 0x43, 0x44, 0x3f, 0x47, 0xcc, 0x4c, +0x3f, 0xca, 0x54, 0x55, 0x3f, 0x4c, 0xdd, 0x5d, 0x3f, 0xcf, 0x65, 0x66, 0x3f, 0x52, 0xee, 0x6e, 0x3f, 0xd5, 0x76, 0x77, +0x3f, 0x58, 0xff, 0x7f, 0x3f, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xa0, 0xdb, 0xf, 0x41, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0xb7, 0x90, 0xd3, 0x90, 0x41, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x70, 0xda, 0x41, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x70, 0x41, 0x12, +0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x65, 0x37, 0x42, 0x0, 0x0, 0x0, 0x0, 0x82, 0xa8, 0x7b, +0xb7, 0xd8, 0x82, 0x5c, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf6, 0xbc, 0x80, 0x42, 0x0, 0x0, 0x0, +0x0, 0xbd, 0x37, 0x6, 0x37, 0xf8, 0x14, 0x93, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x28, 0x39, 0xa5, +0x42, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0xb7, 0x42, 0x19, 0xb7, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xa, 0xa5, 0xc8, 0x42, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x42, 0xcc, 0xd9, 0x42, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0xa4, 0x7e, 0xea, 0x42, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0xb7, 0xe4, 0xab, 0xfa, +0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe8, 0x21, 0x5, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xe, 0x9b, 0xc, 0x43, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x46, 0xb9, 0x13, 0x43, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x6d, 0x74, 0x1a, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x62, 0xc4, 0x20, +0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xa1, 0x26, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x35, 0x2, 0x2c, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd1, 0xdf, 0x30, 0x43, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0xb8, 0x31, 0x35, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc8, 0xef, 0x38, +0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe2, 0x11, 0x3c, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xe3, 0x8f, 0x3e, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xac, 0x61, 0x40, 0x43, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x1a, 0x7f, 0x41, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xe0, 0x41, +0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xe0, 0x41, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xc, 0xe0, 0x41, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x2, 0x1, 0x10, 0x68, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x16, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x88, 0x8, 0x3d, 0x2f, 0x88, 0x88, 0x3d, 0x47, 0xcc, 0xcc, 0x3d, 0x2f, 0x88, 0x8, +0x3e, 0x3b, 0xaa, 0x2a, 0x3e, 0x47, 0xcc, 0x4c, 0x3e, 0x52, 0xee, 0x6e, 0x3e, 0x2f, 0x88, 0x88, 0x3e, 0x35, 0x99, 0x99, +0x3e, 0x3b, 0xaa, 0xaa, 0x3e, 0x41, 0xbb, 0xbb, 0x3e, 0x47, 0xcc, 0xcc, 0x3e, 0x4c, 0xdd, 0xdd, 0x3e, 0x52, 0xee, 0xee, +0x3e, 0x58, 0xff, 0xff, 0x3e, 0x2f, 0x88, 0x8, 0x3f, 0xb2, 0x10, 0x11, 0x3f, 0x35, 0x99, 0x19, 0x3f, 0xb8, 0x21, 0x22, +0x3f, 0x3b, 0xaa, 0x2a, 0x3f, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x40, 0xcb, 0xde, 0x40, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0xc0, 0x43, 0x61, 0x41, 0x0, 0x0, 0x0, +0x0, 0xbd, 0x37, 0x6, 0x37, 0xd0, 0x50, 0xaa, 0x41, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x60, 0x43, 0xe4, +0x41, 0x0, 0x0, 0x0, 0x0, 0x82, 0xa8, 0x7b, 0x37, 0xc8, 0xfe, 0xe, 0x42, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, +0xb7, 0x48, 0x81, 0x2b, 0x42, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x60, 0x6b, 0x47, 0x42, 0x82, 0xa8, 0x7b, +0xb7, 0x82, 0xa8, 0x7b, 0xb7, 0xb0, 0x7e, 0x62, 0x42, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x50, 0x7d, 0x7c, +0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x94, 0x8a, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xc8, 0x21, 0x96, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xc7, 0xa0, 0x42, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x94, 0x66, 0xaa, 0x42, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0xb7, 0xf0, 0xdf, 0xb2, +0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x84, 0x14, 0xba, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x46, 0xe5, 0xbf, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x33, 0xc4, 0x42, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xdf, 0xc6, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0xc9, 0xc7, +0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0xc9, 0xc7, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xe0, 0xc9, 0xc7, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x2, 0x1, 0x10, 0x8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x20, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x88, 0x8, 0x3d, 0x2f, 0x88, 0x88, 0x3d, 0x47, 0xcc, 0xcc, 0x3d, 0x2f, 0x88, 0x8, +0x3e, 0x47, 0xcc, 0x4c, 0x3e, 0x52, 0xee, 0x6e, 0x3e, 0x2f, 0x88, 0x88, 0x3e, 0x35, 0x99, 0x99, 0x3e, 0x3b, 0xaa, 0xaa, +0x3e, 0x41, 0xbb, 0xbb, 0x3e, 0x47, 0xcc, 0xcc, 0x3e, 0x4c, 0xdd, 0xdd, 0x3e, 0x52, 0xee, 0xee, 0x3e, 0x58, 0xff, 0xff, +0x3e, 0x2f, 0x88, 0x8, 0x3f, 0xb2, 0x10, 0x11, 0x3f, 0x35, 0x99, 0x19, 0x3f, 0xb8, 0x21, 0x22, 0x3f, 0x3b, 0xaa, 0x2a, +0x3f, 0xbe, 0x32, 0x33, 0x3f, 0x41, 0xbb, 0x3b, 0x3f, 0xc4, 0x43, 0x44, 0x3f, 0x47, 0xcc, 0x4c, 0x3f, 0xca, 0x54, 0x55, +0x3f, 0x4c, 0xdd, 0x5d, 0x3f, 0xcf, 0x65, 0x66, 0x3f, 0x52, 0xee, 0x6e, 0x3f, 0xd5, 0x76, 0x77, 0x3f, 0x58, 0xff, 0x7f, +0x3f, 0xee, 0x43, 0x84, 0x3f, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x80, 0x99, 0x5b, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfd, 0xdc, 0xc0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9b, 0x26, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xd, 0x5f, +0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x1e, 0xa8, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xe8, 0x4e, 0xc4, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa0, 0x4e, 0xe0, 0xc1, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x90, 0x6, 0xfc, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0xaf, 0xb, +0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa0, 0x21, 0x19, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xc, 0x4d, 0x26, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa8, 0x26, 0x33, 0xc2, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0xfc, 0xa2, 0x3f, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0xb6, 0x4b, +0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd4, 0x55, 0x57, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x64, 0x75, 0x62, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc4, 0x9, 0x6d, 0xc2, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x6c, 0x7, 0x77, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x74, 0x31, 0x80, +0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x88, 0x84, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xb8, 0x82, 0x88, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc2, 0x1a, 0x8c, 0xc2, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0x4a, 0x8f, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf4, 0xc, 0x92, +0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa2, 0x5b, 0x94, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xa, 0x31, 0x96, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x70, 0x87, 0x97, 0xc2, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x59, 0x98, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xa0, 0x98, +0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xa0, 0x98, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x3e, 0xa0, 0x98, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x2, 0x1, 0x10, 0x78, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x17, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x88, 0x8, 0x3d, 0x2f, 0x88, 0x88, 0x3d, 0x47, 0xcc, 0xcc, 0x3d, 0x2f, 0x88, 0x8, +0x3e, 0x3b, 0xaa, 0x2a, 0x3e, 0x47, 0xcc, 0x4c, 0x3e, 0x52, 0xee, 0x6e, 0x3e, 0x2f, 0x88, 0x88, 0x3e, 0x35, 0x99, 0x99, +0x3e, 0x3b, 0xaa, 0xaa, 0x3e, 0x41, 0xbb, 0xbb, 0x3e, 0x47, 0xcc, 0xcc, 0x3e, 0x4c, 0xdd, 0xdd, 0x3e, 0x52, 0xee, 0xee, +0x3e, 0x58, 0xff, 0xff, 0x3e, 0x2f, 0x88, 0x8, 0x3f, 0xb2, 0x10, 0x11, 0x3f, 0x35, 0x99, 0x19, 0x3f, 0xb8, 0x21, 0x22, +0x3f, 0x3b, 0xaa, 0x2a, 0x3f, 0xbe, 0x32, 0x33, 0x3f, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x81, 0x20, 0x17, 0xc0, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0xff, 0xbe, 0x98, +0xc0, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x41, 0xf3, 0xe6, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0xe0, 0xc9, 0x1a, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x20, 0xf0, 0xc0, 0x37, 0x80, 0x5, 0x42, 0xc1, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0xa0, 0xdf, 0x68, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x82, 0xa8, 0x7b, 0x37, 0x30, 0x86, 0x87, +0xc1, 0x0, 0x0, 0x0, 0x0, 0x20, 0xf0, 0xc0, 0x37, 0x20, 0x20, 0x9a, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x40, 0x17, 0xac, 0xc1, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0xe0, 0x45, 0xbd, 0xc1, 0x0, 0x0, 0x0, +0x0, 0xbd, 0x37, 0x6, 0x37, 0xd0, 0x85, 0xcd, 0xc1, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x40, 0xb1, 0xdc, +0xc1, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x10, 0xa2, 0xea, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x50, 0x32, 0xf7, 0xc1, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x0, 0x1e, 0x1, 0xc2, 0x0, 0x0, 0x0, +0x0, 0xbd, 0x37, 0x6, 0x37, 0x88, 0xcc, 0x5, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x82, 0xa8, 0x7b, 0x37, 0xd0, 0x91, 0x9, +0xc2, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0xd0, 0x5a, 0xc, 0xc2, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, +0x37, 0x90, 0x14, 0xe, 0xc2, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x8, 0xac, 0xe, 0xc2, 0x0, 0x0, 0x0, +0x0, 0xbd, 0x37, 0x6, 0x37, 0x8, 0xac, 0xe, 0xc2, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x8, 0xac, 0xe, +0xc2, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x37, 0x6, 0x37, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, +0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, +0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, +0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x2, 0x1, 0x10, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82, 0xff, 0x3f, 0x40, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x54, 0x30, 0x31, 0xd7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x4d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, +0x73, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd6, 0x1b, 0x0, 0x0, 0xe, 0x20, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x42, 0x6f, 0x64, 0x79, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6, 0x1f, 0x2, 0x0, 0x28, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x48, 0x65, 0x61, +0x64, 0x65, 0x72, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, +0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +int LogoActor_act_Length = sizeof(LogoActor_act); diff --git a/G3D/Engine/Logo/WebUrl.c b/G3D/Engine/Logo/WebUrl.c new file mode 100644 index 0000000..415d983 --- /dev/null +++ b/G3D/Engine/Logo/WebUrl.c @@ -0,0 +1,3356 @@ +/****************************************************************************************/ +/* WEBURL.C */ +/* */ +/* Author: */ +/* Description: Embedded web url bitmap */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +unsigned char WebUrl_bmp[] = { +66, 77, 56, 4, 1, 0, 0, 0, 0, 0, 54, 4, 0, 0, 40, 0, 0, 0, 0, 1, +0, 0, 0, 1, 0, 0, 1, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 46, +0, 0, 32, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 238, 238, +238, 0, 222, 222, 222, 0, 206, 206, 206, 0, 199, 199, 199, 0, 187, 187, 187, 0, 177, 177, +177, 0, 171, 171, 171, 0, 154, 154, 154, 0, 138, 138, 138, 0, 118, 118, 118, 0, 102, 102, +102, 0, 86, 86, 86, 0, 69, 69, 69, 0, 50, 50, 50, 0, 34, 34, 34, 0, 18, 18, +18, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 13, 13, 13, 14, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 13, 3, 0, 0, 0, 0, 0, 1, 8, 16, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 14, +0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 8, 0, 0, 0, 1, +9, 9, 0, 0, 0, 0, 11, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 5, 3, 5, 8, 12, 17, 17, 8, 0, +0, 0, 5, 17, 17, 17, 17, 17, 17, 15, 13, 13, 14, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 15, 13, 13, 14, +17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 13, 13, 13, 14, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 13, 13, 13, 14, 17, 17, 17, 17, 17, 17, +17, 17, 17, 15, 13, 13, 13, 17, 17, 17, 17, 17, 17, 17, 17, 17, 14, 13, 15, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 13, 13, +13, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 13, 13, 15, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 15, 0, 0, 0, 2, 17, 17, 17, 15, 0, 0, 0, 1, 17, 17, 17, 17, +17, 17, 15, 0, 0, 0, 2, 17, 17, 17, 15, 0, 0, 0, 1, 17, 17, 17, 17, 17, +17, 17, 15, 0, 0, 0, 2, 17, 17, 17, 15, 0, 0, 0, 1, 17, 17, 17, 17, 17, +17, 0, 0, 0, 0, 13, 17, 17, 17, 15, 10, 10, 12, 17, 10, 0, 0, 0, 5, 17, +17, 17, 17, 10, 1, 0, 0, 0, 0, 0, 8, 16, 17, 17, 17, 0, 0, 0, 0, 13, +17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 10, 1, 0, 0, 0, 0, 0, 8, 16, 17, +17, 17, 17, 12, 3, 0, 0, 0, 0, 0, 1, 10, 16, 17, 17, 17, 0, 0, 0, 0, +13, 17, 17, 12, 3, 0, 0, 0, 0, 0, 1, 10, 16, 17, 17, 17, 17, 10, 2, 0, +0, 0, 0, 0, 8, 16, 17, 17, 17, 17, 14, 3, 0, 0, 0, 5, 12, 0, 0, 0, +5, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 10, 2, 0, 0, 0, 0, 0, 8, 15, +17, 17, 17, 17, 17, 12, 3, 0, 0, 0, 0, 2, 10, 17, 17, 17, 17, 17, 0, 0, +0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 9, +0, 0, 0, 0, 14, 17, 17, 10, 0, 0, 0, 0, 12, 17, 17, 17, 17, 17, 9, 0, +0, 0, 0, 14, 17, 17, 10, 0, 0, 0, 0, 12, 17, 17, 17, 17, 17, 17, 9, 0, +0, 0, 0, 14, 17, 17, 10, 0, 0, 0, 0, 12, 17, 17, 17, 17, 17, 0, 0, 0, +0, 13, 17, 17, 11, 1, 0, 0, 0, 3, 7, 0, 0, 0, 5, 17, 17, 17, 8, 0, +0, 0, 0, 0, 0, 0, 0, 3, 16, 17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, +0, 0, 13, 17, 17, 8, 0, 0, 0, 0, 0, 0, 0, 0, 3, 16, 17, 17, 12, 0, +0, 0, 0, 0, 0, 0, 0, 0, 3, 17, 17, 17, 0, 0, 0, 0, 13, 17, 12, 0, +0, 0, 0, 0, 0, 0, 0, 0, 3, 17, 17, 17, 8, 0, 0, 0, 0, 0, 0, 0, +0, 1, 15, 17, 17, 16, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 5, 17, 17, 0, +0, 0, 0, 13, 17, 17, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 14, 17, 17, 17, +10, 0, 0, 0, 0, 0, 0, 0, 0, 3, 17, 17, 17, 17, 0, 0, 0, 0, 13, 17, +17, 0, 0, 0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 2, 0, 0, 0, 0, +9, 17, 17, 3, 0, 0, 0, 0, 7, 17, 17, 17, 17, 17, 2, 0, 0, 0, 0, 9, +17, 17, 3, 0, 0, 0, 0, 7, 17, 17, 17, 17, 17, 17, 2, 0, 0, 0, 0, 9, +17, 17, 3, 0, 0, 0, 0, 7, 17, 17, 17, 17, 17, 0, 0, 0, 0, 13, 17, 14, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 17, 17, 12, 0, 0, 0, 0, 8, 9, +1, 0, 0, 0, 5, 17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, +12, 0, 0, 0, 0, 8, 9, 1, 0, 0, 0, 5, 17, 17, 2, 0, 0, 0, 7, 16, +15, 2, 0, 0, 0, 11, 17, 17, 0, 0, 0, 0, 13, 17, 2, 0, 0, 0, 7, 16, +15, 2, 0, 0, 0, 11, 17, 11, 0, 0, 0, 0, 8, 10, 2, 0, 0, 0, 7, 17, +17, 10, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 5, 17, 17, 0, 0, 0, 0, 13, +17, 11, 0, 0, 0, 0, 8, 9, 1, 0, 0, 0, 5, 17, 17, 13, 0, 0, 0, 0, +8, 9, 1, 0, 0, 0, 10, 17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, 0, +0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 12, 0, 0, 0, 0, 0, 2, 17, 15, 0, +0, 0, 0, 0, 0, 16, 17, 17, 17, 12, 0, 0, 0, 0, 0, 2, 17, 15, 0, 0, +0, 0, 0, 0, 16, 17, 17, 17, 17, 12, 0, 0, 0, 0, 0, 2, 17, 15, 0, 0, +0, 0, 0, 0, 16, 17, 17, 17, 17, 0, 0, 0, 0, 13, 17, 8, 0, 0, 0, 1, +12, 10, 0, 0, 0, 0, 5, 17, 17, 7, 0, 0, 0, 10, 17, 17, 14, 10, 13, 13, +17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 7, 0, 0, 0, +10, 17, 17, 14, 10, 13, 13, 17, 17, 17, 17, 17, 13, 13, 16, 17, 15, 2, 0, 0, +0, 10, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 13, 13, 16, 17, 15, 2, 0, 0, +0, 10, 17, 3, 0, 0, 0, 11, 17, 17, 16, 1, 0, 0, 0, 16, 17, 5, 0, 0, +0, 9, 17, 17, 3, 0, 0, 0, 5, 17, 17, 0, 0, 0, 0, 13, 17, 3, 0, 0, +0, 8, 17, 17, 13, 0, 0, 0, 3, 15, 17, 7, 0, 0, 0, 8, 17, 17, 11, 0, +0, 0, 1, 17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 17, +0, 0, 0, 0, 13, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 8, 0, 0, 1, 0, 0, 0, 14, 10, 0, 0, 1, 0, 0, +0, 10, 17, 17, 17, 8, 0, 0, 1, 0, 0, 0, 14, 10, 0, 0, 1, 0, 0, 0, +10, 17, 17, 17, 17, 8, 0, 0, 1, 0, 0, 0, 14, 10, 0, 0, 1, 0, 0, 0, +10, 17, 17, 17, 17, 13, 13, 13, 13, 16, 17, 2, 0, 0, 0, 11, 17, 17, 8, 0, +0, 0, 5, 17, 17, 0, 0, 0, 0, 8, 10, 10, 10, 10, 10, 10, 10, 15, 17, 0, +0, 0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 0, 0, 0, 0, 8, 10, 10, 10, +10, 10, 10, 10, 15, 17, 17, 17, 14, 10, 5, 1, 0, 0, 0, 0, 0, 12, 17, 17, +0, 0, 0, 0, 13, 17, 17, 17, 14, 10, 5, 1, 0, 0, 0, 0, 0, 12, 17, 17, +13, 13, 10, 17, 17, 17, 17, 5, 0, 0, 0, 13, 17, 0, 0, 0, 0, 13, 17, 17, +10, 0, 0, 0, 5, 17, 17, 13, 13, 13, 13, 16, 17, 0, 0, 0, 0, 13, 17, 17, +17, 13, 17, 17, 17, 17, 17, 0, 0, 0, 0, 12, 17, 17, 17, 0, 0, 0, 0, 13, +17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, 0, 0, +13, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 16, 0, 0, 0, 9, 2, 0, 0, 9, 3, 0, 0, 8, 5, 0, 0, 3, 17, 17, +16, 0, 0, 0, 9, 2, 0, 0, 9, 3, 0, 0, 8, 5, 0, 0, 3, 17, 17, 17, +16, 0, 0, 0, 9, 2, 0, 0, 9, 3, 0, 0, 8, 5, 0, 0, 3, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 10, 0, 0, 0, 5, 17, +17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 17, 0, 0, 0, 0, 13, +17, 17, 0, 0, 0, 0, 13, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +13, 17, 17, 8, 0, 0, 0, 0, 0, 0, 0, 0, 8, 17, 17, 17, 0, 0, 0, 0, +13, 17, 17, 8, 0, 0, 0, 0, 0, 0, 0, 0, 8, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 2, 0, 0, 0, 14, 17, 0, 0, 0, 0, 13, 17, 17, 10, 0, 0, 0, +5, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 17, 17, 17, +17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, +0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 11, 0, 0, +0, 14, 9, 0, 0, 2, 0, 0, 0, 12, 10, 0, 0, 0, 14, 17, 11, 0, 0, 0, +14, 9, 0, 0, 2, 0, 0, 0, 12, 10, 0, 0, 0, 14, 17, 17, 11, 0, 0, 0, +14, 9, 0, 0, 2, 0, 0, 0, 12, 10, 0, 0, 0, 14, 17, 17, 17, 17, 17, 17, +17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 10, 0, 0, 0, 5, 17, 17, 1, 0, 0, +0, 8, 10, 10, 10, 0, 0, 0, 0, 15, 17, 0, 0, 0, 0, 11, 17, 17, 0, 0, +0, 0, 13, 17, 1, 0, 0, 0, 8, 10, 10, 10, 0, 0, 0, 0, 15, 17, 13, 0, +0, 0, 0, 0, 0, 5, 8, 13, 17, 17, 17, 17, 0, 0, 0, 0, 13, 17, 13, 0, +0, 0, 0, 0, 0, 5, 8, 13, 17, 17, 17, 17, 17, 17, 17, 15, 12, 13, 7, 0, +0, 0, 2, 17, 17, 0, 0, 0, 0, 12, 17, 17, 9, 0, 0, 0, 5, 17, 17, 17, +17, 17, 17, 17, 17, 1, 0, 0, 0, 11, 17, 17, 16, 14, 17, 17, 17, 17, 17, 2, +0, 0, 0, 11, 17, 17, 15, 0, 0, 0, 0, 14, 17, 17, 0, 0, 0, 0, 11, 17, +17, 0, 0, 0, 0, 11, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 3, 0, 0, 1, 17, 14, 0, +0, 0, 0, 0, 1, 17, 14, 0, 0, 0, 9, 17, 3, 0, 0, 1, 17, 14, 0, 0, +0, 0, 0, 1, 17, 14, 0, 0, 0, 9, 17, 17, 3, 0, 0, 1, 17, 14, 0, 0, +0, 0, 0, 1, 17, 14, 0, 0, 0, 9, 17, 17, 17, 17, 17, 17, 17, 17, 17, 3, +0, 0, 0, 7, 17, 16, 2, 0, 0, 0, 5, 17, 17, 8, 0, 0, 0, 7, 17, 17, +10, 0, 0, 0, 2, 17, 17, 0, 0, 0, 0, 2, 12, 8, 0, 0, 0, 0, 13, 17, +8, 0, 0, 0, 7, 17, 17, 10, 0, 0, 0, 2, 17, 17, 10, 0, 0, 0, 10, 16, +17, 13, 13, 16, 17, 17, 17, 17, 0, 0, 0, 0, 13, 17, 10, 0, 0, 0, 10, 16, +17, 13, 13, 16, 17, 17, 17, 17, 17, 17, 17, 13, 0, 0, 0, 0, 0, 1, 14, 17, +17, 5, 0, 0, 0, 7, 17, 16, 2, 0, 0, 0, 5, 17, 17, 17, 17, 17, 17, 17, +17, 7, 0, 0, 0, 3, 17, 17, 10, 0, 0, 0, 7, 17, 17, 8, 0, 0, 0, 5, +17, 17, 10, 0, 0, 0, 2, 17, 17, 17, 0, 0, 0, 0, 3, 12, 9, 0, 0, 0, +0, 3, 12, 8, 0, 0, 0, 0, 13, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 15, 0, 0, 0, 8, 17, 17, 2, 0, 0, 0, 0, +8, 17, 17, 2, 0, 0, 2, 15, 0, 0, 0, 8, 17, 17, 2, 0, 0, 0, 0, 8, +17, 17, 2, 0, 0, 2, 17, 15, 0, 0, 0, 8, 17, 17, 2, 0, 0, 0, 0, 8, +17, 17, 2, 0, 0, 2, 17, 17, 17, 17, 17, 17, 17, 17, 17, 9, 0, 0, 0, 0, +3, 2, 0, 0, 0, 0, 5, 17, 17, 14, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0, +10, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 14, 0, 0, 0, +0, 2, 5, 0, 0, 0, 0, 10, 17, 17, 11, 0, 0, 0, 8, 13, 9, 0, 0, 0, +1, 16, 17, 17, 0, 0, 0, 0, 13, 17, 11, 0, 0, 0, 8, 13, 9, 0, 0, 0, +1, 16, 17, 17, 17, 17, 17, 16, 0, 0, 0, 0, 2, 15, 17, 17, 17, 11, 0, 0, +0, 0, 3, 1, 0, 0, 0, 0, 5, 17, 17, 17, 17, 17, 17, 17, 17, 14, 0, 0, +0, 0, 2, 3, 0, 0, 0, 0, 10, 17, 17, 15, 1, 0, 0, 0, 2, 3, 0, 0, +0, 0, 11, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 9, 0, 0, 0, 11, 17, 17, 9, 0, 0, 0, 0, 12, 17, 17, 8, +0, 0, 0, 6, 0, 0, 0, 11, 17, 17, 9, 0, 0, 0, 0, 12, 17, 17, 8, 0, +0, 0, 12, 9, 0, 0, 0, 11, 17, 17, 9, 0, 0, 0, 0, 12, 17, 17, 8, 0, +0, 0, 12, 17, 17, 17, 17, 17, 17, 17, 17, 16, 2, 0, 0, 0, 0, 0, 3, 0, +0, 0, 5, 17, 17, 17, 11, 0, 0, 0, 0, 0, 0, 0, 0, 8, 17, 17, 17, 0, +0, 0, 0, 8, 0, 0, 0, 0, 0, 8, 17, 17, 17, 11, 0, 0, 0, 0, 0, 0, +0, 0, 8, 17, 17, 17, 17, 3, 0, 0, 0, 0, 0, 0, 0, 0, 11, 17, 17, 17, +0, 0, 0, 0, 13, 17, 17, 3, 0, 0, 0, 0, 0, 0, 0, 0, 11, 17, 17, 17, +17, 17, 17, 17, 10, 5, 0, 0, 0, 3, 17, 17, 17, 17, 3, 0, 0, 0, 0, 0, +0, 0, 0, 0, 5, 17, 17, 17, 17, 17, 17, 17, 17, 17, 11, 0, 0, 0, 0, 0, +0, 0, 0, 8, 17, 17, 17, 17, 13, 1, 0, 0, 0, 0, 0, 0, 0, 9, 17, 17, +17, 17, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 7, 3, 0, 0, 0, 0, 0, 9, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +8, 5, 5, 5, 16, 17, 17, 14, 5, 5, 5, 5, 17, 17, 17, 13, 5, 5, 5, 4, +5, 5, 5, 16, 17, 17, 14, 5, 5, 5, 5, 17, 17, 17, 13, 5, 5, 5, 10, 8, +5, 5, 5, 16, 17, 17, 14, 5, 5, 5, 5, 17, 17, 17, 13, 5, 5, 5, 10, 17, +17, 17, 17, 17, 17, 17, 17, 17, 16, 8, 1, 0, 2, 10, 14, 5, 5, 5, 9, 17, +17, 17, 17, 15, 8, 2, 0, 0, 1, 7, 12, 17, 17, 17, 17, 5, 5, 5, 5, 17, +10, 2, 0, 1, 9, 16, 17, 17, 17, 17, 15, 8, 2, 0, 0, 1, 7, 12, 17, 17, +17, 17, 17, 16, 10, 5, 0, 0, 0, 0, 7, 12, 17, 17, 17, 17, 5, 5, 5, 5, +14, 17, 17, 16, 10, 5, 0, 0, 0, 0, 7, 12, 17, 17, 17, 17, 16, 13, 11, 15, +17, 17, 8, 0, 0, 0, 11, 17, 17, 17, 16, 10, 1, 0, 2, 10, 9, 0, 0, 0, +5, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 14, 8, 2, 0, 0, 1, 5, 11, 17, +17, 17, 17, 17, 17, 15, 9, 3, 0, 0, 1, 8, 13, 17, 17, 17, 17, 17, 5, 5, +5, 5, 17, 10, 2, 0, 1, 8, 16, 17, 10, 2, 0, 1, 9, 16, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 8, 0, 0, 0, 8, 17, 17, 8, 0, +0, 0, 10, 17, 17, 17, 17, 17, 17, 17, 17, 17, 10, 0, 0, 0, 5, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 13, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 13, 17, +17, 17, 17, 17, 17, 17, 17, 17, 10, 0, 0, 0, 5, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 0, 0, 0, 0, 13, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 11, 0, 0, 0, 0, 0, 0, 0, 0, 8, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 10, 0, 0, 0, 5, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +5, 5, 5, 5, 14, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 13, 7, 2, 0, 0, 1, 5, 11, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +11, 5, 5, 5, 9, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, +17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, +}; + +int WebUrl_bmp_Length = sizeof(WebUrl_bmp); diff --git a/G3D/Engine/Logo/electric.c b/G3D/Engine/Logo/electric.c new file mode 100644 index 0000000..6dca954 --- /dev/null +++ b/G3D/Engine/Logo/electric.c @@ -0,0 +1,333 @@ +/****************************************************************************************/ +/* ELECTRIC.C */ +/* */ +/* Author: Eli Boling */ +/* Description: Animated electrical bolt special effect implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "genesis.h" +#include "ErrorLog.h" + +#include "Electric.h" +#include "ram.h" + +static int logBase2(int n) +{ + int i = 0; + + assert(n != 0); + + while (!(n & 1)) + { + n = n >> 1; + i++; + } + + assert((n & ~1) == 0); + + return i; +} + +static geBoolean IsPowerOf2(int n) +{ + if (n == 0) + return GE_TRUE; + + while (!(n & 1)) + n = n >> 1; + + if (n & ~1) + return GE_FALSE; + + return GE_TRUE; +} + +_Electric_BoltEffect * _Electric_BoltEffectCreate( + int NumPolys, + int Width, + geFloat Wildness) +{ + _Electric_BoltEffect * be; + GE_RGBA color; + + assert(Wildness >= 0.0f && Wildness <= 1.0f); + + /* Asserts power of 2 */ + logBase2(NumPolys); + + be = (_Electric_BoltEffect *)geRam_Allocate(sizeof(*be)); + if (!be) + return be; + + memset(be, 0, sizeof(*be)); + + be->beCenterPoints = (geVec3d *)geRam_Allocate(sizeof(*be->beCenterPoints) * (NumPolys + 1)); + if (!be->beCenterPoints) + goto fail; + + be->beNumPoints = NumPolys; + be->beWildness = Wildness; + be->beWidth = Width; + + color.r = 160.0f; + color.g = 160.0f; + color.b = 255.0f; + _Electric_BoltEffectSetColorInfo(be, &color, ELECTRIC_BOLT_BLUEDOMINANT); + + return be; + +fail: + if (be->beCenterPoints) + geRam_Free(be->beCenterPoints); + if (be) + geRam_Free(be); + + return NULL; +} + +void _Electric_BoltEffectDestroy(_Electric_BoltEffect *Effect) +{ + geRam_Free(Effect->beCenterPoints); + geRam_Free(Effect); +} + +static geFloat GaussRand(void) +{ + int i; + int r; + + r = 0; + + for (i = 0; i < 6; i++) + r = r + rand() - rand(); + + return (geFloat)r / ((geFloat)RAND_MAX * 6.0f); +} + +static void subdivide( + _Electric_BoltEffect * be, + const geVec3d * start, + const geVec3d * end, + geFloat s, + int n) +{ + geVec3d tmp; + + if (n == 0) + { + be->beCurrentPoint++; + *be->beCurrentPoint = *end; + return; + } + + tmp.X = (end->X + start->X) / 2 + s * GaussRand(); + tmp.Y = (end->Y + start->Y) / 2 + s * GaussRand(); + tmp.Z = (end->Z + start->Z) / 2 + s * GaussRand(); + subdivide(be, start, &tmp, s / 2, n - 1); + subdivide(be, &tmp, end, s / 2, n - 1); +} + +#define LIGHTNINGWIDTH 8.0f + +static void genLightning( + _Electric_BoltEffect * be, + int RangeLow, + int RangeHigh, + const geVec3d * start, + const geVec3d * end) +{ + geFloat length; + int seed; + + assert(be); + assert(start); + assert(end); + assert(RangeHigh > RangeLow); + assert(IsPowerOf2(RangeHigh - RangeLow)); + + /* Manhattan length is good enough for this */ + length = (geFloat)(fabs(start->X - end->X) + + fabs(start->Y - end->Y) + + fabs(start->Z - end->Z)); + + seed = rand(); + + srand(seed); + be->beCurrentPoint = be->beCenterPoints + RangeLow; + be->beCenterPoints[RangeLow] = *start; + be->beCenterPoints[RangeHigh] = *end; + subdivide(be, start, end, length * be->beWildness, logBase2(RangeHigh - RangeLow)); +} + +void _Electric_BoltEffectSetColorInfo( + _Electric_BoltEffect * Effect, + GE_RGBA * BaseColor, + int DominantColor) +{ + Effect->beBaseColors[0] = BaseColor->r; + Effect->beBaseColors[1] = BaseColor->g; + Effect->beBaseColors[2] = BaseColor->b; + Effect->beCurrentColors[0] = BaseColor->r; + Effect->beCurrentColors[1] = BaseColor->g; + Effect->beCurrentColors[2] = BaseColor->b; + Effect->beDominantColor = DominantColor; +} + +void _Electric_BoltEffectAnimate( + _Electric_BoltEffect * Effect, + const geVec3d * start, + const geVec3d * end) +{ + int dominant; + int nonDominant1; + int nonDominant2; + geVec3d SubdivideStart; + geVec3d SubdivideEnd; + int LowIndex; + int HighIndex; + + Effect->beStart = *start; + Effect->beEnd = *end; + + dominant = Effect->beDominantColor; + nonDominant1 = (dominant + 1) % 3; + nonDominant2 = (dominant + 2) % 3; + if (Effect->beBaseColors[nonDominant1] == Effect->beCurrentColors[nonDominant1]) + { + int DecayRate; + int Spike; + + DecayRate = rand() % (int)(Effect->beBaseColors[dominant] - Effect->beBaseColors[nonDominant1]); + DecayRate = max(DecayRate, 5); + Effect->beDecayRate = DecayRate; + if (Effect->beBaseColors[nonDominant1] >= 1.0f) + Spike = rand() % (int)(Effect->beBaseColors[nonDominant1]); + else + Spike = 0; + Effect->beCurrentColors[nonDominant1] -= Spike; + Effect->beCurrentColors[nonDominant2] -= Spike; + } + else + { + Effect->beCurrentColors[nonDominant1] += Effect->beDecayRate; + Effect->beCurrentColors[nonDominant2] += Effect->beDecayRate; + if (Effect->beCurrentColors[nonDominant1] > Effect->beBaseColors[nonDominant1]) + { + Effect->beCurrentColors[nonDominant1] = Effect->beBaseColors[nonDominant1]; + Effect->beCurrentColors[nonDominant2] = Effect->beBaseColors[nonDominant2]; + } + } + + Effect->beInitialized = 1; + LowIndex = 0; + HighIndex = Effect->beNumPoints; + SubdivideStart = *start; + SubdivideEnd = *end; + + genLightning(Effect, LowIndex, HighIndex, &SubdivideStart, &SubdivideEnd); +} + +//#define LIGHTNINGALPHA 160.0f +#define LIGHTNINGALPHA 220.0f + +void _Electric_BoltEffectRender( + geWorld * World, + _Electric_BoltEffect * be, + const geXForm3d * XForm) +{ + geVec3d perp; + geVec3d temp; + geVec3d in; + GE_LVertex verts[4]; + int i; + + geVec3d_Subtract(&be->beStart, &be->beEnd, &temp); + geXForm3d_GetIn(XForm, &in); + + geVec3d_CrossProduct(&in, &temp, &perp); + geVec3d_Normalize(&perp); + + geVec3d_Scale(&perp, be->beWidth / 2.0f, &perp); + + /* + We've got the perpendicular to the camera in the + rough direction of the electric bolt center. Walk + the left and right sides, constructing verts, then + do the drawing. + */ + for (i = 0; i < be->beNumPoints - 1; i++) + { + geVec3d temp; + + geVec3d_Subtract(&be->beCenterPoints[i], &perp, &temp); + verts[0].X = temp.X; + verts[0].Y = temp.Y; + verts[0].Z = temp.Z; + verts[0].u = 0.0f; + verts[0].v = 0.0f; + verts[0].r = be->beCurrentColors[0]; + verts[0].g = be->beCurrentColors[1]; + verts[0].b = be->beCurrentColors[2]; + verts[0].a = LIGHTNINGALPHA; + + geVec3d_Subtract(&be->beCenterPoints[i + 1], &perp, &temp); + verts[1].X = temp.X; + verts[1].Y = temp.Y; + verts[1].Z = temp.Z; + verts[1].u = 0.0f; + verts[1].v = 1.0f; + verts[1].r = be->beCurrentColors[0]; + verts[1].g = be->beCurrentColors[1]; + verts[1].b = be->beCurrentColors[2]; + verts[1].a = LIGHTNINGALPHA; + + geVec3d_Add(&be->beCenterPoints[i + 1], &perp, &temp); + verts[2].X = temp.X; + verts[2].Y = temp.Y; + verts[2].Z = temp.Z; + verts[2].u = 1.0f; + verts[2].v = 1.0f; + verts[2].r = be->beCurrentColors[0]; + verts[2].g = be->beCurrentColors[1]; + verts[2].b = be->beCurrentColors[2]; + verts[2].a = LIGHTNINGALPHA; + + geVec3d_Add(&be->beCenterPoints[i], &perp, &temp); + verts[3].X = temp.X; + verts[3].Y = temp.Y; + verts[3].Z = temp.Z; + verts[3].u = 1.0f; + verts[3].v = 0.0f; + verts[3].r = be->beCurrentColors[0]; + verts[3].g = be->beCurrentColors[1]; + verts[3].b = be->beCurrentColors[2]; + verts[3].a = LIGHTNINGALPHA; + + geWorld_AddPolyOnce(World, + verts, + 4, + NULL, + GE_GOURAUD_POLY, + GE_RENDER_DO_NOT_OCCLUDE_OTHERS, + 1.0f); + + } +} diff --git a/G3D/Engine/Logo/electric.h b/G3D/Engine/Logo/electric.h new file mode 100644 index 0000000..709a9b2 --- /dev/null +++ b/G3D/Engine/Logo/electric.h @@ -0,0 +1,88 @@ +/****************************************************************************************/ +/* ELECTRIC.H */ +/* */ +/* Author: Eli Boling */ +/* Description: Animated electrical bolt special effect interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef ELECTRIC_H +#define ELECTRIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "Genesis.h" + +#define ELECTRIC_BOLT_REDDOMINANT 0 +#define ELECTRIC_BOLT_GREENDOMINANT 1 +#define ELECTRIC_BOLT_BLUEDOMINANT 2 + +#pragma warning( disable : 4068 ) + +typedef struct _Electric_BoltEffect +{ + int beInitialized; + int beNumPoints; + geFloat beWildness; + + /* For rendering */ + geVec3d beStart; + geVec3d beEnd; + + /* For generating the geometry */ + geVec3d * beCenterPoints; + geVec3d * beCurrentPoint; + + geFloat beBaseColors[3]; + geFloat beCurrentColors[3]; + geFloat beBaseBlue; + int beDecayRate; + int beDominantColor; + + int beWidth; + +} _Electric_BoltEffect; + +_Electric_BoltEffect * _Electric_BoltEffectCreate( + int NumPolys, /* Number of polys, must be power of 2 */ + int Width, /* Width in world units of the bolt */ + geFloat Wildness); /* How wild the bolt is (0 to 1 inclusive) */ + +void _Electric_BoltEffectDestroy(_Electric_BoltEffect *Effect); + +void _Electric_BoltEffectAnimate( + _Electric_BoltEffect * Effect, + const geVec3d * start, /* Starting point of the bolt */ + const geVec3d * end); /* Ending point of the bolt */ + +void _Electric_BoltEffectRender( + geWorld * World, /* World to render for */ + _Electric_BoltEffect * Effect, /* Bolt to render */ + const geXForm3d * XForm); /* Transform of our point of view */ + +void _Electric_BoltEffectSetColorInfo( + _Electric_BoltEffect * Effect, + GE_RGBA * BaseColor, /* Base color of the bolt (2 colors should be the same */ + int DominantColor); /* Which color is the one to leave fixed */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Engine/Logo/logo.c b/G3D/Engine/Logo/logo.c new file mode 100644 index 0000000..17f7632 --- /dev/null +++ b/G3D/Engine/Logo/logo.c @@ -0,0 +1,513 @@ +/****************************************************************************************/ +/* LOGO.C */ +/* */ +/* Author: Eli Boling */ +/* Description: The Genesis3D Logo implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define WIN32_LEAN_AND_MEAN +#pragma warning(disable : 4201 4214 4115) +#include +#include //timeGetTime +#pragma warning(default : 4201 4214 4115) + +#include + +#include "genesis.h" +#include "engine.h" +#include "bitmap.h" +#include "PixelFormat.h" +#include "errorlog.h" +#include "electric.h" + +extern unsigned char LogoActor_act[]; +extern int LogoActor_act_Length; +extern unsigned char Corona_bmp[]; +extern int Corona_bmp_Length; +extern unsigned char Streak_bmp[]; +extern int Streak_bmp_Length; +extern unsigned char WebUrl_bmp[]; +extern int WebUrl_bmp_Length; +extern unsigned char A_Corona_bmp[]; +extern int A_Corona_bmp_Length; +extern unsigned char A_Streak_bmp[]; +extern int A_Streak_bmp_Length; + +#pragma warning (disable:4514) // unreferenced inline function (caused by Windows) + +static void SubLarge(LARGE_INTEGER *start, LARGE_INTEGER *end, LARGE_INTEGER *delta) +{ + _asm { + mov ebx,dword ptr [start] + mov esi,dword ptr [end] + + mov eax,dword ptr [esi+0] + sub eax,dword ptr [ebx+0] + + mov edx,dword ptr [esi+4] + sbb edx,dword ptr [ebx+4] + + mov ebx,dword ptr [delta] + mov dword ptr [ebx+0],eax + mov dword ptr [ebx+4],edx + } +} + +static geBoolean GetBonePosition(geActor *Actor, const char *BoneName, geVec3d *Pos) +{ + geXForm3d BoneXForm; + geBoolean Result; + + Result = geActor_GetBoneTransform(Actor, BoneName, &BoneXForm); + *Pos = BoneXForm.Translation; + return Result; +} + +static geLight *AddBoneLight(geWorld *World, geActor *Actor, const char *BoneName, + geFloat R, geFloat G, geFloat B, int Intensity) +{ + geXForm3d BoneXForm; + geLight * Light; + GE_RGBA Color; + + geActor_GetBoneTransform(Actor, BoneName, &BoneXForm); + BoneXForm.Translation.Z += 50; + Color.r = R; + Color.g = G; + Color.b = B; + Color.a = 255.0f; + Light = geWorld_AddLight(World); + if (Light) + geWorld_SetLightAttributes(World, Light, &BoneXForm.Translation, &Color, (geFloat)Intensity, GE_FALSE); + return Light; +} + +static geBitmap * GetABitmap(void *BmpData, int BmpLength, void *AlphaData, int AlphaLength) +{ + geBitmap * Bitmap; + geBitmap * Alpha; + geVFile * MemFile; + geVFile_MemoryContext Context; + + Context.Data = BmpData; + Context.DataLength = BmpLength; + + MemFile = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_MEMORY, NULL, &Context, GE_VFILE_OPEN_READONLY); + if (!MemFile) + return NULL; + Bitmap = geBitmap_CreateFromFile(MemFile); + geVFile_Close(MemFile); + if (!Bitmap) + return NULL; + + Context.Data = AlphaData; + Context.DataLength = AlphaLength; + + MemFile = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_MEMORY, NULL, &Context, GE_VFILE_OPEN_READONLY); + if (!MemFile) + { + geBitmap_Destroy(&Bitmap); + return NULL; + } + Alpha = geBitmap_CreateFromFile(MemFile); + geVFile_Close(MemFile); + if (!Alpha) + { + geBitmap_Destroy(&Bitmap); + return NULL; + } + + if (!geBitmap_SetAlpha(Bitmap, Alpha)) + { + geBitmap_Destroy(&Bitmap); + geBitmap_Destroy(&Alpha); + return NULL; + } + + geBitmap_Destroy(&Alpha); + + geBitmap_SetPreferredFormat(Bitmap, GE_PIXELFORMAT_16BIT_4444_ARGB); + + return Bitmap; +} + +geBoolean DoSplashScreen(geEngine *Engine, geDriver_Mode *DriverMode) +{ + geActor_Def * ActorDef; + geCamera * Camera; + geVFile * MemFile; + geVFile_MemoryContext Context; + geBoolean Result; + geActor * Actor; + geWorld * World; + geFloat StartTime; + geFloat CurrentTime; + geFloat EndTime; + geMotion * Motion; + geXForm3d CameraXForm; + geRect Rect; + geXForm3d ActorXForm; + geBoolean KeepGoing; + int32 Width, Height; + + geVec3d LightingNormal; + LARGE_INTEGER CurrentTic; + + _Electric_BoltEffect *Bolt=NULL; + geVec3d BoltStart; + geVec3d BoltEnd; + + geBitmap * Corona; + geBitmap * Streak; + geBitmap * WebUrl; + GE_LVertex CoronaVert; + GE_LVertex StreakVert; + geVec3d CoronaVertex; + geLight * CoronaLight; + +static geBoolean DisplayedOnceAlready = GE_FALSE; + + if (DisplayedOnceAlready == GE_TRUE) + return GE_TRUE; + + DisplayedOnceAlready = GE_TRUE; + + Actor = NULL; + Camera = NULL; + World = NULL; + + geDriver_ModeGetWidthHeight(DriverMode, &Width, &Height); + + if (Width == -1) + { + RECT R; + + GetClientRect(Engine->hWnd, &R); + + Rect.Left = R.left; + Rect.Right = R.right; + Rect.Top = R.top; + Rect.Bottom = R.bottom; + } + else + { + Rect.Left = 0; + Rect.Right = Width-1; + Rect.Top = 0; + Rect.Bottom = Height-1; + } + + World = geWorld_Create(NULL); + + if (!World) + goto fail; + + // Add the world to the engine, so we can render it + if (!geEngine_AddWorld(Engine, World)) + { + geErrorLog_AddString(-1, "DoSplashScreen: geEngine_AddWorld failed.", NULL); + goto fail; + } + + // Open the actor def file + Context.Data = LogoActor_act; + Context.DataLength = LogoActor_act_Length; + MemFile = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_MEMORY, NULL, &Context, GE_VFILE_OPEN_READONLY); + if (!MemFile) + return GE_FALSE; + + // Create the actor def + ActorDef = geActor_DefCreateFromFile(MemFile); + geVFile_Close(MemFile); + if (!ActorDef) + return GE_FALSE; + + // Create the actor form the actor def + Actor = geActor_Create(ActorDef); + // Remove the ref count that was just added by geACtor_Create + geActor_DefDestroy(&ActorDef); + if (!Actor) + goto fail; // Oops + + // Add the actor to the NULL world + Result = geWorld_AddActor(World, Actor, GE_ACTOR_RENDER_ALWAYS, 0xffffffff); + if (Result == GE_FALSE) + goto fail; + + Motion = geActor_GetMotionByIndex(ActorDef, 0); + if (!Motion) + goto fail; + + if (geMotion_GetTimeExtents(Motion, &StartTime, &EndTime) == GE_FALSE) + goto fail; + CurrentTime = StartTime; + + Camera = geCamera_Create(2.0f, &Rect); + if (!Camera) + goto fail; + + geXForm3d_SetTranslation(&CameraXForm, 0.0f, 40.0f, 800.0f); + geCamera_SetWorldSpaceXForm(Camera, &CameraXForm); + geXForm3d_SetXRotation(&ActorXForm, -3.1415926f / 2.0f); + geActor_SetPose(Actor, Motion, 0.0f, &ActorXForm); + +#define BRIGHTNESS (1.7f) +#define BRIGHTEN(XX) ((((XX)*BRIGHTNESS)>255.0f)?255.0f:((XX)*BRIGHTNESS) ) + +#define FILL_LIGHT_RED (10.0f + 20.0f) +#define FILL_LIGHT_GREEN (10.0f + 20.0f) +#define FILL_LIGHT_BLUE (10.0f + 20.0f) + +#define AMB_LIGHT_RED (5.0f + 0.0f) +#define AMB_LIGHT_GREEN (5.0f + 0.0f) +#define AMB_LIGHT_BLUE (5.0f + 0.0f) + +#define GEAR_R BRIGHTEN(251.0f) +#define GEAR_G BRIGHTEN(155.0f) +#define GEAR_B BRIGHTEN(110.0f) + +#define PISTON_R BRIGHTEN(150.0f) +#define PISTON_G BRIGHTEN(80.0f) +#define PISTON_B BRIGHTEN(4.0f) + +#define GENESISB_R BRIGHTEN(255.0f) +#define GENESISB_G BRIGHTEN(255.0f) +#define GENESISB_B BRIGHTEN(255.0f) + +#define BONE01_R BRIGHTEN(75.0f) +#define BONE01_G BRIGHTEN(56.0f) +#define BONE01_B BRIGHTEN(2.0f) + +#define LINKTO_R BRIGHTEN(75.0f) +#define LINKTO_G BRIGHTEN(40.0f) +#define LINKTO_B BRIGHTEN(2.0f) + +#define CORONALIGHT1_R (100.0f) +#define CORONALIGHT1_G (100.0f) +#define CORONALIGHT1_B (255.0f) + +#define CORONALIGHT2_R (255.0f) +#define CORONALIGHT2_G (255.0f) +#define CORONALIGHT2_B (255.0f) + +#define CORONALIGHT_RADIUS (1600.0f) + + geVec3d_Set(&LightingNormal, -0.3f, /*1.0f*/0.5f, 0.4f); + geVec3d_Normalize(&LightingNormal); + geActor_SetLightingOptions(Actor, + GE_TRUE, + &LightingNormal, + FILL_LIGHT_RED,FILL_LIGHT_GREEN,FILL_LIGHT_BLUE, + AMB_LIGHT_RED,AMB_LIGHT_GREEN,AMB_LIGHT_BLUE, + GE_FALSE, + 20, + NULL, + GE_TRUE); + + + AddBoneLight(World, Actor, "GEAR01B", GEAR_R, GEAR_G, GEAR_B, 200); + AddBoneLight(World, Actor, "GEAR02B", GEAR_R, GEAR_G, GEAR_B, 200); + AddBoneLight(World, Actor, "GEAR03B", GEAR_R, GEAR_G, GEAR_B, 200); + AddBoneLight(World, Actor, "GEAR04B", GEAR_R, GEAR_G, GEAR_B, 200); + AddBoneLight(World, Actor, "GEAR05B", GEAR_R, GEAR_G, GEAR_B, 200); + AddBoneLight(World, Actor, "GEAR06B", GEAR_R, GEAR_G, GEAR_B, 200); + AddBoneLight(World, Actor, "GEAR07B", GEAR_R, GEAR_G, GEAR_B, 200); + AddBoneLight(World, Actor, "GEAR08B", GEAR_R, GEAR_G, GEAR_B, 200); + + AddBoneLight(World, Actor, "GENESISB", 255, 255, 255, 200); + AddBoneLight(World, Actor, "BONE01", 75, 56, 2, 60); + AddBoneLight(World, Actor, "LINKTO", 75, 40, 2, 200); + + AddBoneLight(World, Actor, "R_CYL01", PISTON_R, PISTON_G, PISTON_B, 150); + AddBoneLight(World, Actor, "R_CYL02", PISTON_R, PISTON_G, PISTON_B, 150); + AddBoneLight(World, Actor, "L_CYL01", PISTON_R, PISTON_G, PISTON_B, 150); + AddBoneLight(World, Actor, "L_CYL02", PISTON_R, PISTON_G, PISTON_B, 150); + + CoronaLight = AddBoneLight(World, Actor, "CORONA", 0,0,0, (int)CORONALIGHT_RADIUS); + + Bolt = _Electric_BoltEffectCreate(32, 4, 0.5f); + + if (!Bolt) + goto fail; + + Corona = GetABitmap(Corona_bmp, Corona_bmp_Length, A_Corona_bmp, A_Corona_bmp_Length); + if (!Corona) + goto fail; + Streak = GetABitmap(Streak_bmp, Streak_bmp_Length, A_Streak_bmp, A_Streak_bmp_Length); + if (!Streak) + goto fail; + WebUrl = GetABitmap(WebUrl_bmp, WebUrl_bmp_Length, WebUrl_bmp, WebUrl_bmp_Length ); + if (!WebUrl) + goto fail; + + geWorld_AddBitmap(World, Corona); + geWorld_AddBitmap(World, Streak); + geWorld_AddBitmap(World, WebUrl); + + GetBonePosition(Actor, "CORONA", (geVec3d *)&CoronaVert.X); + CoronaVert.u = CoronaVert.v = 0.0f; + CoronaVert.r = CoronaVert.g = CoronaVert.b = CoronaVert.a = 255.0f; + CoronaVert.X += 30.0f; + StreakVert = CoronaVert; + + GetBonePosition(Actor, "CORONA", &CoronaVertex); + CoronaVertex.Z += 100.0f; + CoronaVertex.X += 30.0f; + + QueryPerformanceCounter(&CurrentTic); + + KeepGoing = GE_TRUE; + + while (KeepGoing) // Play the entire animation + { + LARGE_INTEGER NowTic, DeltaTic; + geFloat CoronaScale; + geFloat StreakScale; + + if (CurrentTime >= EndTime) + { + CurrentTime = EndTime; + KeepGoing = GE_FALSE; + } + + geActor_SetPose(Actor, Motion, CurrentTime, &ActorXForm); + + if (!geEngine_BeginFrame(Engine, Camera, GE_TRUE)) + goto fail; + + GetBonePosition(Actor, "BONE22", &BoltStart); + GetBonePosition(Actor, "BONE28", &BoltEnd); + + if (CoronaLight) + { + static geFloat Random = 0.76324f; + GE_RGBA Color; + geFloat Attenuation = 0.97f * CurrentTime; + Attenuation += (Random*0.15f)*(CurrentTime>1.0f?0:(1.0f-CurrentTime)); + Random = 1.0f - Random*Random; + Color.r = CORONALIGHT1_R * Attenuation; + Color.g = CORONALIGHT1_G * Attenuation; + Color.b = CORONALIGHT1_B * Attenuation; + if (Color.r>200.0f) Color.r = 200.0f; + if (Color.g>200.0f) Color.g = 200.0f; + if (Color.b>255.0f) Color.b = 255.0f; + Color.a = 255.0f; + geWorld_SetLightAttributes( World,CoronaLight,&CoronaVertex, + &Color, CORONALIGHT_RADIUS,GE_FALSE); + } + + + if (CurrentTime < 1.0f) + { + _Electric_BoltEffectAnimate(Bolt, &BoltStart, &BoltEnd); + _Electric_BoltEffectRender(World, Bolt, &CameraXForm); + } + if (CurrentTime > 1.0f) + { + CoronaScale = (CurrentTime - 1.0f) * 1.75f; + if (CoronaScale > 1.0f) + CoronaScale = 1.0f; + CoronaVert.a = 255.0f * CoronaScale; + StreakScale = CurrentTime * 5.0f; + if (StreakScale > 10.0f) + StreakScale = 10.0f; + geWorld_AddPolyOnce(World, &CoronaVert, 1, Corona, GE_TEXTURED_POINT, GE_RENDER_DO_NOT_OCCLUDE_OTHERS | GE_RENDER_DO_NOT_OCCLUDE_SELF, 3.0f); + geWorld_AddPolyOnce(World, &StreakVert, 1, Streak, GE_TEXTURED_POINT, GE_RENDER_DO_NOT_OCCLUDE_OTHERS | GE_RENDER_DO_NOT_OCCLUDE_SELF, StreakScale); + } + + // add web url poly + { + GE_LVertex WebVert; + + WebVert.r = 255.0f; + WebVert.g = 255.0f; + WebVert.b = 255.0f; + WebVert.a = 255.0f; + WebVert.u = 0.0f; + WebVert.v = 0.0f; + WebVert.X = 0.0f; + WebVert.Y = 0.0f; + WebVert.Z = 350.0f; + + geWorld_AddPolyOnce( World, &WebVert, 1, WebUrl, GE_TEXTURED_POINT, GE_RENDER_DO_NOT_OCCLUDE_OTHERS | GE_RENDER_DO_NOT_OCCLUDE_SELF, 1.0 ); + } + + if (!geEngine_RenderWorld(Engine, World, Camera, 0.0f)) + goto fail; + + if (!geEngine_EndFrame(Engine)) + goto fail; + + QueryPerformanceCounter(&NowTic); + + SubLarge(&CurrentTic, &NowTic, &DeltaTic); + +// CurrentTime += ((geFloat)DeltaTic.LowPart / (geFloat)Engine->CPUInfo.Freq) / 10.0f; +// CurrentTime += ((geFloat)DeltaTic.LowPart / (geFloat)Engine->CPUInfo.Freq) / 45.0f; + CurrentTime += ((geFloat)DeltaTic.LowPart / (geFloat)Engine->CPUInfo.Freq) / 75.0f; + } + + Sleep(500); + + // Remove Bolt and Bitmaps that were causing leak + if (Bolt) + _Electric_BoltEffectDestroy(Bolt); + + geWorld_RemoveBitmap(World, Corona); + geWorld_RemoveBitmap(World, Streak); + geWorld_RemoveBitmap(World, WebUrl); + + // Destroy Bmps + geBitmap_Destroy(&Corona); + geBitmap_Destroy(&Streak); + geBitmap_Destroy(&WebUrl); + + // Remove the actor from the world + geWorld_RemoveActor(World,Actor); + + // Utterly Destroy the actor + geActor_DestroyDirect(&Actor); + + // Rmeove the world from the engine + if (!geEngine_RemoveWorld(Engine, World)) + { + geErrorLog_AddString(-1, "DoSplashScreen: geEngine_RemoveWorld failed.", NULL); + goto fail; + } + + // Destroy the world + geWorld_Free(World); + // Destroy the camera + geCamera_Destroy(&Camera); + + return GE_TRUE; + +fail: + if (Bolt) + _Electric_BoltEffectDestroy(Bolt); + if (Actor) + geActor_Destroy(&Actor); + if (World) + geWorld_Free(World); + if (Camera) + geCamera_Destroy(&Camera); + + Engine->Changed = GE_TRUE; + + return GE_FALSE; +} + diff --git a/G3D/Engine/Logo/poweredby.c b/G3D/Engine/Logo/poweredby.c new file mode 100644 index 0000000..4ba504e --- /dev/null +++ b/G3D/Engine/Logo/poweredby.c @@ -0,0 +1,3308 @@ +/****************************************************************************************/ +/* Poweredby.C */ +/* */ +/* Author: */ +/* Description: Embedded powered by bitmap */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +unsigned char Poweredby_bmp[] = { +66, 77, 120, 0, 1, 0, 0, 0, 0, 0, 118, 0, 0, 0, 40, 0, 0, 0, 0, 1, +0, 0, 0, 1, 0, 0, 1, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 11, +0, 0, 18, 11, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 255, 255, 255, 0, 238, 238, +238, 0, 222, 222, 222, 0, 206, 206, 206, 0, 186, 186, 186, 0, 170, 170, 170, 0, 153, 153, +153, 0, 137, 137, 137, 0, 117, 117, 117, 0, 101, 101, 101, 0, 85, 85, 85, 0, 68, 68, +68, 0, 48, 48, 48, 0, 32, 32, 32, 0, 16, 16, 16, 0, 0, 0, 0, 0, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 12, 8, 7, 4, 4, +4, 4, 8, 9, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 4, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 9, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 10, 15, 15, 15, 15, 15, 5, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 12, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, +9, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 6, 8, 14, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 12, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, +14, 15, 15, 15, 15, 15, 15, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 8, 15, 15, 15, 15, 15, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 11, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 10, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 12, 1, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 14, 15, 15, +15, 15, 15, 15, 15, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 15, 15, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, +0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 2, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, +15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 11, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, +0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 13, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 0, +0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 15, 15, 15, 15, 15, 15, 3, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 15, 15, 15, 15, 9, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, +0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 5, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 14, 13, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 12, 15, 15, 15, 15, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 12, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 3, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 15, 15, +15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 5, 0, 0, 0, +0, 0, 0, 0, 0, 0, 8, 15, 15, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, +15, 15, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 15, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, +0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 13, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 12, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, +15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, +11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, +0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 6, 0, +0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 0, +0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 8, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 11, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 9, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, +0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, +0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, +0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 10, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, +4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, +0, 0, 0, 4, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 3, 15, 15, 8, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, +0, 0, 8, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, +15, 15, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, +15, 15, 5, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, +0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, +15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 13, 15, 4, 0, +0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, +0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, +0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 0, +0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 11, 15, 0, 0, 0, 0, 0, 0, +7, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, +0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 0, 0, 0, 0, 0, +0, 0, 0, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, +0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 12, 0, 0, 0, 0, 0, 0, 0, 0, +2, 5, 0, 0, 0, 0, 0, 0, 9, 13, 0, 0, 0, 0, 0, 0, 8, 4, 0, 0, +0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 6, 0, 0, 0, 0, 0, 0, 0, 0, 3, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, +7, 15, 15, 15, 15, 15, 15, 15, 15, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 9, 14, 15, 15, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, +0, 0, 0, 4, 15, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 0, 0, +0, 0, 0, 0, 8, 11, 0, 0, 0, 0, 0, 0, 8, 4, 0, 0, 0, 0, 0, 0, +0, 0, 0, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 8, +8, 8, 8, 8, 9, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 6, 8, 8, 8, 8, 8, 9, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 15, 15, 15, +15, 15, 15, 15, 15, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 8, 15, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 0, 0, 0, 0, 0, 0, +5, 8, 0, 0, 0, 0, 0, 0, 10, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 5, 0, 0, +0, 0, 0, 0, 0, 0, 0, 12, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, +10, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 15, 15, 15, 15, 15, 15, 15, +15, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 7, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 8, +0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 0, 0, 0, 0, 0, 0, 4, 8, 0, 0, +0, 0, 0, 0, 11, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 8, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 13, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 6, 0, 0, 0, 0, +0, 0, 0, 0, 8, 11, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, +11, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 10, 15, 15, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 4, 14, 15, 15, 15, 15, 15, 15, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +7, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, +0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, +8, 11, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 14, 8, 0, 0, +0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 7, 15, 15, 15, 15, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 9, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 6, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, +0, 0, 0, 4, 15, 15, 15, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 14, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 11, 0, 0, 0, 0, 0, 0, +0, 0, 0, 6, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 14, 15, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 8, 14, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 3, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 14, 15, 15, 15, 15, 15, 15, 15, 15, 13, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 13, +1, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 14, 0, +0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 3, 15, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 9, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 3, 14, 15, 15, 15, 15, 15, 15, 15, 9, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 6, 0, 0, 0, +0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 11, 0, 0, 0, 0, 0, +0, 0, 0, 0, 11, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 14, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 11, 1, 0, 0, 0, 0, 0, +0, 0, 0, 8, 15, 15, 15, 15, 15, 15, 15, 5, 0, 0, 0, 0, 0, 0, 3, 1, +0, 0, 0, 0, 0, 0, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, +0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, +0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, +15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 5, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 15, 15, 15, 15, 15, 1, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, +0, 0, 0, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, +0, 0, 0, 4, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 8, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 15, 15, 4, 0, 0, 0, 0, 0, +0, 0, 0, 0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 15, 15, 15, 15, +15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 9, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 8, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, +10, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, +0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 7, 0, +0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 5, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, +8, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 4, 0, +0, 0, 0, 0, 0, 0, 0, 3, 15, 15, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 8, 15, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, +0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, +0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 3, 0, 0, 0, 0, 0, +0, 0, 11, 11, 0, 0, 0, 0, 0, 0, 0, 1, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, +0, 0, 0, 0, 0, 15, 15, 15, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, +15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 15, 4, 0, 0, 0, 0, 0, +0, 0, 0, 4, 15, 15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, +15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, +0, 0, 0, 0, 15, 15, 15, 15, 15, 13, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, +0, 0, 0, 0, 0, 0, 0, 0, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, +0, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 8, 0, 0, +0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, +15, 15, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 9, 0, +0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, +15, 15, 15, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 1, 15, 15, 2, 0, 0, 0, +0, 0, 0, 0, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 11, 15, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, +4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 15, 15, 8, 0, 0, 0, 0, 0, 0, +0, 0, 0, 8, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 11, 0, 0, 0, 0, 0, +0, 0, 0, 0, 4, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 8, +8, 8, 8, 8, 8, 13, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 6, 8, 8, 8, 8, 8, 8, 13, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, +4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 11, 15, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, +15, 5, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 5, 0, 0, 0, 0, 0, 0, 0, +2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 8, 10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 7, 0, 0, 0, +0, 0, 0, 0, 0, 0, 7, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, +15, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 3, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 14, 15, 15, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 5, 0, 0, +0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 8, 11, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, +11, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 6, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 12, 15, 15, +15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 5, 15, 15, 15, 10, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 11, 0, 0, +0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 8, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 10, 0, 0, 0, 0, 0, 0, 0, +0, 8, 15, 15, 10, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 15, 15, +15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 8, 15, 15, 15, 15, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 15, 8, 0, 0, 0, 0, 0, 0, +0, 0, 0, 8, 15, 15, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, +15, 15, 15, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, +15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 13, 15, 15, 15, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, +13, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, +14, 15, 15, 15, 15, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 1, 13, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, +15, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 15, 15, 15, 15, 4, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 15, +15, 15, 15, 15, 2, 0, 0, 0, 0, 0, 0, 0, 0, 13, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 14, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, +15, 15, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 10, 15, 15, 15, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 11, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 5, 0, 0, 0, 0, +0, 0, 0, 0, 0, 8, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 13, 15, 15, 15, 15, 15, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 14, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 14, 15, 15, 15, 15, 13, +0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 4, 0, 0, 0, 0, 0, 0, +0, 0, 9, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 15, 15, 15, 15, 6, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 15, 15, 15, +15, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 11, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, +0, 8, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 2, 12, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 14, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 4, 14, 15, 15, 15, 15, 15, 8, 0, 0, 0, 0, +0, 0, 0, 0, 4, 15, 15, 15, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, +15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 2, 7, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 10, 2, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 12, 15, 15, 15, 15, 15, 2, 0, 0, +0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 7, 15, 15, 15, 15, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 15, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 15, 15, +15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, +14, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 11, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 1, 6, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 5, 9, 15, 15, 15, 15, 15, 15, 15, 5, 0, 0, 0, 0, 0, 0, 0, 0, +6, 15, 15, 15, 15, 9, 0, 0, 0, 0, 0, 0, 0, 0, 1, 15, 15, 15, 15, 15, +15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 11, 13, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 9, 5, 1, 0, 0, 0, +0, 0, 0, 2, 6, 11, 15, 15, 15, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, +8, 8, 8, 15, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 11, 15, +15, 15, 15, 13, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 15, 15, 8, 8, 8, 8, +8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 13, 15, 15, 15, 8, 8, 8, +8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +8, 13, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 11, +11, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 11, 12, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 11, 15, 15, 15, +15, 13, 8, 8, 8, 8, 8, 8, 8, 8, 8, 13, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 11, 11, 11, 11, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, +}; + +int Poweredby_bmp_Length = sizeof(Poweredby_bmp); diff --git a/G3D/Engine/Logo/streak.c b/G3D/Engine/Logo/streak.c new file mode 100644 index 0000000..20f4774 --- /dev/null +++ b/G3D/Engine/Logo/streak.c @@ -0,0 +1,899 @@ +/****************************************************************************************/ +/* STREAK.C */ +/* */ +/* Author: */ +/* Description: Embedded streak bitmap */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +unsigned char Streak_bmp[] = { +0x42, 0x4d, 0x38, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x4, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x80, +0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x1, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, +0xb, 0x0, 0x0, 0x12, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x1, 0x1, 0x0, 0x4, +0x1, 0x1, 0x0, 0x7, 0x3, 0x3, 0x0, 0x9, 0x4, 0x4, 0x0, 0xf, 0xa, 0xa, 0x0, 0x17, 0x10, 0x10, 0x0, 0xc, +0x9, 0x9, 0x0, 0x4, 0x3, 0x3, 0x0, 0x5, 0x4, 0x4, 0x0, 0x6, 0x5, 0x5, 0x0, 0x7, 0x6, 0x6, 0x0, 0x8, +0x7, 0x7, 0x0, 0x9, 0x8, 0x8, 0x0, 0xa, 0x9, 0x9, 0x0, 0xb, 0xa, 0xa, 0x0, 0xc, 0xb, 0xb, 0x0, 0xd, +0xc, 0xc, 0x0, 0xe, 0xd, 0xd, 0x0, 0xf, 0xe, 0xe, 0x0, 0x32, 0x2f, 0x2f, 0x0, 0x11, 0x10, 0x10, 0x0, 0x10, +0xf, 0xf, 0x0, 0x46, 0x42, 0x42, 0x0, 0x12, 0x11, 0x11, 0x0, 0x27, 0x25, 0x25, 0x0, 0x13, 0x12, 0x12, 0x0, 0x15, +0x14, 0x14, 0x0, 0x14, 0x13, 0x13, 0x0, 0x17, 0x16, 0x16, 0x0, 0x16, 0x15, 0x15, 0x0, 0x19, 0x18, 0x18, 0x0, 0x18, +0x17, 0x17, 0x0, 0x1c, 0x1b, 0x1b, 0x0, 0x1b, 0x1a, 0x1a, 0x0, 0x1a, 0x19, 0x19, 0x0, 0x1f, 0x1e, 0x1e, 0x0, 0x1e, +0x1d, 0x1d, 0x0, 0x1d, 0x1c, 0x1c, 0x0, 0x24, 0x23, 0x23, 0x0, 0x23, 0x22, 0x22, 0x0, 0x22, 0x21, 0x21, 0x0, 0x21, +0x20, 0x20, 0x0, 0x2a, 0x29, 0x29, 0x0, 0x25, 0x24, 0x24, 0x0, 0x2c, 0x2b, 0x2b, 0x0, 0x12, 0x7, 0x6, 0x0, 0xd, +0x3, 0x2, 0x0, 0x1c, 0xb, 0x9, 0x0, 0xf, 0x6, 0x5, 0x0, 0x26, 0x1c, 0x1b, 0x0, 0x29, 0x1f, 0x1e, 0x0, 0x2e, +0x24, 0x23, 0x0, 0x33, 0x29, 0x28, 0x0, 0x13, 0x5, 0x3, 0x0, 0x21, 0x9, 0x6, 0x0, 0xb, 0x3, 0x2, 0x0, 0x2b, +0xc, 0x8, 0x0, 0x15, 0x6, 0x4, 0x0, 0x33, 0x12, 0xd, 0x0, 0x23, 0xd, 0xa, 0x0, 0x2c, 0x11, 0xd, 0x0, 0x39, +0x17, 0x12, 0x0, 0x15, 0xe, 0xd, 0x0, 0x1b, 0x13, 0x12, 0x0, 0x1e, 0x16, 0x15, 0x0, 0x22, 0x1a, 0x19, 0x0, 0x10, +0x4, 0x2, 0x0, 0x19, 0x7, 0x4, 0x0, 0x2f, 0xe, 0x8, 0x0, 0x25, 0xb, 0x7, 0x0, 0x43, 0x1c, 0x15, 0x0, 0x16, +0x9, 0x7, 0x0, 0xb, 0x5, 0x4, 0x0, 0x4c, 0x23, 0x1c, 0x0, 0xf, 0x9, 0x8, 0x0, 0x11, 0xb, 0xa, 0x0, 0x52, +0x4c, 0x4b, 0x0, 0x21, 0x7, 0x2, 0x0, 0x2a, 0xa, 0x3, 0x0, 0x26, 0xa, 0x4, 0x0, 0x29, 0xb, 0x5, 0x0, 0x44, +0x14, 0xa, 0x0, 0x4a, 0x16, 0xb, 0x0, 0x1e, 0x9, 0x5, 0x0, 0x3c, 0x14, 0xc, 0x0, 0x8, 0x3, 0x2, 0x0, 0xc, +0x7, 0x6, 0x0, 0x11, 0xc, 0xb, 0x0, 0x12, 0xd, 0xc, 0x0, 0x10, 0x4, 0x1, 0x0, 0x30, 0xc, 0x4, 0x0, 0x4b, +0x14, 0x7, 0x0, 0xb, 0x3, 0x1, 0x0, 0x33, 0xe, 0x5, 0x0, 0xd, 0x4, 0x2, 0x0, 0x58, 0x2d, 0x23, 0x0, 0x67, +0x3a, 0x2f, 0x0, 0xa, 0x6, 0x5, 0x0, 0xb, 0x7, 0x6, 0x0, 0xe, 0xa, 0x9, 0x0, 0x39, 0x35, 0x34, 0x0, 0x37, +0xf, 0x4, 0x0, 0x5b, 0x1d, 0xb, 0x0, 0x50, 0x19, 0xa, 0x0, 0x16, 0x6, 0x1, 0x0, 0x1c, 0x8, 0x2, 0x0, 0x3c, +0x12, 0x5, 0x0, 0x43, 0x15, 0x6, 0x0, 0x37, 0x11, 0x5, 0x0, 0xf, 0x5, 0x2, 0x0, 0x69, 0x26, 0x10, 0x0, 0x62, +0x22, 0xf, 0x0, 0x20, 0xa, 0x2, 0x0, 0x29, 0xd, 0x3, 0x0, 0xd, 0x4, 0x1, 0x0, 0x32, 0x10, 0x4, 0x0, 0x67, +0x23, 0xa, 0x0, 0x55, 0x1c, 0x8, 0x0, 0x62, 0x21, 0xa, 0x0, 0x60, 0x20, 0xa, 0x0, 0x9, 0x3, 0x1, 0x0, 0x11, +0x6, 0x2, 0x0, 0x73, 0x2d, 0x13, 0x0, 0x5, 0x2, 0x1, 0x0, 0x7, 0x4, 0x3, 0x0, 0xb, 0x8, 0x7, 0x0, 0xd, +0xa, 0x9, 0x0, 0xab, 0x85, 0x77, 0x0, 0x12, 0x6, 0x1, 0x0, 0x2e, 0xf, 0x3, 0x0, 0xf, 0x5, 0x1, 0x0, 0x1a, +0x9, 0x2, 0x0, 0x25, 0xd, 0x3, 0x0, 0x17, 0x8, 0x2, 0x0, 0x4a, 0x1a, 0x7, 0x0, 0x6d, 0x28, 0xb, 0x0, 0x65, +0x25, 0xa, 0x0, 0x72, 0x28, 0xc, 0x0, 0x6a, 0x26, 0xb, 0x0, 0x5f, 0x23, 0xa, 0x0, 0x13, 0x7, 0x2, 0x0, 0x7c, +0x2d, 0xe, 0x0, 0x76, 0x2c, 0xd, 0x0, 0x52, 0x1d, 0x9, 0x0, 0xa, 0x5, 0x3, 0x0, 0x78, 0x56, 0x49, 0x0, 0x8d, +0x70, 0x64, 0x0, 0x23, 0xc, 0x2, 0x0, 0x32, 0x11, 0x3, 0x0, 0x11, 0x6, 0x1, 0x0, 0x2b, 0xf, 0x3, 0x0, 0x58, +0x20, 0x8, 0x0, 0x42, 0x19, 0x6, 0x0, 0xb, 0x4, 0x1, 0x0, 0x5c, 0x22, 0x9, 0x0, 0x71, 0x2b, 0xc, 0x0, 0x36, +0x16, 0x7, 0x0, 0x25, 0xf, 0x5, 0x0, 0xf, 0x6, 0x2, 0x0, 0x19, 0xb, 0x5, 0x0, 0xea, 0xab, 0x8f, 0x0, 0x72, +0x62, 0x5b, 0x0, 0x4c, 0x1e, 0x8, 0x0, 0x88, 0x37, 0xf, 0x0, 0x3c, 0x18, 0x7, 0x0, 0x2b, 0x12, 0x5, 0x0, 0x7c, +0x32, 0xf, 0x0, 0x22, 0xe, 0x4, 0x0, 0x30, 0x14, 0x6, 0x0, 0x28, 0x11, 0x5, 0x0, 0x1f, 0xd, 0x4, 0x0, 0x3c, +0x19, 0x8, 0x0, 0x7, 0x3, 0x1, 0x0, 0x4e, 0x22, 0xc, 0x0, 0x54, 0x26, 0xe, 0x0, 0x84, 0x3c, 0x18, 0x0, 0x65, +0x48, 0x3a, 0x0, 0x8, 0x6, 0x5, 0x0, 0x3e, 0x3c, 0x3b, 0x0, 0x82, 0x36, 0xe, 0x0, 0x1c, 0xc, 0x3, 0x0, 0x8f, +0x3e, 0x10, 0x0, 0x46, 0x1e, 0x9, 0x0, 0x5b, 0x2a, 0x10, 0x0, 0x60, 0x2f, 0x13, 0x0, 0x69, 0x35, 0x18, 0x0, 0x9, +0x4, 0x1, 0x0, 0x84, 0x3a, 0xf, 0x0, 0x75, 0x40, 0x20, 0x0, 0x85, 0x4d, 0x2c, 0x0, 0xc, 0x7, 0x4, 0x0, 0x22, +0x15, 0xd, 0x0, 0x1d, 0x12, 0xb, 0x0, 0x9a, 0x49, 0x11, 0x0, 0x88, 0x41, 0x11, 0x0, 0x16, 0xd, 0x7, 0x0, 0x9c, +0x63, 0x3e, 0x0, 0x2a, 0x1c, 0x13, 0x0, 0x31, 0x22, 0x18, 0x0, 0x3b, 0x2b, 0x20, 0x0, 0x5a, 0x57, 0x55, 0x0, 0x8c, +0x47, 0x15, 0x0, 0x92, 0x4d, 0x19, 0x0, 0x11, 0xa, 0x5, 0x0, 0x25, 0x19, 0x10, 0x0, 0x4c, 0x3a, 0x2d, 0x0, 0xf, +0x9, 0x4, 0x0, 0x18, 0xf, 0x8, 0x0, 0xfc, 0xc0, 0x91, 0x0, 0xa7, 0x59, 0x13, 0x0, 0x99, 0x57, 0x1d, 0x0, 0xa3, +0x5e, 0x23, 0x0, 0x13, 0xc, 0x6, 0x0, 0xaf, 0x6e, 0x2c, 0x0, 0x8, 0x5, 0x2, 0x0, 0x9, 0x6, 0x3, 0x0, 0xbb, +0x82, 0x4b, 0x0, 0xb, 0xa, 0x9, 0x0, 0xf, 0xe, 0xd, 0x0, 0x11, 0x10, 0xf, 0x0, 0x13, 0x12, 0x11, 0x0, 0x15, +0x14, 0x13, 0x0, 0x17, 0x16, 0x15, 0x0, 0x19, 0x18, 0x17, 0x0, 0x1b, 0x1a, 0x19, 0x0, 0x1d, 0x1c, 0x1b, 0x0, 0x1f, +0x1e, 0x1d, 0x0, 0x20, 0x1f, 0x1e, 0x0, 0x23, 0x22, 0x21, 0x0, 0x27, 0x26, 0x25, 0x0, 0x25, 0x24, 0x23, 0x0, 0x28, +0x27, 0x26, 0x0, 0x2e, 0x2d, 0x2c, 0x0, 0x2d, 0x2c, 0x2b, 0x0, 0x35, 0x34, 0x33, 0x0, 0xcf, 0x8c, 0x41, 0x0, 0xe5, +0xa8, 0x65, 0x0, 0xc2, 0x7b, 0x27, 0x0, 0xb6, 0x6f, 0x16, 0x0, 0xcc, 0x8c, 0x1c, 0x0, 0xdc, 0xa2, 0x24, 0x0, 0xea, +0xb4, 0x2b, 0x0, 0xfb, 0xd0, 0x3b, 0x0, 0xff, 0xea, 0xa1, 0x0, 0xff, 0xf1, 0x69, 0x0, 0xff, 0xfe, 0xd0, 0x0, 0x2, +0x2, 0x1, 0x0, 0x4, 0x4, 0x3, 0x0, 0x6, 0x6, 0x5, 0x0, 0x8, 0x8, 0x7, 0x0, 0xc, 0xc, 0xb, 0x0, 0xff, +0xff, 0xff, 0x0, 0x2, 0x2, 0x2, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, +0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, +0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, +0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, +0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, +0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, +0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, +0xfe, 0xf6, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, +0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0xf6, 0xfd, 0xfd, 0xfe, 0xfd, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, +0xfd, 0xf6, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xf6, 0xfd, 0xfd, 0xfe, +0xfe, 0xf6, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, +0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xf6, 0xfd, 0xf6, 0xf6, 0xf6, +0xfd, 0xf6, 0xfd, 0xfc, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, +0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, +0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, +0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0x7, 0x7, 0xfc, 0xf6, 0xfd, 0xfe, 0xfd, 0xfc, 0xf6, 0xf6, +0xf6, 0xfe, 0xfd, 0xfc, 0xf6, 0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xfc, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xf6, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, +0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfc, 0xf6, 0xfc, 0xfc, 0xfd, 0xf6, 0xf6, 0xfc, 0xf6, 0xf6, 0xfd, 0xf6, 0xfc, 0xfc, 0xfc, +0xfc, 0xfc, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfe, 0xfe, 0xfe, 0xfd, +0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, +0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0x7, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xfc, +0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, +0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, +0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xf6, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x8, 0x7, 0xfc, 0xf6, +0xf6, 0xfc, 0x7, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0x7, 0xfc, 0xfc, 0xf6, 0xf6, 0xfc, 0x7, 0x7, 0xfc, 0xfd, 0xfd, 0xfd, +0xfd, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, +0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfc, 0xf6, 0xfc, 0xfc, +0xfc, 0x7, 0x7, 0x8, 0x8, 0x8, 0x7, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +0x7, 0x7, 0x7, 0x7, 0xfc, 0xf6, 0xf6, 0xfc, 0xf6, 0xfd, 0xfd, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfd, 0xfd, +0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xf6, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xf6, 0xfe, 0xfe, 0xfe, 0xfd, 0xf6, 0xfc, +0xf6, 0xfc, 0xfd, 0xfd, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x9, 0x8, 0x8, 0x7, 0xfc, 0xfc, 0x7, 0x7, 0x7, +0x7, 0xfc, 0x7, 0x7, 0xfc, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x8, 0x7, 0xfc, 0xf6, 0xfc, 0xfd, 0xfc, 0xf6, 0xf6, 0xf6, +0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xfd, 0xf6, 0xf6, 0xfc, 0x7, 0x7, 0x7, 0x8, 0x8, +0x9, 0x9, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0xfc, 0x7, 0x7, 0x8, 0x8, 0x7, +0xfc, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, +0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xf6, 0xf6, 0xfd, +0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, +0xfc, 0xf6, 0x7, 0x7, 0x7, 0xf7, 0x8, 0x9, 0xa, 0x9, 0x8, 0x7, 0x7, 0x7, 0x8, 0xf7, 0x7, 0x7, 0x7, 0xf7, +0x7, 0x7, 0x7, 0xf7, 0x8, 0x8, 0xf7, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, +0xf6, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, +0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xf6, 0xfc, 0xfd, 0xfc, 0xf6, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, +0xf6, 0xf6, 0xf6, 0xfd, 0xf6, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x8, 0x9, 0xa, 0xb, 0xa, 0xa, 0x8, +0x7, 0xf7, 0x8, 0x8, 0x7, 0x7, 0x7, 0x8, 0x8, 0x7, 0x8, 0x8, 0x9, 0x9, 0x8, 0x7, 0xfc, 0xfc, 0x7, 0x7, +0x7, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xf6, 0xfc, 0xf6, 0xf6, 0xfc, +0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, +0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, +0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0xfc, 0x7, +0xf7, 0x8, 0x8, 0xa, 0xb, 0xc, 0xa, 0x8, 0x8, 0xf7, 0x9, 0x9, 0x8, 0x7, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, +0xa, 0x9, 0x8, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x8, 0x7, 0x8, 0x7, 0x7, 0xfc, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, +0xfe, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, +0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, +0xf6, 0xfd, 0xfd, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfd, 0xf6, 0xfd, 0xf6, 0xfc, 0xf6, +0xf6, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0x7, 0x8, 0x8, 0x9, 0xb, 0xc, 0xc, 0xb, 0xa, 0x9, 0x8, 0x9, 0x9, +0x8, 0x8, 0x9, 0x9, 0x8, 0x9, 0x9, 0xa, 0xa, 0x9, 0xf7, 0x7, 0x7, 0xf7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x7, +0x7, 0xfc, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, +0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xf6, 0xfd, 0xfd, 0xfc, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +0xfc, 0xfc, 0xf6, 0xfd, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0x7, 0xf7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x9, 0xb, +0xb, 0x6, 0xd, 0xb, 0xa, 0x9, 0xa, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0xa, 0xb, 0xa, 0xf8, 0x8, 0x7, +0x8, 0x7, 0x8, 0x8, 0x8, 0x8, 0xf7, 0xf7, 0x7, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xfc, 0x7, 0xfc, 0xfc, +0xfc, 0xfc, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfd, 0xf6, 0xf6, 0xfd, 0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xf6, 0xfd, 0xfc, 0xfd, 0xfc, +0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0xf6, 0xfc, 0xfc, 0xfd, 0xf6, 0xfc, 0x7, 0xfc, 0xfc, 0x7, +0x7, 0x7, 0x8, 0x7, 0x7, 0x9, 0xa, 0xb, 0xc, 0xd9, 0x6, 0xd, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, +0xa, 0xa, 0xb, 0xc, 0xb, 0x9, 0x8, 0x7, 0x8, 0x8, 0x8, 0x9, 0x9, 0x8, 0x8, 0x7, 0xf6, 0xfd, 0xfd, 0xfd, +0xfd, 0xfc, 0x7, 0x7, 0xf7, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, +0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0xf6, 0xfd, +0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, +0xf6, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0x7, 0xfc, 0xf7, 0x7, 0x8, 0xf7, 0xf7, 0x8, 0xa, 0xb, 0xd, 0xf, 0xf, 0xd9, +0xc, 0xb, 0xb, 0xb, 0xa, 0xa, 0xb, 0xb, 0xb, 0xb, 0xc, 0xc, 0xb, 0x9, 0x8, 0x9, 0x8, 0x9, 0xa, 0x9, +0x9, 0x8, 0x7, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, +0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, +0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, +0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xf6, 0xfc, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, +0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0x7, 0x7, 0xfc, 0x7, 0x7, 0x8, 0x8, 0x8, +0x8, 0x8, 0x9, 0xb, 0xd, 0xf, 0x10, 0x10, 0xd, 0xc, 0xc, 0xc, 0xb, 0xb, 0xb, 0xb, 0xc, 0xd, 0xd, 0xd, +0xa, 0xa, 0x9, 0x9, 0xf8, 0xa, 0xa, 0xa, 0x9, 0x7, 0xfc, 0xfc, 0xfd, 0xf6, 0x7, 0x7, 0xf7, 0x8, 0x8, 0x7, +0x7, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, +0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, +0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0xf7, 0xf7, 0x8, 0x8, 0x7, 0x7, 0x7, 0x7, +0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x9, 0x9, 0xa, 0xb, 0xd, 0x10, 0x11, 0x11, 0xf, 0xd, 0xd, 0xd, +0xd, 0xc, 0xc, 0xd, 0x6, 0xe, 0xe, 0xd, 0xa, 0xa, 0x9, 0xa, 0xa, 0xb, 0xb, 0x9, 0x8, 0x7, 0xfd, 0xfd, +0xfc, 0x7, 0x8, 0x8, 0x8, 0x8, 0x7, 0x7, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, +0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, +0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0x7, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, +0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x8, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x9, 0xf8, 0x9, 0xa, 0xf9, +0xd, 0x10, 0x15, 0x15, 0x11, 0xf, 0xe, 0xe, 0xd9, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xd, 0xb, 0xb, 0xb, 0xc, +0xc, 0xc, 0xa, 0x9, 0x7, 0xfc, 0xf6, 0xfc, 0x7, 0x8, 0x9, 0x9, 0x8, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, +0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, +0xf6, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, +0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0xf8, 0x9, 0x8, 0x8, 0x8, 0x7, +0x8, 0x9, 0x9, 0xf8, 0xa, 0xa, 0xb, 0xc, 0xe, 0x11, 0x15, 0x14, 0x15, 0x11, 0xf, 0x10, 0xf, 0xe, 0xf, 0x10, +0x11, 0x11, 0x10, 0xd, 0xc, 0xc, 0xd, 0xd, 0xc, 0xb, 0xa, 0x7, 0x7, 0xfc, 0x7, 0x8, 0x9, 0xf8, 0x9, 0x8, +0x7, 0x7, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, +0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, +0xfd, 0xf6, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, +0x9, 0xa, 0xf8, 0xa, 0x9, 0x9, 0x9, 0x8, 0x8, 0x9, 0x9, 0x9, 0xa, 0xa, 0xb, 0xc, 0xe, 0x11, 0x17, 0x1b, +0x17, 0x15, 0x12, 0x10, 0x11, 0x11, 0x11, 0xda, 0xda, 0xda, 0x10, 0xe, 0xd, 0xe, 0xe, 0xd, 0xd, 0xa, 0x9, 0x7, +0x7, 0x8, 0x9, 0xa, 0xa, 0xa, 0x9, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfc, +0xfc, 0xfc, 0xfd, 0xfc, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0xf6, 0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xf7, 0x8, 0x8, 0x8, 0x8, +0x8, 0x8, 0x8, 0x8, 0x7, 0xf7, 0x8, 0x9, 0x9, 0x9, 0xf8, 0xa, 0xb, 0xa, 0xf8, 0xa, 0x9, 0x9, 0x9, 0xa, +0xa, 0xb, 0xb, 0xc, 0xe, 0x11, 0x17, 0x1a, 0xdd, 0x19, 0xdb, 0x15, 0x11, 0x12, 0x15, 0x15, 0x15, 0x15, 0x10, 0xf, +0xf, 0xf, 0xf, 0xe, 0xb, 0x9, 0x8, 0x8, 0x9, 0xa, 0xa, 0xb, 0xa, 0x9, 0x8, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, +0x7, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, +0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, +0xfd, 0xf6, 0xf6, 0xfc, 0x7, 0x7, 0x8, 0x9, 0x9, 0x8, 0x9, 0x9, 0x8, 0x9, 0x9, 0x9, 0x9, 0xf8, 0xa, 0xa, +0xb, 0xb, 0xb, 0xb, 0xa, 0xa, 0xf8, 0xb, 0xa, 0xf9, 0xc, 0xd, 0xf, 0xda, 0x19, 0x1d, 0x1c, 0x1d, 0x1b, 0x17, +0xdb, 0x14, 0x17, 0xdc, 0x17, 0xdb, 0xda, 0x10, 0x10, 0x11, 0xf, 0xd, 0xa, 0x9, 0x9, 0xa, 0xa, 0xb, 0xa, 0xa, +0x8, 0x8, 0x7, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0x7, 0x7, 0xfc, 0x7, 0xfc, 0x7, +0xfc, 0x7, 0xfc, 0xf6, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xf6, 0x7, 0x7, 0x8, 0x8, 0x8, 0x9, 0xf8, +0xa, 0xa, 0x9, 0x9, 0xa, 0xa, 0xa, 0xb, 0xb, 0xc, 0xc, 0xd, 0xd, 0xc, 0xb, 0xc, 0xc, 0xc, 0xd, 0xe, +0xf, 0x12, 0x19, 0x1f, 0x22, 0x22, 0x1c, 0x1a, 0x1b, 0x1b, 0xdd, 0x1a, 0x1b, 0x17, 0x15, 0x12, 0x12, 0x11, 0xe, 0xc, +0xa, 0xa, 0xb, 0xc, 0xc, 0xf9, 0xa, 0x9, 0x8, 0x8, 0x7, 0x7, 0x7, 0xf7, 0x7, 0xf7, 0x7, 0x7, 0x7, 0xf7, +0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, +0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, +0xfd, 0xfd, 0xfc, 0xfc, 0x7, 0x8, 0x8, 0x9, 0xa, 0xa, 0xb, 0xa, 0xb, 0xb, 0xb, 0xb, 0xc, 0xf9, 0xc, 0xe, +0xe, 0xd, 0xe, 0xd, 0xc, 0xc, 0xd, 0xe, 0x10, 0x15, 0x19, 0xdf, 0x20, 0x24, 0xe0, 0x1f, 0x1c, 0x1f, 0x1f, 0x1f, +0x1d, 0x1b, 0x17, 0x14, 0x15, 0x11, 0xe, 0xc, 0xc, 0xc, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x8, 0x8, 0xf7, 0x8, +0x8, 0x8, 0xf7, 0x7, 0x8, 0x8, 0x8, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, +0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0x7, 0x8, 0x8, 0x9, 0xa, 0xb, +0xf9, 0xf9, 0xc, 0xc, 0xc, 0xc, 0xd, 0xe, 0xe, 0xf, 0x10, 0xf, 0xf, 0xf, 0xe, 0xfa, 0x11, 0x15, 0x1b, 0x22, +0x23, 0x29, 0xe2, 0x25, 0xe0, 0x20, 0x20, 0x21, 0x1f, 0x1d, 0x1b, 0x17, 0x15, 0x10, 0xe, 0xd, 0xe, 0xe, 0xd, 0xc, +0xb, 0x9, 0x8, 0x9, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x9, 0x8, 0x8, 0x7, 0x7, 0xfc, 0xfc, +0xf6, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, +0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, +0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0x7, 0x9, 0x9, 0xb, 0xc, 0xc, 0xc, 0xd, 0xe, 0xe, 0xe, 0x10, 0x11, 0x11, 0x11, +0x11, 0x11, 0x10, 0x11, 0x12, 0x14, 0x1a, 0xe0, 0x29, 0x2b, 0x26, 0x28, 0x29, 0xe3, 0xe3, 0x24, 0x21, 0xdf, 0x1d, 0x17, +0x15, 0x11, 0x10, 0xfa, 0xfa, 0xe, 0xc, 0xb, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x9, 0x8, 0x9, +0x8, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, +0xfe, 0xfd, 0xf6, 0xfd, 0xfc, 0xf6, 0xf6, 0xfd, 0xfd, 0xf6, 0xfd, 0xfc, 0xfd, 0xf6, 0xfd, 0xf6, 0xfc, 0xfd, 0xfc, 0xfc, +0xfd, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xf6, 0xfc, 0xf7, 0x8, 0xa, 0xb, 0xc, +0xd, 0xe, 0xe, 0xfa, 0x10, 0x11, 0x12, 0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x19, 0x1d, 0x20, 0x26, 0x2a, 0x2c, 0x2a, +0xe7, 0x18, 0x2b, 0x28, 0x24, 0x22, 0x1c, 0x19, 0x14, 0x12, 0x12, 0x10, 0xf, 0xe, 0xc, 0xb, 0xf9, 0xc, 0xc, 0xb, +0xa, 0xa, 0xa, 0xa, 0xa, 0x8, 0x8, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xf6, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, +0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, +0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfd, 0xf6, 0xf6, 0xfd, +0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0x7, 0x8, 0x9, 0xa, 0xd, 0xe, 0x10, 0x10, 0x12, 0x15, 0x14, 0x19, 0x1b, 0x1b, 0x1a, +0x1a, 0x1d, 0x1e, 0xe2, 0x18, 0x13, 0x13, 0x13, 0xe8, 0xe8, 0x2a, 0x18, 0x29, 0x20, 0x1c, 0x1b, 0x14, 0x15, 0x12, 0x11, +0xfa, 0xe, 0xd, 0xd, 0xd, 0xc, 0xc, 0xb, 0xb, 0xa, 0x9, 0x9, 0x8, 0x7, 0x8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, +0xfc, 0xfd, 0xf6, 0xf6, 0xfc, 0xfd, 0xfc, 0xfd, 0xfc, 0xf6, 0xfd, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, +0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xf6, 0xfd, 0xfc, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, +0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0x8, 0x9, 0xa, 0xc, 0xd, +0xf, 0x10, 0x15, 0x14, 0x1b, 0x1a, 0x1c, 0x1e, 0x22, 0x22, 0xe1, 0x28, 0x2a, 0xea, 0xb2, 0xb2, 0xb2, 0x64, 0xea, 0x2a, +0x26, 0x24, 0x1e, 0x1d, 0x19, 0x17, 0x12, 0x12, 0xfa, 0xf, 0xe, 0xe, 0xd, 0xc, 0xc, 0xb, 0xa, 0x9, 0x9, 0x8, +0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfd, 0xf6, +0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, +0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, +0x8, 0x7, 0x8, 0x8, 0x8, 0x8, 0xa, 0xb, 0xd, 0xe, 0x11, 0x15, 0x17, 0x1a, 0x1f, 0x22, 0x25, 0x29, 0x28, 0xe7, +0x13, 0xb2, 0x4c, 0x4c, 0x4c, 0x16, 0xb2, 0xe8, 0xe7, 0xe3, 0x21, 0x1f, 0x1b, 0x17, 0x15, 0x12, 0x10, 0xf, 0xe, 0xe, +0xd, 0xc, 0xa, 0xa, 0x9, 0x8, 0x8, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, 0xfc, +0xfc, 0xf6, 0xfc, 0xfc, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, +0xfd, 0xfe, 0xfd, 0xfd, 0xf6, 0xfd, 0xf6, 0xfc, 0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, +0x2, 0x9, 0x9, 0xb1, 0xb1, 0xb1, 0x61, 0x61, 0x61, 0x61, 0x62, 0x61, 0x62, 0x56, 0x56, 0x56, 0x4a, 0x4b, 0x4b, 0x58, +0x5, 0x3f, 0x40, 0x41, 0x32, 0x32, 0x34, 0x34, 0x16, 0x4c, 0xa1, 0x92, 0x92, 0xa1, 0xc8, 0xb0, 0xcd, 0xc7, 0xc7, 0xc6, +0xc6, 0xc5, 0xc5, 0xcc, 0xbf, 0xbf, 0xc0, 0xc0, 0xcf, 0xcf, 0xc3, 0xd4, 0xd4, 0xcb, 0xce, 0xce, 0xbe, 0xbe, 0x61, 0xd7, +0xd6, 0xb1, 0x7c, 0x7c, 0xf7, 0x8, 0x7, 0xfc, 0x7, 0xf6, 0xfc, 0xf6, 0xfc, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, +0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, +0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x78, 0x37, 0x37, 0x2e, 0x2e, +0x2e, 0x5e, 0x59, 0x42, 0x42, 0x35, 0x35, 0x39, 0x68, 0x43, 0x43, 0x43, 0x53, 0x36, 0x4d, 0x36, 0x4f, 0x45, 0x45, 0x38, +0x38, 0x38, 0x44, 0x44, 0x44, 0x44, 0x3a, 0x54, 0x54, 0x46, 0x46, 0x49, 0x49, 0x5f, 0x60, 0x60, 0x91, 0xc4, 0x7f, 0xa0, +0xa0, 0xec, 0xd8, 0xc4, 0xbd, 0xbd, 0xbc, 0xbc, 0xb9, 0xb9, 0xb8, 0xb8, 0xb7, 0xb7, 0xae, 0xae, 0xad, 0xad, 0xb6, 0xb6, +0xb6, 0xab, 0xab, 0xa4, 0x9c, 0xa8, 0xa8, 0xa5, 0xa5, 0xa9, 0x9d, 0xa7, 0xa7, 0xaa, 0xb4, 0xb4, 0xb4, 0x85, 0x85, 0x85, +0x8c, 0x8c, 0x79, 0x6d, 0x9e, 0x72, 0x72, 0x99, 0x5c, 0x55, 0xac, 0xac, 0x7b, 0x7b, 0x1, 0xf6, 0xfe, 0xfe, 0xfd, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xf6, 0x1, 0xac, 0x78, 0x5c, 0x2e, 0x59, 0x35, 0x68, +0x68, 0x69, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x5a, 0x5a, 0x5a, 0x65, 0x65, 0x6a, 0x6a, 0x6b, 0x51, 0x5b, 0x5b, 0x5b, +0x67, 0x75, 0x75, 0x66, 0x77, 0x76, 0x74, 0x8a, 0x87, 0x87, 0x9b, 0x8e, 0xa6, 0xa6, 0xb3, 0xc2, 0xc2, 0xc9, 0xca, 0xd2, +0xd3, 0xd5, 0xd5, 0xeb, 0xeb, 0xd0, 0xf3, 0xf5, 0xf5, 0xd0, 0xec, 0xeb, 0xed, 0xd5, 0xd5, 0xd3, 0xd2, 0xd2, 0xd2, 0xca, +0xc9, 0xc9, 0xc9, 0xc9, 0xc2, 0xa3, 0xbb, 0xa3, 0xb3, 0xb3, 0xa6, 0xa6, 0x8e, 0x9b, 0x87, 0x87, 0x6e, 0x88, 0x8b, 0x8b, +0x9a, 0x97, 0x8f, 0x8f, 0xa2, 0xa2, 0x86, 0x98, 0x98, 0x6a, 0x6a, 0x9c, 0x94, 0x81, 0x71, 0x84, 0x93, 0x69, 0x83, 0x68, +0x80, 0x82, 0x99, 0xac, 0x1, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0x1, +0xac, 0x5c, 0x82, 0x8c, 0x68, 0x69, 0x70, 0x93, 0x71, 0x81, 0x81, 0x65, 0x6a, 0x6a, 0x6b, 0x6b, 0x86, 0x67, 0x75, 0x97, +0x97, 0x77, 0x76, 0x74, 0x8a, 0x87, 0x89, 0x8e, 0x8d, 0x8d, 0xb3, 0xa3, 0xb5, 0xb5, 0xc1, 0xc1, 0xc1, 0xd1, 0xd1, 0xd1, +0xd1, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf2, 0xf2, 0xf4, 0xf4, 0xf5, 0xfb, 0xfb, 0xf5, 0xf4, 0xf4, +0xf2, 0xf2, 0xf1, 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xed, 0xee, 0xee, 0xee, 0xee, 0xd1, 0xd1, 0xd1, 0xc1, 0xc1, 0xc1, +0xb5, 0xb5, 0xa3, 0xb3, 0xa6, 0x8d, 0x7a, 0x89, 0x87, 0x8a, 0x88, 0x76, 0x9a, 0x66, 0x75, 0x8f, 0x86, 0x86, 0x6b, 0x6b, +0x6a, 0x6c, 0x73, 0x81, 0x71, 0x84, 0x70, 0x83, 0x85, 0x8c, 0x6d, 0x78, 0x7, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xac, 0x5c, 0x72, 0x95, 0x68, 0x83, 0x69, 0x70, 0x93, 0x71, 0x96, 0x81, +0x94, 0x6c, 0x6a, 0x98, 0x98, 0x86, 0x86, 0xa2, 0x8f, 0x8f, 0x97, 0x9a, 0x8b, 0x8b, 0x88, 0x74, 0x8a, 0x87, 0x9b, 0x8e, +0x8e, 0x8d, 0xa6, 0xb3, 0xb3, 0xb3, 0xbb, 0xbb, 0xbb, 0xc2, 0xc2, 0xc9, 0xc9, 0xca, 0xd2, 0xd2, 0xd3, 0xd5, 0xd5, 0xd8, +0xec, 0xd0, 0xf3, 0xfb, 0xf5, 0xf3, 0xd0, 0xec, 0xeb, 0xeb, 0xed, 0xed, 0xd5, 0xd3, 0xd3, 0xd3, 0xd2, 0xca, 0xca, 0xc9, +0xaf, 0xaf, 0xaf, 0xa6, 0x7a, 0x7a, 0x7a, 0x6e, 0x6e, 0x6f, 0x6f, 0x66, 0x66, 0x66, 0x67, 0x67, 0x52, 0x52, 0x51, 0x51, +0x54, 0x6a, 0x6c, 0x6c, 0x5d, 0x44, 0x38, 0x50, 0x4f, 0x4f, 0x36, 0x53, 0x69, 0x43, 0x39, 0x35, 0x42, 0x5e, 0x37, 0x55, +0x7, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0x1, 0x1, 0x7b, +0x2, 0xac, 0x55, 0xba, 0x99, 0x72, 0x72, 0x79, 0x79, 0x8c, 0x85, 0x85, 0x9f, 0xb4, 0xaa, 0xaa, 0xa7, 0x9d, 0xa9, 0xa5, +0xa5, 0xa8, 0xa8, 0x9c, 0x9c, 0xa4, 0xa4, 0xa4, 0x98, 0xb6, 0xb6, 0xa2, 0xad, 0xad, 0xae, 0xae, 0xb7, 0xb7, 0xb8, 0xb8, +0xb9, 0xb9, 0xbc, 0xbc, 0xbd, 0xbd, 0xc4, 0xc4, 0xd8, 0xec, 0xa0, 0xd0, 0xa0, 0x7f, 0x92, 0xc4, 0xb0, 0x60, 0x60, 0x5f, +0x5f, 0x5f, 0x5f, 0x49, 0x49, 0x49, 0x46, 0x46, 0x46, 0x3d, 0x3d, 0x3d, 0x3d, 0x3a, 0x3a, 0x3a, 0x3c, 0x3c, 0x3c, 0x3c, +0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x2f, 0x2f, 0x2f, 0x2f, 0x47, 0x47, 0x47, 0x2d, 0x2d, 0x2d, 0x30, 0x30, 0x56, 0x56, 0x48, +0x48, 0x3, 0x3, 0x2, 0x7c, 0x2, 0x2, 0x1, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, +0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, +0x1, 0x7, 0x7b, 0x7c, 0xac, 0x55, 0x55, 0xd6, 0x90, 0x90, 0xbe, 0xbe, 0xbe, 0xce, 0xce, 0xcb, 0xd4, 0xd4, 0xc3, 0xcf, +0xcf, 0xc0, 0xc0, 0xbf, 0xcc, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xcd, 0xcd, 0xcd, 0xb0, 0xa1, 0x92, 0x7f, 0x7f, +0x92, 0xa1, 0x4c, 0x16, 0x64, 0x34, 0x33, 0x32, 0x32, 0x31, 0x41, 0x41, 0x40, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x5, 0x5, +0x5, 0x3e, 0x3e, 0x58, 0x58, 0x58, 0x57, 0x4b, 0x4, 0x63, 0x7e, 0x6, 0x6, 0x7d, 0x7d, 0x62, 0xb, 0xb, 0xb, 0xb1, +0xa, 0xa, 0x9, 0x8, 0x9, 0x8, 0x8, 0x7, 0xf7, 0x8, 0x7, 0x7, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xf6, +0xfc, 0xf6, 0xf6, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, +0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, +0x7, 0x8, 0x9, 0xa, 0xa, 0xb, 0xd, 0xe, 0x10, 0x11, 0x15, 0x17, 0x1b, 0x1a, 0x1f, 0x1e, 0x20, 0x24, 0x23, 0xe4, +0x18, 0x2a, 0x13, 0x64, 0x16, 0x4c, 0xc8, 0xc8, 0x4c, 0x16, 0x64, 0x13, 0xe7, 0xe4, 0x24, 0x22, 0x1c, 0x1a, 0x1b, 0x17, +0x17, 0x17, 0x14, 0x15, 0x12, 0x11, 0x11, 0x11, 0x10, 0xf, 0xf, 0xe, 0xe, 0xd, 0xd, 0xd, 0xd, 0xc, 0xb, 0xf9, +0xb, 0xa, 0xa, 0xa, 0xf8, 0xa, 0x9, 0x8, 0x8, 0x8, 0x8, 0xf7, 0x8, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, +0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xf6, 0xfc, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, +0xf6, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x8, 0x9, 0xf8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xfa, 0x11, 0x15, 0x14, 0x17, 0x1b, +0x1b, 0x1a, 0x1d, 0x1c, 0x1e, 0x22, 0x20, 0x24, 0xe3, 0x27, 0xe5, 0x2c, 0xea, 0xb2, 0x16, 0xb2, 0x64, 0x13, 0x2a, 0x18, +0x28, 0x24, 0x21, 0x1c, 0x19, 0x14, 0x12, 0x11, 0x11, 0x11, 0x10, 0xfa, 0xfa, 0xf, 0xe, 0xe, 0xe, 0xd, 0xc, 0xc, +0xc, 0xc, 0xc, 0xb, 0xb, 0xb, 0xb, 0xa, 0xa, 0xa, 0x9, 0x8, 0x9, 0x9, 0x8, 0xf7, 0x8, 0xf7, 0x7, 0x8, +0x7, 0x7, 0x7, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xf6, 0xf6, 0xf6, 0xfd, 0xf6, 0xf6, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, +0xfd, 0xfd, 0xfd, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x8, 0x9, 0x9, 0xa, 0xb, 0xc, 0xc, 0xd, 0xf, +0x10, 0x11, 0x12, 0x15, 0x15, 0x14, 0x14, 0x14, 0x14, 0x17, 0x17, 0x1b, 0x1d, 0x1c, 0x1f, 0x22, 0x20, 0x25, 0x29, 0x18, +0xe8, 0xea, 0xea, 0x13, 0x2a, 0xe6, 0x29, 0x23, 0x25, 0x22, 0x1e, 0x1d, 0x1b, 0x14, 0x11, 0xf, 0xe, 0xd, 0xd, 0xd, +0xd, 0xd, 0xd, 0xd, 0xc, 0xc, 0xc, 0xb, 0xb, 0xa, 0xa, 0x9, 0xf8, 0xf8, 0xa, 0xf8, 0x9, 0x9, 0x8, 0x8, +0x8, 0x8, 0x8, 0x8, 0x7, 0xf7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xf6, 0xf6, 0xf6, 0xf6, 0xfd, 0xf6, +0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0x7, 0x7, 0xf7, 0x7, 0x8, 0x9, 0xa, +0xa, 0xf9, 0xc, 0xd, 0xd, 0xe, 0xe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x10, 0x10, 0x10, 0x11, 0x12, 0x15, 0x14, +0x19, 0xdd, 0x1a, 0x1d, 0x1f, 0x22, 0x25, 0x28, 0xe7, 0xe8, 0xe9, 0xe5, 0xe3, 0x20, 0xe0, 0x22, 0xdf, 0x1d, 0x1a, 0x1b, +0x19, 0x14, 0x12, 0x10, 0xd, 0xc, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xa, 0xa, 0x9, 0xa, 0x9, 0x9, +0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x7, 0x7, 0x7, 0x7, 0xf7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, +0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xf6, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +0x7, 0x7, 0x8, 0x9, 0x9, 0xa, 0xa, 0xb, 0xc, 0xc, 0xd, 0xd, 0xd, 0xd9, 0xd, 0xe, 0xe, 0xe, 0xe, 0xe, +0xd, 0xe, 0xe, 0xe, 0x10, 0x11, 0x12, 0x15, 0x17, 0x17, 0x19, 0x1b, 0x1b, 0x1d, 0x1e, 0x23, 0xe6, 0xe7, 0x2b, 0xe3, +0x1e, 0x1c, 0x1d, 0x1d, 0x1a, 0x19, 0x17, 0x14, 0x14, 0x15, 0x15, 0x10, 0xe, 0xc, 0xa, 0xf8, 0xa, 0xa, 0xf8, 0xa, +0xa, 0x9, 0x9, 0x9, 0x9, 0x8, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8, 0x7, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, +0xfc, 0x7, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xf6, 0xfc, 0xf6, 0xf6, 0xf6, 0xf6, 0xfd, 0xf6, 0xfd, 0xf6, 0xfd, +0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, +0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0x7, 0x8, 0x8, 0x8, 0x8, 0xa, 0xa, 0xa, 0xb, 0xb, 0xb, 0xb, 0xc, 0xc, +0xc, 0xc, 0xc, 0xc, 0xc, 0xb, 0xc, 0xc, 0xc, 0xc, 0xd, 0xe, 0xfa, 0x11, 0x12, 0x12, 0x15, 0x15, 0x15, 0x14, +0x14, 0x1b, 0x1f, 0x25, 0x29, 0x28, 0x23, 0x22, 0x1a, 0x17, 0x17, 0x19, 0xdc, 0x14, 0x15, 0x12, 0x12, 0x12, 0x11, 0x11, +0x10, 0xe, 0xb, 0xa, 0x9, 0x9, 0x8, 0x8, 0x9, 0x8, 0x9, 0x8, 0x8, 0x9, 0x8, 0x8, 0x8, 0x8, 0x7, 0x7, +0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xf6, 0xf6, 0xfd, +0xfc, 0xf6, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, +0xfd, 0xfe, 0xfd, 0xfd, 0xf6, 0xfc, 0xfd, 0xf6, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x8, 0xf7, 0x8, 0x9, 0x9, 0x9, 0xf8, +0x9, 0xa, 0xa, 0xa, 0xa, 0xa, 0xb, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xb, 0xc, 0xd, 0xe, +0xf, 0xf, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x15, 0x19, 0x1c, 0xe0, 0x25, 0x24, 0xe0, 0x1d, 0x17, 0x12, 0x12, 0x14, +0x15, 0x15, 0x12, 0x10, 0x10, 0xfa, 0x10, 0x10, 0xf, 0xf, 0xd, 0xf9, 0xf8, 0x8, 0x7, 0x7, 0x7, 0x7, 0xf7, 0x7, +0x7, 0x7, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfc, +0xf6, 0xf6, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xfd, 0xf6, 0xfe, 0xf6, 0xfd, 0xf6, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, +0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x8, +0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0x8, +0x9, 0x9, 0xf8, 0xb, 0xf9, 0xd, 0xd, 0xe, 0xe, 0xd, 0xe, 0xe, 0xf, 0xfa, 0xf, 0x10, 0x12, 0x17, 0x1d, 0xdf, +0x22, 0xdf, 0xde, 0x19, 0x11, 0xfa, 0x10, 0x10, 0x11, 0x11, 0x10, 0x10, 0xd, 0xd, 0xd, 0xe, 0xe, 0xe, 0xe, 0xc, +0xc, 0xa, 0x8, 0x7, 0x7, 0x7, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0x7, 0x7, 0xfc, +0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, +0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xf6, 0xfc, +0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x8, 0x7, 0x7, 0x8, 0x7, 0x8, 0x8, 0x8, 0xf7, 0x8, 0x8, 0x8, +0x8, 0xf7, 0x7, 0x8, 0x8, 0x8, 0xf7, 0x8, 0x9, 0x9, 0xa, 0xb, 0xc, 0xd, 0xd, 0xc, 0xc, 0xc, 0xc, 0xd, +0xe, 0xe, 0xd, 0xf, 0x12, 0x17, 0x1a, 0x1d, 0xde, 0x1d, 0x1b, 0x15, 0x10, 0xd, 0xd, 0xf, 0x10, 0xf, 0xe, 0xf, +0xd, 0xc, 0xb, 0xc, 0xc, 0xd, 0xc, 0xd, 0xc, 0xb, 0xf8, 0x9, 0x8, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0x7, +0xfc, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfd, 0xfd, 0xf6, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, +0xfe, 0xf6, 0xfd, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, +0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x8, 0x8, 0xa, 0xa, 0xb, 0xb, +0xb, 0xf9, 0xb, 0xb, 0xb, 0xc, 0xc, 0xd, 0xc, 0xc, 0xd, 0xf, 0x11, 0x17, 0x19, 0x19, 0x1b, 0x19, 0x14, 0x11, +0xe, 0xf9, 0xc, 0xd, 0xe, 0xe, 0xd, 0xe, 0xd, 0xc, 0xb, 0xb, 0xa, 0xb, 0xc, 0xb, 0xb, 0xb, 0xb, 0xa, +0x9, 0x7, 0xfc, 0xf6, 0xf6, 0xfd, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfc, +0xf6, 0xf6, 0xfd, 0xfc, 0xfd, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, +0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, +0x7, 0x7, 0x8, 0xf8, 0xa, 0xb, 0xa, 0xb, 0xa, 0xf8, 0x9, 0xa, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xd, 0xf, +0x11, 0x15, 0x14, 0x14, 0x17, 0xdb, 0xda, 0x10, 0xc, 0xa, 0xb, 0xc, 0xd, 0xd, 0xd, 0xc, 0xc, 0xc, 0xa, 0xa, +0x9, 0xa, 0xa, 0xb, 0xa, 0xa, 0xb, 0xb, 0xa, 0x9, 0x7, 0xfc, 0xfc, 0xfd, 0xfd, 0xf6, 0xf6, 0xfc, 0xf6, 0xf6, +0xfc, 0xfc, 0xf6, 0xfc, 0xf6, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, +0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, 0xf6, +0xf6, 0xf6, 0xfc, 0xfc, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, +0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x8, 0x8, 0x8, 0xa, 0xa, 0xa, 0xa, 0x9, 0x9, 0x8, 0x9, 0xa, +0xa, 0xb, 0xa, 0xa, 0xa, 0xb, 0xc, 0xf, 0x11, 0x12, 0x12, 0x12, 0x12, 0xda, 0x10, 0xe, 0xb, 0x9, 0xa, 0xb, +0xc, 0xc, 0xc, 0xb, 0xb, 0xc, 0xa, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0xa, 0xa, 0xa, 0x8, 0xf7, +0xfc, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xf6, 0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, +0xf6, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x8, 0x8, 0x9, 0xf8, +0x9, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0xf8, 0x9, 0xf8, 0x9, 0xa, 0xb, 0xd, 0xf, 0xf, 0x10, 0x10, 0x11, +0x11, 0x10, 0xf, 0xd, 0xb, 0x9, 0x9, 0xa, 0xb, 0xf9, 0xb, 0xb, 0xa, 0xb, 0xb, 0x9, 0x8, 0x8, 0x8, 0x8, +0x8, 0x8, 0x8, 0x8, 0xf8, 0xf8, 0x9, 0x9, 0x8, 0x7, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xfd, 0xf6, +0xf6, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, +0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, +0xfd, 0xf6, 0xfd, 0xfd, 0xfc, 0xfd, 0xf6, 0xfc, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, +0xfc, 0x7, 0xf7, 0x8, 0x8, 0x8, 0x9, 0x8, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x8, 0x9, +0xa, 0xb, 0x6, 0xe, 0xe, 0xf, 0x10, 0xf, 0xf, 0xe, 0xd, 0xc, 0xa, 0xf7, 0x8, 0x9, 0xa, 0xa, 0xb, 0x9, +0xa, 0x9, 0xa, 0x9, 0x9, 0xf7, 0x8, 0x8, 0x8, 0x8, 0xf7, 0xf7, 0x8, 0x8, 0x8, 0x9, 0x8, 0x8, 0x7, 0xfc, +0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, +0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, +0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xfd, 0xf6, 0xfc, 0x7, 0x7, 0x7, 0x8, 0xf7, 0x7, 0xf7, 0x7, 0x7, 0xfc, 0x7, 0x8, +0x8, 0x8, 0x8, 0x8, 0x7, 0x7, 0xf7, 0x9, 0xa, 0xb, 0xd, 0x6, 0xd9, 0xd9, 0xf, 0xe, 0x6, 0xd, 0xd, 0xf9, +0x9, 0x7, 0x7, 0xf7, 0x9, 0xa, 0xa, 0xf8, 0x9, 0x8, 0x9, 0x9, 0x8, 0x8, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x8, +0x7, 0x8, 0x8, 0x8, 0x8, 0x8, 0x7, 0x7, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, +0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0x7, 0x7, 0xf7, 0x7, 0x8, +0x7, 0xfc, 0x7, 0xfc, 0xfc, 0x7, 0x7, 0x8, 0x8, 0x8, 0x7, 0x8, 0x8, 0x7, 0xf7, 0x8, 0xf8, 0xb, 0xc, 0xc, +0xc, 0xd, 0xd, 0xd, 0xc, 0xc, 0xb, 0xa, 0x9, 0x7, 0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, +0x9, 0x7, 0x7, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x7, 0x7, 0x7, 0xf6, 0xfd, +0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, +0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, +0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, +0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0x7, 0x7, 0x8, 0x7, 0x8, 0x7, 0x7, 0x7, +0x7, 0x7, 0x7, 0x8, 0xa, 0xb, 0xb, 0xb, 0xb, 0xc, 0xc, 0xc, 0xb, 0xb, 0xb, 0xf8, 0x8, 0xfc, 0xfc, 0x7, +0xf7, 0x8, 0x9, 0x9, 0x8, 0x7, 0x7, 0x8, 0x8, 0x8, 0x7, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0x7, +0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0xfc, 0xfc, 0xf6, 0xfc, 0xf6, 0xf6, 0x7, +0x7, 0x7, 0x7, 0x7, 0xfc, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x9, 0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb, +0xa, 0xa, 0xa, 0x9, 0x8, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x8, 0x8, 0xf7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x7, +0xf6, 0xfd, 0xf6, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, +0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, +0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, +0xfc, 0xf6, 0xfc, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x7, 0x8, 0x9, +0xa, 0xa, 0xa, 0x9, 0xa, 0xa, 0xa, 0xf8, 0x9, 0xa, 0xa, 0x9, 0x7, 0xfc, 0xf6, 0xfc, 0xfc, 0x7, 0xf7, 0x7, +0x8, 0x7, 0x7, 0xfc, 0x7, 0x7, 0xf7, 0x7, 0xf6, 0xfd, 0xf6, 0xf6, 0xfc, 0x7, 0xfc, 0xfc, 0xf6, 0xf6, 0xfc, 0xf6, +0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, +0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xf6, +0xf6, 0xfd, 0xf6, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, +0xfc, 0xfc, 0xf6, 0xfc, 0xfc, 0x7, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0xa, 0xa, 0x9, 0x9, 0x8, 0x8, 0x9, 0x8, +0x7, 0xfc, 0xf6, 0xf6, 0xfc, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xf7, 0x7, 0xfc, 0xf6, 0xfd, 0xf6, +0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, +0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xf6, 0xfc, 0xf6, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, +0xfd, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0xfc, 0xf6, 0x7, 0x7, 0x8, 0x9, 0x9, 0x8, 0x8, 0x9, +0x9, 0x9, 0x9, 0x8, 0xf7, 0x9, 0x8, 0xf7, 0x7, 0xfd, 0xfc, 0xfd, 0xfc, 0xfc, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfc, +0xfc, 0xfc, 0x7, 0x7, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xfc, 0xf6, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, +0xf6, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, +0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xfc, 0xf6, 0xf6, 0xfc, 0xfc, 0xfd, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, +0xfc, 0x7, 0x8, 0x8, 0x8, 0x7, 0x7, 0x8, 0x8, 0x8, 0x8, 0xf7, 0x8, 0x8, 0x7, 0x7, 0x7, 0xf6, 0xfd, 0xf6, +0xf6, 0xf6, 0x7, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xfc, 0x7, 0xfc, 0x7, 0xfc, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, +0xfd, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xfc, 0xfc, 0xf6, 0xf6, 0xf6, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, +0xfe, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xfc, 0xfc, 0xfc, +0xf6, 0xfd, 0xf6, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0x7, 0x8, 0xf7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x8, 0x7, +0x7, 0x7, 0x7, 0xfc, 0xfc, 0xf6, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0xfd, 0xfc, 0xf6, 0xfc, +0xfc, 0xfc, 0xfc, 0xf6, 0xfe, 0xfe, 0xfe, 0xf6, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, +0xf6, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xfc, 0x7, 0x7, 0x7, 0x7, +0x7, 0x7, 0x7, 0x8, 0x7, 0x7, 0x7, 0xfc, 0x7, 0x7, 0x7, 0x7, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xf6, +0xfc, 0xfc, 0xfc, 0xf6, 0xfd, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xf6, 0xf6, +0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xf6, 0xf6, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, +0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, +0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0x7, 0xfc, 0xfc, 0xfc, 0x7, 0xfc, 0x7, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0x7, 0x7, 0xfc, +0xf6, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xfc, 0xfc, 0xf6, +0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xf6, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, +0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, +0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, +0xf6, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xf6, 0xf6, 0xfc, 0xfc, 0x7, 0xfc, 0xfc, 0xf6, 0xfc, 0x7, 0xfc, +0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, +0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, +0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, +0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, +0xfc, 0xfc, 0xf6, 0xfc, 0xf6, 0xfc, 0x7, 0x7, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, 0xfd, 0xfe, 0xfe, +0xfe, 0xfd, 0xfe, 0xfd, 0xf6, 0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, +0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xf6, 0xf6, 0xfc, 0xf6, 0xfc, 0xf6, 0xfc, 0xf6, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf6, 0xf6, +0xf6, 0xfc, 0xfc, 0xf6, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xf6, 0xf6, 0xfd, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, +0xfd, 0xfe, 0xfe, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, +0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0xf6, 0xf6, +0xfd, 0xf6, 0xfc, 0xf6, 0xf6, 0xf6, 0xfd, 0xf6, 0xfc, 0xf6, 0xf6, 0xf6, 0xf6, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xf6, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, +0xfe, 0xf6, 0xf6, 0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xf6, 0xf6, 0xfd, 0xf6, +0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xf6, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xf6, 0xfe, 0xf6, 0xf6, 0xf6, 0xf6, +0xfe, 0xf6, 0xf6, 0xf6, 0xfd, 0xfd, 0xfd, 0xf6, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, +0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, +0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xf6, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xf6, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, +0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, +0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, +0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, +0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, +0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, +0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, +0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, +0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +0xfe, 0xfe, 0xfe, 0x0, 0x0, +}; + +int Streak_bmp_Length = sizeof(Streak_bmp); diff --git a/G3D/Engine/Sound.c b/G3D/Engine/Sound.c new file mode 100644 index 0000000..5f54ed7 --- /dev/null +++ b/G3D/Engine/Sound.c @@ -0,0 +1,1068 @@ +/****************************************************************************************/ +/* Sound.c */ +/* */ +/* Author: Brian Adelberg */ +/* Description: DirectSound wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include + +#include "BaseType.h" +#include "ErrorLog.h" +#include "VFile.h" +#include "Sound.h" +#include "Ram.h" + +typedef struct SoundManager SoundManager; +typedef struct Channel Channel; + + +typedef struct geSound_System +{ + geBoolean Active; + SoundManager *SoundM; + geFloat GlobalVolume; +} geSound_System; + +typedef struct geSound_Cfg +{ + geFloat Volume; + geFloat Pan; + geFloat Frequency; +} geSound_Cfg; + + +/* + The interfaces here allow an application to write sound data to + abstract channels which are then to be mixed. The interfaces here + require two things. First, that the application create only one + sound manager per instance, and second that the type of sound data + being passed into the sound channels remains constant. That is, + the format of the binary information is all one format from + one sound to another; the application cannot combine RIFF and WAV + formats in a single channel. +*/ +/* + Call these ones only once per application: +*/ + +static SoundManager * CreateSoundManager(HWND hWnd); +static void DestroySoundManager(SoundManager *sm); + +//static BOOL FillSoundChannel(SoundManager *sm, char* Dir, char *Name, unsigned int* Handle ); +static BOOL FillSoundChannel(SoundManager *sm, geVFile *File, unsigned int* Handle ); +//static BOOL FillSoundChannelMemory(SoundManager *sm, const void *Buffer, unsigned int* Handle ); +static BOOL StartSoundChannel( SoundManager *sm, unsigned int Handle, geSound_Cfg *cfg, int loop, unsigned int* sfx); +static BOOL StopSoundChannel(Channel *channel); +static BOOL FreeAllChannels(SoundManager *sm); +static BOOL FreeChannel(SoundManager *sm, Channel *channel); +static BOOL ModifyChannel( Channel *channel, geSound_Cfg *cfg ); +static int ChannelPlaying( Channel *channel ); +static Channel* GetChannel( SoundManager *sm, unsigned int ID ); + + +typedef struct Channel +{ +// char* name; + LPDIRECTSOUNDBUFFER buffer; + unsigned int ID; + int BaseFreq; + geSound_Cfg cfg; + void * Data; + struct Channel *next; + struct Channel *nextDup; +} Channel; + +typedef struct SoundManager +{ + int smChannelCount; + unsigned int smNextChannelID; + + LPDIRECTSOUNDBUFFER smPrimaryChannel; + Channel* smChannels; + //LPDIRECTSOUNDNOTIFY * smNotify; +} SoundManager; + +static LPDIRECTSOUND lpDirectSound = NULL; +// This isn't really safe as a global. But it's consistent with the global lpDirectSound. +static HMODULE hmodDirectSound = NULL; + +// Added 11/08/1999 Ed Averill to expose DSound object for external code +GENESISAPI void *geSound_GetDSound() +{ + return (void *)lpDirectSound; +} +// End 11/08/1999 addition + +//===================================================================================== +// geSound_SystemCreate +//===================================================================================== +GENESISAPI geSound_System *geSound_CreateSoundSystem(HWND hWnd) +{ + geSound_System *SoundSystem; + + SoundSystem = GE_RAM_ALLOCATE_STRUCT(geSound_System); + + if (!SoundSystem) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return NULL; + } + + memset(SoundSystem, 0, sizeof(geSound_System)); + + // Initialize the sound system + SoundSystem->SoundM = CreateSoundManager(hWnd); + + if (!SoundSystem->SoundM) + { + geRam_Free(SoundSystem); + geErrorLog_Add(GE_ERR_CREATE_SOUND_MANAGER_FAILED, NULL); + return NULL; + } + SoundSystem->GlobalVolume = 1.0f; + + return SoundSystem; +} + +//===================================================================================== +// geSound_SystemFree +//===================================================================================== +GENESISAPI void geSound_DestroySoundSystem(geSound_System *Sound) +{ + assert(Sound != NULL); + + // Shutdown the sound system + DestroySoundManager(Sound->SoundM); + + Sound->SoundM = NULL; + + geRam_Free(Sound); +} + +//===================================================================================== +// Sound_LoadSound +//===================================================================================== +//GENESISAPI geSound_Def *geSound_LoadSoundDef(geSound_System *SoundS, const char *Path, const char *FileName) +GENESISAPI geSound_Def *geSound_LoadSoundDef(geSound_System *SoundS, geVFile *File) +{ + unsigned int SoundDef = 0; + + assert(SoundS != NULL); + +// if (!FillSoundChannel(SoundS->SoundM, (char*)Path, (char*)FileName, &SoundDef)) + if (!FillSoundChannel(SoundS->SoundM, File, &SoundDef)) + return 0; + + return (geSound_Def *)SoundDef; +} + +#if 0 +//===================================================================================== +// Sound_LoadSound +//===================================================================================== +GENESISAPI geSound_Def *geSound_LoadSoundDefFromMemory( + geSound_System *SoundS, + const void *Buffer) +{ + unsigned int SoundDef = 0; + + assert(SoundS != NULL); + assert(Buffer != NULL); + + if (!FillSoundChannelMemory(SoundS->SoundM, Buffer, &SoundDef)) + return 0; + + return (geSound_Def *)SoundDef; +} +#endif + +//===================================================================================== +// Sound_FreeSound +//===================================================================================== +GENESISAPI void geSound_FreeSoundDef(geSound_System *SoundS, geSound_Def *SoundDef) +{ + Channel* Channel; + + assert(SoundS != NULL); + assert(SoundDef != 0); + + Channel = GetChannel(SoundS->SoundM, (unsigned int)SoundDef); + + if (!Channel) + return; + + FreeChannel(SoundS->SoundM, Channel); +} + +//===================================================================================== +// Sound_SetGlobalVolume +//===================================================================================== +GENESISAPI geBoolean geSound_SetMasterVolume( geSound_System *SoundS, geFloat Volume ) +{ + if( !SoundS ) + return( GE_FALSE ); + SoundS->GlobalVolume = Volume; + return( GE_TRUE ); +} + +//===================================================================================== +// Sound_PlaySound +//===================================================================================== +GENESISAPI geSound *geSound_PlaySoundDef(geSound_System *SoundS, + geSound_Def *SoundDef, + geFloat Volume, + geFloat Pan, + geFloat Frequency, + geBoolean Loop) +{ + unsigned int Sound; + geSound_Cfg LocalCfg; + + LocalCfg.Volume = Volume; + LocalCfg.Pan = Pan; + LocalCfg.Frequency = Frequency; + + LocalCfg.Volume *= SoundS->GlobalVolume; + if (!StartSoundChannel(SoundS->SoundM, (unsigned int)SoundDef, &LocalCfg, (BOOL)Loop, &Sound)) + { + return 0; + } + + return (geSound *)Sound; +} + +//===================================================================================== +// Sound_StopSound +//===================================================================================== +GENESISAPI geBoolean geSound_StopSound(geSound_System *SoundS, geSound *Sound) +{ + Channel* Channel; + + assert(SoundS != NULL); + assert(Sound != NULL); + + Channel = GetChannel(SoundS->SoundM, (unsigned int)Sound); + + if (!Channel) + return GE_FALSE; + + return StopSoundChannel(Channel); +} + +//===================================================================================== +// Sound_ModifySound +//===================================================================================== +GENESISAPI geBoolean geSound_ModifySound(geSound_System *SoundS, + geSound *Sound,geFloat Volume, + geFloat Pan, + geFloat Frequency) +{ + Channel* Channel; + geSound_Cfg LocalCfg; + + assert(SoundS != NULL); + assert(Sound != NULL); + + Channel = GetChannel(SoundS->SoundM, (unsigned int)Sound); + + if (!Channel) + return GE_FALSE; + LocalCfg.Volume = Volume; + LocalCfg.Pan = Pan; + LocalCfg.Frequency = Frequency; + LocalCfg.Volume *= SoundS->GlobalVolume; + return ModifyChannel(Channel, &LocalCfg); +} + +//===================================================================================== +// Sound_SoundIsPlaying +//===================================================================================== +GENESISAPI geBoolean geSound_SoundIsPlaying(geSound_System *SoundS, geSound *Sound) +{ + Channel* Channel; + + assert(SoundS != NULL); + assert(Sound != NULL); + + Channel = GetChannel(SoundS->SoundM, (unsigned int)Sound); + + if (!Channel) + return GE_FALSE; + + return ChannelPlaying(Channel); +} + + +//===================================================================================== +//===================================================================================== + +static BOOL DSParseWaveResource(const void *pvRes, WAVEFORMATEX **ppWaveHeader, + BYTE **ppbWaveData,DWORD *pcbWaveSize) +{ + DWORD *pdw; + DWORD *pdwEnd; + DWORD dwRiff; + DWORD dwType; + DWORD dwLength; + + if (ppWaveHeader) + *ppWaveHeader = NULL; + + if (ppbWaveData) + *ppbWaveData = NULL; + + if (pcbWaveSize) + *pcbWaveSize = 0; + + pdw = (DWORD *)pvRes; + dwRiff = *pdw++; + dwLength = *pdw++; + dwType = *pdw++; + + if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F')) + goto exit; // not even RIFF + + if (dwType != mmioFOURCC('W', 'A', 'V', 'E')) + goto exit; // not a WAV + + pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4); + + while (pdw < pdwEnd) + { + dwType = *pdw++; + dwLength = *pdw++; + + switch (dwType) + { + case mmioFOURCC('f', 'm', 't', ' '): + if (ppWaveHeader && !*ppWaveHeader) + { + if (dwLength < sizeof(WAVEFORMAT)) + goto exit; // not a WAV + + *ppWaveHeader = (WAVEFORMATEX *)pdw; + + if ((!ppbWaveData || *ppbWaveData) && + (!pcbWaveSize || *pcbWaveSize)) + { + return TRUE; + } + } + break; + + case mmioFOURCC('d', 'a', 't', 'a'): + if ((ppbWaveData && !*ppbWaveData) || + (pcbWaveSize && !*pcbWaveSize)) + { + if (ppbWaveData) + *ppbWaveData = (LPBYTE)pdw; + + if (pcbWaveSize) + *pcbWaveSize = dwLength; + + if (!ppWaveHeader || *ppWaveHeader) + return TRUE; + } + break; + } + + pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1)); + } + +exit: + return FALSE; +} + +static BOOL DSFillSoundBuffer(IDirectSoundBuffer *pDSB, BYTE *pbWaveData, DWORD cbWaveSize) +{ + + if (pDSB && pbWaveData && cbWaveSize) + { + LPVOID pMem1, pMem2; + DWORD dwSize1, dwSize2; + + if (SUCCEEDED(IDirectSoundBuffer_Lock(pDSB, 0, cbWaveSize, + &pMem1, &dwSize1, &pMem2, &dwSize2, 0))) + { + ZeroMemory(pMem1, dwSize1); + CopyMemory(pMem1, pbWaveData, dwSize1); + + if ( 0 != dwSize2 ) + CopyMemory(pMem2, pbWaveData+dwSize1, dwSize2); + + IDirectSoundBuffer_Unlock(pDSB, pMem1, dwSize1, pMem2, dwSize2); + return TRUE; + } + } + return FALSE; +} + + +DSCAPS dsCaps; +static SoundManager * CreateSoundManager(HWND hWnd ) +{ + typedef HRESULT (WINAPI *DS_CREATE_FUNC)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); + PCMWAVEFORMAT pcmwf; + DSBUFFERDESC dsbdesc; + HRESULT hres; + SoundManager * sm; + DS_CREATE_FUNC pDirectSoundCreate; + + // load the DirectSound DLL + hmodDirectSound = LoadLibrary ("DSOUND.DLL"); + if (hmodDirectSound == NULL) + { + // Couldn't load DSOUND.DLL + return NULL; + } + + pDirectSoundCreate = (DS_CREATE_FUNC)GetProcAddress (hmodDirectSound, "DirectSoundCreate"); + if (pDirectSoundCreate == NULL) + { + // couldn't find the DirectSoundCreate function + FreeLibrary (hmodDirectSound); + return NULL; + } + + hres = pDirectSoundCreate(NULL, &lpDirectSound, NULL); + if (hres != DS_OK) + { + // failed somehow + FreeLibrary (hmodDirectSound); + return NULL; + } + +// sm = malloc(sizeof(*sm)); + sm = geRam_Allocate(sizeof(*sm)); + if (!sm) + { + IDirectSound_Release(lpDirectSound); + FreeLibrary (hmodDirectSound); + return NULL; + } + sm->smChannelCount = 0; + sm->smNextChannelID = 1; + sm->smChannels = NULL; + + memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT)); + pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM; + + //pcmwf.wf.nChannels = 1; + //pcmwf.wf.nSamplesPerSec = 44050; + //pcmwf.wf.nBlockAlign = 2; +#if 1 + pcmwf.wf.nChannels = 2; + pcmwf.wf.nSamplesPerSec = 44100; + pcmwf.wf.nBlockAlign = 4; + pcmwf.wBitsPerSample = 16; + pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign; +#else + pcmwf.wf.nChannels = 1; + pcmwf.wf.nSamplesPerSec = 22050; + pcmwf.wf.nBlockAlign = 1; + pcmwf.wBitsPerSample = 8; + pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * 2; +#endif + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;// | DSBCAPS_CTRLDEFAULT;// | DSBCAPS_CTRL3D; + dsbdesc.dwBufferBytes = 0; //dwBufferBytes and lpwfxFormat must be set this way. + dsbdesc.lpwfxFormat = NULL; + +#if 1 + if (DS_OK== IDirectSound_SetCooperativeLevel(lpDirectSound, hWnd,DSSCL_NORMAL)) +#else + if (DS_OK== IDirectSound_SetCooperativeLevel(lpDirectSound, hWnd,DSSCL_EXCLUSIVE)) +#endif + { + if (DS_OK== IDirectSound_CreateSoundBuffer(lpDirectSound, &dsbdesc, &sm->smPrimaryChannel, NULL)) + { + return sm; + } + IDirectSound_Release(lpDirectSound); + FreeLibrary (hmodDirectSound); + } +// free( sm ); + geRam_Free(sm); + return NULL; +} + +//static BOOL CreateChannel( char* Name, DSBUFFERDESC* dsBD, Channel** chanelPtr) +static BOOL CreateChannel(DSBUFFERDESC* dsBD, Channel** chanelPtr) +{ + Channel* channel; + +// channel = malloc( sizeof( Channel ) ); + channel = geRam_Allocate( sizeof( Channel ) ); + if ( channel == NULL ) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return( FALSE ); + } + if(DS_OK != IDirectSound_CreateSoundBuffer(lpDirectSound, dsBD, &channel->buffer, NULL)) + { + geErrorLog_Add(GE_ERR_CREATE_SOUND_BUFFER_FAILED, NULL); + return FALSE; + } + if(DS_OK != IDirectSoundBuffer_GetFrequency(channel->buffer, &channel->BaseFreq) ) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + channel->next = NULL; + channel->nextDup = NULL; + channel->ID = 0; + channel->cfg.Volume = 1.0f; + channel->cfg.Pan = 0.0f; + channel->cfg.Frequency = 0.0f; +// channel->name = Name; + + *chanelPtr = channel; + return( TRUE ); +} + +//static BOOL GetSoundData( char* Name, unsigned char** dataPtr) +static BOOL GetSoundData( geVFile *File, unsigned char** dataPtr) +{ +// FILE * f; + int32 Size; + uint8 *data; +// int32 CurPos; + +#if 0 + f = fopen(Name, "rb"); + + if (!f) + { + geErrorLog_Add(GE_ERR_FILE_OPEN_ERROR, NULL); + return FALSE; + } +#endif + +#if 0 + CurPos = ftell (f); // Save the startinf pos into this function + fseek (f, 0, SEEK_END); // Seek to end + Size = ftell (f); // Get End (this will be the size) + fseek (f, CurPos, SEEK_SET); // Restore file position +#endif + + if (geVFile_Size(File, &Size) == GE_FALSE) + return FALSE; + + data = geRam_Allocate(Size); + + if (!data) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return FALSE; + } + + if (geVFile_Read(File, data, Size) == GE_FALSE) + { + geRam_Free(data); + return FALSE; + } + +// fread(data, Size, 1, f); + +// fclose(f); + *dataPtr = data; + return( TRUE ); +} + +static BOOL ParseData( const uint8* data, DSBUFFERDESC* dsBD, BYTE ** pbWaveData ) +{ + + //Parse the Data + memset(dsBD, 0, sizeof(DSBUFFERDESC)); + + dsBD->dwSize = sizeof(DSBUFFERDESC); + dsBD->dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN | + DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME; + if (!DSParseWaveResource(data, &dsBD->lpwfxFormat, pbWaveData, &dsBD->dwBufferBytes)) + { + geErrorLog_Add(GE_ERR_INVALID_WAV, NULL); + return FALSE; + } + return( TRUE ); + +} + +//static BOOL FillSoundChannel(SoundManager *sm, char* Dir, char *Name, unsigned int* Handle ) +static BOOL FillSoundChannel(SoundManager *sm, geVFile *File, unsigned int* Handle ) +{ + DSBUFFERDESC dsBD; + INT NumBytes; + uint8 *data = NULL; + BYTE * pbWaveData; +// char* Name2; + Channel* channel; + + *Handle = 0; + if (!sm) + return TRUE; + +#if 0 + //Open the file + if (Dir) + { + Name2 = malloc( strlen( Name ) + strlen( Dir ) + 3); // 2 for the "//" and 1 for terminator + if( !Name2 ) + return( 0 ); + sprintf(Name2, "%s\\%s", Dir, Name); + } + else + { + Name2 = malloc( strlen( Name ) + 3); // 2 for the "//" and 1 for terminator + if( !Name2 ) + return( 0 ); + + sprintf(Name2, "%s", Name); + } +#endif + if(!GetSoundData( File, &data )) + return( FALSE ); + + if( !ParseData( data, &dsBD, &pbWaveData ) ) + { + geRam_Free(data); + return( FALSE ); + } + + NumBytes = dsBD.dwBufferBytes; + + //Create the channel +// if( !CreateChannel( Name2, &dsBD, &channel ) ) + if (!CreateChannel(&dsBD, &channel)) + { + geRam_Free(data); + return FALSE; + } + channel->next = sm->smChannels; + channel->ID = sm->smNextChannelID++; + channel->Data = data; + + sm->smChannels = channel; + sm->smChannelCount++; + + //Fill the channel + if (!DSFillSoundBuffer(channel->buffer, pbWaveData, NumBytes)) + return FALSE; + +// free( data ); +// geRam_Free(data); + + *Handle = channel->ID; + return TRUE; +} + +#if 0 +static BOOL FillSoundChannelMemory(SoundManager *sm, const void *Buffer, unsigned int* Handle ) +{ + DSBUFFERDESC dsBD; + INT NumBytes; + BYTE * pbWaveData; + char * Name; + Channel * channel; + + *Handle = 0; + if (!sm) + return TRUE; + + if (!ParseData(Buffer, &dsBD, &pbWaveData)) + return FALSE; + + NumBytes = dsBD.dwBufferBytes; + + Name = malloc(11); + if (Name == NULL) + return FALSE; + sprintf(Name, "0x%8x", Buffer); + + //Create the channel +// if (!CreateChannel(Name, &dsBD, &channel)) + if (!CreateChannel(&dsBD, &channel)) + return FALSE; + + channel->next = sm->smChannels; + channel->ID = sm->smNextChannelID++; + + sm->smChannels = channel; + sm->smChannelCount++; + + //Fill the channel + if (!DSFillSoundBuffer(channel->buffer, pbWaveData, NumBytes)) + return FALSE; + + *Handle = channel->ID; + return TRUE; +} +#endif + +static void StopDupBuffers( Channel* channel ) +{ + Channel* dupChannel, *prevChannel; + + assert( channel ); + + dupChannel = channel->nextDup; + prevChannel = channel; + while( dupChannel ) + { + IDirectSoundBuffer_Stop(dupChannel->buffer); + dupChannel = dupChannel->nextDup; + } +} + +static void ClearDupBuffers( Channel* channel ) +{ + Channel* dupChannel, *prevChannel; + + if( channel == NULL) + return; + + dupChannel = channel->nextDup; + prevChannel = channel; + while( dupChannel ) + { + if( !ChannelPlaying( dupChannel ) ) + { + prevChannel->nextDup = dupChannel->nextDup; + IDirectSound_Release(dupChannel->buffer); +// free( dupChannel ); + geRam_Free(dupChannel); + dupChannel = prevChannel->nextDup; + } + else + { + prevChannel = dupChannel; + dupChannel = dupChannel->nextDup; + } + } +} + +static BOOL FreeAllChannels(SoundManager *sm) +{ + int Error; + + Channel* channel, *nextChannel; + + channel = sm->smChannels; + while( channel ) + { + nextChannel = channel->next; + StopDupBuffers( channel ); + ClearDupBuffers( channel ); + Error = IDirectSoundBuffer_Stop(channel->buffer); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + Error = IDirectSound_Release(channel->buffer); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + +// if( channel->name ) +// geRam_Free(channel->name); +// free( channel->name ); + if (channel->Data) + geRam_Free(channel->Data); + geRam_Free(channel); +// free( channel ); + channel = nextChannel; + } + sm->smChannels = NULL; + sm->smChannelCount = 0; + + return TRUE; +} + + +static BOOL FreeChannel(SoundManager *sm, Channel* channel) +{ + int Error; + Channel*prevChannel = NULL, *curChannel; + if ( channel ) + { + StopDupBuffers( channel ); + ClearDupBuffers( channel ); + Error = IDirectSoundBuffer_Stop(channel->buffer); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + Error = IDirectSound_Release(channel->buffer); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } +// if( channel->name ) +// geRam_Free(channel->name); +// free( channel->name ); + + if( channel->Data ) + geRam_Free(channel->Data); + + curChannel = sm->smChannels; + while( curChannel && curChannel != channel ) + { + prevChannel = curChannel; + curChannel = curChannel->next; + } + if( curChannel ) + { + if( prevChannel ) + prevChannel->next = curChannel->next; + else + sm->smChannels = curChannel->next; + geRam_Free(curChannel); +// free( curChannel ); + } + } + + return TRUE; +} + +static Channel* ReloadData(void *Data) +{ + DSBUFFERDESC dsBD; + BYTE * pbWaveData; + INT NumBytes; +// uint8 *data = NULL; + Channel* channel; + +// if( !Name ) +// return( NULL ); +// if( !GetSoundData( Data, &data ) ) +// return( NULL ); + + if( !ParseData( Data, &dsBD, &pbWaveData ) ) + return( NULL ); + + NumBytes = dsBD.dwBufferBytes; + + //Create the channel +// if( !CreateChannel( Name, &dsBD, &channel ) ) + if( !CreateChannel(&dsBD, &channel ) ) + return NULL; + + //Fill the channel + if ( !DSFillSoundBuffer(channel->buffer, pbWaveData, NumBytes)) + return NULL; + +// geRam_Free(data); +// free( data ); + return( channel ); +} + +static BOOL DupChannel( SoundManager *sm, Channel* channel, Channel** dupChannelPtr ) +{ + Channel* dupChannel; + HRESULT Error; + + *dupChannelPtr = NULL; +// dupChannel = malloc( sizeof(Channel ) ); + dupChannel = geRam_Allocate( sizeof(Channel ) ); + if( dupChannel == NULL ) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL ); + return FALSE; + } + Error = IDirectSound_DuplicateSoundBuffer( lpDirectSound, channel->buffer, &dupChannel->buffer ); + if( Error != DS_OK ) + { + geRam_Free(dupChannel); +// free( dupChannel ); + dupChannel = ReloadData( channel->Data ); + if( dupChannel == NULL ) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + } + dupChannel->ID = sm->smNextChannelID++; + dupChannel->next = NULL; + dupChannel->nextDup = channel->nextDup; + dupChannel->cfg = channel->cfg; +// dupChannel->name = NULL; + dupChannel->Data = channel->Data; + channel->nextDup = dupChannel; + *dupChannelPtr = dupChannel; + return( TRUE ); +} + +static BOOL StartSoundChannel( SoundManager *sm, unsigned int Handle, geSound_Cfg *cfg, int loop, unsigned int* sfx) +{ + HRESULT hres; + Channel* channel, *dupChannel; + + if( Handle == 0 ) + return( FALSE ); + channel = GetChannel( sm, Handle ); + //Clear all non-playing duplicate buffers. + ClearDupBuffers(channel); + //If the main buffer is playing and all non-playing dups have been cleared + //we need a new duplicate. + if( ChannelPlaying( channel ) ) + { + if(!DupChannel( sm,channel, &dupChannel ) ) + return( FALSE ); + channel = dupChannel; + } + if( !ModifyChannel( channel, cfg ) ) + return( FALSE ); + IDirectSoundBuffer_SetCurrentPosition(channel->buffer, 0); + hres = IDirectSoundBuffer_Play( channel->buffer, + 0, + 0, + loop ? DSBPLAY_LOOPING : 0); + + if (hres == DS_OK) + { + if( sfx ) + *sfx = channel->ID; + return TRUE; + } + + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; +} + +static BOOL StopSoundChannel(Channel* channel) +{ + HRESULT hres; + + assert(channel); + + hres = IDirectSoundBuffer_Stop(channel->buffer); + + if (hres == DS_OK) + return TRUE; + + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; +} + +static void DestroySoundManager(SoundManager *sm) +{ + if (!sm) return; + + FreeAllChannels( sm ); + if (sm->smPrimaryChannel != NULL) + sm->smPrimaryChannel->lpVtbl->Release(sm->smPrimaryChannel); + if (lpDirectSound != NULL) + IDirectSound_Release(lpDirectSound); + if (hmodDirectSound != NULL) + FreeLibrary (hmodDirectSound); + geRam_Free(sm); +// free(sm); +} + +static BOOL ModifyChannel( Channel *channel, geSound_Cfg *cfg ) +{ + int Error, Vol, Pan, Freq; + assert(channel); + + if( !cfg ) + return( TRUE ); + ClearDupBuffers(channel); + if( cfg->Volume != channel->cfg.Volume ) + { + Vol = (DWORD)((1.0 - cfg->Volume ) * DSBVOLUME_MIN); + Error = IDirectSoundBuffer_SetVolume(channel->buffer, Vol); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + channel->cfg.Volume = cfg->Volume; + } + + if( cfg->Pan != channel->cfg.Pan ) + { + Pan = (int)(cfg->Pan * DSBPAN_RIGHT); + Error = IDirectSoundBuffer_SetPan(channel->buffer, Pan); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + channel->cfg.Pan = cfg->Pan; + } + + + if( cfg->Frequency != channel->cfg.Frequency ) + { + + Freq = (DWORD)(channel->BaseFreq * cfg->Frequency); + Error = IDirectSoundBuffer_SetFrequency(channel->buffer, Freq); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + channel->cfg.Frequency = cfg->Frequency; + } + + return TRUE; +} + +static int ChannelPlaying( Channel *channel ) +{ + DWORD status, Error; + + if(!channel) + return( 0 ); + + Error = IDirectSoundBuffer_GetStatus( channel->buffer, &status); + if( Error != DS_OK) + return 0; + return( status & DSBSTATUS_PLAYING ); +} + +static Channel* GetChannel( SoundManager *sm, unsigned int ID ) +{ + Channel* dupChannel; + Channel* channel = sm->smChannels; + + while( channel ) + { + if( channel->ID == ID ) + break; + dupChannel = channel->nextDup; + while( dupChannel ) + { + if( dupChannel->ID == ID ) + break; + dupChannel = dupChannel->nextDup; + } + if( dupChannel ) + return( dupChannel ); + channel = channel->next; + } + return( channel ); +} diff --git a/G3D/Engine/System.c b/G3D/Engine/System.c new file mode 100644 index 0000000..90a53ae --- /dev/null +++ b/G3D/Engine/System.c @@ -0,0 +1,504 @@ +/****************************************************************************************/ +/* System.c */ +/* */ +/* Author: John Pollard */ +/* Description: Friend of engine.c. Takes care of some of the driver work. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "BaseType.h" +#include "System.h" +#include "Genesis.h" +#include "ErrorLog.h" +#include "Ram.h" +#include "engine.h" + +#include "list.h" +#include "Surface.h" +#include "World.h" +#include "Plane.h" +#include "Light.h" +#include "WBitmap.h" +#include "Camera.h" +#include "Sound.h" +#include "Entities.h" +#include "User.h" + +#include "dcommon.h" + +#include "geassert.h" + +#include "BitmapList.h" +//#define SKY_HACK +//extern BOOL GlobalReset; + +//===================================================================================== +// Local static globals +//===================================================================================== +static char DriverFileNames[][200] = +{ + {"D3DDrv.dll"}, + {"GlideDrv.dll"}, + {"SoftDrv.dll"}, + {"SoftDrv2.dll"}, + {"OglDrv.dll"}, + {"WireDrv.dll"}, + {""} +}; + +//===================================================================================== +// local static function prototypes +//===================================================================================== + +static geBoolean EnumSubDrivers(Sys_DriverInfo *DriverInfo, const char *DriverDirectory); + +static BOOL EnumSubDriversCB(S32 DriverId, char *Name, void *Context); +static BOOL EnumModesCB(S32 ModeId, char *Name, S32 Width, S32 Height, void *Context); + +//===================================================================================== +// geDriver_SystemGetNextDriver +//===================================================================================== +GENESISAPI geDriver *geDriver_SystemGetNextDriver(geDriver_System *DriverSystem, geDriver *Start) +{ + Sys_DriverInfo *DriverInfo; + geDriver *Last; + + assert(DriverSystem != NULL); + + DriverInfo = (Sys_DriverInfo*)DriverSystem; + + if (!DriverInfo->NumSubDrivers) + return NULL; + + Last = &DriverInfo->SubDrivers[DriverInfo->NumSubDrivers-1]; + + if (Start) // If they have a driver, return the next one + Start++; + else + Start = DriverInfo->SubDrivers; // Else, return the first one... + + if (Start > Last) // No more drivers left + return NULL; + + // This must be true!!! + assert(Start >= DriverInfo->SubDrivers && Start <= Last); + + return Start; // This is it... +} + +//===================================================================================== +// geDriver_GetNextMode +//===================================================================================== +GENESISAPI geDriver_Mode *geDriver_GetNextMode(geDriver *Driver, geDriver_Mode *Start) +{ + geDriver_Mode *Last; + + Last = &Driver->Modes[Driver->NumModes-1]; + + if (Start) // If there is a start, return the next one + Start++; + else + Start = Driver->Modes; // Else, return the first + + if (Start > Last) // No more Modes left + return NULL; + + // This must be true... + assert(Start >= Driver->Modes && Start <= Last); + + return Start; +} + +//===================================================================================== +// geDriver_GetName +//===================================================================================== +GENESISAPI geBoolean geDriver_GetName(geDriver *Driver, const char **Name) +{ + assert(Driver); + assert(Name); + + *Name = Driver->Name; + + return GE_TRUE; +} + +//===================================================================================== +// geDriver_ModeGetName +//===================================================================================== +GENESISAPI geBoolean geDriver_ModeGetName(geDriver_Mode *Mode, const char **Name) +{ + assert(Mode); + assert(Name); + + *Name = Mode->Name; + + return GE_TRUE; +} + +//===================================================================================== +// geDriver_ModeGetWidthHeight +//===================================================================================== +GENESISAPI geBoolean geDriver_ModeGetWidthHeight(geDriver_Mode *Mode, int32 *Width, int32 *Height) +{ + assert(Mode); + assert(Width); + assert(Height); + + *Width = Mode->Width; + *Height = Mode->Height; + + return GE_TRUE; +} + +//===================================================================================== +// Sys_EngineCreate +// <> geEngine_Create +//===================================================================================== + +const uint32 geEngine_Version = GE_VERSION; +const uint32 geEngine_Version_OldestSupported = + ( (GE_VERSION_MAJOR << GE_VERSION_MAJOR_SHIFT) + GE_VERSION_MINOR_MIN ); + +geEngine *Sys_EngineCreate(HWND hWnd, const char *AppName, const char *DriverDirectory, uint32 Version) +{ + int32 i; + geEngine *NewEngine; + int Length; + + if ( (Version & GE_VERSION_MAJOR_MASK) != (geEngine_Version & GE_VERSION_MAJOR_MASK) ) + { + geErrorLog_AddString(-1,"Genesis Engine has wrong major version!", NULL); + return NULL; + } + + if ( Version > geEngine_Version ) + { + char str[1024]; + sprintf(str,"%d - %d",Version,geEngine_Version); + geErrorLog_AddString(-1,"Genesis Engine is older than application; aborting!", str); + return NULL; + } + + if ( Version < geEngine_Version_OldestSupported ) + { + char str[1024]; + sprintf(str,"%d - %d",Version,geEngine_Version); + geErrorLog_AddString(-1,"Genesis Engine does not support the old version!", str); + return NULL; + } + + // Attempt to create a new engine object + NewEngine = GE_RAM_ALLOCATE_STRUCT(geEngine); + + if (!NewEngine) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + goto ExitWithError; + } + + // Clear the engine structure... + memset(NewEngine, 0, sizeof(geEngine)); + + if ( ! List_Start() ) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + goto ExitWithError; + } + + Length = strlen(DriverDirectory) + 1; + NewEngine->DriverDirectory = geRam_Allocate(Length); + + if (!NewEngine->DriverDirectory) + goto ExitWithError; + + memcpy(NewEngine->DriverDirectory, DriverDirectory, Length); + + NewEngine->hWnd = hWnd; + strcpy(NewEngine->AppName, AppName); + + // Get cpu info + if (!Sys_GetCPUFreq(&NewEngine->CPUInfo)) + goto ExitWithError; + + // Build the wavetable + for (i = 0; i < 20; i++) + NewEngine->WaveTable[i] = ((i * 65)%200) + 50; + + if (!EnumSubDrivers(&NewEngine->DriverInfo, DriverDirectory)) + goto ExitWithError; + + if (!geEngine_BitmapListInit(NewEngine)) + goto ExitWithError; + + if (!Light_EngineInit(NewEngine)) + goto ExitWithError; + + if (!User_EngineInit(NewEngine)) + goto ExitWithError; + + if (!geEngine_InitFonts(NewEngine)) // must be after BitmapList + goto ExitWithError; + + NewEngine->Changed = GE_TRUE; // Force a first time driver upload + + NewEngine->DisplayFrameRateCounter = GE_TRUE; // Default to showing the FPS counter + + geAssert_SetCriticalShutdownCallback( geEngine_ShutdownDriver , NewEngine ); + + NewEngine->CurrentGamma = 1.0f; + + //geEngine_SetFogEnable(NewEngine, GE_TRUE, 255.0f, 0.0f, 0.0f, 250.0f, 1000.0f); + geEngine_SetFogEnable(NewEngine, GE_FALSE, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + + return NewEngine; + + // Error cleanup + ExitWithError: + { + if (NewEngine) + { + if (NewEngine->DriverDirectory) + geRam_Free(NewEngine->DriverDirectory); + + geRam_Free(NewEngine); + } + + return NULL; + } +} + + +//===================================================================================== +// Sys_EngineFree +// <> geEngine_Destroy() +//===================================================================================== +void Sys_EngineFree(geEngine *Engine) +{ + geBoolean Ret; + + assert(Engine != NULL); + + if (!Engine) + return; + + Ret = geEngine_RemoveAllWorlds(Engine); + assert(Ret); + + // Call upon modules to free allocated data in the engine + Light_EngineShutdown(Engine); + User_EngineShutdown(Engine); + + Ret = geEngine_ShutdownFonts(Engine); + assert(Ret == GE_TRUE); + + Ret = geEngine_ShutdownDriver(Engine); + assert(Ret == GE_TRUE); + + Ret = geEngine_BitmapListShutdown(Engine); + assert(Ret == GE_TRUE); + + geRam_Free(Engine->DriverDirectory); + + List_Stop(); + + geRam_Free(Engine); +} + +//===================================================================================== +// SysGetCPUFreq +//===================================================================================== +geBoolean Sys_GetCPUFreq(Sys_CPUInfo *Info) +{ + LARGE_INTEGER Freq; + + assert(Info != NULL); + + if (!QueryPerformanceFrequency(&Freq)) + { + geErrorLog_Add(GE_ERR_NO_PERF_FREQ, NULL); + return GE_FALSE; + } + + Info->Freq = Freq.LowPart; + + return GE_TRUE; +} + +#ifdef MESHES +//=================================================================================== +// Sys_WorldCreateMesh +// Create a mesh definition object +//=================================================================================== +Mesh_MeshDef *Sys_WorldCreateMesh(geWorld *World, const char *BitmapPath, const char *FileName) +{ + Mesh_MeshDef *MeshDef; + + assert(World != NULL); + assert(BitmapPath != NULL); + assert(FileName != NULL); + + MeshDef = Mesh_WorldCreateMesh(World, BitmapPath, FileName); + + return MeshDef; +} + +//=================================================================================== +// Sys_WorldFreeMesh +//=================================================================================== +void Sys_WorldFreeMesh(geWorld *World, Mesh_MeshDef *MeshDef) +{ + assert(World != NULL); + assert(MeshDef != NULL); + + Mesh_WorldFreeMesh(World, MeshDef); +} +#endif + +//=================================================================================== +// EnumSubDriversCB +//=================================================================================== +static BOOL EnumSubDriversCB(S32 DriverId, char *Name, void *Context) +{ + Sys_DriverInfo *DriverInfo = (Sys_DriverInfo*)Context; + DRV_Driver *RDriver; + geDriver *Driver; + + if (strlen(Name) >= DRV_STR_SIZE) + return TRUE; // Ignore + + if (DriverInfo->NumSubDrivers+1 >= MAX_SUB_DRIVERS) + return FALSE; // Stop when no more driver slots available + + Driver = &DriverInfo->SubDrivers[DriverInfo->NumSubDrivers]; + + Driver->Id = DriverId; + strcpy(Driver->Name, Name); + strcpy(Driver->FileName, DriverInfo->CurFileName); + + RDriver = DriverInfo->RDriver; + + // Store this, so enum modes know what driver we are working on... + DriverInfo->CurDriver = Driver; + + if (!RDriver->EnumModes(Driver->Id, Driver->Name, EnumModesCB, (void*)DriverInfo)) + return FALSE; + + DriverInfo->NumSubDrivers++; + + return TRUE; +} + +//=================================================================================== +// EnumModesCB +//=================================================================================== +static BOOL EnumModesCB(S32 ModeId, char *Name, S32 Width, S32 Height, void *Context) +{ + Sys_DriverInfo *DriverInfo; + geDriver *Driver; + geDriver_Mode *Mode; + + if (strlen(Name) >= DRV_MODE_STR_SIZE) + return TRUE; // Ignore + + DriverInfo = (Sys_DriverInfo*)Context; + + Driver = DriverInfo->CurDriver; + + if (Driver->NumModes+1 >= MAX_DRIVER_MODES) + return FALSE; + + Mode = &Driver->Modes[Driver->NumModes]; + + Mode->Id = ModeId; + strcpy(Mode->Name, Name); + Mode->Width = Width; + Mode->Height = Height; + + Driver->NumModes++; + + return TRUE; +} + +//=================================================================================== +// EnumSubDrivers +//=================================================================================== +static geBoolean EnumSubDrivers(Sys_DriverInfo *DriverInfo, const char *DriverDirectory) +{ + int32 i; + DRV_Hook *DriverHook; + HINSTANCE Handle; + DRV_Driver *RDriver; + geBoolean GlideFound; + + DriverInfo->NumSubDrivers = 0; + + GlideFound = GE_FALSE; + + for (i=0; DriverFileNames[i][0]!=0; i++) + { + // if (!strcmp(DriverFileNames[i], "D3DDrv.dll") && GlideFound) + // continue; // Skip D3D if we found a glidedrv + + Handle = geEngine_LoadLibrary(DriverFileNames[i], DriverDirectory); + + if (!Handle) + continue; + + DriverInfo->CurFileName = DriverFileNames[i]; + + DriverHook = (DRV_Hook*)GetProcAddress(Handle, "DriverHook"); + + if (!DriverHook) + { + FreeLibrary(Handle); + continue; + } + + if (!DriverHook(&RDriver)) + { + FreeLibrary(Handle); + continue; + } + + if (RDriver->VersionMajor != DRV_VERSION_MAJOR || RDriver->VersionMinor != DRV_VERSION_MINOR) + { + FreeLibrary(Handle); + geErrorLog_AddString(-1,"EnumSubDrivers : found driver of different version; ignoring; non-fatal",DriverFileNames[i]); + continue; + } + + DriverInfo->RDriver = RDriver; + + if (!RDriver->EnumSubDrivers(EnumSubDriversCB, (void*)DriverInfo)) + { + FreeLibrary(Handle); + continue; // Should we return FALSE, or just continue? + } + + FreeLibrary(Handle); + + if (!strcmp(DriverFileNames[i], "GlideDrv.dll")) + GlideFound = GE_TRUE; + } + + DriverInfo->RDriver = NULL; // Reset this + + return GE_TRUE; +} + + diff --git a/G3D/Engine/System.h b/G3D/Engine/System.h new file mode 100644 index 0000000..c30a344 --- /dev/null +++ b/G3D/Engine/System.h @@ -0,0 +1,235 @@ +/****************************************************************************************/ +/* System.h */ +/* */ +/* Author: John Pollard */ +/* Description: Friend of engine.c. Takes care of some of the driver work. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_SYSTEM_H +#define GE_SYSTEM_H + +//#define OLD_FONT + +#include "ErrorLog.h" +#include "Genesis.h" +#include +#include "dcommon.h" +#include "Camera.h" +#include "PtrTypes.h" + +#define VectorToSUB(a, b) ( *(((geFloat*)&a) + b) ) + +#define MAX_SUB_DRIVERS 12 +#define MAX_DRIVER_MODES 32 +#define DRV_STR_SIZE 512 +#define DRV_MODE_STR_SIZE 512 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + FrameState_None = 0, + FrameState_Begin, +} geEngine_FrameState; + +//===================================================================================== +// Structure defines +//===================================================================================== + +#define MAX_CLIENT_STRING_LEN 80 +#define MAX_CLIENT_STRINGS 20 + +typedef struct +{ + int32 x,y; + char String[MAX_CLIENT_STRING_LEN]; +} Sys_String; + +typedef struct +{ + geBitmap *FontBitmap; + + uint32 FontLUT1[256]; + Sys_String ClientStrings[MAX_CLIENT_STRINGS]; + int32 NumStrings; +} Sys_FontInfo; + +typedef struct +{ + int32 Freq; +} Sys_CPUInfo; + +typedef struct geDriver_Mode +{ + int32 Id; // Driver assigned mode id + char Name[DRV_MODE_STR_SIZE]; // Driver assigned mode name + int32 Width; // Mode width + int32 Height; // Mode height +} geDriver_Mode; + +typedef struct geDriver +{ + int32 Id; // Driver assigned Id + char Name[DRV_STR_SIZE]; // Driver assigned name + char FileName[256]; // FileName of driver + + geDriver_Mode Modes[MAX_DRIVER_MODES]; // Modes for this driver + int32 NumModes; // Num modes for this driver + +} geDriver; + +typedef struct +{ + // Info the enuming fills in + geDriver SubDrivers[MAX_SUB_DRIVERS]; + int32 NumSubDrivers; + char *CurFileName; + + // Data for current driver + geBoolean Active; // GE_TRUE if a driver and mode has been initialized + + HINSTANCE DriverHandle; // CurrentDriver Handle (for DLL) + + geDriver *CurDriver; // Current driver + geDriver_Mode *CurMode; // Current mode + DRV_Driver *RDriver; // Current driver function hook +} Sys_DriverInfo; + +typedef struct +{ + int32 TraversedPolys; // Total Polys traversed + int32 SentPolys; // Total Polys sent to driver + int32 RenderedPolys; // Total Rendered polys reported by driver + + int32 NumModels; + int32 NumMirrors; +#ifdef MESHES + int32 NumMeshes; +#endif + int32 NumActors; + int32 NumDLights; + int32 NumFog; + int32 LMap1; // Lmaps gone through first pass (reg light) + int32 LMap2; // LMaps gone through 2nd pass (fog) +} Sys_DebugInfo; + +//{} Hack: + +#define ENGINE_PF_WORLD (0) +#define ENGINE_PF_LIGHTMAP (1) +#define ENGINE_PF_USER (2) +#define ENGINE_PF_USER_ALPHA (3) +#define ENGINE_PF_DECAL (4) +#define ENGINE_PF_PALETTE (5) +#define ENGINE_PF_ALPHA_CHANNEL (6) +#define ENGINE_PF_COUNT (7) + +typedef struct BitmapList BitmapList; + +#define ENGINE_MAX_WORLDS 8 + +typedef struct +{ + geWorld *World; + int32 RefCount; + +} geEngine_WorldList; + +// System globals initialized by module it belongs to... +typedef struct geEngine +{ + // System info + Sys_DriverInfo DriverInfo; // Info about current driver (this should be enumed) + Sys_CPUInfo CPUInfo; // Info about the Cpu + Sys_DebugInfo DebugInfo; + + LARGE_INTEGER CurrentTic; + + Sys_FontInfo FontInfo; + + User_Info *UserInfo; // Client loaded resources, etc... + + HWND hWnd; + char AppName[200]; + + // Global LUT's + int16 WaveTable[20]; // Global Wave table (for wavy effects, pumping, etc) + int16 WaveDir[20]; + + // Global info that modules need to render world + //geWorld *World; // The global World + geEngine_WorldList WorldList[ENGINE_MAX_WORLDS]; // Current list of worlds renderable by the engine + + int32 NumWorlds; // Number of active worlds in world list + geWorld *Worlds[ENGINE_MAX_WORLDS]; // Linear array of worlds contained in WorldList + + // Light module info + uint8 StyleLUT1[64][256]; // Style intensity table (StyleLUT1[Intensity][Number]); + + geBoolean Changed; // == GE_TRUE if needs to be updated with Driver + + geBoolean DisplayFrameRateCounter; // Whether or not to display the FPS string + + char *DriverDirectory; // Path to load driver DLLs from + + BitmapList *AttachedBitmaps; + + geBoolean HasPixelFormat[ENGINE_PF_COUNT]; + geRDriver_PixelFormat PixelFormats[ENGINE_PF_COUNT]; + + geFloat CurrentGamma; + geFloat BitmapGamma; + + geBoolean FogEnable; + geFloat FogR; + geFloat FogG; + geFloat FogB; + geFloat FogStart; + geFloat FogEnd; + + geEngine_FrameState FrameState; + +} geEngine; + +//===================================================================================== +// Function prototypes +//===================================================================================== + +//Engine +geEngine *Sys_EngineCreate(HWND hWnd, const char *AppName, const char *DriverDirectory, uint32 Version); + +geBoolean Sys_ShutdownDriver(geEngine *Engine); + +void Sys_EngineFree(geEngine *Engine); + +#ifdef MESHES +Mesh_RenderQ *Sys_WorldAddMesh(geWorld *World, Mesh_MeshDef *MeshDef, int32 Flags); +Mesh_MeshDef *Sys_WorldCreateMesh(geWorld *World, const char *BitmapPath, const char *FileName); +void Sys_WorldFreeMesh(geWorld *World, Mesh_MeshDef *MeshDef); +#endif + +// Misc system +geBoolean Sys_GetCPUFreq(Sys_CPUInfo *Info); +geBoolean Sys_EnginePrint(geEngine *Engine, int32 x, int32 y, char *String); +geBoolean Sys_EngineResetDecorators(geEngine *Engine); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/G3D/Engine/engine.c b/G3D/Engine/engine.c new file mode 100644 index 0000000..77d2cb5 --- /dev/null +++ b/G3D/Engine/engine.c @@ -0,0 +1,2199 @@ +/****************************************************************************************/ +/* Engine.c */ +/* */ +/* Author: Charles Bloom/John Pollard */ +/* Description: Maintains the driver interface, as well as the bitmaps attached */ +/* to the driver. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +//#define DONT_DO_SPLASH // CB hack + +#define WIN32_LEAN_AND_MEAN +#include +#include //timeGetTime +#include // _MAX_PATH +#include // getcwd + +#include "engine.h" + +#include "Errorlog.h" +#include "DCommon.h" +#include "BitmapList.h" +#include "Bitmap.h" +#include "Bitmap._h" +#include "World.h" +#include "log.h" + +//#define DO_ADDREMOVE_MESSAGES +#ifndef _DEBUG +#undef DO_ADDREMOVE_MESSAGES +#endif + +extern geBoolean DoSplashScreen(geEngine *Engine, geDriver_Mode *Mode); + +//============================ +// Internal Protos +//============================ + +static geBoolean Engine_InitDriver( geEngine *Engine, + geDriver *Driver, + geDriver_Mode *DriverMode); + +static void Engine_DrawFontBuffer(geEngine *Engine); +static void Engine_Tick(geEngine *Engine); + +static void SubLarge(LARGE_INTEGER *start, LARGE_INTEGER *end, LARGE_INTEGER *delta); + +#define ABS(xx) ( (xx) < 0 ? (-(xx)) : (xx) ) + +//===================================================================================== +// geEngine_SetGamma +//===================================================================================== +GENESISAPI geBoolean geEngine_SetGamma(geEngine *Engine, geFloat Gamma) +{ + assert(Engine); + + if ( Gamma < 0.01f ) + Gamma = 0.01f; + + if ( ABS( Engine->CurrentGamma - Gamma) < 0.01f ) + return GE_TRUE; + + Engine->CurrentGamma = Gamma; + + geEngine_UpdateGamma(Engine); + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_GetGamma +//===================================================================================== +GENESISAPI geBoolean geEngine_GetGamma(geEngine *Engine, geFloat *Gamma) +{ + assert(Engine); + assert(Gamma); + + *Gamma = Engine->CurrentGamma; + + return GE_TRUE;//Engine->DriverInfo.RDriver->GetGamma(Gamma); +} + +//===================================================================================== +// geEngine_UpdateFogEnable +//===================================================================================== +static geBoolean geEngine_UpdateFogEnable(geEngine *Engine) +{ + if (Engine->DriverInfo.RDriver) + { + return Engine->DriverInfo.RDriver->SetFogEnable(Engine->FogEnable, + Engine->FogR, + Engine->FogG, + Engine->FogB, + Engine->FogStart, + Engine->FogEnd); + } + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_SetFogEnable +//===================================================================================== +GENESISAPI geBoolean geEngine_SetFogEnable(geEngine *Engine, geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End) +{ + Engine->FogEnable = Enable; + + Engine->FogR = r; + Engine->FogG = g; + Engine->FogB = b; + + Engine->FogStart = Start; + Engine->FogEnd = End; + + return geEngine_UpdateFogEnable(Engine); +} + +void geEngine_UpdateGamma(geEngine *Engine) +{ +DRV_Driver * RDriver; +geFloat LastBitmapGamma; + + assert(Engine); + + RDriver = Engine->DriverInfo.RDriver; + + LastBitmapGamma = Engine->BitmapGamma; + + if ( RDriver && (RDriver->EngineSettings->CanSupportFlags & DRV_SUPPORT_GAMMA) ) + { + if ( RDriver->SetGamma(Engine->CurrentGamma) ) + Engine->BitmapGamma = 1.0f; + else + Engine->BitmapGamma = Engine->CurrentGamma; + } + else + { + Engine->BitmapGamma = Engine->CurrentGamma; + } + + if ( ABS(Engine->BitmapGamma - LastBitmapGamma) < 0.1f ) + { + Engine->BitmapGamma = LastBitmapGamma; + } + else + { + int i; + + // Attach all the bitmaps for the engine + if (!BitmapList_SetGamma(Engine->AttachedBitmaps, Engine->BitmapGamma)) + { + geErrorLog_AddString(-1, "geEngine_UpdateGamma: BitmapList_SetGamma for Engine failed", NULL); + } + + for (i=0; i< Engine->NumWorlds; i++) + { + // <> sleazy to peak into World like this + if (!BitmapList_SetGamma(Engine->Worlds[i]->AttachedBitmaps, Engine->BitmapGamma )) + { + geErrorLog_AddString(-1, "geEngine_UpdateGamma: BitmapList_SetGamma for World failed", NULL); + } + } + } + +} + +//================================================================================ +// geEngine_BitmapListInit +// Initializes the engine bitmaplist +//================================================================================ +geBoolean geEngine_BitmapListInit(geEngine *Engine) +{ + assert(Engine); + assert(Engine->AttachedBitmaps == NULL); + + if ( Engine->AttachedBitmaps == NULL ) + { + Engine->AttachedBitmaps = BitmapList_Create(); + if ( ! Engine->AttachedBitmaps ) + { + geErrorLog_AddString(-1, "geEngine_BitmapListInit: BitmapList_Create failed...", NULL); + return GE_FALSE; + } + } + return GE_TRUE; +} + +//================================================================================ +// geEngine_BitmapListShutdown +//================================================================================ +geBoolean geEngine_BitmapListShutdown(geEngine *Engine) +{ + assert(Engine); + + if ( Engine->AttachedBitmaps ) + { + assert( Engine->DriverInfo.Active || BitmapList_CountMembersAttached(Engine->AttachedBitmaps) == 0 ); + + //BitmapList_DetachAll(Engine->AttachedBitmaps); + // Destroy detaches for you! + BitmapList_Destroy(Engine->AttachedBitmaps); + Engine->AttachedBitmaps = NULL; + } + + return GE_TRUE; +} + +//================================================================================ +// geEngine_AddBitmap +//================================================================================ +GENESISAPI geBoolean geEngine_AddBitmap(geEngine *Engine, geBitmap *Bitmap) +{ + assert(Engine); + assert(Bitmap); + assert(Engine->AttachedBitmaps); + + assert(Engine->FrameState == FrameState_None); + + if (!Engine->AttachedBitmaps) + { + geErrorLog_AddString(-1, "geEngine_AddBitmap: AttachedBitmaps is NULL.", NULL); + return GE_FALSE; + } + + geBitmap_SetDriverFlags(Bitmap,RDRIVER_PF_2D); + + // Add bitmap to the lit of bitmaps attached to the engine + if ( BitmapList_Add(Engine->AttachedBitmaps, (geBitmap *)Bitmap) ) + { + Engine->Changed = GE_TRUE; + + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"Engine_AddBitmap : %08X : new\n",Bitmap); + OutputDebugString(str); + } + #endif + } + else + { + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"Engine_AddBitmap : %08X : old\n",Bitmap); + OutputDebugString(str); + } + #endif + } + + return GE_TRUE; +} + +//================================================================================ +// geEngine_RemoveBitmap +//================================================================================ +GENESISAPI geBoolean geEngine_RemoveBitmap(geEngine *Engine, geBitmap *Bitmap) +{ + assert(Engine); + assert(Bitmap); + assert(Engine->AttachedBitmaps); + +// assert(Engine->FrameState == FrameState_None); + + if ( ! Engine->AttachedBitmaps ) + return GE_FALSE; + + if ( BitmapList_Remove(Engine->AttachedBitmaps,Bitmap) ) + { + Engine->Changed = GE_TRUE; + + if (!geBitmap_DetachDriver(Bitmap, GE_TRUE)) + { + geErrorLog_AddString(-1, "geEngine_RemoveBitmap: geBitmap_DetachDriver failed...", NULL); + return GE_FALSE; + } + + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"Engine_RemoveBitmap : %08X : removed\n",Bitmap); + OutputDebugString(str); + } + #endif + } + else + { + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"Engine_RemoveBitmap : %08X : left\n",Bitmap); + OutputDebugString(str); + } + #endif + } + + return GE_TRUE; +} + +// DrawAlphaBitmap + +/////////////////////////////////////////////////////////////// +// +// geEngine_DrawAlphaBitmap() +// +// Draw a btimap with alpha transparancy +// +/////////////////////////////////////////////////////////////// + +GENESISAPI geBoolean GENESISCC geEngine_DrawAlphaBitmap( + geEngine * Engine, + geBitmap * pBitmap, + geVec3d * VertUVArray, + geCamera * ClipCamera, // if null, uses full screen + GE_Rect * PixelRect, // pixels in the "camera" view + GE_Rect * PercentRect, // percent of the "camera" view + geFloat Alpha, + GE_RGBA * RGBA_Array + ) +{ +// set up variables + GE_TLVertex vertex[4]; + geFloat fUVAdd = 0.0f; + geFloat fWidthBmp = 0; + geFloat fHeightBmp = 0; + GE_Rect ClipRect = {0,0,0,0}; + GE_Rect UseRect = {0,0,0,0}; + geVec3d DefaultUVArray[4] = {{0,0,0},{1,0,0},{1,1,0},{0,1,0}}; + GE_RGBA DefaultRGBA_Array[4] = + {{255,255,255,Alpha}, + {255,255,255,Alpha}, + {255,255,255,Alpha}, + {255,255,255,Alpha}}; + geBitmap_Info TempInfo, TempInfo2; + geFloat UVbreak = 0.0f; + + if(pBitmap) + geBitmap_GetInfo(pBitmap, &TempInfo, &TempInfo2); + else + TempInfo.Height = TempInfo.Width = 8; + + fWidthBmp = (geFloat)TempInfo.Width; + fHeightBmp = (geFloat)TempInfo.Height; + +// +// Clip 2d viewport +// + +#if 0 +// eaa3 01/14/2001 Right now, you have to pass the camera in. +// ..I'll fix it eventually... + if(!ClipCamera ) + { + ClipRect.Top = 0; + ClipRect.Left = 0; + ClipRect.Bottom = CHeight-1; + ClipRect.Right = CWidth-1; + } + else +#endif + geCamera_GetClippingRect( ClipCamera, &ClipRect ); + + if(!VertUVArray) + VertUVArray = &DefaultUVArray[0]; + if(!RGBA_Array) + RGBA_Array = &DefaultRGBA_Array[0]; + if(PixelRect) + { + UseRect.Top = PixelRect->Top + ClipRect.Top; + UseRect.Left = PixelRect->Left + ClipRect.Left; + UseRect.Bottom = PixelRect->Bottom + ClipRect.Top; + UseRect.Right = PixelRect->Right + ClipRect.Left; + } + else + { + if(PercentRect) + { + UseRect.Top = ClipRect.Top + + (int32)(0.01f * PercentRect->Top + * (ClipRect.Bottom - ClipRect.Top)); + UseRect.Left = ClipRect.Left + + (int32)(0.01f * PercentRect->Left + * (ClipRect.Right - ClipRect.Left)); + UseRect.Bottom = ClipRect.Bottom + + (int32)(0.01f * PercentRect->Bottom + * (ClipRect.Bottom - ClipRect.Top)); + UseRect.Right = ClipRect.Right + + (int32)(0.01f * PercentRect->Right + * (ClipRect.Right - ClipRect.Left)); + } + else + { + UseRect = ClipRect; + } + } + + vertex[0].x = (geFloat)UseRect.Left; + vertex[0].y = (geFloat)UseRect.Top; + vertex[0].z = 1.0f; + vertex[0].r = RGBA_Array[0].r; + vertex[0].g = RGBA_Array[0].g; + vertex[0].b = RGBA_Array[0].b; + vertex[0].a = RGBA_Array[0].a; + vertex[0].u = VertUVArray[0].X + UVbreak/fWidthBmp; + vertex[0].v = VertUVArray[0].Y + UVbreak/fHeightBmp; + + vertex[1].x = (geFloat)UseRect.Right; + vertex[1].y = (geFloat)UseRect.Top; + vertex[1].z = vertex[0].z; + vertex[1].r = RGBA_Array[1].r; + vertex[1].g = RGBA_Array[1].g; + vertex[1].b = RGBA_Array[1].b; + vertex[1].a = RGBA_Array[1].a; + vertex[1].u = VertUVArray[1].X - UVbreak/fWidthBmp; + vertex[1].v = VertUVArray[1].Y + UVbreak/fHeightBmp; + + vertex[2].x = (geFloat)UseRect.Right; + vertex[2].y = (geFloat)UseRect.Bottom; + vertex[2].z = vertex[0].z; + vertex[2].r = RGBA_Array[2].r; + vertex[2].g = RGBA_Array[2].g; + vertex[2].b = RGBA_Array[2].b; + vertex[2].a = RGBA_Array[2].a; + vertex[2].u = VertUVArray[2].X - UVbreak/fWidthBmp; + vertex[2].v = VertUVArray[2].Y - UVbreak/fHeightBmp; + + vertex[3].x = (geFloat)UseRect.Left; + vertex[3].y = (geFloat)UseRect.Bottom; + vertex[3].z = vertex[0].z; + vertex[3].r = RGBA_Array[3].r; + vertex[3].g = RGBA_Array[3].g; + vertex[3].b = RGBA_Array[3].b; + vertex[3].a = RGBA_Array[3].a; + vertex[3].u = VertUVArray[3].X + UVbreak/fWidthBmp; + vertex[3].v = VertUVArray[3].Y - UVbreak/fHeightBmp; + + if(vertex[0].x < ClipRect.Left ) + { + if(vertex[1].x <= ClipRect.Left ) + { + geErrorLog_AddString(-1, "Clipping Rect has negative dimension", + NULL); + return GE_FALSE; + } + fUVAdd = ( ClipRect.Left - vertex[0].x ) / fWidthBmp; + fWidthBmp -= ( ClipRect.Left - vertex[0].x ); + vertex[0].u += fUVAdd; + vertex[3].u = vertex[0].u; + vertex[0].x = (geFloat)ClipRect.Left; + vertex[3].x = vertex[0].x; + } + + if( vertex[0].y < ClipRect.Top ) + { + if( vertex[2].y <= ClipRect.Top ) + { + geErrorLog_AddString(-1, "Clipping Rect has negative dimension", + NULL); + return GE_FALSE; + } + fUVAdd = ( ClipRect.Top - vertex[0].y ) / fHeightBmp; + fHeightBmp -= ( ClipRect.Top - vertex[0].y ); + vertex[0].v += fUVAdd; + vertex[1].v = vertex[0].v; + vertex[0].y = (geFloat)ClipRect.Top; + vertex[1].y = vertex[0].y; + } + + if(vertex[1].x > ClipRect.Right ) + { + if( vertex[0].x >= ClipRect.Right ) + { + geErrorLog_AddString(-1, "Clipping Rect has negative dimension", + NULL); + return GE_FALSE; + } + fUVAdd = ( vertex[1].x - ClipRect.Right ) / fWidthBmp; + vertex[1].u -= fUVAdd; + vertex[2].u = vertex[1].u; + vertex[1].x = (geFloat)ClipRect.Right - 1; + vertex[2].x = vertex[1].x; + } + + if( vertex[2].y > ClipRect.Bottom ) + { + if( vertex[0].y >= ClipRect.Bottom ) + { + geErrorLog_AddString(-1, "Clipping Rect has negative dimension", + NULL); + return GE_FALSE; + } + fUVAdd = ( vertex[2].y - ClipRect.Bottom ) / fHeightBmp; + vertex[2].v -= fUVAdd; + vertex[3].v = vertex[2].v; + vertex[2].y = (geFloat)ClipRect.Bottom - 1; + vertex[3].y = vertex[2].y; + } + + geEngine_RenderPoly( Engine, + vertex, + 4, + pBitmap, + ( Alpha != 255 ? DRV_RENDER_ALPHA : 0 ) | + DRV_RENDER_CLAMP_UV | DRV_RENDER_FLUSH | + DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE ); + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_SetDriverAndMode +//===================================================================================== +GENESISAPI geBoolean geEngine_SetDriverAndMode( geEngine *Engine, + geDriver *Driver, + geDriver_Mode *DriverMode) +{ + assert(Engine); + assert(Driver); + assert(DriverMode); + + // init calls _Reset and eventually it gets down and Detaches all + + // Set up the Render Driver + if (!Engine_InitDriver(Engine, Driver, DriverMode)) + return GE_FALSE; + + // Force a Driver update + geEngine_SetAllWorldChangedFlag(Engine, GE_TRUE); + Engine->Changed = GE_TRUE; + + geEngine_UpdateGamma(Engine); + geEngine_UpdateFogEnable(Engine); + +//#ifdef DONT_DO_SPLASH +#ifdef _DEBUG + #pragma message("Engine :splash screen disabled") + Engine = Engine; +#else + // Do the splash screen + if (DoSplashScreen(Engine, DriverMode) == GE_FALSE) + return GE_FALSE; +#endif + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_GetDriverSystem +//===================================================================================== +GENESISAPI geDriver_System *geEngine_GetDriverSystem(geEngine *Engine) +{ + assert(Engine); + + return (geDriver_System*)&Engine->DriverInfo; +} + +//===================================================================================== +// geEngine_Activate +// this hits the drivers activation code to manage +// surfaces and exclusive modes for devices (WM_ACTIVATEAPP) +//===================================================================================== +GENESISAPI geBoolean geEngine_Activate(geEngine *Engine, geBoolean bActive) +{ + DRV_Driver *RDriver; + + assert(Engine); + + RDriver =Engine->DriverInfo.RDriver; + + if(Engine->DriverInfo.Active && RDriver) + { + // <> this can sometimes be a pain for debugging + #if 1 + if ( RDriver->SetActive ) + return RDriver->SetActive(bActive); + #endif + } + + return GE_TRUE; +} + +//==================================================================================== +// geEngine_UpdateWindow +// this call updates the drivers with a new rect to blit to +// (usually the result of a window move or resize) +//==================================================================================== +GENESISAPI geBoolean geEngine_UpdateWindow(geEngine *Engine) +{ + DRV_Driver *RDriver; + + RDriver = Engine->DriverInfo.RDriver; + + if(Engine->DriverInfo.Active && RDriver) + { + if (RDriver->UpdateWindow ) + return RDriver->UpdateWindow(); + } + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_ShutdownDriver +//===================================================================================== +GENESISAPI geBoolean geEngine_ShutdownDriver(geEngine *Engine) +{ +Sys_DriverInfo *DrvInfo; + + assert(Engine); + + DrvInfo = &(Engine->DriverInfo); + + assert(DrvInfo); + + if (!DrvInfo->Active) + return GE_TRUE; // Just return true, and don't do nothing + + #if 0 // <> + #ifdef _DEBUG + OutputDebugString("geEngine_ShutdownDriver\n"); + #endif + #endif + + // First, reset the driver + if (!geEngine_ResetDriver(Engine)) + { + geErrorLog_AddString(-1, "geEngine_ShutdownDriver: geEngine_ResetDriver failed.", NULL); + return GE_FALSE; + } + + // Shutdown the driver + DrvInfo->RDriver->Shutdown(); + + if (!FreeLibrary(DrvInfo->DriverHandle) ) + return GE_FALSE; + + DrvInfo->Active = GE_FALSE; + DrvInfo->RDriver = NULL; + + return GE_TRUE; +} + +//================================================================================ +// geEngine_RenderPoly +// World MUST ne passed in if using a texture, as it is a container object for ALL 3d textures +// * stop passing World ? +// * cut the Flags parameter and pass in zero ? +//================================================================================ +GENESISAPI void GENESISCC geEngine_RenderPoly(const geEngine *Engine, + const GE_TLVertex *Points, int NumPoints, const geBitmap *Texture, uint32 Flags) +{ + geBoolean Ret; + + assert(Engine && Points ); + + if ( Texture ) + { + geRDriver_THandle * TH; + +// assert(World); +// assert(geEngine_HasWorld(Engine, World) == GE_TRUE); +// assert(World->AttachedBitmaps); +// assert(BitmapList_Has(World->AttachedBitmaps, (geBitmap*)Texture) == GE_TRUE); + + TH = geBitmap_GetTHandle(Texture); + assert(TH); + + Ret = Engine->DriverInfo.RDriver->RenderMiscTexturePoly((DRV_TLVertex *)Points, + NumPoints,TH,Flags); + } + else + { + Ret = Engine->DriverInfo.RDriver->RenderGouraudPoly((DRV_TLVertex *)Points, + NumPoints,Flags); + } + + assert(Ret == GE_TRUE); +} + +GENESISAPI void GENESISCC geEngine_RenderPolyArray(const geEngine *Engine, const GE_TLVertex ** pPoints, int * pNumPoints, int NumPolys, + const geBitmap *Texture, uint32 Flags) +{ +geBoolean Ret; +int pn; +DRV_Driver * Driver; + + assert(Engine && pPoints && pNumPoints ); + + Driver = Engine->DriverInfo.RDriver; + assert(Driver); + + if ( Texture ) + { + geRDriver_THandle * TH; + + TH = geBitmap_GetTHandle(Texture); + assert(TH); + + for(pn=0;pnRenderMiscTexturePoly((DRV_TLVertex *)pPoints[pn], + pNumPoints[pn],TH,Flags); + assert(Ret); + } + } + else + { + for(pn=0;pnRenderGouraudPoly((DRV_TLVertex *)pPoints[pn], + pNumPoints[pn],Flags); + assert(Ret); + } + } + +} + +//================================================================================ +// geEngine_DrawBitmap +//================================================================================ +GENESISAPI geBoolean GENESISCC geEngine_DrawBitmap(const geEngine *Engine, + const geBitmap *Bitmap, + const geRect * Source, uint32 x, uint32 y) +{ +geRDriver_THandle * TH; +geBoolean Ret; + + //#pragma message("make geRect the same as RECT, or don't use RECT!?") + // The drivers once did not include genesis .h's + // (D3D uses RECT so thats why the drivers adopted RECT's...) + #pragma message("Engine : Make the drivers use geRect, JP") + + assert(Engine); + assert(Bitmap); + + assert(Engine->AttachedBitmaps); + assert(BitmapList_Has(Engine->AttachedBitmaps, (geBitmap *)Bitmap) == GE_TRUE); + + TH = geBitmap_GetTHandle(Bitmap); + assert(TH); + + //Ret = Engine->DriverInfo.RDriver->Drawdecal(TH,(RECT *)Source,x,y); + + if (Source) // Source CAN be NULL!!! + { + RECT rect; + + rect.left = Source->Left; + rect.top = Source->Top; + rect.right = Source->Right; + rect.bottom = Source->Bottom; + + Ret = Engine->DriverInfo.RDriver->DrawDecal(TH, &rect, x,y); + } + else + Ret = Engine->DriverInfo.RDriver->DrawDecal(TH, NULL, x,y); + + if ( ! Ret ) + { + geErrorLog_AddString(-1,"geEngine_DrawBitmap : DrawDecal failed", NULL); + } + +return Ret; +} + +//==================================================================================== +// geEngine_RebuildFastWorldList +//==================================================================================== +geBoolean geEngine_RebuildFastWorldList(geEngine *Engine) +{ + int32 i; + geEngine_WorldList *pWorldList; + + Engine->NumWorlds = 0; + + pWorldList = Engine->WorldList; + + for (i=0; i< ENGINE_MAX_WORLDS; i++, pWorldList++) + { + if (pWorldList->RefCount > 0) + { + assert(pWorldList->World); + + Engine->Worlds[Engine->NumWorlds++] = pWorldList->World; + + assert(Engine->NumWorlds <= ENGINE_MAX_WORLDS); + } + } + + return GE_TRUE; +} + +//==================================================================================== +// geEngine_AddWorld +//==================================================================================== +GENESISAPI geBoolean geEngine_AddWorld(geEngine *Engine, geWorld *World) +{ + int32 i; + geEngine_WorldList *pWorldList; + + assert(Engine); + assert(World); + + // Try to find it in the list first + pWorldList = Engine->WorldList; + for (i=0; i< ENGINE_MAX_WORLDS; i++, pWorldList++) + { + if (pWorldList->World == World) // World is allready in list + { + assert(pWorldList->RefCount > 0); // There should allready be a ref count!!! + pWorldList->RefCount++; + + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"Engine_AddWorld : %08X : old\n",World); + OutputDebugString(str); + } + #endif + + return GE_TRUE; + } + + } + + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"Engine_AddWorld : %08X : new\n",World); + OutputDebugString(str); + } + #endif + + // Not found, add a new one + pWorldList = Engine->WorldList; + for (i=0; i< ENGINE_MAX_WORLDS; i++, pWorldList++) + { + if (!pWorldList->RefCount) + break; + } + + if (i == ENGINE_MAX_WORLDS) + { + geErrorLog_AddString(-1, "geEngine_AddWorld: Out of slots.", NULL); + return GE_FALSE; + } + + // Save the info for the first time + pWorldList->World = World; + pWorldList->RefCount = 1; + + // Re-build the fast list of worlds + geEngine_RebuildFastWorldList(Engine); + Engine->Changed = GE_TRUE; + World->Changed = GE_TRUE; + + if (!geWorld_CreateRef(World)) + { + geErrorLog_AddString(-1, "geEngine_AddWorld: geWorld_CreateRef failed...", NULL); + return GE_FALSE; + } + + return GE_TRUE; +} + +//==================================================================================== +// geEngine_RemoveWorld +//==================================================================================== +GENESISAPI geBoolean geEngine_RemoveWorld(geEngine *Engine, geWorld *World) +{ + int32 i; + geEngine_WorldList *pWorldList; + + assert(Engine); + assert(World); + + // Try to find it in the list + pWorldList = Engine->WorldList; + for (i=0; i< ENGINE_MAX_WORLDS; i++, pWorldList++) + { + if (pWorldList->World == World) + break; + } + + if (i == ENGINE_MAX_WORLDS) + { + geErrorLog_AddString(-1, "geEngine_RemoveWorld: World not found.", NULL); + return GE_FALSE; + } + + assert(pWorldList->RefCount > 0); + + // Decrease the reference count on the worldlist + pWorldList->RefCount--; + + // When the ref count gos to zero, remove the world for good + if (pWorldList->RefCount == 0) + { + + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"Engine_RemoveWorld : %08X : removed\n",World); + OutputDebugString(str); + } + #endif + + // Detach all the bitmaps in the world before finally removing it + if (Engine->DriverInfo.Active) + { + if (!geWorld_DetachAll(World)) + { + geErrorLog_AddString(-1, "geEngine_RemoveWorld: geWorld_DetachAll failed.", NULL); + return GE_FALSE; + } + } + + // Clear this pWorldList slot + memset(pWorldList, 0, sizeof(*pWorldList)); + + // Re-build the fast list of worlds + geEngine_RebuildFastWorldList(Engine); + + // Force an update + Engine->Changed = GE_TRUE; + + // Free the world (decrease it's reference count) + geWorld_Free(World); + } + else + { + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"Engine_RemoveWorld : %08X : left\n",World); + OutputDebugString(str); + } + #endif + } + + return GE_TRUE; +} + + +//==================================================================================== +// geEngine_RemoveAllWorlds +//==================================================================================== +geBoolean geEngine_RemoveAllWorlds(geEngine *Engine) +{ + int32 i; + geEngine_WorldList *pWorldList; + geWorld *World; + + assert(Engine); + + // Try to find it in the list + pWorldList = Engine->WorldList; + for (i=0; i< ENGINE_MAX_WORLDS; i++, pWorldList++) + { + World = pWorldList->World; + if ( World ) + { + assert(pWorldList->RefCount > 0); + + if (Engine->DriverInfo.Active) + { + if (!geWorld_DetachAll(World)) + { + geErrorLog_AddString(-1, "geEngine_RemoveWorld: geWorld_DetachAll failed.", NULL); + return GE_FALSE; + } + } + + assert( World->RefCount >= 1 ); + + // Free the world (decrease it's reference count) + geWorld_Free(World); + } + memset(pWorldList, 0, sizeof(*pWorldList)); + } + + // Force an update + geEngine_RebuildFastWorldList(Engine); + Engine->Changed = GE_TRUE; + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_HasWorld +//===================================================================================== +geBoolean geEngine_HasWorld(const geEngine *Engine, const geWorld *World) +{ + int32 i; + const geEngine_WorldList *pWorldList; + + assert(Engine); + assert(World); + + // Try to find it in the list + pWorldList = Engine->WorldList; + for (i=0; i< ENGINE_MAX_WORLDS; i++, pWorldList++) + { + if (pWorldList->World == World) + { + assert(pWorldList->RefCount > 0); + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//===================================================================================== +// geEngine_DetachAllWorlds +//===================================================================================== +geBoolean geEngine_DetachAllWorlds(geEngine *Engine) +{ + int32 i; + geBoolean Ret; + + Ret = GE_TRUE; + + for (i=0; i< Engine->NumWorlds; i++) + { + if (!geWorld_DetachAll(Engine->Worlds[i])) + { + geErrorLog_AddString(-1, "geEngine_DetachAllWorlds: geWorld_DetachAll failed.", NULL); + Ret = GE_FALSE; + } + + if (!geEngine_DestroyWorldLightmapTHandles(Engine, Engine->Worlds[i])) + { + geErrorLog_AddString(-1, "geEngine_DetachAllWorlds: geEngine_DestroyWorldLightmapTHandles failed.", NULL); + Ret = GE_FALSE; + } + } + + return Ret; +} + +//===================================================================================== +// geEngine_CreateWorldLightmapTHandles +//===================================================================================== +geBoolean geEngine_CreateWorldLightmapTHandles(geEngine *Engine, geWorld *World) +{ + DRV_Driver *RDriver; + int32 i; + World_BSP *BSP; + GBSP_BSPData *BSPData; + #ifdef _DEBUG + int CreatedCount = 0; + #endif + + assert(Engine); + assert(World); + + BSP = World->CurrentBSP; + BSPData = &BSP->BSPData; + RDriver = Engine->DriverInfo.RDriver; + + // + // Create all the lightmap thandles + // + World_SetEngine(Engine); + World_SetWorld(World); + World_SetGBSP(World->CurrentBSP); + + for (i=0; iNumGFXFaces; i++) + { + BOOL D; + DRV_LInfo *pLInfo; + + pLInfo = &BSP->SurfInfo[i].LInfo; + + if ((pLInfo->Face == -1)) + continue; + + if (!(BSP->SurfInfo[i].Flags & SURFINFO_LIGHTMAP)) + continue; + + assert(!pLInfo->THandle); // This should be true!!! + + if (pLInfo->THandle) + continue; + + Light_SetupLightmap(pLInfo, &D); + + // {} _LIGHTMAP_ + pLInfo->THandle = Engine_CreateTHandle(Engine,pLInfo->Width, pLInfo->Height, 1, ENGINE_PF_LIGHTMAP); + + if (!pLInfo->THandle) + { + geErrorLog_AddString(-1, RDriver->LastErrorStr, NULL); + geErrorLog_AddString(-1, "geEngine_CreateWorldTHandles: Engine_CreateTHandle failed...\n", NULL); + return GE_FALSE; + } + + #ifdef _DEBUG + CreatedCount ++; + #endif + } + +#ifdef _DEBUG + Log_Printf("geEngine_CreateWorldLightmapTHandles:Created %d of %d\n",CreatedCount,BSPData->NumGFXFaces); +#endif + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_DestroyWorldLightmapTHandles +//===================================================================================== +geBoolean geEngine_DestroyWorldLightmapTHandles(geEngine *Engine, geWorld *World) +{ + DRV_Driver *RDriver; + int32 i; + World_BSP *BSP; + GBSP_BSPData *BSPData; + geBoolean Ret; + int32 Handle1=1768710981; + int32 Handle2=0x21657370; + #ifdef _DEBUG + int DestroyedCount = 0; + #endif + + assert(Engine); + assert(World); + + Ret = GE_TRUE; + + BSP = World->CurrentBSP; + BSPData = &BSP->BSPData; + RDriver = Engine->DriverInfo.RDriver; + + // + // Create all the lightmap thandles + // + World_SetEngine(Engine); + World_SetWorld(World); + World_SetGBSP(World->CurrentBSP); + + for (i=0; iNumGFXFaces; i++) + { + DRV_LInfo *pLInfo; + + pLInfo = &BSP->SurfInfo[i].LInfo; + + if ((pLInfo->Face == -1)) + continue; + + if (!(BSP->SurfInfo[i].Flags & SURFINFO_LIGHTMAP)) + continue; + + if (!pLInfo->THandle) + continue; + + if (!RDriver->THandle_Destroy(pLInfo->THandle)) + Ret = GE_FALSE; + + pLInfo->THandle = NULL; + + #ifdef _DEBUG + DestroyedCount ++; + #endif + } + +#ifdef _DEBUG + Log_Printf("geEngine_DestroyWorldLightmapTHandles: Freed %d of %d\n",DestroyedCount,BSPData->NumGFXFaces); +#endif + + return Ret; +} + +//===================================================================================== +// geEngine_AttachAllWorlds +//===================================================================================== +geBoolean geEngine_AttachAllWorlds(geEngine *Engine) +{ + int32 i; + DRV_Driver *RDriver; + + assert(Engine); + + RDriver = Engine->DriverInfo.RDriver; + + for (i=0; i< Engine->NumWorlds; i++) + { + if (!geWorld_AttachAll(Engine->Worlds[i], RDriver, Engine->BitmapGamma )) + { + geErrorLog_AddString(-1, "geEngine_AttachAllWorlds: geWorld_AttachAll failed.", NULL); + return GE_FALSE; + } + + if (!geEngine_CreateWorldLightmapTHandles(Engine, Engine->Worlds[i])) + { + geErrorLog_AddString(-1, "geEngine_AttachAllWorlds: geEngine_CreateWorldLightmapTHandles failed.", NULL); + return GE_FALSE; + } + + } + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_AttachAll +//===================================================================================== +geBoolean geEngine_AttachAll(geEngine *Engine) +{ + DRV_Driver *RDriver; + + assert( Engine ); + + RDriver = Engine->DriverInfo.RDriver; + assert( RDriver ); + + // If current driver is not active, then split + if (!Engine->DriverInfo.Active) + return GE_TRUE; + + // Attach all the bitmaps for the engine + if (!BitmapList_AttachAll(Engine->AttachedBitmaps, RDriver, Engine->BitmapGamma)) + { + geErrorLog_AddString(-1, "geEngine_AttachAll: BitmapList_AttachAll for Engine failed...", NULL); + return GE_FALSE; + } + + // Attach all the bitmaps for the world + if (!geEngine_AttachAllWorlds(Engine)) + { + geErrorLog_AddString(-1, "geEngine_AttachAll: geEngine_AttachAllWorlds failed.", NULL); + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_DetachAll +//===================================================================================== +geBoolean geEngine_DetachAll(geEngine *Engine) +{ + assert(Engine); + + // Shutdown all the geBitmaps + if (!BitmapList_DetachAll(Engine->AttachedBitmaps)) + { + geErrorLog_AddString(-1, "geEngine_DetachAll: BitmapList_DetachAll failed for engine.", NULL); + return GE_FALSE; + } + + // Detach all the bitmaps that belong to all the currently connected worlds + if (!geEngine_DetachAllWorlds(Engine)) + { + geErrorLog_AddString(-1, "geEngine_DetachAll: geEngine_DetachAllWorlds failed for engine.", NULL); + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_ResetDriver +//===================================================================================== +geBoolean geEngine_ResetDriver(geEngine *Engine) +{ + assert(Engine != NULL); + assert(Engine->DriverInfo.RDriver); + + // To be safe, detach all things from the current driver + if (!geEngine_DetachAll(Engine)) + { + geErrorLog_AddString(-1, "geEngine_ResetDriver: geEngine_DetachAll failed.", NULL); + return GE_FALSE; + } + + // Reset the driver + if (!Engine->DriverInfo.RDriver->Reset()) + { + geErrorLog_AddString(-1, "geEngine_ResetDriver: Engine->DriverInfo.RDriver->Reset() failed.", NULL); + return GE_FALSE; + } + + geEngine_UpdateFogEnable(Engine); + + return GE_TRUE; +} + +//=================================================================================== +// geEngine_InitFonts +//=================================================================================== +geBoolean geEngine_InitFonts(geEngine *Engine) +{ + Sys_FontInfo *Fi; + + assert(Engine); + + Fi = &Engine->FontInfo; + + assert(Fi->FontBitmap == NULL); + + // Load the bitmap + { + geVFile * MemFile; + geVFile_MemoryContext Context; + + { + extern unsigned char font_bmp[]; + extern int font_bmp_length; + + Context.Data = font_bmp; + Context.DataLength = font_bmp_length; + + MemFile = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_MEMORY, NULL, &Context, GE_VFILE_OPEN_READONLY); + } + + if (!MemFile) + { + geErrorLog_AddString(-1,"InitFonts : geVFile_OpenNewSystem Memory fontbmp failed.", NULL); + return GE_FALSE; + } + + if ( ! (Fi->FontBitmap = geBitmap_CreateFromFile(MemFile)) ) + { + geErrorLog_AddString(-1,"InitFonts : geBitmap_CreateFromFile failed.", NULL); + goto fail; + } + + #if 0 + #pragma message("Engine : fonts will have alpha once Decals do : CB"); + // <> CB : give fonts alpha so they look purty + // pointless right now cuz we don't get enum'ed a _2D_ type with alpha + { + geBitmap * FontAlpha; + FontAlpha = geBitmap_Create( geBitmap_Width(Fi->FontBitmap), geBitmap_Height(Fi->FontBitmap), 1, GE_PIXELFORMAT_8BIT_GRAY ); + if ( FontAlpha ) + { + if ( geBitmap_BlitBitmap(Fi->FontBitmap,FontAlpha) ) + { + if ( ! geBitmap_SetAlpha( Fi->FontBitmap, FontAlpha ) ) + { + geErrorLog_AddString(-1,"InitFonts : SetAlpha failed : non-fatal", NULL); + } + } + else + { + geErrorLog_AddString(-1,"InitFonts : BlitBitmap failed : non-fatal", NULL); + } + geBitmap_Destroy(&FontAlpha); + } + } + #endif + + if (!geBitmap_SetColorKey(Fi->FontBitmap, GE_TRUE, 0, GE_FALSE)) + { + geErrorLog_AddString(-1,"InitFonts : geBitmap_SetColorKey failed.", NULL); + goto fail; + } + + if ( ! geEngine_AddBitmap(Engine,Fi->FontBitmap) ) + { + geErrorLog_AddString(-1,"InitFonts : geEngine_AddBitmap failed.", NULL); + goto fail; + } + + goto success; + + fail: + + geVFile_Close(MemFile); + return GE_FALSE; + + success: + + geVFile_Close(MemFile); + } + + // + // Setup font lookups + // + { + int PosX, PosY, Width, i; + + PosX = 0; + PosY = 0; + Width = 128*8; + + for (i=0; i< 128; i++) + { + Fi->FontLUT1[i] = (PosX<<16) | PosY; + PosX+=8; + + if (PosX >= Width) + { + PosY += 14; + PosX = 0; + } + } + } + + return GE_TRUE; +} + +//=================================================================================== +// geEngine_ShutdownFonts +//=================================================================================== +geBoolean geEngine_ShutdownFonts(geEngine *Engine) +{ + Sys_FontInfo *Fi; + + assert(Engine); + + Fi = &Engine->FontInfo; + + if (Fi->FontBitmap) + { + if (!geEngine_RemoveBitmap(Engine, Fi->FontBitmap)) + { + geErrorLog_AddString(-1, "geEngine_ShutdownFonts: geEngine_RemoveBitmap failed.", NULL); + return GE_FALSE; + } + + geBitmap_Destroy(&Fi->FontBitmap); + } + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_SetAllWorldChangedFlag +// Forces all worlds to be uploaded to the card again +//===================================================================================== +void geEngine_SetAllWorldChangedFlag(geEngine *Engine, geBoolean Flag) +{ + int32 i; + + for (i=0; i< Engine->NumWorlds; i++) + Engine->Worlds[i]->Changed = Flag; +} + + +//===================================================================================== +// geEngine_LoadLibrary +//===================================================================================== +HINSTANCE geEngine_LoadLibrary( const char * lpLibFileName, const char *DriverDirectory) +{ + char Buff[_MAX_PATH]; + char *StrEnd; + HINSTANCE Library; + + //------------------------- + strcpy(Buff, DriverDirectory); + StrEnd = Buff + strlen(Buff) - 1; + if ( *StrEnd != '\\' && *StrEnd != '/' && *StrEnd != ':' ) + { + strcat(Buff,"\\"); + } + strcat(Buff, lpLibFileName); + Library = LoadLibrary(Buff); + if ( Library ) + return Library; + +#pragma message("Engine : LoadLibrary : need geConfig_GetDriverDir") +#ifdef LOADLIBRARY_HARDCODES + #pragma message("Engine : using LoadLibrary HardCodes : curdir, q:\\genesis, c:\\genesis") + + //------------------------- + + getcwd(Buff,_MAX_PATH); + StrEnd = Buff + strlen(Buff) - 1; + if ( *StrEnd != '\\' && *StrEnd != '/' && *StrEnd != ':' ) + { + strcat(Buff,"\\"); + } + strcat(Buff, lpLibFileName); + Library = LoadLibrary(Buff); + if ( Library ) + return Library; + + //------------------------- + + strcpy(Buff, "q:\\genesis"); + StrEnd = Buff + strlen(Buff) - 1; + if ( *StrEnd != '\\' && *StrEnd != '/' && *StrEnd != ':' ) + { + strcat(Buff,"\\"); + } + strcat(Buff, lpLibFileName); + Library = LoadLibrary(Buff); + if ( Library ) + return Library; + + //------------------------- + + strcpy(Buff, "c:\\genesis"); + StrEnd = Buff + strlen(Buff) - 1; + if ( *StrEnd != '\\' && *StrEnd != '/' && *StrEnd != ':' ) + { + strcat(Buff,"\\"); + } + strcat(Buff, lpLibFileName); + Library = LoadLibrary(Buff); + if ( Library ) + return Library; +#endif + +return NULL; +} + + +extern GInfo GlobalInfo; // AHH!!! Get rid of this!!! + +//===================================================================================== +// EngineInitDriver +//===================================================================================== + +static geBoolean Engine_InitDriver( geEngine *Engine, + geDriver *Driver, + geDriver_Mode *DriverMode) +{ + Sys_DriverInfo *DrvInfo; + DRV_Hook *Hook; + DRV_DriverHook DLLDriverHook; + DRV_Driver *RDriver; + + assert(Engine != NULL); + assert(Driver != NULL); + assert(DriverMode != NULL); + + DrvInfo = &Engine->DriverInfo; + + //#pragma message("Engine : DriverMode is changing, do Bitmap re-attaches") + // _Shutdown calls _Reset which detaches all + + if (! geEngine_ShutdownDriver(Engine)) + { + geErrorLog_AddString(-1, "Engine_InitDriver: geEngine_ShutdownDriver failed.", NULL); + return GE_FALSE; + } + + if (DrvInfo->Active) + { + geErrorLog_Add(GE_ERR_DRIVER_ALLREADY_INITIALIZED, NULL); + return GE_FALSE; + } + + DrvInfo->CurDriver = Driver; + DrvInfo->CurMode = DriverMode; + + DrvInfo->DriverHandle = geEngine_LoadLibrary(Driver->FileName, Engine->DriverDirectory); + + if (!DrvInfo->DriverHandle) + { + geErrorLog_Add(GE_ERR_DRIVER_NOT_FOUND, NULL); + return GE_FALSE; + } + + #ifdef LINK_STATIC_DRIVER + { + extern BOOL DriverHook(DRV_Driver **Driver); + Hook = (DRV_Hook*)DriverHook; + } + #else + Hook = (DRV_Hook*)GetProcAddress(DrvInfo->DriverHandle, "DriverHook"); + #endif + + if (!Hook) + { + geErrorLog_Add(GE_ERR_INVALID_DRIVER, NULL); + return GE_FALSE; + } + + if (!Hook(&DrvInfo->RDriver)) + { + DrvInfo->RDriver = NULL; + geErrorLog_Add(GE_ERR_INVALID_DRIVER, NULL); + return GE_FALSE; + } + + // Get a handy pointer to the driver + RDriver = DrvInfo->RDriver; + + if (RDriver->VersionMajor != DRV_VERSION_MAJOR || RDriver->VersionMinor != DRV_VERSION_MINOR) + { + geErrorLog_Add(GE_ERR_INVALID_DRIVER, NULL); + return GE_FALSE; + } + + // We MUST set this! So driver can setup lightmap data when needed... + RDriver->SetupLightmap = Light_SetupLightmap; + RDriver->GlobalInfo = &GlobalInfo; + + strcpy(DLLDriverHook.AppName, Engine->AppName); + + // + // Setup what driver they want + // + + DLLDriverHook.Driver = Driver->Id; + strcpy(DLLDriverHook.DriverName, Driver->Name); + DLLDriverHook.Mode = DriverMode->Id; + DLLDriverHook.Width = DriverMode->Width; + DLLDriverHook.Height = DriverMode->Height; + DLLDriverHook.hWnd = Engine->hWnd; + strcpy(DLLDriverHook.ModeName, DriverMode->Name); + + if (!RDriver->Init(&DLLDriverHook)) + { + geErrorLog_Add(GE_ERR_DRIVER_INIT_FAILED, NULL); + geErrorLog_AddString(-1, RDriver->LastErrorStr , NULL); + return GE_FALSE; + } + + DrvInfo->Active = GE_TRUE; + + Engine_SetupPixelFormats(Engine); // <> temp hack + + Engine->Changed = GE_TRUE; + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_Prep +//===================================================================================== +static geBoolean geEngine_Prep(geEngine *Engine) +{ + geBoolean WorldChanged; + int32 i; + + assert(Engine); + + // See if any of the attached worlds has changed... + WorldChanged = GE_FALSE; + + for (i=0; i< Engine->NumWorlds; i++) + { + if (Engine->Worlds[i]->Changed) + WorldChanged = GE_TRUE; + } + + // Check to see if the world has changed + if (!WorldChanged && !Engine->Changed) + return GE_TRUE; // Nothing to do if any of the worlds (and engine) has not changed + + // Throw everything off the card... + if (!geEngine_ResetDriver(Engine)) + { + geErrorLog_AddString(-1,"geEngine_Prep : geEngine_ResetDriver", NULL); + return GE_FALSE; + } + + // Attach all the current bitmaps to the current driver + if (!geEngine_AttachAll(Engine)) + { + geErrorLog_AddString(-1,"geEngine_Prep : geEngine_AttachAll failed", NULL); + return GE_FALSE; + } + + // Reset all the changed flags + geEngine_SetAllWorldChangedFlag(Engine, GE_FALSE); + Engine->Changed = GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// geEngine_RenderWorld +//===================================================================================== +GENESISAPI geBoolean geEngine_RenderWorld(geEngine *Engine, geWorld *World, geCamera *Camera, geFloat Time) +{ + Sys_DriverInfo *DInfo; + int32 Width, Height; + + assert(Engine != NULL); + assert(World != NULL); + assert(Camera != NULL); + + assert(geEngine_HasWorld(Engine, World) == GE_TRUE); // You have to add the world to the engine before rendering! + + assert(Engine->Changed == GE_FALSE); + assert(World->Changed == GE_FALSE); + + if (!World || !Camera) + { + geErrorLog_Add(GE_ERR_INVALID_PARMS, NULL); + return GE_FALSE; + } + + DInfo = &Engine->DriverInfo; + + // This must not be NULL, or there is not a true current driver mode set + assert(DInfo->CurMode); + + Width = DInfo->CurMode->Width; + Height = DInfo->CurMode->Height; + + if (Width != -1 && Height != -1) // If not in window mode... + { + geFloat CameraWidth,CameraHeight; + + geCamera_GetWidthHeight(Camera,&CameraWidth,&CameraHeight); + + if (CameraWidth > Width || CameraHeight > Height) + { + geErrorLog_Add(GE_ERR_INVALID_CAMERA, NULL); + return GE_FALSE; + } + } + + if (!World_WorldRenderQ(Engine, World, Camera)) + return GE_FALSE; + + return GE_TRUE; +} + +//=================================================================================== +// geEngine_BeginFrame +//=================================================================================== +GENESISAPI geBoolean geEngine_BeginFrame(geEngine *Engine, geCamera *Camera, geBoolean ClearScreen) +{ + RECT DrvRect, *pDrvRect; + geRect gDrvRect; + + assert(Engine != NULL); + + assert(Engine->FrameState == FrameState_None); + + Engine->FrameState = FrameState_Begin; + + // Make sure the driver is avtive + if (!Engine->DriverInfo.Active) + { + geErrorLog_Add(GE_ERR_DRIVER_NOT_INITIALIZED, NULL); + return GE_FALSE; + } + + assert(Engine->DriverInfo.RDriver != NULL); + + // Make sure we have everything finalized with this world so the engine can render it + if (!geEngine_Prep(Engine)) + return FALSE; + + // Do some timing stuff + QueryPerformanceCounter(&Engine->CurrentTic); + + // Clear some debug info + memset(&Engine->DebugInfo, 0, sizeof(Engine->DebugInfo)); + + if(Camera) + { + geCamera_GetClippingRect(Camera, &gDrvRect); + + DrvRect.left =gDrvRect.Left; + DrvRect.top =gDrvRect.Top; + DrvRect.right =gDrvRect.Right; + DrvRect.bottom =gDrvRect.Bottom; + + pDrvRect = &DrvRect; + } + else + pDrvRect = NULL; + + if (!Engine->DriverInfo.RDriver->BeginScene( ClearScreen , TRUE, pDrvRect)) + { + geErrorLog_Add(GE_ERR_DRIVER_BEGIN_SCENE_FAILED, NULL); + return GE_FALSE; + } + + return GE_TRUE; +} + +extern int32 NumExactCast; +extern int32 NumBBoxCast; +extern int32 NumGetContents; + +//=================================================================================== +// geEngine_EndFrame +//=================================================================================== +GENESISAPI geBoolean geEngine_EndFrame(geEngine *Engine) +{ + LARGE_INTEGER NowTic, DeltaTic; + geFloat Fps; + //DRV_Debug *Debug; + + assert(Engine != NULL); + + assert(Engine->FrameState == FrameState_Begin); + + Engine->FrameState = FrameState_None; + + if (!Engine->DriverInfo.Active) + { + geErrorLog_Add(GE_ERR_DRIVER_NOT_INITIALIZED, NULL); + return GE_FALSE; + } + + assert(Engine->DriverInfo.RDriver != NULL); + + //Debug = (DRV_Debug*)Engine->DriverInfo.RDriver->LoadMiscTexture; + //geEngine_Printf(Engine, 2, 20, "LMap Cycles = %i", Debug->LMapCount[0][0]); + + Engine_DrawFontBuffer(Engine); + + if (!Engine->DriverInfo.RDriver->EndScene()) + { + geErrorLog_Add(GE_ERR_DRIVER_END_SCENE_FAILED, NULL); + return GE_FALSE; + } + + QueryPerformanceCounter(&NowTic); + //CurrentFrequency = ((geFloat)PR_EntireFrame.ElapsedCycles/200.0f) + + SubLarge(&Engine->CurrentTic, &NowTic, &DeltaTic); + + if (DeltaTic.LowPart > 0) + Fps = (geFloat)Engine->CPUInfo.Freq / (geFloat)DeltaTic.LowPart; + else + Fps = 100.0f; + + if (Engine->DisplayFrameRateCounter == GE_TRUE) // Dieplay debug info + { + #define MAX_FPS_ARRAY 20 + + geFloat AverageFps; + //DRV_CacheInfo *pCacheInfo; + static geFloat FpsArray[MAX_FPS_ARRAY]; + static int32 NumFps = 0, i; + + // Changed Average Fps to go accross last n frames, JP... + FpsArray[(NumFps++) % MAX_FPS_ARRAY] = Fps; + + for (AverageFps = 0.0f, i=0; iDebugInfo.RenderedPolys = Engine->DriverInfo.RDriver->NumRenderedPolys; + + geEngine_Printf(Engine, 2,2+15*0, "Fps : %2.2f / %2.2f", Fps, AverageFps); + geEngine_Printf(Engine, 2,2+15*1, "Polys : %4i/%4i/%4i", Engine->DebugInfo.TraversedPolys, Engine->DebugInfo.SentPolys, Engine->DebugInfo.RenderedPolys); + + geEngine_Printf(Engine, 2,2+15*2, "Mirrors: %3i", Engine->DebugInfo.NumMirrors); +/* + pCacheInfo = Engine->DriverInfo.RDriver->CacheInfo; + + if (pCacheInfo) + { + geEngine_Printf(Engine, 2, 2+15*3, "Cache: %4i/%4i/%4i/%4i/%4i", + pCacheInfo->CacheFull, + pCacheInfo->CacheRemoved, + pCacheInfo->CacheFlushes, + pCacheInfo->TexMisses, + pCacheInfo->LMapMisses); + + } +*/ + geEngine_Printf(Engine, 2,2+15*3, "Actors : %3i, Models: %3i", Engine->DebugInfo.NumActors, Engine->DebugInfo.NumModels); + geEngine_Printf(Engine, 2,2+15*4, "DLights: %3i", Engine->DebugInfo.NumDLights); + geEngine_Printf(Engine, 2,2+15*5, "Fog : %3i", Engine->DebugInfo.NumFog); +// geEngine_Printf(Engine, 2,2+15*7, "LMap1 : %3i, LMap2 : %3i", Engine->DebugInfo.LMap1, Engine->DebugInfo.LMap2); +/* + // For now, just display debug info for the first world... + if (Engine->NumWorlds) + { + geWorld_DebugInfo *Info; + + Info = &Engine->Worlds[0]->DebugInfo; + geEngine_Printf(Engine, 2, 2+15*8, "Nodes: %3i/%3i, Leafs: %3i/%3i, Userp: %3i/%3i", Info->NumNodesTraversed1, Info->NumNodesTraversed2, Info->NumLeafsHit1, Info->NumLeafsHit2, Info->NumLeafsWithUserPolys, Info->NumUserPolys); + geEngine_Printf(Engine, 2, 2+15*9, "Cast: %3i/%3i, GetC: %3i: %i", NumExactCast, NumBBoxCast, NumGetContents); + + memset(Info, 0, sizeof(*Info)); + + NumExactCast = 0; + NumBBoxCast = 0; + NumGetContents = 0; + + } +*/ + } + + // Do an engine frame + Engine_Tick(Engine); + + return GE_TRUE; +} + +//=================================================================================== +// Engine_Tick +//=================================================================================== +static void Engine_Tick(geEngine *Engine) +{ + int32 i; + + for (i=0; i< 20; i++) + { + if (Engine->WaveDir[i] == 1) + Engine->WaveTable[i] += 14; + else + Engine->WaveTable[i] -= 14; + if (Engine->WaveTable[i] < 50) + { + Engine->WaveTable[i] += 14; + Engine->WaveDir[i] = 1; + } + if (Engine->WaveTable[i] > 255) + { + Engine->WaveTable[i] -= 14; + Engine->WaveDir[i] = 0; + } + } +} + +//=================================================================================== +// Engine_DrawFontBuffer +//=================================================================================== +static void Engine_DrawFontBuffer(geEngine *Engine) +{ + geRect Rect; + int32 i, x, y, w, StrLength; + Sys_FontInfo *Fi; + char *Str; + int32 FontWidth,FontHeight; + + Fi = &Engine->FontInfo; + + if ( Fi->NumStrings == 0) + return; + + FontWidth = 8; + FontHeight = 15; + + for (i=0; i< Fi->NumStrings; i++) + { + x = Fi->ClientStrings[i].x; + y = Fi->ClientStrings[i].y; + Str = Fi->ClientStrings[i].String; + StrLength = strlen(Str); + + for (w=0; w< StrLength; w++) + { + /* + Rect.left = (Fi->FontLUT1[*Str]>>16)+1; + Rect.right = Rect.left+16; + Rect.top = (Fi->FontLUT1[*Str]&0xffff)+1; + Rect.bottom = Rect.top+16; + */ + Rect.Left = (Fi->FontLUT1[*Str]>>16); + Rect.Right = Rect.Left + FontWidth - 1; + Rect.Top = (Fi->FontLUT1[*Str]&0xffff); + Rect.Bottom = Rect.Top + FontHeight - 1; + + if ( ! geEngine_DrawBitmap(Engine, Fi->FontBitmap, &Rect, x, y) ) + { + geEngine_Printf(Engine, 10, 50, "Could not draw font...\n"); + geErrorLog_AddString(-1,"DrawFontBuffer : Could not draw font...\n", NULL); + } + //x+= 16; + x += FontWidth; + Str++; + } + } + + Fi->NumStrings = 0; +} + +static void SubLarge(LARGE_INTEGER *start, LARGE_INTEGER *end, LARGE_INTEGER *delta) +{ + _asm { + mov ebx,dword ptr [start] + mov esi,dword ptr [end] + + mov eax,dword ptr [esi+0] + sub eax,dword ptr [ebx+0] + + mov edx,dword ptr [esi+4] + sbb edx,dword ptr [ebx+4] + + mov ebx,dword ptr [delta] + mov dword ptr [ebx+0],eax + mov dword ptr [ebx+4],edx + } +} + + +//=================================================================================== +// geEngine_Puts +//=================================================================================== +geBoolean geEngine_Puts(geEngine *Engine, int32 x, int32 y, const char *String) +{ + Sys_FontInfo *Fi; + + Fi = &Engine->FontInfo; + + if (strlen(String) > MAX_CLIENT_STRING_LEN) + return GE_FALSE; + + if (Fi->NumStrings >= MAX_CLIENT_STRINGS) + return GE_FALSE; + + strcpy(Fi->ClientStrings[Fi->NumStrings].String, String); + + Fi->ClientStrings[Fi->NumStrings].x = x; + Fi->ClientStrings[Fi->NumStrings].y = y; + + Fi->NumStrings++; + + return TRUE; +} + +//======================================================================================== +// geEngine_Printf +//======================================================================================== +GENESISAPI geBoolean geEngine_Printf(geEngine *Engine, int32 x, int32 y, const char *String, ...) +{ + va_list ArgPtr; + char TempStr[1024]; + + va_start(ArgPtr, String); + vsprintf(TempStr, String, ArgPtr); + va_end(ArgPtr); + + return geEngine_Puts(Engine, x, y, TempStr); +} + + + +//======================================================================================== +//======================================================================================== +static BOOL Hack_EnumCallBack(const geRDriver_PixelFormat *Format, void *Context) +{ +geRDriver_PixelFormat ** pPixelArrayPtr; + pPixelArrayPtr = Context; +#if 0 + *(*pPixelArrayPtr)++ = *Format; +#else + **pPixelArrayPtr = *Format; + (*pPixelArrayPtr) += 1; +#endif +return 1; +} + +static geRDriver_PixelFormat * Hack_FindPixelFormat(geRDriver_PixelFormat * PixelFormats,int ArrayLen,uint32 Flags,geBoolean NeedsAlpha) +{ +int cnt; +geRDriver_PixelFormat * pf; + + for(cnt=ArrayLen,pf = PixelFormats;cnt--;pf++) + { + if ( ! NeedsAlpha || ( NeedsAlpha && (gePixelFormat_HasAlpha(pf->PixelFormat) || pf->Flags & RDRIVER_PF_HAS_ALPHA) ) ) + { + if( pf->Flags == Flags ) + { + return pf; + } + } + } + for(cnt=ArrayLen,pf = PixelFormats;cnt--;pf++) + { + if ( ! NeedsAlpha || ( NeedsAlpha && (gePixelFormat_HasAlpha(pf->PixelFormat) || pf->Flags & RDRIVER_PF_HAS_ALPHA) ) ) + { + if( pf->Flags & Flags ) + { + return pf; + } + } + } + + for(cnt=ArrayLen,pf = PixelFormats;cnt--;pf++) + { + if( pf->Flags == Flags ) + { + return pf; + } + } + for(cnt=ArrayLen,pf = PixelFormats;cnt--;pf++) + { + if( pf->Flags & Flags ) + { + return pf; + } + } + + return NULL; +} + +geBoolean Engine_SetupPixelFormats(geEngine *Engine) +{ + geRDriver_PixelFormat PixelFormatsArray[100],*PixelArrayPtr; + int PixelFormatsLen; + + PixelArrayPtr = PixelFormatsArray; + + Engine->DriverInfo.RDriver->EnumPixelFormats(Hack_EnumCallBack , &PixelArrayPtr); + + PixelFormatsLen = ((uint32)PixelArrayPtr - (uint32)PixelFormatsArray)/sizeof(geRDriver_PixelFormat); + assert(PixelFormatsLen > 0); + + #define SetupPF( type, flag, alpha ) \ + if ( PixelArrayPtr = Hack_FindPixelFormat(PixelFormatsArray,PixelFormatsLen,flag,alpha) ) \ + { \ + Engine->PixelFormats[type] = *PixelArrayPtr; \ + Engine->HasPixelFormat[type] = GE_TRUE; \ + } \ + else \ + { \ + Engine->HasPixelFormat[type] = GE_FALSE; \ + } + + SetupPF( ENGINE_PF_WORLD, RDRIVER_PF_COMBINE_LIGHTMAP,0); + SetupPF( ENGINE_PF_LIGHTMAP, RDRIVER_PF_LIGHTMAP,0); + SetupPF( ENGINE_PF_USER, RDRIVER_PF_3D,0); + SetupPF( ENGINE_PF_USER_ALPHA, RDRIVER_PF_3D,1); + SetupPF( ENGINE_PF_DECAL, RDRIVER_PF_2D,0); + SetupPF( ENGINE_PF_PALETTE, RDRIVER_PF_PALETTE,0); + SetupPF( ENGINE_PF_ALPHA_CHANNEL,RDRIVER_PF_ALPHA,0); + + return GE_TRUE; +} + +//===================================================================================== +// Engine_CreateTHandle +//===================================================================================== + +geRDriver_THandle * Engine_CreateTHandle(geEngine *Engine,int Width,int Height,int Mips, int EngineTexType) +{ +geRDriver_THandle * THandle; + + if ( ! Engine->HasPixelFormat[EngineTexType] ) + { + //{} assert( Engine->HasPixelFormat[EngineTexType] ); + return NULL; + } + + THandle = Engine->DriverInfo.RDriver->THandle_Create(Width,Height,Mips,&(Engine->PixelFormats[EngineTexType])); + + if (! THandle ) + return NULL; + + if ( gePixelFormat_HasPalette(Engine->PixelFormats[EngineTexType].PixelFormat) ) + { + geRDriver_THandle * PalHandle; + PalHandle = Engine->DriverInfo.RDriver->THandle_Create(256,1,1,&(Engine->PixelFormats[ENGINE_PF_PALETTE])); + if ( ! PalHandle ) + { + Engine->DriverInfo.RDriver->THandle_Destroy(THandle); + return NULL; + } + Engine->DriverInfo.RDriver->THandle_SetPalette(THandle,PalHandle); + + #ifdef _DEBUG + { + geRDriver_THandleInfo Info; + (Engine->DriverInfo.RDriver)->THandle_GetInfo(PalHandle,0,&Info); + assert(Info.Width == 256); + assert(Info.Height == 1); + } + #endif + } + + if ( (Engine->PixelFormats[EngineTexType].Flags) & RDRIVER_PF_HAS_ALPHA ) + { + geRDriver_THandle * AlphaHandle; + assert( Engine->PixelFormats[ENGINE_PF_ALPHA_CHANNEL].Flags & RDRIVER_PF_ALPHA ); + assert( ! (Engine->PixelFormats[ENGINE_PF_ALPHA_CHANNEL].Flags & RDRIVER_PF_HAS_ALPHA) ); + AlphaHandle = Engine_CreateTHandle(Engine,Width,Height,Mips,ENGINE_PF_ALPHA_CHANNEL); + if ( ! AlphaHandle ) + { + Engine->DriverInfo.RDriver->THandle_Destroy(THandle); + return NULL; + } + Engine->DriverInfo.RDriver->THandle_SetAlpha(THandle,AlphaHandle); + } + +return THandle; +} + +void Engine_DestroyTHandle(geEngine *Engine,geRDriver_THandle * THandle) +{ + Engine->DriverInfo.RDriver->THandle_Destroy(THandle); +} diff --git a/G3D/Engine/engine.h b/G3D/Engine/engine.h new file mode 100644 index 0000000..b70601b --- /dev/null +++ b/G3D/Engine/engine.h @@ -0,0 +1,124 @@ +/****************************************************************************************/ +/* Engine.h */ +/* */ +/* Author: Charles Bloom/John Pollard */ +/* Description: Maintains the driver interface, as well as the bitmaps attached */ +/* to the driver. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_ENGINE_H +#define GE_ENGINE_H + +#include "Genesis.h" +#include "System.h" +#include "world.h" +#include "bitmap.h" +#include "BitmapList.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------- +// fake out windows include +//------------------------------------------------- +#ifndef WINVER // if you want windows, you must include it first! +#ifdef STRICT +typedef struct HINSTANCE__ * HINSTANCE; +#else // STRICT +typedef void * HINSTANCE; +#endif // STRICT +#endif + +//------------------------------------------------- +// Engine Functions +//------------------------------------------------- + +//-------- engine world list funcs +GENESISAPI geBoolean geEngine_AddWorld(geEngine *Engine, geWorld *World); +GENESISAPI geBoolean geEngine_RemoveWorld(geEngine *Engine, geWorld *World); +geBoolean geEngine_RemoveAllWorlds(geEngine *Engine); +geBoolean geEngine_HasWorld(const geEngine *Engine, const geWorld *World); +void geEngine_SetAllWorldChangedFlag(geEngine *Engine, geBoolean Flag); + +//-------- engine attach/detach thandle funcs + +// call updategamma when drivers change +GENESISAPI geBoolean geEngine_SetGamma(geEngine *Engine, geFloat Gamma); +GENESISAPI geBoolean geEngine_GetGamma(geEngine *Engine, geFloat *Gamma); +GENESISAPI geBoolean geEngine_SetFogEnable(geEngine *Engine, geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End); +void geEngine_UpdateGamma(geEngine *Engine); + +geBoolean geEngine_BitmapListInit(geEngine *Engine); +geBoolean geEngine_BitmapListShutdown(geEngine *Engine); +geBoolean geEngine_DetachAllWorlds(geEngine *Engine); +geBoolean geEngine_CreateWorldLightmapTHandles(geEngine *Engine, geWorld *World); +geBoolean geEngine_DestroyWorldLightmapTHandles(geEngine *Engine, geWorld *World); +geBoolean geEngine_AttachAllWorlds(geEngine *Engine); +geBoolean geEngine_AttachAll(geEngine *Engine); +geBoolean geEngine_DetachAll(geEngine *Engine); + +//-------- the splash screen +geBoolean geEngine_DoSplashScreen(geEngine *Engine, geDriver_Mode *DriverMode); + +//-------- engine fonts +geBoolean geEngine_InitFonts(geEngine *Engine); +geBoolean geEngine_ShutdownFonts(geEngine *Engine); + +//-------- engine drivers +HINSTANCE geEngine_LoadLibrary( const char * lpLibFileName, const char *DriverDirectory); +geBoolean geEngine_ResetDriver(geEngine *Engine); +GENESISAPI geDriver_System *geEngine_GetDriverSystem(geEngine *Engine); + +GENESISAPI geBoolean geEngine_SetDriverAndMode( geEngine *Engine, + geDriver *Driver, + geDriver_Mode *DriverMode); + +//-------- drawing with the engine (Decals & Misc Polys) + +GENESISAPI geBoolean GENESISCC geEngine_DrawBitmap(const geEngine *Engine, + const geBitmap *Bitmap, + const geRect * Source, uint32 x, uint32 y); + +GENESISAPI geBoolean GENESISCC geEngine_DrawAlphaBitmap( + geEngine * Engine, + geBitmap * pBitmap, + geVec3d * VertUVArray, + geCamera * ClipCamera, // if null, uses full screen + GE_Rect * PixelRect, // pixels in the "camera" view + GE_Rect * PercentRect, // percent of the "camera" view + geFloat Alpha, + GE_RGBA * RGBA_Array + ); + +GENESISAPI void GENESISCC geEngine_RenderPoly(const geEngine *Engine, const GE_TLVertex *Points, + int NumPoints, const geBitmap *Texture, uint32 Flags); + +GENESISAPI void GENESISCC geEngine_RenderPolyArray(const geEngine *Engine, const GE_TLVertex ** pPoints, int * pNumPoints, int NumPolys, + const geBitmap *Texture, uint32 Flags); + +//-------- temporary pre-geBitmap hacks +geBoolean Engine_UploadBitmap(geEngine *Engine, DRV_Bitmap *Bitmap, DRV_Bitmap *ABitmap, geFloat Gamma); +geBoolean Engine_SetupPixelFormats(geEngine *Engine); +geRDriver_THandle * Engine_CreateTHandle(geEngine *Engine,int Width,int Height,int Mips, int EngineTexType); +void Engine_DestroyTHandle(geEngine *Engine,geRDriver_THandle * THandle); + +#ifdef __cplusplus +} +#endif + +#endif // GE_ENGINE_H diff --git a/G3D/Engine/fontbmp.c b/G3D/Engine/fontbmp.c new file mode 100644 index 0000000..2681c79 --- /dev/null +++ b/G3D/Engine/fontbmp.c @@ -0,0 +1,849 @@ +/****************************************************************************************/ +/* FONTBMP.C */ +/* */ +/* Author: */ +/* Description: Binary image of a font bitmap. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +unsigned char font_bmp[] = { +66, 77, 0, 0, 0, 0, 0, 0, 0, 0, 54, 4, 0, 0, 40, 0, 0, 0, 0, 4, +0, 0, 14, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, +0, 0, 128, 0, 0, 0, 255, 0, 0, 0, 0, 32, 0, 0, 64, 32, 0, 0, 128, 32, +0, 0, 255, 32, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 128, 64, 0, 0, 255, 64, +0, 0, 0, 96, 0, 0, 64, 96, 0, 0, 128, 96, 0, 0, 255, 96, 0, 0, 0, 128, +0, 0, 64, 128, 0, 0, 128, 128, 0, 0, 255, 128, 0, 0, 0, 160, 0, 0, 64, 160, +0, 0, 128, 160, 0, 0, 255, 160, 0, 0, 0, 192, 0, 0, 64, 192, 0, 0, 128, 192, +0, 0, 255, 192, 0, 0, 0, 255, 0, 0, 64, 255, 0, 0, 128, 255, 0, 0, 255, 255, +0, 0, 0, 0, 32, 0, 64, 0, 32, 0, 128, 0, 32, 0, 255, 0, 32, 0, 0, 32, +32, 0, 64, 32, 32, 0, 128, 32, 32, 0, 255, 32, 32, 0, 0, 64, 32, 0, 64, 64, +32, 0, 128, 64, 32, 0, 255, 64, 32, 0, 0, 96, 32, 0, 64, 96, 32, 0, 128, 96, +32, 0, 255, 96, 32, 0, 0, 128, 32, 0, 64, 128, 32, 0, 128, 128, 32, 0, 255, 128, +32, 0, 0, 160, 32, 0, 64, 160, 32, 0, 128, 160, 32, 0, 255, 160, 32, 0, 0, 192, +32, 0, 64, 192, 32, 0, 128, 192, 32, 0, 255, 192, 32, 0, 0, 255, 32, 0, 64, 255, +32, 0, 128, 255, 32, 0, 255, 255, 32, 0, 0, 0, 64, 0, 64, 0, 64, 0, 128, 0, +64, 0, 255, 0, 64, 0, 0, 32, 64, 0, 64, 32, 64, 0, 128, 32, 64, 0, 255, 32, +64, 0, 0, 64, 64, 0, 64, 64, 64, 0, 128, 64, 64, 0, 255, 64, 64, 0, 0, 96, +64, 0, 64, 96, 64, 0, 128, 96, 64, 0, 255, 96, 64, 0, 0, 128, 64, 0, 64, 128, +64, 0, 128, 128, 64, 0, 255, 128, 64, 0, 0, 160, 64, 0, 64, 160, 64, 0, 128, 160, +64, 0, 255, 160, 64, 0, 0, 192, 64, 0, 64, 192, 64, 0, 128, 192, 64, 0, 255, 192, +64, 0, 0, 255, 64, 0, 64, 255, 64, 0, 128, 255, 64, 0, 255, 255, 64, 0, 0, 0, +96, 0, 64, 0, 96, 0, 128, 0, 96, 0, 255, 0, 96, 0, 0, 32, 96, 0, 64, 32, +96, 0, 128, 32, 96, 0, 255, 32, 96, 0, 0, 64, 96, 0, 64, 64, 96, 0, 128, 64, +96, 0, 255, 64, 96, 0, 0, 96, 96, 0, 64, 96, 96, 0, 128, 96, 96, 0, 255, 96, +96, 0, 0, 128, 96, 0, 64, 128, 96, 0, 128, 128, 96, 0, 255, 128, 96, 0, 0, 160, +96, 0, 64, 160, 96, 0, 128, 160, 96, 0, 255, 160, 96, 0, 0, 192, 96, 0, 64, 192, +96, 0, 128, 192, 96, 0, 255, 192, 96, 0, 0, 255, 96, 0, 64, 255, 96, 0, 128, 255, +96, 0, 255, 255, 96, 0, 0, 0, 128, 0, 64, 0, 128, 0, 128, 0, 128, 0, 255, 0, +128, 0, 0, 32, 128, 0, 64, 32, 128, 0, 128, 32, 128, 0, 255, 32, 128, 0, 0, 64, +128, 0, 64, 64, 128, 0, 128, 64, 128, 0, 255, 64, 128, 0, 0, 96, 128, 0, 64, 96, +128, 0, 128, 96, 128, 0, 255, 96, 128, 0, 0, 128, 128, 0, 64, 128, 128, 0, 128, 128, +128, 0, 255, 128, 128, 0, 0, 160, 128, 0, 64, 160, 128, 0, 128, 160, 128, 0, 255, 160, +128, 0, 0, 192, 128, 0, 64, 192, 128, 0, 128, 192, 128, 0, 255, 192, 128, 0, 0, 255, +128, 0, 64, 255, 128, 0, 128, 255, 128, 0, 255, 255, 128, 0, 0, 0, 160, 0, 64, 0, +160, 0, 128, 0, 160, 0, 255, 0, 160, 0, 0, 32, 160, 0, 64, 32, 160, 0, 128, 32, +160, 0, 255, 32, 160, 0, 0, 64, 160, 0, 64, 64, 160, 0, 128, 64, 160, 0, 255, 64, +160, 0, 0, 96, 160, 0, 64, 96, 160, 0, 128, 96, 160, 0, 255, 96, 160, 0, 0, 128, +160, 0, 64, 128, 160, 0, 128, 128, 160, 0, 255, 128, 160, 0, 0, 160, 160, 0, 64, 160, +160, 0, 128, 160, 160, 0, 255, 160, 160, 0, 0, 192, 160, 0, 64, 192, 160, 0, 128, 192, +160, 0, 255, 192, 160, 0, 0, 255, 160, 0, 64, 255, 160, 0, 128, 255, 160, 0, 255, 255, +160, 0, 0, 0, 192, 0, 64, 0, 192, 0, 128, 0, 192, 0, 255, 0, 192, 0, 0, 32, +192, 0, 64, 32, 192, 0, 128, 32, 192, 0, 255, 32, 192, 0, 0, 64, 192, 0, 64, 64, +192, 0, 128, 64, 192, 0, 255, 64, 192, 0, 0, 96, 192, 0, 64, 96, 192, 0, 128, 96, +192, 0, 255, 96, 192, 0, 0, 128, 192, 0, 64, 128, 192, 0, 128, 128, 192, 0, 255, 128, +192, 0, 0, 160, 192, 0, 64, 160, 192, 0, 128, 160, 192, 0, 255, 160, 192, 0, 0, 192, +192, 0, 64, 192, 192, 0, 128, 192, 192, 0, 255, 192, 192, 0, 0, 255, 192, 0, 64, 255, +192, 0, 128, 255, 192, 0, 255, 255, 192, 0, 0, 0, 255, 0, 64, 0, 255, 0, 128, 0, +255, 0, 255, 0, 255, 0, 0, 32, 255, 0, 64, 32, 255, 0, 128, 32, 255, 0, 255, 32, +255, 0, 0, 64, 255, 0, 64, 64, 255, 0, 128, 64, 255, 0, 255, 64, 255, 0, 0, 96, +255, 0, 64, 96, 255, 0, 128, 96, 255, 0, 255, 96, 255, 0, 0, 128, 255, 0, 64, 128, +255, 0, 128, 128, 255, 0, 255, 128, 255, 0, 0, 160, 255, 0, 64, 160, 255, 0, 128, 160, +255, 0, 255, 160, 255, 0, 0, 192, 255, 0, 64, 192, 255, 0, 128, 192, 255, 0, 255, 192, +255, 0, 0, 255, 255, 0, 64, 255, 255, 0, 128, 255, 255, 0, 255, 255, 255, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 147, 147, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 71, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, +71, 0, 0, 0, 0, 0, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 71, 71, 0, 0, 0, +0, 0, 0, 0, 0, 0, 147, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 71, 71, 0, 0, 0, 0, 147, +147, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, +0, 147, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 71, 71, 0, 0, 147, 147, +71, 0, 0, 0, 0, 0, 0, 0, 0, 71, 71, 71, 71, 0, 0, 0, 0, 0, 71, 71, +0, 0, 0, 71, 71, 71, 71, 71, 71, 0, 0, 0, 71, 71, 71, 71, 0, 0, 0, 0, +0, 0, 0, 71, 71, 0, 0, 71, 71, 71, 71, 0, 0, 0, 0, 0, 71, 71, 71, 71, +0, 0, 0, 0, 71, 71, 0, 0, 0, 0, 0, 0, 71, 71, 71, 71, 0, 0, 0, 0, +71, 71, 71, 0, 0, 0, 0, 0, 0, 71, 71, 71, 0, 0, 0, 0, 0, 147, 147, 71, +0, 0, 0, 0, 0, 0, 0, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, +71, 0, 0, 0, 0, 0, 0, 0, 0, 71, 71, 0, 0, 0, 0, 71, 71, 71, 71, 71, +71, 71, 0, 71, 71, 0, 0, 71, 71, 0, 0, 71, 71, 71, 71, 0, 0, 0, 0, 0, +71, 71, 71, 0, 0, 0, 0, 71, 71, 71, 0, 0, 0, 0, 0, 71, 71, 71, 71, 71, +71, 0, 0, 71, 71, 0, 0, 0, 0, 0, 0, 0, 71, 71, 71, 71, 71, 0, 0, 71, +71, 0, 0, 71, 71, 0, 0, 0, 71, 71, 71, 71, 0, 0, 0, 0, 71, 71, 71, 0, +0, 0, 0, 71, 71, 0, 0, 71, 71, 0, 0, 71, 71, 71, 71, 71, 71, 0, 0, 71, +71, 0, 0, 0, 71, 71, 0, 71, 71, 0, 0, 0, 71, 71, 0, 0, 71, 71, 71, 0, +0, 0, 0, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 71, +71, 0, 0, 71, 71, 0, 0, 0, 71, 71, 71, 0, 0, 0, 0, 0, 0, 71, 71, 0, +0, 0, 0, 0, 71, 71, 71, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, +71, 71, 0, 71, 0, 0, 0, 71, 71, 0, 0, 71, 71, 0, 0, 0, 0, 71, 71, 0, +0, 0, 0, 71, 71, 71, 71, 71, 71, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, +0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +71, 71, 71, 71, 71, 0, 0, 71, 71, 71, 71, 71, 0, 0, 0, 0, 71, 71, 71, 71, +0, 0, 0, 0, 71, 71, 71, 71, 71, 0, 0, 0, 71, 71, 71, 71, 0, 0, 0, 0, +71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 71, 71, 0, 71, 71, +71, 0, 0, 71, 71, 71, 71, 71, 71, 0, 0, 0, 0, 147, 71, 71, 0, 0, 0, 71, +71, 0, 0, 71, 0, 0, 0, 71, 71, 71, 71, 71, 71, 0, 0, 71, 71, 0, 0, 0, +71, 71, 0, 71, 71, 0, 0, 71, 71, 0, 0, 0, 71, 71, 71, 71, 0, 0, 147, 147, +71, 71, 71, 71, 0, 0, 0, 0, 71, 71, 147, 147, 71, 0, 0, 71, 71, 0, 0, 0, +0, 0, 0, 71, 71, 71, 71, 71, 0, 0, 0, 0, 0, 71, 71, 71, 71, 0, 0, 0, +71, 71, 71, 71, 71, 0, 0, 0, 0, 71, 71, 0, 0, 0, 0, 0, 71, 71, 0, 71, +71, 0, 0, 71, 71, 0, 0, 71, 71, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 71, +71, 71, 71, 71, 71, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 147, 147, 71, 0, +0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 111, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 0, 147, 147, 147, 147, 0, +0, 0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 147, 147, 147, 0, 147, 147, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +147, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 147, 71, +0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, 71, 71, 0, 0, +0, 147, 147, 71, 0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 71, +71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, 147, 147, 71, 71, 0, 0, 0, 147, +147, 147, 147, 71, 71, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 147, 147, 71, +71, 0, 0, 147, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 147, 71, 0, 0, 0, 0, +147, 147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, +147, 147, 147, 147, 147, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 147, 147, 147, 71, +0, 0, 0, 147, 147, 147, 147, 71, 0, 0, 147, 147, 147, 147, 71, 0, 0, 0, 147, 147, +147, 147, 147, 147, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 147, +147, 147, 147, 71, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 147, 147, 147, 147, +0, 0, 147, 147, 71, 0, 0, 147, 147, 71, 147, 147, 71, 0, 0, 147, 147, 71, 0, 147, +147, 147, 147, 71, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, 71, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 147, 147, 71, 0, 0, 0, 0, +147, 147, 71, 0, 0, 0, 0, 147, 147, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 0, +0, 0, 0, 147, 147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, +147, 147, 71, 0, 0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 147, 147, 71, 0, 0, +0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 147, 147, 147, 147, 147, 71, 0, 147, 147, 147, 147, 147, 71, 71, 0, 0, 147, +147, 147, 147, 71, 71, 0, 0, 147, 147, 147, 147, 147, 71, 0, 0, 147, 147, 147, 147, 0, +0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 147, 147, 147, 71, 0, 147, 147, +71, 0, 147, 71, 71, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 0, 0, 147, 147, 71, +0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 147, 147, 147, 147, 0, 0, 147, 147, +71, 0, 71, 147, 147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 147, 147, 71, +71, 0, 147, 147, 147, 147, 147, 71, 71, 0, 0, 147, 147, 147, 147, 147, 71, 0, 147, 147, +71, 0, 0, 0, 0, 0, 147, 147, 147, 147, 147, 71, 71, 0, 0, 0, 147, 147, 147, 147, +0, 0, 0, 147, 147, 147, 147, 147, 71, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 147, +147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 147, 147, 71, +71, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, +147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 111, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 147, 147, +0, 0, 147, 147, 0, 0, 147, 0, 147, 147, 0, 147, 147, 0, 147, 147, 0, 0, 147, 147, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, +0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +147, 147, 147, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 71, 147, +147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 147, 147, 71, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 147, 147, 147, 0, +0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 147, 147, 0, 0, +0, 147, 147, 71, 0, 0, 71, 71, 71, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 147, 147, 71, +0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, +0, 0, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 0, 0, 147, 147, +71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, 147, 71, 147, 147, 71, 0, 0, 147, +147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 0, 0, 147, 147, +71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, +147, 147, 147, 71, 0, 0, 0, 147, 147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 147, +147, 71, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, +0, 147, 147, 71, 0, 0, 147, 147, 71, 0, 147, 147, 0, 0, 0, 0, 147, 147, 71, 0, +0, 0, 147, 147, 71, 147, 71, 147, 147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, +147, 71, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 147, 147, 71, +71, 0, 0, 147, 147, 71, 147, 147, 71, 71, 147, 147, 71, 0, 147, 147, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, +0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 0, 147, 147, 0, 147, 147, +0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, 147, 147, +147, 0, 0, 0, 0, 0, 147, 147, 0, 0, 147, 147, 0, 147, 147, 147, 0, 0, 147, 147, +0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, +0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 0, 0, +147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 147, +147, 147, 71, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 71, 0, +0, 0, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, 147, 147, 147, 147, 147, 0, 0, 0, +0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 71, 71, 0, +0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, +0, 0, 0, 71, 71, 71, 71, 71, 71, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, +0, 71, 71, 0, 0, 147, 147, 71, 0, 147, 147, 147, 147, 71, 147, 147, 71, 71, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, +0, 0, 147, 147, 71, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, +147, 147, 71, 0, 0, 0, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, 71, 147, 147, 71, +0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 71, 71, 147, 147, 71, 147, 147, +71, 0, 71, 147, 147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, +0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 0, 0, 0, 0, +0, 0, 147, 147, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 71, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, +0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, +0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 71, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 71, 71, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, +0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, 147, 71, 147, 147, 0, 0, 0, 0, 0, +147, 147, 71, 0, 0, 0, 147, 147, 71, 147, 71, 147, 147, 71, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, +0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 147, 71, 147, 147, 71, 0, 147, 147, 147, 147, 0, +0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 147, +147, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, +71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 0, 0, +147, 147, 147, 0, 0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, +147, 0, 147, 147, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 147, 147, 0, 0, 0, +0, 0, 147, 147, 0, 147, 147, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, +147, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 147, 147, 147, 0, +0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, +0, 0, 0, 147, 147, 147, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, +147, 147, 71, 0, 0, 0, 0, 0, 0, 71, 147, 147, 71, 0, 147, 147, 71, 71, 147, 147, +71, 0, 0, 0, 0, 0, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, +147, 147, 71, 0, 0, 0, 147, 147, 71, 147, 147, 147, 71, 0, 0, 147, 147, 147, 147, 147, +71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, +147, 0, 0, 0, 0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 0, 0, 147, 147, 71, +71, 0, 0, 0, 147, 147, 71, 0, 0, 147, 147, 71, 147, 147, 0, 147, 147, 71, 147, 147, +147, 147, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, +0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 71, 71, 71, 0, 0, 147, 147, +71, 71, 71, 71, 0, 0, 147, 147, 71, 147, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, +71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, +71, 147, 147, 71, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 147, 71, 147, +147, 71, 147, 147, 71, 71, 147, 147, 147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 71, 71, 0, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 147, 147, 71, +0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 147, 71, 147, +147, 71, 0, 147, 71, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, +147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, +0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 147, 147, 147, 71, 71, 0, 0, 147, 147, 71, 71, 71, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, +147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, 147, 147, 147, 71, 71, +0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 147, 71, 147, 147, 71, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 147, +147, 147, 147, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 147, 71, 147, 147, 71, 0, 0, +147, 147, 71, 71, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 71, +0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, +0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, +255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, +255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, +255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, +255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, +255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, +255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, +255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, +255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, +255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, +255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, +255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 147, 147, 147, 147, 147, 147, +147, 0, 147, 147, 147, 147, 147, 147, 147, 0, 147, 147, 147, 147, 147, 147, 147, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, +147, 147, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 147, 147, +147, 147, 147, 147, 147, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +147, 147, 71, 71, 0, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, +0, 0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 147, 147, 147, 71, 71, 0, 0, 147, +147, 71, 147, 147, 71, 0, 147, 147, 147, 147, 147, 0, 0, 0, 147, 147, 71, 71, 147, 147, +0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 147, 147, 147, 147, 71, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 0, 0, 71, 71, 71, 0, 0, 0, 0, 0, 71, 71, 71, +0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 71, 71, 71, 71, 71, 71, 0, 0, 0, +0, 0, 147, 147, 0, 0, 0, 0, 147, 147, 71, 71, 0, 147, 147, 71, 147, 147, 0, 147, +147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 147, 147, 147, 71, 0, 0, 147, 147, +71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 147, 147, 147, 0, +0, 0, 147, 147, 147, 147, 147, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, +147, 147, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 147, 147, +71, 0, 147, 147, 147, 147, 71, 71, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, +71, 147, 71, 147, 147, 71, 147, 147, 71, 147, 147, 147, 147, 71, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 147, 147, 147, 71, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +147, 147, 147, 71, 71, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, +0, 0, 147, 71, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 147, 71, 147, 147, 71, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, 147, 147, 71, +0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, +147, 147, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 71, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +147, 147, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, 147, +71, 147, 147, 71, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 147, 71, 147, +147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 147, 71, 71, 71, +71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 147, 71, 147, +147, 71, 0, 147, 147, 147, 147, 71, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, +0, 147, 147, 71, 71, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, +0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, +0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, +147, 147, 147, 0, 0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 0, 0, 147, 147, 147, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 0, 147, 147, 0, 0, 0, +0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, +0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 147, 147, 147, 71, 0, 71, +71, 147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 71, 71, 0, 147, 147, +71, 0, 0, 147, 147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, +147, 147, 147, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, 147, 147, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 147, 71, 0, 0, 0, 0, +147, 147, 147, 71, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 147, 147, 147, 147, 147, 147, +0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 71, 71, 147, 147, 71, 71, 147, 147, 71, +0, 147, 147, 147, 147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 71, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 71, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, +0, 0, 147, 147, 71, 0, 147, 147, 71, 147, 147, 71, 0, 0, 147, 147, 71, 0, 0, 0, +0, 0, 147, 147, 71, 147, 71, 147, 147, 71, 147, 147, 147, 147, 0, 147, 147, 71, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, +147, 147, 71, 0, 0, 0, 147, 71, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 147, 0, 147, 147, 71, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, +0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 71, 71, 147, 147, 0, 0, 147, 147, 71, 71, 147, 147, 0, 0, 147, 147, +71, 71, 147, 147, 0, 0, 147, 147, 71, 71, 147, 147, 71, 0, 147, 147, 71, 71, 147, 147, +0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, 71, 71, 147, 147, 71, 0, 147, 147, +71, 71, 147, 147, 0, 0, 0, 71, 147, 147, 71, 0, 0, 0, 0, 0, 71, 147, 147, 71, +0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, +71, 147, 71, 147, 147, 0, 147, 147, 71, 71, 147, 147, 0, 0, 147, 147, 71, 71, 147, 147, +0, 0, 147, 147, 71, 71, 147, 147, 0, 0, 147, 147, 71, 71, 147, 147, 71, 0, 147, 147, +71, 147, 147, 147, 71, 0, 147, 147, 71, 71, 71, 71, 71, 0, 0, 147, 147, 71, 71, 71, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 147, 0, 147, 147, 71, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, +147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 71, 0, 0, 0, 71, 71, +71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, +255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 255, +0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 0, 147, +147, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, 0, +0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 147, 147, 147, 147, 147, 147, 147, 0, 147, 147, +0, 0, 0, 0, 0, 0, 147, 147, 147, 0, 147, 147, 0, 0, 147, 147, 0, 147, 147, 0, +0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, +147, 147, 0, 0, 0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 0, 0, 147, 147, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 147, 147, 71, 147, 147, +147, 71, 147, 147, 147, 147, 147, 71, 0, 0, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 147, 147, 71, 147, 147, 0, 0, 147, 147, 71, 0, 0, 0, +0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 147, 0, +0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, +71, 147, 147, 71, 0, 0, 0, 147, 147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 147, 147, 71, 0, +0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, 71, 147, 147, 71, 0, 0, 147, 147, +71, 0, 0, 0, 0, 0, 147, 147, 147, 0, 147, 147, 147, 71, 147, 147, 147, 0, 0, 147, +147, 71, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 71, +71, 0, 0, 0, 147, 147, 71, 0, 0, 0, 147, 71, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 71, 0, 147, 147, 71, 147, 71, +0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, +147, 71, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 147, 0, +0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 147, 147, 147, 147, 147, 71, 0, 0, 147, +147, 147, 147, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 147, 147, 147, +0, 0, 147, 147, 147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 0, 147, +147, 147, 147, 0, 0, 0, 147, 147, 71, 0, 147, 147, 0, 0, 0, 0, 147, 147, 71, 0, +0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 147, 147, 147, 147, 147, 0, 0, 0, 0, 147, +147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 147, 0, 0, 0, 0, 147, 147, 147, 147, 147, +0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 0, 147, 147, 147, 147, 147, 0, 0, 147, 147, +147, 147, 147, 147, 0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 147, 147, +0, 0, 147, 147, 0, 0, 0, 147, 147, 0, 147, 147, 0, 0, 147, 147, 0, 0, 147, 147, +0, 0, 147, 147, 0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 0, 147, 147, 71, 0, +0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, 71, 71, +0, 147, 147, 147, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, +147, 147, 147, 0, 0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 0, 147, 147, 0, 147, 147, +0, 0, 147, 147, 0, 0, 147, 147, 0, 147, 147, 0, 147, 147, 0, 147, 0, 0, 147, 147, +0, 147, 147, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, +0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, +147, 71, 0, 147, 147, 0, 0, 0, 147, 147, 147, 71, 0, 0, 147, 147, 0, 0, 147, 147, +0, 0, 147, 147, 71, 71, 147, 147, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 147, 147, +71, 71, 71, 71, 71, 0, 0, 0, 147, 147, 71, 71, 0, 0, 0, 71, 71, 71, 147, 147, +71, 0, 147, 147, 71, 71, 147, 147, 0, 0, 147, 147, 71, 71, 147, 147, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, +71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 147, 147, +71, 71, 147, 147, 71, 147, 147, 71, 71, 71, 71, 147, 147, 0, 0, 147, 147, 147, 147, 71, +0, 0, 147, 147, 71, 71, 147, 147, 0, 0, 147, 147, 71, 71, 147, 147, 0, 0, 147, 147, +71, 147, 147, 71, 0, 0, 147, 147, 71, 71, 71, 71, 71, 0, 147, 147, 71, 71, 71, 71, +71, 0, 147, 147, 71, 71, 147, 147, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, +147, 147, 71, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, 147, 71, 147, 147, +0, 0, 0, 147, 147, 71, 147, 147, 71, 0, 147, 147, 0, 0, 147, 147, 71, 71, 147, 147, +0, 0, 147, 147, 71, 71, 147, 147, 0, 0, 147, 147, 71, 71, 147, 147, 0, 0, 147, 147, +71, 71, 147, 147, 0, 0, 0, 0, 147, 147, 71, 71, 71, 0, 147, 147, 71, 0, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 147, 147, 71, 147, 147, +71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, +71, 0, 0, 147, 147, 71, 71, 71, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, +0, 147, 147, 71, 0, 0, 0, 71, 71, 0, 0, 71, 71, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, +71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, +71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 71, 71, 71, 0, 0, 0, +0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 71, 71, 0, +0, 0, 0, 0, 0, 0, 71, 71, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 71, +147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +147, 147, 71, 71, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, 147, 147, 0, 0, +0, 147, 147, 71, 147, 147, 0, 147, 147, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 0, 147, +147, 0, 147, 147, 0, 0, 0, 147, 147, 147, 147, 0, 0, 147, 147, 0, 147, 147, 0, 0, +0, 0, 0, 147, 147, 147, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, +0, 147, 147, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, +0, 0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 147, +147, 147, 147, 0, 0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 147, 147, 0, 0, 0, +0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 147, 147, +147, 147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 147, 147, 147, 147, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, +0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 0, 0, +147, 147, 0, 0, 0, 0, 147, 147, 147, 147, 147, 0, 0, 0, 0, 147, 147, 147, 147, 0, +0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 147, 147, +147, 147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 147, 147, 0, 0, 147, 147, +0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 147, 147, +0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 147, +147, 0, 147, 147, 0, 0, 0, 147, 147, 0, 0, 147, 147, 147, 147, 0, 0, 0, 147, 147, +147, 147, 147, 0, 0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 147, 0, +0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 147, 147, +0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 147, 147, 0, 0, 0, 147, +147, 0, 147, 147, 0, 0, 147, 147, 0, 0, 147, 147, 71, 0, 147, 71, 0, 0, 147, 147, +147, 147, 147, 147, 0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 147, 147, 0, 0, 0, 0, +0, 0, 0, 147, 147, 147, 147, 0, 0, 0, 147, 147, 71, 71, 147, 147, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, +147, 147, 71, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 147, 147, 0, 0, 0, 0, +0, 0, 147, 147, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 147, +147, 0, 0, 0, 0, 0, 147, 147, 147, 0, 0, 0, 147, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 147, 147, +147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 147, 147, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 71, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +147, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 147, 147, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +}; + +int font_bmp_length = sizeof(font_bmp); + diff --git a/G3D/Engine/genesis3d.c b/G3D/Engine/genesis3d.c new file mode 100644 index 0000000..d695a38 --- /dev/null +++ b/G3D/Engine/genesis3d.c @@ -0,0 +1,12588 @@ +/****************************************************************************************/ +/* Genesis3d.c */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +unsigned char genesis3d_act[] = { +86, 70, 48, 48, 0, 0, 69, 0, 0, 0, 0, 0, 188, 212, 3, 0, 188, 212, 3, 0, +147, 213, 3, 0, 65, 67, 84, 82, 241, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, +86, 70, 48, 48, 0, 0, 69, 0, 0, 0, 0, 0, 137, 210, 3, 0, 137, 210, 3, 0, +95, 211, 3, 0, 66, 79, 68, 94, 241, 0, 0, 0, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 198, 6, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 10, 215, 35, 60, 0, 0, 0, 0, 1, 233, +0, 0, 170, 124, 99, 191, 45, 210, 12, 191, 247, 5, 157, 65, 0, 0, 0, 128, 16, 215, +35, 61, 1, 233, 0, 0, 229, 9, 80, 191, 151, 60, 46, 191, 181, 247, 156, 65, 10, 215, +163, 60, 16, 215, 35, 61, 1, 233, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 143, 194, 245, 60, 0, 0, 0, 0, 1, 233, 0, 0, 181, 140, 56, 191, 115, 244, +76, 191, 150, 234, 156, 65, 10, 215, 35, 61, 16, 215, 35, 61, 1, 233, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 205, 204, 76, 61, 0, 0, 0, 0, 1, 233, +0, 0, 237, 99, 29, 191, 162, 125, 104, 191, 205, 222, 156, 65, 143, 194, 117, 61, 16, 215, +35, 61, 1, 233, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 41, 92, +143, 61, 0, 0, 0, 0, 1, 233, 0, 0, 102, 250, 253, 190, 135, 52, 128, 191, 140, 212, +156, 65, 10, 215, 163, 61, 16, 215, 35, 61, 1, 233, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 236, 81, 184, 61, 0, 0, 0, 0, 1, 234, 0, 0, 139, 166, +187, 190, 15, 43, 138, 191, 250, 203, 156, 65, 205, 204, 204, 61, 16, 215, 35, 61, 1, 234, +0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 174, 71, 225, 61, 0, 0, +0, 0, 1, 234, 0, 0, 37, 176, 105, 190, 43, 250, 145, 191, 59, 197, 156, 65, 143, 194, +245, 61, 16, 215, 35, 61, 1, 234, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 184, 30, 5, 62, 0, 0, 0, 0, 1, 234, 0, 0, 104, 179, 170, 189, 94, 130, +151, 191, 107, 192, 156, 65, 41, 92, 15, 62, 16, 215, 35, 61, 1, 234, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 154, 153, 25, 62, 0, 0, 0, 0, 1, 234, +0, 0, 123, 190, 134, 61, 71, 173, 154, 191, 155, 189, 156, 65, 10, 215, 35, 62, 16, 215, +35, 61, 1, 234, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 123, 20, +46, 62, 0, 0, 0, 0, 1, 234, 0, 0, 98, 18, 94, 62, 38, 110, 155, 191, 216, 188, +156, 65, 236, 81, 56, 62, 16, 215, 35, 61, 1, 234, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 92, 143, 66, 62, 0, 0, 0, 0, 1, 235, 0, 0, 133, 39, +188, 62, 240, 193, 153, 191, 38, 190, 156, 65, 205, 204, 76, 62, 16, 215, 35, 61, 1, 235, +0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 61, 10, 87, 62, 0, 0, +0, 0, 1, 235, 0, 0, 150, 233, 3, 63, 92, 175, 149, 191, 125, 193, 156, 65, 174, 71, +97, 62, 16, 215, 35, 61, 1, 235, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 31, 133, 107, 62, 0, 0, 0, 0, 1, 235, 0, 0, 80, 109, 40, 63, 229, 70, +143, 191, 210, 198, 156, 65, 143, 194, 117, 62, 16, 215, 35, 61, 1, 235, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 0, 0, 128, 62, 0, 0, 0, 0, 1, 235, +0, 0, 158, 11, 75, 63, 102, 162, 134, 191, 15, 206, 156, 65, 184, 30, 133, 62, 16, 215, +35, 61, 1, 235, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 113, 61, +138, 62, 0, 0, 0, 0, 1, 235, 0, 0, 180, 56, 107, 63, 138, 201, 119, 191, 21, 215, +156, 65, 41, 92, 143, 62, 16, 215, 35, 61, 1, 235, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 225, 122, 148, 62, 0, 0, 0, 0, 1, 236, 0, 0, 80, 57, +132, 63, 185, 114, 94, 191, 194, 225, 156, 65, 154, 153, 153, 62, 16, 215, 35, 61, 1, 236, +0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 82, 184, 158, 62, 0, 0, +0, 0, 1, 236, 0, 0, 180, 33, 145, 63, 164, 166, 65, 191, 233, 237, 156, 65, 10, 215, +163, 62, 16, 215, 35, 61, 1, 236, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 195, 245, 168, 62, 0, 0, 0, 0, 1, 236, 0, 0, 108, 33, 156, 63, 144, 217, +33, 191, 90, 251, 156, 65, 123, 20, 174, 62, 16, 215, 35, 61, 1, 236, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 51, 51, 179, 62, 0, 0, 0, 0, 1, 236, +0, 0, 11, 12, 165, 63, 223, 23, 255, 190, 223, 9, 157, 65, 236, 81, 184, 62, 16, 215, +35, 61, 1, 236, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 164, 112, +189, 62, 0, 0, 0, 0, 1, 236, 0, 0, 148, 189, 171, 63, 88, 144, 182, 190, 60, 25, +157, 65, 92, 143, 194, 62, 16, 215, 35, 61, 1, 236, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 20, 174, 199, 62, 0, 0, 0, 0, 1, 236, 0, 0, 0, 27, +176, 63, 249, 130, 86, 190, 53, 41, 157, 65, 205, 204, 204, 62, 16, 215, 35, 61, 1, 236, +0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 133, 235, 209, 62, 0, 0, +0, 0, 1, 237, 0, 0, 182, 18, 178, 63, 6, 217, 114, 189, 135, 57, 157, 65, 61, 10, +215, 62, 16, 215, 35, 61, 1, 237, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 246, 40, 220, 62, 0, 0, 0, 0, 1, 237, 0, 0, 183, 156, 177, 63, 217, 175, +187, 61, 242, 73, 157, 65, 174, 71, 225, 62, 16, 215, 35, 61, 1, 237, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 102, 102, 230, 62, 0, 0, 0, 0, 1, 237, +0, 0, 241, 186, 174, 63, 237, 183, 118, 62, 52, 90, 157, 65, 31, 133, 235, 62, 16, 215, +35, 61, 1, 237, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 215, 163, +240, 62, 0, 0, 0, 0, 1, 237, 0, 0, 247, 120, 169, 63, 51, 192, 197, 62, 9, 106, +157, 65, 143, 194, 245, 62, 16, 215, 35, 61, 1, 237, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 72, 225, 250, 62, 0, 0, 0, 0, 1, 237, 0, 0, 11, 236, +161, 63, 66, 118, 6, 63, 52, 121, 157, 65, 0, 0, 0, 63, 16, 215, 35, 61, 1, 237, +0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 92, 143, 2, 63, 0, 0, +0, 0, 1, 238, 0, 0, 169, 50, 152, 63, 172, 224, 39, 63, 118, 135, 157, 65, 184, 30, +5, 63, 16, 215, 35, 61, 1, 238, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 20, 174, 7, 63, 0, 0, 0, 0, 1, 238, 0, 0, 16, 116, 140, 63, 137, 152, +70, 63, 149, 148, 157, 65, 113, 61, 10, 63, 16, 215, 35, 61, 1, 238, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 205, 204, 12, 63, 0, 0, 0, 0, 1, 238, +0, 0, 89, 191, 125, 63, 184, 33, 98, 63, 94, 160, 157, 65, 41, 92, 15, 63, 16, 215, +35, 61, 1, 238, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 133, 235, +17, 63, 0, 0, 0, 0, 1, 238, 0, 0, 159, 88, 95, 63, 36, 13, 122, 63, 159, 170, +157, 65, 225, 122, 20, 63, 16, 215, 35, 61, 1, 238, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 61, 10, 23, 63, 0, 0, 0, 0, 1, 238, 0, 0, 178, 46, +62, 63, 26, 253, 134, 63, 49, 179, 157, 65, 154, 153, 25, 63, 16, 215, 35, 61, 1, 238, +0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 246, 40, 28, 63, 0, 0, +0, 0, 1, 239, 0, 0, 117, 199, 26, 63, 54, 204, 142, 63, 240, 185, 157, 65, 82, 184, +30, 63, 16, 215, 35, 61, 1, 239, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 174, 71, 33, 63, 0, 0, 0, 0, 1, 239, 0, 0, 178, 99, 235, 62, 105, 84, +148, 63, 192, 190, 157, 65, 10, 215, 35, 63, 16, 215, 35, 61, 1, 239, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 102, 102, 38, 63, 0, 0, 0, 0, 1, 239, +0, 0, 58, 7, 159, 62, 82, 127, 151, 63, 144, 193, 157, 65, 195, 245, 40, 63, 16, 215, +35, 61, 1, 239, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 31, 133, +43, 63, 0, 0, 0, 0, 1, 239, 0, 0, 79, 91, 35, 62, 49, 64, 152, 63, 83, 194, +157, 65, 123, 20, 46, 63, 16, 215, 35, 61, 1, 239, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 215, 163, 48, 63, 0, 0, 0, 0, 1, 239, 0, 0, 121, 234, +17, 60, 251, 147, 150, 63, 5, 193, 157, 65, 51, 51, 51, 63, 16, 215, 35, 61, 1, 239, +0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 143, 194, 53, 63, 0, 0, +0, 0, 1, 239, 0, 0, 168, 56, 14, 190, 103, 129, 146, 63, 174, 189, 157, 65, 236, 81, +56, 63, 16, 215, 35, 61, 1, 239, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 72, 225, 58, 63, 0, 0, 0, 0, 1, 240, 0, 0, 234, 35, 144, 190, 240, 24, +140, 63, 89, 184, 157, 65, 164, 112, 61, 63, 16, 215, 35, 61, 1, 240, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 0, 0, 64, 63, 0, 0, 0, 0, 1, 240, +0, 0, 133, 96, 213, 190, 113, 116, 131, 63, 28, 177, 157, 65, 92, 143, 66, 63, 16, 215, +35, 61, 1, 240, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 184, 30, +69, 63, 0, 0, 0, 0, 1, 240, 0, 0, 72, 221, 10, 191, 160, 109, 113, 63, 22, 168, +157, 65, 20, 174, 71, 63, 16, 215, 35, 61, 1, 240, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 113, 61, 74, 63, 0, 0, 0, 0, 1, 240, 0, 0, 51, 23, +40, 191, 190, 22, 88, 63, 105, 157, 157, 65, 205, 204, 76, 63, 16, 215, 35, 61, 1, 240, +0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 41, 92, 79, 63, 0, 0, +0, 0, 1, 240, 0, 0, 251, 231, 65, 191, 186, 74, 59, 63, 66, 145, 157, 65, 133, 235, +81, 63, 16, 215, 35, 61, 1, 240, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 225, 122, 84, 63, 0, 0, 0, 0, 1, 241, 0, 0, 109, 231, 87, 191, 166, 125, +27, 63, 209, 131, 157, 65, 61, 10, 87, 63, 16, 215, 35, 61, 1, 241, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 154, 153, 89, 63, 0, 0, 0, 0, 1, 241, +0, 0, 169, 188, 105, 191, 233, 95, 242, 62, 76, 117, 157, 65, 246, 40, 92, 63, 16, 215, +35, 61, 1, 241, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 82, 184, +94, 63, 0, 0, 0, 0, 1, 241, 0, 0, 188, 31, 119, 191, 132, 216, 169, 62, 239, 101, +157, 65, 174, 71, 97, 63, 16, 215, 35, 61, 1, 241, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 10, 215, 99, 63, 0, 0, 0, 0, 1, 241, 0, 0, 148, 218, +127, 191, 14, 19, 61, 62, 246, 85, 157, 65, 102, 102, 102, 63, 16, 215, 35, 61, 1, 241, +0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 195, 245, 104, 63, 0, 0, +0, 0, 1, 241, 0, 0, 0, 229, 129, 191, 101, 26, 13, 61, 164, 69, 157, 65, 31, 133, +107, 63, 16, 215, 35, 61, 1, 241, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, +157, 65, 123, 20, 110, 63, 0, 0, 0, 0, 1, 242, 0, 0, 0, 111, 129, 191, 42, 143, +238, 189, 57, 53, 157, 65, 215, 163, 112, 63, 16, 215, 35, 61, 1, 242, 0, 0, 148, 190, +64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 51, 51, 115, 63, 0, 0, 0, 0, 1, 242, +0, 0, 118, 26, 125, 191, 203, 19, 136, 190, 247, 36, 157, 65, 143, 194, 117, 63, 16, 215, +35, 61, 1, 242, 0, 0, 148, 190, 64, 62, 227, 166, 134, 188, 125, 218, 157, 65, 236, 81, +120, 63, 0, 0, 0, 0, 1, 242, 0, 0, 129, 150, 114, 191, 41, 120, 210, 190, 34, 21, +157, 65, 72, 225, 122, 63, 16, 215, 35, 61, 1, 242, 0, 0, 148, 190, 64, 62, 227, 166, +134, 188, 125, 218, 157, 65, 164, 112, 125, 63, 0, 0, 0, 0, 1, 242, 0, 0, 170, 124, +99, 191, 45, 210, 12, 191, 247, 5, 157, 65, 0, 0, 128, 63, 16, 215, 35, 61, 1, 242, +0, 0, 236, 105, 249, 191, 145, 156, 136, 191, 252, 254, 154, 65, 0, 0, 0, 128, 8, 215, +163, 61, 1, 242, 0, 0, 105, 30, 230, 191, 139, 195, 169, 191, 178, 226, 154, 65, 10, 215, +163, 60, 8, 215, 163, 61, 1, 242, 0, 0, 162, 208, 206, 191, 87, 61, 200, 191, 168, 200, +154, 65, 10, 215, 35, 61, 8, 215, 163, 61, 1, 242, 0, 0, 173, 222, 179, 191, 252, 142, +227, 191, 70, 177, 154, 65, 143, 194, 117, 61, 8, 215, 163, 61, 1, 243, 0, 0, 82, 181, +149, 191, 27, 74, 251, 191, 236, 156, 154, 65, 10, 215, 163, 61, 8, 215, 163, 61, 1, 243, +0, 0, 174, 156, 105, 191, 123, 135, 7, 192, 236, 139, 154, 65, 205, 204, 204, 61, 8, 215, +163, 61, 1, 243, 0, 0, 37, 93, 35, 191, 212, 70, 15, 192, 138, 126, 154, 65, 143, 194, +245, 61, 8, 215, 163, 61, 1, 243, 0, 0, 88, 143, 179, 190, 219, 195, 20, 192, 251, 116, +154, 65, 41, 92, 15, 62, 8, 215, 163, 61, 1, 243, 0, 0, 117, 85, 96, 189, 96, 232, +23, 192, 104, 111, 154, 65, 10, 215, 35, 62, 8, 215, 163, 61, 1, 243, 0, 0, 126, 224, +122, 62, 189, 167, 24, 192, 230, 109, 154, 65, 236, 81, 56, 62, 8, 215, 163, 61, 1, 243, +0, 0, 172, 58, 11, 63, 227, 254, 22, 192, 123, 112, 154, 65, 205, 204, 76, 62, 8, 215, +163, 61, 1, 243, 0, 0, 161, 77, 86, 63, 136, 244, 18, 192, 29, 119, 154, 65, 174, 71, +97, 62, 8, 215, 163, 61, 1, 243, 0, 0, 225, 96, 143, 63, 254, 152, 12, 192, 177, 129, +154, 65, 143, 194, 117, 62, 8, 215, 163, 61, 1, 243, 0, 0, 73, 185, 177, 63, 243, 5, +4, 192, 12, 144, 154, 65, 184, 30, 133, 62, 8, 215, 163, 61, 1, 243, 0, 0, 101, 165, +209, 63, 253, 187, 242, 191, 245, 161, 154, 65, 41, 92, 143, 62, 8, 215, 163, 61, 1, 244, +0, 0, 85, 164, 238, 63, 74, 152, 217, 191, 35, 183, 154, 65, 154, 153, 153, 62, 8, 215, +163, 61, 1, 244, 0, 0, 125, 32, 4, 64, 96, 6, 189, 191, 65, 207, 154, 65, 10, 215, +163, 62, 8, 215, 163, 61, 1, 244, 0, 0, 3, 10, 15, 64, 133, 121, 157, 191, 237, 233, +154, 65, 123, 20, 174, 62, 8, 215, 163, 61, 1, 244, 0, 0, 160, 226, 23, 64, 51, 226, +118, 191, 188, 6, 155, 65, 236, 81, 184, 62, 8, 215, 163, 61, 1, 244, 0, 0, 169, 134, +30, 64, 20, 237, 46, 191, 57, 37, 155, 65, 92, 143, 194, 62, 8, 215, 163, 61, 1, 244, +0, 0, 68, 219, 34, 64, 102, 108, 200, 190, 233, 68, 155, 65, 205, 204, 204, 62, 8, 215, +163, 61, 1, 244, 0, 0, 255, 206, 36, 64, 205, 89, 191, 189, 76, 101, 155, 65, 61, 10, +215, 62, 8, 215, 163, 61, 1, 244, 0, 0, 243, 89, 36, 64, 143, 255, 82, 62, 224, 133, +155, 65, 174, 71, 225, 62, 8, 215, 163, 61, 1, 244, 0, 0, 250, 125, 33, 64, 158, 149, +0, 63, 33, 166, 155, 65, 31, 133, 235, 62, 8, 215, 163, 61, 1, 244, 0, 0, 157, 70, +28, 64, 199, 99, 74, 63, 140, 197, 155, 65, 143, 194, 245, 62, 8, 215, 163, 61, 1, 245, +0, 0, 243, 200, 20, 64, 48, 128, 136, 63, 164, 227, 155, 65, 0, 0, 0, 63, 8, 215, +163, 61, 1, 245, 0, 0, 45, 35, 11, 64, 42, 167, 169, 63, 238, 255, 155, 65, 184, 30, +5, 63, 8, 215, 163, 61, 1, 245, 0, 0, 148, 248, 254, 63, 247, 32, 200, 63, 248, 25, +156, 65, 113, 61, 10, 63, 8, 215, 163, 61, 1, 245, 0, 0, 158, 6, 228, 63, 155, 114, +227, 63, 89, 49, 156, 65, 41, 92, 15, 63, 8, 215, 163, 61, 1, 245, 0, 0, 68, 221, +197, 63, 186, 45, 251, 63, 179, 69, 156, 65, 225, 122, 20, 63, 8, 215, 163, 61, 1, 245, +0, 0, 73, 246, 164, 63, 70, 121, 7, 64, 180, 86, 156, 65, 154, 153, 25, 63, 8, 215, +163, 61, 1, 245, 0, 0, 140, 214, 129, 63, 164, 56, 15, 64, 22, 100, 156, 65, 82, 184, +30, 63, 8, 215, 163, 61, 1, 245, 0, 0, 143, 23, 58, 63, 170, 181, 20, 64, 164, 109, +156, 65, 10, 215, 35, 63, 8, 215, 163, 61, 1, 245, 0, 0, 118, 170, 220, 62, 48, 218, +23, 64, 56, 115, 156, 65, 195, 245, 40, 63, 8, 215, 163, 61, 1, 245, 0, 0, 82, 95, +6, 62, 137, 153, 24, 64, 186, 116, 156, 65, 123, 20, 46, 63, 8, 215, 163, 61, 1, 245, +0, 0, 34, 171, 43, 190, 174, 240, 22, 64, 37, 114, 156, 65, 51, 51, 51, 63, 8, 215, +163, 61, 1, 246, 0, 0, 122, 251, 235, 190, 88, 230, 18, 64, 131, 107, 156, 65, 236, 81, +56, 63, 8, 215, 163, 61, 1, 246, 0, 0, 222, 113, 62, 191, 206, 138, 12, 64, 239, 96, +156, 65, 164, 112, 61, 63, 8, 215, 163, 61, 1, 246, 0, 0, 88, 145, 129, 191, 190, 247, +3, 64, 147, 82, 156, 65, 92, 143, 66, 63, 8, 215, 163, 61, 1, 246, 0, 0, 116, 125, +161, 191, 149, 159, 242, 63, 170, 64, 156, 65, 20, 174, 71, 63, 8, 215, 163, 61, 1, 246, +0, 0, 99, 124, 190, 191, 234, 123, 217, 63, 124, 43, 156, 65, 205, 204, 76, 63, 8, 215, +163, 61, 1, 246, 0, 0, 9, 25, 216, 191, 247, 233, 188, 63, 95, 19, 156, 65, 133, 235, +81, 63, 8, 215, 163, 61, 1, 246, 0, 0, 11, 236, 237, 191, 28, 93, 157, 63, 179, 248, +155, 65, 61, 10, 87, 63, 8, 215, 163, 61, 1, 246, 0, 0, 78, 157, 255, 191, 97, 169, +118, 63, 228, 219, 155, 65, 246, 40, 92, 63, 8, 215, 163, 61, 1, 246, 0, 0, 172, 114, +6, 192, 83, 180, 46, 63, 103, 189, 155, 65, 174, 71, 97, 63, 8, 215, 163, 61, 1, 246, +0, 0, 76, 199, 10, 192, 227, 250, 199, 62, 183, 157, 155, 65, 102, 102, 102, 63, 8, 215, +163, 61, 1, 246, 0, 0, 6, 187, 12, 192, 62, 147, 189, 61, 84, 125, 155, 65, 31, 133, +107, 63, 8, 215, 163, 61, 1, 247, 0, 0, 250, 69, 12, 192, 214, 226, 83, 190, 192, 92, +155, 65, 215, 163, 112, 63, 8, 215, 163, 61, 1, 247, 0, 0, 253, 105, 9, 192, 112, 206, +0, 191, 127, 60, 155, 65, 143, 194, 117, 63, 8, 215, 163, 61, 1, 247, 0, 0, 165, 50, +4, 192, 153, 156, 74, 191, 19, 29, 155, 65, 72, 225, 122, 63, 8, 215, 163, 61, 1, 247, +0, 0, 236, 105, 249, 191, 145, 156, 136, 191, 252, 254, 154, 65, 0, 0, 128, 63, 8, 215, +163, 61, 1, 247, 0, 0, 157, 99, 62, 192, 193, 169, 199, 191, 186, 205, 151, 65, 0, 0, +0, 128, 144, 194, 245, 61, 1, 247, 0, 0, 189, 27, 48, 192, 165, 188, 248, 191, 218, 163, +151, 65, 10, 215, 163, 60, 144, 194, 245, 61, 1, 247, 0, 0, 77, 220, 30, 192, 171, 236, +18, 192, 78, 125, 151, 65, 10, 215, 35, 61, 144, 194, 245, 61, 1, 247, 0, 0, 238, 234, +10, 192, 213, 36, 39, 192, 179, 90, 151, 65, 143, 194, 117, 61, 144, 194, 245, 61, 1, 247, +0, 0, 73, 48, 233, 191, 53, 181, 56, 192, 146, 60, 151, 65, 10, 215, 163, 61, 144, 194, +245, 61, 1, 247, 0, 0, 32, 124, 184, 191, 222, 86, 71, 192, 104, 35, 151, 65, 205, 204, +204, 61, 144, 194, 245, 61, 1, 248, 0, 0, 7, 126, 132, 191, 192, 206, 82, 192, 152, 15, +151, 65, 143, 194, 245, 61, 144, 194, 245, 61, 1, 248, 0, 0, 203, 15, 28, 191, 141, 238, +90, 192, 115, 1, 151, 65, 41, 92, 15, 62, 144, 194, 245, 61, 1, 248, 0, 0, 163, 172, +47, 190, 116, 149, 95, 192, 50, 249, 150, 65, 10, 215, 35, 62, 144, 194, 245, 61, 1, 248, +0, 0, 33, 90, 139, 62, 180, 176, 96, 192, 246, 246, 150, 65, 236, 81, 56, 62, 144, 194, +245, 61, 1, 248, 0, 0, 66, 238, 54, 63, 209, 59, 94, 192, 200, 250, 150, 65, 205, 204, +76, 62, 144, 194, 245, 61, 1, 248, 0, 0, 150, 7, 147, 63, 184, 64, 88, 192, 154, 4, +151, 65, 174, 71, 97, 62, 144, 194, 245, 61, 1, 248, 0, 0, 139, 167, 200, 63, 140, 215, +78, 192, 67, 20, 151, 65, 143, 194, 117, 62, 144, 194, 245, 61, 1, 248, 0, 0, 153, 126, +251, 63, 78, 38, 66, 192, 131, 41, 151, 65, 184, 30, 133, 62, 144, 194, 245, 61, 1, 248, +0, 0, 179, 95, 21, 64, 61, 96, 50, 192, 6, 68, 151, 65, 41, 92, 143, 62, 144, 194, +245, 61, 1, 248, 0, 0, 157, 213, 42, 64, 5, 197, 31, 192, 96, 99, 151, 65, 154, 153, +153, 62, 144, 194, 245, 61, 1, 248, 0, 0, 96, 202, 61, 64, 195, 159, 10, 192, 19, 135, +151, 65, 10, 215, 163, 62, 144, 194, 245, 61, 1, 249, 0, 0, 124, 241, 77, 64, 185, 139, +230, 191, 142, 174, 151, 65, 123, 20, 174, 62, 144, 194, 245, 61, 1, 249, 0, 0, 179, 9, +91, 64, 31, 43, 180, 191, 51, 217, 151, 65, 236, 81, 184, 62, 144, 194, 245, 61, 1, 249, +0, 0, 47, 222, 100, 64, 91, 210, 125, 191, 84, 6, 152, 65, 92, 143, 194, 62, 144, 194, +245, 61, 1, 249, 0, 0, 57, 71, 107, 64, 176, 57, 15, 191, 60, 53, 152, 65, 205, 204, +204, 62, 144, 194, 245, 61, 1, 249, 0, 0, 241, 42, 110, 64, 122, 86, 242, 189, 45, 101, +152, 65, 61, 10, 215, 62, 144, 194, 245, 61, 1, 249, 0, 0, 175, 125, 109, 64, 212, 100, +166, 62, 102, 149, 152, 65, 174, 71, 225, 62, 144, 194, 245, 61, 1, 249, 0, 0, 45, 66, +105, 64, 159, 115, 67, 63, 36, 197, 152, 65, 31, 133, 235, 62, 144, 194, 245, 61, 1, 249, +0, 0, 131, 137, 97, 64, 226, 89, 152, 63, 167, 243, 152, 65, 143, 194, 245, 62, 144, 194, +245, 61, 1, 249, 0, 0, 218, 114, 86, 64, 229, 156, 204, 63, 50, 32, 153, 65, 0, 0, +0, 63, 144, 194, 245, 61, 1, 249, 0, 0, 250, 42, 72, 64, 201, 175, 253, 63, 18, 74, +153, 65, 184, 30, 5, 63, 144, 194, 245, 61, 1, 249, 0, 0, 137, 235, 54, 64, 60, 102, +21, 64, 158, 112, 153, 65, 113, 61, 10, 63, 144, 194, 245, 61, 1, 250, 0, 0, 43, 250, +34, 64, 103, 158, 41, 64, 58, 147, 153, 65, 41, 92, 15, 63, 144, 194, 245, 61, 1, 250, +0, 0, 97, 167, 12, 64, 199, 46, 59, 64, 90, 177, 153, 65, 225, 122, 20, 63, 144, 194, +245, 61, 1, 250, 0, 0, 153, 154, 232, 63, 112, 208, 73, 64, 132, 202, 153, 65, 154, 153, +25, 63, 144, 194, 245, 61, 1, 250, 0, 0, 128, 156, 180, 63, 82, 72, 85, 64, 84, 222, +153, 65, 82, 184, 30, 63, 144, 194, 245, 61, 1, 250, 0, 0, 173, 76, 124, 63, 27, 104, +93, 64, 121, 236, 153, 65, 10, 215, 35, 63, 144, 194, 245, 61, 1, 250, 0, 0, 11, 40, +12, 63, 2, 15, 98, 64, 186, 244, 153, 65, 195, 245, 40, 63, 144, 194, 245, 61, 1, 250, +0, 0, 19, 127, 212, 61, 65, 42, 99, 64, 246, 246, 153, 65, 123, 20, 46, 63, 144, 194, +245, 61, 1, 250, 0, 0, 158, 98, 173, 190, 95, 181, 96, 64, 36, 243, 153, 65, 51, 51, +51, 63, 144, 194, 245, 61, 1, 250, 0, 0, 57, 210, 69, 191, 69, 186, 90, 64, 82, 233, +153, 65, 236, 81, 56, 63, 144, 194, 245, 61, 1, 250, 0, 0, 26, 137, 152, 191, 26, 81, +81, 64, 169, 217, 153, 65, 164, 112, 61, 63, 144, 194, 245, 61, 1, 251, 0, 0, 32, 96, +203, 191, 220, 159, 68, 64, 105, 196, 153, 65, 92, 143, 66, 63, 144, 194, 245, 61, 1, 251, +0, 0, 245, 160, 250, 191, 203, 217, 52, 64, 230, 169, 153, 65, 20, 174, 71, 63, 144, 194, +245, 61, 1, 251, 0, 0, 97, 198, 18, 192, 146, 62, 34, 64, 140, 138, 153, 65, 205, 204, +76, 63, 144, 194, 245, 61, 1, 251, 0, 0, 40, 187, 37, 192, 80, 25, 13, 64, 217, 102, +153, 65, 133, 235, 81, 63, 144, 194, 245, 61, 1, 251, 0, 0, 63, 226, 53, 192, 212, 126, +235, 63, 94, 63, 153, 65, 61, 10, 87, 63, 144, 194, 245, 61, 1, 251, 0, 0, 118, 250, +66, 192, 58, 30, 185, 63, 185, 20, 153, 65, 246, 40, 92, 63, 144, 194, 245, 61, 1, 251, +0, 0, 242, 206, 76, 192, 72, 220, 131, 63, 152, 231, 152, 65, 174, 71, 97, 63, 144, 194, +245, 61, 1, 251, 0, 0, 252, 55, 83, 192, 230, 31, 25, 63, 176, 184, 152, 65, 102, 102, +102, 63, 144, 194, 245, 61, 1, 251, 0, 0, 181, 27, 86, 192, 210, 195, 32, 62, 191, 136, +152, 65, 31, 133, 107, 63, 144, 194, 245, 61, 1, 251, 0, 0, 114, 110, 85, 192, 103, 152, +146, 190, 134, 88, 152, 65, 215, 163, 112, 63, 144, 194, 245, 61, 1, 251, 0, 0, 240, 50, +81, 192, 105, 141, 57, 191, 200, 40, 152, 65, 143, 194, 117, 63, 144, 194, 245, 61, 1, 252, +0, 0, 66, 122, 73, 192, 199, 102, 147, 191, 69, 250, 151, 65, 72, 225, 122, 63, 144, 194, +245, 61, 1, 252, 0, 0, 157, 99, 62, 192, 193, 169, 199, 191, 186, 205, 151, 65, 0, 0, +128, 63, 144, 194, 245, 61, 1, 252, 0, 0, 244, 225, 124, 192, 10, 73, 1, 192, 21, 127, +147, 65, 0, 0, 0, 128, 12, 215, 35, 62, 1, 252, 0, 0, 156, 49, 106, 192, 103, 101, +33, 192, 73, 72, 147, 65, 10, 215, 163, 60, 12, 215, 35, 62, 1, 252, 0, 0, 65, 159, +83, 192, 24, 234, 62, 192, 215, 21, 147, 65, 10, 215, 35, 61, 12, 215, 35, 62, 1, 252, +0, 0, 1, 134, 57, 192, 3, 96, 89, 192, 141, 232, 146, 65, 143, 194, 117, 61, 12, 215, +35, 62, 1, 252, 0, 0, 60, 79, 28, 192, 70, 92, 112, 192, 32, 193, 146, 65, 10, 215, +163, 61, 12, 215, 35, 62, 1, 252, 0, 0, 198, 225, 248, 191, 16, 193, 129, 192, 49, 160, +146, 65, 205, 204, 204, 61, 12, 215, 35, 62, 1, 252, 0, 0, 56, 215, 180, 191, 28, 66, +137, 192, 67, 134, 146, 65, 143, 194, 245, 61, 12, 215, 35, 62, 1, 252, 0, 0, 37, 35, +91, 191, 253, 146, 142, 192, 192, 115, 146, 65, 41, 92, 15, 62, 12, 215, 35, 62, 1, 252, +0, 0, 253, 193, 144, 190, 63, 158, 145, 192, 243, 104, 146, 65, 10, 215, 35, 62, 12, 215, +35, 62, 1, 253, 0, 0, 222, 142, 152, 62, 149, 87, 146, 192, 7, 102, 146, 65, 236, 81, +56, 62, 12, 215, 35, 62, 1, 253, 0, 0, 246, 125, 96, 63, 18, 188, 144, 192, 8, 107, +146, 65, 205, 204, 76, 62, 12, 215, 35, 62, 1, 253, 0, 0, 22, 246, 184, 63, 57, 210, +140, 192, 225, 119, 146, 65, 174, 71, 97, 62, 12, 215, 35, 62, 1, 253, 0, 0, 129, 35, +255, 63, 210, 169, 134, 192, 95, 140, 146, 65, 143, 194, 117, 62, 12, 215, 35, 62, 1, 253, +0, 0, 241, 213, 32, 64, 120, 183, 124, 192, 47, 168, 146, 65, 184, 30, 133, 62, 12, 215, +35, 62, 1, 253, 0, 0, 81, 193, 63, 64, 245, 18, 104, 192, 225, 202, 146, 65, 41, 92, +143, 62, 12, 215, 35, 62, 1, 253, 0, 0, 6, 215, 91, 64, 120, 185, 79, 192, 232, 243, +146, 65, 154, 153, 153, 62, 12, 215, 35, 62, 1, 253, 0, 0, 181, 165, 116, 64, 78, 13, +52, 192, 160, 34, 147, 65, 10, 215, 163, 62, 12, 215, 35, 62, 1, 253, 0, 0, 153, 228, +132, 64, 53, 126, 21, 192, 75, 86, 147, 65, 123, 20, 174, 62, 12, 215, 35, 62, 1, 253, +0, 0, 18, 118, 141, 64, 6, 15, 233, 191, 25, 142, 147, 65, 236, 81, 184, 62, 12, 215, +35, 62, 1, 254, 0, 0, 176, 228, 147, 64, 167, 92, 163, 191, 40, 201, 147, 65, 92, 143, +194, 62, 12, 215, 35, 62, 1, 254, 0, 0, 123, 22, 152, 64, 89, 253, 53, 191, 139, 6, +148, 65, 205, 204, 204, 62, 12, 215, 35, 62, 1, 254, 0, 0, 129, 250, 153, 64, 62, 202, +8, 190, 72, 69, 148, 65, 61, 10, 215, 62, 12, 215, 35, 62, 1, 254, 0, 0, 34, 137, +153, 64, 244, 164, 228, 62, 100, 132, 148, 65, 174, 71, 225, 62, 12, 215, 35, 62, 1, 254, +0, 0, 40, 196, 150, 64, 6, 157, 130, 63, 223, 194, 148, 65, 31, 133, 235, 62, 12, 215, +35, 62, 1, 254, 0, 0, 193, 182, 145, 64, 143, 25, 202, 63, 189, 255, 148, 65, 143, 194, +245, 62, 12, 215, 35, 62, 1, 254, 0, 0, 83, 117, 138, 64, 33, 63, 7, 64, 8, 58, +149, 65, 0, 0, 0, 63, 12, 215, 35, 62, 1, 254, 0, 0, 42, 29, 129, 64, 121, 91, +39, 64, 213, 112, 149, 65, 184, 30, 5, 63, 12, 215, 35, 62, 1, 254, 0, 0, 244, 167, +107, 64, 47, 224, 68, 64, 70, 163, 149, 65, 113, 61, 10, 63, 12, 215, 35, 62, 1, 254, +0, 0, 180, 142, 81, 64, 25, 86, 95, 64, 144, 208, 149, 65, 41, 92, 15, 63, 12, 215, +35, 62, 1, 254, 0, 0, 239, 87, 52, 64, 93, 82, 118, 64, 253, 247, 149, 65, 225, 122, +20, 63, 12, 215, 35, 62, 1, 255, 0, 0, 150, 121, 20, 64, 25, 188, 132, 64, 236, 24, +150, 65, 154, 153, 25, 63, 12, 215, 35, 62, 1, 255, 0, 0, 159, 232, 228, 63, 37, 61, +140, 64, 218, 50, 150, 65, 82, 184, 30, 63, 12, 215, 35, 62, 1, 255, 0, 0, 240, 162, +157, 63, 6, 142, 145, 64, 93, 69, 150, 65, 10, 215, 35, 63, 12, 215, 35, 62, 1, 255, +0, 0, 203, 131, 40, 63, 72, 153, 148, 64, 42, 80, 150, 65, 195, 245, 40, 63, 12, 215, +35, 62, 1, 255, 0, 0, 236, 218, 158, 61, 158, 82, 149, 64, 22, 83, 150, 65, 123, 20, +46, 63, 12, 215, 35, 62, 1, 255, 0, 0, 41, 91, 0, 191, 28, 183, 147, 64, 22, 78, +150, 65, 51, 51, 51, 63, 12, 215, 35, 62, 1, 255, 0, 0, 176, 228, 136, 191, 66, 205, +143, 64, 60, 65, 150, 65, 236, 81, 56, 63, 12, 215, 35, 62, 1, 255, 0, 0, 27, 18, +207, 191, 217, 164, 137, 64, 190, 44, 150, 65, 164, 112, 61, 63, 12, 215, 35, 62, 1, 255, +0, 0, 62, 205, 8, 192, 197, 86, 129, 64, 238, 16, 150, 65, 92, 143, 66, 63, 12, 215, +35, 62, 1, 255, 0, 0, 157, 184, 39, 192, 7, 9, 110, 64, 60, 238, 149, 65, 20, 174, +71, 63, 12, 215, 35, 62, 1, 138, 0, 0, 83, 206, 67, 192, 138, 175, 85, 64, 53, 197, +149, 65, 205, 204, 76, 63, 12, 215, 35, 62, 1, 138, 0, 0, 2, 157, 92, 192, 96, 3, +58, 64, 125, 150, 149, 65, 133, 235, 81, 63, 12, 215, 35, 62, 1, 138, 0, 0, 127, 192, +113, 192, 67, 116, 27, 64, 210, 98, 149, 65, 61, 10, 87, 63, 12, 215, 35, 62, 1, 138, +0, 0, 185, 113, 129, 192, 34, 251, 244, 63, 4, 43, 149, 65, 246, 40, 92, 63, 12, 215, +35, 62, 1, 138, 0, 0, 87, 224, 135, 192, 195, 72, 175, 63, 245, 239, 148, 65, 174, 71, +97, 63, 12, 215, 35, 62, 1, 138, 0, 0, 31, 18, 140, 192, 162, 213, 77, 63, 147, 178, +148, 65, 102, 102, 102, 63, 12, 215, 35, 62, 1, 138, 0, 0, 37, 246, 141, 192, 31, 43, +104, 62, 213, 115, 148, 65, 31, 133, 107, 63, 12, 215, 35, 62, 1, 138, 0, 0, 199, 132, +141, 192, 98, 244, 180, 190, 185, 52, 148, 65, 215, 163, 112, 63, 12, 215, 35, 62, 1, 138, +0, 0, 207, 191, 138, 192, 212, 97, 109, 191, 62, 246, 147, 65, 143, 194, 117, 63, 12, 215, +35, 62, 1, 138, 0, 0, 102, 178, 133, 192, 115, 45, 190, 191, 96, 185, 147, 65, 72, 225, +122, 63, 12, 215, 35, 62, 1, 139, 0, 0, 244, 225, 124, 192, 10, 73, 1, 192, 21, 127, +147, 65, 0, 0, 128, 63, 12, 215, 35, 62, 1, 139, 0, 0, 210, 153, 155, 192, 227, 51, +28, 192, 114, 36, 142, 65, 0, 0, 0, 128, 204, 204, 76, 62, 1, 139, 0, 0, 39, 51, +144, 192, 124, 97, 67, 192, 150, 225, 141, 65, 10, 215, 163, 60, 204, 204, 76, 62, 1, 139, +0, 0, 22, 110, 130, 192, 103, 101, 103, 192, 10, 164, 141, 65, 10, 215, 35, 61, 204, 204, +76, 62, 1, 139, 0, 0, 104, 4, 101, 192, 27, 215, 131, 192, 200, 108, 141, 65, 143, 194, +117, 61, 204, 204, 76, 62, 1, 139, 0, 0, 154, 95, 65, 192, 200, 220, 145, 192, 174, 60, +141, 65, 10, 215, 163, 61, 204, 204, 76, 62, 1, 139, 0, 0, 162, 125, 26, 192, 34, 139, +157, 192, 126, 20, 141, 65, 205, 204, 204, 61, 204, 204, 76, 62, 1, 139, 0, 0, 253, 246, +225, 191, 1, 179, 166, 192, 220, 244, 140, 65, 143, 194, 245, 61, 204, 204, 76, 62, 1, 139, +0, 0, 134, 1, 139, 191, 104, 47, 173, 192, 70, 222, 140, 65, 41, 92, 15, 62, 204, 204, +76, 62, 1, 139, 0, 0, 234, 231, 197, 190, 44, 230, 176, 192, 24, 209, 140, 65, 10, 215, +35, 62, 204, 204, 76, 62, 1, 139, 0, 0, 253, 216, 164, 62, 75, 200, 177, 192, 136, 205, +140, 65, 236, 81, 56, 62, 204, 204, 76, 62, 1, 140, 0, 0, 1, 161, 131, 63, 59, 210, +175, 192, 162, 211, 140, 65, 205, 204, 76, 62, 204, 204, 76, 62, 1, 140, 0, 0, 50, 89, +220, 63, 223, 11, 171, 192, 79, 227, 140, 65, 174, 71, 97, 62, 204, 204, 76, 62, 1, 140, +0, 0, 93, 252, 24, 64, 131, 136, 163, 192, 80, 252, 140, 65, 143, 194, 117, 62, 204, 204, +76, 62, 1, 140, 0, 0, 234, 146, 65, 64, 121, 102, 153, 192, 63, 30, 141, 65, 184, 30, +133, 62, 204, 204, 76, 62, 1, 140, 0, 0, 106, 76, 103, 64, 173, 206, 140, 192, 148, 72, +141, 65, 41, 92, 143, 62, 204, 204, 76, 62, 1, 140, 0, 0, 71, 200, 132, 64, 234, 231, +123, 192, 163, 122, 141, 65, 154, 153, 153, 62, 204, 204, 76, 62, 1, 140, 0, 0, 127, 234, +147, 64, 146, 36, 90, 192, 163, 179, 141, 65, 10, 215, 163, 62, 204, 204, 76, 62, 1, 140, +0, 0, 194, 207, 160, 64, 161, 219, 52, 192, 173, 242, 141, 65, 123, 20, 174, 62, 204, 204, +76, 62, 1, 140, 0, 0, 3, 68, 171, 64, 161, 163, 12, 192, 195, 54, 142, 65, 236, 81, +184, 62, 204, 204, 76, 62, 1, 140, 0, 0, 10, 29, 179, 64, 222, 61, 196, 191, 210, 126, +142, 65, 92, 143, 194, 62, 204, 204, 76, 62, 1, 140, 0, 0, 40, 59, 184, 64, 222, 228, +87, 191, 183, 201, 142, 65, 205, 204, 204, 62, 204, 204, 76, 62, 1, 141, 0, 0, 185, 137, +186, 64, 2, 75, 14, 190, 68, 22, 143, 65, 61, 10, 215, 62, 204, 204, 76, 62, 1, 141, +0, 0, 101, 255, 185, 64, 115, 162, 17, 63, 68, 99, 143, 65, 174, 71, 225, 62, 204, 204, +76, 62, 1, 141, 0, 0, 98, 158, 182, 64, 172, 111, 162, 63, 127, 175, 143, 65, 31, 133, +235, 62, 204, 204, 76, 62, 1, 141, 0, 0, 79, 116, 176, 64, 13, 168, 249, 63, 194, 249, +143, 65, 143, 194, 245, 62, 204, 204, 76, 62, 1, 141, 0, 0, 15, 154, 167, 64, 42, 141, +38, 64, 226, 64, 144, 65, 0, 0, 0, 63, 204, 204, 76, 62, 1, 141, 0, 0, 99, 51, +156, 64, 195, 186, 77, 64, 190, 131, 144, 65, 184, 30, 5, 63, 204, 204, 76, 62, 1, 141, +0, 0, 82, 110, 142, 64, 173, 190, 113, 64, 74, 193, 144, 65, 113, 61, 10, 63, 204, 204, +76, 62, 1, 141, 0, 0, 226, 4, 125, 64, 188, 3, 137, 64, 140, 248, 144, 65, 41, 92, +15, 63, 204, 204, 76, 62, 1, 141, 0, 0, 15, 96, 89, 64, 108, 9, 151, 64, 166, 40, +145, 65, 225, 122, 20, 63, 204, 204, 76, 62, 1, 141, 0, 0, 28, 126, 50, 64, 200, 183, +162, 64, 213, 80, 145, 65, 154, 153, 25, 63, 204, 204, 76, 62, 1, 142, 0, 0, 244, 251, +8, 64, 162, 223, 171, 64, 120, 112, 145, 65, 82, 184, 30, 63, 204, 204, 76, 62, 1, 142, +0, 0, 121, 2, 187, 63, 10, 92, 178, 64, 13, 135, 145, 65, 10, 215, 35, 63, 204, 204, +76, 62, 1, 142, 0, 0, 203, 245, 66, 63, 205, 18, 182, 64, 59, 148, 145, 65, 195, 245, +40, 63, 204, 204, 76, 62, 1, 142, 0, 0, 126, 86, 89, 61, 239, 244, 182, 64, 204, 151, +145, 65, 123, 20, 46, 63, 204, 204, 76, 62, 1, 142, 0, 0, 28, 64, 39, 191, 220, 254, +180, 64, 178, 145, 145, 65, 51, 51, 51, 63, 204, 204, 76, 62, 1, 142, 0, 0, 63, 88, +172, 191, 126, 56, 176, 64, 5, 130, 145, 65, 236, 81, 56, 63, 204, 204, 76, 62, 1, 142, +0, 0, 227, 251, 0, 192, 36, 181, 168, 64, 4, 105, 145, 65, 164, 112, 61, 63, 204, 204, +76, 62, 1, 142, 0, 0, 113, 146, 41, 192, 27, 147, 158, 64, 21, 71, 145, 65, 92, 143, +66, 63, 204, 204, 76, 62, 1, 142, 0, 0, 241, 75, 79, 192, 76, 251, 145, 64, 192, 28, +145, 65, 20, 174, 71, 63, 204, 204, 76, 62, 1, 142, 0, 0, 21, 144, 113, 192, 148, 32, +131, 64, 177, 234, 144, 65, 205, 204, 76, 63, 204, 204, 76, 62, 1, 142, 0, 0, 64, 234, +135, 192, 208, 125, 100, 64, 177, 177, 144, 65, 133, 235, 81, 63, 204, 204, 76, 62, 1, 143, +0, 0, 133, 207, 148, 192, 223, 52, 63, 64, 167, 114, 144, 65, 61, 10, 87, 63, 204, 204, +76, 62, 1, 143, 0, 0, 198, 67, 159, 192, 223, 252, 22, 64, 145, 46, 144, 65, 246, 40, +92, 63, 204, 204, 76, 62, 1, 143, 0, 0, 203, 28, 167, 192, 90, 240, 216, 63, 130, 230, +143, 65, 174, 71, 97, 63, 204, 204, 76, 62, 1, 143, 0, 0, 237, 58, 172, 192, 236, 164, +128, 63, 156, 155, 143, 65, 102, 102, 102, 63, 204, 204, 76, 62, 1, 143, 0, 0, 122, 137, +174, 192, 116, 239, 153, 62, 16, 79, 143, 65, 31, 133, 107, 63, 204, 204, 76, 62, 1, 143, +0, 0, 40, 255, 173, 192, 242, 122, 208, 190, 16, 2, 143, 65, 215, 163, 112, 63, 204, 204, +76, 62, 1, 143, 0, 0, 35, 158, 170, 192, 48, 189, 141, 191, 213, 181, 142, 65, 143, 194, +117, 63, 204, 204, 76, 62, 1, 143, 0, 0, 16, 116, 164, 192, 144, 245, 228, 191, 146, 107, +142, 65, 72, 225, 122, 63, 204, 204, 76, 62, 1, 143, 0, 0, 210, 153, 155, 192, 227, 51, +28, 192, 114, 36, 142, 65, 0, 0, 128, 63, 204, 204, 76, 62, 1, 143, 0, 0, 162, 54, +182, 192, 187, 40, 52, 192, 109, 211, 135, 65, 0, 0, 0, 128, 144, 194, 117, 62, 1, 143, +0, 0, 124, 239, 168, 192, 105, 201, 97, 192, 143, 133, 135, 65, 10, 215, 163, 60, 144, 194, +117, 62, 1, 143, 0, 0, 29, 230, 152, 192, 141, 221, 133, 192, 226, 61, 135, 65, 10, 215, +35, 61, 144, 194, 117, 62, 1, 144, 0, 0, 66, 91, 134, 192, 61, 170, 152, 192, 134, 253, +134, 65, 143, 194, 117, 61, 144, 194, 117, 62, 1, 144, 0, 0, 148, 51, 99, 192, 220, 254, +168, 192, 130, 197, 134, 65, 10, 215, 163, 61, 144, 194, 117, 62, 1, 144, 0, 0, 251, 234, +53, 192, 124, 153, 182, 192, 181, 150, 134, 65, 205, 204, 204, 61, 144, 194, 117, 62, 1, 144, +0, 0, 142, 147, 5, 192, 51, 67, 193, 192, 221, 113, 134, 65, 143, 194, 245, 61, 144, 194, +117, 62, 1, 144, 0, 0, 240, 224, 165, 191, 242, 208, 200, 192, 144, 87, 134, 65, 41, 92, +15, 62, 144, 194, 117, 62, 1, 144, 0, 0, 105, 113, 246, 190, 58, 36, 205, 192, 54, 72, +134, 65, 10, 215, 35, 62, 144, 194, 117, 62, 1, 144, 0, 0, 20, 7, 176, 62, 149, 43, +206, 192, 15, 68, 134, 65, 236, 81, 56, 62, 144, 194, 117, 62, 1, 144, 0, 0, 236, 78, +149, 63, 218, 226, 203, 192, 43, 75, 134, 65, 205, 204, 76, 62, 144, 194, 117, 62, 1, 144, +0, 0, 18, 162, 252, 63, 70, 83, 198, 192, 109, 93, 134, 65, 174, 71, 97, 62, 144, 194, +117, 62, 1, 145, 0, 0, 254, 44, 48, 64, 73, 147, 189, 192, 139, 122, 134, 65, 143, 194, +117, 62, 144, 194, 117, 62, 1, 145, 0, 0, 17, 114, 95, 64, 57, 198, 177, 192, 16, 162, +134, 65, 184, 30, 133, 62, 144, 194, 117, 62, 1, 145, 0, 0, 177, 176, 133, 64, 183, 27, +163, 192, 93, 211, 134, 65, 41, 92, 143, 62, 144, 194, 117, 62, 1, 145, 0, 0, 204, 164, +153, 64, 251, 206, 145, 192, 170, 13, 135, 65, 154, 153, 153, 62, 144, 194, 117, 62, 1, 145, +0, 0, 204, 68, 171, 64, 190, 75, 124, 192, 12, 80, 135, 65, 10, 215, 163, 62, 144, 194, +117, 62, 1, 145, 0, 0, 134, 73, 186, 64, 131, 223, 80, 192, 119, 153, 135, 65, 123, 20, +174, 62, 144, 194, 117, 62, 1, 145, 0, 0, 85, 118, 198, 64, 146, 8, 34, 192, 194, 232, +135, 65, 236, 81, 184, 62, 144, 194, 117, 62, 1, 145, 0, 0, 23, 154, 207, 64, 11, 8, +225, 191, 174, 60, 136, 65, 92, 143, 194, 62, 144, 194, 117, 62, 1, 145, 0, 0, 226, 143, +213, 64, 39, 103, 116, 191, 232, 147, 136, 65, 205, 204, 204, 62, 144, 194, 117, 62, 1, 145, +0, 0, 171, 63, 216, 64, 129, 151, 9, 190, 14, 237, 136, 65, 61, 10, 215, 62, 144, 194, +117, 62, 1, 145, 0, 0, 147, 158, 215, 64, 9, 164, 48, 63, 187, 70, 137, 65, 174, 71, +225, 62, 144, 194, 117, 62, 1, 146, 0, 0, 39, 175, 211, 64, 62, 177, 192, 63, 131, 159, +137, 65, 31, 133, 235, 62, 144, 194, 117, 62, 1, 146, 0, 0, 75, 129, 204, 64, 175, 34, +19, 64, 0, 246, 137, 65, 143, 194, 245, 62, 144, 194, 117, 62, 1, 146, 0, 0, 251, 49, +194, 64, 40, 186, 67, 64, 213, 72, 138, 65, 0, 0, 0, 63, 144, 194, 117, 62, 1, 146, +0, 0, 213, 234, 180, 64, 213, 90, 113, 64, 179, 150, 138, 65, 184, 30, 5, 63, 144, 194, +117, 62, 1, 146, 0, 0, 120, 225, 164, 64, 70, 166, 141, 64, 96, 222, 138, 65, 113, 61, +10, 63, 144, 194, 117, 62, 1, 146, 0, 0, 155, 86, 146, 64, 243, 114, 160, 64, 187, 30, +139, 65, 41, 92, 15, 63, 144, 194, 117, 62, 1, 146, 0, 0, 69, 42, 123, 64, 147, 199, +176, 64, 192, 86, 139, 65, 225, 122, 20, 63, 144, 194, 117, 62, 1, 146, 0, 0, 168, 225, +77, 64, 51, 98, 190, 64, 141, 133, 139, 65, 154, 153, 25, 63, 144, 194, 117, 62, 1, 146, +0, 0, 64, 138, 29, 64, 231, 11, 201, 64, 101, 170, 139, 65, 82, 184, 30, 63, 144, 194, +117, 62, 1, 146, 0, 0, 83, 206, 213, 63, 166, 153, 208, 64, 178, 196, 139, 65, 10, 215, +35, 63, 144, 194, 117, 62, 1, 146, 0, 0, 106, 19, 91, 63, 240, 236, 212, 64, 11, 212, +139, 65, 195, 245, 40, 63, 144, 194, 117, 62, 1, 147, 0, 0, 146, 231, 250, 60, 73, 244, +213, 64, 51, 216, 139, 65, 123, 20, 46, 63, 144, 194, 117, 62, 1, 147, 0, 0, 34, 195, +74, 191, 145, 171, 211, 64, 23, 209, 139, 65, 51, 51, 51, 63, 144, 194, 117, 62, 1, 147, +0, 0, 175, 180, 204, 191, 250, 27, 206, 64, 213, 190, 139, 65, 236, 81, 56, 63, 144, 194, +117, 62, 1, 147, 0, 0, 76, 54, 24, 192, 255, 91, 197, 64, 183, 161, 139, 65, 164, 112, +61, 63, 144, 194, 117, 62, 1, 147, 0, 0, 95, 123, 71, 192, 235, 142, 185, 64, 49, 122, +139, 65, 92, 143, 66, 63, 144, 194, 117, 62, 1, 147, 0, 0, 177, 106, 115, 192, 107, 228, +170, 64, 229, 72, 139, 65, 20, 174, 71, 63, 144, 194, 117, 62, 1, 147, 0, 0, 118, 169, +141, 192, 177, 151, 153, 64, 152, 14, 139, 65, 205, 204, 76, 63, 144, 194, 117, 62, 1, 147, +0, 0, 115, 73, 159, 192, 147, 238, 133, 64, 54, 204, 138, 65, 133, 235, 81, 63, 144, 194, +117, 62, 1, 147, 0, 0, 43, 78, 174, 192, 231, 112, 96, 64, 203, 130, 138, 65, 61, 10, +87, 63, 144, 194, 117, 62, 1, 147, 0, 0, 253, 122, 186, 192, 246, 153, 49, 64, 128, 51, +138, 65, 246, 40, 92, 63, 144, 194, 117, 62, 1, 148, 0, 0, 189, 158, 195, 192, 106, 21, +0, 64, 148, 223, 137, 65, 174, 71, 97, 63, 144, 194, 117, 62, 1, 148, 0, 0, 138, 148, +201, 192, 101, 86, 153, 63, 90, 136, 137, 65, 102, 102, 102, 63, 144, 194, 117, 62, 1, 148, +0, 0, 80, 68, 204, 192, 226, 86, 193, 62, 51, 47, 137, 65, 31, 133, 107, 63, 144, 194, +117, 62, 1, 148, 0, 0, 58, 163, 203, 192, 241, 188, 228, 190, 135, 213, 136, 65, 215, 163, +112, 63, 144, 194, 117, 62, 1, 148, 0, 0, 204, 179, 199, 192, 117, 142, 161, 191, 191, 124, +136, 65, 143, 194, 117, 63, 144, 194, 117, 62, 1, 148, 0, 0, 240, 133, 192, 192, 75, 145, +3, 192, 66, 38, 136, 65, 72, 225, 122, 63, 144, 194, 117, 62, 1, 148, 0, 0, 162, 54, +182, 192, 187, 40, 52, 192, 109, 211, 135, 65, 0, 0, 128, 63, 144, 194, 117, 62, 1, 148, +0, 0, 247, 219, 205, 192, 214, 198, 72, 192, 136, 165, 128, 65, 0, 0, 0, 128, 40, 92, +143, 62, 1, 148, 0, 0, 242, 233, 190, 192, 100, 34, 124, 192, 226, 77, 128, 65, 10, 215, +163, 60, 40, 92, 143, 62, 1, 148, 0, 0, 5, 221, 172, 192, 69, 172, 149, 192, 105, 250, +127, 65, 10, 215, 35, 61, 40, 92, 143, 62, 1, 148, 0, 0, 13, 254, 151, 192, 86, 213, +170, 192, 136, 105, 127, 65, 143, 194, 117, 61, 40, 92, 143, 62, 1, 149, 0, 0, 79, 161, +128, 192, 248, 54, 189, 192, 109, 235, 126, 65, 10, 215, 163, 61, 40, 92, 143, 62, 1, 149, +0, 0, 52, 74, 78, 192, 240, 134, 204, 192, 16, 130, 126, 65, 205, 204, 204, 61, 40, 92, +143, 62, 1, 149, 0, 0, 168, 224, 23, 192, 116, 135, 216, 192, 34, 47, 126, 65, 143, 194, +245, 61, 40, 92, 143, 62, 1, 149, 0, 0, 80, 195, 189, 191, 11, 8, 225, 192, 235, 243, +125, 65, 41, 92, 15, 62, 40, 92, 143, 62, 1, 149, 0, 0, 66, 205, 16, 191, 96, 230, +229, 192, 94, 209, 125, 65, 10, 215, 35, 62, 40, 92, 143, 62, 1, 149, 0, 0, 200, 235, +185, 62, 206, 14, 231, 192, 5, 200, 125, 65, 236, 81, 56, 62, 40, 92, 143, 62, 1, 149, +0, 0, 109, 1, 165, 63, 166, 124, 228, 192, 5, 216, 125, 65, 205, 204, 76, 62, 40, 92, +143, 62, 1, 149, 0, 0, 38, 167, 12, 64, 75, 58, 222, 192, 31, 1, 126, 65, 174, 71, +97, 62, 40, 92, 143, 62, 1, 149, 0, 0, 9, 198, 68, 64, 0, 97, 212, 192, 172, 66, +126, 65, 143, 194, 117, 62, 40, 92, 143, 62, 1, 149, 0, 0, 194, 250, 121, 64, 139, 24, +199, 192, 163, 155, 126, 65, 184, 30, 133, 62, 40, 92, 143, 62, 1, 149, 0, 0, 69, 183, +149, 64, 141, 150, 182, 192, 159, 10, 127, 65, 41, 92, 143, 62, 40, 92, 143, 62, 1, 150, +0, 0, 220, 44, 172, 64, 168, 29, 163, 192, 220, 141, 127, 65, 154, 153, 153, 62, 40, 92, +143, 62, 1, 150, 0, 0, 121, 3, 192, 64, 122, 252, 140, 192, 167, 17, 128, 65, 10, 215, +163, 62, 40, 92, 143, 62, 1, 150, 0, 0, 5, 235, 208, 64, 189, 24, 105, 192, 74, 100, +128, 65, 123, 20, 174, 62, 40, 92, 143, 62, 1, 150, 0, 0, 63, 159, 222, 64, 246, 95, +52, 192, 138, 189, 128, 65, 236, 81, 184, 62, 40, 92, 143, 62, 1, 150, 0, 0, 213, 232, +232, 64, 246, 70, 249, 191, 0, 28, 129, 65, 92, 143, 194, 62, 40, 92, 143, 62, 1, 150, +0, 0, 63, 158, 239, 64, 169, 136, 133, 191, 46, 126, 129, 65, 205, 204, 204, 62, 40, 92, +143, 62, 1, 150, 0, 0, 102, 164, 242, 64, 56, 133, 245, 189, 135, 226, 129, 65, 61, 10, +215, 62, 40, 92, 143, 62, 1, 150, 0, 0, 17, 239, 241, 64, 241, 217, 78, 63, 118, 71, +130, 65, 174, 71, 225, 62, 40, 92, 143, 62, 1, 150, 0, 0, 36, 129, 237, 64, 155, 231, +220, 63, 100, 171, 130, 65, 31, 133, 235, 62, 40, 92, 143, 62, 1, 150, 0, 0, 125, 108, +229, 64, 178, 158, 39, 64, 190, 12, 131, 65, 143, 194, 245, 62, 40, 92, 143, 62, 1, 151, +0, 0, 183, 209, 217, 64, 80, 80, 94, 64, 250, 105, 131, 65, 0, 0, 0, 63, 40, 92, +143, 62, 1, 151, 0, 0, 181, 223, 202, 64, 239, 213, 136, 64, 159, 193, 131, 65, 184, 30, +5, 63, 40, 92, 143, 62, 1, 151, 0, 0, 198, 210, 184, 64, 2, 113, 160, 64, 77, 18, +132, 65, 113, 61, 10, 63, 40, 92, 143, 62, 1, 151, 0, 0, 205, 243, 163, 64, 19, 154, +181, 64, 189, 90, 132, 65, 41, 92, 15, 63, 40, 92, 143, 62, 1, 151, 0, 0, 13, 151, +140, 64, 179, 251, 199, 64, 203, 153, 132, 65, 225, 122, 20, 63, 40, 92, 143, 62, 1, 151, +0, 0, 181, 53, 102, 64, 173, 75, 215, 64, 120, 206, 132, 65, 154, 153, 25, 63, 40, 92, +143, 62, 1, 151, 0, 0, 41, 204, 47, 64, 50, 76, 227, 64, 240, 247, 132, 65, 82, 184, +30, 63, 40, 92, 143, 62, 1, 151, 0, 0, 82, 154, 237, 63, 199, 204, 235, 64, 139, 21, +133, 65, 10, 215, 35, 63, 40, 92, 143, 62, 1, 151, 0, 0, 70, 123, 112, 63, 27, 171, +240, 64, 210, 38, 133, 65, 195, 245, 40, 63, 40, 92, 143, 62, 1, 151, 0, 0, 230, 7, +46, 60, 139, 211, 241, 64, 127, 43, 133, 65, 123, 20, 46, 63, 40, 92, 143, 62, 1, 151, +0, 0, 214, 84, 106, 191, 97, 65, 239, 64, 127, 35, 133, 65, 51, 51, 51, 63, 40, 92, +143, 62, 1, 152, 0, 0, 75, 119, 233, 191, 6, 255, 232, 64, 242, 14, 133, 65, 236, 81, +56, 63, 40, 92, 143, 62, 1, 152, 0, 0, 136, 218, 44, 192, 190, 37, 223, 64, 43, 238, +132, 65, 164, 112, 61, 63, 40, 92, 143, 62, 1, 152, 0, 0, 65, 15, 98, 192, 70, 221, +209, 64, 175, 193, 132, 65, 92, 143, 66, 63, 40, 92, 143, 62, 1, 152, 0, 0, 133, 193, +137, 192, 70, 91, 193, 64, 50, 138, 132, 65, 20, 174, 71, 63, 40, 92, 143, 62, 1, 152, +0, 0, 28, 55, 160, 192, 99, 226, 173, 64, 147, 72, 132, 65, 205, 204, 76, 63, 40, 92, +143, 62, 1, 152, 0, 0, 185, 13, 180, 192, 53, 193, 151, 64, 219, 253, 131, 65, 133, 235, +81, 63, 40, 92, 143, 62, 1, 152, 0, 0, 67, 245, 196, 192, 47, 162, 126, 64, 55, 171, +131, 65, 61, 10, 87, 63, 40, 92, 143, 62, 1, 152, 0, 0, 126, 169, 210, 192, 104, 233, +73, 64, 247, 81, 131, 65, 246, 40, 92, 63, 40, 92, 143, 62, 1, 152, 0, 0, 21, 243, +220, 192, 237, 44, 18, 64, 129, 243, 130, 65, 174, 71, 97, 63, 40, 92, 143, 62, 1, 152, +0, 0, 124, 168, 227, 192, 141, 155, 176, 63, 83, 145, 130, 65, 102, 102, 102, 63, 40, 92, +143, 62, 1, 152, 0, 0, 163, 174, 230, 192, 189, 172, 233, 62, 250, 44, 130, 65, 31, 133, +107, 63, 40, 92, 143, 62, 1, 153, 0, 0, 81, 249, 229, 192, 81, 104, 241, 190, 11, 200, +129, 65, 215, 163, 112, 63, 40, 92, 143, 62, 1, 153, 0, 0, 97, 139, 225, 192, 191, 212, +177, 191, 29, 100, 129, 65, 143, 194, 117, 63, 40, 92, 143, 62, 1, 153, 0, 0, 184, 118, +217, 192, 60, 21, 18, 192, 195, 2, 129, 65, 72, 225, 122, 63, 40, 92, 143, 62, 1, 153, +0, 0, 247, 219, 205, 192, 214, 198, 72, 192, 136, 165, 128, 65, 0, 0, 128, 63, 40, 92, +143, 62, 1, 153, 0, 0, 88, 42, 226, 192, 249, 186, 89, 192, 122, 111, 113, 65, 0, 0, +0, 128, 10, 215, 163, 62, 1, 153, 0, 0, 203, 201, 209, 192, 8, 1, 137, 192, 99, 175, +112, 65, 10, 215, 163, 60, 10, 215, 163, 62, 1, 153, 0, 0, 50, 2, 190, 192, 7, 223, +162, 192, 147, 254, 111, 65, 10, 215, 35, 61, 10, 215, 163, 62, 1, 153, 0, 0, 96, 35, +167, 192, 12, 15, 186, 192, 210, 95, 111, 65, 143, 194, 117, 61, 10, 215, 163, 62, 1, 153, +0, 0, 173, 137, 141, 192, 120, 51, 206, 192, 160, 213, 110, 65, 10, 215, 163, 61, 10, 215, +163, 62, 1, 153, 0, 0, 231, 56, 99, 192, 253, 250, 222, 192, 47, 98, 110, 65, 205, 204, +204, 61, 10, 215, 163, 62, 1, 154, 0, 0, 238, 152, 39, 192, 213, 33, 236, 192, 77, 7, +110, 65, 143, 194, 245, 61, 10, 215, 163, 62, 1, 154, 0, 0, 56, 72, 210, 191, 239, 114, +245, 192, 107, 198, 109, 65, 41, 92, 15, 62, 10, 215, 163, 62, 1, 154, 0, 0, 150, 90, +35, 191, 170, 200, 250, 192, 141, 160, 109, 65, 10, 215, 35, 62, 10, 215, 163, 62, 1, 154, +0, 0, 66, 95, 194, 62, 126, 13, 252, 192, 79, 150, 109, 65, 236, 81, 56, 62, 10, 215, +163, 62, 1, 154, 0, 0, 20, 121, 178, 63, 75, 60, 249, 192, 215, 167, 109, 65, 205, 204, +76, 62, 10, 215, 163, 62, 1, 154, 0, 0, 23, 245, 24, 64, 112, 96, 242, 192, 225, 212, +109, 65, 174, 71, 97, 62, 10, 215, 163, 62, 1, 154, 0, 0, 79, 116, 86, 64, 154, 149, +231, 192, 183, 28, 110, 65, 143, 194, 117, 62, 10, 215, 163, 62, 1, 154, 0, 0, 242, 96, +136, 64, 100, 7, 217, 192, 51, 126, 110, 65, 184, 30, 133, 62, 10, 215, 163, 62, 1, 154, +0, 0, 60, 121, 163, 64, 139, 240, 198, 192, 208, 247, 110, 65, 41, 92, 143, 62, 10, 215, +163, 62, 1, 154, 0, 0, 163, 21, 188, 64, 26, 154, 177, 192, 161, 135, 111, 65, 154, 153, +153, 62, 10, 215, 163, 62, 1, 154, 0, 0, 198, 210, 209, 64, 52, 90, 153, 192, 99, 43, +112, 65, 10, 215, 163, 62, 10, 215, 163, 62, 1, 155, 0, 0, 228, 88, 228, 64, 129, 37, +125, 192, 126, 224, 112, 65, 123, 20, 174, 62, 10, 215, 163, 62, 1, 155, 0, 0, 53, 93, +243, 64, 192, 95, 67, 192, 25, 164, 113, 65, 236, 81, 184, 62, 10, 215, 163, 62, 1, 155, +0, 0, 24, 163, 254, 64, 98, 76, 6, 192, 30, 115, 114, 65, 92, 143, 194, 62, 10, 215, +163, 62, 1, 155, 0, 0, 131, 254, 2, 65, 223, 195, 141, 191, 73, 74, 115, 65, 205, 204, +204, 62, 10, 215, 163, 62, 1, 155, 0, 0, 171, 166, 4, 65, 170, 15, 196, 189, 53, 38, +116, 65, 61, 10, 215, 62, 10, 215, 163, 62, 1, 155, 0, 0, 82, 67, 4, 65, 50, 202, +107, 63, 107, 3, 117, 65, 174, 71, 225, 62, 10, 215, 163, 62, 1, 155, 0, 0, 12, 214, +1, 65, 228, 160, 246, 63, 108, 222, 117, 65, 31, 133, 235, 62, 10, 215, 163, 62, 1, 155, +0, 0, 66, 209, 250, 64, 86, 245, 57, 64, 198, 179, 118, 65, 143, 194, 245, 62, 10, 215, +163, 62, 1, 155, 0, 0, 227, 25, 238, 64, 75, 228, 117, 64, 26, 128, 119, 65, 0, 0, +0, 63, 10, 215, 163, 62, 1, 155, 0, 0, 88, 185, 221, 64, 177, 21, 151, 64, 49, 64, +120, 65, 184, 30, 5, 63, 10, 215, 163, 62, 1, 155, 0, 0, 189, 241, 201, 64, 176, 243, +176, 64, 1, 241, 120, 65, 113, 61, 10, 63, 10, 215, 163, 62, 1, 156, 0, 0, 234, 18, +179, 64, 181, 35, 200, 64, 194, 143, 121, 65, 41, 92, 15, 63, 10, 215, 163, 62, 1, 156, +0, 0, 56, 121, 153, 64, 33, 72, 220, 64, 243, 25, 122, 65, 225, 122, 20, 63, 10, 215, +163, 62, 1, 156, 0, 0, 1, 24, 123, 64, 163, 15, 237, 64, 101, 141, 122, 65, 154, 153, +25, 63, 10, 215, 163, 62, 1, 156, 0, 0, 3, 120, 63, 64, 126, 54, 250, 64, 71, 232, +122, 65, 82, 184, 30, 63, 10, 215, 163, 62, 1, 156, 0, 0, 54, 3, 1, 64, 204, 195, +1, 65, 41, 41, 123, 65, 10, 215, 35, 63, 10, 215, 163, 62, 1, 156, 0, 0, 118, 107, +129, 63, 170, 110, 4, 65, 6, 79, 123, 65, 195, 245, 40, 63, 10, 215, 163, 62, 1, 156, +0, 0, 34, 165, 217, 187, 20, 17, 5, 65, 69, 89, 123, 65, 123, 20, 46, 63, 10, 215, +163, 62, 1, 156, 0, 0, 233, 186, 130, 191, 121, 168, 3, 65, 188, 71, 123, 65, 51, 51, +51, 63, 10, 215, 163, 62, 1, 156, 0, 0, 1, 22, 1, 192, 139, 58, 0, 65, 179, 26, +123, 65, 236, 81, 56, 63, 10, 215, 163, 62, 1, 156, 0, 0, 54, 149, 62, 192, 65, 170, +245, 64, 222, 210, 122, 65, 164, 112, 61, 63, 10, 215, 163, 62, 1, 157, 0, 0, 206, 226, +120, 192, 8, 28, 231, 64, 97, 113, 122, 65, 92, 143, 66, 63, 10, 215, 163, 62, 1, 157, +0, 0, 177, 137, 151, 192, 47, 5, 213, 64, 196, 247, 121, 65, 20, 174, 71, 63, 10, 215, +163, 62, 1, 157, 0, 0, 22, 38, 176, 192, 188, 174, 191, 64, 243, 103, 121, 65, 205, 204, +76, 63, 10, 215, 163, 62, 1, 157, 0, 0, 59, 227, 197, 192, 217, 110, 167, 64, 50, 196, +120, 65, 133, 235, 81, 63, 10, 215, 163, 62, 1, 157, 0, 0, 87, 105, 216, 192, 103, 167, +140, 64, 22, 15, 120, 65, 61, 10, 87, 63, 10, 215, 163, 62, 1, 157, 0, 0, 171, 109, +231, 192, 13, 137, 95, 64, 123, 75, 119, 65, 246, 40, 92, 63, 10, 215, 163, 62, 1, 157, +0, 0, 137, 179, 242, 192, 167, 117, 34, 64, 118, 124, 118, 65, 174, 71, 97, 63, 10, 215, +163, 62, 1, 157, 0, 0, 122, 13, 250, 192, 114, 22, 198, 63, 75, 165, 117, 65, 102, 102, +102, 63, 10, 215, 163, 62, 1, 157, 0, 0, 200, 93, 253, 192, 28, 39, 9, 63, 95, 201, +116, 65, 31, 133, 107, 63, 10, 215, 163, 62, 1, 157, 0, 0, 24, 151, 252, 192, 23, 74, +246, 190, 42, 236, 115, 65, 215, 163, 112, 63, 10, 215, 163, 62, 1, 157, 0, 0, 136, 188, +247, 192, 81, 78, 190, 191, 40, 17, 115, 65, 143, 194, 117, 63, 10, 215, 163, 62, 1, 158, +0, 0, 179, 225, 238, 192, 12, 204, 29, 192, 206, 59, 114, 65, 72, 225, 122, 63, 10, 215, +163, 62, 1, 158, 0, 0, 88, 42, 226, 192, 249, 186, 89, 192, 122, 111, 113, 65, 0, 0, +128, 63, 10, 215, 163, 62, 1, 158, 0, 0, 204, 207, 242, 192, 181, 192, 102, 192, 32, 84, +96, 65, 0, 0, 0, 128, 236, 81, 184, 62, 1, 158, 0, 0, 217, 66, 225, 192, 16, 136, +145, 192, 70, 134, 95, 65, 10, 215, 163, 60, 236, 81, 184, 62, 1, 158, 0, 0, 105, 16, +204, 192, 139, 64, 173, 192, 202, 200, 94, 65, 10, 215, 35, 61, 236, 81, 184, 62, 1, 158, +0, 0, 19, 142, 179, 192, 229, 25, 198, 192, 169, 30, 94, 65, 143, 194, 117, 61, 236, 81, +184, 62, 1, 158, 0, 0, 199, 30, 152, 192, 205, 175, 219, 192, 145, 138, 93, 65, 10, 215, +163, 61, 236, 81, 184, 62, 1, 158, 0, 0, 149, 98, 116, 192, 25, 171, 237, 192, 217, 14, +93, 65, 205, 204, 204, 61, 236, 81, 184, 62, 1, 158, 0, 0, 225, 124, 52, 192, 53, 195, +251, 192, 117, 173, 92, 65, 143, 194, 245, 61, 236, 81, 184, 62, 1, 158, 0, 0, 218, 28, +227, 191, 154, 223, 2, 193, 236, 103, 92, 65, 41, 92, 15, 62, 236, 81, 184, 62, 1, 158, +0, 0, 167, 149, 50, 191, 102, 187, 5, 193, 88, 63, 92, 65, 10, 215, 35, 62, 236, 81, +184, 62, 1, 159, 0, 0, 75, 63, 201, 62, 113, 105, 6, 193, 94, 52, 92, 65, 236, 81, +56, 62, 236, 81, 184, 62, 1, 159, 0, 0, 132, 127, 189, 63, 1, 231, 4, 193, 40, 71, +92, 65, 205, 204, 76, 62, 236, 81, 184, 62, 1, 159, 0, 0, 45, 9, 35, 64, 44, 58, +1, 193, 108, 119, 92, 65, 174, 71, 97, 62, 236, 81, 184, 62, 1, 159, 0, 0, 116, 240, +100, 64, 141, 227, 246, 192, 102, 196, 92, 65, 143, 194, 117, 62, 236, 81, 184, 62, 1, 159, +0, 0, 191, 181, 145, 64, 86, 74, 231, 192, 224, 44, 93, 65, 184, 30, 133, 62, 236, 81, +184, 62, 1, 159, 0, 0, 14, 191, 174, 64, 171, 231, 211, 192, 51, 175, 93, 65, 41, 92, +143, 62, 236, 81, 184, 62, 1, 159, 0, 0, 228, 30, 201, 64, 210, 9, 189, 192, 83, 73, +94, 65, 154, 153, 153, 62, 236, 81, 184, 62, 1, 159, 0, 0, 205, 106, 224, 64, 30, 13, +163, 192, 208, 248, 94, 65, 10, 215, 163, 62, 236, 81, 184, 62, 1, 159, 0, 0, 183, 68, +244, 64, 115, 90, 134, 192, 229, 186, 95, 65, 123, 20, 174, 62, 236, 81, 184, 62, 1, 243, +0, 0, 62, 46, 2, 65, 100, 203, 78, 192, 133, 140, 96, 65, 236, 81, 184, 62, 236, 81, +184, 62, 1, 243, 0, 0, 147, 56, 8, 65, 176, 87, 13, 192, 96, 106, 97, 65, 92, 143, +194, 62, 236, 81, 184, 62, 1, 243, 0, 0, 247, 40, 12, 65, 252, 195, 146, 191, 244, 80, +98, 65, 205, 204, 204, 62, 236, 81, 184, 62, 1, 243, 0, 0, 131, 239, 13, 65, 60, 45, +127, 189, 163, 60, 99, 65, 61, 10, 215, 62, 236, 81, 184, 62, 1, 243, 0, 0, 12, 133, +13, 65, 2, 128, 131, 63, 179, 41, 100, 65, 174, 71, 225, 62, 236, 81, 184, 62, 1, 243, +0, 0, 64, 235, 10, 65, 153, 186, 6, 64, 101, 20, 101, 65, 31, 133, 235, 62, 236, 81, +184, 62, 1, 243, 0, 0, 159, 44, 6, 65, 148, 220, 73, 64, 8, 249, 101, 65, 143, 194, +245, 62, 236, 81, 184, 62, 1, 243, 0, 0, 160, 184, 254, 64, 120, 11, 133, 64, 1, 212, +102, 65, 0, 0, 0, 63, 236, 81, 184, 62, 1, 243, 0, 0, 172, 43, 237, 64, 43, 51, +163, 64, 218, 161, 103, 65, 184, 30, 5, 63, 236, 81, 184, 62, 1, 243, 0, 0, 60, 249, +215, 64, 169, 235, 190, 64, 87, 95, 104, 65, 113, 61, 10, 63, 236, 81, 184, 62, 1, 244, +0, 0, 228, 118, 191, 64, 2, 197, 215, 64, 120, 9, 105, 65, 41, 92, 15, 63, 236, 81, +184, 62, 1, 244, 0, 0, 152, 7, 164, 64, 232, 90, 237, 64, 143, 157, 105, 65, 225, 122, +20, 63, 236, 81, 184, 62, 1, 244, 0, 0, 28, 26, 134, 64, 52, 86, 255, 64, 71, 25, +106, 65, 154, 153, 25, 63, 236, 81, 184, 62, 1, 244, 0, 0, 131, 78, 76, 64, 40, 183, +6, 65, 172, 122, 106, 65, 82, 184, 30, 63, 236, 81, 184, 62, 1, 244, 0, 0, 11, 96, +9, 64, 40, 181, 11, 65, 53, 192, 106, 65, 10, 215, 35, 63, 236, 81, 184, 62, 1, 244, +0, 0, 32, 238, 136, 63, 243, 144, 14, 65, 200, 232, 106, 65, 195, 245, 40, 63, 236, 81, +184, 62, 1, 244, 0, 0, 154, 35, 171, 188, 255, 62, 15, 65, 195, 243, 106, 65, 123, 20, +46, 63, 236, 81, 184, 62, 1, 244, 0, 0, 64, 220, 141, 191, 142, 188, 13, 65, 249, 224, +106, 65, 51, 51, 51, 63, 236, 81, 184, 62, 1, 244, 0, 0, 134, 55, 11, 192, 184, 15, +10, 65, 181, 176, 106, 65, 236, 81, 56, 63, 236, 81, 184, 62, 1, 244, 0, 0, 205, 30, +77, 192, 83, 71, 4, 65, 187, 99, 106, 65, 164, 112, 61, 63, 236, 81, 184, 62, 1, 244, +0, 0, 238, 204, 133, 192, 111, 245, 248, 64, 65, 251, 105, 65, 92, 143, 66, 63, 236, 81, +184, 62, 1, 245, 0, 0, 59, 214, 162, 192, 197, 146, 229, 64, 237, 120, 105, 65, 20, 174, +71, 63, 236, 81, 184, 62, 1, 245, 0, 0, 19, 54, 189, 192, 236, 180, 206, 64, 206, 222, +104, 65, 205, 204, 76, 63, 236, 81, 184, 62, 1, 245, 0, 0, 249, 129, 212, 192, 53, 184, +180, 64, 81, 47, 104, 65, 133, 235, 81, 63, 236, 81, 184, 62, 1, 245, 0, 0, 228, 91, +232, 192, 140, 5, 152, 64, 59, 109, 103, 65, 61, 10, 87, 63, 236, 81, 184, 62, 1, 245, +0, 0, 168, 115, 248, 192, 150, 33, 114, 64, 156, 155, 102, 65, 246, 40, 92, 63, 236, 81, +184, 62, 1, 245, 0, 0, 41, 68, 2, 193, 222, 173, 48, 64, 194, 189, 101, 65, 174, 71, +97, 63, 236, 81, 184, 62, 1, 245, 0, 0, 141, 52, 6, 193, 97, 112, 217, 63, 44, 215, +100, 65, 102, 102, 102, 63, 236, 81, 184, 62, 1, 245, 0, 0, 25, 251, 7, 193, 157, 75, +29, 63, 126, 235, 99, 65, 31, 133, 107, 63, 236, 81, 184, 62, 1, 245, 0, 0, 162, 144, +7, 193, 119, 78, 243, 190, 111, 254, 98, 65, 215, 163, 112, 63, 236, 81, 184, 62, 1, 245, +0, 0, 215, 246, 4, 193, 214, 200, 198, 191, 188, 19, 98, 65, 143, 194, 117, 63, 236, 81, +184, 62, 1, 245, 0, 0, 52, 56, 0, 193, 102, 134, 38, 192, 25, 47, 97, 65, 72, 225, +122, 63, 236, 81, 184, 62, 1, 246, 0, 0, 204, 207, 242, 192, 181, 192, 102, 192, 32, 84, +96, 65, 0, 0, 128, 63, 236, 81, 184, 62, 1, 246, 0, 0, 32, 137, 255, 192, 119, 163, +111, 192, 19, 62, 78, 65, 0, 0, 0, 128, 204, 204, 204, 62, 1, 246, 0, 0, 158, 22, +237, 192, 218, 131, 151, 192, 180, 101, 77, 65, 10, 215, 163, 60, 204, 204, 204, 62, 1, 246, +0, 0, 238, 206, 214, 192, 233, 166, 180, 192, 138, 158, 76, 65, 10, 215, 35, 61, 204, 204, +204, 62, 1, 246, 0, 0, 7, 12, 189, 192, 74, 197, 206, 192, 183, 235, 75, 65, 143, 194, +117, 61, 204, 204, 204, 62, 1, 246, 0, 0, 229, 53, 160, 192, 132, 117, 229, 192, 15, 80, +75, 65, 10, 215, 163, 61, 204, 204, 204, 62, 1, 246, 0, 0, 249, 192, 128, 192, 255, 91, +248, 192, 5, 206, 74, 65, 205, 204, 204, 61, 204, 204, 204, 62, 1, 246, 0, 0, 125, 88, +62, 192, 58, 150, 3, 193, 166, 103, 74, 65, 143, 194, 245, 61, 204, 204, 204, 62, 1, 246, +0, 0, 47, 253, 239, 191, 134, 213, 8, 193, 144, 30, 74, 65, 41, 92, 15, 62, 204, 204, +204, 62, 1, 246, 0, 0, 28, 65, 62, 191, 181, 214, 11, 193, 234, 243, 73, 65, 10, 215, +35, 62, 204, 204, 204, 62, 1, 247, 0, 0, 93, 112, 206, 62, 166, 141, 12, 193, 95, 232, +73, 65, 236, 81, 56, 62, 204, 204, 204, 62, 1, 247, 0, 0, 71, 232, 197, 63, 119, 247, +10, 193, 32, 252, 73, 65, 205, 204, 76, 62, 204, 204, 204, 62, 1, 247, 0, 0, 182, 186, +42, 64, 142, 26, 7, 193, 219, 46, 74, 65, 174, 71, 97, 62, 204, 204, 204, 62, 1, 247, +0, 0, 248, 255, 111, 64, 134, 6, 1, 193, 196, 127, 74, 65, 143, 194, 117, 62, 204, 204, +204, 62, 1, 247, 0, 0, 31, 214, 152, 64, 208, 167, 241, 192, 148, 237, 74, 65, 184, 30, +133, 62, 204, 204, 204, 62, 1, 247, 0, 0, 54, 91, 183, 64, 153, 71, 221, 192, 144, 118, +75, 65, 41, 92, 143, 62, 204, 204, 204, 62, 1, 247, 0, 0, 3, 20, 211, 64, 169, 62, +197, 192, 143, 24, 76, 65, 154, 153, 153, 62, 204, 204, 204, 62, 1, 247, 0, 0, 161, 144, +235, 64, 13, 238, 169, 192, 3, 209, 76, 65, 10, 215, 163, 62, 204, 204, 204, 62, 1, 247, +0, 0, 23, 55, 0, 65, 9, 196, 139, 192, 4, 157, 77, 65, 123, 20, 174, 62, 204, 204, +204, 62, 1, 247, 0, 0, 59, 172, 8, 65, 201, 116, 86, 192, 89, 121, 78, 65, 236, 81, +184, 62, 204, 204, 204, 62, 1, 247, 0, 0, 145, 5, 15, 65, 252, 168, 17, 192, 137, 98, +79, 65, 92, 143, 194, 62, 204, 204, 204, 62, 1, 248, 0, 0, 121, 41, 19, 65, 218, 116, +148, 191, 230, 84, 80, 65, 205, 204, 204, 62, 204, 204, 204, 62, 1, 248, 0, 0, 63, 7, +21, 65, 161, 187, 164, 188, 159, 76, 81, 65, 61, 10, 215, 62, 204, 204, 204, 62, 1, 248, +0, 0, 87, 151, 20, 65, 192, 6, 144, 63, 203, 69, 82, 65, 174, 71, 225, 62, 204, 204, +204, 62, 1, 248, 0, 0, 135, 219, 17, 65, 48, 132, 16, 64, 124, 60, 83, 65, 31, 133, +235, 62, 204, 204, 204, 62, 1, 248, 0, 0, 215, 222, 12, 65, 64, 20, 87, 64, 205, 44, +84, 65, 143, 194, 245, 62, 204, 204, 204, 62, 1, 248, 0, 0, 104, 181, 5, 65, 85, 75, +141, 64, 246, 18, 85, 65, 0, 0, 0, 63, 204, 204, 204, 62, 1, 248, 0, 0, 79, 248, +248, 64, 116, 253, 172, 64, 84, 235, 85, 65, 184, 30, 5, 63, 204, 204, 204, 62, 1, 248, +0, 0, 161, 176, 226, 64, 132, 32, 202, 64, 127, 178, 86, 65, 113, 61, 10, 63, 204, 204, +204, 62, 1, 248, 0, 0, 181, 237, 200, 64, 228, 62, 228, 64, 81, 101, 87, 65, 41, 92, +15, 63, 204, 204, 204, 62, 1, 248, 0, 0, 150, 23, 172, 64, 30, 239, 250, 64, 250, 0, +88, 65, 225, 122, 20, 63, 204, 204, 204, 62, 1, 248, 0, 0, 167, 162, 140, 64, 205, 234, +6, 65, 4, 131, 88, 65, 154, 153, 25, 63, 204, 204, 204, 62, 1, 249, 0, 0, 223, 27, +86, 64, 7, 83, 14, 65, 99, 233, 88, 65, 82, 184, 30, 63, 204, 204, 204, 62, 1, 249, +0, 0, 244, 193, 15, 64, 82, 146, 19, 65, 121, 50, 89, 65, 10, 215, 35, 63, 204, 204, +204, 62, 1, 249, 0, 0, 72, 167, 142, 63, 129, 147, 22, 65, 31, 93, 89, 65, 195, 245, +40, 63, 204, 204, 204, 62, 1, 249, 0, 0, 159, 170, 2, 189, 114, 74, 23, 65, 169, 104, +89, 65, 123, 20, 46, 63, 204, 204, 204, 62, 1, 249, 0, 0, 141, 97, 150, 191, 67, 180, +21, 65, 233, 84, 89, 65, 51, 51, 51, 63, 204, 204, 204, 62, 1, 249, 0, 0, 85, 247, +18, 192, 90, 215, 17, 65, 46, 34, 89, 65, 236, 81, 56, 63, 204, 204, 204, 62, 1, 249, +0, 0, 151, 60, 88, 192, 82, 195, 11, 65, 69, 209, 88, 65, 164, 112, 61, 63, 204, 204, +204, 62, 1, 249, 0, 0, 113, 244, 140, 192, 180, 144, 3, 65, 118, 99, 88, 65, 92, 143, +66, 63, 204, 204, 204, 62, 1, 249, 0, 0, 133, 121, 171, 192, 47, 193, 242, 64, 120, 218, +87, 65, 20, 174, 71, 63, 204, 204, 204, 62, 1, 249, 0, 0, 83, 50, 199, 192, 65, 184, +218, 64, 121, 56, 87, 65, 205, 204, 76, 63, 204, 204, 204, 62, 1, 250, 0, 0, 241, 174, +223, 192, 163, 103, 191, 64, 5, 128, 86, 65, 133, 235, 81, 63, 204, 204, 204, 62, 1, 250, +0, 0, 126, 140, 244, 192, 159, 61, 161, 64, 5, 180, 85, 65, 61, 10, 87, 63, 204, 204, +204, 62, 1, 250, 0, 0, 96, 187, 2, 193, 248, 179, 128, 64, 176, 215, 84, 65, 246, 40, +92, 63, 204, 204, 204, 62, 1, 250, 0, 0, 183, 20, 9, 193, 40, 156, 60, 64, 128, 238, +83, 65, 174, 71, 97, 63, 204, 204, 204, 62, 1, 250, 0, 0, 160, 56, 13, 193, 41, 91, +234, 63, 34, 252, 82, 65, 102, 102, 102, 63, 204, 204, 204, 62, 1, 98, 0, 0, 102, 22, +15, 193, 124, 242, 48, 63, 106, 4, 82, 65, 31, 133, 107, 63, 204, 204, 204, 62, 1, 98, +0, 0, 127, 166, 14, 193, 195, 129, 232, 190, 62, 11, 81, 65, 215, 163, 112, 63, 204, 204, +204, 62, 1, 98, 0, 0, 173, 234, 11, 193, 16, 34, 203, 191, 141, 20, 80, 65, 143, 194, +117, 63, 204, 204, 204, 62, 1, 99, 0, 0, 253, 237, 6, 193, 20, 33, 44, 192, 59, 36, +79, 65, 72, 225, 122, 63, 204, 204, 204, 62, 1, 99, 0, 0, 32, 137, 255, 192, 119, 163, +111, 192, 19, 62, 78, 65, 0, 0, 128, 63, 204, 204, 204, 62, 1, 99, 0, 0, 120, 17, +4, 193, 91, 63, 116, 192, 86, 118, 59, 65, 0, 0, 0, 128, 174, 71, 225, 62, 1, 99, +0, 0, 91, 21, 245, 192, 62, 220, 154, 192, 221, 150, 58, 65, 10, 215, 163, 60, 174, 71, +225, 62, 1, 99, 0, 0, 96, 18, 222, 192, 65, 244, 184, 192, 41, 201, 57, 65, 10, 215, +35, 61, 174, 71, 225, 62, 1, 99, 0, 0, 230, 118, 195, 192, 49, 238, 211, 192, 119, 16, +57, 65, 143, 194, 117, 61, 174, 71, 225, 62, 1, 99, 0, 0, 92, 174, 165, 192, 37, 93, +235, 192, 178, 111, 56, 65, 10, 215, 163, 61, 174, 71, 225, 62, 1, 99, 0, 0, 253, 48, +133, 192, 132, 226, 254, 192, 99, 233, 55, 65, 205, 204, 204, 61, 174, 71, 225, 62, 1, 99, +0, 0, 239, 3, 69, 192, 193, 23, 7, 193, 167, 127, 55, 65, 143, 194, 245, 61, 174, 71, +225, 62, 1, 99, 0, 0, 70, 181, 248, 191, 42, 131, 12, 193, 43, 52, 55, 65, 41, 92, +15, 62, 174, 71, 225, 62, 1, 99, 0, 0, 182, 45, 70, 191, 154, 157, 15, 193, 30, 8, +55, 65, 10, 215, 35, 62, 174, 71, 225, 62, 1, 100, 0, 0, 60, 221, 209, 62, 141, 90, +16, 193, 51, 252, 54, 65, 236, 81, 56, 62, 174, 71, 225, 62, 1, 100, 0, 0, 96, 145, +203, 63, 7, 183, 14, 193, 153, 16, 55, 65, 205, 204, 76, 62, 174, 71, 225, 62, 1, 100, +0, 0, 163, 234, 47, 64, 167, 185, 10, 193, 254, 68, 55, 65, 174, 71, 97, 62, 174, 71, +225, 62, 1, 100, 0, 0, 54, 118, 119, 64, 133, 114, 4, 193, 143, 152, 55, 65, 143, 194, +117, 62, 174, 71, 225, 62, 1, 100, 0, 0, 72, 165, 157, 64, 249, 245, 247, 192, 251, 9, +56, 65, 184, 30, 133, 62, 174, 71, 225, 62, 1, 100, 0, 0, 239, 42, 189, 64, 121, 234, +226, 192, 119, 151, 56, 65, 41, 92, 143, 62, 174, 71, 225, 62, 1, 100, 0, 0, 201, 204, +217, 64, 125, 23, 202, 192, 200, 62, 57, 65, 154, 153, 153, 62, 174, 71, 225, 62, 1, 100, +0, 0, 64, 23, 243, 64, 65, 225, 173, 192, 74, 253, 57, 65, 10, 215, 163, 62, 174, 71, +225, 62, 1, 100, 0, 0, 26, 82, 4, 65, 168, 185, 142, 192, 254, 207, 58, 65, 123, 20, +174, 62, 174, 71, 225, 62, 1, 100, 0, 0, 85, 14, 13, 65, 247, 60, 90, 192, 143, 179, +59, 65, 236, 81, 184, 62, 174, 71, 225, 62, 1, 101, 0, 0, 11, 157, 19, 65, 216, 46, +19, 192, 103, 164, 60, 65, 92, 143, 194, 62, 174, 71, 225, 62, 1, 101, 0, 0, 195, 227, +23, 65, 141, 207, 146, 191, 186, 158, 61, 65, 205, 204, 204, 62, 174, 71, 225, 62, 1, 101, +0, 0, 57, 209, 25, 65, 69, 43, 247, 60, 149, 158, 62, 65, 61, 10, 215, 62, 174, 71, +225, 62, 1, 101, 0, 0, 165, 93, 25, 65, 195, 70, 155, 63, 240, 159, 63, 65, 174, 71, +225, 62, 174, 71, 225, 62, 1, 101, 0, 0, 218, 138, 22, 65, 178, 133, 24, 64, 186, 158, +64, 65, 31, 133, 235, 62, 174, 71, 225, 62, 1, 101, 0, 0, 60, 100, 17, 65, 241, 102, +97, 64, 241, 150, 65, 65, 143, 194, 245, 62, 174, 71, 225, 62, 1, 101, 0, 0, 154, 254, +9, 65, 113, 144, 147, 64, 168, 132, 66, 65, 0, 0, 0, 63, 174, 71, 225, 62, 1, 101, +0, 0, 207, 119, 0, 65, 3, 77, 180, 64, 33, 100, 67, 65, 184, 30, 5, 63, 174, 71, +225, 62, 1, 101, 0, 0, 162, 236, 233, 64, 4, 101, 210, 64, 214, 49, 68, 65, 113, 61, +10, 63, 174, 71, 225, 62, 1, 101, 0, 0, 43, 81, 207, 64, 242, 94, 237, 64, 136, 234, +68, 65, 41, 92, 15, 63, 174, 71, 225, 62, 1, 101, 0, 0, 158, 136, 177, 64, 245, 102, +2, 65, 77, 139, 69, 65, 225, 122, 20, 63, 174, 71, 225, 62, 1, 102, 0, 0, 65, 11, +145, 64, 164, 41, 12, 65, 156, 17, 70, 65, 154, 153, 25, 63, 174, 71, 225, 62, 1, 102, +0, 0, 115, 184, 92, 64, 34, 208, 19, 65, 87, 123, 70, 65, 82, 184, 30, 63, 174, 71, +225, 62, 1, 102, 0, 0, 40, 15, 20, 64, 138, 59, 25, 65, 212, 198, 70, 65, 10, 215, +35, 63, 174, 71, 225, 62, 1, 102, 0, 0, 229, 127, 146, 63, 251, 85, 28, 65, 225, 242, +70, 65, 195, 245, 40, 63, 174, 71, 225, 62, 1, 102, 0, 0, 168, 200, 33, 189, 239, 18, +29, 65, 204, 254, 70, 65, 123, 20, 46, 63, 174, 71, 225, 62, 1, 102, 0, 0, 86, 40, +156, 191, 103, 111, 27, 65, 102, 234, 70, 65, 51, 51, 51, 63, 174, 71, 225, 62, 1, 102, +0, 0, 34, 54, 24, 192, 7, 114, 23, 65, 0, 182, 70, 65, 236, 81, 56, 63, 174, 71, +225, 62, 1, 102, 0, 0, 177, 193, 95, 192, 229, 42, 17, 65, 111, 98, 70, 65, 164, 112, +61, 63, 174, 71, 225, 62, 1, 102, 0, 0, 8, 203, 145, 192, 94, 179, 8, 65, 4, 241, +69, 65, 92, 143, 66, 63, 174, 71, 225, 62, 1, 102, 0, 0, 173, 80, 177, 192, 56, 91, +252, 64, 136, 99, 69, 65, 20, 174, 71, 63, 174, 71, 225, 62, 1, 102, 0, 0, 136, 242, +205, 192, 60, 136, 227, 64, 55, 188, 68, 65, 205, 204, 76, 63, 174, 71, 225, 62, 1, 103, +0, 0, 253, 60, 231, 192, 0, 82, 199, 64, 180, 253, 67, 65, 133, 235, 81, 63, 174, 71, +225, 62, 1, 103, 0, 0, 243, 201, 252, 192, 103, 42, 168, 64, 1, 43, 67, 65, 61, 10, +87, 63, 174, 71, 225, 62, 1, 103, 0, 0, 52, 33, 7, 193, 61, 143, 134, 64, 112, 71, +66, 65, 246, 40, 92, 63, 174, 71, 225, 62, 1, 103, 0, 0, 234, 175, 13, 193, 86, 16, +70, 64, 151, 86, 65, 65, 174, 71, 97, 63, 174, 71, 225, 62, 1, 103, 0, 0, 161, 246, +17, 193, 138, 146, 248, 63, 68, 92, 64, 65, 102, 102, 102, 63, 174, 71, 225, 62, 1, 103, +0, 0, 23, 228, 19, 193, 142, 204, 67, 63, 105, 92, 63, 65, 31, 133, 107, 63, 174, 71, +225, 62, 1, 103, 0, 0, 131, 112, 19, 193, 61, 15, 214, 190, 15, 91, 62, 65, 215, 163, +112, 63, 174, 71, 225, 62, 1, 103, 0, 0, 183, 157, 16, 193, 111, 72, 203, 191, 68, 92, +61, 65, 143, 194, 117, 63, 174, 71, 225, 62, 1, 103, 0, 0, 26, 119, 11, 193, 115, 133, +46, 192, 14, 100, 60, 65, 72, 225, 122, 63, 174, 71, 225, 62, 1, 103, 0, 0, 120, 17, +4, 193, 91, 63, 116, 192, 86, 118, 59, 65, 0, 0, 128, 63, 174, 71, 225, 62, 1, 104, +0, 0, 69, 61, 6, 193, 199, 129, 116, 192, 190, 72, 40, 65, 0, 0, 0, 128, 144, 194, +245, 62, 1, 104, 0, 0, 203, 30, 249, 192, 190, 131, 155, 192, 176, 101, 39, 65, 10, 215, +163, 60, 144, 194, 245, 62, 1, 104, 0, 0, 108, 189, 225, 192, 49, 23, 186, 192, 175, 148, +38, 65, 10, 215, 35, 61, 144, 194, 245, 62, 1, 104, 0, 0, 206, 180, 198, 192, 199, 127, +213, 192, 8, 217, 37, 65, 143, 194, 117, 61, 144, 194, 245, 62, 1, 104, 0, 0, 23, 114, +168, 192, 221, 78, 237, 192, 175, 53, 37, 65, 10, 215, 163, 61, 144, 194, 245, 62, 1, 104, +0, 0, 118, 111, 135, 192, 40, 146, 0, 193, 57, 173, 36, 65, 205, 204, 204, 61, 144, 194, +245, 62, 1, 104, 0, 0, 86, 100, 72, 192, 9, 88, 8, 193, 204, 65, 36, 65, 143, 194, +245, 61, 144, 194, 245, 62, 1, 104, 0, 0, 238, 33, 253, 191, 172, 217, 13, 193, 26, 245, +35, 65, 41, 92, 15, 62, 144, 194, 245, 62, 1, 104, 0, 0, 155, 59, 74, 191, 216, 0, +17, 193, 89, 200, 35, 65, 10, 215, 35, 62, 144, 194, 245, 62, 1, 104, 0, 0, 70, 120, +211, 62, 210, 192, 17, 193, 60, 188, 35, 65, 236, 81, 56, 62, 144, 194, 245, 62, 1, 104, +0, 0, 233, 99, 206, 63, 147, 22, 16, 193, 246, 208, 35, 65, 205, 204, 76, 62, 144, 194, +245, 62, 1, 105, 0, 0, 2, 132, 50, 64, 212, 8, 12, 193, 50, 6, 36, 65, 174, 71, +97, 62, 144, 194, 245, 62, 1, 105, 0, 0, 17, 53, 123, 64, 243, 167, 5, 193, 27, 91, +36, 65, 143, 194, 117, 62, 144, 194, 245, 62, 1, 105, 0, 0, 212, 15, 160, 64, 95, 27, +250, 192, 87, 206, 36, 65, 184, 30, 133, 62, 144, 194, 245, 62, 1, 105, 0, 0, 200, 22, +192, 64, 138, 185, 228, 192, 24, 94, 37, 65, 41, 92, 143, 62, 144, 194, 245, 62, 1, 105, +0, 0, 20, 46, 221, 64, 187, 128, 203, 192, 23, 8, 38, 65, 154, 153, 153, 62, 144, 194, +245, 62, 1, 105, 0, 0, 72, 224, 246, 64, 197, 214, 174, 192, 167, 201, 38, 65, 10, 215, +163, 62, 144, 194, 245, 62, 1, 105, 0, 0, 210, 98, 6, 65, 96, 47, 143, 192, 187, 159, +39, 65, 123, 20, 174, 62, 144, 194, 245, 62, 1, 105, 0, 0, 226, 66, 15, 65, 186, 20, +90, 192, 241, 134, 40, 65, 236, 81, 184, 62, 144, 194, 245, 62, 1, 105, 0, 0, 126, 236, +21, 65, 34, 227, 17, 192, 165, 123, 41, 65, 92, 143, 194, 62, 144, 194, 245, 62, 1, 105, +0, 0, 192, 68, 26, 65, 215, 218, 141, 191, 251, 121, 42, 65, 205, 204, 204, 62, 144, 194, +245, 62, 1, 105, 0, 0, 31, 58, 28, 65, 82, 183, 179, 61, 240, 125, 43, 65, 61, 10, +215, 62, 144, 194, 245, 62, 1, 106, 0, 0, 177, 196, 27, 65, 169, 18, 165, 63, 107, 131, +44, 65, 174, 71, 225, 62, 144, 194, 245, 62, 1, 106, 0, 0, 80, 230, 24, 65, 207, 158, +30, 64, 74, 134, 45, 65, 31, 133, 235, 62, 144, 194, 245, 62, 1, 106, 0, 0, 146, 170, +19, 65, 0, 171, 104, 64, 122, 130, 46, 65, 143, 194, 245, 62, 144, 194, 245, 62, 1, 106, +0, 0, 152, 38, 12, 65, 123, 193, 151, 64, 1, 116, 47, 65, 0, 0, 0, 63, 144, 194, +245, 62, 1, 106, 0, 0, 185, 120, 2, 65, 85, 4, 185, 64, 15, 87, 48, 65, 184, 30, +5, 63, 144, 194, 245, 62, 1, 106, 0, 0, 19, 144, 237, 64, 200, 151, 215, 64, 15, 40, +49, 65, 113, 61, 10, 63, 144, 194, 245, 62, 1, 106, 0, 0, 116, 135, 210, 64, 94, 0, +243, 64, 183, 227, 49, 65, 41, 92, 15, 63, 144, 194, 245, 62, 1, 106, 0, 0, 189, 68, +180, 64, 186, 103, 5, 65, 15, 135, 50, 65, 225, 122, 20, 63, 144, 194, 245, 62, 1, 106, +0, 0, 26, 66, 147, 64, 115, 82, 15, 65, 133, 15, 51, 65, 154, 153, 25, 63, 144, 194, +245, 62, 1, 106, 0, 0, 158, 9, 96, 64, 83, 24, 23, 65, 242, 122, 51, 65, 82, 184, +30, 63, 144, 194, 245, 62, 1, 107, 0, 0, 63, 54, 22, 64, 246, 153, 28, 65, 164, 199, +51, 65, 10, 215, 35, 63, 144, 194, 245, 62, 1, 107, 0, 0, 94, 104, 148, 63, 34, 193, +31, 65, 102, 244, 51, 65, 195, 245, 40, 63, 144, 194, 245, 62, 1, 107, 0, 0, 42, 112, +50, 189, 28, 129, 32, 65, 130, 0, 52, 65, 123, 20, 46, 63, 144, 194, 245, 62, 1, 107, +0, 0, 97, 25, 159, 191, 221, 214, 30, 65, 200, 235, 51, 65, 51, 51, 51, 63, 144, 194, +245, 62, 1, 107, 0, 0, 185, 222, 26, 192, 31, 201, 26, 65, 140, 182, 51, 65, 236, 81, +56, 63, 144, 194, 245, 62, 1, 107, 0, 0, 197, 143, 99, 192, 61, 104, 20, 65, 164, 97, +51, 65, 164, 112, 61, 63, 144, 194, 245, 62, 1, 107, 0, 0, 48, 61, 148, 192, 249, 205, +11, 65, 103, 238, 50, 65, 92, 143, 66, 63, 144, 194, 245, 62, 1, 107, 0, 0, 34, 68, +180, 192, 14, 29, 1, 65, 166, 94, 50, 65, 20, 174, 71, 63, 144, 194, 245, 62, 1, 107, +0, 0, 110, 91, 209, 192, 77, 1, 233, 64, 167, 180, 49, 65, 205, 204, 76, 63, 144, 194, +245, 62, 1, 107, 0, 0, 164, 13, 235, 192, 88, 87, 204, 64, 23, 243, 48, 65, 133, 235, +81, 63, 144, 194, 245, 62, 1, 107, 0, 0, 127, 121, 0, 193, 243, 175, 172, 64, 4, 29, +48, 65, 61, 10, 87, 63, 144, 194, 245, 62, 1, 108, 0, 0, 143, 89, 9, 193, 238, 138, +138, 64, 205, 53, 47, 65, 246, 40, 92, 63, 144, 194, 245, 62, 1, 108, 0, 0, 43, 3, +16, 193, 67, 228, 76, 64, 25, 65, 46, 65, 174, 71, 97, 63, 144, 194, 245, 62, 1, 108, +0, 0, 109, 91, 20, 193, 145, 238, 1, 64, 195, 66, 45, 65, 102, 102, 102, 63, 144, 194, +245, 62, 1, 108, 0, 0, 203, 80, 22, 193, 155, 141, 85, 63, 206, 62, 44, 65, 31, 133, +107, 63, 144, 194, 245, 62, 1, 108, 0, 0, 92, 219, 21, 193, 120, 65, 188, 190, 84, 57, +43, 65, 215, 163, 112, 63, 144, 194, 245, 62, 1, 108, 0, 0, 252, 252, 18, 193, 84, 59, +199, 191, 116, 54, 42, 65, 143, 194, 117, 63, 144, 194, 245, 62, 1, 108, 0, 0, 62, 193, +13, 193, 223, 169, 45, 192, 68, 58, 41, 65, 72, 225, 122, 63, 144, 194, 245, 62, 1, 108, +0, 0, 69, 61, 6, 193, 199, 129, 116, 192, 190, 72, 40, 65, 0, 0, 128, 63, 144, 194, +245, 62, 1, 108, 0, 0, 48, 63, 6, 193, 177, 105, 112, 192, 182, 2, 21, 65, 0, 0, +0, 128, 184, 30, 5, 63, 1, 108, 0, 0, 163, 34, 249, 192, 177, 119, 153, 192, 168, 31, +20, 65, 10, 215, 163, 60, 184, 30, 5, 63, 1, 108, 0, 0, 66, 193, 225, 192, 36, 11, +184, 192, 167, 78, 19, 65, 10, 215, 35, 61, 184, 30, 5, 63, 1, 109, 0, 0, 166, 184, +198, 192, 189, 115, 211, 192, 0, 147, 18, 65, 143, 194, 117, 61, 184, 30, 5, 63, 1, 109, +0, 0, 239, 117, 168, 192, 210, 66, 235, 192, 167, 239, 17, 65, 10, 215, 163, 61, 184, 30, +5, 63, 1, 109, 0, 0, 75, 115, 135, 192, 70, 24, 255, 192, 49, 103, 17, 65, 205, 204, +204, 61, 184, 30, 5, 63, 1, 109, 0, 0, 1, 108, 72, 192, 3, 82, 7, 193, 196, 251, +16, 65, 143, 194, 245, 61, 184, 30, 5, 63, 1, 109, 0, 0, 68, 49, 253, 191, 166, 211, +12, 193, 18, 175, 16, 65, 41, 92, 15, 62, 184, 30, 5, 63, 1, 109, 0, 0, 71, 90, +74, 191, 210, 250, 15, 193, 81, 130, 16, 65, 10, 215, 35, 62, 184, 30, 5, 63, 1, 109, +0, 0, 239, 58, 211, 62, 204, 186, 16, 193, 52, 118, 16, 65, 236, 81, 56, 62, 184, 30, +5, 63, 1, 109, 0, 0, 147, 84, 206, 63, 141, 16, 15, 193, 238, 138, 16, 65, 205, 204, +76, 62, 184, 30, 5, 63, 1, 109, 0, 0, 87, 124, 50, 64, 207, 2, 11, 193, 43, 192, +16, 65, 174, 71, 97, 62, 184, 30, 5, 63, 1, 109, 0, 0, 98, 45, 123, 64, 237, 161, +4, 193, 19, 21, 17, 65, 143, 194, 117, 62, 184, 30, 5, 63, 1, 110, 0, 0, 254, 11, +160, 64, 84, 15, 248, 192, 79, 136, 17, 65, 184, 30, 133, 62, 184, 30, 5, 63, 1, 110, +0, 0, 243, 18, 192, 64, 128, 173, 226, 192, 15, 24, 18, 65, 41, 92, 143, 62, 184, 30, +5, 63, 1, 110, 0, 0, 63, 42, 221, 64, 176, 116, 201, 192, 15, 194, 18, 65, 154, 153, +153, 62, 184, 30, 5, 63, 1, 110, 0, 0, 114, 220, 246, 64, 184, 202, 172, 192, 159, 131, +19, 65, 10, 215, 163, 62, 184, 30, 5, 63, 1, 110, 0, 0, 231, 96, 6, 65, 85, 35, +141, 192, 179, 89, 20, 65, 123, 20, 174, 62, 184, 30, 5, 63, 1, 110, 0, 0, 247, 64, +15, 65, 160, 252, 85, 192, 233, 64, 21, 65, 236, 81, 184, 62, 184, 30, 5, 63, 1, 110, +0, 0, 147, 234, 21, 65, 8, 203, 13, 192, 157, 53, 22, 65, 92, 143, 194, 62, 184, 30, +5, 63, 1, 110, 0, 0, 213, 66, 26, 65, 172, 170, 133, 191, 243, 51, 23, 65, 205, 204, +204, 62, 184, 30, 5, 63, 1, 110, 0, 0, 52, 56, 28, 65, 70, 93, 27, 62, 232, 55, +24, 65, 61, 10, 215, 62, 184, 30, 5, 63, 1, 110, 0, 0, 198, 194, 27, 65, 213, 66, +173, 63, 98, 61, 25, 65, 174, 71, 225, 62, 184, 30, 5, 63, 1, 110, 0, 0, 101, 228, +24, 65, 229, 182, 34, 64, 66, 64, 26, 65, 31, 133, 235, 62, 184, 30, 5, 63, 1, 111, +0, 0, 167, 168, 19, 65, 26, 195, 108, 64, 114, 60, 27, 65, 143, 194, 245, 62, 184, 30, +5, 63, 1, 111, 0, 0, 173, 36, 12, 65, 133, 205, 153, 64, 249, 45, 28, 65, 0, 0, +0, 63, 184, 30, 5, 63, 1, 111, 0, 0, 207, 118, 2, 65, 98, 16, 187, 64, 7, 17, +29, 65, 184, 30, 5, 63, 184, 30, 5, 63, 1, 111, 0, 0, 59, 140, 237, 64, 211, 163, +217, 64, 7, 226, 29, 65, 113, 61, 10, 63, 184, 30, 5, 63, 1, 111, 0, 0, 159, 131, +210, 64, 107, 12, 245, 64, 174, 157, 30, 65, 41, 92, 15, 63, 184, 30, 5, 63, 1, 111, +0, 0, 232, 64, 180, 64, 192, 109, 6, 65, 7, 65, 31, 65, 225, 122, 20, 63, 184, 30, +5, 63, 1, 111, 0, 0, 68, 62, 147, 64, 122, 88, 16, 65, 125, 201, 31, 65, 154, 153, +25, 63, 184, 30, 5, 63, 1, 111, 0, 0, 239, 1, 96, 64, 89, 30, 24, 65, 234, 52, +32, 65, 82, 184, 30, 63, 184, 30, 5, 63, 1, 111, 0, 0, 148, 46, 22, 64, 252, 159, +29, 65, 156, 129, 32, 65, 10, 215, 35, 63, 184, 30, 5, 63, 1, 111, 0, 0, 8, 89, +148, 63, 40, 199, 32, 65, 94, 174, 32, 65, 195, 245, 40, 63, 184, 30, 5, 63, 1, 111, +0, 0, 230, 90, 52, 189, 34, 135, 33, 65, 123, 186, 32, 65, 123, 20, 46, 63, 184, 30, +5, 63, 1, 112, 0, 0, 174, 40, 159, 191, 227, 220, 31, 65, 192, 165, 32, 65, 51, 51, +51, 63, 184, 30, 5, 63, 1, 112, 0, 0, 100, 230, 26, 192, 36, 207, 27, 65, 132, 112, +32, 65, 236, 81, 56, 63, 184, 30, 5, 63, 1, 112, 0, 0, 112, 151, 99, 192, 67, 110, +21, 65, 156, 27, 32, 65, 164, 112, 61, 63, 184, 30, 5, 63, 1, 112, 0, 0, 5, 65, +148, 192, 255, 211, 12, 65, 95, 168, 31, 65, 92, 143, 66, 63, 184, 30, 5, 63, 1, 112, +0, 0, 247, 71, 180, 192, 20, 35, 2, 65, 159, 24, 31, 65, 20, 174, 71, 63, 184, 30, +5, 63, 1, 112, 0, 0, 70, 95, 209, 192, 88, 13, 235, 64, 159, 110, 30, 65, 205, 204, +76, 63, 184, 30, 5, 63, 1, 112, 0, 0, 121, 17, 235, 192, 99, 99, 206, 64, 15, 173, +29, 65, 133, 235, 81, 63, 184, 30, 5, 63, 1, 112, 0, 0, 106, 123, 0, 193, 0, 188, +174, 64, 252, 214, 28, 65, 61, 10, 87, 63, 184, 30, 5, 63, 1, 112, 0, 0, 122, 91, +9, 193, 248, 150, 140, 64, 196, 239, 27, 65, 246, 40, 92, 63, 184, 30, 5, 63, 1, 112, +0, 0, 23, 5, 16, 193, 89, 252, 80, 64, 18, 251, 26, 65, 174, 71, 97, 63, 184, 30, +5, 63, 1, 113, 0, 0, 88, 93, 20, 193, 167, 6, 6, 64, 187, 252, 25, 65, 102, 102, +102, 63, 184, 30, 5, 63, 1, 113, 0, 0, 182, 82, 22, 193, 242, 237, 101, 63, 198, 248, +24, 65, 31, 133, 107, 63, 184, 30, 5, 63, 1, 113, 0, 0, 71, 221, 21, 193, 203, 128, +155, 190, 76, 243, 23, 65, 215, 163, 112, 63, 184, 30, 5, 63, 1, 113, 0, 0, 231, 254, +18, 193, 40, 11, 191, 191, 108, 240, 22, 65, 143, 194, 117, 63, 184, 30, 5, 63, 1, 113, +0, 0, 42, 195, 13, 193, 201, 145, 41, 192, 60, 244, 21, 65, 72, 225, 122, 63, 184, 30, +5, 63, 1, 113, 0, 0, 48, 63, 6, 193, 177, 105, 112, 192, 182, 2, 21, 65, 0, 0, +128, 63, 184, 30, 5, 63, 1, 113, 0, 0, 50, 23, 4, 193, 154, 7, 104, 192, 14, 242, +1, 65, 0, 0, 0, 128, 41, 92, 15, 63, 1, 113, 0, 0, 205, 32, 245, 192, 95, 192, +148, 192, 149, 18, 1, 65, 10, 215, 163, 60, 41, 92, 15, 63, 1, 113, 0, 0, 210, 29, +222, 192, 96, 216, 178, 192, 224, 68, 0, 65, 10, 215, 35, 61, 41, 92, 15, 63, 1, 113, +0, 0, 90, 130, 195, 192, 80, 210, 205, 192, 93, 24, 255, 64, 143, 194, 117, 61, 41, 92, +15, 63, 1, 113, 0, 0, 208, 185, 165, 192, 70, 65, 229, 192, 212, 214, 253, 64, 10, 215, +163, 61, 41, 92, 15, 63, 1, 114, 0, 0, 113, 60, 133, 192, 168, 198, 248, 192, 52, 202, +252, 64, 205, 204, 204, 61, 41, 92, 15, 63, 1, 114, 0, 0, 210, 26, 69, 192, 209, 9, +4, 193, 190, 246, 251, 64, 143, 194, 245, 61, 41, 92, 15, 63, 1, 114, 0, 0, 13, 227, +248, 191, 58, 117, 9, 193, 198, 95, 251, 64, 41, 92, 15, 62, 41, 92, 15, 63, 1, 114, +0, 0, 68, 137, 70, 191, 171, 143, 12, 193, 173, 7, 251, 64, 10, 215, 35, 62, 41, 92, +15, 63, 1, 114, 0, 0, 32, 38, 209, 62, 158, 76, 13, 193, 212, 239, 250, 64, 236, 81, +56, 62, 41, 92, 15, 63, 1, 114, 0, 0, 153, 99, 203, 63, 24, 169, 11, 193, 160, 24, +251, 64, 205, 204, 76, 62, 41, 92, 15, 63, 1, 114, 0, 0, 187, 211, 47, 64, 183, 171, +7, 193, 109, 129, 251, 64, 174, 71, 97, 62, 41, 92, 15, 63, 1, 114, 0, 0, 82, 95, +119, 64, 149, 100, 1, 193, 143, 40, 252, 64, 143, 194, 117, 62, 41, 92, 15, 63, 1, 114, +0, 0, 214, 153, 157, 64, 27, 218, 241, 192, 101, 11, 253, 64, 184, 30, 133, 62, 41, 92, +15, 63, 1, 114, 0, 0, 125, 31, 189, 64, 154, 206, 220, 192, 93, 38, 254, 64, 41, 92, +143, 62, 41, 92, 15, 63, 1, 114, 0, 0, 87, 193, 217, 64, 158, 251, 195, 192, 0, 117, +255, 64, 154, 153, 153, 62, 41, 92, 15, 63, 1, 115, 0, 0, 206, 11, 243, 64, 99, 197, +167, 192, 2, 121, 0, 65, 10, 215, 163, 62, 41, 92, 15, 63, 1, 115, 0, 0, 97, 76, +4, 65, 201, 157, 136, 192, 182, 75, 1, 65, 123, 20, 174, 62, 41, 92, 15, 63, 1, 115, +0, 0, 156, 8, 13, 65, 62, 5, 78, 192, 71, 47, 2, 65, 236, 81, 184, 62, 41, 92, +15, 63, 1, 115, 0, 0, 82, 151, 19, 65, 26, 247, 6, 192, 31, 32, 3, 65, 92, 143, +194, 62, 41, 92, 15, 63, 1, 115, 0, 0, 10, 222, 23, 65, 39, 192, 116, 191, 114, 26, +4, 65, 205, 204, 204, 62, 41, 92, 15, 63, 1, 115, 0, 0, 128, 203, 25, 65, 57, 97, +98, 62, 77, 26, 5, 65, 61, 10, 215, 62, 41, 92, 15, 63, 1, 115, 0, 0, 236, 87, +25, 65, 70, 182, 179, 63, 168, 27, 6, 65, 174, 71, 225, 62, 41, 92, 15, 63, 1, 115, +0, 0, 32, 133, 22, 65, 111, 189, 36, 64, 114, 26, 7, 65, 31, 133, 235, 62, 41, 92, +15, 63, 1, 115, 0, 0, 131, 94, 17, 65, 174, 158, 109, 64, 168, 18, 8, 65, 143, 194, +245, 62, 41, 92, 15, 63, 1, 115, 0, 0, 225, 248, 9, 65, 79, 172, 153, 64, 96, 0, +9, 65, 0, 0, 0, 63, 41, 92, 15, 63, 1, 116, 0, 0, 21, 114, 0, 65, 226, 104, +186, 64, 217, 223, 9, 65, 184, 30, 5, 63, 41, 92, 15, 63, 1, 116, 0, 0, 49, 225, +233, 64, 226, 128, 216, 64, 142, 173, 10, 65, 113, 61, 10, 63, 41, 92, 15, 63, 1, 116, +0, 0, 183, 69, 207, 64, 209, 122, 243, 64, 64, 102, 11, 65, 41, 92, 15, 63, 41, 92, +15, 63, 1, 116, 0, 0, 44, 125, 177, 64, 228, 116, 5, 65, 5, 7, 12, 65, 225, 122, +20, 63, 41, 92, 15, 63, 1, 116, 0, 0, 206, 255, 144, 64, 148, 55, 15, 65, 84, 141, +12, 65, 154, 153, 25, 63, 41, 92, 15, 63, 1, 116, 0, 0, 144, 161, 92, 64, 17, 222, +22, 65, 15, 247, 12, 65, 82, 184, 30, 63, 41, 92, 15, 63, 1, 116, 0, 0, 64, 248, +19, 64, 121, 73, 28, 65, 140, 66, 13, 65, 10, 215, 35, 63, 41, 92, 15, 63, 1, 116, +0, 0, 21, 82, 146, 63, 234, 99, 31, 65, 152, 110, 13, 65, 195, 245, 40, 63, 41, 92, +15, 63, 1, 116, 0, 0, 144, 130, 39, 189, 221, 32, 32, 65, 132, 122, 13, 65, 123, 20, +46, 63, 41, 92, 15, 63, 1, 116, 0, 0, 29, 86, 156, 191, 87, 125, 30, 65, 30, 102, +13, 65, 51, 51, 51, 63, 41, 92, 15, 63, 1, 116, 0, 0, 5, 77, 24, 192, 247, 127, +26, 65, 184, 49, 13, 65, 236, 81, 56, 63, 41, 92, 15, 63, 1, 117, 0, 0, 153, 216, +95, 192, 213, 56, 20, 65, 39, 222, 12, 65, 164, 112, 61, 63, 41, 92, 15, 63, 1, 117, +0, 0, 122, 214, 145, 192, 77, 193, 11, 65, 187, 108, 12, 65, 92, 143, 66, 63, 41, 92, +15, 63, 1, 117, 0, 0, 30, 92, 177, 192, 139, 59, 1, 65, 64, 223, 11, 65, 20, 174, +71, 63, 41, 92, 15, 63, 1, 117, 0, 0, 250, 253, 205, 192, 28, 164, 233, 64, 239, 55, +11, 65, 205, 204, 76, 63, 41, 92, 15, 63, 1, 117, 0, 0, 111, 72, 231, 192, 223, 109, +205, 64, 108, 121, 10, 65, 133, 235, 81, 63, 41, 92, 15, 63, 1, 117, 0, 0, 101, 213, +252, 192, 69, 70, 174, 64, 185, 166, 9, 65, 61, 10, 87, 63, 41, 92, 15, 63, 1, 117, +0, 0, 238, 38, 7, 193, 27, 171, 140, 64, 39, 195, 8, 65, 246, 40, 92, 63, 41, 92, +15, 63, 1, 117, 0, 0, 163, 181, 13, 193, 19, 72, 82, 64, 79, 210, 7, 65, 174, 71, +97, 63, 41, 92, 15, 63, 1, 117, 0, 0, 90, 252, 17, 193, 2, 129, 8, 64, 252, 215, +6, 65, 102, 102, 102, 63, 41, 92, 15, 63, 1, 117, 0, 0, 208, 233, 19, 193, 130, 171, +116, 63, 33, 216, 5, 65, 31, 133, 107, 63, 41, 92, 15, 63, 1, 117, 0, 0, 60, 118, +19, 193, 169, 162, 104, 190, 198, 214, 4, 65, 215, 163, 112, 63, 41, 92, 15, 63, 1, 118, +0, 0, 112, 163, 16, 193, 237, 216, 178, 191, 252, 215, 3, 65, 143, 194, 117, 63, 41, 92, +15, 63, 1, 118, 0, 0, 211, 124, 11, 193, 182, 77, 34, 192, 198, 223, 2, 65, 72, 225, +122, 63, 41, 92, 15, 63, 1, 118, 0, 0, 50, 23, 4, 193, 154, 7, 104, 192, 14, 242, +1, 65, 0, 0, 128, 63, 41, 92, 15, 63, 1, 118, 0, 0, 0, 156, 255, 192, 99, 125, +91, 192, 130, 199, 222, 64, 0, 0, 0, 128, 154, 153, 25, 63, 1, 118, 0, 0, 124, 41, +237, 192, 208, 112, 141, 192, 196, 22, 221, 64, 10, 215, 163, 60, 154, 153, 25, 63, 1, 118, +0, 0, 206, 225, 214, 192, 224, 147, 170, 192, 110, 136, 219, 64, 10, 215, 35, 61, 154, 153, +25, 63, 1, 118, 0, 0, 230, 30, 189, 192, 64, 178, 196, 192, 203, 34, 218, 64, 143, 194, +117, 61, 154, 153, 25, 63, 1, 118, 0, 0, 197, 72, 160, 192, 122, 98, 219, 192, 121, 235, +216, 64, 10, 215, 163, 61, 154, 153, 25, 63, 1, 118, 0, 0, 216, 211, 128, 192, 249, 72, +238, 192, 100, 231, 215, 64, 205, 204, 204, 61, 154, 153, 25, 63, 1, 118, 0, 0, 61, 126, +62, 192, 105, 25, 253, 192, 168, 26, 215, 64, 143, 194, 245, 61, 154, 153, 25, 63, 1, 119, +0, 0, 174, 72, 240, 191, 1, 204, 3, 193, 125, 136, 214, 64, 41, 92, 15, 62, 154, 153, +25, 63, 1, 119, 0, 0, 27, 216, 62, 191, 48, 205, 6, 193, 47, 51, 214, 64, 10, 215, +35, 62, 154, 153, 25, 63, 1, 119, 0, 0, 62, 66, 205, 62, 33, 132, 7, 193, 25, 28, +214, 64, 236, 81, 56, 62, 154, 153, 25, 63, 1, 119, 0, 0, 199, 156, 197, 63, 242, 237, +5, 193, 156, 67, 214, 64, 205, 204, 76, 62, 154, 153, 25, 63, 1, 119, 0, 0, 242, 148, +42, 64, 10, 17, 2, 193, 17, 169, 214, 64, 174, 71, 97, 62, 154, 153, 25, 63, 1, 119, +0, 0, 56, 218, 111, 64, 3, 250, 247, 192, 226, 74, 215, 64, 143, 194, 117, 62, 154, 153, +25, 63, 1, 119, 0, 0, 61, 195, 152, 64, 200, 148, 231, 192, 131, 38, 216, 64, 184, 30, +133, 62, 154, 153, 25, 63, 1, 119, 0, 0, 84, 72, 183, 64, 145, 52, 211, 192, 124, 56, +217, 64, 41, 92, 143, 62, 154, 153, 25, 63, 1, 119, 0, 0, 33, 1, 211, 64, 161, 43, +187, 192, 122, 124, 218, 64, 154, 153, 153, 62, 154, 153, 25, 63, 1, 119, 0, 0, 191, 125, +235, 64, 5, 219, 159, 192, 97, 237, 219, 64, 10, 215, 163, 62, 154, 153, 25, 63, 1, 119, +0, 0, 166, 45, 0, 65, 255, 176, 129, 192, 100, 133, 221, 64, 123, 20, 174, 62, 154, 153, +25, 63, 1, 120, 0, 0, 201, 162, 8, 65, 181, 78, 66, 192, 14, 62, 223, 64, 236, 81, +184, 62, 154, 153, 25, 63, 1, 120, 0, 0, 30, 252, 14, 65, 217, 5, 251, 191, 109, 16, +225, 64, 92, 143, 194, 62, 154, 153, 25, 63, 1, 120, 0, 0, 8, 32, 19, 65, 101, 81, +88, 191, 39, 245, 226, 64, 205, 204, 204, 62, 154, 153, 25, 63, 1, 120, 0, 0, 206, 253, +20, 65, 193, 228, 150, 62, 153, 228, 228, 64, 61, 10, 215, 62, 154, 153, 25, 63, 1, 120, +0, 0, 230, 141, 20, 65, 223, 82, 184, 63, 241, 214, 230, 64, 174, 71, 225, 62, 154, 153, +25, 63, 1, 120, 0, 0, 23, 210, 17, 65, 63, 170, 36, 64, 82, 196, 232, 64, 31, 133, +235, 62, 154, 153, 25, 63, 1, 120, 0, 0, 102, 213, 12, 65, 80, 58, 107, 64, 246, 164, +234, 64, 143, 194, 245, 62, 154, 153, 25, 63, 1, 120, 0, 0, 248, 171, 5, 65, 93, 94, +151, 64, 71, 113, 236, 64, 0, 0, 0, 63, 154, 153, 25, 63, 1, 120, 0, 0, 109, 229, +248, 64, 123, 16, 183, 64, 3, 34, 238, 64, 184, 30, 5, 63, 154, 153, 25, 63, 1, 120, +0, 0, 191, 157, 226, 64, 139, 51, 212, 64, 89, 176, 239, 64, 113, 61, 10, 63, 154, 153, +25, 63, 1, 120, 0, 0, 213, 218, 200, 64, 233, 81, 238, 64, 255, 21, 241, 64, 41, 92, +15, 63, 154, 153, 25, 63, 1, 121, 0, 0, 182, 4, 172, 64, 19, 129, 2, 65, 79, 77, +242, 64, 225, 122, 20, 63, 154, 153, 25, 63, 1, 121, 0, 0, 199, 143, 140, 64, 81, 244, +11, 65, 99, 81, 243, 64, 154, 153, 25, 63, 154, 153, 25, 63, 1, 121, 0, 0, 27, 246, +85, 64, 138, 92, 19, 65, 33, 30, 244, 64, 82, 184, 30, 63, 154, 153, 25, 63, 1, 121, +0, 0, 52, 156, 15, 64, 213, 155, 24, 65, 77, 176, 244, 64, 10, 215, 35, 63, 154, 153, +25, 63, 1, 121, 0, 0, 200, 91, 142, 63, 4, 157, 27, 65, 152, 5, 245, 64, 195, 245, +40, 63, 154, 153, 25, 63, 1, 121, 0, 0, 139, 26, 12, 189, 245, 83, 28, 65, 174, 28, +245, 64, 123, 20, 46, 63, 154, 153, 25, 63, 1, 121, 0, 0, 12, 173, 150, 191, 198, 189, +26, 65, 46, 245, 244, 64, 51, 51, 51, 63, 154, 153, 25, 63, 1, 121, 0, 0, 25, 29, +19, 192, 222, 224, 22, 65, 184, 143, 244, 64, 236, 81, 56, 63, 154, 153, 25, 63, 1, 121, +0, 0, 90, 98, 88, 192, 214, 204, 16, 65, 229, 237, 243, 64, 164, 112, 61, 63, 154, 153, +25, 63, 1, 121, 0, 0, 81, 7, 141, 192, 56, 154, 8, 65, 71, 18, 243, 64, 92, 143, +66, 63, 154, 153, 25, 63, 1, 122, 0, 0, 101, 140, 171, 192, 55, 212, 252, 64, 75, 0, +242, 64, 20, 174, 71, 63, 154, 153, 25, 63, 1, 122, 0, 0, 51, 69, 199, 192, 73, 203, +228, 64, 79, 188, 240, 64, 205, 204, 76, 63, 154, 153, 25, 63, 1, 122, 0, 0, 209, 193, +223, 192, 171, 122, 201, 64, 102, 75, 239, 64, 133, 235, 81, 63, 154, 153, 25, 63, 1, 122, +0, 0, 94, 159, 244, 192, 166, 80, 171, 64, 102, 179, 237, 64, 61, 10, 87, 63, 154, 153, +25, 63, 1, 122, 0, 0, 208, 196, 2, 193, 2, 199, 138, 64, 188, 250, 235, 64, 246, 40, +92, 63, 154, 153, 25, 63, 1, 122, 0, 0, 38, 30, 9, 193, 55, 194, 80, 64, 91, 40, +234, 64, 174, 71, 97, 63, 154, 153, 25, 63, 1, 122, 0, 0, 16, 66, 13, 193, 164, 83, +9, 64, 160, 67, 232, 64, 102, 102, 102, 63, 154, 153, 25, 63, 1, 122, 0, 0, 212, 31, +15, 193, 101, 197, 128, 63, 46, 84, 230, 64, 31, 133, 107, 63, 154, 153, 25, 63, 1, 122, +0, 0, 238, 175, 14, 193, 144, 162, 14, 190, 214, 97, 228, 64, 215, 163, 112, 63, 154, 153, +25, 63, 1, 122, 0, 0, 29, 244, 11, 193, 233, 213, 162, 191, 117, 116, 226, 64, 143, 194, +117, 63, 154, 153, 25, 63, 1, 122, 0, 0, 108, 247, 6, 193, 5, 251, 23, 192, 209, 147, +224, 64, 72, 225, 122, 63, 154, 153, 25, 63, 1, 123, 0, 0, 0, 156, 255, 192, 99, 125, +91, 192, 130, 199, 222, 64, 0, 0, 128, 63, 154, 153, 25, 63, 1, 123, 0, 0, 207, 233, +242, 192, 168, 253, 74, 192, 107, 69, 187, 64, 0, 0, 0, 128, 10, 215, 35, 63, 1, 123, +0, 0, 217, 92, 225, 192, 137, 166, 131, 192, 185, 169, 185, 64, 10, 215, 163, 60, 10, 215, +35, 63, 1, 123, 0, 0, 107, 42, 204, 192, 5, 95, 159, 192, 192, 46, 184, 64, 10, 215, +35, 61, 10, 215, 35, 63, 1, 123, 0, 0, 19, 168, 179, 192, 97, 56, 184, 192, 127, 218, +182, 64, 143, 194, 117, 61, 10, 215, 35, 63, 1, 123, 0, 0, 199, 56, 152, 192, 70, 206, +205, 192, 81, 178, 181, 64, 10, 215, 163, 61, 10, 215, 35, 63, 1, 123, 0, 0, 154, 150, +116, 192, 147, 201, 223, 192, 224, 186, 180, 64, 205, 204, 204, 61, 10, 215, 35, 63, 1, 123, +0, 0, 230, 176, 52, 192, 174, 225, 237, 192, 20, 248, 179, 64, 143, 194, 245, 61, 10, 215, +35, 63, 1, 123, 0, 0, 220, 132, 227, 191, 175, 221, 247, 192, 5, 109, 179, 64, 41, 92, +15, 62, 10, 215, 35, 63, 1, 123, 0, 0, 186, 101, 51, 191, 68, 149, 253, 192, 220, 27, +179, 64, 10, 215, 35, 62, 10, 215, 35, 63, 1, 123, 0, 0, 35, 159, 199, 62, 94, 241, +254, 192, 232, 5, 179, 64, 236, 81, 56, 62, 10, 215, 35, 63, 1, 124, 0, 0, 122, 23, +189, 63, 125, 236, 251, 192, 126, 43, 179, 64, 205, 204, 76, 62, 10, 215, 35, 63, 1, 124, +0, 0, 40, 213, 34, 64, 207, 146, 244, 192, 5, 140, 179, 64, 174, 71, 97, 62, 10, 215, +35, 63, 1, 124, 0, 0, 106, 188, 100, 64, 6, 2, 233, 192, 248, 37, 180, 64, 143, 194, +117, 62, 10, 215, 35, 63, 1, 124, 0, 0, 189, 155, 145, 64, 207, 104, 217, 192, 236, 246, +180, 64, 184, 30, 133, 62, 10, 215, 35, 63, 1, 124, 0, 0, 9, 165, 174, 64, 37, 6, +198, 192, 148, 251, 181, 64, 41, 92, 143, 62, 10, 215, 35, 63, 1, 124, 0, 0, 224, 4, +201, 64, 76, 40, 175, 192, 211, 47, 183, 64, 154, 153, 153, 62, 10, 215, 35, 63, 1, 124, +0, 0, 200, 80, 224, 64, 149, 43, 149, 192, 203, 142, 184, 64, 10, 215, 163, 62, 10, 215, +35, 63, 1, 124, 0, 0, 178, 42, 244, 64, 216, 241, 112, 192, 249, 18, 186, 64, 123, 20, +174, 62, 10, 215, 35, 63, 1, 124, 0, 0, 59, 33, 2, 65, 91, 8, 51, 192, 53, 182, +187, 64, 236, 81, 184, 62, 10, 215, 35, 63, 1, 124, 0, 0, 145, 43, 8, 65, 69, 41, +227, 191, 235, 113, 189, 64, 92, 143, 194, 62, 10, 215, 35, 63, 1, 125, 0, 0, 245, 27, +12, 65, 213, 123, 54, 191, 22, 63, 191, 64, 205, 204, 204, 62, 10, 215, 35, 63, 1, 125, +0, 0, 129, 226, 13, 65, 160, 50, 190, 62, 112, 22, 193, 64, 61, 10, 215, 62, 10, 215, +35, 63, 1, 125, 0, 0, 10, 120, 13, 65, 20, 6, 187, 63, 145, 240, 194, 64, 174, 71, +225, 62, 10, 215, 35, 63, 1, 125, 0, 0, 62, 222, 10, 65, 162, 125, 34, 64, 246, 197, +196, 64, 31, 133, 235, 62, 10, 215, 35, 63, 1, 125, 0, 0, 157, 31, 6, 65, 161, 159, +101, 64, 61, 143, 198, 64, 143, 194, 245, 62, 10, 215, 35, 63, 1, 125, 0, 0, 155, 158, +254, 64, 253, 236, 146, 64, 46, 69, 200, 64, 0, 0, 0, 63, 10, 215, 35, 63, 1, 125, +0, 0, 167, 17, 237, 64, 177, 20, 177, 64, 225, 224, 201, 64, 184, 30, 5, 63, 10, 215, +35, 63, 1, 125, 0, 0, 55, 223, 215, 64, 45, 205, 204, 64, 217, 91, 203, 64, 113, 61, +10, 63, 10, 215, 35, 63, 1, 125, 0, 0, 223, 92, 191, 64, 137, 166, 229, 64, 29, 176, +204, 64, 41, 92, 15, 63, 10, 215, 35, 63, 1, 125, 0, 0, 150, 237, 163, 64, 111, 60, +251, 64, 75, 216, 205, 64, 225, 122, 20, 63, 10, 215, 35, 63, 1, 125, 0, 0, 25, 0, +134, 64, 223, 155, 6, 65, 188, 207, 206, 64, 154, 153, 25, 63, 10, 215, 35, 63, 1, 126, +0, 0, 126, 26, 76, 64, 234, 167, 13, 65, 132, 146, 207, 64, 82, 184, 30, 63, 10, 215, +35, 63, 1, 126, 0, 0, 6, 44, 9, 64, 234, 165, 18, 65, 151, 29, 208, 64, 10, 215, +35, 63, 10, 215, 35, 63, 1, 126, 0, 0, 14, 134, 136, 63, 181, 129, 21, 65, 189, 110, +208, 64, 195, 245, 40, 63, 10, 215, 35, 63, 1, 126, 0, 0, 15, 38, 197, 188, 194, 47, +22, 65, 180, 132, 208, 64, 123, 20, 46, 63, 10, 215, 35, 63, 1, 126, 0, 0, 74, 68, +142, 191, 81, 173, 20, 65, 30, 95, 208, 64, 51, 51, 51, 63, 10, 215, 35, 63, 1, 126, +0, 0, 139, 107, 11, 192, 122, 0, 17, 65, 149, 254, 207, 64, 236, 81, 56, 63, 10, 215, +35, 63, 1, 126, 0, 0, 210, 82, 77, 192, 21, 56, 11, 65, 161, 100, 207, 64, 164, 112, +61, 63, 10, 215, 35, 63, 1, 126, 0, 0, 241, 230, 133, 192, 121, 107, 3, 65, 173, 147, +206, 64, 92, 143, 66, 63, 10, 215, 35, 63, 1, 126, 0, 0, 61, 240, 162, 192, 73, 116, +243, 64, 6, 143, 205, 64, 20, 174, 71, 63, 10, 215, 35, 63, 1, 126, 0, 0, 20, 80, +189, 192, 112, 150, 220, 64, 201, 90, 204, 64, 205, 204, 76, 63, 10, 215, 35, 63, 1, 126, +0, 0, 252, 155, 212, 192, 185, 153, 194, 64, 206, 251, 202, 64, 133, 235, 81, 63, 10, 215, +35, 63, 1, 127, 0, 0, 228, 117, 232, 192, 16, 231, 165, 64, 163, 119, 201, 64, 61, 10, +87, 63, 10, 215, 35, 63, 1, 127, 0, 0, 170, 141, 248, 192, 80, 242, 134, 64, 101, 212, +199, 64, 246, 40, 92, 63, 10, 215, 35, 63, 1, 127, 0, 0, 42, 81, 2, 193, 231, 112, +76, 64, 177, 24, 198, 64, 174, 71, 97, 63, 10, 215, 35, 63, 1, 127, 0, 0, 141, 65, +6, 193, 57, 123, 8, 64, 134, 75, 196, 64, 102, 102, 102, 63, 10, 215, 35, 63, 1, 127, +0, 0, 26, 8, 8, 193, 224, 43, 134, 63, 40, 116, 194, 64, 31, 133, 107, 63, 10, 215, +35, 63, 1, 127, 0, 0, 163, 157, 7, 193, 117, 177, 41, 189, 11, 154, 192, 64, 215, 163, +112, 63, 10, 215, 35, 63, 1, 127, 0, 0, 215, 3, 5, 193, 187, 66, 143, 191, 164, 196, +190, 64, 143, 194, 117, 63, 10, 215, 35, 63, 1, 127, 0, 0, 53, 69, 0, 193, 89, 195, +10, 192, 93, 251, 188, 64, 72, 225, 122, 63, 10, 215, 35, 63, 1, 127, 0, 0, 207, 233, +242, 192, 168, 253, 74, 192, 107, 69, 187, 64, 0, 0, 128, 63, 10, 215, 35, 63, 1, 196, +0, 0, 18, 75, 226, 192, 8, 203, 54, 192, 57, 237, 153, 64, 0, 0, 0, 128, 123, 20, +46, 63, 1, 196, 0, 0, 135, 234, 209, 192, 31, 18, 111, 192, 13, 109, 152, 64, 10, 215, +163, 60, 123, 20, 46, 63, 1, 196, 0, 0, 236, 34, 190, 192, 14, 103, 145, 192, 107, 11, +151, 64, 10, 215, 35, 61, 123, 20, 46, 63, 1, 196, 0, 0, 26, 68, 167, 192, 20, 151, +168, 192, 234, 205, 149, 64, 143, 194, 117, 61, 123, 20, 46, 63, 1, 196, 0, 0, 103, 170, +141, 192, 128, 187, 188, 192, 136, 185, 148, 64, 10, 215, 163, 61, 123, 20, 46, 63, 1, 196, +0, 0, 95, 122, 99, 192, 2, 131, 205, 192, 164, 210, 147, 64, 205, 204, 204, 61, 123, 20, +46, 63, 1, 197, 0, 0, 98, 218, 39, 192, 220, 169, 218, 192, 224, 28, 147, 64, 143, 194, +245, 61, 123, 20, 46, 63, 1, 197, 0, 0, 41, 203, 210, 191, 246, 250, 227, 192, 27, 155, +146, 64, 41, 92, 15, 62, 123, 20, 46, 63, 1, 197, 0, 0, 103, 96, 36, 191, 179, 80, +233, 192, 97, 79, 146, 64, 10, 215, 35, 62, 123, 20, 46, 63, 1, 197, 0, 0, 126, 83, +192, 62, 131, 149, 234, 192, 228, 58, 146, 64, 236, 81, 56, 62, 123, 20, 46, 63, 1, 197, +0, 0, 35, 246, 177, 63, 80, 196, 231, 192, 246, 93, 146, 64, 205, 204, 76, 62, 123, 20, +46, 63, 1, 197, 0, 0, 158, 179, 24, 64, 117, 232, 224, 192, 9, 184, 146, 64, 174, 71, +97, 62, 123, 20, 46, 63, 1, 197, 0, 0, 215, 50, 86, 64, 161, 29, 214, 192, 176, 71, +147, 64, 143, 194, 117, 62, 123, 20, 46, 63, 1, 197, 0, 0, 53, 64, 136, 64, 105, 143, +199, 192, 173, 10, 148, 64, 184, 30, 133, 62, 123, 20, 46, 63, 1, 197, 0, 0, 128, 88, +163, 64, 146, 120, 181, 192, 231, 253, 148, 64, 41, 92, 143, 62, 123, 20, 46, 63, 1, 197, +0, 0, 228, 244, 187, 64, 31, 34, 160, 192, 136, 29, 150, 64, 154, 153, 153, 62, 123, 20, +46, 63, 1, 197, 0, 0, 7, 178, 209, 64, 57, 226, 135, 192, 10, 101, 151, 64, 10, 215, +163, 62, 123, 20, 46, 63, 1, 198, 0, 0, 40, 56, 228, 64, 147, 53, 90, 192, 68, 207, +152, 64, 123, 20, 174, 62, 123, 20, 46, 63, 1, 198, 0, 0, 121, 60, 243, 64, 206, 111, +32, 192, 122, 86, 154, 64, 236, 81, 184, 62, 123, 20, 46, 63, 1, 198, 0, 0, 90, 130, +254, 64, 216, 184, 198, 191, 130, 244, 155, 64, 92, 143, 194, 62, 123, 20, 46, 63, 1, 198, +0, 0, 38, 238, 2, 65, 247, 199, 15, 191, 215, 162, 157, 64, 205, 204, 204, 62, 123, 20, +46, 63, 1, 198, 0, 0, 77, 150, 4, 65, 162, 123, 230, 62, 175, 90, 159, 64, 61, 10, +215, 62, 123, 20, 46, 63, 1, 198, 0, 0, 244, 50, 4, 65, 252, 196, 187, 63, 26, 21, +161, 64, 174, 71, 225, 62, 123, 20, 46, 63, 1, 198, 0, 0, 172, 197, 1, 65, 95, 64, +30, 64, 31, 203, 162, 64, 31, 133, 235, 62, 123, 20, 46, 63, 1, 198, 0, 0, 131, 176, +250, 64, 71, 229, 92, 64, 209, 117, 164, 64, 143, 194, 245, 62, 123, 20, 46, 63, 1, 198, +0, 0, 39, 249, 237, 64, 31, 106, 140, 64, 122, 14, 166, 64, 0, 0, 0, 63, 123, 20, +46, 63, 1, 198, 0, 0, 156, 152, 221, 64, 170, 141, 168, 64, 168, 142, 167, 64, 184, 30, +5, 63, 123, 20, 46, 63, 1, 199, 0, 0, 255, 208, 201, 64, 169, 107, 194, 64, 74, 240, +168, 64, 113, 61, 10, 63, 123, 20, 46, 63, 1, 199, 0, 0, 44, 242, 178, 64, 172, 155, +217, 64, 203, 45, 170, 64, 41, 92, 15, 63, 123, 20, 46, 63, 1, 199, 0, 0, 123, 88, +153, 64, 24, 192, 237, 64, 45, 66, 171, 64, 225, 122, 20, 63, 123, 20, 46, 63, 1, 199, +0, 0, 132, 214, 122, 64, 156, 135, 254, 64, 17, 41, 172, 64, 154, 153, 25, 63, 123, 20, +46, 63, 1, 199, 0, 0, 139, 54, 63, 64, 60, 215, 5, 65, 213, 222, 172, 64, 82, 184, +30, 63, 123, 20, 46, 63, 1, 199, 0, 0, 185, 193, 0, 64, 200, 127, 10, 65, 154, 96, +173, 64, 10, 215, 35, 63, 123, 20, 46, 63, 1, 199, 0, 0, 125, 232, 128, 63, 165, 42, +13, 65, 84, 172, 173, 64, 195, 245, 40, 63, 123, 20, 46, 63, 1, 199, 0, 0, 208, 70, +46, 188, 14, 205, 13, 65, 209, 192, 173, 64, 123, 20, 46, 63, 123, 20, 46, 63, 1, 199, +0, 0, 217, 61, 131, 191, 116, 100, 12, 65, 191, 157, 173, 64, 51, 51, 51, 63, 123, 20, +46, 63, 1, 199, 0, 0, 121, 87, 1, 192, 134, 246, 8, 65, 173, 67, 173, 64, 236, 81, +56, 63, 123, 20, 46, 63, 1, 199, 0, 0, 174, 214, 62, 192, 29, 145, 3, 65, 3, 180, +172, 64, 164, 112, 61, 63, 123, 20, 46, 63, 1, 200, 0, 0, 66, 36, 121, 192, 1, 148, +248, 64, 6, 241, 171, 64, 92, 143, 66, 63, 123, 20, 46, 63, 1, 200, 0, 0, 107, 170, +151, 192, 40, 125, 230, 64, 206, 253, 170, 64, 20, 174, 71, 63, 123, 20, 46, 63, 1, 200, +0, 0, 210, 70, 176, 192, 181, 38, 209, 64, 45, 222, 169, 64, 205, 204, 76, 63, 123, 20, +46, 63, 1, 200, 0, 0, 245, 3, 198, 192, 207, 230, 184, 64, 171, 150, 168, 64, 133, 235, +81, 63, 123, 20, 46, 63, 1, 200, 0, 0, 19, 138, 216, 192, 94, 31, 158, 64, 113, 44, +167, 64, 61, 10, 87, 63, 123, 20, 46, 63, 1, 200, 0, 0, 101, 142, 231, 192, 125, 60, +129, 64, 60, 165, 165, 64, 246, 40, 92, 63, 123, 20, 46, 63, 1, 200, 0, 0, 69, 212, +242, 192, 153, 101, 69, 64, 51, 7, 164, 64, 174, 71, 97, 63, 123, 20, 46, 63, 1, 200, +0, 0, 54, 46, 250, 192, 43, 251, 5, 64, 220, 88, 162, 64, 102, 102, 102, 63, 123, 20, +46, 63, 1, 200, 0, 0, 132, 126, 253, 192, 113, 115, 138, 63, 4, 161, 160, 64, 31, 133, +107, 63, 123, 20, 46, 63, 1, 200, 0, 0, 210, 183, 252, 192, 216, 213, 132, 61, 155, 230, +158, 64, 215, 163, 112, 63, 123, 20, 46, 63, 1, 200, 0, 0, 66, 221, 247, 192, 219, 220, +112, 191, 150, 48, 157, 64, 143, 194, 117, 63, 123, 20, 46, 63, 1, 201, 0, 0, 109, 2, +239, 192, 44, 184, 245, 191, 226, 133, 155, 64, 72, 225, 122, 63, 123, 20, 46, 63, 1, 201, +0, 0, 18, 75, 226, 192, 8, 203, 54, 192, 57, 237, 153, 64, 0, 0, 128, 63, 123, 20, +46, 63, 1, 201, 0, 0, 228, 2, 206, 192, 9, 55, 31, 192, 17, 139, 118, 64, 0, 0, +0, 128, 236, 81, 56, 63, 1, 201, 0, 0, 224, 16, 191, 192, 150, 146, 82, 192, 230, 205, +115, 64, 10, 215, 163, 60, 236, 81, 56, 63, 1, 201, 0, 0, 243, 3, 173, 192, 94, 228, +128, 192, 119, 72, 113, 64, 10, 215, 35, 61, 236, 81, 56, 63, 1, 201, 0, 0, 253, 36, +152, 192, 111, 13, 150, 192, 247, 4, 111, 64, 143, 194, 117, 61, 236, 81, 56, 63, 1, 201, +0, 0, 63, 200, 128, 192, 17, 111, 168, 192, 132, 12, 109, 64, 10, 215, 163, 61, 236, 81, +56, 63, 1, 201, 0, 0, 20, 152, 78, 192, 12, 191, 183, 192, 27, 103, 107, 64, 205, 204, +204, 61, 236, 81, 56, 63, 1, 201, 0, 0, 136, 46, 24, 192, 142, 191, 195, 192, 92, 27, +106, 64, 143, 194, 245, 61, 236, 81, 56, 63, 1, 201, 0, 0, 24, 95, 190, 191, 35, 64, +204, 192, 132, 46, 105, 64, 41, 92, 15, 62, 236, 81, 56, 63, 1, 202, 0, 0, 192, 4, +18, 191, 121, 30, 209, 192, 76, 164, 104, 64, 10, 215, 35, 62, 236, 81, 56, 63, 1, 202, +0, 0, 170, 124, 183, 62, 231, 70, 210, 192, 233, 126, 104, 64, 236, 81, 56, 62, 236, 81, +56, 63, 1, 202, 0, 0, 165, 101, 164, 63, 192, 180, 207, 192, 232, 190, 104, 64, 205, 204, +76, 62, 236, 81, 56, 63, 1, 202, 0, 0, 67, 89, 12, 64, 99, 114, 201, 192, 78, 99, +105, 64, 174, 71, 97, 62, 236, 81, 56, 63, 1, 202, 0, 0, 33, 120, 68, 64, 26, 153, +191, 192, 131, 105, 106, 64, 143, 194, 117, 62, 236, 81, 56, 63, 1, 202, 0, 0, 222, 172, +121, 64, 164, 80, 178, 192, 100, 205, 107, 64, 184, 30, 133, 62, 236, 81, 56, 63, 1, 202, +0, 0, 84, 144, 149, 64, 167, 206, 161, 192, 80, 137, 109, 64, 41, 92, 143, 62, 236, 81, +56, 63, 1, 202, 0, 0, 234, 5, 172, 64, 193, 85, 142, 192, 74, 150, 111, 64, 154, 153, +153, 62, 236, 81, 56, 63, 1, 202, 0, 0, 135, 220, 191, 64, 43, 105, 112, 192, 7, 236, +113, 64, 10, 215, 163, 62, 236, 81, 56, 63, 1, 202, 0, 0, 17, 196, 208, 64, 240, 136, +63, 192, 36, 129, 116, 64, 123, 20, 174, 62, 236, 81, 56, 63, 1, 202, 0, 0, 79, 120, +222, 64, 41, 208, 10, 192, 39, 75, 119, 64, 236, 81, 184, 62, 236, 81, 56, 63, 1, 203, +0, 0, 225, 193, 232, 64, 99, 39, 166, 191, 213, 62, 122, 64, 92, 143, 194, 62, 236, 81, +56, 63, 1, 203, 0, 0, 75, 119, 239, 64, 89, 164, 201, 190, 68, 80, 125, 64, 205, 204, +204, 62, 236, 81, 56, 63, 1, 203, 0, 0, 114, 125, 242, 64, 126, 142, 7, 63, 132, 57, +128, 64, 61, 10, 215, 62, 236, 81, 56, 63, 1, 203, 0, 0, 31, 200, 241, 64, 139, 140, +186, 63, 66, 205, 129, 64, 174, 71, 225, 62, 236, 81, 56, 63, 1, 203, 0, 0, 50, 90, +237, 64, 151, 3, 24, 64, 251, 92, 131, 64, 31, 133, 235, 62, 236, 81, 56, 63, 1, 203, +0, 0, 137, 69, 229, 64, 119, 46, 81, 64, 97, 226, 132, 64, 143, 194, 245, 62, 236, 81, +56, 63, 1, 203, 0, 0, 197, 170, 217, 64, 13, 240, 131, 64, 79, 87, 134, 64, 0, 0, +0, 63, 236, 81, 56, 63, 1, 203, 0, 0, 193, 184, 202, 64, 212, 157, 157, 64, 231, 181, +135, 64, 184, 30, 5, 63, 236, 81, 56, 63, 1, 203, 0, 0, 212, 171, 184, 64, 231, 56, +181, 64, 156, 248, 136, 64, 113, 61, 10, 63, 236, 81, 56, 63, 1, 203, 0, 0, 219, 204, +163, 64, 246, 97, 202, 64, 95, 26, 138, 64, 41, 92, 15, 63, 236, 81, 56, 63, 1, 203, +0, 0, 30, 112, 140, 64, 152, 195, 220, 64, 148, 22, 139, 64, 225, 122, 20, 63, 236, 81, +56, 63, 1, 204, 0, 0, 209, 231, 101, 64, 144, 19, 236, 64, 73, 233, 139, 64, 154, 153, +25, 63, 236, 81, 56, 63, 1, 204, 0, 0, 70, 126, 47, 64, 20, 20, 248, 64, 42, 143, +140, 64, 82, 184, 30, 63, 236, 81, 56, 63, 1, 204, 0, 0, 147, 254, 236, 63, 85, 74, +0, 65, 148, 5, 141, 64, 10, 215, 35, 63, 236, 81, 56, 63, 1, 204, 0, 0, 183, 67, +111, 63, 127, 185, 2, 65, 178, 74, 141, 64, 195, 245, 40, 63, 236, 81, 56, 63, 1, 204, +0, 0, 190, 80, 192, 59, 181, 77, 3, 65, 102, 93, 141, 64, 123, 20, 46, 63, 236, 81, +56, 63, 1, 204, 0, 0, 84, 140, 107, 191, 161, 4, 2, 65, 100, 61, 141, 64, 51, 51, +51, 63, 236, 81, 56, 63, 1, 204, 0, 0, 10, 19, 234, 191, 233, 198, 253, 64, 49, 235, +140, 64, 236, 81, 56, 63, 236, 81, 56, 63, 1, 204, 0, 0, 103, 40, 45, 192, 158, 237, +243, 64, 22, 104, 140, 64, 164, 112, 61, 63, 236, 81, 56, 63, 1, 204, 0, 0, 32, 93, +98, 192, 41, 165, 230, 64, 38, 182, 139, 64, 92, 143, 66, 63, 236, 81, 56, 63, 1, 204, +0, 0, 117, 232, 137, 192, 41, 35, 214, 64, 48, 216, 138, 64, 20, 174, 71, 63, 236, 81, +56, 63, 1, 205, 0, 0, 9, 94, 160, 192, 69, 170, 194, 64, 179, 209, 137, 64, 205, 204, +76, 63, 236, 81, 56, 63, 1, 205, 0, 0, 166, 52, 180, 192, 24, 137, 172, 64, 213, 166, +136, 64, 133, 235, 81, 63, 236, 81, 56, 63, 1, 205, 0, 0, 50, 28, 197, 192, 250, 24, +148, 64, 70, 92, 135, 64, 61, 10, 87, 63, 236, 81, 56, 63, 1, 205, 0, 0, 108, 208, +210, 192, 45, 121, 115, 64, 68, 247, 133, 64, 246, 40, 92, 63, 236, 81, 56, 63, 1, 205, +0, 0, 2, 26, 221, 192, 182, 188, 59, 64, 107, 125, 132, 64, 174, 71, 97, 63, 236, 81, +56, 63, 1, 205, 0, 0, 108, 207, 227, 192, 144, 221, 1, 64, 182, 244, 130, 64, 102, 102, +102, 63, 236, 81, 56, 63, 1, 205, 0, 0, 145, 213, 230, 192, 194, 138, 141, 63, 84, 99, +129, 64, 31, 133, 107, 63, 236, 81, 56, 63, 1, 205, 0, 0, 62, 32, 230, 192, 241, 43, +54, 62, 44, 159, 127, 64, 215, 163, 112, 63, 236, 81, 56, 63, 1, 205, 0, 0, 79, 178, +225, 192, 72, 106, 61, 191, 187, 127, 124, 64, 143, 194, 117, 63, 236, 81, 56, 63, 1, 205, +0, 0, 166, 157, 217, 192, 229, 10, 209, 191, 239, 116, 121, 64, 72, 225, 122, 63, 236, 81, +56, 63, 1, 205, 0, 0, 228, 2, 206, 192, 9, 55, 31, 192, 17, 139, 118, 64, 0, 0, +128, 63, 236, 81, 56, 63, 1, 206, 0, 0, 40, 99, 182, 192, 224, 160, 4, 192, 54, 148, +63, 64, 0, 0, 0, 128, 92, 143, 66, 63, 1, 206, 0, 0, 2, 28, 169, 192, 146, 65, +50, 192, 70, 37, 61, 64, 10, 215, 163, 60, 92, 143, 66, 63, 1, 206, 0, 0, 163, 18, +153, 192, 68, 51, 92, 192, 218, 231, 58, 64, 10, 215, 35, 61, 92, 143, 66, 63, 1, 206, +0, 0, 202, 135, 134, 192, 81, 230, 128, 192, 4, 229, 56, 64, 143, 194, 117, 61, 92, 143, +66, 63, 1, 206, 0, 0, 160, 140, 99, 192, 239, 58, 145, 192, 217, 36, 55, 64, 10, 215, +163, 61, 92, 143, 66, 63, 1, 206, 0, 0, 11, 68, 54, 192, 145, 213, 158, 192, 117, 174, +53, 64, 205, 204, 204, 61, 92, 143, 66, 63, 1, 206, 0, 0, 158, 236, 5, 192, 69, 127, +169, 192, 186, 135, 52, 64, 143, 194, 245, 61, 92, 143, 66, 63, 1, 206, 0, 0, 16, 147, +166, 191, 2, 13, 177, 192, 78, 181, 51, 64, 41, 92, 15, 62, 92, 143, 66, 63, 1, 206, +0, 0, 201, 57, 249, 190, 76, 96, 181, 192, 130, 58, 51, 64, 10, 215, 35, 62, 92, 143, +66, 63, 1, 206, 0, 0, 146, 62, 173, 62, 165, 103, 182, 192, 72, 25, 51, 64, 236, 81, +56, 62, 92, 143, 66, 63, 1, 206, 0, 0, 203, 156, 148, 63, 239, 30, 180, 192, 34, 82, +51, 64, 205, 204, 76, 62, 92, 143, 66, 63, 1, 207, 0, 0, 233, 239, 251, 63, 88, 143, +174, 192, 50, 228, 51, 64, 174, 71, 97, 62, 92, 143, 66, 63, 1, 207, 0, 0, 233, 211, +47, 64, 91, 207, 165, 192, 41, 205, 52, 64, 143, 194, 117, 62, 92, 143, 66, 63, 1, 207, +0, 0, 252, 24, 95, 64, 75, 2, 154, 192, 83, 9, 54, 64, 184, 30, 133, 62, 92, 143, +66, 63, 1, 207, 0, 0, 39, 132, 133, 64, 201, 87, 139, 192, 184, 147, 55, 64, 41, 92, +143, 62, 92, 143, 66, 63, 1, 207, 0, 0, 66, 120, 153, 64, 30, 22, 116, 192, 31, 102, +57, 64, 154, 153, 153, 62, 92, 143, 66, 63, 1, 207, 0, 0, 66, 24, 171, 64, 231, 195, +76, 192, 45, 121, 59, 64, 10, 215, 163, 62, 92, 143, 66, 63, 1, 207, 0, 0, 250, 28, +186, 64, 168, 87, 33, 192, 135, 196, 61, 64, 123, 20, 174, 62, 92, 143, 66, 63, 1, 207, +0, 0, 203, 73, 198, 64, 117, 1, 229, 191, 226, 62, 64, 64, 236, 81, 184, 62, 92, 143, +66, 63, 1, 207, 0, 0, 141, 109, 207, 64, 93, 248, 129, 191, 64, 222, 66, 64, 92, 143, +194, 62, 92, 143, 66, 63, 1, 10, 0, 0, 88, 99, 213, 64, 113, 31, 89, 190, 7, 152, +69, 64, 205, 204, 204, 62, 92, 143, 66, 63, 1, 10, 0, 0, 31, 19, 216, 64, 124, 185, +27, 63, 65, 97, 72, 64, 61, 10, 215, 62, 92, 143, 66, 63, 1, 10, 0, 0, 8, 114, +215, 64, 170, 97, 183, 63, 165, 46, 75, 64, 174, 71, 225, 62, 92, 143, 66, 63, 1, 10, +0, 0, 157, 130, 211, 64, 118, 224, 15, 64, 224, 244, 77, 64, 31, 133, 235, 62, 92, 143, +66, 63, 1, 10, 0, 0, 193, 84, 204, 64, 130, 170, 66, 64, 206, 168, 80, 64, 143, 194, +245, 62, 92, 143, 66, 63, 1, 10, 0, 0, 113, 5, 194, 64, 250, 65, 115, 64, 117, 63, +83, 64, 0, 0, 0, 63, 92, 143, 66, 63, 1, 10, 0, 0, 75, 190, 180, 64, 84, 113, +144, 64, 100, 174, 85, 64, 184, 30, 5, 63, 92, 143, 66, 63, 1, 10, 0, 0, 238, 180, +164, 64, 45, 106, 165, 64, 209, 235, 87, 64, 113, 61, 10, 63, 92, 143, 66, 63, 1, 10, +0, 0, 17, 42, 146, 64, 221, 54, 184, 64, 170, 238, 89, 64, 41, 92, 15, 63, 92, 143, +66, 63, 1, 11, 0, 0, 49, 209, 122, 64, 122, 139, 200, 64, 209, 174, 91, 64, 225, 122, +20, 63, 92, 143, 66, 63, 1, 11, 0, 0, 152, 136, 77, 64, 28, 38, 214, 64, 53, 37, +93, 64, 154, 153, 25, 63, 92, 143, 66, 63, 1, 11, 0, 0, 43, 49, 29, 64, 209, 207, +224, 64, 245, 75, 94, 64, 82, 184, 30, 63, 92, 143, 66, 63, 1, 11, 0, 0, 50, 28, +213, 63, 144, 93, 232, 64, 96, 30, 95, 64, 10, 215, 35, 63, 92, 143, 66, 63, 1, 11, +0, 0, 41, 175, 89, 63, 215, 176, 236, 64, 40, 153, 95, 64, 195, 245, 40, 63, 92, 143, +66, 63, 1, 11, 0, 0, 116, 95, 206, 60, 48, 184, 237, 64, 98, 186, 95, 64, 123, 20, +46, 63, 92, 143, 66, 63, 1, 11, 0, 0, 99, 39, 76, 191, 122, 111, 235, 64, 132, 129, +95, 64, 51, 51, 51, 63, 92, 143, 66, 63, 1, 11, 0, 0, 207, 102, 205, 191, 227, 223, +229, 64, 116, 239, 94, 64, 236, 81, 56, 63, 92, 143, 66, 63, 1, 11, 0, 0, 92, 143, +24, 192, 230, 31, 221, 64, 133, 6, 94, 64, 164, 112, 61, 63, 92, 143, 66, 63, 1, 11, +0, 0, 107, 212, 71, 192, 212, 82, 209, 64, 88, 202, 92, 64, 92, 143, 66, 63, 92, 143, +66, 63, 1, 11, 0, 0, 189, 195, 115, 192, 82, 168, 194, 64, 242, 63, 91, 64, 20, 174, +71, 63, 92, 143, 66, 63, 1, 12, 0, 0, 252, 213, 141, 192, 152, 91, 177, 64, 139, 109, +89, 64, 205, 204, 76, 63, 92, 143, 66, 63, 1, 12, 0, 0, 249, 117, 159, 192, 125, 178, +157, 64, 121, 90, 87, 64, 133, 235, 81, 63, 92, 143, 66, 63, 1, 12, 0, 0, 177, 122, +174, 192, 95, 252, 135, 64, 40, 15, 85, 64, 61, 10, 87, 63, 92, 143, 66, 63, 1, 12, +0, 0, 131, 167, 186, 192, 205, 33, 97, 64, 205, 148, 82, 64, 246, 40, 92, 63, 92, 143, +66, 63, 1, 12, 0, 0, 69, 203, 195, 192, 65, 157, 47, 64, 106, 245, 79, 64, 174, 71, +97, 63, 92, 143, 66, 63, 1, 12, 0, 0, 16, 193, 201, 192, 19, 102, 248, 63, 159, 59, +77, 64, 102, 102, 102, 63, 92, 143, 66, 63, 1, 12, 0, 0, 214, 112, 204, 192, 103, 101, +143, 63, 105, 114, 74, 64, 31, 133, 107, 63, 92, 143, 66, 63, 1, 12, 0, 0, 192, 207, +203, 192, 199, 129, 151, 62, 5, 165, 71, 64, 215, 163, 112, 63, 92, 143, 66, 63, 1, 12, +0, 0, 82, 224, 199, 192, 143, 253, 4, 191, 198, 222, 68, 64, 143, 194, 117, 63, 92, 143, +66, 63, 1, 12, 0, 0, 118, 178, 192, 192, 224, 18, 168, 191, 224, 42, 66, 64, 72, 225, +122, 63, 92, 143, 66, 63, 1, 13, 0, 0, 40, 99, 182, 192, 224, 160, 4, 192, 54, 148, +63, 64, 0, 0, 128, 63, 92, 143, 66, 63, 1, 13, 0, 0, 60, 203, 155, 192, 197, 231, +206, 191, 208, 211, 15, 64, 0, 0, 0, 128, 205, 204, 76, 63, 1, 13, 0, 0, 145, 100, +144, 192, 123, 161, 14, 192, 232, 188, 13, 64, 10, 215, 163, 60, 205, 204, 76, 63, 1, 13, +0, 0, 128, 159, 130, 192, 101, 165, 50, 192, 141, 208, 11, 64, 10, 215, 35, 61, 205, 204, +76, 63, 1, 13, 0, 0, 60, 103, 101, 192, 53, 238, 82, 192, 123, 22, 10, 64, 143, 194, +117, 61, 205, 204, 76, 63, 1, 13, 0, 0, 110, 194, 65, 192, 144, 249, 110, 192, 171, 149, +8, 64, 10, 215, 163, 61, 205, 204, 76, 63, 1, 13, 0, 0, 118, 224, 26, 192, 34, 43, +131, 192, 51, 84, 7, 64, 205, 204, 204, 61, 205, 204, 76, 63, 1, 13, 0, 0, 174, 188, +226, 191, 254, 82, 140, 192, 29, 87, 6, 64, 143, 194, 245, 61, 205, 204, 76, 63, 1, 13, +0, 0, 55, 199, 139, 191, 102, 207, 146, 192, 115, 162, 5, 64, 41, 92, 15, 62, 205, 204, +76, 63, 1, 13, 0, 0, 172, 254, 200, 190, 43, 134, 150, 192, 0, 57, 5, 64, 10, 215, +35, 62, 205, 204, 76, 63, 1, 13, 0, 0, 59, 194, 161, 62, 77, 104, 151, 192, 126, 28, +5, 64, 236, 81, 56, 62, 205, 204, 76, 63, 1, 14, 0, 0, 73, 219, 130, 63, 59, 114, +149, 192, 77, 77, 5, 64, 205, 204, 76, 62, 205, 204, 76, 63, 1, 14, 0, 0, 129, 147, +219, 63, 222, 171, 144, 192, 184, 202, 5, 64, 174, 71, 97, 62, 205, 204, 76, 63, 1, 14, +0, 0, 128, 153, 24, 64, 130, 40, 137, 192, 188, 146, 6, 64, 143, 194, 117, 62, 205, 204, +76, 63, 1, 14, 0, 0, 14, 48, 65, 64, 242, 12, 126, 192, 56, 162, 7, 64, 184, 30, +133, 62, 205, 204, 76, 63, 1, 14, 0, 0, 146, 233, 102, 64, 89, 221, 100, 192, 220, 244, +8, 64, 41, 92, 143, 62, 205, 204, 76, 63, 1, 14, 0, 0, 217, 150, 132, 64, 233, 39, +71, 192, 89, 133, 10, 64, 154, 153, 153, 62, 205, 204, 76, 63, 1, 14, 0, 0, 17, 185, +147, 64, 145, 100, 37, 192, 85, 77, 12, 64, 10, 215, 163, 62, 205, 204, 76, 63, 1, 14, +0, 0, 84, 158, 160, 64, 160, 27, 0, 192, 166, 69, 14, 64, 123, 20, 174, 62, 205, 204, +76, 63, 1, 14, 0, 0, 146, 18, 171, 64, 63, 199, 175, 191, 86, 102, 16, 64, 236, 81, +184, 62, 205, 204, 76, 63, 1, 14, 0, 0, 154, 235, 178, 64, 183, 123, 53, 191, 210, 166, +18, 64, 92, 143, 194, 62, 205, 204, 76, 63, 1, 14, 0, 0, 187, 9, 184, 64, 65, 155, +156, 188, 248, 253, 20, 64, 205, 204, 204, 62, 205, 204, 76, 63, 1, 15, 0, 0, 73, 88, +186, 64, 51, 109, 47, 63, 99, 98, 23, 64, 61, 10, 215, 62, 205, 204, 76, 63, 1, 15, +0, 0, 249, 205, 185, 64, 59, 81, 178, 63, 92, 202, 25, 64, 174, 71, 225, 62, 205, 204, +76, 63, 1, 15, 0, 0, 242, 108, 182, 64, 211, 247, 5, 64, 56, 44, 28, 64, 31, 133, +235, 62, 205, 204, 76, 63, 1, 15, 0, 0, 223, 66, 176, 64, 3, 148, 49, 64, 78, 126, +30, 64, 143, 194, 245, 62, 205, 204, 76, 63, 1, 15, 0, 0, 161, 104, 167, 64, 35, 77, +91, 64, 74, 183, 32, 64, 0, 0, 0, 63, 205, 204, 76, 63, 1, 15, 0, 0, 245, 1, +156, 64, 96, 61, 129, 64, 49, 206, 34, 64, 184, 30, 5, 63, 205, 204, 76, 63, 1, 15, +0, 0, 228, 60, 142, 64, 83, 63, 147, 64, 140, 186, 36, 64, 113, 61, 10, 63, 205, 204, +76, 63, 1, 15, 0, 0, 5, 162, 124, 64, 187, 99, 163, 64, 163, 116, 38, 64, 41, 92, +15, 63, 205, 204, 76, 63, 1, 15, 0, 0, 55, 253, 88, 64, 104, 105, 177, 64, 111, 245, +39, 64, 225, 122, 20, 63, 205, 204, 76, 63, 1, 15, 0, 0, 63, 27, 50, 64, 194, 23, +189, 64, 235, 54, 41, 64, 154, 153, 25, 63, 205, 204, 76, 63, 1, 16, 0, 0, 32, 153, +8, 64, 158, 63, 198, 64, 253, 51, 42, 64, 82, 184, 30, 63, 205, 204, 76, 63, 1, 16, +0, 0, 201, 60, 186, 63, 6, 188, 204, 64, 167, 232, 42, 64, 10, 215, 35, 63, 205, 204, +76, 63, 1, 16, 0, 0, 106, 106, 65, 63, 201, 114, 208, 64, 26, 82, 43, 64, 195, 245, +40, 63, 205, 204, 76, 63, 1, 16, 0, 0, 111, 160, 64, 61, 233, 84, 209, 64, 160, 110, +43, 64, 123, 20, 46, 63, 205, 204, 76, 63, 1, 16, 0, 0, 125, 203, 40, 191, 217, 94, +207, 64, 205, 61, 43, 64, 51, 51, 51, 63, 205, 204, 76, 63, 1, 16, 0, 0, 239, 29, +173, 191, 124, 152, 202, 64, 102, 192, 42, 64, 236, 81, 56, 63, 205, 204, 76, 63, 1, 16, +0, 0, 183, 94, 1, 192, 33, 21, 195, 64, 93, 248, 41, 64, 164, 112, 61, 63, 205, 204, +76, 63, 1, 16, 0, 0, 73, 245, 41, 192, 23, 243, 184, 64, 226, 232, 40, 64, 92, 143, +66, 63, 205, 204, 76, 63, 1, 16, 0, 0, 201, 174, 79, 192, 75, 91, 172, 64, 66, 150, +39, 64, 20, 174, 71, 63, 205, 204, 76, 63, 1, 16, 0, 0, 237, 242, 113, 192, 147, 128, +157, 64, 196, 5, 38, 64, 205, 204, 76, 63, 205, 204, 76, 63, 1, 16, 0, 0, 172, 27, +136, 192, 228, 158, 140, 64, 201, 61, 36, 64, 133, 235, 81, 63, 205, 204, 76, 63, 1, 17, +0, 0, 239, 0, 149, 192, 220, 244, 115, 64, 116, 69, 34, 64, 61, 10, 87, 63, 205, 204, +76, 63, 1, 17, 0, 0, 48, 117, 159, 192, 220, 188, 75, 64, 196, 36, 32, 64, 246, 40, +92, 63, 205, 204, 76, 63, 1, 17, 0, 0, 54, 78, 167, 192, 42, 56, 33, 64, 75, 228, +29, 64, 174, 71, 97, 63, 205, 204, 76, 63, 1, 17, 0, 0, 85, 108, 172, 192, 230, 36, +234, 63, 34, 141, 27, 64, 102, 102, 102, 63, 205, 204, 76, 63, 1, 17, 0, 0, 228, 186, +174, 192, 223, 251, 143, 63, 187, 40, 25, 64, 31, 133, 107, 63, 205, 204, 76, 63, 1, 17, +0, 0, 146, 48, 174, 192, 245, 132, 213, 62, 190, 192, 22, 64, 215, 163, 112, 63, 205, 204, +76, 63, 1, 17, 0, 0, 139, 207, 170, 192, 182, 244, 144, 190, 229, 94, 20, 64, 143, 194, +117, 63, 205, 204, 76, 63, 1, 17, 0, 0, 120, 165, 164, 192, 45, 235, 118, 191, 200, 12, +18, 64, 72, 225, 122, 63, 205, 204, 76, 63, 1, 17, 0, 0, 60, 203, 155, 192, 197, 231, +206, 191, 208, 211, 15, 64, 0, 0, 128, 63, 205, 204, 76, 63, 1, 17, 0, 0, 253, 76, +125, 192, 186, 75, 144, 191, 68, 21, 208, 63, 0, 0, 0, 128, 62, 10, 87, 63, 1, 17, +0, 0, 170, 156, 106, 192, 106, 132, 208, 191, 118, 168, 204, 63, 10, 215, 163, 60, 62, 10, +87, 63, 1, 17, 0, 0, 78, 10, 84, 192, 235, 198, 5, 192, 90, 129, 201, 63, 10, 215, +35, 61, 62, 10, 87, 63, 1, 18, 0, 0, 15, 241, 57, 192, 209, 60, 32, 192, 184, 172, +198, 63, 143, 194, 117, 61, 62, 10, 87, 63, 1, 18, 0, 0, 73, 186, 28, 192, 21, 57, +55, 192, 240, 53, 196, 63, 10, 215, 163, 61, 62, 10, 87, 63, 1, 18, 0, 0, 225, 183, +249, 191, 234, 94, 74, 192, 246, 38, 194, 63, 205, 204, 204, 61, 62, 10, 87, 63, 1, 18, +0, 0, 92, 173, 181, 191, 2, 97, 89, 192, 30, 136, 192, 63, 143, 194, 245, 61, 62, 10, +87, 63, 1, 18, 0, 0, 91, 207, 92, 191, 197, 2, 100, 192, 246, 95, 191, 63, 41, 92, +15, 62, 62, 10, 87, 63, 1, 18, 0, 0, 139, 26, 148, 190, 72, 25, 106, 192, 37, 179, +190, 63, 10, 215, 35, 62, 62, 10, 87, 63, 1, 18, 0, 0, 80, 54, 149, 62, 248, 139, +107, 192, 98, 132, 190, 63, 236, 81, 56, 62, 62, 10, 87, 63, 1, 18, 0, 0, 175, 209, +94, 63, 243, 84, 104, 192, 103, 212, 190, 63, 205, 204, 76, 62, 62, 10, 87, 63, 1, 18, +0, 0, 243, 31, 184, 63, 65, 129, 96, 192, 245, 161, 191, 63, 174, 71, 97, 62, 62, 10, +87, 63, 1, 19, 0, 0, 94, 77, 254, 63, 115, 48, 84, 192, 221, 233, 192, 63, 143, 194, +117, 62, 62, 10, 87, 63, 1, 19, 0, 0, 219, 106, 32, 64, 66, 148, 67, 192, 219, 166, +194, 63, 184, 30, 133, 62, 62, 10, 87, 63, 1, 19, 0, 0, 59, 86, 63, 64, 195, 239, +46, 192, 242, 209, 196, 63, 41, 92, 143, 62, 62, 10, 87, 63, 1, 19, 0, 0, 240, 107, +91, 64, 70, 150, 22, 192, 116, 98, 199, 63, 154, 153, 153, 62, 62, 10, 87, 63, 1, 19, +0, 0, 159, 58, 116, 64, 65, 212, 245, 191, 228, 77, 202, 63, 10, 215, 163, 62, 62, 10, +87, 63, 1, 19, 0, 0, 14, 175, 132, 64, 7, 182, 184, 191, 152, 136, 205, 63, 123, 20, +174, 62, 62, 10, 87, 63, 1, 19, 0, 0, 135, 64, 141, 64, 71, 145, 109, 191, 117, 5, +209, 63, 236, 81, 184, 62, 62, 10, 87, 63, 1, 19, 0, 0, 37, 175, 147, 64, 50, 89, +196, 190, 107, 182, 212, 63, 92, 143, 194, 62, 62, 10, 87, 63, 1, 19, 0, 0, 240, 224, +151, 64, 113, 61, 58, 62, 147, 140, 216, 63, 205, 204, 204, 62, 62, 10, 87, 63, 1, 19, +0, 0, 246, 196, 153, 64, 37, 90, 66, 63, 117, 120, 220, 63, 61, 10, 215, 62, 62, 10, +87, 63, 1, 19, 0, 0, 151, 83, 153, 64, 151, 111, 171, 63, 43, 106, 224, 63, 174, 71, +225, 62, 62, 10, 87, 63, 1, 20, 0, 0, 157, 142, 150, 64, 97, 227, 244, 63, 219, 81, +228, 63, 31, 133, 235, 62, 62, 10, 87, 63, 1, 20, 0, 0, 54, 129, 145, 64, 245, 47, +30, 64, 184, 31, 232, 63, 143, 194, 245, 62, 62, 10, 87, 63, 1, 20, 0, 0, 200, 63, +138, 64, 78, 98, 64, 64, 101, 196, 235, 63, 0, 0, 0, 63, 62, 10, 87, 63, 1, 20, +0, 0, 157, 231, 128, 64, 166, 126, 96, 64, 51, 49, 239, 63, 184, 30, 5, 63, 62, 10, +87, 63, 1, 20, 0, 0, 226, 60, 107, 64, 92, 3, 126, 64, 71, 88, 242, 63, 113, 61, +10, 63, 62, 10, 87, 63, 1, 20, 0, 0, 158, 35, 81, 64, 161, 60, 140, 64, 249, 44, +245, 63, 41, 92, 15, 63, 62, 10, 87, 63, 1, 20, 0, 0, 221, 236, 51, 64, 195, 186, +151, 64, 186, 163, 247, 63, 225, 122, 20, 63, 62, 10, 87, 63, 1, 20, 0, 0, 128, 14, +20, 64, 173, 77, 161, 64, 179, 178, 249, 63, 154, 153, 25, 63, 62, 10, 87, 63, 1, 20, +0, 0, 123, 18, 228, 63, 186, 206, 168, 64, 139, 81, 251, 63, 82, 184, 30, 63, 62, 10, +87, 63, 1, 20, 0, 0, 205, 204, 156, 63, 155, 31, 174, 64, 179, 121, 252, 63, 10, 215, +35, 63, 62, 10, 87, 63, 1, 20, 0, 0, 132, 215, 38, 63, 220, 42, 177, 64, 133, 38, +253, 63, 195, 245, 40, 63, 62, 10, 87, 63, 1, 21, 0, 0, 179, 120, 145, 61, 50, 228, +177, 64, 80, 85, 253, 63, 123, 20, 46, 63, 62, 10, 87, 63, 1, 21, 0, 0, 112, 7, +2, 191, 176, 72, 176, 64, 66, 5, 253, 63, 51, 51, 51, 63, 62, 10, 87, 63, 1, 21, +0, 0, 212, 186, 137, 191, 215, 94, 172, 64, 172, 55, 252, 63, 236, 81, 56, 63, 62, 10, +87, 63, 1, 21, 0, 0, 54, 232, 207, 191, 112, 54, 166, 64, 212, 239, 250, 63, 164, 112, +61, 63, 62, 10, 87, 63, 1, 21, 0, 0, 76, 56, 9, 192, 87, 232, 157, 64, 207, 50, +249, 63, 92, 143, 66, 63, 62, 10, 87, 63, 1, 21, 0, 0, 171, 35, 40, 192, 24, 150, +147, 64, 184, 7, 247, 63, 20, 174, 71, 63, 62, 10, 87, 63, 1, 21, 0, 0, 96, 57, +68, 192, 89, 105, 135, 64, 54, 119, 244, 63, 205, 204, 76, 63, 62, 10, 87, 63, 1, 21, +0, 0, 16, 8, 93, 192, 137, 38, 115, 64, 189, 139, 241, 63, 133, 235, 81, 63, 62, 10, +87, 63, 1, 21, 0, 0, 136, 43, 114, 192, 112, 151, 84, 64, 17, 81, 238, 63, 61, 10, +87, 63, 62, 10, 87, 63, 1, 21, 0, 0, 61, 167, 129, 192, 190, 160, 51, 64, 53, 212, +234, 63, 246, 40, 92, 63, 62, 10, 87, 63, 1, 22, 0, 0, 219, 21, 136, 192, 143, 199, +16, 64, 62, 35, 231, 63, 174, 71, 97, 63, 62, 10, 87, 63, 1, 22, 0, 0, 166, 71, +140, 192, 43, 49, 217, 63, 22, 77, 227, 63, 102, 102, 102, 63, 62, 10, 87, 63, 1, 22, +0, 0, 172, 43, 142, 192, 190, 75, 143, 63, 61, 97, 223, 63, 31, 133, 107, 63, 62, 10, +87, 63, 1, 22, 0, 0, 77, 186, 141, 192, 132, 18, 10, 63, 126, 111, 219, 63, 215, 163, +112, 63, 62, 10, 87, 63, 1, 22, 0, 0, 83, 245, 138, 192, 236, 80, 13, 189, 207, 135, +215, 63, 143, 194, 117, 63, 62, 10, 87, 63, 1, 22, 0, 0, 236, 231, 133, 192, 49, 206, +23, 191, 241, 185, 211, 63, 72, 225, 122, 63, 62, 10, 87, 63, 1, 22, 0, 0, 253, 76, +125, 192, 186, 75, 144, 191, 68, 21, 208, 63, 0, 0, 128, 63, 62, 10, 87, 63, 1, 22, +0, 0, 52, 213, 62, 192, 170, 212, 28, 191, 154, 178, 145, 63, 0, 0, 0, 128, 174, 71, +97, 63, 1, 22, 0, 0, 84, 141, 48, 192, 131, 250, 126, 191, 161, 20, 143, 63, 10, 215, +163, 60, 174, 71, 97, 63, 1, 22, 0, 0, 228, 77, 31, 192, 233, 153, 172, 191, 222, 171, +140, 63, 10, 215, 35, 61, 174, 71, 97, 63, 1, 22, 0, 0, 133, 92, 11, 192, 70, 10, +213, 191, 40, 130, 138, 63, 143, 194, 117, 61, 174, 71, 97, 63, 1, 23, 0, 0, 119, 19, +234, 191, 254, 42, 248, 191, 35, 160, 136, 63, 10, 215, 163, 61, 174, 71, 97, 63, 1, 23, +0, 0, 78, 95, 185, 191, 44, 183, 10, 192, 124, 13, 135, 63, 205, 204, 204, 61, 174, 71, +97, 63, 1, 23, 0, 0, 61, 97, 133, 191, 10, 47, 22, 192, 125, 208, 133, 63, 143, 194, +245, 61, 174, 71, 97, 63, 1, 23, 0, 0, 40, 214, 29, 191, 215, 78, 30, 192, 40, 238, +132, 63, 41, 92, 15, 62, 174, 71, 97, 63, 1, 23, 0, 0, 21, 198, 54, 190, 190, 245, +34, 192, 26, 106, 132, 63, 10, 215, 35, 62, 174, 71, 97, 63, 1, 23, 0, 0, 70, 205, +135, 62, 253, 16, 36, 192, 90, 70, 132, 63, 236, 81, 56, 62, 174, 71, 97, 63, 1, 23, +0, 0, 212, 39, 53, 63, 27, 156, 33, 192, 136, 131, 132, 63, 205, 204, 76, 62, 174, 71, +97, 63, 1, 23, 0, 0, 95, 36, 146, 63, 1, 161, 27, 192, 159, 32, 133, 63, 174, 71, +97, 62, 174, 71, 97, 63, 1, 23, 0, 0, 93, 196, 199, 63, 214, 55, 18, 192, 42, 27, +134, 63, 143, 194, 117, 62, 174, 71, 97, 63, 1, 23, 0, 0, 99, 155, 250, 63, 152, 134, +5, 192, 51, 111, 135, 63, 184, 30, 133, 62, 174, 71, 97, 63, 1, 23, 0, 0, 24, 238, +20, 64, 15, 129, 235, 191, 97, 23, 137, 63, 41, 92, 143, 62, 174, 71, 97, 63, 1, 24, +0, 0, 254, 99, 42, 64, 157, 74, 198, 191, 254, 12, 139, 63, 154, 153, 153, 62, 174, 71, +97, 63, 1, 24, 0, 0, 197, 88, 61, 64, 34, 0, 156, 191, 44, 72, 141, 63, 10, 215, +163, 62, 174, 71, 97, 63, 1, 24, 0, 0, 225, 127, 77, 64, 171, 152, 90, 191, 223, 191, +143, 63, 123, 20, 174, 62, 174, 71, 97, 63, 1, 24, 0, 0, 24, 152, 90, 64, 239, 174, +235, 190, 35, 106, 146, 63, 236, 81, 184, 62, 174, 71, 97, 63, 1, 24, 0, 0, 143, 108, +100, 64, 38, 56, 53, 189, 54, 60, 149, 63, 92, 143, 194, 62, 174, 71, 97, 63, 1, 24, +0, 0, 153, 213, 106, 64, 47, 138, 198, 62, 187, 42, 152, 63, 205, 204, 204, 62, 174, 71, +97, 63, 1, 24, 0, 0, 82, 185, 109, 64, 248, 51, 84, 63, 204, 41, 155, 63, 61, 10, +215, 62, 174, 71, 97, 63, 1, 24, 0, 0, 15, 12, 109, 64, 144, 216, 162, 63, 98, 45, +158, 63, 174, 71, 225, 62, 174, 71, 97, 63, 1, 24, 0, 0, 141, 208, 104, 64, 51, 249, +218, 63, 69, 41, 161, 63, 31, 133, 235, 62, 174, 71, 97, 63, 1, 24, 0, 0, 227, 23, +97, 64, 163, 204, 8, 64, 111, 17, 164, 63, 143, 194, 245, 62, 174, 71, 97, 63, 1, 25, +0, 0, 59, 1, 86, 64, 32, 238, 34, 64, 35, 218, 166, 63, 0, 0, 0, 63, 174, 71, +97, 63, 1, 25, 0, 0, 90, 185, 71, 64, 146, 119, 59, 64, 28, 120, 169, 63, 184, 30, +5, 63, 174, 71, 97, 63, 1, 25, 0, 0, 238, 121, 54, 64, 234, 5, 82, 64, 214, 224, +171, 63, 113, 61, 10, 63, 174, 71, 97, 63, 1, 25, 0, 0, 144, 136, 34, 64, 20, 62, +102, 64, 150, 10, 174, 63, 41, 92, 15, 63, 174, 71, 97, 63, 1, 25, 0, 0, 198, 53, +12, 64, 116, 206, 119, 64, 146, 236, 175, 63, 225, 122, 20, 63, 174, 71, 97, 63, 1, 25, +0, 0, 99, 183, 231, 63, 15, 56, 131, 64, 74, 127, 177, 63, 154, 153, 25, 63, 174, 71, +97, 63, 1, 25, 0, 0, 73, 185, 179, 63, 254, 243, 136, 64, 65, 188, 178, 63, 82, 184, +30, 63, 174, 71, 97, 63, 1, 25, 0, 0, 64, 134, 122, 63, 226, 3, 141, 64, 149, 158, +179, 63, 10, 215, 35, 63, 174, 71, 97, 63, 1, 25, 0, 0, 174, 97, 10, 63, 88, 87, +143, 64, 163, 34, 180, 63, 195, 245, 40, 63, 174, 71, 97, 63, 1, 25, 0, 0, 169, 75, +198, 61, 247, 228, 143, 64, 90, 70, 180, 63, 123, 20, 46, 63, 174, 71, 97, 63, 1, 25, +0, 0, 120, 239, 176, 190, 134, 170, 142, 64, 53, 9, 180, 63, 51, 51, 51, 63, 174, 71, +97, 63, 1, 26, 0, 0, 150, 152, 71, 191, 249, 172, 139, 64, 30, 108, 179, 63, 236, 81, +56, 63, 174, 71, 97, 63, 1, 26, 0, 0, 72, 108, 153, 191, 98, 248, 134, 64, 147, 113, +178, 63, 164, 112, 61, 63, 174, 71, 97, 63, 1, 26, 0, 0, 78, 67, 204, 191, 197, 159, +128, 64, 138, 29, 177, 63, 92, 143, 66, 63, 174, 71, 97, 63, 1, 26, 0, 0, 27, 132, +251, 191, 121, 121, 113, 64, 92, 117, 175, 63, 20, 174, 71, 63, 174, 71, 97, 63, 1, 26, +0, 0, 248, 55, 19, 192, 64, 222, 94, 64, 183, 127, 173, 63, 205, 204, 76, 63, 174, 71, +97, 63, 1, 26, 0, 0, 186, 44, 38, 192, 254, 184, 73, 64, 137, 68, 171, 63, 133, 235, +81, 63, 174, 71, 97, 63, 1, 26, 0, 0, 214, 83, 54, 192, 24, 95, 50, 64, 213, 204, +168, 63, 61, 10, 87, 63, 174, 71, 97, 63, 1, 26, 0, 0, 13, 108, 67, 192, 203, 46, +25, 64, 146, 34, 166, 63, 246, 40, 92, 63, 174, 71, 97, 63, 1, 26, 0, 0, 133, 64, +77, 192, 164, 27, 253, 63, 127, 80, 163, 63, 174, 71, 97, 63, 174, 71, 97, 63, 1, 26, +0, 0, 143, 169, 83, 192, 79, 207, 197, 63, 2, 98, 160, 63, 102, 102, 102, 63, 174, 71, +97, 63, 1, 26, 0, 0, 71, 141, 86, 192, 222, 87, 141, 63, 233, 98, 157, 63, 31, 133, +107, 63, 174, 71, 97, 63, 1, 27, 0, 0, 5, 224, 85, 192, 148, 50, 41, 63, 91, 95, +154, 63, 215, 163, 112, 63, 174, 71, 97, 63, 1, 27, 0, 0, 131, 164, 81, 192, 122, 197, +99, 62, 120, 99, 151, 63, 143, 194, 117, 63, 174, 71, 97, 63, 1, 27, 0, 0, 217, 235, +73, 192, 25, 59, 81, 190, 78, 123, 148, 63, 72, 225, 122, 63, 174, 71, 97, 63, 1, 27, +0, 0, 52, 213, 62, 192, 170, 212, 28, 191, 154, 178, 145, 63, 0, 0, 128, 63, 174, 71, +97, 63, 1, 27, 0, 0, 147, 86, 250, 191, 144, 218, 164, 189, 10, 247, 74, 63, 0, 0, +0, 128, 31, 133, 107, 63, 1, 27, 0, 0, 15, 11, 231, 191, 107, 210, 173, 190, 202, 109, +71, 63, 10, 215, 163, 60, 31, 133, 107, 63, 1, 27, 0, 0, 73, 189, 207, 191, 223, 220, +19, 191, 128, 44, 68, 63, 10, 215, 35, 61, 31, 133, 107, 63, 1, 27, 0, 0, 83, 203, +180, 191, 23, 128, 74, 191, 87, 64, 65, 63, 143, 194, 117, 61, 31, 133, 107, 63, 1, 27, +0, 0, 249, 161, 150, 191, 102, 246, 121, 191, 28, 181, 62, 63, 10, 215, 163, 61, 31, 133, +107, 63, 1, 27, 0, 0, 12, 118, 107, 191, 5, 192, 144, 191, 24, 149, 60, 63, 205, 204, +204, 61, 31, 133, 107, 63, 1, 28, 0, 0, 130, 54, 37, 191, 184, 62, 160, 191, 192, 232, +58, 63, 143, 194, 245, 61, 31, 133, 107, 63, 1, 28, 0, 0, 20, 66, 183, 190, 197, 56, +171, 191, 246, 182, 57, 63, 41, 92, 15, 62, 31, 133, 107, 63, 1, 28, 0, 0, 70, 234, +125, 189, 216, 129, 177, 191, 146, 4, 57, 63, 10, 215, 35, 62, 31, 133, 107, 63, 1, 28, +0, 0, 7, 123, 115, 62, 138, 0, 179, 191, 69, 212, 56, 63, 236, 81, 56, 62, 31, 133, +107, 63, 1, 28, 0, 0, 78, 97, 9, 63, 213, 174, 175, 191, 233, 38, 57, 63, 205, 204, +76, 62, 31, 133, 107, 63, 1, 28, 0, 0, 50, 116, 84, 63, 32, 154, 167, 191, 30, 251, +57, 63, 174, 71, 97, 62, 31, 133, 107, 63, 1, 28, 0, 0, 42, 116, 142, 63, 21, 227, +154, 191, 173, 77, 59, 63, 143, 194, 117, 62, 31, 133, 107, 63, 1, 28, 0, 0, 154, 204, +176, 63, 245, 188, 137, 191, 21, 25, 61, 63, 184, 30, 133, 62, 31, 133, 107, 63, 1, 28, +0, 0, 183, 184, 208, 63, 27, 218, 104, 191, 50, 86, 63, 63, 41, 92, 143, 62, 31, 133, +107, 63, 1, 28, 0, 0, 158, 183, 237, 63, 197, 146, 54, 191, 248, 251, 65, 63, 154, 153, +153, 62, 31, 133, 107, 63, 1, 28, 0, 0, 34, 170, 3, 64, 190, 221, 250, 190, 185, 255, +68, 63, 10, 215, 163, 62, 31, 133, 107, 63, 1, 29, 0, 0, 163, 147, 14, 64, 168, 84, +121, 190, 50, 85, 72, 63, 123, 20, 174, 62, 31, 133, 107, 63, 1, 29, 0, 0, 68, 108, +23, 64, 159, 115, 183, 60, 7, 239, 75, 63, 236, 81, 184, 62, 31, 133, 107, 63, 1, 29, +0, 0, 73, 16, 30, 64, 120, 97, 155, 62, 169, 190, 79, 63, 92, 143, 194, 62, 31, 133, +107, 63, 1, 29, 0, 0, 233, 100, 34, 64, 140, 103, 24, 63, 162, 180, 83, 63, 205, 204, +204, 62, 31, 133, 107, 63, 1, 29, 0, 0, 163, 88, 36, 64, 150, 178, 100, 63, 22, 193, +87, 63, 61, 10, 215, 62, 31, 133, 107, 63, 1, 29, 0, 0, 151, 227, 35, 64, 218, 174, +152, 63, 145, 211, 91, 63, 174, 71, 225, 62, 31, 133, 107, 63, 1, 29, 0, 0, 158, 7, +33, 64, 175, 153, 190, 63, 161, 219, 95, 63, 31, 133, 235, 62, 31, 133, 107, 63, 1, 29, +0, 0, 66, 208, 27, 64, 195, 128, 227, 63, 21, 201, 99, 63, 143, 194, 245, 62, 31, 133, +107, 63, 1, 29, 0, 0, 147, 82, 20, 64, 136, 103, 3, 64, 17, 140, 103, 63, 0, 0, +0, 63, 31, 133, 107, 63, 1, 29, 0, 0, 210, 172, 10, 64, 5, 251, 19, 64, 81, 21, +107, 63, 184, 30, 5, 63, 31, 133, 107, 63, 1, 29, 0, 0, 221, 11, 254, 63, 235, 55, +35, 64, 138, 86, 110, 63, 113, 61, 10, 63, 31, 133, 107, 63, 1, 30, 0, 0, 231, 25, +227, 63, 185, 224, 48, 64, 179, 66, 113, 63, 41, 92, 15, 63, 31, 133, 107, 63, 1, 30, +0, 0, 149, 240, 196, 63, 73, 190, 60, 64, 255, 205, 115, 63, 225, 122, 20, 63, 31, 133, +107, 63, 1, 30, 0, 0, 154, 9, 164, 63, 182, 160, 70, 64, 3, 238, 117, 63, 154, 153, +25, 63, 31, 133, 107, 63, 1, 30, 0, 0, 213, 233, 128, 63, 15, 96, 78, 64, 74, 154, +119, 63, 82, 184, 30, 63, 31, 133, 107, 63, 1, 30, 0, 0, 50, 62, 56, 63, 22, 221, +83, 64, 20, 204, 120, 63, 10, 215, 35, 63, 31, 133, 107, 63, 1, 30, 0, 0, 186, 247, +216, 62, 155, 1, 87, 64, 137, 126, 121, 63, 195, 245, 40, 63, 31, 133, 107, 63, 1, 30, +0, 0, 182, 243, 253, 61, 244, 192, 87, 64, 213, 174, 121, 63, 123, 20, 46, 63, 31, 133, +107, 63, 1, 30, 0, 0, 153, 16, 51, 190, 30, 24, 86, 64, 49, 92, 121, 63, 51, 51, +51, 63, 31, 133, 107, 63, 1, 30, 0, 0, 20, 174, 239, 190, 195, 13, 82, 64, 236, 135, +120, 63, 236, 81, 56, 63, 31, 133, 107, 63, 1, 30, 0, 0, 43, 75, 64, 191, 58, 178, +75, 64, 110, 53, 119, 63, 164, 112, 61, 63, 31, 133, 107, 63, 1, 31, 0, 0, 254, 125, +130, 191, 46, 31, 67, 64, 245, 105, 117, 63, 92, 143, 66, 63, 31, 133, 107, 63, 1, 31, +0, 0, 26, 106, 162, 191, 54, 119, 56, 64, 216, 44, 115, 63, 20, 174, 71, 63, 31, 133, +107, 63, 1, 31, 0, 0, 1, 105, 191, 191, 96, 229, 43, 64, 18, 135, 112, 63, 205, 204, +76, 63, 31, 133, 107, 63, 1, 31, 0, 0, 175, 5, 217, 191, 107, 156, 29, 64, 98, 131, +109, 63, 133, 235, 81, 63, 31, 133, 107, 63, 1, 31, 0, 0, 178, 216, 238, 191, 254, 213, +13, 64, 232, 45, 106, 63, 61, 10, 87, 63, 31, 133, 107, 63, 1, 31, 0, 0, 250, 68, +0, 192, 144, 163, 249, 63, 20, 148, 102, 63, 246, 40, 92, 63, 31, 133, 107, 63, 1, 31, +0, 0, 255, 232, 6, 192, 9, 169, 213, 63, 114, 196, 98, 63, 174, 71, 97, 63, 31, 133, +107, 63, 1, 31, 0, 0, 155, 61, 11, 192, 152, 77, 176, 63, 104, 206, 94, 63, 102, 102, +102, 63, 31, 133, 107, 63, 1, 31, 0, 0, 85, 49, 13, 192, 28, 40, 138, 63, 5, 194, +90, 63, 31, 133, 107, 63, 31, 133, 107, 63, 1, 31, 0, 0, 73, 188, 12, 192, 26, 165, +71, 63, 138, 175, 86, 63, 215, 163, 112, 63, 31, 133, 107, 63, 1, 31, 0, 0, 80, 224, +9, 192, 191, 158, 247, 62, 105, 167, 82, 63, 143, 194, 117, 63, 31, 133, 107, 63, 1, 32, +0, 0, 248, 168, 4, 192, 218, 4, 72, 62, 245, 185, 78, 63, 72, 225, 122, 63, 31, 133, +107, 63, 1, 32, 0, 0, 147, 86, 250, 191, 144, 218, 164, 189, 10, 247, 74, 63, 0, 0, +128, 63, 31, 133, 107, 63, 1, 32, 0, 0, 112, 97, 101, 191, 152, 221, 235, 62, 19, 69, +24, 63, 0, 0, 0, 128, 143, 194, 117, 63, 1, 32, 0, 0, 170, 238, 81, 191, 196, 8, +169, 62, 208, 124, 22, 63, 10, 215, 163, 60, 143, 194, 117, 63, 1, 32, 0, 0, 122, 113, +58, 191, 22, 50, 87, 62, 220, 216, 20, 63, 10, 215, 35, 61, 143, 194, 117, 63, 1, 32, +0, 0, 178, 72, 31, 191, 181, 26, 210, 61, 212, 95, 19, 63, 143, 194, 117, 61, 143, 194, +117, 63, 1, 32, 0, 0, 248, 225, 0, 191, 169, 250, 21, 60, 160, 23, 18, 63, 10, 215, +163, 61, 143, 194, 117, 63, 1, 32, 0, 0, 55, 112, 191, 190, 160, 168, 140, 189, 108, 5, +17, 63, 205, 204, 204, 61, 143, 194, 117, 63, 1, 32, 0, 0, 124, 67, 113, 190, 117, 205, +4, 190, 140, 45, 16, 63, 143, 194, 245, 61, 143, 194, 117, 63, 1, 32, 0, 0, 22, 218, +185, 189, 203, 14, 49, 190, 121, 147, 15, 63, 41, 92, 15, 62, 143, 194, 117, 63, 1, 32, +0, 0, 152, 47, 111, 61, 86, 102, 74, 190, 143, 57, 15, 63, 10, 215, 35, 62, 143, 194, +117, 63, 1, 33, 0, 0, 200, 126, 86, 62, 80, 109, 80, 190, 62, 33, 15, 63, 236, 81, +56, 62, 143, 194, 117, 63, 1, 33, 0, 0, 183, 93, 184, 62, 91, 11, 67, 190, 220, 74, +15, 63, 205, 204, 76, 62, 143, 194, 117, 63, 1, 33, 0, 0, 176, 4, 2, 63, 251, 118, +34, 190, 208, 181, 15, 63, 174, 71, 97, 62, 143, 194, 117, 63, 1, 33, 0, 0, 106, 136, +38, 63, 136, 102, 222, 189, 103, 96, 16, 63, 143, 194, 117, 62, 143, 194, 117, 63, 1, 33, +0, 0, 183, 38, 73, 63, 41, 60, 40, 189, 241, 71, 17, 63, 184, 30, 133, 62, 143, 194, +117, 63, 1, 33, 0, 0, 206, 83, 105, 63, 242, 119, 47, 61, 211, 104, 18, 63, 41, 92, +143, 62, 143, 194, 117, 63, 1, 33, 0, 0, 220, 70, 131, 63, 67, 57, 17, 62, 102, 190, +19, 63, 154, 153, 153, 62, 143, 194, 117, 63, 1, 33, 0, 0, 56, 47, 144, 63, 168, 52, +130, 62, 74, 67, 21, 63, 10, 215, 163, 62, 143, 194, 117, 63, 1, 33, 0, 0, 241, 46, +155, 63, 209, 206, 193, 62, 120, 241, 22, 63, 123, 20, 174, 62, 143, 194, 117, 63, 1, 33, +0, 0, 143, 25, 164, 63, 9, 53, 3, 63, 13, 194, 24, 63, 236, 81, 184, 62, 143, 194, +117, 63, 1, 34, 0, 0, 25, 203, 170, 63, 205, 120, 39, 63, 180, 173, 26, 63, 92, 143, +194, 62, 143, 194, 117, 63, 1, 34, 0, 0, 133, 40, 175, 63, 58, 32, 77, 63, 193, 172, +28, 63, 205, 204, 204, 62, 143, 194, 117, 63, 1, 34, 0, 0, 58, 32, 177, 63, 87, 147, +115, 63, 19, 183, 30, 63, 61, 10, 215, 62, 143, 194, 117, 63, 1, 34, 0, 0, 59, 170, +176, 63, 113, 27, 141, 63, 122, 196, 32, 63, 174, 71, 225, 62, 143, 194, 117, 63, 1, 34, +0, 0, 117, 200, 173, 63, 114, 55, 160, 63, 163, 204, 34, 63, 31, 133, 235, 62, 143, 194, +117, 63, 1, 34, 0, 0, 123, 134, 168, 63, 129, 208, 178, 63, 92, 199, 36, 63, 143, 194, +245, 62, 143, 194, 117, 63, 1, 34, 0, 0, 144, 249, 160, 63, 149, 155, 196, 63, 168, 172, +38, 63, 0, 0, 0, 63, 143, 194, 117, 63, 1, 34, 0, 0, 45, 64, 151, 63, 202, 80, +213, 63, 218, 116, 40, 63, 184, 30, 5, 63, 143, 194, 117, 63, 1, 34, 0, 0, 149, 129, +139, 63, 176, 172, 228, 63, 206, 24, 42, 63, 113, 61, 10, 63, 143, 194, 117, 63, 1, 34, +0, 0, 98, 218, 123, 63, 71, 113, 242, 63, 213, 145, 43, 63, 41, 92, 15, 63, 143, 194, +117, 63, 1, 34, 0, 0, 184, 115, 93, 63, 253, 102, 254, 63, 10, 218, 44, 63, 225, 122, +20, 63, 143, 194, 117, 63, 1, 35, 0, 0, 203, 73, 60, 63, 195, 46, 4, 64, 62, 236, +45, 63, 154, 153, 25, 63, 143, 194, 117, 63, 1, 35, 0, 0, 143, 226, 24, 63, 81, 22, +8, 64, 30, 196, 46, 63, 82, 184, 30, 63, 143, 194, 117, 63, 1, 35, 0, 0, 229, 153, +231, 62, 106, 218, 10, 64, 49, 94, 47, 63, 10, 215, 35, 63, 143, 194, 117, 63, 1, 35, +0, 0, 108, 61, 155, 62, 223, 111, 12, 64, 27, 184, 47, 63, 195, 245, 40, 63, 143, 194, +117, 63, 1, 35, 0, 0, 180, 199, 27, 62, 78, 208, 12, 64, 125, 208, 47, 63, 123, 20, +46, 63, 143, 194, 117, 63, 1, 35, 0, 0, 21, 168, 197, 58, 51, 250, 11, 64, 206, 166, +47, 63, 51, 51, 51, 63, 143, 194, 117, 63, 1, 35, 0, 0, 255, 203, 21, 190, 233, 240, +9, 64, 218, 59, 47, 63, 236, 81, 56, 63, 143, 194, 117, 63, 1, 35, 0, 0, 116, 237, +147, 190, 174, 188, 6, 64, 67, 145, 46, 63, 164, 112, 61, 63, 143, 194, 117, 63, 1, 35, +0, 0, 15, 42, 217, 190, 110, 106, 2, 64, 185, 169, 45, 63, 92, 143, 66, 63, 143, 194, +117, 63, 1, 35, 0, 0, 30, 194, 12, 191, 60, 23, 250, 63, 215, 136, 44, 63, 20, 174, +71, 63, 143, 194, 117, 63, 1, 35, 0, 0, 9, 252, 41, 191, 211, 107, 237, 63, 68, 51, +43, 63, 205, 204, 76, 63, 143, 194, 117, 63, 1, 36, 0, 0, 192, 204, 67, 191, 201, 5, +223, 63, 96, 174, 41, 63, 133, 235, 81, 63, 143, 194, 117, 63, 1, 36, 0, 0, 50, 204, +89, 191, 63, 31, 207, 63, 50, 0, 40, 63, 61, 10, 87, 63, 143, 194, 117, 63, 1, 36, +0, 0, 110, 161, 107, 191, 110, 248, 189, 63, 157, 47, 38, 63, 246, 40, 92, 63, 143, 194, +117, 63, 1, 36, 0, 0, 129, 4, 121, 191, 140, 214, 171, 63, 246, 67, 36, 63, 174, 71, +97, 63, 143, 194, 117, 63, 1, 36, 0, 0, 173, 223, 128, 191, 214, 2, 153, 63, 233, 68, +34, 63, 102, 102, 102, 63, 143, 194, 117, 63, 1, 36, 0, 0, 98, 215, 130, 191, 71, 201, +133, 63, 151, 58, 32, 63, 31, 133, 107, 63, 143, 194, 117, 63, 1, 36, 0, 0, 99, 97, +130, 191, 3, 239, 100, 63, 48, 45, 30, 63, 215, 163, 112, 63, 143, 194, 117, 63, 1, 36, +0, 0, 59, 255, 126, 191, 2, 183, 62, 63, 7, 37, 28, 63, 143, 194, 117, 63, 143, 194, +117, 63, 1, 36, 0, 0, 70, 123, 116, 191, 228, 132, 25, 63, 94, 42, 26, 63, 72, 225, +122, 63, 143, 194, 117, 63, 1, 36, 0, 0, 112, 97, 101, 191, 152, 221, 235, 62, 19, 69, +24, 63, 0, 0, 128, 63, 143, 194, 117, 63, 1, 37, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 10, 215, 35, 60, 0, 0, 128, 63, 1, 37, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 143, 194, 245, 60, 0, 0, 128, 63, 1, 37, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 205, 204, 76, 61, 0, 0, +128, 63, 1, 37, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 41, 92, +143, 61, 0, 0, 128, 63, 1, 37, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 236, 81, 184, 61, 0, 0, 128, 63, 1, 37, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 174, 71, 225, 61, 0, 0, 128, 63, 1, 37, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 184, 30, 5, 62, 0, 0, 128, 63, 1, 37, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 154, 153, 25, 62, 0, 0, +128, 63, 1, 37, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 123, 20, +46, 62, 0, 0, 128, 63, 1, 37, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 92, 143, 66, 62, 0, 0, 128, 63, 1, 37, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 61, 10, 87, 62, 0, 0, 128, 63, 1, 38, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 31, 133, 107, 62, 0, 0, 128, 63, 1, 38, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 0, 0, 128, 62, 0, 0, +128, 63, 1, 38, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 113, 61, +138, 62, 0, 0, 128, 63, 1, 38, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 225, 122, 148, 62, 0, 0, 128, 63, 1, 38, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 82, 184, 158, 62, 0, 0, 128, 63, 1, 38, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 195, 245, 168, 62, 0, 0, 128, 63, 1, 38, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 51, 51, 179, 62, 0, 0, +128, 63, 1, 38, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 164, 112, +189, 62, 0, 0, 128, 63, 1, 38, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 20, 174, 199, 62, 0, 0, 128, 63, 1, 38, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 133, 235, 209, 62, 0, 0, 128, 63, 1, 38, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 246, 40, 220, 62, 0, 0, 128, 63, 1, 39, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 102, 102, 230, 62, 0, 0, +128, 63, 1, 39, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 215, 163, +240, 62, 0, 0, 128, 63, 1, 39, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 72, 225, 250, 62, 0, 0, 128, 63, 1, 39, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 92, 143, 2, 63, 0, 0, 128, 63, 1, 39, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 20, 174, 7, 63, 0, 0, 128, 63, 1, 39, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 205, 204, 12, 63, 0, 0, +128, 63, 1, 39, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 133, 235, +17, 63, 0, 0, 128, 63, 1, 39, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 61, 10, 23, 63, 0, 0, 128, 63, 1, 39, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 246, 40, 28, 63, 0, 0, 128, 63, 1, 39, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 174, 71, 33, 63, 0, 0, 128, 63, 1, 40, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 102, 102, 38, 63, 0, 0, +128, 63, 1, 40, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 31, 133, +43, 63, 0, 0, 128, 63, 1, 40, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 215, 163, 48, 63, 0, 0, 128, 63, 1, 40, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 143, 194, 53, 63, 0, 0, 128, 63, 1, 40, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 72, 225, 58, 63, 0, 0, 128, 63, 1, 40, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 0, 0, 64, 63, 0, 0, +128, 63, 1, 40, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 184, 30, +69, 63, 0, 0, 128, 63, 1, 40, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 113, 61, 74, 63, 0, 0, 128, 63, 1, 40, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 41, 92, 79, 63, 0, 0, 128, 63, 1, 40, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 225, 122, 84, 63, 0, 0, 128, 63, 1, 40, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 154, 153, 89, 63, 0, 0, +128, 63, 1, 41, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 82, 184, +94, 63, 0, 0, 128, 63, 1, 41, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 10, 215, 99, 63, 0, 0, 128, 63, 1, 41, 0, 0, 197, 27, 57, 62, 26, 77, +128, 63, 218, 27, 12, 63, 195, 245, 104, 63, 0, 0, 128, 63, 1, 41, 0, 0, 197, 27, +57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 123, 20, 110, 63, 0, 0, 128, 63, 1, 41, +0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 51, 51, 115, 63, 0, 0, +128, 63, 1, 41, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, 12, 63, 236, 81, +120, 63, 0, 0, 128, 63, 1, 41, 0, 0, 197, 27, 57, 62, 26, 77, 128, 63, 218, 27, +12, 63, 164, 112, 125, 63, 0, 0, 128, 63, 1, 41, 0, 0, 116, 180, 117, 65, 12, 255, +254, 65, 64, 176, 103, 63, 41, 149, 112, 60, 228, 48, 144, 62, 1, 0, 1, 0, 95, 56, +119, 65, 20, 226, 254, 65, 0, 129, 41, 63, 6, 127, 63, 60, 144, 224, 166, 62, 1, 0, +1, 0, 175, 60, 125, 65, 168, 129, 9, 66, 48, 135, 41, 63, 6, 127, 63, 60, 110, 224, +166, 62, 1, 0, 1, 0, 195, 184, 123, 65, 35, 144, 9, 66, 112, 182, 103, 63, 41, 149, +112, 60, 228, 48, 144, 62, 1, 93, 1, 0, 124, 158, 120, 65, 86, 199, 254, 65, 64, 163, +214, 62, 149, 45, 18, 60, 24, 144, 189, 62, 1, 81, 1, 0, 204, 162, 126, 65, 73, 116, +9, 66, 192, 175, 214, 62, 149, 45, 18, 60, 24, 144, 189, 62, 1, 81, 1, 0, 15, 201, +121, 65, 12, 177, 254, 65, 0, 233, 134, 61, 107, 211, 216, 59, 108, 143, 222, 62, 1, 81, +1, 0, 94, 205, 127, 65, 36, 105, 9, 66, 0, 27, 135, 61, 107, 211, 216, 59, 108, 143, +222, 62, 1, 81, 1, 0, 190, 64, 122, 65, 35, 168, 254, 65, 64, 48, 147, 190, 31, 157, +186, 59, 226, 142, 255, 62, 1, 89, 1, 0, 135, 34, 128, 65, 175, 100, 9, 66, 192, 35, +147, 190, 31, 157, 186, 59, 226, 142, 255, 62, 1, 89, 1, 0, 63, 142, 121, 65, 130, 181, +254, 65, 128, 4, 53, 191, 145, 238, 231, 59, 28, 95, 19, 63, 1, 89, 1, 0, 143, 146, +127, 65, 95, 107, 9, 66, 64, 254, 52, 191, 145, 238, 231, 59, 11, 95, 19, 63, 1, 89, +1, 0, 232, 10, 120, 65, 122, 210, 254, 65, 64, 160, 137, 191, 157, 17, 37, 60, 189, 142, +36, 63, 1, 83, 1, 0, 55, 15, 126, 65, 219, 121, 9, 66, 32, 157, 137, 191, 157, 17, +37, 60, 189, 142, 36, 63, 1, 83, 1, 0, 129, 135, 118, 65, 114, 239, 254, 65, 8, 156, +170, 191, 191, 39, 86, 60, 138, 150, 48, 63, 1, 83, 1, 0, 209, 139, 124, 65, 87, 136, +9, 66, 232, 152, 170, 191, 191, 39, 86, 60, 138, 150, 48, 63, 1, 83, 1, 0, 186, 247, +115, 65, 121, 32, 255, 65, 216, 107, 206, 191, 136, 158, 148, 60, 80, 166, 61, 63, 1, 99, +1, 0, 9, 252, 121, 65, 218, 160, 9, 66, 192, 104, 206, 191, 136, 158, 148, 60, 80, 166, +61, 63, 1, 99, 1, 0, 144, 240, 112, 65, 106, 90, 255, 65, 40, 178, 234, 191, 195, 182, +197, 60, 27, 246, 71, 63, 1, 88, 1, 0, 224, 244, 118, 65, 211, 189, 9, 66, 16, 175, +234, 191, 195, 182, 197, 60, 27, 246, 71, 63, 1, 88, 1, 0, 16, 37, 110, 65, 229, 143, +255, 65, 144, 3, 3, 192, 28, 6, 243, 60, 242, 237, 81, 63, 1, 89, 1, 0, 95, 41, +116, 65, 145, 216, 9, 66, 4, 2, 3, 192, 28, 6, 243, 60, 242, 237, 81, 63, 1, 89, +1, 0, 243, 106, 106, 65, 53, 215, 255, 65, 176, 53, 16, 192, 90, 185, 23, 61, 197, 141, +91, 63, 1, 89, 1, 0, 66, 111, 112, 65, 57, 252, 9, 66, 32, 52, 16, 192, 90, 185, +23, 61, 180, 141, 91, 63, 1, 89, 1, 0, 53, 117, 102, 65, 124, 17, 0, 66, 108, 133, +27, 192, 11, 211, 55, 61, 154, 205, 99, 63, 1, 89, 1, 0, 132, 121, 108, 65, 27, 34, +10, 66, 220, 131, 27, 192, 11, 211, 55, 61, 154, 205, 99, 63, 1, 89, 1, 0, 97, 127, +98, 65, 94, 55, 0, 66, 116, 166, 33, 192, 175, 235, 87, 61, 137, 69, 104, 63, 1, 89, +1, 0, 175, 131, 104, 65, 253, 71, 10, 66, 228, 164, 33, 192, 175, 235, 87, 61, 137, 69, +104, 63, 1, 89, 1, 0, 215, 5, 93, 65, 189, 107, 0, 66, 158, 49, 41, 192, 250, 37, +130, 61, 97, 197, 109, 63, 1, 89, 1, 0, 39, 10, 99, 65, 91, 124, 10, 66, 16, 48, +41, 192, 250, 37, 130, 61, 97, 197, 109, 63, 1, 89, 1, 0, 206, 234, 85, 65, 181, 175, +0, 66, 62, 98, 46, 192, 120, 241, 158, 61, 88, 141, 113, 63, 1, 94, 1, 0, 30, 239, +91, 65, 83, 192, 10, 66, 176, 96, 46, 192, 120, 241, 158, 61, 88, 141, 113, 63, 1, 94, +1, 0, 87, 218, 50, 65, 23, 255, 1, 66, 166, 242, 45, 192, 195, 131, 22, 62, 84, 53, +113, 63, 1, 95, 1, 0, 166, 222, 56, 65, 181, 15, 12, 66, 24, 241, 45, 192, 195, 131, +22, 62, 84, 53, 113, 63, 1, 95, 1, 0, 87, 185, 50, 65, 52, 0, 2, 66, 32, 117, +191, 62, 81, 192, 22, 62, 4, 176, 193, 62, 1, 95, 1, 0, 167, 189, 56, 65, 210, 16, +12, 66, 160, 129, 191, 62, 81, 192, 22, 62, 4, 176, 193, 62, 1, 95, 1, 0, 255, 243, +86, 65, 173, 165, 0, 66, 0, 192, 191, 62, 146, 177, 154, 61, 4, 176, 193, 62, 1, 95, +1, 0, 79, 248, 92, 65, 76, 182, 10, 66, 128, 204, 191, 62, 146, 177, 154, 61, 4, 176, +193, 62, 1, 95, 1, 0, 38, 19, 87, 65, 144, 164, 0, 66, 160, 177, 109, 191, 252, 56, +154, 61, 230, 174, 29, 63, 1, 95, 1, 0, 118, 23, 93, 65, 47, 181, 10, 66, 96, 171, +109, 191, 252, 56, 154, 61, 230, 174, 29, 63, 1, 95, 1, 0, 50, 89, 71, 65, 252, 58, +1, 66, 128, 164, 111, 191, 187, 242, 217, 61, 234, 6, 30, 63, 1, 95, 1, 0, 128, 93, +77, 65, 154, 75, 11, 66, 64, 158, 111, 191, 187, 242, 217, 61, 234, 6, 30, 63, 1, 95, +1, 0, 181, 89, 71, 65, 252, 58, 1, 66, 128, 229, 183, 191, 187, 242, 217, 61, 124, 102, +53, 63, 1, 96, 1, 0, 5, 94, 77, 65, 154, 75, 11, 66, 96, 226, 183, 191, 187, 242, +217, 61, 106, 102, 53, 63, 1, 96, 1, 0, 53, 191, 84, 65, 217, 186, 0, 66, 64, 237, +182, 191, 244, 169, 163, 61, 103, 14, 53, 63, 1, 96, 1, 0, 133, 195, 90, 65, 120, 203, +10, 66, 40, 234, 182, 191, 244, 169, 163, 61, 103, 14, 53, 63, 1, 96, 1, 0, 28, 109, +87, 65, 57, 161, 0, 66, 56, 24, 180, 191, 45, 206, 152, 61, 108, 6, 52, 63, 1, 96, +1, 0, 108, 113, 93, 65, 215, 177, 10, 66, 24, 21, 180, 191, 45, 206, 152, 61, 108, 6, +52, 63, 1, 96, 1, 0, 221, 21, 92, 65, 167, 116, 0, 66, 192, 228, 166, 191, 196, 236, +133, 61, 139, 54, 47, 63, 1, 91, 1, 0, 44, 26, 98, 65, 69, 133, 10, 66, 160, 225, +166, 191, 196, 236, 133, 61, 139, 54, 47, 63, 1, 91, 1, 0, 147, 118, 95, 65, 87, 84, +0, 66, 168, 251, 148, 191, 205, 119, 112, 61, 168, 174, 40, 63, 1, 91, 1, 0, 226, 122, +101, 65, 245, 100, 10, 66, 144, 248, 148, 191, 205, 119, 112, 61, 168, 174, 40, 63, 1, 91, +1, 0, 230, 95, 98, 65, 124, 56, 0, 66, 32, 18, 119, 191, 232, 221, 88, 61, 216, 102, +31, 63, 1, 92, 1, 0, 54, 100, 104, 65, 26, 73, 10, 66, 240, 11, 119, 191, 232, 221, +88, 61, 216, 102, 31, 63, 1, 92, 1, 0, 110, 120, 100, 65, 110, 36, 0, 66, 80, 26, +53, 191, 93, 223, 71, 61, 28, 95, 19, 63, 1, 92, 1, 0, 190, 124, 106, 65, 12, 53, +10, 66, 16, 20, 53, 191, 93, 223, 71, 61, 28, 95, 19, 63, 1, 92, 1, 0, 164, 132, +101, 65, 102, 26, 0, 66, 192, 251, 5, 191, 158, 96, 63, 61, 50, 199, 10, 63, 1, 92, +1, 0, 243, 136, 107, 65, 5, 43, 10, 66, 128, 245, 5, 191, 158, 96, 63, 61, 50, 199, +10, 63, 1, 92, 1, 0, 97, 214, 101, 65, 86, 23, 0, 66, 0, 130, 128, 190, 210, 199, +60, 61, 0, 31, 252, 62, 1, 92, 1, 0, 177, 218, 107, 65, 244, 39, 10, 66, 160, 117, +128, 190, 210, 199, 60, 61, 0, 31, 252, 62, 1, 92, 1, 0, 138, 57, 101, 65, 48, 29, +0, 66, 0, 32, 67, 59, 153, 188, 65, 61, 90, 103, 228, 62, 1, 92, 1, 0, 217, 61, +107, 65, 206, 45, 10, 66, 0, 96, 73, 59, 153, 188, 65, 61, 90, 103, 228, 62, 1, 92, +1, 0, 177, 166, 99, 65, 58, 44, 0, 66, 224, 80, 135, 62, 196, 123, 78, 61, 206, 255, +203, 62, 1, 93, 1, 0, 2, 171, 105, 65, 216, 60, 10, 66, 64, 93, 135, 62, 196, 123, +78, 61, 206, 255, 203, 62, 1, 93, 1, 0, 5, 82, 97, 65, 131, 66, 0, 66, 128, 213, +240, 62, 179, 93, 97, 61, 38, 192, 184, 62, 1, 93, 1, 0, 84, 86, 103, 65, 33, 83, +10, 66, 0, 226, 240, 62, 179, 93, 97, 61, 38, 192, 184, 62, 1, 93, 1, 0, 249, 163, +94, 65, 35, 92, 0, 66, 64, 192, 35, 63, 52, 20, 119, 61, 132, 240, 168, 62, 1, 93, +1, 0, 73, 168, 100, 65, 194, 108, 10, 66, 128, 198, 35, 63, 52, 20, 119, 61, 98, 240, +168, 62, 1, 93, 1, 0, 80, 7, 91, 65, 174, 126, 0, 66, 48, 139, 71, 63, 35, 44, +138, 61, 156, 224, 155, 62, 1, 93, 1, 0, 159, 11, 97, 65, 76, 143, 10, 66, 112, 145, +71, 63, 35, 44, 138, 61, 156, 224, 155, 62, 1, 93, 1, 0, 178, 34, 86, 65, 122, 173, +0, 66, 240, 64, 92, 63, 197, 255, 157, 61, 206, 80, 148, 62, 1, 93, 1, 0, 3, 39, +92, 65, 25, 190, 10, 66, 48, 71, 92, 63, 197, 255, 157, 61, 206, 80, 148, 62, 1, 93, +1, 0, 169, 40, 51, 65, 7, 252, 1, 66, 0, 14, 93, 63, 144, 221, 21, 62, 220, 248, +147, 62, 1, 94, 1, 0, 249, 44, 57, 65, 165, 12, 12, 66, 64, 20, 93, 63, 144, 221, +21, 62, 220, 248, 147, 62, 1, 94, 1, 0, 249, 16, 51, 65, 220, 252, 1, 66, 112, 122, +9, 64, 233, 10, 22, 62, 144, 23, 96, 61, 1, 94, 1, 0, 73, 21, 57, 65, 122, 13, +12, 66, 0, 124, 9, 64, 233, 10, 22, 62, 144, 23, 96, 61, 1, 94, 1, 0, 76, 207, +88, 65, 218, 147, 0, 66, 72, 162, 9, 64, 133, 36, 147, 61, 80, 184, 94, 61, 1, 94, +1, 0, 156, 211, 94, 65, 120, 164, 10, 66, 220, 163, 9, 64, 133, 36, 147, 61, 80, 184, +94, 61, 1, 94, 1, 0, 251, 241, 98, 65, 234, 50, 0, 66, 80, 97, 253, 63, 242, 37, +84, 61, 216, 74, 175, 61, 1, 94, 1, 0, 75, 246, 104, 65, 136, 67, 10, 66, 120, 100, +253, 63, 242, 37, 84, 61, 216, 74, 175, 61, 1, 94, 1, 0, 96, 13, 106, 65, 229, 221, +255, 65, 48, 106, 220, 63, 247, 142, 26, 61, 160, 196, 7, 62, 1, 94, 1, 0, 175, 17, +112, 65, 144, 255, 9, 66, 72, 109, 220, 63, 247, 142, 26, 61, 160, 196, 7, 62, 1, 94, +1, 0, 134, 105, 111, 65, 98, 119, 255, 65, 216, 187, 182, 63, 213, 65, 222, 60, 152, 195, +62, 62, 1, 94, 1, 0, 214, 109, 117, 65, 79, 204, 9, 66, 248, 190, 182, 63, 213, 65, +222, 60, 152, 195, 62, 62, 1, 94, 1, 0, 67, 6, 115, 65, 77, 50, 255, 65, 144, 209, +148, 63, 174, 185, 163, 60, 216, 66, 112, 62, 1, 95, 1, 0, 148, 10, 121, 65, 196, 169, +9, 66, 176, 212, 148, 63, 174, 185, 163, 60, 216, 66, 112, 62, 1, 95, 1, 0, 30, 135, +197, 64, 41, 124, 4, 66, 32, 231, 89, 63, 93, 21, 152, 62, 248, 0, 149, 62, 1, 95, +1, 0, 104, 132, 197, 64, 41, 124, 4, 66, 228, 86, 10, 64, 93, 21, 152, 62, 48, 25, +85, 61, 1, 95, 1, 0, 199, 187, 206, 64, 166, 152, 14, 66, 20, 88, 10, 64, 93, 21, +152, 62, 48, 25, 85, 61, 1, 95, 1, 0, 123, 190, 206, 64, 166, 152, 14, 66, 240, 235, +89, 63, 93, 21, 152, 62, 214, 0, 149, 62, 1, 95, 1, 0, 38, 59, 37, 65, 116, 151, +2, 66, 16, 104, 10, 64, 214, 26, 42, 62, 48, 25, 85, 61, 1, 95, 1, 0, 213, 214, +41, 65, 241, 179, 12, 66, 68, 105, 10, 64, 214, 26, 42, 62, 48, 24, 85, 61, 1, 95, +1, 0, 129, 60, 37, 65, 116, 151, 2, 66, 208, 43, 90, 63, 214, 26, 42, 62, 214, 0, +149, 62, 1, 95, 1, 0, 48, 216, 41, 65, 241, 179, 12, 66, 160, 48, 90, 63, 214, 26, +42, 62, 214, 0, 149, 62, 1, 95, 1, 0, 225, 139, 197, 64, 41, 124, 4, 66, 232, 251, +185, 191, 93, 21, 152, 62, 114, 22, 54, 63, 1, 96, 1, 0, 214, 29, 17, 65, 59, 42, +3, 66, 248, 227, 185, 191, 137, 179, 82, 62, 114, 22, 54, 63, 1, 96, 1, 0, 133, 185, +21, 65, 184, 70, 13, 66, 144, 225, 185, 191, 137, 179, 82, 62, 114, 22, 54, 63, 1, 96, +1, 0, 61, 195, 206, 64, 166, 152, 14, 66, 136, 249, 185, 191, 93, 21, 152, 62, 114, 22, +54, 63, 1, 96, 1, 0, 72, 29, 17, 65, 59, 42, 3, 66, 16, 53, 106, 191, 137, 179, +82, 62, 240, 254, 28, 63, 1, 96, 1, 0, 247, 184, 21, 65, 184, 70, 13, 66, 64, 48, +106, 191, 137, 179, 82, 62, 240, 254, 28, 63, 1, 96, 1, 0, 227, 155, 240, 64, 36, 223, +3, 66, 192, 78, 106, 191, 120, 94, 130, 62, 240, 254, 28, 63, 1, 96, 1, 0, 63, 211, +249, 64, 161, 251, 13, 66, 240, 73, 106, 191, 120, 94, 130, 62, 240, 254, 28, 63, 1, 96, +1, 0, 62, 93, 240, 64, 255, 223, 3, 66, 0, 55, 187, 62, 191, 124, 130, 62, 12, 96, +194, 62, 1, 96, 1, 0, 154, 148, 249, 64, 124, 252, 13, 66, 160, 64, 187, 62, 191, 124, +130, 62, 12, 96, 194, 62, 1, 96, 1, 0, 245, 27, 17, 65, 59, 42, 3, 66, 128, 106, +187, 62, 137, 179, 82, 62, 12, 96, 194, 62, 1, 97, 1, 0, 164, 183, 21, 65, 184, 70, +13, 66, 32, 116, 187, 62, 137, 179, 82, 62, 12, 96, 194, 62, 1, 97, 1, 0, 18, 1, +37, 65, 41, 153, 2, 66, 160, 147, 187, 62, 175, 147, 42, 62, 12, 96, 194, 62, 1, 97, +1, 0, 191, 156, 41, 65, 166, 181, 12, 66, 64, 157, 187, 62, 175, 147, 42, 62, 12, 96, +194, 62, 1, 97, 1, 0, 101, 2, 37, 65, 41, 153, 2, 66, 128, 32, 106, 191, 175, 147, +42, 62, 240, 254, 28, 63, 1, 97, 1, 0, 18, 158, 41, 65, 166, 181, 12, 66, 176, 27, +106, 191, 175, 147, 42, 62, 240, 254, 28, 63, 1, 97, 1, 0, 64, 4, 37, 65, 41, 153, +2, 66, 150, 125, 45, 192, 175, 147, 42, 62, 81, 221, 112, 63, 1, 97, 1, 0, 239, 159, +41, 65, 166, 181, 12, 66, 100, 124, 45, 192, 175, 147, 42, 62, 81, 221, 112, 63, 1, 97, +1, 0, 35, 31, 17, 65, 59, 42, 3, 66, 188, 130, 45, 192, 137, 179, 82, 62, 81, 221, +112, 63, 1, 97, 1, 0, 209, 186, 21, 65, 184, 70, 13, 66, 138, 129, 45, 192, 137, 179, +82, 62, 81, 221, 112, 63, 1, 97, 1, 0, 34, 31, 17, 65, 59, 42, 3, 66, 42, 10, +45, 192, 137, 179, 82, 62, 94, 133, 112, 63, 1, 97, 1, 0, 207, 186, 21, 65, 184, 70, +13, 66, 248, 8, 45, 192, 137, 179, 82, 62, 94, 133, 112, 63, 1, 97, 1, 0, 120, 142, +197, 64, 41, 124, 4, 66, 36, 22, 45, 192, 93, 21, 152, 62, 94, 133, 112, 63, 1, 98, +1, 0, 214, 197, 206, 64, 166, 152, 14, 66, 242, 20, 45, 192, 93, 21, 152, 62, 94, 133, +112, 63, 1, 98, 1, 0, 200, 224, 142, 64, 43, 229, 4, 66, 128, 23, 190, 190, 63, 196, +182, 62, 88, 143, 3, 63, 1, 98, 1, 0, 71, 170, 155, 63, 140, 147, 5, 66, 40, 72, +43, 192, 154, 237, 234, 62, 112, 37, 111, 63, 1, 98, 1, 0, 103, 181, 172, 63, 55, 189, +15, 66, 154, 71, 43, 192, 154, 237, 234, 62, 112, 37, 111, 63, 1, 98, 1, 0, 144, 35, +147, 64, 213, 14, 15, 66, 32, 19, 190, 190, 63, 196, 182, 62, 88, 143, 3, 63, 1, 98, +1, 0, 102, 130, 155, 63, 140, 147, 5, 66, 44, 81, 9, 64, 154, 237, 234, 62, 160, 24, +96, 61, 1, 98, 1, 0, 134, 141, 172, 63, 55, 189, 15, 66, 184, 81, 9, 64, 154, 237, +234, 62, 160, 24, 96, 61, 1, 98, 1, 0, 175, 38, 31, 64, 76, 79, 5, 66, 248, 206, +9, 64, 27, 131, 214, 62, 112, 153, 90, 61, 1, 98, 1, 0, 63, 172, 39, 64, 246, 120, +15, 66, 128, 207, 9, 64, 27, 131, 214, 62, 112, 153, 90, 61, 1, 98, 1, 0, 53, 184, +30, 64, 177, 79, 5, 66, 128, 1, 117, 190, 64, 161, 214, 62, 240, 190, 250, 62, 1, 20, +1, 0, 197, 61, 39, 64, 91, 121, 15, 66, 128, 248, 116, 190, 64, 161, 214, 62, 240, 190, +250, 62, 1, 20, 1, 0, 136, 202, 183, 64, 133, 160, 4, 66, 152, 114, 8, 64, 121, 59, +162, 62, 32, 25, 107, 61, 1, 20, 1, 0, 78, 13, 188, 64, 48, 202, 14, 66, 36, 115, +8, 64, 121, 59, 162, 62, 32, 25, 107, 61, 1, 20, 1, 0, 238, 76, 184, 64, 188, 159, +4, 66, 176, 129, 46, 192, 46, 255, 161, 62, 105, 141, 113, 63, 1, 20, 1, 0, 182, 143, +188, 64, 102, 201, 14, 66, 32, 129, 46, 192, 46, 255, 161, 62, 105, 141, 113, 63, 1, 20, +1, 0, 5, 94, 143, 64, 97, 228, 4, 66, 250, 134, 46, 192, 211, 135, 182, 62, 105, 141, +113, 63, 1, 124, 1, 0, 205, 160, 147, 64, 12, 14, 15, 66, 108, 134, 46, 192, 211, 135, +182, 62, 105, 141, 113, 63, 1, 124, 1, 0, 158, 92, 77, 192, 29, 124, 4, 66, 144, 46, +91, 63, 90, 185, 31, 63, 162, 237, 144, 62, 1, 124, 1, 0, 11, 98, 77, 192, 29, 124, +4, 66, 188, 168, 10, 64, 19, 186, 31, 63, 128, 235, 238, 60, 1, 124, 1, 0, 190, 189, +88, 192, 0, 163, 14, 66, 0, 168, 10, 64, 22, 48, 33, 63, 160, 18, 9, 61, 1, 124, +1, 0, 86, 184, 88, 192, 0, 163, 14, 66, 176, 43, 91, 63, 111, 47, 33, 63, 62, 33, +147, 62, 1, 125, 1, 0, 64, 76, 118, 63, 203, 166, 5, 66, 248, 185, 10, 64, 227, 197, +250, 62, 160, 75, 241, 60, 1, 125, 1, 0, 97, 221, 72, 63, 174, 205, 15, 66, 60, 185, +10, 64, 234, 177, 253, 62, 176, 66, 10, 61, 1, 125, 1, 0, 225, 97, 118, 63, 203, 166, +5, 66, 144, 115, 91, 63, 114, 196, 250, 62, 164, 19, 145, 62, 1, 125, 1, 0, 19, 243, +72, 63, 174, 205, 15, 66, 160, 112, 91, 63, 154, 176, 253, 62, 66, 71, 147, 62, 1, 125, +1, 0, 26, 83, 77, 192, 29, 124, 4, 66, 72, 88, 185, 191, 44, 184, 31, 63, 22, 194, +58, 63, 1, 125, 1, 0, 215, 166, 153, 190, 89, 76, 5, 66, 56, 64, 185, 191, 29, 199, +7, 63, 82, 207, 58, 63, 1, 125, 1, 0, 148, 132, 244, 190, 60, 115, 15, 66, 176, 65, +185, 191, 33, 61, 9, 63, 33, 233, 59, 63, 1, 125, 1, 0, 209, 174, 88, 192, 0, 163, +14, 66, 192, 89, 185, 191, 48, 46, 33, 63, 244, 219, 59, 63, 1, 125, 1, 0, 136, 184, +153, 190, 89, 76, 5, 66, 128, 237, 104, 191, 96, 199, 7, 63, 66, 39, 32, 63, 1, 125, +1, 0, 70, 150, 244, 190, 60, 115, 15, 66, 96, 240, 104, 191, 117, 61, 9, 63, 32, 65, +33, 63, 1, 125, 1, 0, 133, 181, 237, 191, 222, 220, 4, 66, 64, 7, 105, 191, 162, 152, +20, 63, 46, 32, 32, 63, 1, 126, 1, 0, 122, 54, 2, 192, 193, 3, 15, 66, 32, 10, +105, 191, 166, 14, 22, 63, 252, 57, 33, 63, 1, 126, 1, 0, 150, 176, 238, 191, 88, 220, +4, 66, 0, 198, 189, 62, 193, 168, 20, 63, 52, 45, 193, 62, 1, 126, 1, 0, 3, 180, +2, 192, 59, 3, 15, 66, 64, 192, 189, 62, 214, 30, 22, 63, 242, 96, 195, 62, 1, 126, +1, 0, 0, 227, 153, 190, 89, 76, 5, 66, 224, 249, 189, 62, 25, 200, 7, 63, 126, 59, +193, 62, 1, 126, 1, 0, 156, 192, 244, 190, 60, 115, 15, 66, 224, 243, 189, 62, 29, 62, +9, 63, 26, 111, 195, 62, 1, 126, 1, 0, 189, 167, 114, 63, 190, 165, 5, 66, 32, 35, +190, 62, 201, 1, 251, 62, 228, 70, 193, 62, 1, 126, 1, 0, 222, 56, 69, 63, 161, 204, +15, 66, 64, 29, 190, 62, 242, 237, 253, 62, 128, 122, 195, 62, 1, 126, 1, 0, 232, 188, +114, 63, 190, 165, 5, 66, 208, 216, 104, 191, 122, 0, 251, 62, 245, 44, 32, 63, 1, 126, +1, 0, 9, 78, 69, 63, 161, 204, 15, 66, 192, 219, 104, 191, 129, 236, 253, 62, 195, 70, +33, 63, 1, 126, 1, 0, 152, 218, 114, 63, 190, 165, 5, 66, 176, 43, 45, 192, 130, 254, +250, 62, 27, 70, 121, 63, 1, 127, 1, 0, 186, 107, 69, 63, 161, 204, 15, 66, 108, 44, +45, 192, 171, 234, 253, 62, 233, 95, 122, 63, 1, 127, 1, 0, 40, 125, 153, 190, 89, 76, +5, 66, 216, 48, 45, 192, 118, 198, 7, 63, 104, 64, 121, 63, 1, 127, 1, 0, 230, 90, +244, 190, 60, 115, 15, 66, 154, 49, 45, 192, 121, 60, 9, 63, 54, 90, 122, 63, 1, 127, +1, 0, 107, 125, 153, 190, 89, 76, 5, 66, 62, 184, 44, 192, 118, 198, 7, 63, 244, 226, +120, 63, 1, 127, 1, 0, 41, 91, 244, 190, 60, 115, 15, 66, 250, 184, 44, 192, 121, 60, +9, 63, 194, 252, 121, 63, 1, 127, 1, 0, 236, 77, 77, 192, 29, 124, 4, 66, 68, 196, +44, 192, 132, 183, 31, 63, 182, 213, 120, 63, 1, 127, 1, 0, 164, 169, 88, 192, 0, 163, +14, 66, 2, 197, 44, 192, 136, 45, 33, 63, 133, 239, 121, 63, 1, 127, 1, 0, 146, 60, +255, 192, 216, 239, 1, 66, 240, 39, 28, 191, 240, 248, 70, 63, 8, 234, 16, 63, 1, 127, +1, 0, 120, 52, 251, 192, 177, 255, 1, 66, 192, 223, 204, 190, 116, 239, 69, 63, 27, 131, +6, 63, 1, 127, 1, 0, 58, 144, 2, 193, 129, 25, 12, 66, 224, 233, 204, 190, 233, 124, +72, 63, 254, 155, 7, 63, 1, 127, 1, 0, 71, 148, 4, 193, 168, 9, 12, 66, 16, 45, +28, 191, 119, 134, 73, 63, 218, 2, 18, 63, 1, 128, 1, 0, 0, 31, 246, 192, 172, 19, +2, 66, 192, 123, 89, 190, 161, 160, 68, 63, 34, 106, 250, 62, 1, 128, 1, 0, 125, 5, +0, 193, 124, 45, 12, 66, 64, 144, 89, 190, 23, 46, 71, 63, 200, 155, 252, 62, 1, 128, +1, 0, 13, 41, 240, 192, 25, 43, 2, 66, 0, 170, 201, 188, 1, 24, 67, 63, 150, 206, +231, 62, 1, 128, 1, 0, 9, 21, 250, 192, 234, 68, 12, 66, 0, 78, 202, 188, 118, 165, +69, 63, 58, 0, 234, 62, 1, 128, 1, 0, 173, 37, 233, 192, 169, 70, 2, 66, 64, 39, +5, 62, 27, 74, 65, 63, 234, 124, 216, 62, 1, 128, 1, 0, 167, 17, 243, 192, 121, 96, +12, 66, 192, 18, 5, 62, 144, 215, 67, 63, 142, 174, 218, 62, 1, 128, 1, 0, 28, 250, +222, 192, 159, 110, 2, 66, 160, 206, 128, 62, 67, 172, 62, 63, 210, 118, 204, 62, 1, 128, +1, 0, 27, 230, 232, 192, 112, 136, 12, 66, 128, 196, 128, 62, 201, 57, 65, 63, 118, 168, +206, 62, 1, 128, 1, 0, 187, 139, 207, 192, 66, 171, 2, 66, 224, 84, 170, 62, 255, 179, +58, 63, 32, 120, 196, 62, 1, 128, 1, 0, 184, 119, 217, 192, 18, 197, 12, 66, 160, 74, +170, 62, 116, 65, 61, 63, 198, 169, 198, 62, 1, 128, 1, 0, 54, 145, 185, 192, 157, 1, +3, 66, 192, 166, 166, 62, 111, 12, 53, 63, 116, 65, 197, 62, 1, 129, 1, 0, 51, 125, +195, 192, 109, 27, 13, 66, 128, 156, 166, 62, 229, 153, 55, 63, 24, 115, 199, 62, 1, 129, +1, 0, 23, 1, 163, 192, 68, 90, 3, 66, 32, 239, 179, 62, 104, 62, 47, 63, 178, 193, +194, 62, 1, 129, 1, 0, 20, 237, 172, 192, 20, 116, 13, 66, 224, 228, 179, 62, 222, 203, +49, 63, 86, 243, 196, 62, 1, 129, 1, 0, 203, 203, 158, 192, 205, 106, 3, 66, 0, 56, +208, 62, 65, 41, 46, 63, 94, 74, 189, 62, 1, 129, 1, 0, 197, 183, 168, 192, 158, 132, +13, 66, 192, 45, 208, 62, 183, 182, 48, 63, 2, 124, 191, 62, 1, 129, 1, 0, 184, 190, +157, 192, 240, 110, 3, 66, 240, 175, 15, 63, 252, 227, 45, 63, 228, 244, 173, 62, 1, 129, +1, 0, 180, 170, 167, 192, 192, 136, 13, 66, 208, 170, 15, 63, 113, 113, 48, 63, 138, 38, +176, 62, 1, 129, 1, 0, 207, 172, 159, 192, 91, 103, 3, 66, 64, 49, 48, 63, 32, 99, +46, 63, 142, 90, 161, 62, 1, 129, 1, 0, 206, 152, 169, 192, 44, 129, 13, 66, 32, 44, +48, 63, 149, 240, 48, 63, 50, 140, 163, 62, 1, 129, 1, 0, 81, 78, 162, 192, 6, 93, +3, 66, 176, 126, 59, 63, 102, 16, 47, 63, 2, 247, 156, 62, 1, 130, 1, 0, 75, 58, +172, 192, 214, 118, 13, 66, 144, 121, 59, 63, 220, 157, 49, 63, 166, 40, 159, 62, 1, 130, +1, 0, 119, 145, 163, 192, 16, 88, 3, 66, 32, 72, 65, 63, 128, 99, 47, 63, 220, 183, +154, 62, 1, 130, 1, 0, 116, 125, 173, 192, 224, 113, 13, 66, 0, 67, 65, 63, 6, 241, +49, 63, 130, 233, 156, 62, 1, 130, 1, 0, 246, 124, 226, 192, 216, 96, 2, 66, 0, 229, +58, 63, 138, 147, 63, 63, 252, 251, 156, 62, 1, 130, 1, 0, 241, 104, 236, 192, 168, 122, +12, 66, 208, 223, 58, 63, 255, 32, 66, 63, 162, 45, 159, 62, 1, 130, 1, 0, 205, 41, +8, 193, 200, 172, 1, 66, 160, 129, 3, 64, 133, 94, 75, 63, 240, 74, 75, 61, 1, 130, +1, 0, 203, 31, 13, 193, 152, 198, 11, 66, 84, 128, 3, 64, 251, 235, 77, 63, 16, 216, +92, 61, 1, 130, 1, 0, 22, 190, 150, 192, 127, 138, 3, 66, 84, 145, 3, 64, 206, 22, +44, 63, 48, 195, 77, 61, 1, 130, 1, 0, 19, 170, 160, 192, 80, 164, 13, 66, 12, 144, +3, 64, 68, 164, 46, 63, 96, 80, 95, 61, 1, 130, 1, 0, 124, 66, 143, 192, 229, 167, +3, 66, 56, 184, 253, 63, 250, 41, 42, 63, 248, 43, 132, 61, 1, 131, 1, 0, 119, 46, +153, 192, 182, 193, 13, 66, 176, 181, 253, 63, 111, 183, 44, 63, 144, 242, 140, 61, 1, 131, +1, 0, 236, 105, 137, 192, 221, 190, 3, 66, 184, 227, 242, 63, 244, 168, 40, 63, 16, 211, +165, 61, 1, 131, 1, 0, 233, 85, 147, 192, 173, 216, 13, 66, 48, 225, 242, 63, 105, 54, +43, 63, 168, 153, 174, 61, 1, 131, 1, 0, 190, 161, 130, 192, 129, 217, 3, 66, 120, 133, +224, 63, 66, 234, 38, 63, 248, 219, 222, 61, 1, 131, 1, 0, 187, 141, 140, 192, 82, 243, +13, 66, 224, 130, 224, 63, 184, 119, 41, 63, 136, 162, 231, 61, 1, 131, 1, 0, 8, 146, +121, 192, 121, 240, 3, 66, 216, 218, 202, 63, 60, 105, 37, 63, 192, 13, 17, 62, 1, 131, +1, 0, 254, 180, 134, 192, 73, 10, 14, 66, 72, 216, 202, 63, 178, 246, 39, 63, 8, 113, +21, 62, 1, 131, 1, 0, 187, 71, 111, 192, 175, 4, 4, 66, 8, 48, 181, 63, 89, 22, +36, 63, 116, 172, 50, 62, 1, 131, 1, 0, 218, 143, 129, 192, 127, 30, 14, 66, 120, 45, +181, 63, 207, 163, 38, 63, 192, 15, 55, 62, 1, 131, 1, 0, 70, 34, 106, 192, 202, 14, +4, 66, 208, 43, 165, 63, 223, 108, 35, 63, 152, 132, 75, 62, 1, 131, 1, 0, 64, 250, +125, 192, 154, 40, 14, 66, 64, 41, 165, 63, 85, 250, 37, 63, 224, 231, 79, 62, 1, 131, +1, 0, 202, 252, 100, 192, 229, 24, 4, 66, 96, 54, 148, 63, 101, 195, 34, 63, 140, 210, +101, 62, 1, 132, 1, 0, 195, 212, 120, 192, 181, 50, 14, 66, 200, 51, 148, 63, 219, 80, +37, 63, 216, 53, 106, 62, 1, 132, 1, 0, 5, 79, 96, 192, 21, 34, 4, 66, 192, 21, +125, 63, 82, 41, 34, 63, 204, 182, 131, 62, 1, 132, 1, 0, 254, 38, 116, 192, 229, 59, +14, 66, 144, 16, 125, 63, 200, 182, 36, 63, 112, 232, 133, 62, 1, 132, 1, 0, 27, 128, +93, 192, 152, 39, 4, 66, 16, 131, 85, 63, 217, 204, 33, 63, 216, 13, 147, 62, 1, 132, +1, 0, 25, 88, 113, 192, 104, 65, 14, 66, 240, 125, 85, 63, 79, 90, 36, 63, 124, 63, +149, 62, 1, 132, 1, 0, 99, 100, 91, 192, 186, 43, 4, 66, 144, 156, 18, 63, 98, 135, +33, 63, 152, 251, 172, 62, 1, 132, 1, 0, 88, 60, 111, 192, 138, 69, 14, 66, 112, 151, +18, 63, 232, 20, 36, 63, 60, 45, 175, 62, 1, 132, 1, 0, 172, 116, 91, 192, 153, 43, +4, 66, 96, 207, 0, 63, 122, 137, 33, 63, 168, 225, 179, 62, 1, 132, 1, 0, 161, 76, +111, 192, 106, 69, 14, 66, 64, 202, 0, 63, 1, 23, 36, 63, 76, 19, 182, 62, 1, 132, +1, 0, 39, 159, 91, 192, 69, 43, 4, 66, 160, 138, 227, 62, 252, 142, 33, 63, 132, 181, +185, 62, 1, 133, 1, 0, 33, 119, 111, 192, 22, 69, 14, 66, 96, 128, 227, 62, 113, 28, +36, 63, 42, 231, 187, 62, 1, 133, 1, 0, 94, 217, 91, 192, 211, 42, 4, 66, 128, 248, +202, 62, 116, 150, 33, 63, 58, 120, 190, 62, 1, 133, 1, 0, 87, 177, 111, 192, 163, 68, +14, 66, 64, 238, 202, 62, 234, 35, 36, 63, 222, 169, 192, 62, 1, 133, 1, 0, 227, 24, +92, 192, 86, 42, 4, 66, 224, 227, 183, 62, 165, 158, 33, 63, 144, 42, 194, 62, 1, 133, +1, 0, 220, 240, 111, 192, 38, 68, 14, 66, 192, 217, 183, 62, 27, 44, 36, 63, 54, 92, +196, 62, 1, 133, 1, 0, 51, 83, 92, 192, 227, 41, 4, 66, 64, 72, 170, 62, 30, 166, +33, 63, 116, 205, 196, 62, 1, 133, 1, 0, 44, 43, 112, 192, 179, 67, 14, 66, 0, 62, +170, 62, 148, 51, 36, 63, 26, 255, 198, 62, 1, 133, 1, 0, 221, 125, 92, 192, 143, 41, +4, 66, 96, 33, 162, 62, 159, 171, 33, 63, 174, 97, 198, 62, 1, 133, 1, 0, 214, 85, +112, 192, 95, 67, 14, 66, 32, 23, 162, 62, 21, 57, 36, 63, 116, 147, 200, 62, 1, 133, +1, 0, 105, 142, 92, 192, 110, 41, 4, 66, 192, 106, 159, 62, 184, 173, 33, 63, 74, 232, +198, 62, 1, 134, 1, 0, 98, 102, 112, 192, 63, 67, 14, 66, 128, 96, 159, 62, 63, 59, +36, 63, 240, 25, 201, 62, 1, 134, 1, 0, 128, 241, 95, 192, 197, 34, 4, 66, 128, 128, +166, 61, 67, 29, 34, 63, 166, 185, 221, 62, 1, 134, 1, 0, 121, 201, 115, 192, 149, 60, +14, 66, 128, 87, 166, 61, 201, 170, 36, 63, 74, 235, 223, 62, 1, 134, 1, 0, 54, 91, +104, 192, 60, 18, 4, 66, 192, 31, 77, 190, 89, 50, 35, 63, 46, 166, 249, 62, 1, 134, +1, 0, 47, 51, 124, 192, 12, 44, 14, 66, 64, 52, 77, 190, 207, 191, 37, 63, 212, 215, +251, 62, 1, 134, 1, 0, 96, 147, 115, 192, 47, 252, 3, 66, 32, 36, 224, 190, 198, 163, +36, 63, 11, 152, 8, 63, 1, 134, 1, 0, 170, 181, 131, 192, 0, 22, 14, 66, 128, 46, +224, 190, 60, 49, 39, 63, 222, 176, 9, 63, 1, 134, 1, 0, 160, 53, 129, 192, 4, 223, +3, 66, 0, 83, 37, 191, 156, 140, 38, 63, 100, 230, 18, 63, 1, 134, 1, 0, 159, 33, +139, 192, 213, 248, 13, 66, 32, 88, 37, 191, 17, 26, 41, 63, 54, 255, 19, 63, 1, 134, +1, 0, 50, 185, 140, 192, 197, 177, 3, 66, 0, 91, 94, 191, 237, 130, 41, 63, 104, 238, +29, 63, 1, 134, 1, 0, 47, 165, 150, 192, 150, 203, 13, 66, 32, 96, 94, 191, 98, 16, +44, 63, 58, 7, 31, 63, 1, 134, 1, 0, 81, 4, 150, 192, 65, 141, 3, 66, 176, 41, +114, 191, 8, 231, 43, 63, 252, 192, 33, 63, 1, 135, 1, 0, 78, 240, 159, 192, 17, 167, +13, 66, 224, 46, 114, 191, 126, 116, 46, 63, 207, 217, 34, 63, 1, 135, 1, 0, 207, 107, +160, 192, 95, 100, 3, 66, 232, 25, 129, 191, 70, 148, 46, 63, 36, 216, 36, 63, 1, 135, +1, 0, 203, 87, 170, 192, 48, 126, 13, 66, 120, 28, 129, 191, 188, 33, 49, 63, 246, 240, +37, 63, 1, 135, 1, 0, 17, 170, 205, 192, 155, 178, 2, 66, 120, 218, 129, 191, 17, 56, +58, 63, 132, 15, 37, 63, 1, 135, 1, 0, 11, 150, 215, 192, 108, 204, 12, 66, 8, 221, +129, 191, 135, 197, 60, 63, 86, 40, 38, 63, 1, 135, 1, 0, 223, 239, 208, 192, 190, 165, +2, 66, 176, 253, 143, 191, 157, 15, 59, 63, 173, 136, 42, 63, 1, 135, 1, 0, 219, 219, +218, 192, 143, 191, 12, 66, 56, 0, 144, 191, 19, 157, 61, 63, 128, 161, 43, 63, 1, 135, +1, 0, 145, 239, 208, 192, 190, 165, 2, 66, 80, 214, 162, 191, 140, 15, 59, 63, 74, 214, +49, 63, 1, 135, 1, 0, 142, 219, 218, 192, 143, 191, 12, 66, 216, 216, 162, 191, 2, 157, +61, 63, 28, 239, 50, 63, 1, 135, 1, 0, 228, 92, 206, 192, 218, 175, 2, 66, 184, 6, +176, 191, 19, 102, 58, 63, 212, 243, 54, 63, 1, 136, 1, 0, 222, 72, 216, 192, 170, 201, +12, 66, 64, 9, 176, 191, 136, 243, 60, 63, 166, 12, 56, 63, 1, 136, 1, 0, 123, 121, +206, 192, 105, 175, 2, 66, 48, 233, 177, 191, 106, 109, 58, 63, 188, 174, 55, 63, 1, 136, +1, 0, 119, 101, 216, 192, 57, 201, 12, 66, 184, 235, 177, 191, 223, 250, 60, 63, 142, 199, +56, 63, 1, 136, 1, 0, 46, 255, 92, 192, 131, 40, 4, 66, 96, 208, 177, 191, 69, 188, +33, 63, 238, 205, 55, 63, 1, 136, 1, 0, 40, 215, 112, 192, 83, 66, 14, 66, 232, 210, +177, 191, 186, 73, 36, 63, 192, 230, 56, 63, 1, 136, 1, 0, 194, 249, 92, 192, 131, 40, +4, 66, 64, 197, 44, 192, 140, 187, 33, 63, 100, 205, 120, 63, 1, 136, 1, 0, 187, 209, +112, 192, 83, 66, 14, 66, 136, 198, 44, 192, 2, 73, 36, 63, 54, 230, 121, 63, 1, 136, +1, 0, 111, 2, 214, 192, 195, 145, 2, 66, 144, 90, 46, 192, 167, 93, 60, 63, 135, 219, +121, 63, 1, 136, 1, 0, 108, 238, 223, 192, 148, 171, 12, 66, 210, 91, 46, 192, 45, 235, +62, 63, 90, 244, 122, 63, 1, 136, 1, 0, 166, 27, 217, 192, 151, 133, 2, 66, 166, 72, +44, 192, 187, 41, 61, 63, 129, 63, 120, 63, 1, 137, 1, 0, 163, 7, 227, 192, 103, 159, +12, 66, 238, 73, 44, 192, 49, 183, 63, 63, 84, 88, 121, 63, 1, 137, 1, 0, 165, 78, +232, 192, 224, 73, 2, 66, 12, 149, 32, 192, 203, 18, 65, 63, 86, 39, 111, 63, 1, 137, +1, 0, 161, 58, 242, 192, 177, 99, 12, 66, 88, 150, 32, 192, 64, 160, 67, 63, 41, 64, +112, 63, 1, 137, 1, 0, 76, 196, 243, 192, 220, 28, 2, 66, 56, 175, 14, 192, 146, 5, +68, 63, 91, 67, 97, 63, 1, 137, 1, 0, 71, 176, 253, 192, 172, 54, 12, 66, 128, 176, +14, 192, 8, 147, 70, 63, 45, 92, 98, 63, 1, 137, 1, 0, 159, 173, 248, 192, 145, 9, +2, 66, 200, 217, 3, 192, 254, 72, 69, 63, 173, 219, 88, 63, 1, 137, 1, 0, 207, 76, +1, 193, 97, 35, 12, 66, 16, 219, 3, 192, 132, 214, 71, 63, 128, 244, 89, 63, 1, 137, +1, 0, 224, 47, 252, 192, 201, 251, 1, 66, 216, 37, 240, 191, 35, 48, 70, 63, 140, 185, +79, 63, 1, 137, 1, 0, 238, 13, 3, 193, 154, 21, 12, 66, 104, 40, 240, 191, 152, 189, +72, 63, 95, 210, 80, 63, 1, 137, 1, 0, 141, 254, 254, 192, 195, 240, 1, 66, 120, 181, +214, 191, 3, 233, 70, 63, 182, 220, 69, 63, 1, 137, 1, 0, 68, 117, 4, 193, 147, 10, +12, 66, 8, 184, 214, 191, 121, 118, 73, 63, 136, 245, 70, 63, 1, 137, 1, 0, 206, 170, +0, 193, 147, 231, 1, 66, 120, 247, 181, 191, 39, 131, 71, 63, 128, 43, 57, 63, 1, 138, +1, 0, 204, 160, 5, 193, 100, 1, 12, 66, 0, 250, 181, 191, 157, 16, 74, 63, 82, 68, +58, 63, 1, 138, 1, 0, 83, 171, 0, 193, 147, 231, 1, 66, 240, 79, 107, 191, 107, 131, +71, 63, 129, 63, 32, 63, 1, 138, 1, 0, 81, 161, 5, 193, 100, 1, 12, 66, 16, 85, +107, 191, 224, 16, 74, 63, 84, 88, 33, 63, 1, 138, 1, 0, 23, 247, 33, 193, 26, 59, +0, 66, 112, 40, 100, 63, 72, 165, 88, 63, 118, 135, 140, 62, 1, 138, 1, 0, 114, 248, +33, 193, 26, 59, 0, 66, 56, 231, 12, 64, 240, 165, 88, 63, 160, 134, 168, 60, 1, 138, +1, 0, 12, 22, 42, 193, 9, 52, 10, 66, 32, 229, 12, 64, 246, 210, 92, 63, 160, 68, +203, 60, 1, 138, 1, 0, 177, 20, 42, 193, 9, 52, 10, 66, 48, 32, 100, 63, 78, 210, +92, 63, 54, 179, 142, 62, 1, 101, 1, 0, 228, 108, 13, 193, 158, 70, 1, 66, 136, 236, +12, 64, 178, 19, 78, 63, 96, 161, 171, 60, 1, 64, 1, 0, 126, 138, 21, 193, 141, 63, +11, 66, 112, 234, 12, 64, 184, 64, 82, 63, 128, 95, 206, 60, 1, 64, 1, 0, 137, 107, +13, 193, 158, 70, 1, 66, 192, 61, 100, 63, 249, 18, 78, 63, 36, 185, 140, 62, 1, 35, +1, 0, 35, 137, 21, 193, 141, 63, 11, 66, 112, 53, 100, 63, 255, 63, 82, 63, 226, 228, +142, 62, 1, 35, 1, 0, 36, 2, 34, 193, 90, 58, 0, 66, 254, 43, 44, 192, 235, 170, +88, 63, 184, 233, 119, 63, 1, 35, 1, 0, 86, 5, 34, 193, 90, 58, 0, 66, 128, 171, +205, 62, 159, 172, 88, 63, 10, 24, 189, 62, 1, 35, 1, 0, 240, 34, 42, 193, 73, 51, +10, 66, 0, 155, 205, 62, 165, 217, 92, 63, 200, 67, 191, 62, 1, 35, 1, 0, 190, 31, +42, 193, 73, 51, 10, 66, 20, 46, 44, 192, 241, 215, 92, 63, 151, 255, 120, 63, 1, 35, +1, 0, 216, 121, 13, 193, 221, 69, 1, 66, 0, 214, 205, 62, 97, 26, 78, 63, 182, 73, +189, 62, 1, 35, 1, 0, 114, 151, 21, 193, 205, 62, 11, 66, 96, 197, 205, 62, 86, 71, +82, 63, 116, 117, 191, 62, 1, 35, 1, 0, 166, 118, 13, 193, 222, 69, 1, 66, 176, 38, +44, 192, 173, 24, 78, 63, 142, 2, 120, 63, 1, 35, 1, 0, 64, 148, 21, 193, 205, 62, +11, 66, 196, 40, 44, 192, 179, 69, 82, 63, 110, 24, 121, 63, 1, 35, 1, 0, 69, 41, +110, 193, 65, 91, 245, 65, 176, 193, 9, 191, 14, 218, 127, 63, 62, 144, 12, 63, 1, 36, +1, 0, 132, 53, 108, 193, 239, 162, 245, 65, 96, 20, 168, 190, 245, 216, 126, 63, 157, 43, +2, 63, 1, 36, 1, 0, 233, 109, 119, 193, 199, 153, 4, 66, 128, 43, 168, 190, 118, 79, +130, 63, 230, 60, 3, 63, 1, 36, 1, 0, 171, 97, 121, 193, 240, 117, 4, 66, 64, 205, +9, 191, 3, 208, 130, 63, 136, 161, 13, 63, 1, 161, 1, 0, 67, 191, 105, 193, 83, 253, +245, 65, 64, 227, 15, 190, 159, 148, 125, 63, 102, 192, 241, 62, 1, 222, 1, 0, 169, 247, +116, 193, 249, 198, 4, 66, 128, 17, 16, 190, 75, 173, 129, 63, 248, 226, 243, 62, 1, 222, +1, 0, 86, 220, 102, 193, 75, 103, 246, 65, 0, 134, 65, 61, 114, 24, 124, 63, 102, 43, +223, 62, 1, 223, 1, 0, 188, 20, 114, 193, 245, 251, 4, 66, 0, 205, 64, 61, 53, 239, +128, 63, 216, 77, 225, 62, 1, 223, 1, 0, 243, 118, 99, 193, 246, 227, 246, 65, 192, 189, +78, 62, 25, 89, 122, 63, 84, 225, 207, 62, 1, 223, 1, 0, 88, 175, 110, 193, 75, 58, +5, 66, 128, 143, 78, 62, 136, 15, 128, 63, 196, 3, 210, 62, 1, 223, 1, 0, 58, 138, +94, 193, 188, 152, 247, 65, 128, 154, 165, 62, 91, 208, 119, 63, 252, 229, 195, 62, 1, 223, +1, 0, 159, 194, 105, 193, 174, 148, 5, 66, 96, 131, 165, 62, 100, 150, 125, 63, 108, 8, +198, 62, 1, 223, 1, 0, 71, 17, 87, 193, 2, 171, 248, 65, 160, 31, 207, 62, 18, 248, +115, 63, 18, 248, 187, 62, 1, 223, 1, 0, 173, 73, 98, 193, 209, 29, 6, 66, 128, 8, +207, 62, 10, 190, 121, 63, 164, 26, 190, 62, 1, 223, 1, 0, 177, 108, 76, 193, 164, 49, +250, 65, 32, 112, 203, 62, 49, 126, 110, 63, 64, 217, 188, 62, 1, 223, 1, 0, 24, 165, +87, 193, 34, 225, 6, 66, 0, 89, 203, 62, 40, 68, 116, 63, 176, 251, 190, 62, 1, 223, +1, 0, 166, 127, 65, 193, 170, 194, 251, 65, 0, 184, 216, 62, 244, 222, 104, 63, 222, 113, +186, 62, 1, 224, 1, 0, 12, 184, 76, 193, 164, 169, 7, 66, 0, 161, 216, 62, 236, 164, +110, 63, 78, 148, 188, 62, 1, 224, 1, 0, 250, 117, 63, 193, 119, 13, 252, 65, 128, 1, +245, 62, 133, 210, 103, 63, 222, 254, 180, 62, 1, 224, 1, 0, 98, 174, 74, 193, 11, 207, +7, 66, 96, 234, 244, 62, 124, 152, 109, 63, 80, 33, 183, 62, 1, 224, 1, 0, 176, 243, +62, 193, 43, 32, 252, 65, 208, 20, 34, 63, 122, 143, 103, 63, 114, 170, 165, 62, 1, 224, +1, 0, 24, 44, 74, 193, 101, 216, 7, 66, 64, 9, 34, 63, 130, 85, 109, 63, 4, 205, +167, 62, 1, 224, 1, 0, 245, 226, 63, 193, 226, 253, 251, 65, 208, 149, 66, 63, 158, 10, +104, 63, 36, 14, 153, 62, 1, 224, 1, 0, 91, 27, 75, 193, 64, 199, 7, 66, 64, 138, +66, 63, 150, 208, 109, 63, 182, 48, 155, 62, 1, 224, 1, 0, 23, 41, 65, 193, 33, 207, +251, 65, 32, 227, 77, 63, 100, 178, 104, 63, 248, 167, 148, 62, 1, 224, 1, 0, 125, 97, +76, 193, 224, 175, 7, 66, 160, 215, 77, 63, 108, 120, 110, 63, 104, 202, 150, 62, 1, 224, +1, 0, 162, 197, 65, 193, 176, 184, 251, 65, 96, 173, 83, 63, 239, 2, 105, 63, 254, 102, +146, 62, 1, 225, 1, 0, 8, 254, 76, 193, 168, 164, 7, 66, 224, 161, 83, 63, 247, 200, +110, 63, 144, 137, 148, 62, 1, 225, 1, 0, 127, 61, 96, 193, 102, 90, 247, 65, 160, 74, +77, 63, 91, 176, 120, 63, 124, 103, 148, 62, 1, 225, 1, 0, 228, 117, 107, 193, 131, 117, +5, 66, 16, 63, 77, 63, 83, 118, 126, 63, 14, 138, 150, 62, 1, 225, 1, 0, 241, 111, +118, 193, 227, 43, 244, 65, 44, 27, 8, 64, 31, 14, 130, 63, 144, 27, 5, 61, 1, 225, +1, 0, 44, 212, 128, 193, 65, 222, 3, 66, 76, 24, 8, 64, 27, 241, 132, 63, 32, 48, +22, 61, 1, 225, 1, 0, 175, 143, 59, 193, 214, 156, 252, 65, 104, 42, 8, 64, 217, 208, +101, 63, 144, 174, 11, 61, 1, 225, 1, 0, 21, 200, 70, 193, 187, 22, 8, 66, 136, 39, +8, 64, 209, 150, 107, 63, 16, 194, 28, 61, 1, 225, 1, 0, 25, 240, 55, 193, 209, 33, +253, 65, 44, 117, 3, 64, 140, 243, 99, 63, 64, 131, 70, 61, 1, 225, 1, 0, 127, 40, +67, 193, 56, 89, 8, 66, 72, 114, 3, 64, 149, 185, 105, 63, 192, 150, 87, 61, 1, 225, +1, 0, 95, 27, 53, 193, 182, 137, 253, 65, 184, 21, 252, 63, 166, 126, 98, 63, 224, 1, +133, 61, 1, 225, 1, 0, 197, 83, 64, 193, 42, 141, 8, 66, 240, 15, 252, 63, 175, 68, +104, 63, 40, 140, 141, 61, 1, 225, 1, 0, 171, 210, 49, 193, 57, 2, 254, 65, 168, 183, +233, 63, 28, 206, 96, 63, 160, 39, 190, 61, 1, 226, 1, 0, 17, 11, 61, 193, 108, 201, +8, 66, 240, 177, 233, 63, 20, 148, 102, 63, 96, 177, 198, 61, 1, 226, 1, 0, 219, 253, +46, 193, 30, 106, 254, 65, 208, 12, 212, 63, 37, 89, 95, 63, 104, 192, 0, 62, 1, 226, +1, 0, 66, 54, 58, 193, 94, 253, 8, 66, 8, 7, 212, 63, 29, 31, 101, 63, 76, 5, +5, 62, 1, 226, 1, 0, 6, 128, 44, 193, 138, 197, 254, 65, 8, 98, 190, 63, 241, 16, +94, 63, 36, 106, 34, 62, 1, 226, 1, 0, 108, 184, 55, 193, 21, 43, 9, 66, 64, 92, +190, 63, 233, 214, 99, 63, 4, 175, 38, 62, 1, 226, 1, 0, 9, 65, 43, 193, 65, 243, +254, 65, 224, 93, 174, 63, 215, 108, 93, 63, 132, 71, 59, 62, 1, 226, 1, 0, 113, 121, +54, 193, 240, 65, 9, 66, 24, 88, 174, 63, 207, 50, 99, 63, 168, 140, 63, 62, 1, 226, +1, 0, 21, 2, 42, 193, 247, 32, 255, 65, 128, 104, 157, 63, 172, 200, 92, 63, 248, 154, +85, 62, 1, 226, 1, 0, 123, 58, 53, 193, 203, 88, 9, 66, 184, 98, 157, 63, 180, 142, +98, 63, 28, 224, 89, 62, 1, 226, 1, 0, 11, 224, 40, 193, 134, 74, 255, 65, 184, 188, +135, 63, 114, 51, 92, 63, 132, 59, 119, 62, 1, 227, 1, 0, 113, 24, 52, 193, 146, 109, +9, 66, 240, 182, 135, 63, 106, 249, 97, 63, 168, 128, 123, 62, 1, 227, 1, 0, 248, 49, +40, 193, 117, 99, 255, 65, 144, 230, 103, 63, 236, 217, 91, 63, 98, 246, 138, 62, 1, 227, +1, 0, 94, 106, 51, 193, 10, 122, 9, 66, 0, 219, 103, 63, 228, 159, 97, 63, 244, 24, +141, 62, 1, 227, 1, 0, 74, 175, 39, 193, 40, 118, 255, 65, 48, 0, 37, 63, 175, 150, +91, 63, 80, 229, 164, 62, 1, 227, 1, 0, 176, 231, 50, 193, 99, 131, 9, 66, 160, 244, +36, 63, 167, 92, 97, 63, 192, 7, 167, 62, 1, 227, 1, 0, 59, 179, 39, 193, 148, 117, +255, 65, 48, 51, 19, 63, 183, 152, 91, 63, 28, 203, 171, 62, 1, 227, 1, 0, 162, 235, +50, 193, 26, 131, 9, 66, 160, 39, 19, 63, 175, 94, 97, 63, 174, 237, 173, 62, 1, 227, +1, 0, 135, 189, 39, 193, 24, 116, 255, 65, 48, 41, 4, 63, 245, 157, 91, 63, 250, 158, +177, 62, 1, 227, 1, 0, 237, 245, 50, 193, 92, 130, 9, 66, 176, 29, 4, 63, 254, 99, +97, 63, 106, 193, 179, 62, 1, 227, 1, 0, 158, 203, 39, 193, 17, 114, 255, 65, 64, 192, +239, 62, 60, 165, 91, 63, 140, 97, 182, 62, 1, 228, 1, 0, 4, 4, 51, 193, 88, 129, +9, 66, 64, 169, 239, 62, 51, 107, 97, 63, 254, 131, 184, 62, 1, 228, 1, 0, 0, 219, +39, 193, 219, 111, 255, 65, 160, 171, 220, 62, 42, 173, 91, 63, 194, 19, 186, 62, 1, 228, +1, 0, 104, 19, 51, 193, 61, 128, 9, 66, 128, 148, 220, 62, 33, 115, 97, 63, 50, 54, +188, 62, 1, 228, 1, 0, 31, 233, 39, 193, 212, 109, 255, 65, 0, 16, 207, 62, 112, 180, +91, 63, 132, 182, 188, 62, 1, 228, 1, 0, 132, 33, 51, 193, 58, 127, 9, 66, 224, 248, +206, 62, 104, 122, 97, 63, 244, 216, 190, 62, 1, 228, 1, 0, 118, 243, 39, 193, 88, 108, +255, 65, 0, 233, 198, 62, 191, 185, 91, 63, 190, 74, 190, 62, 1, 228, 1, 0, 220, 43, +51, 193, 123, 126, 9, 66, 224, 209, 198, 62, 183, 127, 97, 63, 46, 109, 192, 62, 1, 228, +1, 0, 119, 247, 39, 193, 196, 107, 255, 65, 96, 50, 196, 62, 199, 187, 91, 63, 58, 209, +190, 62, 1, 228, 1, 0, 222, 47, 51, 193, 50, 126, 9, 66, 64, 27, 196, 62, 191, 129, +97, 63, 204, 243, 192, 62, 1, 228, 1, 0, 95, 201, 40, 193, 164, 77, 255, 65, 192, 206, +28, 62, 200, 39, 92, 63, 224, 160, 213, 62, 1, 228, 1, 0, 197, 1, 52, 193, 33, 111, +9, 66, 128, 160, 28, 62, 208, 237, 97, 63, 80, 195, 215, 62, 1, 228, 1, 0, 207, 210, +42, 193, 214, 2, 255, 65, 128, 145, 3, 190, 22, 52, 93, 63, 210, 136, 241, 62, 1, 229, +1, 0, 53, 11, 54, 193, 187, 73, 9, 66, 192, 191, 3, 190, 30, 250, 98, 63, 100, 171, +243, 62, 1, 229, 1, 0, 53, 138, 45, 193, 26, 159, 254, 65, 128, 92, 187, 190, 233, 153, +94, 63, 72, 134, 4, 63, 1, 229, 1, 0, 156, 194, 56, 193, 221, 23, 9, 66, 160, 115, +187, 190, 225, 95, 100, 63, 146, 151, 5, 63, 1, 229, 1, 0, 69, 34, 49, 193, 41, 27, +254, 65, 32, 239, 18, 191, 88, 115, 96, 63, 179, 208, 14, 63, 1, 229, 1, 0, 173, 90, +60, 193, 228, 213, 8, 66, 176, 250, 18, 191, 80, 57, 102, 63, 236, 225, 15, 63, 1, 229, +1, 0, 142, 181, 54, 193, 126, 78, 253, 65, 224, 246, 75, 191, 189, 81, 99, 63, 124, 210, +25, 63, 1, 229, 1, 0, 245, 237, 65, 193, 143, 111, 8, 66, 112, 2, 76, 191, 181, 23, +105, 63, 180, 227, 26, 63, 1, 229, 1, 0, 161, 53, 59, 193, 78, 169, 252, 65, 128, 197, +95, 191, 131, 162, 101, 63, 6, 160, 29, 63, 1, 229, 1, 0, 7, 110, 70, 193, 247, 28, +8, 66, 0, 209, 95, 191, 123, 104, 107, 63, 79, 177, 30, 63, 1, 229, 1, 0, 103, 63, +64, 193, 97, 240, 251, 65, 240, 206, 111, 191, 50, 58, 104, 63, 120, 177, 32, 63, 1, 230, +1, 0, 205, 119, 75, 193, 128, 192, 7, 66, 144, 218, 111, 191, 42, 0, 110, 63, 194, 194, +33, 63, 1, 230, 1, 0, 5, 40, 86, 193, 65, 204, 248, 65, 208, 79, 113, 191, 19, 128, +115, 63, 137, 208, 32, 63, 1, 230, 1, 0, 107, 96, 97, 193, 112, 46, 6, 66, 96, 91, +113, 191, 11, 70, 121, 63, 210, 225, 33, 63, 1, 230, 1, 0, 175, 189, 87, 193, 20, 146, +248, 65, 24, 203, 134, 191, 206, 80, 116, 63, 237, 71, 38, 63, 1, 230, 1, 0, 20, 246, +98, 193, 89, 17, 6, 66, 224, 208, 134, 191, 198, 22, 122, 63, 37, 89, 39, 63, 1, 230, +1, 0, 135, 189, 87, 193, 20, 146, 248, 65, 144, 163, 153, 191, 190, 80, 116, 63, 120, 149, +45, 63, 1, 230, 1, 0, 237, 245, 98, 193, 89, 17, 6, 66, 88, 169, 153, 191, 181, 22, +122, 63, 194, 166, 46, 63, 1, 230, 1, 0, 155, 126, 86, 193, 201, 191, 248, 65, 64, 212, +166, 191, 163, 172, 115, 63, 133, 180, 50, 63, 1, 230, 1, 0, 1, 183, 97, 193, 52, 40, +6, 66, 0, 218, 166, 191, 155, 114, 121, 63, 189, 197, 51, 63, 1, 230, 1, 0, 106, 140, +86, 193, 206, 189, 248, 65, 144, 182, 168, 191, 183, 179, 115, 63, 76, 111, 51, 63, 1, 231, +1, 0, 207, 196, 97, 193, 55, 39, 6, 66, 80, 188, 168, 191, 175, 121, 121, 63, 149, 128, +52, 63, 1, 231, 1, 0, 174, 18, 40, 193, 158, 103, 255, 65, 136, 158, 168, 191, 205, 201, +91, 63, 84, 194, 51, 63, 1, 231, 1, 0, 19, 75, 51, 193, 30, 124, 9, 66, 80, 164, +168, 191, 197, 143, 97, 63, 141, 211, 52, 63, 1, 231, 1, 0, 82, 17, 40, 193, 158, 103, +255, 65, 100, 44, 40, 192, 21, 201, 91, 63, 202, 193, 116, 63, 1, 231, 1, 0, 184, 73, +51, 193, 31, 124, 9, 66, 70, 47, 40, 192, 12, 143, 97, 63, 19, 211, 117, 63, 1, 231, +1, 0, 122, 50, 90, 193, 176, 55, 248, 65, 78, 193, 41, 192, 91, 148, 117, 63, 24, 152, +117, 63, 1, 231, 1, 0, 224, 106, 101, 193, 40, 228, 5, 66, 52, 196, 41, 192, 83, 90, +123, 63, 80, 169, 118, 63, 1, 231, 1, 0, 143, 178, 91, 193, 160, 0, 248, 65, 88, 175, +39, 192, 243, 89, 118, 63, 93, 250, 115, 63, 1, 231, 1, 0, 247, 234, 102, 193, 160, 200, +5, 66, 64, 178, 39, 192, 235, 31, 124, 63, 149, 11, 117, 63, 1, 231, 1, 0, 197, 14, +99, 193, 130, 242, 246, 65, 158, 251, 27, 192, 125, 35, 122, 63, 241, 217, 106, 63, 1, 231, +1, 0, 44, 71, 110, 193, 145, 65, 5, 66, 132, 254, 27, 192, 117, 233, 127, 63, 41, 235, +107, 63, 1, 231, 1, 0, 85, 155, 104, 193, 225, 38, 246, 65, 208, 21, 10, 192, 105, 254, +124, 63, 204, 239, 92, 63, 1, 232, 1, 0, 187, 211, 115, 193, 192, 219, 4, 66, 180, 24, +10, 192, 48, 98, 129, 63, 21, 1, 94, 63, 1, 232, 1, 0, 51, 252, 106, 193, 156, 207, +245, 65, 208, 128, 254, 191, 189, 55, 126, 63, 144, 133, 84, 63, 1, 232, 1, 0, 153, 52, +118, 193, 30, 176, 4, 66, 152, 134, 254, 191, 218, 254, 129, 63, 217, 150, 85, 63, 1, 232, +1, 0, 42, 175, 108, 193, 70, 145, 245, 65, 224, 242, 230, 191, 139, 23, 127, 63, 120, 97, +75, 63, 1, 232, 1, 0, 144, 231, 119, 193, 243, 144, 4, 66, 168, 248, 230, 191, 193, 110, +130, 63, 176, 114, 76, 63, 1, 232, 1, 0, 49, 11, 110, 193, 104, 95, 245, 65, 128, 130, +205, 191, 151, 202, 127, 63, 14, 131, 65, 63, 1, 232, 1, 0, 152, 67, 121, 193, 4, 120, +4, 66, 72, 136, 205, 191, 71, 200, 130, 63, 87, 148, 66, 63, 1, 232, 1, 0, 74, 45, +111, 193, 218, 53, 245, 65, 152, 196, 172, 191, 241, 47, 128, 63, 170, 208, 52, 63, 1, 232, +1, 0, 177, 101, 122, 193, 61, 99, 4, 66, 96, 202, 172, 191, 236, 18, 131, 63, 227, 225, +53, 63, 1, 232, 1, 0, 207, 45, 111, 193, 218, 53, 245, 65, 160, 233, 88, 191, 18, 48, +128, 63, 155, 228, 27, 63, 1, 233, 1, 0, 54, 102, 122, 193, 61, 99, 4, 66, 64, 245, +88, 191, 14, 19, 131, 63, 212, 245, 28, 63, 1, 233, 1, 0, 123, 7, 34, 66, 121, 63, +212, 239, 163, 189, 28, 151, 90, 62, 1, 165, 1, 0, 216, 185, 124, 63, 170, 69, 101, 189, +106, 218, 24, 62, 1, 205, 1, 0, 17, 26, 122, 63, 179, 125, 164, 189, 42, 122, 74, 62, +1, 205, 1, 0, 159, 36, 125, 63, 111, 166, 101, 189, 107, 87, 13, 62, 1, 205, 1, 0, +13, 145, 124, 63, 93, 73, 193, 189, 184, 95, 8, 62, 1, 205, 1, 0, 85, 32, 126, 63, +89, 1, 143, 189, 14, 204, 201, 61, 1, 205, 1, 0, 197, 119, 126, 63, 218, 188, 194, 189, +218, 75, 92, 61, 1, 205, 1, 0, 11, 43, 127, 63, 1, 151, 143, 189, 142, 110, 34, 61, +1, 205, 1, 0, 161, 10, 126, 63, 140, 30, 206, 189, 156, 112, 146, 189, 1, 205, 1, 0, +112, 223, 126, 63, 10, 128, 156, 189, 197, 95, 94, 189, 1, 205, 1, 0, 91, 53, 123, 63, +52, 10, 195, 189, 69, 100, 43, 190, 1, 205, 1, 0, 237, 86, 125, 63, 51, 163, 145, 189, +36, 245, 255, 189, 1, 205, 1, 0, 150, 151, 121, 63, 156, 120, 168, 189, 6, 133, 83, 190, +1, 205, 1, 0, 58, 212, 124, 63, 149, 200, 109, 189, 166, 69, 21, 190, 1, 205, 1, 0, +143, 101, 113, 63, 164, 187, 168, 189, 214, 38, 165, 190, 1, 205, 1, 0, 85, 99, 120, 63, +102, 89, 117, 189, 74, 36, 112, 190, 1, 205, 1, 0, 231, 226, 103, 63, 135, 235, 145, 189, +95, 215, 213, 190, 1, 205, 1, 0, 127, 0, 116, 63, 14, 102, 80, 189, 118, 179, 152, 190, +1, 205, 1, 0, 159, 80, 106, 63, 115, 20, 145, 189, 130, 3, 203, 190, 1, 205, 1, 0, +218, 104, 117, 63, 103, 14, 77, 189, 67, 120, 143, 190, 1, 205, 1, 0, 148, 48, 92, 63, +98, 5, 134, 189, 141, 129, 1, 191, 1, 205, 1, 0, 84, 222, 109, 63, 184, 60, 66, 189, +134, 177, 187, 190, 1, 205, 1, 0, 128, 238, 83, 63, 128, 121, 110, 189, 19, 211, 14, 191, +1, 205, 1, 0, 237, 13, 106, 63, 80, 56, 44, 189, 188, 73, 206, 190, 1, 205, 1, 0, +203, 7, 66, 63, 66, 201, 22, 189, 64, 187, 38, 191, 1, 205, 1, 0, 124, 177, 99, 63, +73, 78, 211, 188, 150, 166, 233, 190, 1, 205, 1, 0, 169, 168, 43, 63, 222, 182, 24, 189, +215, 173, 61, 191, 1, 205, 1, 0, 68, 184, 83, 63, 174, 112, 231, 188, 250, 186, 15, 191, +1, 205, 1, 0, 203, 70, 6, 63, 238, 218, 185, 188, 130, 225, 89, 191, 1, 205, 1, 0, +208, 173, 57, 63, 88, 71, 150, 188, 139, 44, 48, 191, 1, 205, 1, 0, 250, 200, 174, 61, +87, 77, 0, 58, 227, 16, 127, 191, 1, 205, 1, 0, 32, 225, 47, 62, 97, 183, 253, 57, +21, 50, 124, 191, 1, 205, 1, 0, 135, 203, 124, 191, 84, 128, 33, 62, 140, 214, 55, 187, +1, 205, 1, 0, 189, 80, 124, 191, 52, 21, 45, 62, 92, 8, 69, 187, 1, 205, 1, 0, +2, 165, 174, 61, 171, 13, 78, 180, 71, 17, 127, 63, 1, 205, 1, 0, 118, 4, 45, 62, +75, 213, 75, 180, 194, 81, 124, 63, 1, 205, 1, 0, 252, 222, 125, 63, 235, 174, 3, 190, +146, 23, 168, 59, 1, 205, 1, 0, 192, 85, 126, 63, 203, 3, 233, 189, 100, 184, 148, 59, +1, 205, 1, 0, 81, 246, 77, 62, 250, 153, 140, 186, 164, 196, 122, 191, 1, 205, 1, 0, +187, 105, 191, 62, 106, 32, 133, 186, 204, 111, 109, 191, 1, 205, 1, 0, 38, 140, 126, 63, +199, 219, 217, 189, 151, 176, 59, 57, 1, 205, 1, 0, 192, 29, 127, 63, 208, 7, 170, 189, +246, 95, 17, 57, 1, 205, 1, 0, 159, 38, 95, 62, 65, 122, 164, 58, 227, 216, 121, 63, +1, 205, 1, 0, 75, 53, 212, 62, 37, 103, 153, 58, 221, 249, 104, 63, 1, 205, 1, 0, +176, 200, 55, 63, 96, 217, 91, 60, 194, 45, 50, 63, 1, 205, 1, 0, 98, 231, 104, 63, +25, 22, 3, 60, 128, 124, 212, 62, 1, 205, 1, 0, 230, 80, 156, 62, 243, 134, 73, 61, +157, 115, 115, 63, 1, 205, 1, 0, 96, 217, 51, 63, 92, 155, 22, 61, 79, 240, 53, 63, +1, 205, 1, 0, 31, 247, 133, 62, 193, 142, 190, 61, 71, 238, 117, 63, 1, 205, 1, 0, +41, 209, 67, 63, 74, 90, 126, 61, 136, 33, 36, 63, 1, 205, 1, 0, 174, 211, 11, 186, +192, 119, 33, 62, 29, 204, 124, 63, 1, 205, 1, 0, 148, 188, 57, 63, 162, 61, 222, 61, +197, 248, 45, 63, 1, 205, 1, 0, 20, 146, 199, 190, 108, 76, 130, 62, 52, 146, 98, 63, +1, 205, 1, 0, 160, 69, 53, 63, 1, 209, 71, 62, 28, 186, 45, 63, 1, 205, 1, 0, +117, 38, 75, 62, 183, 182, 190, 62, 230, 21, 104, 63, 1, 205, 1, 0, 118, 110, 114, 63, +169, 6, 250, 61, 98, 34, 152, 62, 1, 205, 1, 0, 60, 195, 89, 191, 100, 166, 240, 62, +200, 61, 113, 62, 1, 205, 1, 0, 12, 140, 112, 63, 12, 159, 156, 62, 236, 255, 28, 62, +1, 205, 1, 0, 63, 57, 54, 191, 108, 86, 250, 62, 39, 22, 1, 191, 1, 205, 1, 0, +234, 75, 111, 63, 167, 69, 125, 62, 53, 153, 130, 190, 1, 205, 1, 0, 210, 127, 0, 191, +0, 88, 160, 62, 147, 99, 78, 191, 1, 205, 1, 0, 139, 162, 72, 63, 172, 74, 102, 62, +111, 54, 20, 191, 1, 205, 1, 0, 135, 133, 70, 189, 47, 47, 79, 62, 235, 101, 122, 191, +1, 205, 1, 0, 249, 103, 72, 63, 90, 17, 1, 62, 231, 252, 27, 191, 1, 205, 1, 0, +171, 175, 43, 62, 155, 148, 19, 62, 47, 170, 121, 191, 1, 205, 1, 0, 101, 242, 75, 63, +75, 246, 180, 61, 146, 17, 25, 191, 1, 205, 1, 0, 5, 60, 124, 62, 92, 13, 179, 61, +189, 25, 119, 191, 1, 205, 1, 0, 21, 83, 62, 63, 242, 27, 119, 61, 217, 130, 42, 191, +1, 205, 1, 0, 211, 108, 180, 62, 127, 68, 20, 61, 30, 102, 111, 191, 1, 205, 1, 0, +126, 16, 54, 63, 226, 192, 222, 60, 97, 213, 51, 191, 1, 205, 1, 0, 93, 142, 178, 61, +51, 166, 128, 57, 113, 6, 127, 191, 1, 205, 1, 0, 57, 235, 49, 62, 121, 90, 126, 57, +49, 27, 124, 191, 1, 205, 1, 0, 55, 22, 124, 191, 130, 70, 50, 62, 153, 115, 175, 187, +1, 205, 1, 0, 11, 52, 122, 191, 51, 147, 88, 62, 252, 36, 213, 187, 1, 205, 1, 0, +210, 30, 166, 61, 182, 48, 237, 56, 13, 40, 127, 63, 1, 205, 1, 0, 216, 128, 37, 62, +159, 102, 234, 56, 92, 162, 124, 63, 1, 205, 1, 0, 197, 175, 253, 62, 242, 107, 12, 189, +108, 49, 94, 63, 1, 205, 1, 0, 22, 204, 40, 63, 192, 20, 243, 188, 35, 81, 64, 63, +1, 205, 1, 0, 6, 31, 53, 63, 222, 148, 116, 189, 63, 69, 52, 63, 1, 205, 1, 0, +123, 34, 82, 63, 15, 171, 69, 189, 178, 177, 17, 63, 1, 205, 1, 0, 130, 178, 81, 63, +82, 185, 149, 189, 101, 165, 17, 63, 1, 205, 1, 0, 190, 13, 101, 63, 76, 35, 105, 189, +126, 201, 226, 62, 1, 205, 1, 0, 78, 130, 100, 63, 30, 40, 156, 189, 4, 127, 227, 62, +1, 205, 1, 0, 28, 92, 113, 63, 155, 234, 102, 189, 60, 52, 168, 62, 1, 205, 1, 0, +59, 238, 110, 63, 55, 76, 161, 189, 194, 89, 179, 62, 1, 205, 1, 0, 64, 70, 119, 63, +124, 148, 104, 189, 136, 78, 129, 62, 1, 205, 1, 0, 111, 180, 175, 60, 238, 240, 127, 191, +184, 20, 30, 184, 1, 205, 1, 0, 132, 152, 10, 185, 0, 0, 128, 191, 133, 215, 28, 184, +1, 205, 1, 0, 220, 239, 53, 62, 76, 237, 123, 191, 85, 70, 38, 184, 1, 205, 1, 0, +178, 192, 195, 61, 243, 211, 126, 191, 226, 22, 19, 184, 1, 205, 1, 0, 143, 3, 179, 62, +186, 215, 111, 191, 17, 29, 14, 184, 1, 205, 1, 0, 201, 209, 249, 62, 74, 117, 95, 191, +5, 126, 4, 184, 1, 205, 1, 0, 158, 74, 223, 62, 56, 95, 102, 191, 233, 141, 6, 184, +1, 205, 1, 0, 83, 239, 13, 63, 234, 12, 85, 191, 133, 90, 251, 183, 1, 205, 1, 0, +2, 249, 3, 63, 101, 92, 91, 191, 219, 94, 2, 184, 1, 205, 1, 0, 169, 42, 28, 63, +130, 217, 74, 191, 116, 250, 245, 183, 1, 205, 1, 0, 185, 228, 18, 63, 147, 169, 81, 191, +128, 236, 255, 183, 1, 205, 1, 0, 121, 80, 248, 62, 144, 224, 95, 191, 88, 17, 17, 184, +1, 205, 1, 0, 135, 172, 69, 63, 30, 171, 34, 191, 65, 252, 202, 183, 1, 205, 1, 0, +237, 31, 35, 63, 44, 76, 69, 191, 241, 231, 253, 183, 1, 205, 1, 0, 193, 235, 238, 62, +14, 107, 98, 191, 119, 198, 4, 184, 1, 205, 1, 0, 177, 191, 62, 63, 128, 188, 42, 191, +252, 53, 185, 183, 1, 205, 1, 0, 253, 214, 12, 63, 164, 198, 85, 191, 41, 196, 0, 184, +1, 205, 1, 0, 1, 52, 211, 62, 85, 52, 105, 191, 35, 38, 16, 184, 1, 205, 1, 0, +127, 91, 39, 63, 92, 184, 65, 191, 71, 182, 4, 184, 1, 205, 1, 0, 250, 99, 1, 63, +212, 228, 92, 191, 255, 86, 252, 183, 1, 205, 1, 0, 160, 212, 29, 63, 199, 142, 73, 191, +152, 255, 244, 183, 1, 205, 1, 0, 176, 67, 29, 63, 240, 255, 73, 191, 129, 222, 1, 184, +1, 205, 1, 0, 198, 12, 41, 63, 184, 62, 64, 191, 145, 92, 249, 183, 1, 205, 1, 0, +191, 64, 23, 63, 28, 138, 78, 191, 46, 149, 254, 183, 1, 205, 1, 0, 182, 13, 237, 62, +139, 232, 98, 191, 177, 207, 14, 184, 1, 205, 1, 0, 21, 77, 64, 63, 110, 252, 40, 191, +184, 57, 223, 183, 1, 205, 1, 0, 103, 196, 31, 63, 176, 6, 72, 191, 113, 21, 249, 183, +1, 205, 1, 0, 84, 42, 68, 63, 9, 124, 36, 191, 187, 146, 198, 183, 1, 205, 1, 0, +4, 94, 25, 63, 112, 249, 76, 191, 50, 182, 242, 183, 1, 205, 1, 0, 58, 46, 242, 62, +255, 140, 97, 191, 215, 221, 6, 184, 1, 205, 1, 0, 108, 70, 16, 63, 2, 121, 83, 191, +244, 240, 2, 184, 1, 205, 1, 0, 136, 42, 33, 63, 146, 230, 70, 191, 120, 210, 244, 183, +1, 205, 1, 0, 171, 82, 255, 61, 182, 0, 126, 191, 253, 166, 36, 184, 1, 205, 1, 0, +11, 32, 190, 61, 253, 228, 126, 191, 217, 62, 35, 184, 1, 205, 1, 0, 88, 197, 183, 188, +130, 239, 127, 191, 249, 49, 33, 184, 1, 205, 1, 0, 0, 2, 218, 60, 203, 232, 127, 191, +204, 85, 29, 184, 1, 205, 1, 0, 189, 10, 144, 188, 222, 245, 127, 191, 38, 95, 31, 184, +1, 205, 1, 0, 88, 160, 96, 61, 97, 157, 127, 191, 180, 204, 31, 184, 1, 205, 1, 0, +105, 102, 175, 61, 53, 15, 127, 191, 74, 255, 31, 184, 1, 205, 1, 0, 165, 169, 8, 63, +91, 120, 88, 191, 226, 170, 6, 184, 1, 205, 1, 0, 177, 51, 156, 62, 165, 203, 115, 63, +162, 239, 28, 56, 1, 205, 1, 0, 147, 89, 221, 62, 4, 215, 102, 63, 103, 91, 24, 56, +1, 205, 1, 0, 98, 145, 146, 62, 87, 73, 117, 63, 201, 94, 29, 56, 1, 205, 1, 0, +21, 17, 188, 62, 189, 26, 110, 63, 26, 197, 18, 56, 1, 205, 1, 0, 225, 204, 14, 63, +169, 120, 84, 63, 102, 115, 249, 55, 1, 205, 1, 0, 141, 175, 38, 63, 99, 76, 66, 63, +161, 230, 234, 55, 1, 205, 1, 0, 215, 227, 29, 63, 220, 130, 73, 63, 158, 75, 3, 56, +1, 205, 1, 0, 200, 198, 49, 63, 129, 52, 56, 63, 122, 84, 237, 55, 1, 205, 1, 0, +100, 79, 43, 63, 209, 59, 62, 63, 39, 78, 218, 55, 1, 205, 1, 0, 220, 238, 58, 63, +226, 231, 46, 63, 212, 38, 188, 55, 1, 205, 1, 0, 200, 249, 52, 63, 31, 16, 53, 63, +44, 200, 206, 55, 1, 205, 1, 0, 184, 48, 38, 63, 234, 184, 66, 63, 16, 141, 5, 56, +1, 205, 1, 0, 93, 157, 85, 63, 144, 21, 13, 63, 158, 101, 195, 55, 1, 205, 1, 0, +140, 99, 63, 63, 192, 4, 42, 63, 92, 79, 243, 55, 1, 205, 1, 0, 112, 23, 35, 63, +50, 83, 69, 63, 230, 232, 229, 55, 1, 205, 1, 0, 234, 29, 81, 63, 69, 171, 19, 63, +64, 253, 158, 55, 1, 205, 1, 0, 164, 17, 49, 63, 169, 226, 56, 63, 113, 249, 211, 55, +1, 205, 1, 0, 137, 211, 25, 63, 75, 161, 76, 63, 111, 78, 8, 56, 1, 205, 1, 0, +215, 24, 66, 63, 145, 235, 38, 63, 125, 143, 229, 55, 1, 205, 1, 0, 152, 159, 41, 63, +57, 189, 63, 63, 109, 94, 248, 55, 1, 205, 1, 0, 213, 255, 59, 63, 88, 194, 45, 63, +184, 139, 208, 55, 1, 205, 1, 0, 0, 163, 59, 63, 148, 38, 46, 63, 194, 40, 198, 55, +1, 205, 1, 0, 14, 46, 67, 63, 21, 167, 37, 63, 25, 161, 190, 55, 1, 205, 1, 0, +159, 199, 55, 63, 85, 55, 50, 63, 221, 51, 207, 55, 1, 205, 1, 0, 7, 121, 34, 63, +179, 213, 69, 63, 128, 87, 245, 55, 1, 205, 1, 0, 44, 31, 82, 63, 80, 60, 18, 63, +51, 193, 188, 55, 1, 205, 1, 0, 102, 61, 61, 63, 70, 104, 44, 63, 146, 115, 234, 55, +1, 205, 1, 0, 175, 161, 84, 63, 198, 143, 14, 63, 74, 34, 187, 55, 1, 205, 1, 0, +39, 35, 57, 63, 51, 206, 48, 63, 69, 26, 225, 55, 1, 205, 1, 0, 70, 43, 36, 63, +241, 109, 68, 63, 232, 14, 255, 55, 1, 205, 1, 0, 214, 73, 51, 63, 223, 187, 54, 63, +13, 255, 229, 55, 1, 205, 1, 0, 203, 34, 62, 63, 42, 107, 43, 63, 218, 86, 204, 55, +1, 205, 1, 0, 158, 21, 200, 62, 146, 164, 107, 63, 132, 122, 15, 56, 1, 205, 1, 0, +147, 234, 186, 62, 177, 84, 110, 63, 223, 225, 20, 56, 1, 205, 1, 0, 70, 110, 136, 62, +127, 190, 118, 63, 65, 118, 25, 56, 1, 205, 1, 0, 119, 123, 158, 62, 98, 109, 115, 63, +86, 35, 25, 56, 1, 205, 1, 0, 206, 166, 138, 62, 56, 111, 118, 63, 153, 147, 22, 56, +1, 205, 1, 0, 90, 200, 170, 62, 174, 86, 113, 63, 184, 166, 18, 56, 1, 205, 1, 0, +63, 230, 183, 62, 181, 234, 110, 63, 96, 183, 16, 56, 1, 205, 1, 0, 140, 92, 46, 63, +219, 112, 59, 63, 30, 17, 233, 55, 1, 205, 1, 0, 200, 185, 125, 191, 5, 49, 8, 62, +67, 86, 154, 185, 1, 205, 1, 0, 56, 168, 124, 191, 69, 241, 36, 62, 27, 48, 187, 185, +1, 205, 1, 0, 68, 69, 63, 61, 100, 54, 222, 179, 130, 184, 127, 63, 1, 205, 1, 0, +138, 40, 191, 61, 216, 210, 161, 180, 229, 225, 126, 63, 1, 205, 1, 0, 59, 193, 126, 63, +66, 192, 201, 189, 13, 246, 100, 57, 1, 205, 1, 0, 120, 6, 127, 63, 93, 140, 178, 189, +12, 161, 74, 57, 1, 205, 1, 0, 187, 84, 65, 61, 144, 93, 162, 52, 245, 182, 127, 191, +1, 205, 1, 0, 162, 45, 192, 61, 83, 215, 161, 52, 211, 222, 126, 191, 1, 205, 1, 0, +68, 61, 137, 61, 234, 39, 226, 179, 177, 108, 127, 63, 1, 205, 1, 0, 109, 147, 8, 62, +23, 17, 165, 180, 122, 182, 125, 63, 1, 205, 1, 0, 22, 240, 123, 191, 222, 177, 53, 62, +190, 192, 205, 185, 1, 205, 1, 0, 147, 6, 107, 191, 126, 247, 202, 62, 107, 215, 101, 186, +1, 205, 1, 0, 235, 48, 0, 62, 214, 78, 131, 52, 113, 252, 125, 191, 1, 205, 1, 0, +235, 82, 122, 62, 136, 90, 128, 52, 167, 59, 120, 191, 1, 205, 1, 0, 110, 179, 125, 191, +164, 188, 8, 62, 233, 31, 232, 187, 1, 205, 1, 0, 229, 148, 124, 191, 118, 140, 38, 62, +217, 93, 13, 188, 1, 205, 1, 0, 12, 48, 254, 61, 204, 216, 165, 180, 68, 5, 126, 63, +1, 205, 1, 0, 1, 191, 120, 62, 157, 26, 162, 180, 5, 85, 120, 63, 1, 205, 1, 0, +226, 155, 30, 62, 55, 68, 157, 180, 19, 233, 124, 63, 1, 205, 1, 0, 205, 77, 153, 62, +139, 241, 151, 180, 67, 65, 116, 63, 1, 205, 1, 0, 137, 169, 126, 63, 63, 24, 209, 189, +13, 119, 109, 57, 1, 205, 1, 0, 45, 228, 126, 63, 159, 101, 190, 189, 128, 198, 87, 57, +1, 205, 1, 0, 126, 27, 31, 62, 2, 113, 142, 51, 17, 228, 124, 191, 1, 205, 1, 0, +75, 135, 153, 62, 166, 161, 137, 51, 61, 56, 116, 191, 1, 205, 1, 0, 94, 255, 127, 63, +61, 68, 144, 59, 179, 11, 252, 182, 1, 205, 1, 0, 218, 255, 127, 63, 101, 136, 13, 59, +192, 216, 36, 182, 1, 205, 1, 0, 34, 68, 138, 61, 155, 58, 226, 51, 121, 106, 127, 191, +1, 205, 1, 0, 47, 20, 9, 62, 121, 134, 224, 51, 36, 178, 125, 191, 1, 205, 1, 0, +13, 176, 125, 191, 220, 81, 9, 62, 217, 30, 156, 185, 1, 205, 1, 0, 9, 133, 124, 191, +205, 70, 40, 62, 31, 7, 191, 185, 1, 205, 1, 0, 181, 130, 142, 61, 37, 97, 127, 191, +233, 200, 240, 183, 1, 205, 1, 0, 229, 49, 11, 62, 181, 159, 125, 191, 57, 203, 235, 183, +1, 205, 1, 0, 0, 194, 133, 61, 19, 116, 127, 191, 221, 105, 238, 183, 1, 205, 1, 0, +160, 219, 184, 62, 89, 187, 110, 191, 215, 244, 218, 183, 1, 205, 1, 0, 151, 81, 106, 61, +174, 148, 127, 191, 154, 201, 240, 183, 1, 205, 1, 0, 36, 208, 72, 62, 119, 7, 123, 191, +161, 138, 236, 183, 1, 205, 1, 0, 33, 9, 221, 61, 49, 129, 126, 191, 68, 170, 239, 183, +1, 205, 1, 0, 40, 84, 32, 60, 220, 252, 127, 191, 7, 128, 241, 183, 1, 205, 1, 0, +21, 55, 23, 62, 127, 49, 125, 191, 79, 108, 238, 183, 1, 205, 1, 0, 218, 143, 196, 60, +33, 237, 127, 191, 137, 141, 241, 183, 1, 205, 1, 0, 42, 177, 35, 62, 60, 181, 124, 191, +226, 85, 238, 183, 1, 205, 1, 0, 65, 253, 127, 63, 86, 18, 22, 188, 52, 55, 17, 180, +1, 205, 1, 0, 221, 100, 78, 62, 255, 190, 122, 63, 92, 19, 236, 55, 1, 205, 1, 0, +102, 13, 146, 62, 6, 93, 117, 63, 82, 87, 231, 55, 1, 205, 1, 0, 139, 149, 175, 62, +198, 121, 112, 63, 123, 145, 223, 55, 1, 205, 1, 0, 51, 29, 6, 63, 237, 14, 90, 63, +13, 254, 199, 55, 1, 205, 1, 0, 240, 27, 144, 62, 131, 166, 117, 63, 104, 67, 229, 55, +1, 205, 1, 0, 214, 104, 140, 62, 123, 47, 118, 63, 169, 239, 231, 55, 1, 205, 1, 0, +75, 103, 201, 62, 156, 92, 107, 63, 86, 199, 221, 55, 1, 205, 1, 0, 203, 66, 163, 62, +241, 162, 114, 63, 156, 247, 228, 55, 1, 205, 1, 0, 234, 195, 108, 62, 35, 16, 121, 63, +232, 84, 234, 55, 1, 205, 1, 0, 111, 176, 180, 62, 70, 135, 111, 63, 153, 213, 225, 55, +1, 205, 1, 0, 93, 10, 99, 62, 216, 160, 121, 63, 91, 26, 235, 55, 1, 205, 1, 0, +44, 244, 185, 62, 218, 132, 110, 63, 223, 161, 225, 55, 1, 205, 1, 0, 27, 27, 122, 62, +42, 63, 120, 63, 153, 243, 233, 55, 1, 205, 1, 0, 67, 253, 127, 63, 89, 194, 21, 60, +197, 233, 144, 52, 1, 205, 1, 0, 63, 219, 27, 63, 136, 187, 240, 188, 224, 242, 74, 191, +1, 205, 1, 0, 14, 62, 35, 63, 165, 192, 233, 188, 155, 16, 69, 191, 1, 205, 1, 0, +100, 158, 127, 191, 128, 118, 95, 61, 141, 192, 137, 185, 1, 205, 1, 0, 140, 149, 127, 191, +190, 92, 105, 61, 196, 218, 143, 185, 1, 205, 1, 0, 88, 53, 22, 62, 87, 237, 156, 57, +22, 59, 125, 63, 1, 205, 1, 0, 240, 74, 148, 62, 124, 242, 151, 57, 244, 6, 117, 63, +1, 205, 1, 0, 19, 179, 127, 63, 83, 29, 70, 189, 174, 249, 42, 187, 1, 205, 1, 0, +138, 189, 127, 63, 114, 38, 56, 189, 127, 236, 30, 187, 1, 205, 1, 0, 233, 155, 13, 191, +137, 113, 1, 61, 25, 29, 85, 63, 1, 205, 1, 0, 230, 86, 4, 191, 14, 2, 5, 61, +107, 251, 90, 63, 1, 205, 1, 0, 181, 172, 127, 63, 26, 11, 78, 189, 66, 157, 78, 59, +1, 205, 1, 0, 209, 178, 127, 63, 173, 87, 70, 189, 79, 226, 70, 59, 1, 205, 1, 0, +166, 138, 27, 62, 188, 16, 66, 52, 142, 7, 125, 191, 1, 205, 1, 0, 68, 79, 150, 62, +208, 68, 203, 51, 66, 184, 116, 191, 1, 205, 1, 0, 118, 147, 127, 191, 177, 215, 105, 61, +221, 67, 232, 187, 1, 205, 1, 0, 170, 124, 127, 191, 129, 154, 128, 61, 53, 121, 255, 187, +1, 205, 1, 0, 24, 84, 136, 62, 28, 194, 118, 191, 70, 187, 87, 183, 1, 205, 1, 0, +189, 50, 26, 61, 140, 209, 127, 191, 126, 138, 80, 183, 1, 205, 1, 0, 157, 224, 16, 61, +253, 214, 127, 191, 245, 218, 99, 183, 1, 205, 1, 0, 159, 204, 137, 62, 206, 141, 118, 191, +10, 237, 81, 183, 1, 205, 1, 0, 14, 147, 35, 62, 117, 182, 124, 63, 103, 165, 91, 55, +1, 205, 1, 0, 205, 79, 182, 62, 137, 56, 111, 63, 110, 2, 81, 55, 1, 205, 1, 0, +77, 101, 212, 61, 157, 158, 126, 63, 63, 134, 85, 55, 1, 205, 1, 0, 224, 114, 16, 62, +175, 112, 125, 63, 29, 237, 89, 55, 1, 205, 1, 0, 162, 46, 14, 62, 46, 133, 125, 63, +131, 199, 79, 55, 1, 205, 1, 0, 161, 29, 34, 62, 126, 197, 124, 63, 209, 77, 97, 55, +1, 205, 1, 0, 43, 35, 127, 191, 159, 251, 167, 189, 52, 36, 155, 185, 1, 205, 1, 0, +204, 186, 126, 191, 81, 197, 203, 189, 139, 136, 188, 185, 1, 205, 1, 0, 64, 135, 127, 63, +16, 135, 120, 61, 25, 130, 101, 57, 1, 205, 1, 0, 128, 161, 127, 63, 95, 227, 91, 61, +246, 191, 74, 57, 1, 205, 1, 0, 62, 116, 126, 191, 16, 187, 224, 189, 138, 169, 206, 185, +1, 205, 1, 0, 225, 162, 119, 191, 176, 205, 129, 190, 80, 181, 110, 186, 1, 205, 1, 0, +189, 31, 127, 191, 56, 169, 168, 189, 142, 234, 231, 187, 1, 205, 1, 0, 227, 177, 126, 191, +106, 199, 205, 189, 244, 121, 13, 188, 1, 205, 1, 0, 69, 126, 127, 63, 232, 204, 128, 61, +109, 217, 109, 57, 1, 205, 1, 0, 128, 148, 127, 63, 136, 130, 106, 61, 194, 131, 88, 57, +1, 205, 1, 0, 194, 255, 127, 63, 60, 228, 49, 187, 251, 164, 48, 183, 1, 205, 1, 0, +241, 255, 127, 63, 225, 124, 174, 186, 11, 72, 173, 182, 1, 205, 1, 0, 83, 173, 126, 191, +3, 240, 207, 189, 24, 78, 192, 185, 1, 205, 1, 0, 94, 12, 123, 62, 240, 47, 120, 191, +74, 52, 143, 55, 1, 205, 1, 0, 140, 18, 156, 62, 243, 208, 115, 191, 162, 100, 147, 55, +1, 205, 1, 0, 172, 10, 119, 62, 60, 112, 120, 191, 37, 107, 148, 55, 1, 205, 1, 0, +54, 55, 253, 62, 30, 128, 94, 191, 117, 6, 140, 55, 1, 205, 1, 0, 39, 108, 111, 62, +123, 231, 120, 191, 253, 5, 144, 55, 1, 205, 1, 0, 146, 244, 182, 62, 21, 25, 111, 191, +188, 93, 138, 55, 1, 205, 1, 0, 166, 76, 143, 62, 210, 196, 117, 191, 172, 236, 141, 55, +1, 205, 1, 0, 14, 51, 66, 62, 169, 90, 123, 191, 153, 81, 145, 55, 1, 205, 1, 0, +85, 96, 161, 62, 149, 243, 114, 191, 131, 126, 140, 55, 1, 205, 1, 0, 221, 63, 56, 62, +102, 210, 123, 191, 33, 190, 145, 55, 1, 205, 1, 0, 26, 222, 79, 62, 133, 171, 122, 191, +207, 17, 145, 55, 1, 205, 1, 0, 207, 217, 166, 62, 116, 6, 114, 191, 209, 23, 140, 55, +1, 205, 1, 0, 175, 128, 176, 60, 201, 240, 127, 63, 1, 235, 147, 183, 1, 205, 1, 0, +109, 4, 230, 61, 88, 97, 126, 63, 60, 65, 147, 183, 1, 205, 1, 0, 161, 155, 53, 62, +24, 241, 123, 63, 1, 23, 152, 183, 1, 205, 1, 0, 181, 236, 201, 62, 7, 64, 107, 63, +203, 24, 148, 183, 1, 205, 1, 0, 109, 101, 221, 61, 240, 127, 126, 63, 166, 192, 151, 183, +1, 205, 1, 0, 226, 9, 205, 61, 187, 182, 126, 63, 175, 25, 147, 183, 1, 205, 1, 0, +81, 141, 113, 62, 141, 198, 120, 63, 197, 189, 143, 183, 1, 205, 1, 0, 240, 143, 25, 62, +228, 26, 125, 63, 22, 46, 146, 183, 1, 205, 1, 0, 240, 0, 90, 61, 28, 163, 127, 63, +247, 211, 147, 183, 1, 205, 1, 0, 204, 85, 65, 62, 83, 101, 123, 63, 119, 99, 145, 183, +1, 205, 1, 0, 167, 56, 48, 61, 82, 195, 127, 63, 40, 0, 148, 183, 1, 205, 1, 0, +100, 215, 137, 61, 100, 107, 127, 63, 84, 202, 147, 183, 1, 205, 1, 0, 46, 17, 185, 189, +71, 97, 73, 190, 181, 238, 121, 63, 1, 205, 1, 0, 10, 166, 81, 63, 185, 21, 232, 189, +50, 5, 16, 63, 1, 205, 1, 0, 224, 138, 128, 61, 142, 152, 16, 190, 208, 236, 124, 63, +1, 205, 1, 0, 134, 162, 73, 63, 12, 137, 178, 189, 49, 37, 28, 63, 1, 205, 1, 0, +60, 190, 91, 61, 104, 118, 247, 189, 190, 192, 125, 63, 1, 205, 1, 0, 157, 228, 60, 63, +4, 68, 167, 189, 128, 132, 43, 63, 1, 205, 1, 0, 163, 46, 67, 62, 53, 235, 170, 189, +147, 101, 122, 63, 1, 205, 1, 0, 232, 235, 59, 63, 11, 120, 108, 189, 198, 54, 45, 63, +1, 205, 1, 0, 24, 232, 107, 62, 193, 16, 56, 189, 33, 217, 120, 63, 1, 205, 1, 0, +209, 199, 37, 63, 105, 34, 16, 189, 249, 220, 66, 63, 1, 205, 1, 0, 39, 208, 109, 62, +188, 210, 161, 188, 2, 243, 120, 63, 1, 205, 1, 0, 13, 124, 10, 63, 74, 237, 139, 188, +197, 67, 87, 63, 1, 205, 1, 0, 90, 142, 144, 62, 1, 2, 163, 58, 168, 149, 117, 63, +1, 205, 1, 0, 252, 40, 0, 63, 47, 24, 147, 58, 29, 156, 93, 63, 1, 205, 1, 0, +143, 88, 111, 62, 212, 210, 140, 187, 8, 232, 120, 63, 1, 205, 1, 0, 14, 39, 235, 62, +238, 167, 128, 187, 110, 102, 99, 63, 1, 205, 1, 0, 65, 224, 58, 63, 82, 251, 13, 189, +216, 189, 46, 63, 1, 205, 1, 0, 138, 82, 110, 63, 196, 182, 151, 188, 241, 183, 186, 62, +1, 205, 1, 0, 35, 206, 63, 63, 215, 196, 167, 190, 250, 87, 19, 63, 1, 205, 1, 0, +176, 211, 124, 63, 136, 9, 159, 189, 126, 173, 11, 62, 1, 205, 1, 0, 181, 72, 63, 63, +115, 245, 39, 190, 162, 223, 36, 191, 1, 205, 1, 0, 118, 56, 121, 63, 135, 26, 103, 189, +58, 219, 98, 190, 1, 205, 1, 0, 113, 235, 96, 63, 2, 184, 253, 188, 142, 0, 244, 190, +1, 205, 1, 0, 193, 15, 121, 63, 160, 178, 117, 188, 176, 74, 108, 190, 1, 205, 1, 0, +147, 140, 121, 63, 87, 215, 124, 188, 190, 225, 99, 190, 1, 205, 1, 0, 162, 136, 126, 63, +174, 71, 242, 187, 219, 91, 218, 189, 1, 205, 1, 0, 69, 94, 227, 61, 124, 241, 195, 58, +204, 106, 126, 191, 1, 205, 1, 0, 254, 83, 83, 62, 205, 227, 192, 58, 34, 125, 122, 191, +1, 205, 1, 0, 202, 49, 28, 191, 95, 112, 180, 189, 250, 145, 73, 191, 1, 205, 1, 0, +55, 49, 9, 191, 230, 70, 192, 189, 92, 203, 86, 191, 1, 205, 1, 0, 109, 250, 80, 61, +48, 39, 50, 52, 165, 170, 127, 63, 1, 205, 1, 0, 17, 173, 208, 61, 124, 197, 161, 177, +233, 170, 126, 63, 1, 205, 1, 0, 54, 176, 64, 63, 39, 62, 205, 60, 30, 108, 40, 63, +1, 205, 1, 0, 113, 111, 100, 63, 188, 183, 140, 60, 16, 242, 230, 62, 1, 205, 1, 0, +153, 239, 85, 63, 156, 202, 251, 60, 85, 96, 12, 63, 1, 205, 1, 0, 55, 202, 110, 63, +131, 66, 165, 60, 179, 68, 184, 62, 1, 205, 1, 0, 238, 101, 88, 63, 251, 180, 50, 61, +223, 81, 8, 63, 1, 205, 1, 0, 195, 174, 109, 63, 46, 126, 248, 60, 190, 141, 189, 62, +1, 205, 1, 0, 240, 57, 100, 63, 233, 178, 78, 61, 114, 126, 230, 62, 1, 205, 1, 0, +57, 24, 115, 63, 175, 11, 15, 61, 60, 131, 159, 62, 1, 205, 1, 0, 57, 161, 105, 63, +235, 150, 83, 61, 250, 162, 207, 62, 1, 205, 1, 0, 236, 204, 117, 63, 25, 163, 16, 61, +109, 239, 141, 62, 1, 205, 1, 0, 200, 240, 119, 63, 183, 166, 60, 61, 161, 132, 122, 62, +1, 205, 1, 0, 50, 207, 124, 63, 185, 138, 238, 60, 156, 98, 30, 62, 1, 205, 1, 0, +178, 63, 120, 63, 202, 138, 67, 61, 122, 63, 117, 62, 1, 205, 1, 0, 29, 226, 124, 63, +210, 32, 249, 60, 88, 58, 28, 62, 1, 205, 1, 0, 109, 139, 122, 63, 11, 229, 98, 61, +224, 121, 74, 62, 1, 205, 1, 0, 99, 167, 125, 63, 122, 64, 21, 61, 113, 48, 5, 62, +1, 205, 1, 0, 190, 158, 125, 63, 8, 118, 90, 61, 199, 38, 0, 62, 1, 205, 1, 0, +21, 4, 127, 63, 15, 171, 12, 61, 72, 9, 165, 61, 1, 205, 1, 0, 245, 180, 126, 63, +248, 88, 142, 61, 58, 86, 148, 61, 1, 205, 1, 0, 212, 80, 127, 63, 2, 46, 124, 61, +130, 40, 33, 61, 1, 205, 1, 0, 95, 191, 126, 63, 205, 245, 149, 61, 12, 215, 135, 61, +1, 205, 1, 0, 184, 93, 127, 63, 94, 116, 71, 61, 66, 218, 79, 61, 1, 205, 1, 0, +113, 201, 127, 63, 84, 50, 33, 61, 85, 47, 48, 188, 1, 205, 1, 0, 62, 199, 127, 63, +138, 100, 39, 61, 96, 59, 0, 188, 1, 205, 1, 0, 151, 206, 127, 63, 210, 47, 13, 61, +139, 86, 146, 188, 1, 205, 1, 0, 248, 204, 127, 63, 58, 27, 20, 61, 214, 87, 129, 188, +1, 205, 1, 0, 104, 212, 127, 63, 229, 129, 237, 60, 244, 52, 181, 188, 1, 205, 1, 0, +51, 210, 127, 63, 134, 13, 253, 60, 4, 114, 172, 188, 1, 205, 1, 0, 181, 221, 127, 63, +93, 224, 186, 60, 39, 223, 187, 188, 1, 205, 1, 0, 28, 218, 127, 63, 25, 118, 204, 60, +62, 34, 189, 188, 1, 205, 1, 0, 71, 235, 127, 63, 42, 68, 129, 60, 95, 98, 160, 188, +1, 205, 1, 0, 92, 230, 127, 63, 130, 85, 149, 60, 3, 197, 173, 188, 1, 205, 1, 0, +3, 250, 127, 63, 163, 128, 252, 59, 121, 252, 53, 188, 1, 205, 1, 0, 106, 245, 127, 63, +34, 120, 44, 60, 87, 179, 110, 188, 1, 205, 1, 0, 179, 255, 127, 63, 151, 132, 212, 58, +35, 116, 39, 187, 1, 205, 1, 0, 212, 254, 127, 63, 200, 190, 81, 59, 38, 59, 165, 187, +1, 205, 1, 0, 255, 118, 125, 63, 41, 205, 133, 61, 24, 122, 254, 189, 1, 205, 1, 0, +47, 206, 126, 63, 240, 239, 55, 61, 13, 234, 174, 189, 1, 205, 1, 0, 94, 10, 118, 63, +176, 227, 141, 61, 198, 230, 136, 190, 1, 205, 1, 0, 198, 220, 122, 63, 85, 203, 76, 61, +81, 152, 69, 190, 1, 205, 1, 0, 42, 134, 108, 63, 190, 85, 125, 61, 248, 77, 193, 190, +1, 205, 1, 0, 13, 56, 118, 63, 132, 73, 53, 61, 170, 84, 138, 190, 1, 205, 1, 0, +58, 35, 93, 63, 183, 131, 94, 61, 180, 56, 0, 191, 1, 205, 1, 0, 171, 86, 110, 63, +120, 53, 33, 61, 134, 201, 185, 190, 1, 205, 1, 0, 232, 24, 65, 63, 191, 194, 72, 61, +78, 155, 39, 191, 1, 205, 1, 0, 62, 77, 92, 63, 218, 192, 27, 61, 65, 8, 2, 191, +1, 205, 1, 0, 44, 180, 46, 63, 232, 174, 192, 60, 98, 6, 59, 191, 1, 205, 1, 0, +130, 70, 89, 63, 154, 102, 139, 60, 255, 78, 7, 191, 1, 205, 1, 0, 73, 164, 30, 63, +11, 161, 149, 60, 143, 221, 72, 191, 1, 205, 1, 0, 222, 198, 79, 63, 29, 191, 94, 60, +19, 130, 21, 191, 1, 205, 1, 0, 0, 7, 16, 62, 196, 34, 245, 57, 131, 116, 125, 191, +1, 205, 1, 0, 94, 16, 138, 62, 194, 108, 238, 57, 82, 132, 118, 191, 1, 205, 1, 0, +162, 106, 114, 63, 95, 125, 42, 61, 82, 45, 163, 190, 1, 205, 1, 0, 12, 179, 122, 63, +139, 196, 214, 60, 175, 141, 77, 190, 1, 205, 1, 0, 85, 166, 127, 63, 22, 49, 86, 61, +204, 44, 224, 56, 1, 205, 1, 0, 190, 219, 127, 63, 195, 59, 8, 61, 191, 128, 143, 56, +1, 205, 1, 0, 147, 224, 118, 63, 133, 9, 38, 61, 85, 221, 133, 62, 1, 205, 1, 0, +129, 144, 124, 63, 254, 238, 204, 60, 48, 57, 37, 62, 1, 205, 1, 0, 139, 244, 127, 63, +182, 52, 11, 60, 235, 109, 136, 188, 1, 205, 1, 0, 237, 252, 127, 63, 254, 54, 144, 59, +179, 81, 13, 188, 1, 205, 1, 0, 196, 102, 132, 61, 44, 179, 215, 180, 231, 118, 127, 63, +1, 205, 1, 0, 200, 212, 3, 62, 80, 93, 214, 180, 159, 222, 125, 63, 1, 205, 1, 0, +83, 142, 126, 63, 177, 56, 217, 61, 138, 213, 100, 57, 1, 205, 1, 0, 154, 222, 126, 63, +136, 64, 192, 61, 5, 117, 74, 57, 1, 205, 1, 0, 40, 36, 2, 62, 151, 185, 104, 58, +139, 236, 125, 191, 1, 205, 1, 0, 110, 30, 92, 63, 138, 250, 168, 188, 13, 153, 2, 191, +1, 205, 1, 0, 138, 30, 119, 63, 11, 215, 44, 188, 239, 147, 133, 190, 1, 205, 1, 0, +185, 169, 0, 61, 186, 139, 62, 189, 172, 152, 127, 191, 1, 205, 1, 0, 136, 218, 206, 62, +170, 99, 46, 189, 91, 236, 105, 191, 1, 205, 1, 0, 142, 118, 95, 190, 218, 3, 188, 189, +218, 184, 120, 191, 1, 205, 1, 0, 242, 116, 155, 62, 5, 144, 183, 189, 55, 213, 114, 191, +1, 205, 1, 0, 195, 26, 56, 62, 29, 60, 5, 190, 176, 157, 121, 191, 1, 205, 1, 0, +239, 99, 82, 63, 109, 84, 154, 189, 66, 145, 16, 191, 1, 205, 1, 0, 64, 104, 250, 61, +7, 55, 74, 190, 199, 255, 120, 191, 1, 205, 1, 0, 30, 168, 97, 63, 180, 109, 192, 189, +134, 243, 236, 190, 1, 205, 1, 0, 176, 251, 2, 188, 216, 82, 135, 190, 84, 227, 118, 191, +1, 205, 1, 0, 157, 219, 103, 63, 123, 122, 229, 189, 84, 85, 209, 190, 1, 205, 1, 0, +128, 45, 21, 191, 67, 38, 162, 190, 124, 152, 63, 191, 1, 205, 1, 0, 217, 240, 93, 63, +194, 225, 70, 190, 199, 255, 234, 190, 1, 205, 1, 0, 112, 230, 122, 191, 58, 96, 75, 190, +63, 24, 214, 185, 1, 205, 1, 0, 90, 122, 93, 191, 78, 99, 0, 191, 135, 39, 135, 186, +1, 205, 1, 0, 49, 182, 82, 191, 46, 223, 143, 190, 29, 174, 252, 62, 1, 205, 1, 0, +108, 183, 124, 62, 217, 20, 120, 191, 233, 97, 245, 55, 1, 205, 1, 0, 181, 170, 156, 62, +141, 184, 115, 191, 65, 225, 240, 55, 1, 205, 1, 0, 89, 233, 214, 62, 28, 91, 104, 191, +56, 3, 227, 55, 1, 205, 1, 0, 89, 62, 89, 63, 10, 110, 7, 191, 75, 143, 103, 55, +1, 205, 1, 0, 0, 195, 95, 62, 51, 208, 121, 191, 43, 10, 254, 55, 1, 205, 1, 0, +64, 219, 114, 62, 59, 178, 120, 191, 190, 123, 253, 55, 1, 205, 1, 0, 25, 182, 180, 62, +53, 134, 111, 191, 181, 96, 243, 55, 1, 205, 1, 0, 48, 29, 168, 62, 124, 206, 113, 191, +222, 192, 247, 55, 1, 205, 1, 0, 42, 158, 77, 63, 226, 128, 24, 191, 110, 113, 151, 55, +1, 205, 1, 0, 28, 13, 42, 63, 30, 92, 63, 191, 240, 197, 195, 55, 1, 205, 1, 0, +59, 170, 51, 63, 24, 93, 54, 191, 42, 84, 178, 55, 1, 205, 1, 0, 76, 210, 105, 63, +212, 116, 208, 190, 201, 45, 78, 55, 1, 205, 1, 0, 163, 203, 81, 63, 15, 180, 18, 191, +90, 145, 165, 55, 1, 205, 1, 0, 245, 37, 26, 63, 61, 99, 76, 191, 186, 107, 208, 55, +1, 205, 1, 0, 96, 204, 86, 63, 139, 70, 11, 191, 90, 180, 140, 55, 1, 205, 1, 0, +202, 19, 89, 63, 55, 178, 7, 191, 193, 189, 120, 55, 1, 205, 1, 0, 151, 20, 100, 63, +195, 130, 232, 190, 76, 224, 122, 55, 1, 205, 1, 0, 29, 138, 91, 63, 232, 172, 3, 191, +184, 230, 122, 55, 1, 205, 1, 0, 137, 164, 222, 62, 100, 135, 102, 191, 153, 199, 230, 55, +1, 205, 1, 0, 86, 161, 103, 63, 188, 5, 218, 190, 197, 87, 84, 55, 1, 205, 1, 0, +102, 174, 102, 63, 178, 2, 222, 190, 67, 85, 82, 55, 1, 205, 1, 0, 3, 216, 92, 63, +214, 121, 1, 191, 128, 194, 141, 55, 1, 205, 1, 0, 82, 208, 103, 63, 163, 61, 217, 190, +168, 203, 135, 55, 1, 205, 1, 0, 191, 148, 123, 63, 173, 112, 61, 190, 133, 78, 15, 55, +1, 205, 1, 0, 251, 225, 124, 63, 141, 80, 31, 190, 121, 184, 137, 53, 1, 205, 1, 0, +202, 248, 125, 63, 171, 164, 0, 190, 64, 74, 92, 181, 1, 205, 1, 0, 254, 214, 126, 63, +115, 194, 194, 189, 105, 113, 120, 54, 1, 205, 1, 0, 203, 121, 127, 63, 224, 255, 130, 189, +152, 252, 110, 54, 1, 205, 1, 0, 239, 221, 127, 63, 162, 12, 4, 189, 182, 2, 129, 54, +1, 205, 1, 0, 163, 215, 113, 63, 123, 232, 167, 190, 73, 252, 55, 55, 1, 205, 1, 0, +93, 66, 77, 63, 94, 252, 24, 191, 135, 184, 133, 55, 1, 205, 1, 0, 25, 208, 54, 63, +53, 53, 51, 191, 131, 36, 198, 55, 1, 205, 1, 0, 215, 217, 250, 62, 74, 43, 95, 191, +42, 151, 240, 55, 1, 205, 1, 0, 163, 35, 74, 63, 205, 21, 29, 191, 9, 243, 179, 55, +1, 205, 1, 0, 252, 150, 61, 63, 189, 5, 44, 191, 176, 40, 179, 55, 1, 205, 1, 0, +26, 68, 63, 63, 31, 40, 42, 191, 52, 88, 166, 55, 1, 205, 1, 0, 139, 34, 59, 63, +149, 176, 46, 191, 218, 161, 171, 55, 1, 205, 1, 0, 74, 225, 193, 62, 152, 239, 108, 191, +246, 85, 246, 55, 1, 205, 1, 0, 206, 225, 244, 62, 3, 210, 96, 191, 162, 177, 232, 55, +1, 205, 1, 0, 75, 36, 149, 62, 249, 229, 116, 191, 154, 62, 1, 56, 1, 205, 1, 0, +47, 93, 13, 63, 253, 109, 85, 191, 102, 108, 228, 55, 1, 205, 1, 0, 127, 61, 54, 63, +73, 202, 51, 191, 191, 184, 179, 55, 1, 205, 1, 0, 145, 185, 74, 63, 31, 84, 28, 191, +74, 45, 160, 55, 1, 205, 1, 0, 209, 195, 63, 63, 35, 152, 41, 191, 111, 21, 187, 55, +1, 205, 1, 0, 3, 88, 221, 62, 100, 215, 102, 191, 80, 74, 241, 55, 1, 205, 1, 0, +40, 235, 82, 63, 127, 21, 17, 191, 52, 181, 141, 55, 1, 205, 1, 0, 211, 139, 84, 63, +91, 176, 14, 191, 165, 42, 145, 55, 1, 205, 1, 0, 127, 48, 46, 63, 203, 153, 59, 191, +159, 190, 199, 55, 1, 205, 1, 0, 247, 122, 37, 63, 120, 83, 67, 191, 35, 3, 190, 55, +1, 205, 1, 0, 24, 143, 85, 63, 42, 43, 13, 191, 255, 237, 135, 55, 1, 205, 1, 0, +58, 114, 92, 63, 216, 38, 2, 191, 184, 132, 130, 55, 1, 205, 1, 0, 57, 31, 21, 60, +74, 253, 127, 63, 209, 234, 5, 184, 1, 205, 1, 0, 144, 222, 154, 61, 90, 68, 127, 63, +121, 240, 2, 184, 1, 205, 1, 0, 106, 52, 104, 59, 151, 255, 127, 63, 23, 28, 6, 184, +1, 205, 1, 0, 7, 13, 89, 62, 221, 46, 122, 63, 54, 66, 6, 184, 1, 205, 1, 0, +6, 43, 78, 63, 65, 194, 23, 63, 214, 249, 159, 183, 1, 205, 1, 0, 55, 60, 177, 188, +170, 240, 127, 63, 206, 118, 250, 183, 1, 205, 1, 0, 127, 170, 5, 62, 70, 207, 125, 63, +17, 10, 1, 184, 1, 205, 1, 0, 171, 181, 188, 186, 238, 255, 127, 63, 255, 46, 249, 183, +1, 205, 1, 0, 7, 236, 207, 61, 97, 173, 126, 63, 71, 189, 236, 183, 1, 205, 1, 0, +199, 162, 61, 63, 190, 248, 43, 63, 18, 105, 170, 183, 1, 205, 1, 0, 179, 119, 10, 63, +239, 81, 87, 63, 58, 154, 202, 183, 1, 205, 1, 0, 10, 59, 24, 63, 230, 209, 77, 63, +20, 104, 206, 183, 1, 205, 1, 0, 66, 236, 100, 63, 213, 44, 229, 62, 226, 110, 98, 183, +1, 205, 1, 0, 161, 156, 67, 63, 116, 36, 37, 63, 128, 200, 159, 183, 1, 205, 1, 0, +26, 30, 232, 62, 56, 46, 100, 63, 39, 158, 236, 183, 1, 205, 1, 0, 244, 183, 74, 63, +53, 86, 28, 63, 138, 195, 158, 183, 1, 205, 1, 0, 57, 239, 77, 63, 91, 19, 24, 63, +119, 216, 159, 183, 1, 205, 1, 0, 171, 49, 93, 63, 112, 224, 0, 63, 241, 237, 129, 183, +1, 205, 1, 0, 230, 99, 81, 63, 248, 71, 19, 63, 203, 209, 175, 183, 1, 205, 1, 0, +223, 254, 97, 63, 30, 132, 240, 62, 252, 241, 106, 183, 1, 205, 1, 0, 29, 184, 96, 63, +215, 64, 245, 62, 127, 33, 101, 183, 1, 205, 1, 0, 121, 54, 83, 63, 196, 167, 16, 63, +105, 197, 159, 183, 1, 205, 1, 0, 244, 61, 98, 63, 111, 150, 239, 62, 95, 72, 87, 183, +1, 205, 1, 0, 153, 39, 123, 63, 31, 73, 70, 62, 184, 71, 70, 182, 1, 205, 1, 0, +196, 161, 124, 63, 90, 143, 37, 62, 52, 18, 222, 182, 1, 205, 1, 0, 93, 215, 125, 63, +192, 179, 4, 62, 79, 199, 165, 182, 1, 205, 1, 0, 167, 200, 126, 63, 247, 100, 199, 61, +56, 87, 126, 182, 1, 205, 1, 0, 122, 117, 127, 63, 175, 22, 133, 61, 200, 199, 114, 182, +1, 205, 1, 0, 64, 88, 111, 63, 4, 169, 181, 62, 162, 166, 67, 183, 1, 205, 1, 0, +227, 194, 28, 63, 246, 99, 74, 63, 116, 234, 169, 183, 1, 205, 1, 0, 203, 120, 154, 62, +41, 18, 116, 63, 57, 190, 242, 183, 1, 205, 1, 0, 137, 163, 56, 63, 116, 83, 49, 63, +213, 38, 172, 183, 1, 205, 1, 0, 4, 245, 40, 63, 154, 83, 64, 63, 32, 79, 201, 183, +1, 205, 1, 0, 225, 76, 37, 62, 124, 164, 124, 63, 45, 231, 243, 183, 1, 205, 1, 0, +78, 243, 112, 61, 130, 142, 127, 63, 147, 225, 247, 183, 1, 205, 1, 0, 185, 247, 196, 62, +101, 76, 108, 63, 160, 188, 231, 183, 1, 205, 1, 0, 29, 197, 232, 62, 171, 3, 100, 63, +148, 10, 223, 183, 1, 205, 1, 0, 164, 239, 27, 63, 229, 6, 75, 63, 145, 230, 204, 183, +1, 205, 1, 0, 78, 123, 57, 63, 184, 113, 48, 63, 70, 232, 167, 183, 1, 205, 1, 0, +216, 45, 105, 62, 62, 70, 121, 63, 225, 183, 250, 183, 1, 205, 1, 0, 76, 54, 69, 63, +96, 58, 35, 63, 88, 83, 181, 183, 1, 205, 1, 0, 219, 134, 71, 63, 237, 99, 32, 63, +41, 66, 154, 183, 1, 205, 1, 0, 103, 96, 16, 63, 71, 103, 83, 63, 57, 226, 192, 183, +1, 205, 1, 0, 87, 249, 3, 63, 49, 92, 91, 63, 28, 117, 243, 183, 1, 205, 1, 0, +77, 98, 204, 62, 243, 183, 106, 63, 244, 235, 4, 184, 1, 205, 1, 0, 182, 246, 72, 63, +19, 150, 30, 63, 217, 68, 157, 183, 1, 205, 1, 0, 109, 168, 82, 63, 80, 118, 17, 63, +152, 150, 143, 183, 1, 205, 1, 0, 56, 235, 120, 191, 221, 45, 111, 190, 9, 2, 152, 185, +1, 205, 1, 0, 137, 168, 117, 191, 29, 14, 144, 190, 1, 27, 183, 185, 1, 205, 1, 0, +231, 160, 23, 62, 74, 241, 237, 179, 139, 45, 125, 63, 1, 205, 1, 0, 14, 253, 146, 62, +132, 119, 230, 179, 59, 57, 117, 63, 1, 205, 1, 0, 10, 27, 124, 63, 221, 238, 49, 62, +211, 42, 98, 57, 1, 205, 1, 0, 22, 243, 124, 63, 195, 155, 29, 62, 62, 85, 72, 57, +1, 205, 1, 0, 0, 33, 24, 62, 202, 66, 67, 53, 190, 40, 125, 191, 1, 205, 1, 0, +74, 55, 147, 62, 56, 252, 126, 53, 128, 48, 117, 191, 1, 205, 1, 0, 236, 37, 122, 191, +138, 177, 89, 190, 73, 57, 138, 185, 1, 205, 1, 0, 85, 71, 121, 191, 31, 27, 105, 190, +135, 2, 148, 185, 1, 205, 1, 0, 161, 115, 123, 63, 48, 43, 64, 62, 197, 39, 116, 57, +1, 205, 1, 0, 111, 242, 123, 63, 249, 125, 53, 62, 117, 180, 102, 57, 1, 205, 1, 0, +68, 50, 229, 62, 231, 234, 100, 191, 178, 180, 64, 56, 1, 205, 1, 0, 187, 46, 160, 62, +31, 38, 115, 191, 209, 9, 74, 56, 1, 205, 1, 0, 213, 43, 212, 62, 17, 252, 104, 191, +61, 61, 63, 56, 1, 205, 1, 0, 27, 19, 191, 61, 37, 226, 126, 63, 126, 144, 86, 184, +1, 205, 1, 0, 8, 70, 158, 189, 0, 60, 127, 63, 98, 169, 86, 184, 1, 205, 1, 0, +216, 30, 70, 61, 74, 179, 127, 63, 184, 13, 87, 184, 1, 205, 1, 0, 33, 240, 23, 189, +234, 31, 212, 190, 57, 205, 104, 63, 1, 205, 1, 0, 45, 223, 78, 63, 53, 20, 122, 190, +52, 58, 9, 63, 1, 205, 1, 0, 120, 77, 194, 61, 83, 197, 156, 190, 170, 125, 114, 63, +1, 205, 1, 0, 171, 188, 72, 63, 240, 118, 67, 190, 218, 43, 23, 63, 1, 205, 1, 0, +8, 31, 168, 61, 4, 159, 135, 190, 164, 245, 117, 63, 1, 205, 1, 0, 150, 201, 60, 63, +82, 209, 55, 190, 15, 175, 38, 63, 1, 205, 1, 0, 105, 45, 85, 62, 37, 200, 61, 190, +221, 218, 117, 63, 1, 205, 1, 0, 215, 97, 60, 63, 137, 98, 3, 190, 33, 52, 42, 63, +1, 205, 1, 0, 7, 4, 118, 62, 64, 192, 206, 189, 143, 39, 119, 63, 1, 205, 1, 0, +246, 176, 38, 63, 115, 166, 161, 189, 118, 61, 65, 63, 1, 205, 1, 0, 83, 135, 114, 62, +226, 159, 54, 189, 67, 116, 120, 63, 1, 205, 1, 0, 103, 49, 11, 63, 76, 194, 29, 189, +31, 160, 86, 63, 1, 205, 1, 0, 131, 104, 144, 62, 212, 120, 56, 59, 0, 155, 117, 63, +1, 205, 1, 0, 4, 27, 0, 63, 225, 120, 38, 59, 254, 163, 93, 63, 1, 205, 1, 0, +121, 102, 112, 62, 151, 57, 31, 188, 54, 213, 120, 63, 1, 205, 1, 0, 223, 140, 235, 62, +74, 112, 17, 188, 189, 73, 99, 63, 1, 205, 1, 0, 74, 120, 59, 63, 211, 39, 159, 189, +255, 48, 45, 63, 1, 205, 1, 0, 237, 80, 110, 63, 2, 183, 42, 189, 2, 197, 185, 62, +1, 205, 1, 0, 108, 252, 41, 63, 37, 46, 23, 191, 75, 210, 234, 62, 1, 205, 1, 0, +164, 251, 121, 63, 92, 80, 46, 190, 128, 96, 7, 62, 1, 205, 1, 0, 93, 98, 58, 63, +177, 46, 175, 190, 110, 17, 24, 191, 1, 205, 1, 0, 76, 214, 119, 63, 26, 9, 0, 190, +95, 73, 94, 190, 1, 205, 1, 0, 109, 241, 96, 63, 86, 46, 142, 189, 40, 213, 241, 190, +1, 205, 1, 0, 255, 255, 120, 63, 236, 85, 10, 189, 186, 75, 107, 190, 1, 205, 1, 0, +254, 120, 121, 63, 176, 109, 14, 189, 103, 252, 98, 190, 1, 205, 1, 0, 111, 130, 126, 63, +236, 203, 136, 188, 19, 3, 218, 189, 1, 205, 1, 0, 220, 153, 226, 61, 80, 188, 93, 59, +60, 109, 126, 191, 1, 205, 1, 0, 62, 246, 82, 62, 176, 77, 90, 59, 198, 129, 122, 191, +1, 205, 1, 0, 107, 10, 22, 191, 13, 143, 75, 190, 9, 21, 73, 191, 1, 205, 1, 0, +106, 78, 2, 191, 85, 64, 88, 190, 182, 158, 85, 191, 1, 205, 1, 0, 248, 184, 63, 63, +68, 238, 104, 61, 48, 4, 41, 63, 1, 205, 1, 0, 222, 16, 100, 63, 82, 170, 31, 61, +193, 181, 231, 62, 1, 205, 1, 0, 88, 230, 84, 63, 90, 9, 143, 61, 43, 8, 13, 63, +1, 205, 1, 0, 249, 105, 110, 63, 236, 163, 59, 61, 196, 2, 185, 62, 1, 205, 1, 0, +163, 182, 86, 63, 144, 52, 203, 61, 164, 18, 9, 63, 1, 205, 1, 0, 103, 243, 108, 63, +134, 64, 141, 61, 33, 144, 190, 62, 1, 205, 1, 0, 153, 82, 98, 63, 8, 57, 235, 61, +186, 241, 231, 62, 1, 205, 1, 0, 113, 63, 114, 63, 83, 190, 162, 61, 238, 121, 160, 62, +1, 205, 1, 0, 59, 192, 103, 63, 205, 218, 240, 61, 21, 2, 209, 62, 1, 205, 1, 0, +86, 250, 116, 63, 19, 146, 164, 61, 85, 207, 142, 62, 1, 205, 1, 0, 147, 166, 118, 63, +193, 217, 214, 61, 151, 74, 124, 62, 1, 205, 1, 0, 167, 80, 124, 63, 38, 164, 135, 61, +218, 71, 31, 62, 1, 205, 1, 0, 138, 224, 118, 63, 2, 185, 222, 61, 66, 252, 118, 62, +1, 205, 1, 0, 15, 89, 124, 63, 100, 175, 141, 61, 70, 30, 29, 62, 1, 205, 1, 0, +231, 198, 120, 63, 67, 69, 1, 62, 244, 5, 76, 62, 1, 205, 1, 0, 252, 231, 124, 63, +125, 229, 169, 61, 64, 18, 6, 62, 1, 205, 1, 0, 202, 10, 124, 63, 250, 244, 248, 61, +253, 35, 1, 62, 1, 205, 1, 0, 238, 94, 126, 63, 226, 23, 160, 61, 159, 22, 166, 61, +1, 205, 1, 0, 100, 19, 124, 63, 237, 56, 34, 62, 67, 119, 149, 61, 1, 205, 1, 0, +61, 67, 125, 63, 177, 184, 15, 62, 38, 105, 34, 61, 1, 205, 1, 0, 153, 212, 123, 63, +217, 222, 42, 62, 131, 217, 136, 61, 1, 205, 1, 0, 255, 20, 126, 63, 235, 68, 227, 61, +104, 101, 81, 61, 1, 205, 1, 0, 101, 244, 126, 63, 92, 141, 183, 61, 38, 150, 49, 188, +1, 205, 1, 0, 107, 225, 126, 63, 255, 161, 190, 61, 168, 62, 1, 188, 1, 205, 1, 0, +86, 43, 127, 63, 54, 176, 160, 61, 121, 85, 147, 188, 1, 205, 1, 0, 62, 25, 127, 63, +10, 152, 168, 61, 187, 71, 130, 188, 1, 205, 1, 0, 13, 97, 127, 63, 252, 16, 135, 61, +205, 81, 182, 188, 1, 205, 1, 0, 48, 79, 127, 63, 85, 241, 143, 61, 75, 135, 173, 188, +1, 205, 1, 0, 114, 150, 127, 63, 154, 88, 84, 61, 81, 197, 188, 188, 1, 205, 1, 0, +187, 132, 127, 63, 12, 105, 104, 61, 51, 37, 190, 188, 1, 205, 1, 0, 69, 201, 127, 63, +208, 180, 18, 61, 23, 26, 161, 188, 1, 205, 1, 0, 241, 184, 127, 63, 239, 141, 41, 61, +241, 132, 174, 188, 1, 205, 1, 0, 242, 241, 127, 63, 95, 11, 143, 60, 137, 107, 54, 188, +1, 205, 1, 0, 82, 230, 127, 63, 144, 136, 195, 60, 74, 147, 111, 188, 1, 205, 1, 0, +89, 255, 127, 63, 19, 110, 112, 59, 61, 121, 39, 187, 1, 205, 1, 0, 115, 253, 127, 63, +177, 98, 237, 59, 141, 87, 165, 187, 1, 205, 1, 0, 171, 27, 123, 63, 78, 125, 24, 62, +168, 54, 0, 190, 1, 205, 1, 0, 217, 179, 125, 63, 177, 137, 209, 61, 0, 46, 176, 189, +1, 205, 1, 0, 212, 53, 115, 63, 151, 154, 33, 62, 147, 224, 137, 190, 1, 205, 1, 0, +183, 106, 121, 63, 128, 81, 233, 61, 71, 16, 71, 190, 1, 205, 1, 0, 136, 6, 106, 63, +152, 53, 16, 62, 57, 156, 194, 190, 1, 205, 1, 0, 99, 253, 116, 63, 140, 109, 206, 61, +95, 73, 139, 190, 1, 205, 1, 0, 212, 218, 90, 63, 76, 32, 253, 61, 120, 252, 0, 191, +1, 205, 1, 0, 217, 55, 109, 63, 210, 112, 183, 61, 183, 243, 186, 190, 1, 205, 1, 0, +107, 187, 62, 63, 196, 14, 228, 61, 202, 91, 40, 191, 1, 205, 1, 0, 22, 252, 90, 63, +181, 23, 177, 61, 48, 188, 2, 191, 1, 205, 1, 0, 60, 172, 45, 63, 2, 141, 90, 61, +29, 149, 59, 191, 1, 205, 1, 0, 135, 212, 88, 63, 243, 35, 30, 61, 54, 187, 7, 191, +1, 205, 1, 0, 134, 201, 29, 63, 71, 146, 41, 61, 25, 80, 73, 191, 1, 205, 1, 0, +209, 99, 79, 63, 112, 124, 252, 60, 143, 224, 21, 191, 1, 205, 1, 0, 100, 65, 113, 63, +167, 17, 194, 61, 81, 60, 164, 190, 1, 205, 1, 0, 58, 69, 122, 63, 214, 34, 116, 61, +73, 155, 78, 190, 1, 205, 1, 0, 210, 44, 126, 63, 88, 26, 244, 61, 20, 9, 223, 56, +1, 205, 1, 0, 248, 67, 127, 63, 179, 6, 155, 61, 128, 112, 143, 56, 1, 205, 1, 0, +14, 216, 117, 63, 184, 7, 189, 61, 92, 188, 134, 62, 1, 205, 1, 0, 71, 49, 124, 63, +158, 241, 104, 61, 254, 8, 38, 62, 1, 205, 1, 0, 200, 234, 127, 63, 144, 178, 157, 60, +108, 77, 136, 188, 1, 205, 1, 0, 81, 250, 127, 63, 45, 55, 35, 60, 216, 25, 13, 188, +1, 205, 1, 0, 106, 120, 120, 63, 235, 134, 118, 62, 69, 5, 95, 57, 1, 205, 1, 0, +207, 24, 122, 63, 16, 162, 90, 62, 154, 190, 69, 57, 1, 205, 1, 0, 92, 35, 138, 61, +129, 77, 4, 59, 158, 106, 127, 191, 1, 205, 1, 0, 101, 233, 1, 62, 216, 132, 3, 59, +81, 238, 125, 191, 1, 205, 1, 0, 2, 72, 92, 63, 79, 21, 62, 189, 117, 227, 1, 191, +1, 205, 1, 0, 113, 28, 119, 63, 203, 235, 194, 188, 24, 49, 133, 190, 1, 205, 1, 0, +62, 172, 48, 61, 248, 111, 214, 189, 112, 90, 126, 191, 1, 205, 1, 0, 241, 184, 210, 62, +120, 157, 195, 189, 60, 7, 104, 191, 1, 205, 1, 0, 99, 226, 68, 190, 43, 5, 82, 190, +244, 172, 117, 191, 1, 205, 1, 0, 228, 103, 163, 62, 25, 210, 74, 190, 27, 65, 109, 191, +1, 205, 1, 0, 80, 207, 81, 62, 205, 202, 144, 190, 226, 225, 111, 191, 1, 205, 1, 0, +188, 153, 81, 63, 27, 222, 41, 190, 143, 182, 12, 191, 1, 205, 1, 0, 92, 81, 35, 62, +75, 239, 210, 190, 2, 170, 101, 191, 1, 205, 1, 0, 95, 35, 95, 63, 203, 118, 81, 190, +20, 16, 228, 190, 1, 205, 1, 0, 118, 201, 87, 61, 45, 175, 6, 191, 213, 73, 89, 191, +1, 205, 1, 0, 236, 156, 99, 63, 203, 234, 118, 190, 56, 45, 199, 190, 1, 205, 1, 0, +234, 13, 223, 190, 154, 83, 31, 191, 175, 120, 38, 191, 1, 205, 1, 0, 95, 107, 82, 63, +179, 161, 201, 190, 114, 172, 210, 190, 1, 205, 1, 0, 222, 121, 102, 191, 123, 220, 222, 190, +253, 233, 200, 185, 1, 205, 1, 0, 229, 103, 11, 191, 182, 182, 86, 191, 147, 145, 65, 186, +1, 205, 1, 0, 116, 170, 46, 191, 162, 210, 19, 191, 106, 147, 229, 62, 1, 205, 1, 0, +82, 111, 199, 62, 205, 199, 107, 191, 60, 128, 139, 56, 1, 205, 1, 0, 196, 33, 197, 62, +161, 67, 108, 191, 80, 196, 139, 56, 1, 205, 1, 0, 82, 247, 225, 62, 17, 184, 101, 191, +11, 128, 135, 56, 1, 205, 1, 0, 145, 156, 9, 63, 62, 222, 87, 191, 75, 54, 128, 56, +1, 205, 1, 0, 61, 65, 96, 63, 141, 242, 246, 190, 58, 141, 16, 56, 1, 205, 1, 0, +132, 133, 186, 62, 122, 104, 110, 191, 29, 186, 141, 56, 1, 205, 1, 0, 13, 14, 195, 62, +219, 177, 108, 191, 48, 165, 140, 56, 1, 205, 1, 0, 93, 143, 246, 62, 133, 92, 96, 191, +46, 123, 133, 56, 1, 205, 1, 0, 129, 209, 235, 62, 219, 58, 99, 191, 3, 218, 134, 56, +1, 205, 1, 0, 205, 51, 87, 63, 132, 166, 10, 191, 192, 221, 36, 56, 1, 205, 1, 0, +239, 164, 59, 63, 126, 36, 46, 191, 247, 193, 78, 56, 1, 205, 1, 0, 22, 28, 67, 63, +62, 188, 37, 191, 199, 97, 70, 56, 1, 205, 1, 0, 190, 95, 109, 63, 135, 185, 191, 190, +175, 170, 219, 55, 1, 205, 1, 0, 216, 114, 90, 63, 53, 122, 5, 191, 167, 86, 28, 56, +1, 205, 1, 0, 153, 53, 47, 63, 7, 166, 58, 191, 131, 184, 93, 56, 1, 205, 1, 0, +126, 88, 94, 63, 77, 194, 253, 190, 3, 46, 21, 56, 1, 205, 1, 0, 231, 202, 104, 63, +72, 3, 213, 190, 176, 16, 1, 56, 1, 205, 1, 0, 109, 14, 98, 63, 157, 73, 240, 190, +88, 123, 14, 56, 1, 205, 1, 0, 182, 158, 107, 63, 56, 49, 200, 190, 211, 144, 231, 55, +1, 205, 1, 0, 118, 220, 106, 63, 64, 186, 203, 190, 27, 62, 246, 55, 1, 205, 1, 0, +63, 20, 99, 63, 17, 102, 236, 190, 35, 195, 9, 56, 1, 205, 1, 0, 118, 196, 107, 63, +33, 127, 199, 190, 75, 251, 239, 55, 1, 205, 1, 0, 82, 19, 124, 63, 124, 157, 50, 190, +252, 63, 107, 55, 1, 205, 1, 0, 92, 53, 125, 63, 120, 207, 22, 190, 208, 80, 45, 55, +1, 205, 1, 0, 5, 43, 126, 63, 30, 146, 244, 189, 222, 212, 17, 55, 1, 205, 1, 0, +82, 241, 126, 63, 251, 241, 185, 189, 197, 46, 192, 54, 1, 205, 1, 0, 140, 132, 127, 63, +140, 75, 123, 189, 255, 74, 95, 54, 1, 205, 1, 0, 93, 224, 127, 63, 162, 134, 254, 188, +28, 240, 141, 54, 1, 205, 1, 0, 92, 227, 115, 63, 82, 159, 155, 190, 172, 176, 181, 55, +1, 205, 1, 0, 243, 80, 24, 63, 176, 193, 77, 191, 116, 15, 113, 56, 1, 205, 1, 0, +29, 23, 76, 63, 176, 138, 26, 191, 188, 77, 55, 56, 1, 205, 1, 0, 170, 228, 72, 63, +236, 172, 30, 191, 243, 114, 58, 56, 1, 205, 1, 0, 28, 215, 0, 63, 26, 55, 93, 191, +141, 42, 130, 56, 1, 205, 1, 0, 166, 229, 21, 63, 141, 134, 79, 191, 75, 197, 115, 56, +1, 205, 1, 0, 159, 112, 219, 62, 154, 75, 103, 191, 179, 182, 135, 56, 1, 205, 1, 0, +172, 25, 37, 63, 187, 165, 67, 191, 106, 53, 102, 56, 1, 205, 1, 0, 167, 26, 69, 63, +195, 91, 35, 191, 235, 81, 65, 56, 1, 205, 1, 0, 161, 245, 84, 63, 67, 18, 14, 191, +47, 44, 40, 56, 1, 205, 1, 0, 230, 121, 76, 63, 229, 7, 26, 191, 116, 194, 48, 56, +1, 205, 1, 0, 180, 68, 12, 63, 187, 38, 86, 191, 225, 72, 125, 56, 1, 205, 1, 0, +24, 82, 91, 63, 32, 10, 4, 191, 234, 5, 29, 56, 1, 205, 1, 0, 54, 21, 56, 63, +47, 231, 49, 191, 82, 64, 83, 56, 1, 205, 1, 0, 247, 96, 93, 63, 34, 143, 0, 191, +33, 207, 25, 56, 1, 205, 1, 0, 47, 196, 98, 63, 186, 152, 237, 190, 249, 99, 13, 56, +1, 205, 1, 0, 253, 117, 24, 190, 140, 37, 125, 63, 219, 248, 148, 184, 1, 205, 1, 0, +33, 175, 166, 189, 149, 38, 127, 63, 165, 83, 149, 184, 1, 205, 1, 0, 236, 34, 30, 190, +209, 237, 124, 63, 102, 14, 149, 184, 1, 205, 1, 0, 66, 201, 130, 61, 60, 122, 127, 63, +153, 2, 153, 184, 1, 205, 1, 0, 143, 168, 55, 190, 78, 217, 123, 63, 102, 159, 145, 184, +1, 205, 1, 0, 223, 181, 196, 188, 26, 237, 127, 63, 253, 183, 145, 184, 1, 205, 1, 0, +150, 54, 35, 190, 49, 186, 124, 63, 113, 222, 146, 184, 1, 205, 1, 0, 70, 72, 95, 189, +142, 158, 127, 63, 194, 84, 151, 184, 1, 205, 1, 0, 18, 115, 230, 62, 84, 154, 100, 63, +177, 54, 132, 184, 1, 205, 1, 0, 70, 80, 4, 63, 206, 39, 91, 63, 19, 102, 121, 184, +1, 205, 1, 0, 231, 155, 98, 63, 58, 50, 238, 62, 229, 86, 23, 184, 1, 205, 1, 0, +30, 120, 58, 63, 116, 102, 47, 63, 230, 180, 81, 184, 1, 205, 1, 0, 83, 41, 71, 63, +2, 216, 32, 63, 6, 213, 53, 184, 1, 205, 1, 0, 180, 140, 89, 63, 8, 240, 6, 63, +124, 42, 28, 184, 1, 205, 1, 0, 113, 96, 75, 63, 198, 122, 27, 63, 92, 192, 54, 184, +1, 205, 1, 0, 124, 160, 173, 61, 15, 20, 127, 63, 170, 14, 148, 184, 1, 205, 1, 0, +26, 52, 95, 63, 127, 186, 250, 62, 98, 78, 30, 184, 1, 205, 1, 0, 164, 180, 93, 63, +58, 253, 255, 62, 35, 135, 25, 184, 1, 205, 1, 0, 138, 149, 77, 63, 132, 140, 24, 63, +116, 161, 49, 184, 1, 205, 1, 0, 56, 126, 95, 63, 216, 177, 249, 62, 93, 99, 8, 184, +1, 205, 1, 0, 210, 227, 125, 63, 47, 52, 3, 62, 2, 130, 62, 183, 1, 205, 1, 0, +213, 210, 126, 63, 85, 29, 196, 61, 51, 123, 115, 182, 1, 205, 1, 0, 51, 223, 127, 63, +159, 146, 1, 61, 129, 100, 108, 182, 1, 205, 1, 0, 186, 118, 110, 63, 158, 60, 186, 62, +247, 176, 216, 183, 1, 205, 1, 0, 35, 106, 50, 63, 77, 150, 55, 63, 131, 243, 89, 184, +1, 205, 1, 0, 20, 247, 9, 63, 113, 164, 87, 63, 41, 169, 112, 184, 1, 205, 1, 0, +76, 117, 40, 62, 25, 131, 124, 63, 73, 125, 147, 184, 1, 205, 1, 0, 91, 212, 44, 63, +181, 218, 60, 63, 9, 232, 91, 184, 1, 205, 1, 0, 231, 48, 22, 63, 30, 80, 79, 63, +206, 149, 115, 184, 1, 205, 1, 0, 2, 57, 25, 63, 26, 21, 77, 63, 100, 23, 109, 184, +1, 205, 1, 0, 105, 193, 17, 63, 126, 116, 82, 63, 106, 86, 118, 184, 1, 205, 1, 0, +197, 185, 22, 62, 42, 54, 125, 63, 63, 243, 145, 184, 1, 205, 1, 0, 139, 1, 202, 189, +107, 192, 126, 63, 255, 159, 152, 184, 1, 205, 1, 0, 112, 162, 133, 62, 91, 32, 119, 63, +206, 82, 151, 184, 1, 205, 1, 0, 45, 110, 176, 62, 32, 82, 112, 63, 155, 42, 143, 184, +1, 205, 1, 0, 102, 239, 8, 63, 64, 76, 88, 63, 10, 72, 130, 184, 1, 205, 1, 0, +199, 225, 45, 63, 196, 226, 59, 63, 102, 165, 102, 184, 1, 205, 1, 0, 198, 31, 26, 63, +231, 103, 76, 63, 19, 210, 121, 184, 1, 205, 1, 0, 154, 95, 166, 61, 100, 39, 127, 63, +203, 203, 150, 184, 1, 205, 1, 0, 171, 113, 60, 63, 221, 70, 45, 63, 154, 27, 82, 184, +1, 205, 1, 0, 44, 21, 245, 62, 4, 196, 96, 63, 238, 54, 131, 184, 1, 205, 1, 0, +55, 114, 214, 62, 159, 118, 104, 63, 30, 9, 137, 184, 1, 205, 1, 0, 191, 106, 142, 62, +165, 229, 117, 63, 112, 41, 143, 184, 1, 205, 1, 0, 50, 18, 65, 63, 22, 27, 40, 63, +187, 28, 72, 184, 1, 205, 1, 0, 54, 233, 76, 63, 175, 115, 25, 63, 199, 30, 53, 184, +1, 205, 1, 0, 91, 231, 224, 61, 65, 230, 87, 189, 250, 23, 126, 63, 1, 205, 0, 0, +154, 168, 31, 63, 113, 151, 195, 189, 25, 157, 70, 63, 1, 205, 0, 0, 102, 184, 32, 63, +114, 136, 219, 189, 201, 92, 69, 63, 1, 205, 0, 0, 21, 251, 33, 63, 94, 219, 240, 189, +46, 240, 67, 63, 1, 205, 0, 0, 81, 106, 35, 63, 188, 154, 1, 190, 250, 95, 66, 63, +1, 205, 0, 0, 64, 255, 36, 63, 42, 42, 9, 190, 15, 181, 64, 63, 1, 205, 0, 0, +207, 178, 38, 63, 205, 4, 15, 190, 28, 248, 62, 63, 1, 205, 0, 0, 230, 124, 40, 63, +159, 27, 19, 190, 73, 50, 61, 63, 1, 205, 0, 0, 5, 86, 42, 63, 240, 105, 21, 190, +151, 107, 59, 63, 1, 205, 0, 0, 86, 54, 44, 63, 144, 242, 21, 190, 191, 171, 57, 63, +1, 205, 0, 0, 224, 21, 46, 63, 215, 191, 20, 190, 253, 249, 55, 63, 1, 205, 0, 0, +148, 237, 47, 63, 42, 226, 17, 190, 47, 92, 54, 63, 1, 205, 0, 0, 85, 182, 49, 63, +121, 111, 13, 190, 193, 215, 52, 63, 1, 205, 0, 0, 22, 105, 51, 63, 47, 131, 7, 190, +171, 113, 51, 63, 1, 205, 0, 0, 10, 0, 53, 63, 54, 58, 0, 190, 129, 45, 50, 63, +1, 205, 0, 0, 120, 117, 54, 63, 32, 109, 239, 189, 129, 14, 49, 63, 1, 205, 0, 0, +80, 196, 55, 63, 152, 56, 220, 189, 64, 23, 48, 63, 1, 205, 0, 0, 31, 232, 56, 63, +107, 32, 199, 189, 200, 73, 47, 63, 1, 205, 0, 0, 31, 221, 57, 63, 28, 118, 176, 189, +128, 167, 46, 63, 1, 205, 0, 0, 63, 160, 58, 63, 120, 134, 152, 189, 115, 49, 46, 63, +1, 205, 0, 0, 246, 46, 59, 63, 5, 77, 127, 189, 70, 232, 45, 63, 1, 205, 0, 0, +119, 135, 59, 63, 99, 80, 76, 189, 75, 204, 45, 63, 1, 205, 0, 0, 181, 168, 59, 63, +96, 191, 24, 189, 97, 221, 45, 63, 1, 205, 0, 0, 79, 146, 59, 63, 213, 147, 202, 188, +25, 27, 46, 63, 1, 205, 0, 0, 115, 68, 59, 63, 238, 44, 74, 188, 235, 132, 46, 63, +1, 205, 0, 0, 39, 192, 58, 63, 113, 88, 155, 185, 192, 25, 47, 63, 1, 205, 0, 0, +15, 7, 58, 63, 41, 68, 56, 60, 80, 216, 47, 63, 1, 205, 0, 0, 119, 27, 57, 63, +41, 94, 181, 60, 255, 190, 48, 63, 1, 205, 0, 0, 114, 0, 56, 63, 211, 250, 3, 61, +180, 203, 49, 63, 1, 205, 0, 0, 167, 185, 54, 63, 237, 93, 41, 61, 7, 252, 50, 63, +1, 205, 0, 0, 86, 75, 53, 63, 13, 68, 74, 61, 36, 77, 52, 63, 1, 205, 0, 0, +135, 186, 51, 63, 185, 32, 102, 61, 142, 187, 53, 63, 1, 205, 0, 0, 119, 12, 50, 63, +198, 117, 124, 61, 150, 67, 55, 63, 1, 205, 0, 0, 183, 71, 48, 63, 198, 100, 134, 61, +59, 224, 56, 63, 1, 205, 0, 0, 123, 114, 46, 63, 228, 92, 139, 61, 172, 140, 58, 63, +1, 205, 0, 0, 156, 147, 44, 63, 54, 250, 140, 61, 53, 67, 60, 63, 1, 205, 0, 0, +241, 178, 42, 63, 71, 30, 139, 61, 239, 252, 61, 63, 1, 205, 0, 0, 236, 215, 40, 63, +0, 184, 133, 61, 241, 178, 63, 63, 1, 205, 0, 0, 18, 10, 39, 63, 116, 135, 121, 61, +217, 93, 65, 63, 1, 205, 0, 0, 202, 81, 37, 63, 237, 164, 96, 61, 16, 245, 66, 63, +1, 205, 0, 0, 65, 182, 35, 63, 65, 3, 65, 61, 198, 112, 68, 63, 1, 205, 0, 0, +30, 63, 34, 63, 145, 9, 27, 61, 124, 200, 69, 63, 1, 205, 0, 0, 82, 243, 32, 63, +179, 139, 222, 60, 38, 244, 70, 63, 1, 205, 0, 0, 242, 216, 31, 63, 29, 161, 121, 60, +135, 236, 71, 63, 1, 205, 0, 0, 1, 246, 30, 63, 67, 7, 21, 59, 165, 170, 72, 63, +1, 205, 0, 0, 129, 78, 30, 63, 217, 62, 60, 188, 154, 41, 73, 63, 1, 205, 0, 0, +249, 229, 29, 63, 98, 68, 211, 188, 125, 101, 73, 63, 1, 205, 0, 0, 184, 190, 29, 63, +223, 67, 37, 189, 37, 92, 73, 63, 1, 205, 0, 0, 72, 217, 29, 63, 201, 206, 96, 189, +152, 13, 73, 63, 1, 205, 0, 0, 45, 53, 30, 63, 56, 132, 141, 189, 160, 123, 72, 63, +1, 205, 0, 0, 170, 208, 30, 63, 79, 107, 169, 189, 182, 169, 71, 63, 1, 205, 0, 0, +168, 174, 111, 62, 199, 3, 46, 190, 154, 14, 117, 63, 1, 205, 0, 0, 114, 213, 126, 62, +251, 229, 72, 190, 82, 206, 114, 63, 1, 205, 0, 0, 218, 94, 136, 62, 154, 183, 96, 190, +164, 69, 112, 63, 1, 205, 0, 0, 41, 127, 146, 62, 254, 24, 117, 190, 82, 133, 109, 63, +1, 205, 0, 0, 172, 145, 157, 62, 37, 225, 130, 190, 198, 158, 106, 63, 1, 205, 0, 0, +63, 93, 169, 62, 43, 68, 137, 190, 95, 162, 103, 63, 1, 205, 0, 0, 198, 166, 181, 62, +148, 170, 141, 190, 251, 159, 100, 63, 1, 205, 0, 0, 156, 52, 194, 62, 82, 20, 144, 190, +17, 166, 97, 63, 1, 205, 0, 0, 174, 208, 206, 62, 137, 138, 144, 190, 78, 193, 94, 63, +1, 205, 0, 0, 17, 72, 219, 62, 212, 29, 143, 190, 178, 252, 91, 63, 1, 205, 0, 0, +28, 107, 231, 62, 86, 229, 139, 190, 164, 97, 89, 63, 1, 205, 0, 0, 81, 15, 243, 62, +186, 252, 134, 190, 184, 247, 86, 63, 1, 205, 0, 0, 136, 13, 254, 62, 32, 132, 128, 190, +50, 197, 84, 63, 1, 205, 0, 0, 143, 33, 4, 63, 11, 61, 113, 190, 235, 206, 82, 63, +1, 205, 0, 0, 8, 201, 8, 63, 6, 225, 94, 190, 141, 24, 81, 63, 1, 205, 0, 0, +245, 239, 12, 63, 99, 66, 74, 190, 196, 164, 79, 63, 1, 205, 0, 0, 50, 139, 16, 63, +241, 175, 51, 190, 101, 117, 78, 63, 1, 205, 0, 0, 56, 145, 19, 63, 160, 123, 27, 190, +169, 139, 77, 63, 1, 205, 0, 0, 148, 250, 21, 63, 69, 247, 1, 190, 14, 232, 76, 63, +1, 205, 0, 0, 77, 193, 23, 63, 149, 235, 206, 189, 188, 138, 76, 63, 1, 205, 0, 0, +28, 225, 24, 63, 193, 150, 152, 189, 99, 115, 76, 63, 1, 205, 0, 0, 83, 87, 25, 63, +132, 45, 67, 189, 114, 161, 76, 63, 1, 205, 0, 0, 228, 34, 25, 63, 201, 80, 170, 188, +242, 19, 77, 63, 1, 205, 0, 0, 66, 68, 24, 63, 136, 170, 188, 59, 186, 201, 77, 63, +1, 205, 0, 0, 127, 189, 22, 63, 21, 189, 1, 61, 73, 193, 78, 63, 1, 205, 0, 0, +81, 146, 20, 63, 218, 252, 103, 61, 200, 248, 79, 63, 1, 205, 0, 0, 220, 199, 17, 63, +79, 136, 164, 61, 32, 110, 81, 63, 1, 205, 0, 0, 26, 101, 14, 63, 236, 213, 209, 61, +191, 30, 83, 63, 1, 205, 0, 0, 216, 114, 10, 63, 34, 69, 251, 61, 127, 7, 85, 63, +1, 205, 0, 0, 121, 251, 5, 63, 131, 28, 16, 62, 190, 36, 87, 63, 1, 205, 0, 0, +128, 11, 1, 63, 70, 11, 32, 62, 10, 114, 89, 63, 1, 205, 0, 0, 31, 98, 247, 62, +219, 37, 45, 62, 64, 234, 91, 63, 1, 205, 0, 0, 202, 249, 235, 62, 80, 38, 55, 62, +250, 134, 94, 63, 1, 205, 0, 0, 5, 3, 224, 62, 124, 205, 61, 62, 226, 64, 97, 63, +1, 205, 0, 0, 162, 166, 211, 62, 181, 227, 64, 62, 122, 15, 100, 63, 1, 205, 0, 0, +167, 18, 199, 62, 139, 58, 64, 62, 185, 232, 102, 63, 1, 205, 0, 0, 32, 121, 186, 62, +118, 176, 59, 62, 50, 193, 105, 63, 1, 205, 0, 0, 160, 14, 174, 62, 196, 49, 51, 62, +96, 140, 108, 63, 1, 205, 0, 0, 178, 11, 162, 62, 31, 189, 38, 62, 82, 60, 111, 63, +1, 205, 0, 0, 213, 170, 150, 62, 160, 102, 22, 62, 30, 194, 113, 63, 1, 205, 0, 0, +20, 38, 140, 62, 122, 87, 2, 62, 145, 14, 116, 63, 1, 205, 0, 0, 217, 183, 130, 62, +187, 166, 213, 61, 48, 18, 118, 63, 1, 205, 0, 0, 60, 44, 117, 62, 141, 108, 160, 61, +110, 190, 119, 63, 1, 205, 0, 0, 185, 230, 103, 62, 189, 225, 75, 61, 233, 5, 121, 63, +1, 205, 0, 0, 209, 242, 93, 62, 72, 59, 157, 60, 181, 221, 121, 63, 1, 205, 0, 0, +63, 145, 87, 62, 158, 186, 81, 188, 227, 61, 122, 63, 1, 205, 0, 0, 224, 237, 84, 62, +139, 128, 58, 189, 3, 34, 122, 63, 1, 205, 0, 0, 249, 25, 86, 62, 107, 93, 160, 189, +186, 137, 121, 63, 1, 205, 0, 0, 191, 13, 91, 62, 251, 27, 226, 189, 186, 120, 120, 63, +1, 205, 0, 0, 117, 167, 99, 62, 239, 138, 16, 190, 181, 246, 118, 63, 1, 205, 0, 0, +249, 76, 170, 188, 18, 109, 110, 190, 55, 232, 120, 63, 1, 205, 0, 0, 145, 251, 151, 59, +125, 240, 139, 190, 225, 63, 118, 63, 1, 205, 0, 0, 157, 0, 14, 61, 126, 75, 158, 190, +196, 75, 115, 63, 1, 205, 0, 0, 147, 114, 140, 61, 187, 253, 173, 190, 195, 31, 112, 63, +1, 205, 0, 0, 157, 59, 216, 61, 135, 209, 186, 190, 254, 207, 108, 63, 1, 205, 0, 0, +233, 94, 20, 62, 66, 166, 196, 190, 160, 111, 105, 63, 1, 205, 0, 0, 194, 47, 62, 62, +189, 109, 203, 190, 109, 16, 102, 63, 1, 205, 0, 0, 101, 202, 104, 62, 234, 41, 207, 190, +106, 194, 98, 63, 1, 205, 0, 0, 138, 186, 137, 62, 15, 235, 207, 190, 114, 147, 95, 63, +1, 205, 0, 0, 21, 194, 158, 62, 238, 204, 205, 190, 60, 143, 92, 63, 1, 205, 0, 0, +99, 45, 179, 62, 116, 244, 200, 190, 119, 191, 89, 63, 1, 205, 0, 0, 0, 182, 198, 62, +183, 141, 193, 190, 228, 43, 87, 63, 1, 205, 0, 0, 184, 29, 217, 62, 2, 202, 183, 190, +116, 218, 84, 63, 1, 205, 0, 0, 35, 45, 234, 62, 49, 223, 171, 190, 174, 207, 82, 63, +1, 205, 0, 0, 140, 180, 249, 62, 187, 5, 158, 190, 186, 14, 81, 63, 1, 205, 0, 0, +120, 197, 3, 63, 21, 120, 142, 190, 184, 153, 79, 63, 1, 205, 0, 0, 216, 198, 9, 63, +12, 228, 122, 190, 218, 113, 78, 63, 1, 205, 0, 0, 246, 207, 14, 63, 254, 96, 86, 190, +168, 151, 77, 63, 1, 205, 0, 0, 72, 213, 18, 63, 114, 225, 47, 190, 7, 11, 77, 63, +1, 205, 0, 0, 196, 205, 21, 63, 228, 224, 7, 190, 118, 203, 76, 63, 1, 205, 0, 0, +244, 178, 23, 63, 129, 181, 189, 189, 17, 216, 76, 63, 1, 205, 0, 0, 197, 128, 24, 63, +49, 47, 85, 189, 159, 47, 77, 63, 1, 205, 0, 0, 138, 53, 24, 63, 29, 249, 58, 188, +169, 208, 77, 63, 1, 205, 0, 0, 225, 209, 22, 63, 67, 239, 235, 60, 121, 185, 78, 63, +1, 205, 0, 0, 176, 88, 20, 63, 76, 130, 139, 61, 34, 232, 79, 63, 1, 205, 0, 0, +108, 207, 16, 63, 19, 60, 217, 61, 88, 90, 81, 63, 1, 205, 0, 0, 205, 61, 12, 63, +221, 153, 17, 62, 145, 13, 83, 63, 1, 205, 0, 0, 67, 174, 6, 63, 181, 57, 52, 62, +209, 254, 84, 63, 1, 205, 0, 0, 198, 45, 0, 63, 92, 4, 84, 62, 178, 42, 87, 63, +1, 205, 0, 0, 130, 152, 241, 62, 81, 130, 112, 62, 37, 141, 89, 63, 1, 205, 0, 0, +234, 57, 225, 62, 3, 159, 132, 62, 69, 33, 92, 63, 1, 205, 0, 0, 245, 107, 207, 62, +71, 227, 142, 62, 120, 225, 94, 63, 1, 205, 0, 0, 66, 98, 188, 62, 13, 216, 150, 62, +255, 198, 97, 63, 1, 205, 0, 0, 36, 88, 168, 62, 45, 75, 156, 62, 211, 201, 100, 63, +1, 205, 0, 0, 26, 144, 147, 62, 135, 15, 159, 62, 172, 224, 103, 63, 1, 205, 0, 0, +3, 169, 124, 62, 160, 254, 158, 62, 188, 0, 107, 63, 1, 205, 0, 0, 101, 240, 81, 62, +208, 250, 155, 62, 137, 29, 110, 63, 1, 205, 0, 0, 112, 170, 39, 62, 33, 241, 149, 62, +20, 41, 113, 63, 1, 205, 0, 0, 85, 44, 253, 61, 147, 219, 140, 62, 18, 20, 116, 63, +1, 205, 0, 0, 25, 253, 174, 61, 39, 196, 128, 62, 231, 205, 118, 63, 1, 205, 0, 0, +126, 201, 76, 61, 39, 141, 99, 62, 87, 69, 121, 63, 1, 205, 0, 0, 42, 5, 148, 60, +98, 37, 64, 62, 4, 105, 123, 63, 1, 205, 0, 0, 186, 12, 29, 188, 216, 216, 23, 62, +104, 40, 125, 63, 1, 205, 0, 0, 93, 46, 4, 189, 74, 182, 214, 61, 133, 116, 126, 63, +1, 205, 0, 0, 1, 77, 74, 189, 189, 22, 110, 61, 18, 65, 127, 63, 1, 205, 0, 0, +118, 183, 119, 189, 31, 50, 21, 60, 81, 133, 127, 63, 1, 205, 0, 0, 155, 146, 133, 189, +176, 159, 40, 189, 202, 60, 127, 63, 1, 205, 0, 0, 62, 4, 130, 189, 104, 147, 187, 189, +200, 103, 126, 63, 1, 205, 0, 0, 47, 149, 98, 189, 46, 110, 16, 190, 124, 11, 125, 63, +1, 205, 0, 0, 123, 190, 39, 189, 17, 251, 64, 190, 178, 49, 123, 63, 1, 205, 0, 0, +223, 214, 86, 190, 113, 246, 147, 190, 136, 30, 111, 63, 1, 205, 0, 0, 97, 207, 50, 190, +76, 146, 175, 190, 93, 73, 108, 63, 1, 205, 0, 0, 72, 64, 8, 190, 17, 8, 200, 190, +229, 45, 105, 63, 1, 205, 0, 0, 19, 113, 176, 189, 102, 244, 220, 190, 1, 225, 101, 63, +1, 205, 0, 0, 225, 89, 15, 189, 201, 16, 238, 190, 87, 119, 98, 63, 1, 205, 0, 0, +91, 15, 158, 60, 188, 49, 251, 190, 145, 4, 95, 63, 1, 205, 0, 0, 193, 231, 154, 61, +171, 34, 2, 191, 148, 154, 91, 63, 1, 205, 0, 0, 154, 43, 8, 62, 166, 167, 4, 191, +79, 73, 88, 63, 1, 205, 0, 0, 107, 233, 66, 62, 6, 51, 5, 191, 91, 30, 85, 63, +1, 205, 0, 0, 136, 193, 124, 62, 148, 215, 3, 191, 13, 37, 82, 63, 1, 205, 0, 0, +216, 110, 154, 62, 46, 174, 0, 191, 135, 102, 79, 63, 1, 205, 0, 0, 30, 63, 181, 62, +183, 168, 247, 190, 239, 233, 76, 63, 1, 205, 0, 0, 94, 125, 206, 62, 7, 214, 234, 190, +154, 180, 74, 63, 1, 205, 0, 0, 103, 223, 229, 62, 108, 43, 219, 190, 91, 202, 72, 63, +1, 205, 0, 0, 101, 37, 251, 62, 129, 243, 200, 190, 177, 45, 71, 63, 1, 205, 0, 0, +67, 12, 7, 63, 168, 123, 180, 190, 2, 224, 69, 63, 1, 205, 0, 0, 102, 69, 15, 63, +149, 18, 158, 190, 226, 225, 68, 63, 1, 205, 0, 0, 25, 43, 22, 63, 6, 8, 134, 190, +40, 51, 68, 63, 1, 205, 0, 0, 253, 173, 27, 63, 24, 89, 89, 190, 36, 211, 67, 63, +1, 205, 0, 0, 69, 194, 31, 63, 23, 162, 36, 190, 174, 192, 67, 63, 1, 205, 0, 0, +91, 95, 34, 63, 156, 25, 221, 189, 88, 250, 67, 63, 1, 205, 0, 0, 228, 127, 35, 63, +39, 237, 94, 189, 98, 126, 68, 63, 1, 205, 0, 0, 151, 33, 35, 63, 165, 70, 80, 186, +198, 74, 69, 63, 1, 205, 0, 0, 55, 69, 33, 63, 34, 75, 86, 61, 81, 93, 70, 63, +1, 205, 0, 0, 143, 238, 29, 63, 200, 150, 213, 61, 152, 179, 71, 63, 1, 205, 0, 0, +132, 36, 25, 63, 32, 56, 30, 62, 237, 74, 73, 63, 1, 205, 0, 0, 65, 241, 18, 63, +40, 55, 79, 62, 84, 32, 75, 63, 1, 205, 0, 0, 63, 98, 11, 63, 214, 39, 125, 62, +122, 48, 77, 63, 1, 205, 0, 0, 201, 136, 2, 63, 2, 181, 147, 62, 123, 119, 79, 63, +1, 205, 0, 0, 72, 243, 240, 62, 47, 176, 166, 62, 16, 241, 81, 63, 1, 205, 0, 0, +244, 155, 218, 62, 225, 55, 183, 62, 27, 152, 84, 63, 1, 205, 0, 0, 245, 70, 194, 62, +213, 0, 197, 62, 158, 102, 87, 63, 1, 205, 0, 0, 209, 56, 168, 62, 50, 195, 207, 62, +174, 85, 90, 63, 1, 205, 0, 0, 202, 192, 140, 62, 95, 59, 215, 62, 35, 93, 93, 63, +1, 205, 0, 0, 223, 113, 96, 62, 92, 44, 219, 62, 123, 115, 96, 63, 1, 205, 0, 0, +119, 12, 38, 62, 109, 97, 219, 62, 204, 141, 99, 63, 1, 205, 0, 0, 162, 100, 214, 61, +221, 176, 215, 62, 153, 159, 102, 63, 1, 205, 0, 0, 200, 106, 67, 61, 10, 255, 207, 62, +214, 154, 105, 63, 1, 205, 0, 0, 29, 54, 254, 187, 98, 65, 196, 62, 44, 112, 108, 63, +1, 205, 0, 0, 213, 102, 120, 189, 12, 130, 180, 62, 24, 15, 111, 63, 1, 205, 0, 0, +46, 247, 224, 189, 214, 226, 160, 62, 127, 102, 113, 63, 1, 205, 0, 0, 240, 244, 29, 190, +102, 160, 137, 62, 60, 101, 115, 63, 1, 205, 0, 0, 34, 109, 69, 190, 234, 38, 94, 62, +3, 251, 116, 63, 1, 205, 0, 0, 11, 226, 101, 190, 24, 98, 35, 62, 90, 25, 118, 63, +1, 205, 0, 0, 243, 115, 126, 190, 202, 37, 200, 61, 134, 180, 118, 63, 1, 205, 0, 0, +122, 57, 135, 190, 169, 26, 6, 61, 140, 196, 118, 63, 1, 205, 0, 0, 96, 180, 138, 190, +126, 68, 11, 189, 241, 69, 118, 63, 1, 205, 0, 0, 197, 144, 137, 190, 125, 221, 206, 189, +30, 58, 117, 63, 1, 205, 0, 0, 7, 215, 131, 190, 84, 202, 42, 190, 137, 167, 115, 63, +1, 205, 0, 0, 167, 99, 115, 190, 12, 105, 107, 190, 75, 153, 113, 63, 1, 205, 0, 0, +36, 130, 185, 190, 46, 182, 173, 190, 91, 60, 94, 63, 1, 205, 0, 0, 74, 243, 162, 190, +96, 183, 207, 190, 197, 87, 91, 63, 1, 205, 0, 0, 27, 76, 136, 190, 94, 219, 237, 190, +93, 54, 88, 63, 1, 205, 0, 0, 226, 112, 84, 190, 125, 211, 3, 191, 222, 236, 84, 63, +1, 205, 0, 0, 156, 217, 18, 190, 183, 97, 14, 191, 132, 143, 81, 63, 1, 205, 0, 0, +181, 134, 154, 189, 175, 125, 22, 191, 75, 49, 78, 63, 1, 205, 0, 0, 134, 154, 162, 187, +107, 28, 28, 191, 116, 227, 74, 63, 1, 205, 0, 0, 213, 179, 136, 61, 104, 64, 31, 191, +7, 181, 71, 63, 1, 205, 0, 0, 150, 198, 13, 62, 173, 247, 31, 191, 182, 178, 68, 63, +1, 205, 0, 0, 129, 11, 86, 62, 108, 89, 30, 191, 244, 230, 65, 63, 1, 205, 0, 0, +0, 15, 142, 62, 79, 132, 26, 191, 251, 89, 63, 63, 1, 205, 0, 0, 26, 136, 175, 62, +172, 156, 20, 191, 10, 18, 61, 63, 1, 205, 0, 0, 86, 8, 207, 62, 12, 203, 12, 191, +159, 19, 59, 63, 1, 205, 0, 0, 99, 52, 236, 62, 3, 59, 3, 191, 188, 97, 57, 63, +1, 205, 0, 0, 164, 94, 3, 63, 188, 52, 240, 190, 28, 254, 55, 63, 1, 205, 0, 0, +223, 47, 15, 63, 160, 48, 215, 190, 122, 233, 54, 63, 1, 205, 0, 0, 146, 113, 25, 63, +47, 202, 187, 190, 183, 35, 54, 63, 1, 205, 0, 0, 116, 12, 34, 63, 225, 98, 158, 190, +3, 172, 53, 63, 1, 205, 0, 0, 172, 237, 40, 63, 93, 186, 126, 190, 23, 129, 53, 63, +1, 205, 0, 0, 191, 6, 46, 63, 6, 55, 62, 190, 75, 161, 53, 63, 1, 205, 0, 0, +57, 77, 49, 63, 204, 3, 248, 189, 142, 10, 54, 63, 1, 205, 0, 0, 130, 186, 50, 63, +135, 129, 99, 189, 166, 186, 54, 63, 1, 205, 0, 0, 187, 75, 50, 63, 175, 123, 38, 60, +30, 175, 55, 63, 1, 205, 0, 0, 204, 1, 48, 63, 85, 33, 154, 61, 63, 229, 56, 63, +1, 205, 0, 0, 66, 225, 43, 63, 146, 84, 14, 62, 47, 90, 58, 63, 1, 205, 0, 0, +124, 242, 37, 63, 49, 110, 77, 62, 216, 10, 60, 63, 1, 205, 0, 0, 216, 65, 30, 63, +4, 204, 132, 62, 206, 243, 61, 63, 1, 205, 0, 0, 173, 223, 20, 63, 237, 6, 161, 62, +116, 17, 64, 63, 1, 205, 0, 0, 242, 224, 9, 63, 253, 5, 187, 62, 152, 95, 66, 63, +1, 205, 0, 0, 139, 190, 250, 62, 148, 104, 210, 62, 147, 217, 68, 63, 1, 205, 0, 0, +153, 242, 222, 62, 191, 207, 230, 62, 32, 122, 71, 63, 1, 205, 0, 0, 166, 166, 192, 62, +253, 222, 247, 62, 36, 59, 74, 63, 1, 205, 0, 0, 106, 47, 160, 62, 201, 158, 2, 63, +141, 21, 77, 63, 1, 205, 0, 0, 238, 220, 123, 62, 6, 76, 7, 63, 67, 1, 80, 63, +1, 205, 0, 0, 171, 165, 52, 62, 71, 209, 9, 63, 239, 244, 82, 63, 1, 205, 0, 0, +28, 104, 215, 61, 167, 13, 10, 63, 215, 229, 85, 63, 1, 205, 0, 0, 10, 128, 8, 61, +204, 230, 7, 63, 237, 199, 88, 63, 1, 205, 0, 0, 142, 140, 27, 189, 218, 74, 3, 63, +187, 141, 91, 63, 1, 205, 0, 0, 163, 17, 220, 189, 237, 100, 248, 62, 141, 40, 94, 63, +1, 205, 0, 0, 205, 240, 49, 190, 129, 69, 229, 62, 208, 136, 96, 63, 1, 205, 0, 0, +35, 46, 113, 190, 78, 95, 205, 62, 103, 158, 98, 63, 1, 205, 0, 0, 67, 41, 149, 190, +161, 250, 176, 62, 99, 89, 100, 63, 1, 205, 0, 0, 56, 253, 173, 190, 17, 131, 144, 62, +206, 170, 101, 63, 1, 205, 0, 0, 26, 111, 194, 190, 251, 13, 89, 62, 150, 133, 102, 63, +1, 205, 0, 0, 135, 240, 209, 190, 65, 110, 11, 62, 117, 223, 102, 63, 1, 205, 0, 0, +24, 17, 220, 190, 122, 6, 103, 61, 233, 177, 102, 63, 1, 205, 0, 0, 12, 133, 224, 190, +82, 140, 209, 188, 232, 250, 101, 63, 1, 205, 0, 0, 160, 42, 223, 190, 164, 21, 221, 189, +35, 189, 100, 63, 1, 205, 0, 0, 90, 12, 216, 190, 87, 100, 65, 190, 38, 0, 99, 63, +1, 205, 0, 0, 144, 95, 203, 190, 67, 117, 136, 190, 252, 207, 96, 63, 1, 205, 0, 0, +167, 203, 250, 190, 223, 96, 196, 190, 222, 108, 72, 63, 1, 205, 0, 0, 122, 40, 224, 190, +225, 53, 236, 190, 112, 140, 69, 63, 1, 205, 0, 0, 173, 173, 192, 190, 227, 195, 7, 191, +242, 122, 66, 63, 1, 205, 0, 0, 51, 39, 157, 190, 22, 227, 22, 191, 57, 76, 63, 63, +1, 205, 0, 0, 48, 215, 108, 190, 127, 69, 35, 191, 118, 19, 60, 63, 1, 205, 0, 0, +197, 169, 26, 190, 231, 203, 44, 191, 120, 226, 56, 63, 1, 205, 0, 0, 149, 225, 138, 189, +101, 105, 51, 191, 41, 201, 53, 63, 1, 205, 0, 0, 92, 235, 137, 60, 250, 32, 55, 191, +67, 213, 50, 63, 1, 205, 0, 0, 185, 201, 207, 61, 254, 2, 56, 191, 60, 18, 48, 63, +1, 205, 0, 0, 200, 41, 61, 62, 187, 42, 54, 191, 66, 137, 45, 63, 1, 205, 0, 0, +73, 233, 135, 62, 11, 188, 49, 191, 108, 65, 43, 63, 1, 205, 0, 0, 231, 99, 175, 62, +92, 225, 42, 191, 242, 63, 41, 63, 1, 205, 0, 0, 141, 137, 212, 62, 28, 202, 33, 191, +82, 136, 39, 63, 1, 205, 0, 0, 9, 239, 246, 62, 47, 169, 22, 191, 179, 28, 38, 63, +1, 205, 0, 0, 2, 28, 11, 63, 252, 179, 9, 191, 5, 254, 36, 63, 1, 205, 0, 0, +204, 10, 25, 63, 101, 67, 246, 190, 57, 44, 36, 63, 1, 205, 0, 0, 217, 34, 37, 63, +236, 84, 214, 190, 147, 166, 35, 63, 1, 205, 0, 0, 230, 72, 47, 63, 32, 14, 180, 190, +171, 107, 35, 63, 1, 205, 0, 0, 245, 102, 55, 63, 217, 225, 143, 190, 162, 121, 35, 63, +1, 205, 0, 0, 29, 108, 61, 63, 203, 133, 84, 190, 69, 206, 35, 63, 1, 205, 0, 0, +44, 76, 65, 63, 90, 72, 7, 190, 18, 103, 36, 63, 1, 205, 0, 0, 111, 255, 66, 63, +45, 200, 99, 189, 67, 65, 37, 63, 1, 205, 0, 0, 137, 130, 66, 63, 67, 183, 172, 60, +241, 89, 38, 63, 1, 205, 0, 0, 103, 214, 63, 63, 208, 216, 198, 61, 15, 174, 39, 63, +1, 205, 0, 0, 87, 0, 59, 63, 57, 168, 47, 62, 79, 58, 41, 63, 1, 205, 0, 0, +17, 10, 52, 63, 47, 100, 121, 62, 51, 251, 42, 63, 1, 205, 0, 0, 219, 1, 43, 63, +77, 221, 159, 62, 7, 237, 44, 63, 1, 205, 0, 0, 211, 250, 31, 63, 34, 227, 192, 62, +199, 11, 47, 63, 1, 205, 0, 0, 55, 13, 19, 63, 182, 81, 223, 62, 15, 83, 49, 63, +1, 205, 0, 0, 229, 86, 4, 63, 28, 184, 250, 62, 0, 190, 51, 63, 1, 205, 0, 0, +80, 247, 231, 62, 180, 83, 9, 63, 39, 71, 54, 63, 1, 205, 0, 0, 149, 75, 196, 62, +183, 89, 19, 63, 102, 232, 56, 63, 1, 205, 0, 0, 170, 13, 158, 62, 19, 58, 27, 63, +186, 154, 59, 63, 1, 205, 0, 0, 160, 95, 107, 62, 220, 195, 32, 63, 49, 86, 62, 63, +1, 205, 0, 0, 87, 104, 23, 62, 110, 202, 35, 63, 201, 17, 65, 63, 1, 205, 0, 0, +225, 184, 130, 61, 231, 38, 36, 63, 79, 195, 67, 63, 1, 205, 0, 0, 180, 214, 171, 188, +0, 186, 33, 63, 99, 95, 70, 63, 1, 205, 0, 0, 226, 102, 215, 189, 49, 110, 28, 63, +125, 217, 72, 63, 1, 205, 0, 0, 145, 196, 63, 190, 55, 58, 20, 63, 15, 36, 75, 63, +1, 205, 0, 0, 197, 6, 136, 190, 88, 35, 9, 63, 231, 48, 77, 63, 1, 205, 0, 0, +81, 111, 173, 190, 10, 128, 246, 62, 121, 241, 78, 63, 1, 205, 0, 0, 93, 66, 207, 190, +196, 115, 213, 62, 150, 87, 80, 63, 1, 205, 0, 0, 170, 172, 236, 190, 124, 158, 175, 62, +40, 86, 81, 63, 1, 205, 0, 0, 143, 117, 2, 191, 160, 165, 133, 62, 35, 226, 81, 63, +1, 205, 0, 0, 0, 170, 11, 191, 207, 173, 48, 62, 50, 243, 81, 63, 1, 205, 0, 0, +110, 176, 17, 191, 79, 138, 162, 61, 166, 132, 81, 63, 1, 205, 0, 0, 159, 91, 20, 191, +210, 213, 134, 188, 14, 150, 80, 63, 1, 205, 0, 0, 30, 151, 19, 191, 193, 254, 230, 189, +127, 43, 79, 63, 1, 205, 0, 0, 220, 104, 15, 191, 254, 110, 84, 190, 123, 77, 77, 63, +1, 205, 0, 0, 162, 240, 7, 191, 176, 193, 152, 190, 161, 8, 75, 63, 1, 205, 0, 0, +86, 217, 24, 191, 5, 191, 215, 190, 73, 191, 46, 63, 1, 205, 0, 0, 233, 188, 9, 191, +158, 96, 2, 191, 153, 242, 43, 63, 1, 205, 0, 0, 173, 192, 239, 190, 240, 86, 22, 191, +6, 2, 41, 63, 1, 205, 0, 0, 18, 111, 199, 190, 231, 112, 39, 191, 7, 0, 38, 63, +1, 205, 0, 0, 198, 121, 155, 190, 143, 116, 53, 191, 70, 254, 34, 63, 1, 205, 0, 0, +183, 176, 89, 190, 164, 62, 64, 191, 238, 12, 32, 63, 1, 205, 0, 0, 226, 246, 241, 189, +116, 192, 71, 191, 51, 58, 29, 63, 1, 205, 0, 0, 124, 8, 181, 188, 84, 253, 75, 191, +57, 146, 26, 63, 1, 205, 0, 0, 177, 93, 151, 61, 179, 7, 77, 191, 224, 30, 24, 63, +1, 205, 0, 0, 6, 106, 44, 62, 72, 254, 74, 191, 239, 231, 21, 63, 1, 205, 0, 0, +91, 22, 133, 62, 142, 9, 70, 191, 43, 243, 19, 63, 1, 205, 0, 0, 40, 221, 177, 62, +102, 89, 62, 191, 147, 68, 18, 63, 1, 205, 0, 0, 70, 254, 219, 62, 50, 35, 52, 191, +165, 222, 16, 63, 1, 205, 0, 0, 34, 128, 1, 63, 105, 160, 39, 191, 144, 194, 15, 63, +1, 205, 0, 0, 112, 61, 19, 63, 39, 13, 25, 191, 123, 240, 14, 63, 1, 205, 0, 0, +141, 10, 35, 63, 135, 167, 8, 191, 164, 103, 14, 63, 1, 205, 0, 0, 35, 194, 48, 63, +194, 93, 237, 190, 144, 38, 14, 63, 1, 205, 0, 0, 116, 69, 60, 63, 76, 198, 198, 190, +80, 43, 14, 63, 1, 205, 0, 0, 180, 123, 69, 63, 179, 9, 158, 190, 139, 115, 14, 63, +1, 205, 0, 0, 213, 81, 76, 63, 217, 82, 103, 190, 122, 252, 14, 63, 1, 205, 0, 0, +23, 186, 80, 63, 171, 77, 16, 190, 40, 195, 15, 63, 1, 205, 0, 0, 185, 171, 82, 63, +80, 27, 96, 189, 123, 196, 16, 63, 1, 205, 0, 0, 243, 34, 82, 63, 141, 247, 1, 61, +17, 253, 17, 63, 1, 205, 0, 0, 211, 32, 79, 63, 56, 123, 240, 61, 117, 105, 19, 63, +1, 205, 0, 0, 55, 171, 73, 63, 154, 53, 78, 62, 13, 6, 21, 63, 1, 205, 0, 0, +8, 205, 65, 63, 60, 177, 144, 62, 1, 207, 22, 63, 1, 205, 0, 0, 73, 150, 55, 63, +201, 96, 184, 62, 89, 192, 24, 63, 1, 205, 0, 0, 117, 28, 43, 63, 115, 168, 221, 62, +201, 213, 26, 63, 1, 205, 0, 0, 202, 122, 28, 63, 241, 3, 0, 63, 190, 10, 29, 63, +1, 205, 0, 0, 228, 210, 11, 63, 238, 127, 15, 63, 45, 90, 31, 63, 1, 205, 0, 0, +31, 154, 242, 62, 155, 9, 29, 63, 150, 190, 33, 63, 1, 205, 0, 0, 4, 50, 202, 62, +235, 99, 40, 63, 228, 49, 36, 63, 1, 205, 0, 0, 241, 220, 158, 62, 34, 84, 49, 63, +74, 173, 38, 63, 1, 205, 0, 0, 247, 55, 98, 62, 225, 162, 55, 63, 27, 41, 41, 63, +1, 205, 0, 0, 111, 4, 3, 62, 149, 29, 59, 63, 220, 156, 43, 63, 1, 205, 0, 0, +103, 179, 5, 61, 6, 152, 59, 63, 15, 255, 45, 63, 1, 205, 0, 0, 78, 52, 130, 189, +142, 238, 56, 63, 68, 69, 48, 63, 1, 205, 0, 0, 243, 245, 34, 190, 126, 8, 51, 63, +27, 100, 50, 63, 1, 205, 0, 0, 177, 52, 129, 190, 185, 218, 41, 63, 139, 79, 52, 63, +1, 205, 0, 0, 87, 205, 174, 190, 207, 106, 29, 63, 253, 250, 53, 63, 1, 205, 0, 0, +157, 79, 217, 190, 89, 209, 13, 63, 241, 89, 55, 63, 1, 205, 0, 0, 215, 195, 255, 190, +90, 121, 246, 62, 100, 96, 56, 63, 1, 205, 0, 0, 170, 156, 16, 191, 67, 229, 203, 62, +123, 3, 57, 63, 1, 205, 0, 0, 193, 104, 30, 191, 137, 160, 156, 62, 112, 58, 57, 63, +1, 205, 0, 0, 76, 229, 40, 191, 205, 36, 83, 62, 60, 255, 56, 63, 1, 205, 0, 0, +108, 197, 47, 191, 95, 38, 207, 61, 62, 79, 56, 63, 1, 205, 0, 0, 77, 213, 50, 191, +103, 95, 227, 187, 184, 43, 55, 63, 1, 205, 0, 0, 102, 253, 49, 191, 81, 212, 236, 189, +21, 154, 53, 63, 1, 205, 0, 0, 49, 68, 45, 191, 174, 214, 99, 190, 184, 163, 51, 63, +1, 205, 0, 0, 204, 205, 36, 191, 237, 120, 166, 190, 141, 85, 49, 63, 1, 205, 0, 0, +37, 153, 47, 191, 73, 148, 231, 190, 187, 236, 17, 63, 1, 205, 0, 0, 245, 245, 30, 191, +207, 132, 12, 191, 62, 65, 15, 63, 1, 205, 0, 0, 120, 74, 11, 191, 63, 118, 34, 191, +241, 127, 12, 63, 1, 205, 0, 0, 240, 44, 234, 190, 185, 68, 53, 191, 162, 185, 9, 63, +1, 205, 0, 0, 95, 194, 185, 190, 86, 176, 68, 191, 254, 253, 6, 63, 1, 205, 0, 0, +64, 102, 134, 190, 60, 146, 80, 191, 69, 91, 4, 63, 1, 205, 0, 0, 123, 72, 34, 190, +41, 218, 88, 191, 170, 221, 1, 63, 1, 205, 0, 0, 83, 217, 87, 189, 175, 139, 93, 191, +173, 30, 255, 62, 1, 205, 0, 0, 222, 60, 89, 61, 243, 186, 94, 191, 253, 240, 250, 62, +1, 205, 0, 0, 112, 213, 32, 62, 164, 137, 92, 191, 131, 62, 247, 62, 1, 205, 0, 0, +149, 10, 132, 62, 18, 36, 87, 191, 16, 16, 244, 62, 1, 205, 0, 0, 252, 88, 181, 62, +194, 190, 78, 191, 24, 107, 241, 62, 1, 205, 0, 0, 203, 188, 227, 62, 70, 148, 67, 191, +79, 82, 239, 62, 1, 205, 0, 0, 91, 88, 7, 63, 140, 227, 53, 191, 49, 198, 237, 62, +1, 205, 0, 0, 252, 224, 26, 63, 153, 238, 37, 191, 86, 197, 236, 62, 1, 205, 0, 0, +126, 71, 44, 63, 106, 249, 19, 191, 230, 76, 236, 62, 1, 205, 0, 0, 227, 98, 59, 63, +95, 73, 0, 191, 187, 88, 236, 62, 1, 205, 0, 0, 95, 17, 72, 63, 116, 73, 214, 190, +169, 227, 236, 62, 1, 205, 0, 0, 203, 55, 82, 63, 49, 164, 169, 190, 15, 232, 237, 62, +1, 205, 0, 0, 62, 193, 89, 63, 19, 97, 118, 190, 155, 95, 239, 62, 1, 205, 0, 0, +149, 158, 94, 63, 57, 249, 22, 190, 117, 67, 241, 62, 1, 205, 0, 0, 57, 198, 96, 63, +140, 178, 88, 189, 164, 140, 243, 62, 1, 205, 0, 0, 248, 51, 96, 63, 247, 162, 43, 61, +225, 51, 246, 62, 1, 205, 0, 0, 244, 232, 92, 63, 216, 42, 11, 62, 120, 49, 249, 62, +1, 205, 0, 0, 147, 235, 86, 63, 22, 126, 105, 62, 156, 125, 252, 62, 1, 205, 0, 0, +185, 71, 78, 63, 41, 99, 162, 62, 18, 8, 0, 63, 1, 205, 0, 0, 249, 14, 67, 63, +241, 243, 205, 62, 70, 240, 1, 63, 1, 205, 0, 0, 185, 88, 53, 63, 44, 228, 246, 62, +254, 242, 3, 63, 1, 205, 0, 0, 231, 66, 37, 63, 123, 83, 14, 63, 111, 11, 6, 63, +1, 205, 0, 0, 54, 242, 18, 63, 106, 88, 31, 63, 143, 52, 8, 63, 1, 205, 0, 0, +175, 37, 253, 62, 47, 60, 46, 63, 230, 104, 10, 63, 1, 205, 0, 0, 63, 178, 208, 62, +194, 187, 58, 63, 117, 162, 12, 63, 1, 205, 0, 0, 104, 4, 161, 62, 162, 150, 68, 63, +183, 218, 14, 63, 1, 205, 0, 0, 61, 83, 93, 62, 239, 143, 75, 63, 122, 10, 17, 63, +1, 205, 0, 0, 204, 14, 233, 61, 237, 111, 79, 63, 224, 41, 19, 63, 1, 205, 0, 0, +134, 55, 17, 60, 227, 5, 80, 63, 84, 48, 21, 63, 1, 205, 0, 0, 79, 221, 198, 189, +93, 42, 77, 63, 131, 20, 23, 63, 1, 205, 0, 0, 64, 59, 79, 190, 227, 193, 70, 63, +124, 204, 24, 63, 1, 205, 0, 0, 242, 51, 156, 190, 228, 191, 60, 63, 219, 77, 26, 63, +1, 205, 0, 0, 118, 117, 206, 190, 234, 41, 47, 63, 21, 142, 27, 63, 1, 205, 0, 0, +85, 83, 253, 190, 158, 26, 30, 63, 207, 130, 28, 63, 1, 205, 0, 0, 48, 222, 19, 191, +89, 196, 9, 63, 129, 34, 29, 63, 1, 205, 0, 0, 124, 83, 38, 191, 33, 230, 228, 62, +238, 100, 29, 63, 1, 205, 0, 0, 112, 142, 53, 191, 143, 25, 177, 62, 196, 67, 29, 63, +1, 205, 0, 0, 236, 35, 65, 191, 48, 64, 114, 62, 112, 187, 28, 63, 1, 205, 0, 0, +219, 190, 72, 191, 16, 138, 248, 61, 126, 203, 27, 63, 1, 205, 0, 0, 185, 37, 76, 191, +140, 46, 53, 59, 249, 118, 26, 63, 1, 205, 0, 0, 89, 62, 75, 191, 92, 172, 238, 189, +140, 196, 24, 63, 1, 205, 0, 0, 169, 15, 70, 191, 213, 120, 111, 190, 84, 190, 22, 63, +1, 205, 0, 0, 98, 193, 60, 191, 98, 115, 177, 190, 79, 113, 20, 63, 1, 205, 0, 0, +178, 209, 65, 191, 104, 170, 243, 190, 65, 37, 229, 62, 1, 205, 0, 0, 99, 240, 47, 191, +222, 99, 20, 191, 193, 40, 224, 62, 1, 205, 0, 0, 171, 203, 26, 191, 135, 246, 43, 191, +243, 29, 219, 62, 1, 205, 0, 0, 51, 237, 2, 191, 147, 44, 64, 191, 80, 34, 214, 62, +1, 205, 0, 0, 190, 204, 209, 190, 83, 193, 80, 191, 227, 80, 209, 62, 1, 205, 0, 0, +197, 148, 154, 190, 207, 138, 93, 191, 106, 193, 204, 62, 1, 205, 0, 0, 255, 163, 66, 190, +129, 119, 102, 191, 27, 136, 200, 62, 1, 205, 0, 0, 85, 91, 156, 189, 10, 139, 107, 191, +26, 181, 196, 62, 1, 205, 0, 0, 7, 235, 24, 61, 243, 218, 108, 191, 200, 84, 193, 62, +1, 205, 0, 0, 213, 193, 24, 62, 77, 139, 106, 191, 9, 112, 190, 62, 1, 205, 0, 0, +118, 225, 131, 62, 150, 203, 100, 191, 130, 12, 188, 62, 1, 205, 0, 0, 237, 227, 184, 62, +11, 212, 91, 191, 39, 45, 186, 62, 1, 205, 0, 0, 212, 195, 234, 62, 102, 227, 79, 191, +133, 210, 184, 62, 1, 205, 0, 0, 242, 120, 12, 63, 39, 61, 65, 191, 16, 251, 183, 62, +1, 205, 0, 0, 132, 121, 33, 63, 5, 40, 48, 191, 195, 163, 183, 62, 1, 205, 0, 0, +42, 47, 52, 63, 249, 236, 28, 191, 61, 200, 183, 62, 1, 205, 0, 0, 247, 109, 68, 63, +69, 214, 7, 191, 90, 99, 184, 62, 1, 205, 0, 0, 159, 17, 82, 63, 90, 94, 226, 190, +254, 110, 185, 62, 1, 205, 0, 0, 9, 253, 92, 63, 215, 134, 178, 190, 105, 228, 186, 62, +1, 205, 0, 0, 191, 25, 101, 63, 208, 189, 128, 190, 114, 188, 188, 62, 1, 205, 0, 0, +128, 87, 106, 63, 215, 54, 27, 190, 206, 239, 190, 62, 1, 205, 0, 0, 255, 171, 108, 63, +166, 190, 77, 189, 193, 118, 193, 62, 1, 205, 0, 0, 189, 18, 108, 63, 44, 167, 82, 61, +96, 73, 196, 62, 1, 205, 0, 0, 223, 140, 104, 63, 39, 229, 27, 62, 136, 95, 199, 62, +1, 205, 0, 0, 66, 33, 98, 63, 36, 137, 128, 62, 228, 176, 202, 62, 1, 205, 0, 0, +147, 220, 88, 63, 106, 128, 177, 62, 251, 52, 206, 62, 1, 205, 0, 0, 153, 209, 76, 63, +113, 64, 224, 62, 232, 226, 209, 62, 1, 205, 0, 0, 110, 25, 62, 63, 224, 24, 6, 63, +116, 177, 213, 62, 1, 205, 0, 0, 15, 212, 44, 63, 166, 94, 26, 63, 12, 151, 217, 62, +1, 205, 0, 0, 209, 40, 25, 63, 192, 166, 44, 63, 140, 137, 221, 62, 1, 205, 0, 0, +21, 71, 3, 63, 121, 167, 60, 63, 56, 126, 225, 62, 1, 205, 0, 0, 167, 205, 214, 62, +234, 24, 74, 63, 169, 105, 229, 62, 1, 205, 0, 0, 100, 147, 163, 62, 202, 181, 84, 63, +119, 63, 233, 62, 1, 205, 0, 0, 16, 238, 90, 62, 178, 60, 92, 63, 113, 242, 236, 62, +1, 205, 0, 0, 29, 153, 212, 61, 181, 113, 96, 63, 96, 116, 240, 62, 1, 205, 0, 0, +99, 76, 19, 188, 89, 32, 97, 63, 39, 182, 243, 62, 1, 205, 0, 0, 111, 187, 251, 189, +22, 30, 94, 63, 167, 167, 246, 62, 1, 205, 0, 0, 1, 201, 113, 190, 24, 77, 87, 63, +85, 56, 249, 62, 1, 205, 0, 0, 196, 115, 177, 190, 145, 159, 76, 63, 29, 87, 251, 62, +1, 205, 0, 0, 5, 132, 231, 190, 20, 27, 62, 63, 46, 243, 252, 62, 1, 205, 0, 0, +240, 248, 12, 191, 188, 219, 43, 63, 243, 252, 253, 62, 1, 205, 0, 0, 150, 203, 35, 191, +68, 23, 22, 63, 101, 102, 254, 62, 1, 205, 0, 0, 251, 170, 55, 191, 88, 61, 250, 62, +144, 36, 254, 62, 1, 205, 0, 0, 94, 18, 72, 191, 29, 190, 194, 62, 81, 48, 253, 62, +1, 205, 0, 0, 57, 142, 84, 191, 216, 191, 134, 62, 151, 135, 251, 62, 1, 205, 0, 0, +193, 194, 92, 191, 79, 1, 15, 62, 209, 45, 249, 62, 1, 205, 0, 0, 203, 113, 96, 191, +233, 56, 76, 60, 182, 44, 246, 62, 1, 205, 0, 0, 244, 126, 95, 191, 44, 151, 236, 189, +219, 147, 242, 62, 1, 205, 0, 0, 141, 241, 89, 191, 62, 53, 119, 190, 154, 120, 238, 62, +1, 205, 0, 0, 38, 244, 79, 191, 76, 141, 185, 190, 200, 244, 233, 62, 1, 205, 0, 0, +117, 139, 79, 191, 82, 214, 251, 190, 249, 140, 162, 62, 1, 205, 0, 0, 199, 184, 60, 191, +44, 225, 25, 191, 135, 0, 158, 62, 1, 205, 0, 0, 109, 117, 38, 191, 191, 180, 50, 191, +163, 131, 153, 62, 1, 205, 0, 0, 152, 82, 13, 191, 247, 255, 71, 191, 26, 47, 149, 62, +1, 205, 0, 0, 247, 210, 227, 190, 97, 122, 89, 191, 11, 25, 145, 62, 1, 205, 0, 0, +132, 170, 169, 190, 158, 247, 102, 191, 63, 84, 141, 62, 1, 205, 0, 0, 74, 182, 90, 190, +11, 101, 112, 191, 14, 240, 137, 62, 1, 205, 0, 0, 74, 22, 192, 189, 95, 198, 117, 191, +48, 248, 134, 62, 1, 205, 0, 0, 253, 139, 212, 60, 23, 50, 119, 191, 234, 116, 132, 62, +1, 205, 0, 0, 189, 51, 19, 62, 3, 206, 116, 191, 152, 107, 130, 62, 1, 205, 0, 0, +17, 16, 132, 62, 7, 204, 110, 191, 181, 222, 128, 62, 1, 205, 0, 0, 97, 230, 187, 62, +53, 103, 101, 191, 183, 156, 127, 62, 1, 205, 0, 0, 133, 111, 240, 62, 131, 225, 88, 191, +164, 113, 126, 62, 1, 205, 0, 0, 104, 138, 16, 63, 204, 129, 73, 191, 182, 53, 126, 62, +1, 205, 0, 0, 85, 170, 38, 63, 102, 146, 55, 191, 149, 223, 126, 62, 1, 205, 0, 0, +85, 96, 58, 63, 1, 96, 35, 191, 231, 49, 128, 62, 1, 205, 0, 0, 35, 126, 75, 63, +191, 56, 13, 191, 199, 90, 129, 62, 1, 205, 0, 0, 156, 221, 89, 63, 88, 215, 234, 190, +122, 227, 130, 62, 1, 205, 0, 0, 27, 96, 101, 63, 172, 144, 184, 190, 162, 196, 132, 62, +1, 205, 0, 0, 253, 237, 109, 63, 12, 61, 132, 190, 117, 246, 134, 62, 1, 205, 0, 0, +34, 118, 115, 63, 13, 249, 28, 190, 214, 112, 137, 62, 1, 205, 0, 0, 185, 237, 117, 63, +189, 119, 63, 189, 149, 43, 140, 62, 1, 205, 0, 0, 250, 79, 117, 63, 125, 94, 118, 61, +86, 30, 143, 62, 1, 205, 0, 0, 21, 158, 113, 63, 191, 39, 42, 62, 145, 64, 146, 62, +1, 205, 0, 0, 57, 223, 106, 63, 87, 73, 138, 62, 164, 137, 149, 62, 1, 205, 0, 0, +182, 32, 97, 63, 71, 204, 189, 62, 173, 240, 152, 62, 1, 205, 0, 0, 58, 118, 84, 63, +245, 252, 238, 62, 161, 108, 156, 62, 1, 205, 0, 0, 30, 250, 68, 63, 12, 158, 14, 63, +75, 244, 159, 62, 1, 205, 0, 0, 248, 205, 50, 63, 119, 245, 35, 63, 6, 126, 163, 62, +1, 205, 0, 0, 26, 27, 30, 63, 14, 54, 55, 63, 229, 255, 166, 62, 1, 205, 0, 0, +73, 19, 7, 63, 78, 18, 72, 63, 119, 111, 170, 62, 1, 205, 0, 0, 206, 226, 219, 62, +135, 62, 86, 63, 253, 193, 173, 62, 1, 205, 0, 0, 181, 244, 165, 62, 211, 113, 97, 63, +32, 236, 176, 62, 1, 205, 0, 0, 240, 247, 89, 62, 73, 103, 105, 63, 245, 225, 179, 62, +1, 205, 0, 0, 7, 188, 198, 61, 199, 223, 109, 63, 16, 151, 182, 62, 1, 205, 0, 0, +232, 50, 178, 188, 245, 163, 110, 63, 140, 254, 184, 62, 1, 205, 0, 0, 135, 38, 17, 190, +215, 134, 107, 63, 82, 11, 187, 62, 1, 205, 0, 0, 108, 161, 133, 190, 223, 104, 100, 63, +5, 176, 188, 62, 1, 205, 0, 0, 135, 56, 193, 190, 34, 59, 89, 63, 253, 223, 189, 62, +1, 205, 0, 0, 194, 48, 250, 190, 52, 3, 74, 63, 252, 142, 190, 62, 1, 205, 0, 0, +124, 171, 23, 191, 87, 222, 54, 63, 127, 178, 190, 62, 1, 205, 0, 0, 160, 186, 47, 191, +148, 4, 32, 63, 63, 66, 190, 62, 1, 205, 0, 0, 236, 174, 68, 191, 223, 202, 5, 63, +221, 56, 189, 62, 1, 205, 0, 0, 103, 252, 85, 191, 34, 71, 209, 62, 224, 148, 187, 62, +1, 205, 0, 0, 18, 41, 99, 191, 33, 58, 146, 62, 79, 89, 185, 62, 1, 205, 0, 0, +1, 212, 107, 191, 73, 121, 31, 62, 35, 142, 182, 62, 1, 205, 0, 0, 112, 187, 111, 191, +202, 37, 180, 60, 112, 64, 179, 62, 1, 205, 0, 0, 59, 193, 110, 191, 149, 170, 230, 189, +22, 130, 175, 62, 1, 205, 0, 0, 0, 237, 104, 191, 59, 245, 122, 190, 243, 104, 171, 62, +1, 205, 0, 0, 115, 107, 94, 191, 250, 170, 190, 190, 67, 14, 167, 62, 1, 205, 0, 0, +212, 192, 88, 191, 136, 250, 255, 190, 202, 115, 58, 62, 1, 205, 0, 0, 179, 76, 69, 191, +120, 232, 28, 191, 91, 97, 50, 62, 1, 205, 0, 0, 43, 73, 46, 191, 188, 151, 54, 191, +168, 169, 42, 62, 1, 205, 0, 0, 118, 76, 20, 191, 113, 161, 76, 191, 243, 115, 35, 62, +1, 205, 0, 0, 51, 234, 239, 190, 122, 186, 94, 191, 15, 226, 28, 62, 1, 205, 0, 0, +45, 199, 179, 190, 199, 180, 108, 191, 243, 14, 23, 62, 1, 205, 0, 0, 77, 211, 106, 190, +228, 124, 118, 191, 216, 14, 18, 62, 1, 205, 0, 0, 139, 241, 215, 189, 121, 22, 124, 191, +234, 239, 13, 62, 1, 205, 0, 0, 211, 159, 150, 60, 156, 152, 125, 191, 103, 186, 10, 62, +1, 205, 0, 0, 187, 149, 15, 62, 70, 42, 123, 191, 74, 113, 8, 62, 1, 205, 0, 0, +17, 65, 132, 62, 229, 254, 116, 191, 64, 19, 7, 62, 1, 205, 0, 0, 225, 0, 190, 62, +103, 83, 107, 191, 119, 155, 6, 62, 1, 205, 0, 0, 21, 87, 244, 62, 228, 107, 94, 191, +181, 1, 7, 62, 1, 205, 0, 0, 232, 83, 19, 63, 145, 145, 78, 191, 99, 59, 8, 62, +1, 205, 0, 0, 143, 54, 42, 63, 34, 17, 60, 191, 114, 60, 10, 62, 1, 205, 0, 0, +120, 154, 62, 63, 192, 57, 39, 191, 38, 247, 12, 62, 1, 205, 0, 0, 193, 79, 80, 63, +37, 92, 16, 191, 147, 92, 16, 62, 1, 205, 0, 0, 251, 46, 95, 63, 231, 147, 239, 190, +41, 93, 20, 62, 1, 205, 0, 0, 123, 24, 107, 63, 200, 170, 187, 190, 149, 232, 24, 62, +1, 205, 0, 0, 211, 243, 115, 63, 144, 161, 133, 190, 94, 238, 29, 62, 1, 205, 0, 0, +75, 175, 121, 63, 21, 59, 28, 190, 176, 93, 35, 62, 1, 205, 0, 0, 176, 63, 124, 63, +159, 30, 46, 189, 41, 37, 41, 62, 1, 205, 0, 0, 10, 160, 123, 63, 227, 25, 139, 61, +82, 51, 47, 62, 1, 205, 0, 0, 143, 209, 119, 63, 81, 184, 53, 62, 159, 118, 53, 62, +1, 205, 0, 0, 163, 219, 112, 63, 23, 216, 145, 62, 90, 221, 59, 62, 1, 205, 0, 0, +250, 203, 102, 63, 38, 21, 199, 62, 164, 85, 66, 62, 1, 205, 0, 0, 229, 182, 89, 63, +77, 238, 249, 62, 34, 205, 72, 62, 1, 205, 0, 0, 146, 183, 73, 63, 125, 223, 20, 63, +79, 49, 79, 62, 1, 205, 0, 0, 170, 240, 54, 63, 153, 241, 42, 63, 110, 111, 85, 62, +1, 205, 0, 0, 207, 140, 33, 63, 48, 220, 62, 63, 68, 116, 91, 62, 1, 205, 0, 0, +89, 191, 9, 63, 38, 79, 80, 63, 69, 44, 97, 62, 1, 205, 0, 0, 87, 138, 223, 62, +58, 252, 94, 63, 46, 131, 102, 62, 1, 205, 0, 0, 186, 202, 167, 62, 14, 152, 106, 63, +197, 100, 107, 62, 1, 205, 0, 0, 137, 201, 89, 62, 95, 219, 114, 63, 59, 188, 111, 62, +1, 205, 0, 0, 187, 83, 190, 61, 209, 132, 119, 63, 187, 116, 115, 62, 1, 205, 0, 0, +222, 237, 244, 188, 17, 91, 120, 63, 111, 121, 118, 62, 1, 205, 0, 0, 32, 175, 29, 190, +118, 47, 117, 63, 84, 182, 120, 62, 1, 205, 0, 0, 225, 252, 141, 190, 40, 225, 109, 63, +47, 24, 122, 62, 1, 205, 0, 0, 250, 159, 203, 190, 142, 96, 98, 63, 236, 141, 122, 62, +1, 205, 0, 0, 165, 71, 3, 191, 4, 179, 82, 63, 127, 9, 122, 62, 1, 205, 0, 0, +109, 198, 30, 191, 142, 246, 62, 63, 95, 128, 120, 62, 1, 205, 0, 0, 21, 172, 55, 191, +176, 100, 39, 63, 88, 237, 117, 62, 1, 205, 0, 0, 105, 92, 77, 191, 241, 84, 12, 63, +83, 81, 114, 62, 1, 205, 0, 0, 130, 70, 95, 191, 39, 122, 220, 62, 9, 181, 109, 62, +1, 205, 0, 0, 8, 236, 108, 191, 22, 96, 155, 62, 145, 40, 104, 62, 1, 205, 0, 0, +133, 232, 117, 191, 159, 104, 45, 62, 173, 196, 97, 62, 1, 205, 0, 0, 196, 247, 121, 191, +140, 107, 255, 60, 233, 169, 90, 62, 1, 205, 0, 0, 109, 250, 120, 191, 223, 5, 221, 189, +212, 255, 82, 62, 1, 205, 0, 0, 36, 248, 114, 191, 175, 174, 122, 190, 103, 243, 74, 62, +1, 205, 0, 0, 30, 31, 104, 191, 225, 186, 192, 190, 106, 180, 66, 62, 1, 205, 0, 0, +75, 105, 93, 191, 64, 4, 0, 191, 100, 187, 50, 61, 1, 205, 0, 0, 209, 165, 73, 191, +197, 110, 29, 191, 99, 17, 23, 61, 1, 205, 0, 0, 55, 67, 50, 191, 15, 145, 55, 191, +13, 118, 251, 60, 1, 205, 0, 0, 33, 218, 23, 191, 155, 255, 77, 191, 19, 87, 206, 60, +1, 205, 0, 0, 181, 23, 246, 190, 189, 109, 96, 191, 57, 119, 167, 60, 1, 205, 0, 0, +246, 246, 184, 190, 119, 172, 110, 191, 146, 87, 135, 60, 1, 205, 0, 0, 87, 34, 115, 190, +198, 167, 120, 191, 130, 139, 92, 60, 1, 205, 0, 0, 106, 89, 228, 189, 41, 99, 126, 191, +87, 201, 56, 60, 1, 205, 0, 0, 160, 201, 107, 60, 245, 245, 127, 191, 248, 101, 35, 60, +1, 205, 0, 0, 186, 147, 13, 62, 153, 135, 125, 191, 58, 24, 28, 60, 1, 205, 0, 0, +59, 67, 132, 62, 63, 76, 119, 191, 196, 99, 34, 60, 1, 205, 0, 0, 46, 251, 190, 62, +192, 129, 109, 191, 200, 161, 53, 60, 1, 205, 0, 0, 143, 59, 246, 62, 52, 109, 96, 191, +186, 13, 85, 60, 1, 205, 0, 0, 244, 178, 20, 63, 237, 88, 80, 191, 246, 200, 127, 60, +1, 205, 0, 0, 244, 248, 43, 63, 220, 146, 61, 191, 104, 110, 154, 60, 1, 205, 0, 0, +207, 181, 64, 63, 99, 107, 40, 191, 98, 165, 185, 60, 1, 205, 0, 0, 214, 184, 82, 63, +133, 52, 17, 191, 58, 5, 221, 60, 1, 205, 0, 0, 238, 217, 97, 63, 87, 130, 240, 190, +117, 3, 2, 61, 1, 205, 0, 0, 229, 248, 109, 63, 179, 201, 187, 190, 173, 15, 23, 61, +1, 205, 0, 0, 222, 252, 118, 63, 127, 230, 132, 190, 72, 97, 45, 61, 1, 205, 0, 0, +212, 211, 124, 63, 57, 1, 25, 190, 177, 177, 68, 61, 1, 205, 0, 0, 95, 114, 127, 63, +228, 253, 25, 189, 166, 186, 92, 61, 1, 205, 0, 0, 109, 211, 126, 63, 115, 209, 152, 61, +236, 52, 117, 61, 1, 205, 0, 0, 49, 248, 122, 63, 140, 103, 62, 62, 88, 236, 134, 61, +1, 205, 0, 0, 39, 232, 115, 63, 191, 22, 151, 62, 129, 47, 147, 61, 1, 205, 0, 0, +57, 177, 105, 63, 116, 53, 205, 62, 211, 63, 159, 61, 1, 205, 0, 0, 247, 103, 92, 63, +49, 116, 0, 63, 54, 249, 170, 61, 1, 205, 0, 0, 6, 40, 76, 63, 13, 196, 24, 63, +67, 55, 182, 61, 1, 205, 0, 0, 139, 20, 57, 63, 7, 55, 47, 63, 221, 213, 192, 61, +1, 205, 0, 0, 217, 88, 35, 63, 124, 122, 67, 63, 47, 176, 202, 61, 1, 205, 0, 0, +10, 41, 11, 63, 4, 61, 85, 63, 9, 162, 211, 61, 1, 205, 0, 0, 219, 133, 225, 62, +13, 47, 100, 63, 20, 135, 219, 61, 1, 205, 0, 0, 149, 221, 168, 62, 241, 3, 112, 63, +170, 59, 226, 61, 1, 205, 0, 0, 38, 1, 90, 62, 56, 115, 120, 63, 22, 157, 231, 61, +1, 205, 0, 0, 5, 186, 186, 61, 85, 58, 125, 63, 11, 138, 235, 61, 1, 205, 0, 0, +110, 252, 9, 189, 235, 30, 126, 63, 28, 228, 237, 61, 1, 205, 0, 0, 222, 172, 35, 190, +107, 241, 122, 63, 177, 143, 238, 61, 1, 205, 0, 0, 232, 9, 146, 190, 56, 144, 115, 63, +91, 118, 237, 61, 1, 205, 0, 0, 10, 182, 208, 190, 76, 235, 103, 63, 53, 135, 234, 61, +1, 205, 0, 0, 53, 82, 6, 191, 214, 7, 88, 63, 91, 186, 229, 61, 1, 205, 0, 0, +233, 72, 34, 191, 8, 4, 68, 63, 236, 16, 223, 61, 1, 205, 0, 0, 32, 156, 59, 191, +13, 26, 44, 63, 150, 151, 214, 61, 1, 205, 0, 0, 2, 173, 81, 191, 130, 162, 16, 63, +195, 103, 204, 61, 1, 205, 0, 0, 19, 232, 99, 191, 222, 41, 228, 62, 196, 168, 192, 61, +1, 205, 0, 0, 209, 204, 113, 191, 114, 12, 162, 62, 249, 143, 179, 61, 1, 205, 0, 0, +229, 244, 122, 191, 193, 149, 56, 62, 1, 95, 165, 61, 1, 205, 0, 0, 204, 26, 127, 191, +9, 87, 35, 61, 81, 99, 150, 61, 1, 205, 0, 0, 126, 30, 126, 191, 104, 214, 207, 189, +255, 241, 134, 61, 1, 205, 0, 0, 158, 7, 120, 191, 232, 101, 118, 190, 134, 202, 110, 61, +1, 205, 0, 0, 249, 4, 109, 191, 162, 182, 191, 190, 42, 46, 80, 61, 1, 205, 0, 0, +52, 127, 93, 191, 94, 1, 252, 190, 234, 180, 195, 189, 1, 205, 0, 0, 153, 191, 73, 191, +162, 114, 27, 191, 228, 1, 207, 189, 1, 205, 0, 0, 77, 96, 50, 191, 139, 157, 53, 191, +34, 181, 216, 189, 1, 205, 0, 0, 226, 249, 23, 191, 175, 21, 76, 191, 86, 171, 224, 189, +1, 205, 0, 0, 45, 91, 246, 190, 26, 142, 94, 191, 49, 207, 230, 189, 1, 205, 0, 0, +27, 61, 185, 190, 135, 215, 108, 191, 212, 23, 235, 189, 1, 205, 0, 0, 175, 177, 115, 190, +173, 221, 118, 191, 161, 134, 237, 189, 1, 205, 0, 0, 74, 121, 229, 189, 226, 163, 124, 191, +215, 37, 238, 189, 1, 205, 0, 0, 106, 224, 98, 60, 67, 65, 126, 191, 17, 8, 237, 189, +1, 205, 0, 0, 153, 8, 13, 62, 28, 221, 123, 191, 212, 68, 234, 189, 1, 205, 0, 0, +60, 0, 132, 62, 112, 171, 117, 191, 80, 248, 229, 189, 1, 205, 0, 0, 134, 187, 190, 62, +6, 234, 107, 191, 153, 65, 224, 189, 1, 205, 0, 0, 218, 255, 245, 62, 222, 221, 94, 191, +245, 65, 217, 189, 1, 205, 0, 0, 91, 151, 20, 63, 63, 209, 78, 191, 246, 27, 209, 189, +1, 205, 0, 0, 229, 223, 43, 63, 1, 18, 60, 191, 248, 242, 199, 189, 1, 205, 0, 0, +121, 159, 64, 63, 137, 240, 38, 191, 26, 235, 189, 189, 1, 205, 0, 0, 99, 165, 82, 63, +205, 190, 15, 191, 183, 40, 179, 189, 1, 205, 0, 0, 124, 201, 97, 63, 133, 159, 237, 190, +16, 208, 167, 189, 1, 205, 0, 0, 149, 235, 109, 63, 165, 237, 184, 190, 0, 5, 156, 189, +1, 205, 0, 0, 192, 242, 118, 63, 114, 15, 130, 190, 173, 235, 143, 189, 1, 205, 0, 0, +248, 204, 124, 63, 119, 89, 19, 190, 254, 167, 131, 189, 1, 205, 0, 0, 203, 110, 127, 63, +65, 106, 3, 189, 32, 188, 110, 189, 1, 205, 0, 0, 33, 211, 126, 63, 238, 28, 164, 61, +132, 98, 86, 189, 1, 205, 0, 0, 37, 251, 122, 63, 187, 17, 68, 62, 198, 138, 62, 189, +1, 205, 0, 0, 80, 238, 115, 63, 213, 239, 153, 62, 194, 123, 39, 189, 1, 205, 0, 0, +132, 186, 105, 63, 95, 20, 208, 62, 180, 124, 17, 189, 1, 205, 0, 0, 73, 116, 92, 63, +111, 231, 1, 63, 233, 166, 249, 188, 1, 205, 0, 0, 60, 55, 76, 63, 251, 59, 26, 63, +219, 140, 211, 188, 1, 205, 0, 0, 130, 38, 57, 63, 122, 180, 48, 63, 173, 53, 177, 188, +1, 205, 0, 0, 88, 109, 35, 63, 85, 254, 68, 63, 91, 40, 147, 188, 1, 205, 0, 0, +214, 63, 11, 63, 18, 200, 86, 63, 251, 212, 115, 188, 1, 205, 0, 0, 135, 183, 225, 62, +23, 194, 101, 63, 117, 246, 75, 188, 1, 205, 0, 0, 178, 18, 169, 62, 176, 159, 113, 63, +243, 162, 47, 188, 1, 205, 0, 0, 215, 112, 90, 62, 81, 24, 122, 63, 227, 181, 31, 188, +1, 205, 0, 0, 246, 160, 187, 61, 94, 233, 126, 63, 140, 239, 28, 188, 1, 205, 0, 0, +104, 38, 8, 189, 87, 216, 127, 63, 148, 236, 39, 188, 1, 205, 0, 0, 139, 55, 35, 190, +138, 181, 124, 63, 129, 29, 65, 188, 1, 205, 0, 0, 80, 208, 145, 190, 53, 95, 117, 63, +48, 184, 104, 188, 1, 205, 0, 0, 229, 126, 208, 190, 17, 197, 105, 63, 251, 86, 143, 188, +1, 205, 0, 0, 101, 56, 6, 191, 39, 236, 89, 63, 28, 81, 177, 188, 1, 205, 0, 0, +145, 49, 34, 191, 85, 242, 69, 63, 18, 236, 217, 188, 1, 205, 0, 0, 216, 135, 59, 191, +145, 17, 46, 63, 198, 77, 4, 189, 1, 205, 0, 0, 106, 156, 81, 191, 38, 162, 18, 63, +48, 77, 30, 189, 1, 205, 0, 0, 180, 219, 99, 191, 178, 54, 232, 62, 208, 122, 58, 189, +1, 205, 0, 0, 26, 197, 113, 191, 188, 35, 166, 62, 161, 69, 88, 189, 1, 205, 0, 0, +43, 242, 122, 191, 3, 210, 64, 62, 38, 9, 119, 189, 1, 205, 0, 0, 65, 29, 127, 191, +209, 96, 68, 61, 226, 10, 139, 189, 1, 205, 0, 0, 37, 38, 126, 191, 71, 85, 191, 189, +110, 91, 154, 189, 1, 205, 0, 0, 90, 20, 120, 191, 196, 46, 110, 190, 240, 29, 169, 189, +1, 205, 0, 0, 129, 22, 109, 191, 143, 163, 187, 190, 232, 254, 182, 189, 1, 205, 0, 0, +40, 2, 89, 191, 39, 246, 243, 190, 101, 204, 110, 190, 1, 205, 0, 0, 148, 153, 69, 191, +111, 252, 22, 191, 166, 24, 115, 190, 1, 205, 0, 0, 226, 159, 46, 191, 117, 197, 48, 191, +50, 99, 118, 190, 1, 205, 0, 0, 26, 171, 20, 191, 200, 235, 70, 191, 40, 166, 120, 190, +1, 205, 0, 0, 124, 179, 240, 190, 114, 35, 89, 191, 96, 226, 121, 190, 1, 205, 0, 0, +114, 152, 180, 190, 168, 61, 103, 191, 158, 30, 122, 190, 1, 205, 0, 0, 168, 126, 108, 190, +37, 38, 113, 191, 161, 102, 121, 190, 1, 205, 0, 0, 133, 76, 219, 189, 250, 223, 118, 191, +18, 201, 119, 190, 1, 205, 0, 0, 183, 86, 137, 60, 176, 129, 120, 191, 154, 87, 117, 190, +1, 205, 0, 0, 206, 246, 13, 62, 201, 49, 118, 191, 107, 37, 114, 190, 1, 205, 0, 0, +82, 121, 131, 62, 78, 35, 112, 191, 132, 70, 110, 190, 1, 205, 0, 0, 252, 66, 189, 62, +232, 146, 102, 191, 124, 207, 105, 190, 1, 205, 0, 0, 3, 165, 243, 62, 109, 196, 89, 191, +202, 212, 100, 190, 1, 205, 0, 0, 165, 1, 19, 63, 227, 0, 74, 191, 241, 106, 95, 190, +1, 205, 0, 0, 209, 235, 41, 63, 215, 148, 55, 191, 241, 165, 89, 190, 1, 205, 0, 0, +206, 87, 62, 63, 103, 207, 34, 191, 128, 153, 83, 190, 1, 205, 0, 0, 184, 21, 80, 63, +36, 1, 12, 191, 193, 88, 77, 190, 1, 205, 0, 0, 242, 253, 94, 63, 117, 247, 230, 190, +245, 246, 70, 190, 1, 205, 0, 0, 196, 240, 106, 63, 134, 34, 179, 190, 158, 134, 64, 190, +1, 205, 0, 0, 167, 213, 115, 63, 138, 80, 122, 190, 16, 26, 58, 190, 1, 205, 0, 0, +212, 154, 121, 63, 149, 91, 11, 190, 47, 195, 51, 190, 1, 205, 0, 0, 1, 53, 124, 63, +111, 131, 213, 188, 4, 148, 45, 190, 1, 205, 0, 0, 36, 159, 123, 63, 24, 205, 172, 61, +39, 158, 39, 190, 1, 205, 0, 0, 94, 218, 119, 63, 53, 159, 70, 62, 253, 242, 33, 190, +1, 205, 0, 0, 2, 238, 112, 63, 120, 87, 154, 62, 43, 164, 28, 190, 1, 205, 0, 0, +177, 231, 102, 63, 223, 165, 207, 62, 161, 194, 23, 190, 1, 205, 0, 0, 163, 219, 89, 63, +210, 74, 1, 63, 106, 95, 19, 190, 1, 205, 0, 0, 243, 228, 73, 63, 31, 65, 25, 63, +218, 138, 15, 190, 1, 205, 0, 0, 57, 38, 55, 63, 186, 99, 47, 63, 68, 85, 12, 190, +1, 205, 0, 0, 238, 201, 33, 63, 97, 97, 67, 63, 10, 206, 9, 190, 1, 205, 0, 0, +93, 3, 10, 63, 212, 233, 84, 63, 227, 3, 8, 190, 1, 205, 0, 0, 111, 30, 224, 62, +188, 174, 99, 63, 27, 4, 7, 190, 1, 205, 0, 0, 42, 105, 168, 62, 135, 100, 111, 63, +168, 218, 6, 190, 1, 205, 0, 0, 146, 22, 91, 62, 197, 195, 119, 63, 76, 145, 7, 190, +1, 205, 0, 0, 198, 4, 193, 61, 217, 138, 124, 63, 83, 47, 9, 190, 1, 205, 0, 0, +180, 250, 233, 188, 20, 128, 125, 63, 211, 184, 11, 190, 1, 205, 0, 0, 248, 80, 28, 190, +103, 116, 122, 63, 217, 45, 15, 190, 1, 205, 0, 0, 80, 81, 141, 190, 119, 70, 115, 63, +245, 137, 19, 190, 1, 205, 0, 0, 115, 251, 202, 190, 20, 230, 103, 63, 66, 195, 24, 190, +1, 205, 0, 0, 182, 250, 2, 191, 246, 87, 88, 63, 215, 201, 30, 190, 1, 205, 0, 0, +201, 128, 30, 191, 81, 185, 68, 63, 75, 135, 37, 190, 1, 205, 0, 0, 163, 111, 55, 191, +227, 66, 45, 63, 121, 222, 44, 190, 1, 205, 0, 0, 236, 42, 77, 191, 98, 75, 18, 63, +33, 172, 52, 190, 1, 205, 0, 0, 155, 33, 95, 191, 147, 143, 232, 62, 11, 199, 60, 190, +1, 205, 0, 0, 9, 213, 108, 191, 141, 148, 167, 62, 206, 1, 69, 190, 1, 205, 0, 0, +102, 224, 117, 191, 139, 250, 69, 62, 70, 44, 77, 190, 1, 205, 0, 0, 17, 255, 121, 191, +225, 70, 98, 61, 193, 21, 85, 190, 1, 205, 0, 0, 61, 17, 121, 191, 41, 200, 171, 189, +19, 143, 92, 190, 1, 205, 0, 0, 23, 30, 115, 191, 59, 44, 98, 190, 161, 109, 99, 190, +1, 205, 0, 0, 98, 83, 104, 191, 245, 146, 180, 190, 33, 140, 105, 190, 1, 205, 0, 0, +7, 247, 79, 191, 188, 7, 232, 190, 177, 231, 187, 190, 1, 205, 0, 0, 99, 55, 61, 191, +86, 30, 16, 191, 187, 88, 189, 190, 1, 205, 0, 0, 52, 4, 39, 191, 95, 28, 41, 191, +156, 48, 190, 190, 1, 205, 0, 0, 99, 238, 13, 191, 194, 150, 62, 191, 37, 114, 190, 190, +1, 205, 0, 0, 91, 30, 229, 190, 159, 67, 80, 191, 160, 35, 190, 190, 1, 205, 0, 0, +52, 3, 171, 190, 99, 245, 93, 191, 10, 78, 189, 190, 1, 205, 0, 0, 4, 118, 93, 190, +50, 152, 103, 191, 102, 252, 187, 190, 1, 205, 0, 0, 243, 156, 197, 189, 163, 46, 109, 191, +5, 59, 186, 190, 1, 205, 0, 0, 225, 171, 190, 60, 94, 206, 110, 191, 159, 22, 184, 190, +1, 205, 0, 0, 107, 136, 16, 62, 112, 156, 108, 191, 69, 156, 181, 190, 1, 205, 0, 0, +8, 199, 130, 62, 20, 202, 102, 191, 227, 216, 178, 190, 1, 205, 0, 0, 152, 173, 186, 62, +230, 145, 93, 191, 255, 216, 175, 190, 1, 205, 0, 0, 67, 74, 239, 62, 111, 53, 81, 191, +170, 168, 172, 190, 1, 205, 0, 0, 242, 2, 16, 63, 68, 251, 65, 191, 147, 83, 169, 190, +1, 205, 0, 0, 53, 47, 38, 63, 127, 45, 48, 191, 184, 228, 165, 190, 1, 205, 0, 0, +141, 242, 57, 63, 163, 24, 28, 191, 159, 102, 162, 190, 1, 205, 0, 0, 134, 30, 75, 63, +176, 10, 6, 191, 112, 227, 158, 190, 1, 205, 0, 0, 216, 140, 89, 63, 60, 165, 220, 190, +215, 100, 155, 190, 1, 205, 0, 0, 174, 30, 101, 63, 252, 127, 170, 190, 89, 244, 151, 190, +1, 205, 0, 0, 75, 188, 109, 63, 252, 137, 108, 190, 8, 155, 148, 190, 1, 205, 0, 0, +108, 84, 115, 63, 126, 40, 1, 190, 233, 97, 145, 190, 1, 205, 0, 0, 31, 220, 117, 63, +55, 215, 160, 188, 165, 81, 142, 190, 1, 205, 0, 0, 124, 78, 117, 63, 41, 189, 178, 61, +234, 114, 139, 190, 1, 205, 0, 0, 151, 172, 113, 63, 118, 4, 70, 62, 27, 206, 136, 190, +1, 205, 0, 0, 123, 253, 106, 63, 120, 75, 152, 62, 144, 107, 134, 190, 1, 205, 0, 0, +91, 78, 97, 63, 241, 234, 203, 62, 139, 83, 132, 190, 1, 205, 0, 0, 188, 178, 84, 63, +247, 64, 253, 62, 237, 141, 130, 190, 1, 205, 0, 0, 223, 68, 69, 63, 5, 215, 21, 63, +118, 34, 129, 190, 1, 205, 0, 0, 48, 38, 51, 63, 166, 73, 43, 63, 108, 24, 128, 190, +1, 205, 0, 0, 207, 127, 30, 63, 164, 169, 62, 63, 88, 237, 126, 190, 1, 205, 0, 0, +71, 131, 7, 63, 85, 169, 79, 63, 232, 134, 126, 190, 1, 205, 0, 0, 197, 214, 220, 62, +201, 252, 93, 63, 101, 8, 127, 190, 1, 205, 0, 0, 172, 249, 166, 62, 220, 90, 105, 63, +25, 61, 128, 190, 1, 205, 0, 0, 141, 28, 92, 62, 88, 126, 113, 63, 30, 113, 129, 190, +1, 205, 0, 0, 187, 42, 203, 61, 169, 39, 118, 63, 113, 33, 131, 190, 1, 205, 0, 0, +205, 43, 160, 188, 227, 30, 119, 63, 62, 77, 133, 190, 1, 205, 0, 0, 217, 229, 14, 190, +96, 54, 116, 63, 55, 241, 135, 190, 1, 205, 0, 0, 242, 134, 132, 190, 182, 77, 109, 63, +14, 7, 139, 190, 1, 205, 0, 0, 123, 41, 192, 190, 24, 85, 98, 63, 118, 133, 142, 190, +1, 205, 0, 0, 120, 51, 249, 190, 225, 80, 83, 63, 142, 95, 146, 190, 1, 205, 0, 0, +213, 56, 23, 191, 38, 93, 64, 63, 14, 133, 150, 190, 1, 205, 0, 0, 25, 87, 47, 191, +153, 176, 41, 63, 0, 226, 154, 190, 1, 205, 0, 0, 121, 93, 68, 191, 212, 158, 15, 63, +102, 95, 159, 190, 1, 205, 0, 0, 162, 191, 85, 191, 203, 49, 229, 62, 242, 227, 163, 190, +1, 205, 0, 0, 51, 3, 99, 191, 242, 87, 166, 62, 150, 84, 168, 190, 1, 205, 0, 0, +160, 198, 107, 191, 117, 248, 71, 62, 252, 149, 172, 190, 1, 205, 0, 0, 118, 199, 111, 191, +154, 135, 124, 61, 231, 141, 176, 190, 1, 205, 0, 0, 207, 230, 110, 191, 235, 128, 149, 189, +96, 36, 180, 190, 1, 205, 0, 0, 121, 43, 105, 191, 188, 143, 82, 190, 189, 68, 183, 190, +1, 205, 0, 0, 124, 193, 94, 191, 236, 161, 170, 190, 241, 222, 185, 190, 1, 205, 0, 0, +128, 101, 66, 191, 61, 102, 216, 190, 253, 73, 253, 190, 1, 205, 0, 0, 98, 158, 48, 191, +238, 243, 6, 191, 39, 1, 254, 190, 1, 205, 0, 0, 219, 143, 27, 191, 0, 193, 30, 191, +114, 9, 254, 190, 1, 205, 0, 0, 76, 195, 3, 191, 235, 55, 51, 191, 67, 107, 253, 190, +1, 205, 0, 0, 24, 148, 211, 190, 17, 18, 68, 191, 181, 50, 252, 190, 1, 205, 0, 0, +124, 110, 156, 190, 195, 35, 81, 191, 62, 110, 250, 190, 1, 205, 0, 0, 157, 107, 70, 190, +221, 89, 90, 191, 191, 45, 248, 190, 1, 205, 0, 0, 173, 243, 163, 189, 133, 182, 95, 191, +251, 129, 245, 190, 1, 205, 0, 0, 6, 226, 9, 61, 254, 77, 97, 191, 190, 123, 242, 190, +1, 205, 0, 0, 131, 22, 21, 62, 78, 67, 95, 191, 77, 43, 239, 190, 1, 205, 0, 0, +31, 29, 130, 62, 32, 197, 89, 191, 23, 160, 235, 190, 1, 205, 0, 0, 240, 53, 183, 62, +252, 10, 81, 191, 226, 232, 231, 190, 1, 205, 0, 0, 154, 48, 233, 62, 26, 83, 69, 191, +94, 19, 228, 190, 1, 205, 0, 0, 174, 190, 11, 63, 132, 224, 54, 191, 69, 44, 224, 190, +1, 205, 0, 0, 55, 208, 32, 63, 168, 249, 37, 191, 127, 63, 220, 190, 1, 205, 0, 0, +58, 152, 51, 63, 55, 231, 18, 191, 43, 88, 216, 190, 1, 205, 0, 0, 121, 234, 67, 63, +206, 230, 251, 190, 179, 128, 212, 190, 1, 205, 0, 0, 144, 162, 81, 63, 128, 210, 206, 190, +216, 194, 208, 190, 1, 205, 0, 0, 20, 163, 92, 63, 239, 40, 159, 190, 39, 40, 205, 190, +1, 205, 0, 0, 108, 213, 100, 63, 125, 3, 91, 190, 131, 185, 201, 190, 1, 205, 0, 0, +40, 41, 106, 63, 249, 211, 233, 189, 165, 127, 198, 190, 1, 205, 0, 0, 208, 147, 108, 63, +44, 89, 83, 188, 23, 131, 195, 190, 1, 205, 0, 0, 180, 16, 108, 63, 225, 210, 181, 61, +249, 203, 192, 190, 1, 205, 0, 0, 210, 160, 104, 63, 145, 66, 66, 62, 112, 98, 190, 190, +1, 205, 0, 0, 221, 74, 98, 63, 12, 211, 147, 62, 44, 78, 188, 190, 1, 205, 0, 0, +87, 27, 89, 63, 157, 241, 196, 62, 237, 150, 186, 190, 1, 205, 0, 0, 212, 36, 77, 63, +6, 229, 243, 62, 10, 68, 185, 190, 1, 205, 0, 0, 61, 128, 62, 63, 199, 10, 16, 63, +129, 92, 184, 190, 1, 205, 0, 0, 93, 77, 45, 63, 3, 118, 36, 63, 198, 230, 183, 190, +1, 205, 0, 0, 75, 179, 25, 63, 76, 233, 54, 63, 199, 232, 183, 190, 1, 205, 0, 0, +17, 225, 3, 63, 205, 26, 71, 63, 102, 103, 184, 190, 1, 205, 0, 0, 28, 29, 216, 62, +65, 194, 84, 63, 186, 102, 185, 190, 1, 205, 0, 0, 29, 250, 164, 62, 0, 154, 95, 63, +98, 233, 186, 190, 1, 205, 0, 0, 89, 224, 93, 62, 53, 96, 103, 63, 43, 240, 188, 190, +1, 205, 0, 0, 208, 176, 218, 61, 96, 216, 107, 63, 219, 121, 191, 190, 1, 205, 0, 0, +48, 119, 195, 187, 67, 205, 108, 63, 177, 130, 194, 190, 1, 205, 0, 0, 172, 138, 245, 189, +90, 19, 106, 63, 16, 4, 198, 190, 1, 205, 0, 0, 74, 192, 110, 190, 189, 139, 99, 63, +247, 243, 201, 190, 1, 205, 0, 0, 73, 255, 175, 190, 63, 39, 89, 63, 200, 68, 206, 190, +1, 205, 0, 0, 239, 39, 230, 190, 224, 233, 74, 63, 2, 229, 210, 190, 1, 205, 0, 0, +101, 91, 12, 191, 32, 238, 56, 63, 87, 191, 215, 190, 1, 205, 0, 0, 207, 66, 35, 191, +214, 103, 35, 63, 240, 186, 220, 190, 1, 205, 0, 0, 10, 59, 55, 191, 45, 166, 10, 63, +232, 187, 225, 190, 1, 205, 0, 0, 230, 190, 71, 191, 205, 40, 222, 62, 110, 164, 230, 190, +1, 205, 0, 0, 55, 90, 84, 191, 5, 113, 162, 62, 205, 85, 235, 190, 1, 205, 0, 0, +101, 176, 92, 191, 110, 192, 70, 62, 249, 177, 239, 190, 1, 205, 0, 0, 86, 130, 96, 191, +14, 88, 137, 61, 32, 157, 243, 190, 1, 205, 0, 0, 144, 178, 95, 191, 24, 188, 121, 189, +15, 255, 246, 190, 1, 205, 0, 0, 98, 71, 90, 191, 97, 153, 63, 190, 127, 196, 249, 190, +1, 205, 0, 0, 93, 106, 80, 191, 189, 248, 157, 190, 238, 223, 251, 190, 1, 205, 0, 0, +88, 82, 48, 191, 113, 80, 197, 190, 131, 52, 29, 191, 1, 205, 0, 0, 245, 207, 31, 191, +149, 67, 247, 190, 162, 50, 29, 191, 1, 205, 0, 0, 74, 64, 12, 191, 140, 220, 17, 191, +232, 207, 28, 191, 1, 205, 0, 0, 177, 69, 236, 190, 99, 252, 36, 191, 76, 19, 28, 191, +1, 205, 0, 0, 9, 253, 187, 190, 45, 191, 52, 191, 134, 5, 27, 191, 1, 205, 0, 0, +34, 184, 136, 190, 182, 251, 64, 191, 124, 176, 25, 191, 1, 205, 0, 0, 174, 5, 39, 190, +189, 159, 73, 191, 130, 30, 24, 191, 1, 205, 0, 0, 38, 229, 106, 189, 3, 173, 78, 191, +251, 89, 22, 191, 1, 205, 0, 0, 219, 98, 70, 61, 34, 54, 80, 191, 10, 109, 20, 191, +1, 205, 0, 0, 183, 59, 28, 62, 107, 91, 78, 191, 92, 97, 18, 191, 1, 205, 0, 0, +61, 211, 129, 62, 39, 72, 73, 191, 236, 63, 16, 191, 1, 205, 0, 0, 160, 61, 179, 62, +249, 47, 65, 191, 247, 16, 14, 191, 1, 205, 0, 0, 13, 195, 225, 62, 192, 76, 54, 191, +8, 220, 11, 191, 1, 205, 0, 0, 175, 110, 6, 63, 233, 220, 40, 191, 1, 168, 9, 191, +1, 205, 0, 0, 158, 12, 26, 63, 13, 34, 25, 191, 33, 123, 7, 191, 1, 205, 0, 0, +37, 138, 43, 63, 237, 95, 7, 191, 40, 91, 5, 191, 1, 205, 0, 0, 244, 189, 58, 63, +103, 183, 231, 190, 102, 77, 3, 191, 1, 205, 0, 0, 254, 133, 71, 63, 216, 182, 189, 190, +190, 86, 1, 191, 1, 205, 0, 0, 238, 198, 81, 63, 38, 75, 145, 190, 131, 247, 254, 190, +1, 205, 0, 0, 126, 107, 89, 63, 42, 4, 70, 190, 197, 129, 251, 190, 1, 205, 0, 0, +106, 100, 94, 63, 76, 165, 205, 189, 98, 84, 248, 190, 1, 205, 0, 0, 221, 167, 96, 63, +38, 180, 195, 187, 122, 119, 245, 190, 1, 205, 0, 0, 108, 49, 96, 63, 99, 253, 181, 61, +200, 242, 242, 190, 1, 205, 0, 0, 254, 1, 93, 63, 99, 102, 59, 62, 210, 205, 240, 190, +1, 205, 0, 0, 205, 31, 87, 63, 210, 254, 140, 62, 216, 15, 239, 190, 1, 205, 0, 0, +126, 150, 78, 63, 88, 212, 186, 62, 186, 191, 237, 190, 1, 205, 0, 0, 100, 119, 67, 63, +173, 165, 230, 62, 46, 228, 236, 190, 1, 205, 0, 0, 179, 217, 53, 63, 175, 242, 7, 63, +79, 131, 236, 190, 1, 205, 0, 0, 15, 219, 37, 63, 32, 3, 27, 63, 181, 162, 236, 190, +1, 205, 0, 0, 223, 159, 19, 63, 84, 62, 44, 63, 37, 71, 237, 190, 1, 205, 0, 0, +24, 168, 254, 62, 69, 95, 59, 63, 113, 116, 238, 190, 1, 205, 0, 0, 13, 87, 210, 62, +176, 34, 72, 63, 226, 44, 240, 190, 1, 205, 0, 0, 65, 198, 162, 62, 138, 71, 82, 63, +118, 113, 242, 190, 1, 205, 0, 0, 250, 4, 97, 62, 83, 144, 89, 63, 17, 65, 245, 190, +1, 205, 0, 0, 123, 178, 240, 61, 158, 196, 93, 63, 245, 151, 248, 190, 1, 205, 0, 0, +66, 94, 79, 60, 194, 178, 94, 63, 156, 111, 252, 190, 1, 205, 0, 0, 58, 26, 191, 189, +27, 50, 92, 63, 19, 95, 0, 191, 1, 205, 0, 0, 88, 109, 75, 190, 188, 37, 86, 63, +5, 187, 2, 191, 1, 205, 0, 0, 14, 97, 154, 190, 103, 127, 76, 63, 204, 66, 5, 191, +1, 205, 0, 0, 53, 193, 204, 190, 181, 66, 63, 63, 138, 235, 7, 191, 1, 205, 0, 0, +129, 200, 251, 190, 44, 136, 46, 63, 83, 168, 10, 191, 1, 205, 0, 0, 197, 50, 19, 191, +246, 127, 26, 63, 119, 106, 13, 191, 1, 205, 0, 0, 50, 199, 37, 191, 161, 115, 3, 63, +214, 33, 16, 191, 1, 205, 0, 0, 215, 37, 53, 191, 183, 141, 211, 62, 138, 189, 18, 191, +1, 205, 0, 0, 188, 226, 64, 191, 169, 236, 155, 62, 165, 44, 21, 191, 1, 205, 0, 0, +218, 167, 72, 191, 140, 82, 66, 62, 2, 95, 23, 191, 1, 205, 0, 0, 110, 58, 76, 191, +224, 43, 146, 61, 49, 70, 25, 191, 1, 205, 0, 0, 255, 126, 75, 191, 235, 143, 68, 189, +54, 214, 26, 191, 1, 205, 0, 0, 53, 123, 70, 191, 102, 151, 41, 190, 62, 6, 28, 191, +1, 205, 0, 0, 123, 85, 61, 191, 194, 202, 142, 190, 234, 208, 28, 191, 1, 205, 0, 0, +48, 180, 25, 191, 244, 18, 175, 190, 47, 16, 57, 191, 1, 205, 0, 0, 140, 190, 10, 191, +33, 170, 220, 190, 79, 178, 56, 191, 1, 205, 0, 0, 219, 5, 242, 190, 41, 162, 2, 191, +234, 235, 55, 191, 1, 205, 0, 0, 144, 233, 201, 190, 122, 28, 20, 191, 140, 198, 54, 191, +1, 205, 0, 0, 140, 28, 158, 190, 91, 135, 34, 191, 114, 77, 53, 191, 1, 205, 0, 0, +49, 45, 95, 190, 219, 188, 45, 191, 208, 140, 51, 191, 1, 205, 0, 0, 155, 43, 253, 189, +206, 171, 53, 191, 53, 145, 49, 191, 1, 205, 0, 0, 166, 21, 226, 188, 103, 85, 58, 191, +235, 102, 47, 191, 1, 205, 0, 0, 52, 55, 140, 61, 66, 202, 59, 191, 171, 25, 45, 191, +1, 205, 0, 0, 105, 248, 38, 62, 137, 39, 58, 191, 101, 180, 42, 191, 1, 205, 0, 0, +10, 119, 130, 62, 100, 148, 53, 191, 35, 65, 40, 191, 1, 205, 0, 0, 241, 94, 175, 62, +165, 63, 46, 191, 251, 200, 37, 191, 1, 205, 0, 0, 169, 167, 217, 62, 245, 93, 36, 191, +255, 83, 35, 191, 1, 205, 0, 0, 148, 107, 0, 63, 21, 40, 24, 191, 110, 233, 32, 191, +1, 205, 0, 0, 4, 66, 18, 63, 197, 217, 9, 191, 207, 143, 30, 191, 1, 205, 0, 0, +90, 42, 34, 63, 111, 97, 243, 190, 236, 76, 28, 191, 1, 205, 0, 0, 227, 254, 47, 63, +233, 215, 207, 190, 16, 38, 26, 191, 1, 205, 0, 0, 110, 160, 59, 63, 206, 150, 169, 190, +23, 32, 24, 191, 1, 205, 0, 0, 10, 246, 68, 63, 165, 30, 129, 190, 100, 63, 22, 191, +1, 205, 0, 0, 86, 236, 75, 63, 73, 225, 45, 190, 36, 136, 20, 191, 1, 205, 0, 0, +53, 117, 80, 63, 127, 57, 174, 189, 77, 254, 18, 191, 1, 205, 0, 0, 197, 135, 82, 63, +233, 228, 134, 58, 130, 165, 17, 191, 1, 205, 0, 0, 237, 31, 82, 63, 174, 53, 179, 61, +93, 129, 16, 191, 1, 205, 0, 0, 122, 62, 79, 63, 111, 135, 49, 62, 72, 149, 15, 191, +1, 205, 0, 0, 13, 233, 73, 63, 11, 232, 131, 62, 150, 228, 14, 191, 1, 205, 0, 0, +70, 42, 66, 63, 11, 185, 173, 62, 76, 114, 14, 191, 1, 205, 0, 0, 237, 17, 56, 63, +20, 181, 213, 62, 81, 65, 14, 191, 1, 205, 0, 0, 35, 181, 43, 63, 13, 91, 251, 62, +69, 84, 14, 191, 1, 205, 0, 0, 238, 46, 29, 63, 17, 21, 15, 63, 113, 173, 14, 191, +1, 205, 0, 0, 122, 160, 12, 63, 104, 209, 30, 63, 160, 78, 15, 191, 1, 205, 0, 0, +98, 99, 244, 62, 180, 163, 44, 63, 8, 57, 16, 191, 1, 205, 0, 0, 27, 36, 204, 62, +91, 78, 56, 63, 51, 109, 17, 191, 1, 205, 0, 0, 95, 241, 160, 62, 75, 150, 65, 63, +146, 234, 18, 191, 1, 205, 0, 0, 187, 150, 102, 62, 89, 67, 72, 63, 152, 175, 20, 191, +1, 205, 0, 0, 74, 137, 7, 62, 251, 33, 76, 63, 82, 185, 22, 191, 1, 205, 0, 0, +150, 20, 24, 61, 244, 4, 77, 63, 31, 3, 25, 191, 1, 205, 0, 0, 67, 12, 114, 189, +39, 199, 74, 63, 150, 134, 27, 191, 1, 205, 0, 0, 84, 118, 30, 190, 50, 78, 69, 63, +59, 59, 30, 191, 1, 205, 0, 0, 40, 25, 126, 190, 9, 141, 60, 63, 103, 22, 33, 191, +1, 205, 0, 0, 159, 201, 172, 190, 217, 134, 48, 63, 66, 11, 36, 191, 1, 205, 0, 0, +244, 124, 215, 190, 213, 81, 33, 63, 225, 10, 39, 191, 1, 205, 0, 0, 186, 46, 254, 190, +168, 25, 15, 63, 160, 4, 42, 191, 1, 205, 0, 0, 229, 246, 15, 191, 93, 66, 244, 62, +138, 230, 44, 191, 1, 205, 0, 0, 36, 237, 29, 191, 223, 133, 197, 62, 9, 158, 47, 191, +1, 205, 0, 0, 68, 152, 40, 191, 99, 224, 146, 62, 227, 24, 50, 191, 1, 205, 0, 0, +59, 170, 47, 191, 1, 185, 58, 62, 41, 70, 52, 191, 1, 205, 0, 0, 193, 237, 50, 191, +207, 143, 152, 61, 23, 23, 54, 191, 1, 205, 0, 0, 204, 73, 50, 191, 156, 99, 12, 189, +10, 128, 55, 191, 1, 205, 0, 0, 71, 195, 45, 191, 30, 229, 16, 190, 30, 121, 56, 191, +1, 205, 0, 0, 204, 124, 37, 191, 241, 170, 122, 190, 113, 254, 56, 191, 1, 205, 0, 0, +3, 187, 252, 190, 207, 6, 150, 190, 227, 158, 81, 191, 1, 205, 0, 0, 157, 111, 226, 190, +33, 133, 190, 190, 218, 232, 80, 191, 1, 205, 0, 0, 145, 63, 195, 190, 4, 156, 226, 190, +160, 196, 79, 191, 1, 205, 0, 0, 100, 245, 159, 190, 170, 218, 0, 191, 13, 62, 78, 191, +1, 205, 0, 0, 100, 207, 114, 190, 62, 178, 13, 191, 167, 98, 76, 191, 1, 205, 0, 0, +126, 224, 32, 190, 171, 178, 23, 191, 176, 64, 74, 191, 1, 205, 0, 0, 161, 147, 151, 189, +61, 204, 30, 191, 143, 230, 71, 191, 1, 205, 0, 0, 231, 186, 45, 60, 105, 255, 34, 191, +69, 98, 69, 191, 1, 205, 0, 0, 19, 38, 195, 61, 130, 90, 36, 191, 220, 192, 66, 191, +1, 205, 0, 0, 198, 253, 54, 62, 250, 246, 34, 191, 105, 14, 64, 191, 1, 205, 0, 0, +12, 240, 132, 62, 63, 247, 30, 191, 199, 85, 61, 191, 1, 205, 0, 0, 23, 144, 172, 62, +150, 132, 24, 191, 160, 160, 58, 191, 1, 205, 0, 0, 153, 226, 209, 62, 120, 205, 15, 191, +142, 247, 55, 191, 1, 205, 0, 0, 133, 123, 244, 62, 31, 4, 5, 191, 14, 98, 53, 191, +1, 205, 0, 0, 190, 254, 9, 63, 193, 186, 240, 190, 189, 230, 50, 191, 1, 205, 0, 0, +93, 12, 24, 63, 0, 32, 212, 190, 120, 139, 48, 191, 1, 205, 0, 0, 57, 69, 36, 63, +176, 167, 180, 190, 98, 85, 46, 191, 1, 205, 0, 0, 160, 141, 46, 63, 44, 195, 146, 190, +37, 73, 44, 191, 1, 205, 0, 0, 55, 207, 54, 63, 173, 201, 93, 190, 12, 107, 42, 191, +1, 205, 0, 0, 223, 248, 60, 63, 91, 254, 18, 190, 224, 190, 40, 191, 1, 205, 0, 0, +7, 254, 64, 63, 227, 20, 140, 189, 70, 72, 39, 191, 1, 205, 0, 0, 159, 214, 66, 63, +254, 186, 2, 60, 170, 10, 38, 191, 1, 205, 0, 0, 22, 127, 66, 63, 78, 124, 173, 61, +53, 9, 37, 191, 1, 205, 0, 0, 14, 248, 63, 63, 124, 198, 36, 62, 245, 70, 36, 191, +1, 205, 0, 0, 138, 70, 59, 63, 141, 94, 113, 62, 188, 198, 35, 191, 1, 205, 0, 0, +238, 115, 52, 63, 213, 207, 157, 62, 66, 139, 35, 191, 1, 205, 0, 0, 52, 142, 43, 63, +29, 82, 193, 62, 226, 150, 35, 191, 1, 205, 0, 0, 31, 168, 32, 63, 68, 195, 226, 62, +197, 235, 35, 191, 1, 205, 0, 0, 156, 217, 19, 63, 128, 216, 0, 63, 153, 139, 36, 191, +1, 205, 0, 0, 37, 64, 5, 63, 236, 212, 14, 63, 153, 119, 37, 191, 1, 205, 0, 0, +10, 254, 233, 62, 51, 31, 27, 63, 74, 176, 38, 191, 1, 205, 0, 0, 136, 128, 198, 62, +175, 128, 37, 63, 96, 53, 40, 191, 1, 205, 0, 0, 145, 105, 160, 62, 200, 196, 45, 63, +149, 5, 42, 191, 1, 205, 0, 0, 78, 84, 112, 62, 217, 185, 51, 63, 69, 30, 44, 191, +1, 205, 0, 0, 202, 135, 28, 62, 31, 50, 55, 63, 95, 123, 46, 191, 1, 205, 0, 0, +27, 35, 141, 61, 111, 5, 56, 63, 25, 23, 49, 191, 1, 205, 0, 0, 208, 59, 130, 188, +231, 18, 54, 63, 162, 233, 51, 191, 1, 205, 0, 0, 221, 53, 205, 189, 35, 67, 49, 63, +253, 232, 54, 191, 1, 205, 0, 0, 28, 226, 58, 190, 131, 138, 41, 63, 241, 8, 58, 191, +1, 205, 0, 0, 195, 190, 133, 190, 208, 235, 30, 63, 249, 58, 61, 191, 1, 205, 0, 0, +237, 94, 171, 190, 151, 122, 17, 63, 125, 110, 64, 191, 1, 205, 0, 0, 206, 119, 205, 190, +106, 93, 1, 63, 38, 145, 67, 191, 1, 205, 0, 0, 149, 53, 235, 190, 162, 158, 221, 62, +134, 143, 70, 191, 1, 205, 0, 0, 183, 233, 1, 191, 144, 64, 180, 62, 217, 85, 73, 191, +1, 205, 0, 0, 213, 82, 11, 191, 169, 104, 135, 62, 244, 208, 75, 191, 1, 205, 0, 0, +171, 145, 17, 191, 230, 4, 48, 62, 94, 239, 77, 191, 1, 205, 0, 0, 76, 119, 20, 191, +222, 84, 156, 61, 95, 162, 79, 191, 1, 205, 0, 0, 146, 237, 19, 191, 5, 113, 164, 188, +219, 222, 80, 191, 1, 205, 0, 0, 162, 248, 15, 191, 75, 213, 235, 189, 241, 157, 81, 191, +1, 205, 0, 0, 152, 182, 8, 191, 159, 192, 83, 190, 69, 221, 81, 191, 1, 205, 0, 0, +31, 158, 187, 190, 207, 35, 117, 190, 138, 44, 102, 191, 1, 205, 0, 0, 34, 111, 165, 190, +149, 76, 157, 190, 132, 37, 101, 191, 1, 205, 0, 0, 180, 25, 139, 190, 156, 72, 188, 190, +232, 172, 99, 191, 1, 205, 0, 0, 64, 144, 90, 190, 92, 4, 215, 190, 147, 208, 97, 191, +1, 205, 0, 0, 26, 94, 25, 190, 248, 33, 237, 190, 224, 159, 95, 191, 1, 205, 0, 0, +226, 24, 168, 189, 191, 101, 254, 190, 212, 42, 93, 191, 1, 205, 0, 0, 103, 68, 64, 188, +211, 89, 5, 191, 84, 129, 90, 191, 1, 205, 0, 0, 47, 129, 117, 61, 157, 5, 9, 191, +164, 178, 87, 191, 1, 205, 0, 0, 242, 221, 6, 62, 225, 65, 10, 191, 242, 204, 84, 191, +1, 205, 0, 0, 166, 75, 79, 62, 250, 35, 9, 191, 25, 221, 81, 191, 1, 205, 0, 0, +8, 206, 138, 62, 231, 200, 5, 191, 166, 238, 78, 191, 1, 205, 0, 0, 230, 111, 172, 62, +173, 83, 0, 191, 167, 11, 76, 191, 1, 205, 0, 0, 24, 33, 204, 62, 172, 215, 241, 190, +2, 61, 73, 191, 1, 205, 0, 0, 40, 133, 233, 62, 108, 120, 223, 190, 94, 138, 70, 191, +1, 205, 0, 0, 52, 38, 2, 63, 198, 227, 201, 190, 84, 250, 67, 191, 1, 205, 0, 0, +33, 25, 14, 63, 133, 119, 177, 190, 172, 146, 65, 191, 1, 205, 0, 0, 184, 126, 24, 63, +72, 147, 150, 190, 106, 88, 63, 191, 1, 205, 0, 0, 57, 63, 33, 63, 65, 48, 115, 190, +240, 79, 61, 191, 1, 205, 0, 0, 101, 71, 40, 63, 98, 208, 53, 190, 59, 125, 59, 191, +1, 205, 0, 0, 106, 136, 45, 63, 118, 151, 235, 189, 217, 227, 57, 191, 1, 205, 0, 0, +133, 247, 48, 63, 80, 157, 79, 189, 2, 135, 56, 191, 1, 205, 0, 0, 192, 141, 50, 63, +125, 109, 113, 60, 190, 105, 55, 191, 1, 205, 0, 0, 247, 71, 50, 63, 128, 210, 164, 61, +208, 142, 54, 191, 1, 205, 0, 0, 175, 38, 48, 63, 15, 74, 21, 62, 217, 248, 53, 191, +1, 205, 0, 0, 48, 46, 44, 63, 143, 243, 86, 62, 57, 170, 53, 191, 1, 205, 0, 0, +130, 102, 38, 63, 6, 80, 139, 62, 30, 165, 53, 191, 1, 205, 0, 0, 160, 219, 30, 63, +217, 196, 169, 62, 117, 235, 53, 191, 1, 205, 0, 0, 141, 157, 21, 63, 242, 117, 198, 62, +209, 126, 54, 191, 1, 205, 0, 0, 223, 192, 10, 63, 251, 0, 225, 62, 75, 96, 55, 191, +1, 205, 0, 0, 101, 189, 252, 62, 240, 4, 249, 62, 120, 144, 56, 191, 1, 205, 0, 0, +173, 42, 225, 62, 244, 16, 7, 63, 55, 15, 58, 191, 1, 205, 0, 0, 34, 17, 195, 62, +63, 253, 15, 63, 113, 219, 59, 191, 1, 205, 0, 0, 68, 196, 162, 62, 74, 26, 23, 63, +4, 243, 61, 191, 1, 205, 0, 0, 112, 164, 128, 62, 125, 61, 28, 63, 118, 82, 64, 191, +1, 205, 0, 0, 206, 63, 58, 62, 189, 63, 31, 63, 167, 244, 66, 191, 1, 205, 0, 0, +169, 202, 226, 61, 185, 254, 31, 63, 174, 210, 69, 191, 1, 205, 0, 0, 100, 59, 31, 61, +91, 94, 30, 63, 143, 227, 72, 191, 1, 205, 0, 0, 92, 72, 5, 189, 165, 74, 26, 63, +13, 28, 76, 191, 1, 205, 0, 0, 37, 103, 209, 189, 180, 185, 19, 63, 155, 110, 79, 191, +1, 205, 0, 0, 208, 245, 44, 190, 232, 173, 10, 63, 103, 203, 82, 191, 1, 205, 0, 0, +47, 173, 108, 190, 221, 111, 254, 62, 147, 32, 86, 191, 1, 205, 0, 0, 31, 53, 147, 190, +81, 241, 226, 62, 158, 90, 89, 191, 1, 205, 0, 0, 46, 100, 172, 190, 200, 68, 195, 62, +14, 101, 92, 191, 1, 205, 0, 0, 63, 62, 193, 190, 105, 242, 159, 62, 84, 43, 95, 191, +1, 205, 0, 0, 151, 50, 209, 190, 57, 73, 115, 62, 223, 153, 97, 191, 1, 205, 0, 0, +244, 205, 219, 190, 207, 71, 34, 62, 28, 159, 99, 191, 1, 205, 0, 0, 72, 193, 224, 190, +3, 66, 157, 61, 162, 44, 101, 191, 1, 205, 0, 0, 2, 231, 223, 190, 178, 195, 185, 187, +22, 56, 102, 191, 1, 205, 0, 0, 159, 69, 217, 190, 142, 62, 178, 189, 177, 187, 102, 191, +1, 205, 0, 0, 53, 15, 205, 190, 61, 121, 41, 190, 149, 182, 102, 191, 1, 205, 0, 0, +180, 66, 91, 190, 171, 80, 58, 190, 171, 175, 117, 191, 1, 205, 0, 0, 121, 5, 56, 190, +106, 16, 115, 190, 30, 100, 116, 191, 1, 205, 0, 0, 135, 34, 14, 190, 11, 227, 146, 190, +156, 166, 114, 191, 1, 205, 0, 0, 91, 77, 189, 189, 244, 205, 168, 190, 110, 134, 112, 191, +1, 205, 0, 0, 114, 190, 42, 189, 24, 251, 186, 190, 64, 20, 110, 191, 1, 205, 0, 0, +224, 246, 73, 60, 112, 56, 201, 190, 54, 97, 107, 191, 1, 205, 0, 0, 1, 78, 140, 61, +95, 109, 211, 190, 60, 126, 104, 191, 1, 205, 0, 0, 153, 211, 0, 62, 20, 152, 217, 190, +94, 123, 101, 191, 1, 205, 0, 0, 161, 161, 59, 62, 216, 201, 219, 190, 130, 103, 98, 191, +1, 205, 0, 0, 90, 163, 117, 62, 66, 36, 218, 190, 249, 79, 95, 191, 1, 205, 0, 0, +210, 255, 150, 62, 115, 213, 212, 190, 176, 64, 92, 191, 1, 205, 0, 0, 178, 250, 177, 62, +161, 21, 204, 190, 236, 67, 89, 191, 1, 205, 0, 0, 44, 108, 203, 62, 145, 36, 192, 190, +170, 98, 86, 191, 1, 205, 0, 0, 29, 9, 227, 62, 164, 71, 177, 190, 143, 164, 83, 191, +1, 205, 0, 0, 158, 144, 248, 62, 34, 200, 159, 190, 29, 16, 81, 191, 1, 205, 0, 0, +118, 229, 5, 63, 73, 242, 139, 190, 235, 170, 78, 191, 1, 205, 0, 0, 111, 68, 14, 63, +146, 40, 108, 190, 202, 121, 76, 191, 1, 205, 0, 0, 228, 81, 21, 63, 103, 250, 60, 190, +206, 128, 74, 191, 1, 205, 0, 0, 252, 253, 26, 63, 231, 250, 10, 190, 157, 195, 72, 191, +1, 205, 0, 0, 134, 60, 31, 63, 225, 149, 173, 189, 99, 69, 71, 191, 1, 205, 0, 0, +155, 4, 34, 63, 255, 48, 4, 189, 255, 8, 70, 191, 1, 205, 0, 0, 135, 80, 35, 63, +162, 251, 172, 60, 249, 16, 69, 191, 1, 205, 0, 0, 153, 29, 35, 63, 225, 42, 153, 61, +188, 95, 68, 191, 1, 205, 0, 0, 72, 108, 33, 63, 120, 52, 3, 62, 80, 247, 67, 191, +1, 205, 0, 0, 0, 64, 30, 63, 125, 217, 56, 62, 176, 217, 67, 191, 1, 205, 0, 0, +79, 159, 25, 63, 9, 227, 108, 62, 120, 8, 68, 191, 1, 205, 0, 0, 2, 148, 19, 63, +132, 87, 143, 62, 6, 133, 68, 191, 1, 205, 0, 0, 42, 43, 12, 63, 18, 206, 166, 62, +93, 80, 69, 191, 1, 205, 0, 0, 143, 117, 3, 63, 185, 132, 188, 62, 255, 106, 70, 191, +1, 205, 0, 0, 95, 15, 243, 62, 251, 43, 208, 62, 212, 212, 71, 191, 1, 205, 0, 0, +74, 244, 220, 62, 186, 117, 225, 62, 8, 141, 73, 191, 1, 205, 0, 0, 20, 212, 196, 62, +119, 21, 240, 62, 209, 145, 75, 191, 1, 205, 0, 0, 111, 242, 170, 62, 190, 193, 251, 62, +64, 224, 77, 191, 1, 205, 0, 0, 0, 157, 143, 62, 179, 26, 2, 63, 253, 115, 80, 191, +1, 205, 0, 0, 181, 89, 102, 62, 79, 152, 4, 63, 20, 71, 83, 191, 1, 205, 0, 0, +226, 11, 44, 62, 212, 61, 5, 63, 180, 81, 86, 191, 1, 205, 0, 0, 78, 92, 226, 61, +153, 244, 3, 63, 242, 137, 89, 191, 1, 205, 0, 0, 171, 214, 90, 61, 112, 172, 0, 63, +162, 227, 92, 191, 1, 205, 0, 0, 98, 148, 21, 187, 236, 186, 246, 62, 89, 80, 96, 191, +1, 205, 0, 0, 22, 121, 99, 189, 124, 19, 232, 62, 110, 191, 99, 191, 1, 205, 0, 0, +143, 129, 215, 189, 215, 125, 213, 62, 72, 30, 103, 191, 1, 205, 0, 0, 124, 219, 25, 190, +70, 47, 191, 62, 226, 88, 106, 191, 1, 205, 0, 0, 81, 19, 66, 190, 122, 121, 165, 62, +96, 90, 109, 191, 1, 205, 0, 0, 237, 98, 99, 190, 166, 202, 136, 62, 30, 14, 112, 191, +1, 205, 0, 0, 2, 230, 124, 190, 28, 89, 83, 62, 170, 96, 114, 191, 1, 205, 0, 0, +63, 243, 134, 190, 103, 130, 17, 62, 234, 64, 116, 191, 1, 205, 0, 0, 148, 243, 138, 190, +245, 246, 154, 61, 45, 161, 117, 191, 1, 205, 0, 0, 1, 86, 138, 190, 40, 105, 12, 60, +18, 120, 118, 191, 1, 205, 0, 0, 76, 31, 133, 190, 32, 77, 108, 189, 1, 193, 118, 191, +1, 205, 0, 0, 108, 236, 118, 190, 46, 36, 249, 189, 118, 124, 118, 191, 1, 205, 0, 0, +207, 87, 205, 188, 157, 107, 249, 189, 108, 3, 126, 191, 1, 205, 0, 0, 193, 236, 214, 185, +97, 182, 39, 190, 9, 139, 124, 191, 1, 205, 0, 0, 198, 70, 237, 60, 161, 60, 78, 190, +255, 164, 122, 191, 1, 205, 0, 0, 184, 81, 127, 61, 129, 165, 111, 190, 240, 96, 120, 191, +1, 205, 0, 0, 99, 153, 202, 61, 226, 187, 133, 190, 212, 207, 117, 191, 1, 205, 0, 0, +232, 65, 13, 62, 224, 177, 144, 190, 8, 3, 115, 191, 1, 205, 0, 0, 10, 230, 54, 62, +17, 160, 152, 190, 138, 11, 112, 191, 1, 205, 0, 0, 97, 114, 97, 62, 224, 130, 157, 190, +120, 249, 108, 191, 1, 205, 0, 0, 101, 21, 134, 62, 74, 101, 159, 190, 178, 219, 105, 191, +1, 205, 0, 0, 132, 48, 155, 62, 191, 94, 158, 190, 146, 191, 102, 191, 1, 205, 0, 0, +7, 187, 175, 62, 134, 144, 154, 190, 222, 176, 99, 191, 1, 205, 0, 0, 73, 109, 195, 62, +205, 35, 148, 190, 211, 185, 96, 191, 1, 205, 0, 0, 130, 7, 214, 62, 221, 71, 139, 190, +53, 227, 93, 191, 1, 205, 0, 0, 132, 81, 231, 62, 113, 48, 128, 190, 123, 52, 91, 191, +1, 205, 0, 0, 89, 26, 247, 62, 17, 41, 102, 190, 246, 179, 88, 191, 1, 205, 0, 0, +12, 156, 2, 63, 19, 91, 72, 190, 237, 102, 86, 191, 1, 205, 0, 0, 99, 195, 8, 63, +163, 109, 39, 190, 238, 81, 84, 191, 1, 205, 0, 0, 139, 244, 13, 63, 123, 216, 3, 190, +182, 120, 82, 191, 1, 205, 0, 0, 98, 35, 18, 63, 207, 43, 188, 189, 135, 222, 80, 191, +1, 205, 0, 0, 145, 70, 21, 63, 13, 131, 90, 189, 47, 134, 79, 191, 1, 205, 0, 0, +50, 87, 23, 63, 185, 68, 95, 188, 29, 114, 78, 191, 1, 205, 0, 0, 223, 80, 24, 63, +25, 158, 219, 60, 112, 164, 77, 191, 1, 205, 0, 0, 132, 49, 24, 63, 176, 54, 138, 61, +3, 31, 77, 191, 1, 205, 0, 0, 95, 249, 22, 63, 108, 13, 221, 61, 121, 227, 76, 191, +1, 205, 0, 0, 12, 171, 20, 63, 205, 57, 23, 62, 42, 243, 76, 191, 1, 205, 0, 0, +133, 75, 17, 63, 99, 184, 62, 62, 57, 79, 77, 191, 1, 205, 0, 0, 52, 226, 12, 63, +59, 135, 100, 62, 96, 248, 77, 191, 1, 205, 0, 0, 0, 121, 7, 63, 164, 21, 132, 62, +9, 239, 78, 191, 1, 205, 0, 0, 149, 28, 1, 63, 246, 148, 148, 62, 18, 51, 80, 191, +1, 205, 0, 0, 2, 185, 243, 62, 223, 132, 163, 62, 190, 195, 81, 191, 1, 205, 0, 0, +88, 150, 227, 62, 81, 170, 176, 62, 133, 159, 83, 191, 1, 205, 0, 0, 244, 252, 209, 62, +40, 203, 187, 62, 241, 195, 85, 191, 1, 205, 0, 0, 41, 31, 191, 62, 14, 176, 196, 62, +98, 45, 88, 191, 1, 205, 0, 0, 246, 54, 171, 62, 181, 36, 203, 62, 211, 214, 90, 191, +1, 205, 0, 0, 144, 133, 150, 62, 165, 249, 206, 62, 175, 185, 93, 191, 1, 205, 0, 0, +203, 84, 129, 62, 19, 5, 208, 62, 131, 205, 96, 191, 1, 205, 0, 0, 116, 235, 87, 62, +76, 37, 206, 62, 242, 7, 100, 191, 1, 205, 0, 0, 40, 130, 45, 62, 199, 66, 201, 62, +111, 92, 103, 191, 1, 205, 0, 0, 126, 44, 4, 62, 75, 82, 193, 62, 86, 188, 106, 191, +1, 205, 0, 0, 137, 102, 185, 61, 135, 87, 182, 62, 255, 22, 110, 191, 1, 205, 0, 0, +35, 150, 95, 61, 146, 103, 168, 62, 17, 90, 113, 191, 1, 205, 0, 0, 168, 146, 180, 60, +217, 170, 151, 62, 242, 113, 116, 191, 1, 205, 0, 0, 118, 193, 207, 187, 158, 94, 132, 62, +141, 74, 119, 191, 1, 205, 0, 0, 15, 147, 244, 188, 171, 170, 93, 62, 38, 208, 121, 191, +1, 205, 0, 0, 253, 37, 68, 189, 73, 235, 46, 62, 118, 240, 123, 191, 1, 205, 0, 0, +127, 139, 117, 189, 80, 224, 250, 61, 171, 155, 125, 191, 1, 205, 0, 0, 78, 140, 134, 189, +217, 140, 148, 61, 106, 197, 126, 191, 1, 205, 0, 0, 127, 16, 133, 189, 25, 107, 180, 60, +153, 101, 127, 191, 1, 205, 0, 0, 28, 187, 108, 189, 158, 176, 228, 188, 223, 120, 127, 191, +1, 205, 0, 0, 40, 188, 53, 189, 115, 11, 156, 189, 195, 0, 127, 191, 1, 205, 0, 0, +177, 223, 107, 62, 81, 115, 121, 189, 166, 160, 120, 191, 1, 205, 0, 0, 45, 84, 122, 62, +94, 90, 181, 189, 7, 50, 119, 191, 1, 205, 0, 0, 73, 209, 133, 62, 81, 87, 232, 189, +148, 99, 117, 191, 1, 205, 0, 0, 94, 177, 143, 62, 181, 107, 10, 190, 41, 67, 115, 191, +1, 205, 0, 0, 68, 146, 154, 62, 122, 25, 29, 190, 207, 223, 112, 191, 1, 205, 0, 0, +69, 57, 166, 62, 162, 251, 43, 190, 251, 72, 110, 191, 1, 205, 0, 0, 225, 107, 178, 62, +240, 240, 54, 190, 218, 141, 107, 191, 1, 205, 0, 0, 119, 240, 190, 62, 134, 238, 61, 190, +230, 188, 104, 191, 1, 205, 0, 0, 215, 143, 203, 62, 192, 252, 64, 190, 139, 227, 101, 191, +1, 205, 0, 0, 204, 21, 216, 62, 180, 52, 64, 190, 5, 14, 99, 191, 1, 205, 0, 0, +99, 82, 228, 62, 133, 189, 59, 190, 8, 71, 96, 191, 1, 205, 0, 0, 115, 25, 240, 62, +40, 201, 51, 190, 14, 152, 93, 191, 1, 205, 0, 0, 37, 67, 251, 62, 156, 146, 40, 190, +55, 9, 91, 191, 1, 205, 0, 0, 6, 214, 2, 63, 202, 91, 26, 190, 106, 161, 88, 191, +1, 205, 0, 0, 127, 154, 7, 63, 176, 107, 9, 190, 110, 102, 86, 191, 1, 205, 0, 0, +75, 225, 11, 63, 215, 26, 236, 189, 59, 93, 84, 191, 1, 205, 0, 0, 172, 158, 15, 63, +210, 29, 193, 189, 246, 137, 82, 191, 1, 205, 0, 0, 231, 200, 18, 63, 131, 128, 146, 189, +0, 240, 80, 191, 1, 205, 0, 0, 255, 87, 21, 63, 44, 201, 65, 189, 51, 146, 79, 191, +1, 205, 0, 0, 161, 69, 23, 63, 97, 191, 179, 188, 248, 114, 78, 191, 1, 205, 0, 0, +35, 141, 24, 63, 2, 132, 139, 59, 87, 148, 77, 191, 1, 205, 0, 0, 116, 43, 25, 63, +159, 178, 253, 60, 253, 247, 76, 191, 1, 205, 0, 0, 50, 31, 25, 63, 122, 10, 109, 61, +66, 159, 76, 191, 1, 205, 0, 0, 107, 104, 24, 63, 40, 91, 173, 61, 71, 139, 76, 191, +1, 205, 0, 0, 198, 8, 23, 63, 27, 71, 227, 61, 220, 188, 76, 191, 1, 205, 0, 0, +164, 3, 21, 63, 59, 208, 11, 62, 112, 52, 77, 191, 1, 205, 0, 0, 221, 93, 18, 63, +52, 224, 36, 62, 53, 242, 77, 191, 1, 205, 0, 0, 233, 29, 15, 63, 81, 129, 60, 62, +232, 245, 78, 191, 1, 205, 0, 0, 16, 76, 11, 63, 159, 97, 82, 62, 194, 62, 80, 191, +1, 205, 0, 0, 128, 242, 6, 63, 95, 47, 102, 62, 89, 203, 81, 191, 1, 205, 0, 0, +15, 29, 2, 63, 176, 156, 119, 62, 144, 153, 83, 191, 1, 205, 0, 0, 132, 179, 249, 62, +108, 46, 131, 62, 82, 166, 85, 191, 1, 205, 0, 0, 200, 112, 238, 62, 214, 19, 137, 62, +157, 237, 87, 191, 1, 205, 0, 0, 67, 150, 226, 62, 131, 92, 141, 62, 20, 106, 90, 191, +1, 205, 0, 0, 112, 76, 214, 62, 8, 234, 143, 62, 247, 20, 93, 191, 1, 205, 0, 0, +174, 191, 201, 62, 69, 162, 144, 62, 15, 230, 95, 191, 1, 205, 0, 0, 245, 32, 189, 62, +90, 112, 143, 62, 98, 211, 98, 191, 1, 205, 0, 0, 179, 164, 176, 62, 76, 70, 140, 62, +66, 209, 101, 191, 1, 205, 0, 0, 147, 130, 164, 62, 82, 30, 135, 62, 80, 210, 104, 191, +1, 205, 0, 0, 59, 244, 152, 62, 119, 248, 127, 62, 173, 199, 107, 191, 1, 205, 0, 0, +208, 52, 142, 62, 17, 222, 109, 62, 39, 161, 110, 191, 1, 205, 0, 0, 86, 126, 132, 62, +206, 35, 88, 62, 207, 77, 113, 191, 1, 205, 0, 0, 14, 17, 120, 62, 240, 25, 63, 62, +136, 188, 115, 191, 1, 205, 0, 0, 224, 12, 106, 62, 161, 42, 35, 62, 199, 220, 117, 191, +1, 205, 0, 0, 171, 72, 95, 62, 75, 217, 4, 62, 102, 159, 119, 191, 1, 205, 0, 0, +238, 9, 88, 62, 132, 124, 201, 61, 149, 247, 120, 191, 1, 205, 0, 0, 225, 129, 84, 62, +6, 9, 135, 61, 115, 219, 121, 191, 1, 205, 0, 0, 10, 200, 84, 62, 218, 132, 7, 61, +214, 68, 122, 191, 1, 205, 0, 0, 225, 218, 88, 62, 131, 134, 13, 58, 147, 49, 122, 191, +1, 205, 0, 0, 177, 158, 96, 62, 229, 2, 254, 188, 146, 163, 121, 191, 1, 205, 0, 0, +132, 47, 31, 63, 68, 70, 239, 187, 5, 123, 72, 191, 1, 205, 0, 0, 39, 40, 32, 63, +70, 13, 163, 188, 54, 166, 71, 191, 1, 205, 0, 0, 4, 86, 33, 63, 49, 145, 0, 189, +181, 153, 70, 191, 1, 205, 0, 0, 68, 179, 34, 63, 232, 58, 42, 189, 118, 92, 69, 191, +1, 205, 0, 0, 62, 57, 36, 63, 72, 222, 77, 189, 61, 246, 67, 191, 1, 205, 0, 0, +207, 224, 37, 63, 78, 254, 106, 189, 50, 111, 66, 191, 1, 205, 0, 0, 92, 162, 39, 63, +153, 161, 128, 189, 183, 207, 64, 191, 1, 205, 0, 0, 92, 118, 41, 63, 128, 61, 136, 189, +209, 31, 63, 191, 1, 205, 0, 0, 190, 84, 43, 63, 30, 75, 140, 189, 156, 103, 61, 191, +1, 205, 0, 0, 183, 53, 45, 63, 202, 210, 140, 189, 146, 174, 59, 191, 1, 205, 0, 0, +225, 17, 47, 63, 253, 234, 137, 189, 108, 251, 57, 191, 1, 205, 0, 0, 2, 226, 48, 63, +48, 182, 131, 189, 96, 84, 56, 191, 1, 205, 0, 0, 34, 159, 50, 63, 90, 194, 116, 189, +32, 191, 54, 191, 1, 205, 0, 0, 210, 66, 52, 63, 174, 67, 92, 189, 160, 64, 53, 191, +1, 205, 0, 0, 104, 199, 53, 63, 252, 105, 62, 189, 255, 220, 51, 191, 1, 205, 0, 0, +120, 39, 55, 63, 113, 188, 27, 189, 15, 152, 50, 191, 1, 205, 0, 0, 71, 94, 56, 63, +93, 142, 233, 188, 13, 117, 49, 191, 1, 205, 0, 0, 197, 103, 57, 63, 190, 70, 148, 188, +171, 118, 48, 191, 1, 205, 0, 0, 153, 64, 58, 63, 74, 111, 227, 187, 27, 159, 47, 191, +1, 205, 0, 0, 251, 229, 58, 63, 58, 213, 157, 59, 67, 240, 46, 191, 1, 205, 0, 0, +224, 85, 59, 63, 101, 95, 139, 60, 157, 107, 46, 191, 1, 205, 0, 0, 204, 142, 59, 63, +54, 153, 241, 60, 112, 18, 46, 191, 1, 205, 0, 0, 35, 144, 59, 63, 176, 102, 44, 61, +132, 229, 45, 191, 1, 205, 0, 0, 217, 89, 59, 63, 109, 213, 95, 61, 113, 229, 45, 191, +1, 205, 0, 0, 137, 236, 58, 63, 35, 57, 137, 61, 139, 18, 46, 191, 1, 205, 0, 0, +169, 73, 58, 63, 188, 201, 161, 61, 169, 108, 46, 191, 1, 205, 0, 0, 72, 115, 57, 63, +173, 73, 185, 61, 98, 243, 46, 191, 1, 205, 0, 0, 6, 108, 56, 63, 28, 103, 207, 61, +7, 166, 47, 191, 1, 205, 0, 0, 73, 55, 55, 63, 157, 210, 227, 61, 100, 131, 48, 191, +1, 205, 0, 0, 24, 217, 53, 63, 249, 62, 246, 61, 205, 137, 49, 191, 1, 205, 0, 0, +33, 86, 52, 63, 140, 48, 3, 62, 20, 183, 50, 191, 1, 205, 0, 0, 194, 179, 50, 63, +204, 249, 9, 62, 82, 8, 52, 191, 1, 205, 0, 0, 195, 247, 48, 63, 11, 91, 15, 62, +40, 122, 53, 191, 1, 205, 0, 0, 94, 40, 47, 63, 158, 55, 19, 62, 141, 8, 55, 191, +1, 205, 0, 0, 160, 76, 45, 63, 22, 118, 21, 62, 106, 174, 56, 191, 1, 205, 0, 0, +177, 107, 43, 63, 142, 2, 22, 62, 25, 102, 58, 191, 1, 205, 0, 0, 0, 141, 41, 63, +192, 206, 20, 62, 54, 41, 60, 191, 1, 205, 0, 0, 103, 184, 39, 63, 20, 211, 17, 62, +102, 240, 61, 191, 1, 205, 0, 0, 192, 245, 37, 63, 191, 15, 13, 62, 180, 179, 63, 191, +1, 205, 0, 0, 185, 76, 36, 63, 217, 140, 6, 62, 190, 106, 65, 191, 1, 205, 0, 0, +2, 197, 34, 63, 16, 184, 252, 61, 145, 12, 67, 191, 1, 205, 0, 0, 171, 101, 33, 63, +30, 51, 233, 61, 72, 144, 68, 191, 1, 205, 0, 0, 102, 53, 32, 63, 253, 212, 210, 61, +11, 237, 69, 191, 1, 205, 0, 0, 2, 58, 31, 63, 85, 250, 185, 61, 169, 26, 71, 191, +1, 205, 0, 0, 148, 120, 30, 63, 24, 21, 159, 61, 154, 17, 72, 191, 1, 205, 0, 0, +211, 244, 29, 63, 42, 164, 130, 61, 212, 203, 72, 191, 1, 205, 0, 0, 124, 177, 29, 63, +210, 100, 74, 61, 156, 68, 73, 191, 1, 205, 0, 0, 227, 175, 29, 63, 5, 170, 14, 61, +9, 121, 73, 191, 1, 205, 0, 0, 37, 240, 29, 63, 230, 131, 166, 60, 2, 104, 73, 191, +1, 205, 0, 0, 234, 112, 30, 63, 63, 221, 202, 59, 106, 18, 73, 191, 1, 205, 0, 0, +199, 87, 223, 61, 198, 234, 87, 61, 119, 29, 126, 191, 1, 205, 0, 0, 4, 0, 182, 82, +22, 193, 210, 192, 17, 193, 218, 27, 12, 63, 31, 58, 28, 65, 34, 135, 33, 65, 125, 218, +157, 65, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 165, 165, 44, 212, 128, 193, 227, 43, +244, 65, 250, 134, 46, 192, 135, 34, 128, 65, 174, 205, 15, 66, 136, 236, 12, 64, 0, 0, +128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, +0, 0, 107, 80, 36, 65, 0, 0, 205, 205, 70, 28, 6, 80, 70, 28, 6, 80, 70, 28, +6, 80, 70, 28, 6, 208, 70, 28, 6, 208, 70, 28, 6, 208, 0, 0, 128, 63, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 189, 55, 134, 181, 90, 123, +193, 64, 1, 0, 205, 205, 70, 28, 6, 80, 70, 28, 6, 80, 70, 28, 6, 80, 70, 28, +6, 208, 70, 28, 6, 208, 70, 28, 6, 208, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 189, 55, 134, 181, 30, 171, 156, 65, 1, 0, +205, 205, 83, 66, 75, 66, 4, 0, 0, 0, 44, 0, 0, 0, 16, 0, 0, 0, 23, 0, +0, 0, 30, 0, 0, 0, 37, 0, 0, 0, 66, 79, 78, 69, 48, 49, 0, 66, 79, 78, +69, 48, 50, 0, 66, 79, 78, 69, 48, 51, 0, 66, 79, 78, 69, 48, 52, 0, 2, 0, +141, 106, 169, 0, 0, 0, 127, 67, 0, 0, 127, 67, 0, 0, 127, 67, 93, 105, 169, 0, +0, 0, 127, 67, 0, 0, 127, 67, 0, 0, 127, 67, 83, 66, 75, 66, 2, 0, 0, 0, +25, 0, 0, 0, 8, 0, 0, 0, 16, 0, 0, 0, 71, 69, 78, 76, 79, 71, 79, 0, +69, 97, 114, 116, 104, 109, 97, 112, 0, 1, 0, 0, 0, 108, 12, 0, 0, 44, 5, 45, +5, 46, 5, 0, 0, 1, 0, 0, 0, 0, 0, 44, 5, 46, 5, 47, 5, 0, 0, 0, +0, 1, 0, 0, 0, 45, 5, 48, 5, 49, 5, 2, 0, 3, 0, 2, 0, 0, 0, 45, +5, 49, 5, 46, 5, 2, 0, 2, 0, 3, 0, 0, 0, 48, 5, 50, 5, 51, 5, 4, +0, 5, 0, 4, 0, 0, 0, 48, 5, 51, 5, 49, 5, 4, 0, 4, 0, 5, 0, 0, +0, 50, 5, 52, 5, 53, 5, 6, 0, 7, 0, 6, 0, 0, 0, 50, 5, 53, 5, 51, +5, 6, 0, 6, 0, 7, 0, 0, 0, 52, 5, 54, 5, 55, 5, 8, 0, 9, 0, 8, +0, 0, 0, 52, 5, 55, 5, 53, 5, 8, 0, 8, 0, 9, 0, 0, 0, 54, 5, 56, +5, 57, 5, 10, 0, 11, 0, 10, 0, 0, 0, 54, 5, 57, 5, 55, 5, 10, 0, 10, +0, 11, 0, 0, 0, 56, 5, 58, 5, 59, 5, 12, 0, 13, 0, 12, 0, 0, 0, 56, +5, 59, 5, 57, 5, 12, 0, 12, 0, 13, 0, 0, 0, 58, 5, 60, 5, 61, 5, 14, +0, 15, 0, 14, 0, 0, 0, 58, 5, 61, 5, 59, 5, 14, 0, 14, 0, 15, 0, 0, +0, 60, 5, 62, 5, 63, 5, 16, 0, 17, 0, 16, 0, 0, 0, 60, 5, 63, 5, 61, +5, 16, 0, 16, 0, 17, 0, 0, 0, 62, 5, 64, 5, 65, 5, 18, 0, 19, 0, 18, +0, 0, 0, 62, 5, 65, 5, 63, 5, 18, 0, 18, 0, 19, 0, 0, 0, 64, 5, 66, +5, 67, 5, 20, 0, 21, 0, 20, 0, 0, 0, 64, 5, 67, 5, 65, 5, 20, 0, 20, +0, 21, 0, 0, 0, 66, 5, 68, 5, 69, 5, 22, 0, 23, 0, 22, 0, 0, 0, 66, +5, 69, 5, 67, 5, 22, 0, 22, 0, 23, 0, 0, 0, 68, 5, 70, 5, 71, 5, 24, +0, 25, 0, 24, 0, 0, 0, 68, 5, 71, 5, 69, 5, 24, 0, 24, 0, 25, 0, 0, +0, 70, 5, 72, 5, 73, 5, 26, 0, 27, 0, 26, 0, 0, 0, 70, 5, 73, 5, 71, +5, 26, 0, 26, 0, 27, 0, 0, 0, 72, 5, 74, 5, 75, 5, 28, 0, 29, 0, 28, +0, 0, 0, 72, 5, 75, 5, 73, 5, 28, 0, 28, 0, 29, 0, 0, 0, 74, 5, 76, +5, 77, 5, 30, 0, 31, 0, 30, 0, 0, 0, 74, 5, 77, 5, 75, 5, 30, 0, 30, +0, 31, 0, 0, 0, 76, 5, 78, 5, 79, 5, 32, 0, 33, 0, 32, 0, 0, 0, 76, +5, 79, 5, 77, 5, 32, 0, 32, 0, 33, 0, 0, 0, 78, 5, 80, 5, 81, 5, 34, +0, 35, 0, 34, 0, 0, 0, 78, 5, 81, 5, 79, 5, 34, 0, 34, 0, 35, 0, 0, +0, 80, 5, 82, 5, 83, 5, 36, 0, 37, 0, 36, 0, 0, 0, 80, 5, 83, 5, 81, +5, 36, 0, 36, 0, 37, 0, 0, 0, 82, 5, 84, 5, 85, 5, 38, 0, 39, 0, 38, +0, 0, 0, 82, 5, 85, 5, 83, 5, 38, 0, 38, 0, 39, 0, 0, 0, 84, 5, 86, +5, 87, 5, 40, 0, 41, 0, 40, 0, 0, 0, 84, 5, 87, 5, 85, 5, 40, 0, 40, +0, 41, 0, 0, 0, 86, 5, 88, 5, 89, 5, 42, 0, 43, 0, 42, 0, 0, 0, 86, +5, 89, 5, 87, 5, 42, 0, 42, 0, 43, 0, 0, 0, 88, 5, 90, 5, 91, 5, 44, +0, 45, 0, 44, 0, 0, 0, 88, 5, 91, 5, 89, 5, 44, 0, 44, 0, 45, 0, 0, +0, 90, 5, 92, 5, 93, 5, 46, 0, 47, 0, 46, 0, 0, 0, 90, 5, 93, 5, 91, +5, 46, 0, 46, 0, 47, 0, 0, 0, 92, 5, 94, 5, 95, 5, 48, 0, 49, 0, 48, +0, 0, 0, 92, 5, 95, 5, 93, 5, 48, 0, 48, 0, 49, 0, 0, 0, 94, 5, 96, +5, 97, 5, 50, 0, 51, 0, 50, 0, 0, 0, 94, 5, 97, 5, 95, 5, 50, 0, 50, +0, 51, 0, 0, 0, 96, 5, 98, 5, 99, 5, 52, 0, 53, 0, 52, 0, 0, 0, 96, +5, 99, 5, 97, 5, 52, 0, 52, 0, 53, 0, 0, 0, 98, 5, 100, 5, 101, 5, 54, +0, 55, 0, 54, 0, 0, 0, 98, 5, 101, 5, 99, 5, 54, 0, 54, 0, 55, 0, 0, +0, 100, 5, 102, 5, 103, 5, 56, 0, 57, 0, 56, 0, 0, 0, 100, 5, 103, 5, 101, +5, 56, 0, 56, 0, 57, 0, 0, 0, 102, 5, 104, 5, 105, 5, 58, 0, 59, 0, 58, +0, 0, 0, 102, 5, 105, 5, 103, 5, 58, 0, 58, 0, 59, 0, 0, 0, 104, 5, 106, +5, 107, 5, 60, 0, 61, 0, 60, 0, 0, 0, 104, 5, 107, 5, 105, 5, 60, 0, 60, +0, 61, 0, 0, 0, 106, 5, 108, 5, 109, 5, 62, 0, 63, 0, 62, 0, 0, 0, 106, +5, 109, 5, 107, 5, 62, 0, 62, 0, 63, 0, 0, 0, 108, 5, 110, 5, 111, 5, 64, +0, 65, 0, 64, 0, 0, 0, 108, 5, 111, 5, 109, 5, 64, 0, 64, 0, 65, 0, 0, +0, 110, 5, 112, 5, 113, 5, 66, 0, 67, 0, 66, 0, 0, 0, 110, 5, 113, 5, 111, +5, 66, 0, 66, 0, 67, 0, 0, 0, 112, 5, 114, 5, 115, 5, 68, 0, 69, 0, 68, +0, 0, 0, 112, 5, 115, 5, 113, 5, 68, 0, 68, 0, 69, 0, 0, 0, 114, 5, 116, +5, 117, 5, 70, 0, 71, 0, 70, 0, 0, 0, 114, 5, 117, 5, 115, 5, 70, 0, 70, +0, 71, 0, 0, 0, 116, 5, 118, 5, 119, 5, 72, 0, 73, 0, 72, 0, 0, 0, 116, +5, 119, 5, 117, 5, 72, 0, 72, 0, 73, 0, 0, 0, 118, 5, 120, 5, 121, 5, 74, +0, 75, 0, 74, 0, 0, 0, 118, 5, 121, 5, 119, 5, 74, 0, 74, 0, 75, 0, 0, +0, 120, 5, 122, 5, 123, 5, 76, 0, 77, 0, 76, 0, 0, 0, 120, 5, 123, 5, 121, +5, 76, 0, 76, 0, 77, 0, 0, 0, 122, 5, 124, 5, 125, 5, 78, 0, 79, 0, 78, +0, 0, 0, 122, 5, 125, 5, 123, 5, 78, 0, 78, 0, 79, 0, 0, 0, 124, 5, 126, +5, 127, 5, 80, 0, 81, 0, 80, 0, 0, 0, 124, 5, 127, 5, 125, 5, 80, 0, 80, +0, 81, 0, 0, 0, 126, 5, 128, 5, 129, 5, 82, 0, 83, 0, 82, 0, 0, 0, 126, +5, 129, 5, 127, 5, 82, 0, 82, 0, 83, 0, 0, 0, 128, 5, 44, 5, 47, 5, 84, +0, 85, 0, 84, 0, 0, 0, 128, 5, 47, 5, 129, 5, 84, 0, 84, 0, 85, 0, 0, +0, 116, 5, 120, 5, 118, 5, 86, 0, 87, 0, 88, 0, 0, 0, 114, 5, 120, 5, 116, +5, 89, 0, 87, 0, 86, 0, 0, 0, 114, 5, 122, 5, 120, 5, 89, 0, 90, 0, 87, +0, 0, 0, 112, 5, 122, 5, 114, 5, 91, 0, 90, 0, 89, 0, 0, 0, 112, 5, 124, +5, 122, 5, 91, 0, 92, 0, 90, 0, 0, 0, 110, 5, 124, 5, 112, 5, 93, 0, 92, +0, 91, 0, 0, 0, 110, 5, 126, 5, 124, 5, 93, 0, 94, 0, 92, 0, 0, 0, 108, +5, 126, 5, 110, 5, 95, 0, 94, 0, 93, 0, 0, 0, 108, 5, 128, 5, 126, 5, 95, +0, 96, 0, 94, 0, 0, 0, 106, 5, 128, 5, 108, 5, 97, 0, 96, 0, 95, 0, 0, +0, 106, 5, 44, 5, 128, 5, 97, 0, 98, 0, 96, 0, 0, 0, 106, 5, 45, 5, 44, +5, 97, 0, 99, 0, 98, 0, 0, 0, 104, 5, 45, 5, 106, 5, 100, 0, 99, 0, 97, +0, 0, 0, 104, 5, 48, 5, 45, 5, 100, 0, 101, 0, 99, 0, 0, 0, 104, 5, 50, +5, 48, 5, 100, 0, 102, 0, 101, 0, 0, 0, 102, 5, 50, 5, 104, 5, 103, 0, 102, +0, 100, 0, 0, 0, 102, 5, 52, 5, 50, 5, 103, 0, 104, 0, 102, 0, 0, 0, 102, +5, 54, 5, 52, 5, 103, 0, 105, 0, 104, 0, 0, 0, 100, 5, 54, 5, 102, 5, 106, +0, 105, 0, 103, 0, 0, 0, 100, 5, 56, 5, 54, 5, 106, 0, 107, 0, 105, 0, 0, +0, 98, 5, 56, 5, 100, 5, 108, 0, 107, 0, 106, 0, 0, 0, 98, 5, 58, 5, 56, +5, 108, 0, 109, 0, 107, 0, 0, 0, 96, 5, 58, 5, 98, 5, 110, 0, 109, 0, 108, +0, 0, 0, 96, 5, 60, 5, 58, 5, 110, 0, 111, 0, 109, 0, 0, 0, 96, 5, 62, +5, 60, 5, 110, 0, 112, 0, 111, 0, 0, 0, 94, 5, 62, 5, 96, 5, 91, 0, 112, +0, 110, 0, 0, 0, 94, 5, 64, 5, 62, 5, 91, 0, 113, 0, 112, 0, 0, 0, 94, +5, 66, 5, 64, 5, 91, 0, 114, 0, 113, 0, 0, 0, 92, 5, 66, 5, 94, 5, 115, +0, 114, 0, 91, 0, 0, 0, 92, 5, 68, 5, 66, 5, 115, 0, 98, 0, 114, 0, 0, +0, 92, 5, 70, 5, 68, 5, 115, 0, 116, 0, 98, 0, 0, 0, 90, 5, 70, 5, 92, +5, 103, 0, 116, 0, 115, 0, 0, 0, 90, 5, 72, 5, 70, 5, 103, 0, 117, 0, 116, +0, 0, 0, 90, 5, 74, 5, 72, 5, 103, 0, 118, 0, 117, 0, 0, 0, 88, 5, 74, +5, 90, 5, 119, 0, 118, 0, 103, 0, 0, 0, 88, 5, 76, 5, 74, 5, 119, 0, 120, +0, 118, 0, 0, 0, 86, 5, 76, 5, 88, 5, 121, 0, 120, 0, 119, 0, 0, 0, 86, +5, 78, 5, 76, 5, 121, 0, 122, 0, 120, 0, 0, 0, 84, 5, 78, 5, 86, 5, 123, +0, 122, 0, 121, 0, 0, 0, 84, 5, 80, 5, 78, 5, 123, 0, 124, 0, 122, 0, 0, +0, 84, 5, 82, 5, 80, 5, 123, 0, 125, 0, 124, 0, 0, 0, 117, 5, 119, 5, 121, +5, 126, 0, 127, 0, 128, 0, 0, 0, 115, 5, 117, 5, 121, 5, 129, 0, 126, 0, 128, +0, 0, 0, 115, 5, 121, 5, 123, 5, 129, 0, 128, 0, 130, 0, 0, 0, 113, 5, 115, +5, 123, 5, 131, 0, 129, 0, 130, 0, 0, 0, 113, 5, 123, 5, 125, 5, 131, 0, 130, +0, 132, 0, 0, 0, 111, 5, 113, 5, 125, 5, 133, 0, 131, 0, 132, 0, 0, 0, 111, +5, 125, 5, 127, 5, 133, 0, 132, 0, 134, 0, 0, 0, 109, 5, 111, 5, 127, 5, 135, +0, 133, 0, 134, 0, 0, 0, 109, 5, 127, 5, 129, 5, 135, 0, 134, 0, 136, 0, 0, +0, 107, 5, 109, 5, 129, 5, 137, 0, 135, 0, 136, 0, 0, 0, 107, 5, 129, 5, 47, +5, 137, 0, 136, 0, 138, 0, 0, 0, 107, 5, 47, 5, 46, 5, 137, 0, 138, 0, 139, +0, 0, 0, 105, 5, 107, 5, 46, 5, 140, 0, 137, 0, 139, 0, 0, 0, 105, 5, 46, +5, 49, 5, 140, 0, 139, 0, 141, 0, 0, 0, 105, 5, 49, 5, 51, 5, 140, 0, 141, +0, 142, 0, 0, 0, 103, 5, 105, 5, 51, 5, 143, 0, 140, 0, 142, 0, 0, 0, 103, +5, 51, 5, 53, 5, 143, 0, 142, 0, 144, 0, 0, 0, 103, 5, 53, 5, 55, 5, 143, +0, 144, 0, 145, 0, 0, 0, 101, 5, 103, 5, 55, 5, 146, 0, 143, 0, 145, 0, 0, +0, 101, 5, 55, 5, 57, 5, 146, 0, 145, 0, 147, 0, 0, 0, 99, 5, 101, 5, 57, +5, 148, 0, 146, 0, 147, 0, 0, 0, 99, 5, 57, 5, 59, 5, 148, 0, 147, 0, 149, +0, 0, 0, 97, 5, 99, 5, 59, 5, 150, 0, 148, 0, 149, 0, 0, 0, 97, 5, 59, +5, 61, 5, 150, 0, 149, 0, 151, 0, 0, 0, 97, 5, 61, 5, 63, 5, 150, 0, 151, +0, 152, 0, 0, 0, 95, 5, 97, 5, 63, 5, 131, 0, 150, 0, 152, 0, 0, 0, 95, +5, 63, 5, 65, 5, 131, 0, 152, 0, 153, 0, 0, 0, 95, 5, 65, 5, 67, 5, 131, +0, 153, 0, 154, 0, 0, 0, 93, 5, 95, 5, 67, 5, 155, 0, 131, 0, 154, 0, 0, +0, 93, 5, 67, 5, 69, 5, 155, 0, 154, 0, 138, 0, 0, 0, 93, 5, 69, 5, 71, +5, 155, 0, 138, 0, 156, 0, 0, 0, 91, 5, 93, 5, 71, 5, 143, 0, 155, 0, 156, +0, 0, 0, 91, 5, 71, 5, 73, 5, 143, 0, 156, 0, 157, 0, 0, 0, 91, 5, 73, +5, 75, 5, 143, 0, 157, 0, 158, 0, 0, 0, 89, 5, 91, 5, 75, 5, 159, 0, 143, +0, 158, 0, 0, 0, 89, 5, 75, 5, 77, 5, 159, 0, 158, 0, 160, 0, 0, 0, 87, +5, 89, 5, 77, 5, 161, 0, 159, 0, 160, 0, 0, 0, 87, 5, 77, 5, 79, 5, 161, +0, 160, 0, 162, 0, 0, 0, 85, 5, 87, 5, 79, 5, 163, 0, 161, 0, 162, 0, 0, +0, 85, 5, 79, 5, 81, 5, 163, 0, 162, 0, 164, 0, 0, 0, 85, 5, 81, 5, 83, +5, 163, 0, 164, 0, 165, 0, 0, 0, 130, 5, 131, 5, 132, 5, 166, 0, 167, 0, 166, +0, 0, 0, 130, 5, 132, 5, 133, 5, 166, 0, 166, 0, 167, 0, 0, 0, 131, 5, 134, +5, 135, 5, 168, 0, 169, 0, 168, 0, 0, 0, 131, 5, 135, 5, 132, 5, 168, 0, 168, +0, 169, 0, 0, 0, 134, 5, 136, 5, 137, 5, 170, 0, 171, 0, 170, 0, 0, 0, 134, +5, 137, 5, 135, 5, 170, 0, 170, 0, 171, 0, 0, 0, 136, 5, 130, 5, 133, 5, 172, +0, 173, 0, 172, 0, 0, 0, 136, 5, 133, 5, 137, 5, 172, 0, 172, 0, 173, 0, 0, +0, 138, 5, 139, 5, 140, 5, 174, 0, 175, 0, 174, 0, 0, 0, 138, 5, 140, 5, 141, +5, 174, 0, 174, 0, 175, 0, 0, 0, 139, 5, 142, 5, 143, 5, 176, 0, 177, 0, 176, +0, 0, 0, 139, 5, 143, 5, 140, 5, 176, 0, 176, 0, 177, 0, 0, 0, 142, 5, 144, +5, 145, 5, 178, 0, 179, 0, 178, 0, 0, 0, 142, 5, 145, 5, 143, 5, 178, 0, 178, +0, 179, 0, 0, 0, 144, 5, 146, 5, 147, 5, 180, 0, 181, 0, 180, 0, 0, 0, 144, +5, 147, 5, 145, 5, 180, 0, 180, 0, 181, 0, 0, 0, 146, 5, 148, 5, 149, 5, 182, +0, 183, 0, 182, 0, 0, 0, 146, 5, 149, 5, 147, 5, 182, 0, 182, 0, 183, 0, 0, +0, 148, 5, 150, 5, 151, 5, 184, 0, 185, 0, 184, 0, 0, 0, 148, 5, 151, 5, 149, +5, 184, 0, 184, 0, 185, 0, 0, 0, 150, 5, 152, 5, 153, 5, 170, 0, 171, 0, 170, +0, 0, 0, 150, 5, 153, 5, 151, 5, 170, 0, 170, 0, 171, 0, 0, 0, 152, 5, 154, +5, 155, 5, 186, 0, 187, 0, 186, 0, 0, 0, 152, 5, 155, 5, 153, 5, 186, 0, 186, +0, 187, 0, 0, 0, 154, 5, 156, 5, 157, 5, 188, 0, 189, 0, 188, 0, 0, 0, 154, +5, 157, 5, 155, 5, 188, 0, 188, 0, 189, 0, 0, 0, 156, 5, 158, 5, 159, 5, 190, +0, 191, 0, 190, 0, 0, 0, 156, 5, 159, 5, 157, 5, 190, 0, 190, 0, 191, 0, 0, +0, 158, 5, 160, 5, 161, 5, 192, 0, 193, 0, 192, 0, 0, 0, 158, 5, 161, 5, 159, +5, 192, 0, 192, 0, 193, 0, 0, 0, 160, 5, 138, 5, 141, 5, 194, 0, 195, 0, 194, +0, 0, 0, 160, 5, 141, 5, 161, 5, 194, 0, 194, 0, 195, 0, 0, 0, 134, 5, 130, +5, 136, 5, 120, 0, 120, 0, 196, 0, 0, 0, 131, 5, 130, 5, 134, 5, 196, 0, 120, +0, 120, 0, 0, 0, 144, 5, 148, 5, 146, 5, 197, 0, 198, 0, 199, 0, 0, 0, 142, +5, 148, 5, 144, 5, 200, 0, 198, 0, 197, 0, 0, 0, 142, 5, 150, 5, 148, 5, 200, +0, 201, 0, 198, 0, 0, 0, 142, 5, 152, 5, 150, 5, 200, 0, 202, 0, 201, 0, 0, +0, 139, 5, 152, 5, 142, 5, 203, 0, 202, 0, 200, 0, 0, 0, 139, 5, 154, 5, 152, +5, 203, 0, 204, 0, 202, 0, 0, 0, 158, 5, 138, 5, 160, 5, 87, 0, 205, 0, 206, +0, 0, 0, 158, 5, 139, 5, 138, 5, 87, 0, 203, 0, 205, 0, 0, 0, 158, 5, 154, +5, 139, 5, 87, 0, 204, 0, 203, 0, 0, 0, 158, 5, 156, 5, 154, 5, 87, 0, 207, +0, 204, 0, 0, 0, 135, 5, 137, 5, 133, 5, 208, 0, 209, 0, 208, 0, 0, 0, 132, +5, 135, 5, 133, 5, 209, 0, 208, 0, 208, 0, 0, 0, 145, 5, 147, 5, 149, 5, 210, +0, 211, 0, 212, 0, 0, 0, 143, 5, 145, 5, 149, 5, 213, 0, 210, 0, 212, 0, 0, +0, 143, 5, 149, 5, 151, 5, 213, 0, 212, 0, 214, 0, 0, 0, 143, 5, 151, 5, 153, +5, 213, 0, 214, 0, 215, 0, 0, 0, 140, 5, 143, 5, 153, 5, 216, 0, 213, 0, 215, +0, 0, 0, 140, 5, 153, 5, 155, 5, 216, 0, 215, 0, 217, 0, 0, 0, 159, 5, 161, +5, 141, 5, 218, 0, 219, 0, 220, 0, 0, 0, 159, 5, 141, 5, 140, 5, 218, 0, 220, +0, 216, 0, 0, 0, 159, 5, 140, 5, 155, 5, 218, 0, 216, 0, 217, 0, 0, 0, 159, +5, 155, 5, 157, 5, 218, 0, 217, 0, 221, 0, 0, 0, 162, 5, 163, 5, 164, 5, 222, +0, 223, 0, 222, 0, 0, 0, 162, 5, 164, 5, 165, 5, 222, 0, 222, 0, 223, 0, 0, +0, 163, 5, 166, 5, 167, 5, 224, 0, 225, 0, 224, 0, 0, 0, 163, 5, 167, 5, 164, +5, 224, 0, 224, 0, 225, 0, 0, 0, 166, 5, 168, 5, 169, 5, 226, 0, 227, 0, 226, +0, 0, 0, 166, 5, 169, 5, 167, 5, 226, 0, 226, 0, 227, 0, 0, 0, 168, 5, 170, +5, 171, 5, 228, 0, 229, 0, 228, 0, 0, 0, 168, 5, 171, 5, 169, 5, 228, 0, 228, +0, 229, 0, 0, 0, 170, 5, 172, 5, 173, 5, 230, 0, 231, 0, 230, 0, 0, 0, 170, +5, 173, 5, 171, 5, 230, 0, 230, 0, 231, 0, 0, 0, 172, 5, 174, 5, 175, 5, 232, +0, 233, 0, 232, 0, 0, 0, 172, 5, 175, 5, 173, 5, 232, 0, 232, 0, 233, 0, 0, +0, 174, 5, 176, 5, 177, 5, 234, 0, 235, 0, 234, 0, 0, 0, 174, 5, 177, 5, 175, +5, 234, 0, 234, 0, 235, 0, 0, 0, 176, 5, 162, 5, 165, 5, 236, 0, 237, 0, 236, +0, 0, 0, 176, 5, 165, 5, 177, 5, 236, 0, 236, 0, 237, 0, 0, 0, 166, 5, 170, +5, 168, 5, 200, 0, 87, 0, 238, 0, 0, 0, 163, 5, 170, 5, 166, 5, 239, 0, 87, +0, 200, 0, 0, 0, 162, 5, 170, 5, 163, 5, 87, 0, 87, 0, 239, 0, 0, 0, 162, +5, 172, 5, 170, 5, 87, 0, 240, 0, 87, 0, 0, 0, 162, 5, 174, 5, 172, 5, 87, +0, 123, 0, 240, 0, 0, 0, 176, 5, 174, 5, 162, 5, 241, 0, 123, 0, 87, 0, 0, +0, 167, 5, 169, 5, 171, 5, 242, 0, 243, 0, 244, 0, 0, 0, 164, 5, 167, 5, 171, +5, 245, 0, 242, 0, 244, 0, 0, 0, 165, 5, 164, 5, 171, 5, 244, 0, 245, 0, 244, +0, 0, 0, 165, 5, 171, 5, 173, 5, 244, 0, 244, 0, 246, 0, 0, 0, 165, 5, 173, +5, 175, 5, 244, 0, 246, 0, 247, 0, 0, 0, 177, 5, 165, 5, 175, 5, 164, 0, 244, +0, 247, 0, 0, 0, 178, 5, 179, 5, 180, 5, 248, 0, 249, 0, 248, 0, 0, 0, 178, +5, 180, 5, 181, 5, 248, 0, 248, 0, 249, 0, 0, 0, 179, 5, 182, 5, 183, 5, 168, +0, 169, 0, 168, 0, 0, 0, 179, 5, 183, 5, 180, 5, 168, 0, 168, 0, 169, 0, 0, +0, 182, 5, 184, 5, 185, 5, 250, 0, 251, 0, 250, 0, 0, 0, 182, 5, 185, 5, 183, +5, 250, 0, 250, 0, 251, 0, 0, 0, 184, 5, 178, 5, 181, 5, 172, 0, 173, 0, 172, +0, 0, 0, 184, 5, 181, 5, 185, 5, 172, 0, 172, 0, 173, 0, 0, 0, 186, 5, 187, +5, 188, 5, 174, 0, 175, 0, 174, 0, 0, 0, 186, 5, 188, 5, 189, 5, 174, 0, 174, +0, 175, 0, 0, 0, 187, 5, 190, 5, 191, 5, 252, 0, 253, 0, 252, 0, 0, 0, 187, +5, 191, 5, 188, 5, 252, 0, 252, 0, 253, 0, 0, 0, 190, 5, 192, 5, 193, 5, 178, +0, 179, 0, 178, 0, 0, 0, 190, 5, 193, 5, 191, 5, 178, 0, 178, 0, 179, 0, 0, +0, 192, 5, 194, 5, 195, 5, 254, 0, 255, 0, 254, 0, 0, 0, 192, 5, 195, 5, 193, +5, 254, 0, 254, 0, 255, 0, 0, 0, 194, 5, 196, 5, 197, 5, 182, 0, 183, 0, 182, +0, 0, 0, 194, 5, 197, 5, 195, 5, 182, 0, 182, 0, 183, 0, 0, 0, 196, 5, 198, +5, 199, 5, 184, 0, 185, 0, 184, 0, 0, 0, 196, 5, 199, 5, 197, 5, 184, 0, 184, +0, 185, 0, 0, 0, 198, 5, 200, 5, 201, 5, 250, 0, 251, 0, 250, 0, 0, 0, 198, +5, 201, 5, 199, 5, 250, 0, 250, 0, 251, 0, 0, 0, 200, 5, 202, 5, 203, 5, 0, +1, 1, 1, 0, 1, 0, 0, 200, 5, 203, 5, 201, 5, 0, 1, 0, 1, 1, 1, 0, +0, 202, 5, 204, 5, 205, 5, 188, 0, 189, 0, 188, 0, 0, 0, 202, 5, 205, 5, 203, +5, 188, 0, 188, 0, 189, 0, 0, 0, 204, 5, 206, 5, 207, 5, 2, 1, 3, 1, 2, +1, 0, 0, 204, 5, 207, 5, 205, 5, 2, 1, 2, 1, 3, 1, 0, 0, 206, 5, 208, +5, 209, 5, 192, 0, 193, 0, 192, 0, 0, 0, 206, 5, 209, 5, 207, 5, 192, 0, 192, +0, 193, 0, 0, 0, 208, 5, 186, 5, 189, 5, 248, 0, 4, 1, 248, 0, 0, 0, 208, +5, 189, 5, 209, 5, 248, 0, 248, 0, 4, 1, 0, 0, 182, 5, 178, 5, 184, 5, 206, +0, 206, 0, 5, 1, 0, 0, 179, 5, 178, 5, 182, 5, 5, 1, 206, 0, 206, 0, 0, +0, 192, 5, 196, 5, 194, 5, 6, 1, 7, 1, 8, 1, 0, 0, 190, 5, 196, 5, 192, +5, 9, 1, 7, 1, 6, 1, 0, 0, 190, 5, 198, 5, 196, 5, 9, 1, 10, 1, 7, +1, 0, 0, 190, 5, 200, 5, 198, 5, 9, 1, 11, 1, 10, 1, 0, 0, 187, 5, 200, +5, 190, 5, 12, 1, 11, 1, 9, 1, 0, 0, 187, 5, 202, 5, 200, 5, 12, 1, 13, +1, 11, 1, 0, 0, 206, 5, 186, 5, 208, 5, 14, 1, 15, 1, 16, 1, 0, 0, 206, +5, 187, 5, 186, 5, 14, 1, 12, 1, 15, 1, 0, 0, 206, 5, 202, 5, 187, 5, 14, +1, 13, 1, 12, 1, 0, 0, 206, 5, 204, 5, 202, 5, 14, 1, 207, 0, 13, 1, 0, +0, 183, 5, 185, 5, 181, 5, 17, 1, 18, 1, 17, 1, 0, 0, 180, 5, 183, 5, 181, +5, 18, 1, 17, 1, 17, 1, 0, 0, 193, 5, 195, 5, 197, 5, 19, 1, 20, 1, 21, +1, 0, 0, 191, 5, 193, 5, 197, 5, 22, 1, 19, 1, 21, 1, 0, 0, 191, 5, 197, +5, 199, 5, 22, 1, 21, 1, 23, 1, 0, 0, 191, 5, 199, 5, 201, 5, 22, 1, 23, +1, 24, 1, 0, 0, 188, 5, 191, 5, 201, 5, 25, 1, 22, 1, 24, 1, 0, 0, 188, +5, 201, 5, 203, 5, 25, 1, 24, 1, 26, 1, 0, 0, 207, 5, 209, 5, 189, 5, 27, +1, 208, 0, 28, 1, 0, 0, 207, 5, 189, 5, 188, 5, 27, 1, 28, 1, 25, 1, 0, +0, 207, 5, 188, 5, 203, 5, 27, 1, 25, 1, 26, 1, 0, 0, 207, 5, 203, 5, 205, +5, 27, 1, 26, 1, 221, 0, 0, 0, 210, 5, 211, 5, 212, 5, 29, 1, 30, 1, 29, +1, 0, 0, 210, 5, 212, 5, 213, 5, 29, 1, 29, 1, 30, 1, 0, 0, 211, 5, 214, +5, 215, 5, 31, 1, 32, 1, 31, 1, 0, 0, 211, 5, 215, 5, 212, 5, 31, 1, 31, +1, 32, 1, 0, 0, 214, 5, 216, 5, 217, 5, 33, 1, 34, 1, 33, 1, 0, 0, 214, +5, 217, 5, 215, 5, 33, 1, 33, 1, 34, 1, 0, 0, 216, 5, 218, 5, 219, 5, 35, +1, 36, 1, 35, 1, 0, 0, 216, 5, 219, 5, 217, 5, 35, 1, 35, 1, 36, 1, 0, +0, 218, 5, 220, 5, 221, 5, 37, 1, 38, 1, 37, 1, 0, 0, 218, 5, 221, 5, 219, +5, 37, 1, 37, 1, 38, 1, 0, 0, 220, 5, 222, 5, 223, 5, 39, 1, 40, 1, 39, +1, 0, 0, 220, 5, 223, 5, 221, 5, 39, 1, 39, 1, 40, 1, 0, 0, 222, 5, 224, +5, 225, 5, 41, 1, 42, 1, 41, 1, 0, 0, 222, 5, 225, 5, 223, 5, 41, 1, 41, +1, 42, 1, 0, 0, 224, 5, 226, 5, 227, 5, 43, 1, 44, 1, 43, 1, 0, 0, 224, +5, 227, 5, 225, 5, 43, 1, 43, 1, 44, 1, 0, 0, 226, 5, 228, 5, 229, 5, 45, +1, 46, 1, 45, 1, 0, 0, 226, 5, 229, 5, 227, 5, 45, 1, 45, 1, 46, 1, 0, +0, 228, 5, 230, 5, 231, 5, 47, 1, 48, 1, 47, 1, 0, 0, 228, 5, 231, 5, 229, +5, 47, 1, 47, 1, 48, 1, 0, 0, 230, 5, 232, 5, 233, 5, 49, 1, 50, 1, 49, +1, 0, 0, 230, 5, 233, 5, 231, 5, 49, 1, 49, 1, 50, 1, 0, 0, 232, 5, 234, +5, 235, 5, 51, 1, 52, 1, 51, 1, 0, 0, 232, 5, 235, 5, 233, 5, 51, 1, 51, +1, 52, 1, 0, 0, 234, 5, 236, 5, 237, 5, 53, 1, 54, 1, 53, 1, 0, 0, 234, +5, 237, 5, 235, 5, 53, 1, 53, 1, 54, 1, 0, 0, 236, 5, 238, 5, 239, 5, 55, +1, 56, 1, 55, 1, 0, 0, 236, 5, 239, 5, 237, 5, 55, 1, 55, 1, 56, 1, 0, +0, 238, 5, 240, 5, 241, 5, 57, 1, 58, 1, 57, 1, 0, 0, 238, 5, 241, 5, 239, +5, 57, 1, 57, 1, 58, 1, 0, 0, 240, 5, 242, 5, 243, 5, 59, 1, 60, 1, 59, +1, 0, 0, 240, 5, 243, 5, 241, 5, 59, 1, 59, 1, 60, 1, 0, 0, 242, 5, 244, +5, 245, 5, 61, 1, 62, 1, 61, 1, 0, 0, 242, 5, 245, 5, 243, 5, 61, 1, 61, +1, 62, 1, 0, 0, 244, 5, 246, 5, 247, 5, 63, 1, 64, 1, 63, 1, 0, 0, 244, +5, 247, 5, 245, 5, 63, 1, 63, 1, 64, 1, 0, 0, 246, 5, 248, 5, 249, 5, 65, +1, 66, 1, 65, 1, 0, 0, 246, 5, 249, 5, 247, 5, 65, 1, 65, 1, 66, 1, 0, +0, 248, 5, 250, 5, 251, 5, 67, 1, 68, 1, 67, 1, 0, 0, 248, 5, 251, 5, 249, +5, 67, 1, 67, 1, 68, 1, 0, 0, 250, 5, 252, 5, 253, 5, 69, 1, 70, 1, 69, +1, 0, 0, 250, 5, 253, 5, 251, 5, 69, 1, 69, 1, 70, 1, 0, 0, 252, 5, 254, +5, 255, 5, 71, 1, 72, 1, 71, 1, 0, 0, 252, 5, 255, 5, 253, 5, 71, 1, 71, +1, 72, 1, 0, 0, 254, 5, 0, 6, 1, 6, 73, 1, 74, 1, 73, 1, 0, 0, 254, +5, 1, 6, 255, 5, 73, 1, 73, 1, 74, 1, 0, 0, 0, 6, 2, 6, 3, 6, 75, +1, 76, 1, 75, 1, 0, 0, 0, 6, 3, 6, 1, 6, 75, 1, 75, 1, 76, 1, 0, +0, 2, 6, 4, 6, 5, 6, 77, 1, 78, 1, 77, 1, 0, 0, 2, 6, 5, 6, 3, +6, 77, 1, 77, 1, 78, 1, 0, 0, 4, 6, 6, 6, 7, 6, 79, 1, 80, 1, 81, +1, 0, 0, 4, 6, 7, 6, 5, 6, 79, 1, 81, 1, 82, 1, 0, 0, 6, 6, 8, +6, 9, 6, 80, 1, 83, 1, 84, 1, 0, 0, 6, 6, 9, 6, 7, 6, 80, 1, 84, +1, 81, 1, 0, 0, 8, 6, 10, 6, 11, 6, 83, 1, 85, 1, 86, 1, 0, 0, 8, +6, 11, 6, 9, 6, 83, 1, 86, 1, 84, 1, 0, 0, 10, 6, 12, 6, 13, 6, 85, +1, 87, 1, 88, 1, 0, 0, 10, 6, 13, 6, 11, 6, 85, 1, 88, 1, 86, 1, 0, +0, 12, 6, 14, 6, 15, 6, 87, 1, 89, 1, 90, 1, 0, 0, 12, 6, 15, 6, 13, +6, 87, 1, 90, 1, 88, 1, 0, 0, 14, 6, 16, 6, 17, 6, 89, 1, 91, 1, 92, +1, 0, 0, 14, 6, 17, 6, 15, 6, 89, 1, 92, 1, 90, 1, 0, 0, 16, 6, 18, +6, 19, 6, 91, 1, 93, 1, 94, 1, 0, 0, 16, 6, 19, 6, 17, 6, 91, 1, 94, +1, 92, 1, 0, 0, 18, 6, 20, 6, 21, 6, 93, 1, 95, 1, 96, 1, 0, 0, 18, +6, 21, 6, 19, 6, 93, 1, 96, 1, 94, 1, 0, 0, 20, 6, 22, 6, 23, 6, 97, +1, 98, 1, 97, 1, 0, 0, 20, 6, 23, 6, 21, 6, 97, 1, 97, 1, 98, 1, 0, +0, 22, 6, 24, 6, 25, 6, 99, 1, 100, 1, 99, 1, 0, 0, 22, 6, 25, 6, 23, +6, 99, 1, 99, 1, 100, 1, 0, 0, 24, 6, 26, 6, 27, 6, 101, 1, 102, 1, 101, +1, 0, 0, 24, 6, 27, 6, 25, 6, 101, 1, 101, 1, 102, 1, 0, 0, 26, 6, 28, +6, 29, 6, 103, 1, 104, 1, 103, 1, 0, 0, 26, 6, 29, 6, 27, 6, 103, 1, 103, +1, 104, 1, 0, 0, 28, 6, 30, 6, 31, 6, 105, 1, 106, 1, 105, 1, 0, 0, 28, +6, 31, 6, 29, 6, 105, 1, 105, 1, 106, 1, 0, 0, 30, 6, 32, 6, 33, 6, 107, +1, 108, 1, 107, 1, 0, 0, 30, 6, 33, 6, 31, 6, 107, 1, 107, 1, 108, 1, 0, +0, 32, 6, 34, 6, 35, 6, 109, 1, 110, 1, 109, 1, 0, 0, 32, 6, 35, 6, 33, +6, 109, 1, 109, 1, 110, 1, 0, 0, 34, 6, 36, 6, 37, 6, 111, 1, 112, 1, 111, +1, 0, 0, 34, 6, 37, 6, 35, 6, 111, 1, 111, 1, 112, 1, 0, 0, 36, 6, 38, +6, 39, 6, 113, 1, 114, 1, 113, 1, 0, 0, 36, 6, 39, 6, 37, 6, 113, 1, 113, +1, 114, 1, 0, 0, 38, 6, 40, 6, 41, 6, 115, 1, 116, 1, 115, 1, 0, 0, 38, +6, 41, 6, 39, 6, 115, 1, 115, 1, 116, 1, 0, 0, 40, 6, 42, 6, 43, 6, 117, +1, 118, 1, 117, 1, 0, 0, 40, 6, 43, 6, 41, 6, 117, 1, 117, 1, 118, 1, 0, +0, 42, 6, 44, 6, 45, 6, 119, 1, 120, 1, 119, 1, 0, 0, 42, 6, 45, 6, 43, +6, 119, 1, 119, 1, 120, 1, 0, 0, 44, 6, 46, 6, 47, 6, 121, 1, 122, 1, 121, +1, 0, 0, 44, 6, 47, 6, 45, 6, 121, 1, 121, 1, 122, 1, 0, 0, 46, 6, 48, +6, 49, 6, 123, 1, 124, 1, 123, 1, 0, 0, 46, 6, 49, 6, 47, 6, 123, 1, 123, +1, 124, 1, 0, 0, 48, 6, 50, 6, 51, 6, 192, 0, 125, 1, 192, 0, 0, 0, 48, +6, 51, 6, 49, 6, 192, 0, 192, 0, 125, 1, 0, 0, 50, 6, 52, 6, 53, 6, 126, +1, 127, 1, 126, 1, 0, 0, 50, 6, 53, 6, 51, 6, 126, 1, 126, 1, 127, 1, 0, +0, 52, 6, 54, 6, 55, 6, 128, 1, 129, 1, 128, 1, 0, 0, 52, 6, 55, 6, 53, +6, 128, 1, 128, 1, 129, 1, 0, 0, 54, 6, 56, 6, 57, 6, 130, 1, 131, 1, 130, +1, 0, 0, 54, 6, 57, 6, 55, 6, 130, 1, 130, 1, 131, 1, 0, 0, 56, 6, 58, +6, 59, 6, 132, 1, 133, 1, 132, 1, 0, 0, 56, 6, 59, 6, 57, 6, 132, 1, 132, +1, 133, 1, 0, 0, 58, 6, 60, 6, 61, 6, 134, 1, 135, 1, 134, 1, 0, 0, 58, +6, 61, 6, 59, 6, 134, 1, 134, 1, 135, 1, 0, 0, 60, 6, 62, 6, 63, 6, 136, +1, 137, 1, 136, 1, 0, 0, 60, 6, 63, 6, 61, 6, 136, 1, 136, 1, 137, 1, 0, +0, 62, 6, 64, 6, 65, 6, 138, 1, 139, 1, 138, 1, 0, 0, 62, 6, 65, 6, 63, +6, 138, 1, 138, 1, 139, 1, 0, 0, 64, 6, 66, 6, 67, 6, 140, 1, 141, 1, 140, +1, 0, 0, 64, 6, 67, 6, 65, 6, 140, 1, 140, 1, 141, 1, 0, 0, 66, 6, 210, +5, 213, 5, 142, 1, 47, 1, 142, 1, 0, 0, 66, 6, 213, 5, 67, 6, 142, 1, 142, +1, 47, 1, 0, 0, 238, 5, 242, 5, 240, 5, 143, 1, 7, 1, 144, 1, 0, 0, 236, +5, 242, 5, 238, 5, 145, 1, 7, 1, 143, 1, 0, 0, 236, 5, 244, 5, 242, 5, 145, +1, 146, 1, 7, 1, 0, 0, 44, 6, 48, 6, 46, 6, 147, 1, 148, 1, 149, 1, 0, +0, 44, 6, 50, 6, 48, 6, 147, 1, 150, 1, 148, 1, 0, 0, 44, 6, 52, 6, 50, +6, 147, 1, 151, 1, 150, 1, 0, 0, 44, 6, 54, 6, 52, 6, 147, 1, 152, 1, 151, +1, 0, 0, 44, 6, 56, 6, 54, 6, 147, 1, 153, 1, 152, 1, 0, 0, 234, 5, 244, +5, 236, 5, 154, 1, 146, 1, 145, 1, 0, 0, 234, 5, 246, 5, 244, 5, 154, 1, 155, +1, 146, 1, 0, 0, 232, 5, 246, 5, 234, 5, 156, 1, 155, 1, 154, 1, 0, 0, 232, +5, 248, 5, 246, 5, 156, 1, 157, 1, 155, 1, 0, 0, 232, 5, 250, 5, 248, 5, 156, +1, 158, 1, 157, 1, 0, 0, 232, 5, 252, 5, 250, 5, 156, 1, 159, 1, 158, 1, 0, +0, 232, 5, 254, 5, 252, 5, 156, 1, 160, 1, 159, 1, 0, 0, 230, 5, 254, 5, 232, +5, 161, 1, 160, 1, 156, 1, 0, 0, 230, 5, 0, 6, 254, 5, 161, 1, 162, 1, 160, +1, 0, 0, 230, 5, 2, 6, 0, 6, 161, 1, 163, 1, 162, 1, 0, 0, 230, 5, 4, +6, 2, 6, 161, 1, 164, 1, 163, 1, 0, 0, 230, 5, 6, 6, 4, 6, 161, 1, 165, +1, 164, 1, 0, 0, 230, 5, 8, 6, 6, 6, 161, 1, 166, 1, 165, 1, 0, 0, 230, +5, 10, 6, 8, 6, 161, 1, 167, 1, 166, 1, 0, 0, 230, 5, 12, 6, 10, 6, 161, +1, 168, 1, 167, 1, 0, 0, 230, 5, 14, 6, 12, 6, 161, 1, 169, 1, 168, 1, 0, +0, 230, 5, 16, 6, 14, 6, 161, 1, 170, 1, 169, 1, 0, 0, 230, 5, 18, 6, 16, +6, 161, 1, 171, 1, 170, 1, 0, 0, 230, 5, 20, 6, 18, 6, 161, 1, 172, 1, 171, +1, 0, 0, 230, 5, 22, 6, 20, 6, 161, 1, 173, 1, 172, 1, 0, 0, 230, 5, 24, +6, 22, 6, 161, 1, 174, 1, 173, 1, 0, 0, 228, 5, 24, 6, 230, 5, 175, 1, 174, +1, 161, 1, 0, 0, 228, 5, 26, 6, 24, 6, 175, 1, 176, 1, 174, 1, 0, 0, 228, +5, 28, 6, 26, 6, 175, 1, 177, 1, 176, 1, 0, 0, 228, 5, 30, 6, 28, 6, 175, +1, 178, 1, 177, 1, 0, 0, 228, 5, 32, 6, 30, 6, 175, 1, 179, 1, 178, 1, 0, +0, 226, 5, 32, 6, 228, 5, 180, 1, 179, 1, 175, 1, 0, 0, 226, 5, 34, 6, 32, +6, 180, 1, 181, 1, 179, 1, 0, 0, 226, 5, 36, 6, 34, 6, 180, 1, 182, 1, 181, +1, 0, 0, 224, 5, 36, 6, 226, 5, 183, 1, 182, 1, 180, 1, 0, 0, 222, 5, 36, +6, 224, 5, 156, 1, 182, 1, 183, 1, 0, 0, 220, 5, 36, 6, 222, 5, 184, 1, 182, +1, 156, 1, 0, 0, 218, 5, 36, 6, 220, 5, 185, 1, 182, 1, 184, 1, 0, 0, 216, +5, 36, 6, 218, 5, 186, 1, 182, 1, 185, 1, 0, 0, 216, 5, 38, 6, 36, 6, 186, +1, 187, 1, 182, 1, 0, 0, 214, 5, 38, 6, 216, 5, 188, 1, 187, 1, 186, 1, 0, +0, 211, 5, 38, 6, 214, 5, 189, 1, 187, 1, 188, 1, 0, 0, 210, 5, 38, 6, 211, +5, 185, 1, 187, 1, 189, 1, 0, 0, 66, 6, 38, 6, 210, 5, 190, 1, 187, 1, 185, +1, 0, 0, 64, 6, 38, 6, 66, 6, 191, 1, 187, 1, 190, 1, 0, 0, 64, 6, 40, +6, 38, 6, 191, 1, 116, 0, 187, 1, 0, 0, 62, 6, 40, 6, 64, 6, 192, 1, 116, +0, 191, 1, 0, 0, 60, 6, 40, 6, 62, 6, 193, 1, 116, 0, 192, 1, 0, 0, 58, +6, 40, 6, 60, 6, 160, 1, 116, 0, 193, 1, 0, 0, 56, 6, 40, 6, 58, 6, 153, +1, 116, 0, 160, 1, 0, 0, 44, 6, 40, 6, 56, 6, 147, 1, 116, 0, 153, 1, 0, +0, 44, 6, 42, 6, 40, 6, 147, 1, 3, 1, 116, 0, 0, 0, 239, 5, 241, 5, 243, +5, 194, 1, 195, 1, 196, 1, 0, 0, 237, 5, 239, 5, 243, 5, 197, 1, 194, 1, 196, +1, 0, 0, 237, 5, 243, 5, 245, 5, 197, 1, 196, 1, 198, 1, 0, 0, 45, 6, 47, +6, 49, 6, 199, 1, 200, 1, 201, 1, 0, 0, 45, 6, 49, 6, 51, 6, 199, 1, 201, +1, 202, 1, 0, 0, 45, 6, 51, 6, 53, 6, 199, 1, 202, 1, 203, 1, 0, 0, 45, +6, 53, 6, 55, 6, 199, 1, 203, 1, 204, 1, 0, 0, 45, 6, 55, 6, 57, 6, 199, +1, 204, 1, 205, 1, 0, 0, 235, 5, 237, 5, 245, 5, 206, 1, 197, 1, 198, 1, 0, +0, 235, 5, 245, 5, 247, 5, 206, 1, 198, 1, 207, 1, 0, 0, 233, 5, 235, 5, 247, +5, 208, 1, 206, 1, 207, 1, 0, 0, 233, 5, 247, 5, 249, 5, 208, 1, 207, 1, 209, +1, 0, 0, 233, 5, 249, 5, 251, 5, 208, 1, 209, 1, 210, 1, 0, 0, 233, 5, 251, +5, 253, 5, 208, 1, 210, 1, 211, 1, 0, 0, 233, 5, 253, 5, 255, 5, 208, 1, 211, +1, 212, 1, 0, 0, 231, 5, 233, 5, 255, 5, 216, 0, 208, 1, 212, 1, 0, 0, 231, +5, 255, 5, 1, 6, 216, 0, 212, 1, 213, 1, 0, 0, 231, 5, 1, 6, 3, 6, 216, +0, 213, 1, 214, 1, 0, 0, 231, 5, 3, 6, 5, 6, 216, 0, 214, 1, 215, 1, 0, +0, 231, 5, 5, 6, 7, 6, 216, 0, 215, 1, 216, 1, 0, 0, 231, 5, 7, 6, 9, +6, 216, 0, 216, 1, 217, 1, 0, 0, 231, 5, 9, 6, 11, 6, 216, 0, 217, 1, 218, +1, 0, 0, 231, 5, 11, 6, 13, 6, 216, 0, 218, 1, 219, 1, 0, 0, 231, 5, 13, +6, 15, 6, 216, 0, 219, 1, 220, 1, 0, 0, 231, 5, 15, 6, 17, 6, 216, 0, 220, +1, 221, 1, 0, 0, 231, 5, 17, 6, 19, 6, 216, 0, 221, 1, 116, 1, 0, 0, 231, +5, 19, 6, 21, 6, 216, 0, 116, 1, 222, 1, 0, 0, 231, 5, 21, 6, 23, 6, 216, +0, 222, 1, 152, 0, 0, 0, 231, 5, 23, 6, 25, 6, 216, 0, 152, 0, 223, 1, 0, +0, 229, 5, 231, 5, 25, 6, 224, 1, 216, 0, 223, 1, 0, 0, 229, 5, 25, 6, 27, +6, 224, 1, 223, 1, 225, 1, 0, 0, 229, 5, 27, 6, 29, 6, 224, 1, 225, 1, 131, +0, 0, 0, 229, 5, 29, 6, 31, 6, 224, 1, 131, 0, 226, 1, 0, 0, 229, 5, 31, +6, 33, 6, 224, 1, 226, 1, 140, 0, 0, 0, 227, 5, 229, 5, 33, 6, 227, 1, 224, +1, 140, 0, 0, 0, 227, 5, 33, 6, 35, 6, 227, 1, 140, 0, 128, 0, 0, 0, 227, +5, 35, 6, 37, 6, 227, 1, 128, 0, 228, 1, 0, 0, 225, 5, 227, 5, 37, 6, 229, +1, 227, 1, 228, 1, 0, 0, 223, 5, 225, 5, 37, 6, 230, 1, 229, 1, 228, 1, 0, +0, 221, 5, 223, 5, 37, 6, 231, 1, 230, 1, 228, 1, 0, 0, 219, 5, 221, 5, 37, +6, 232, 1, 231, 1, 228, 1, 0, 0, 217, 5, 219, 5, 37, 6, 145, 0, 232, 1, 228, +1, 0, 0, 217, 5, 37, 6, 39, 6, 145, 0, 228, 1, 233, 1, 0, 0, 215, 5, 217, +5, 39, 6, 234, 1, 145, 0, 233, 1, 0, 0, 212, 5, 215, 5, 39, 6, 235, 1, 234, +1, 233, 1, 0, 0, 213, 5, 212, 5, 39, 6, 232, 1, 235, 1, 233, 1, 0, 0, 67, +6, 213, 5, 39, 6, 236, 1, 232, 1, 233, 1, 0, 0, 65, 6, 67, 6, 39, 6, 237, +1, 236, 1, 233, 1, 0, 0, 65, 6, 39, 6, 41, 6, 237, 1, 233, 1, 238, 1, 0, +0, 63, 6, 65, 6, 41, 6, 239, 1, 237, 1, 238, 1, 0, 0, 61, 6, 63, 6, 41, +6, 240, 1, 239, 1, 238, 1, 0, 0, 59, 6, 61, 6, 41, 6, 212, 1, 240, 1, 238, +1, 0, 0, 57, 6, 59, 6, 41, 6, 205, 1, 212, 1, 238, 1, 0, 0, 45, 6, 57, +6, 41, 6, 199, 1, 205, 1, 238, 1, 0, 0, 45, 6, 41, 6, 43, 6, 199, 1, 238, +1, 191, 0, 0, 0, 68, 6, 69, 6, 70, 6, 241, 1, 242, 1, 241, 1, 0, 0, 68, +6, 70, 6, 71, 6, 241, 1, 241, 1, 242, 1, 0, 0, 69, 6, 72, 6, 73, 6, 243, +1, 244, 1, 243, 1, 0, 0, 69, 6, 73, 6, 70, 6, 243, 1, 243, 1, 244, 1, 0, +0, 72, 6, 74, 6, 75, 6, 245, 1, 246, 1, 245, 1, 0, 0, 72, 6, 75, 6, 73, +6, 245, 1, 245, 1, 246, 1, 0, 0, 74, 6, 68, 6, 71, 6, 247, 1, 248, 1, 247, +1, 0, 0, 74, 6, 71, 6, 75, 6, 247, 1, 247, 1, 248, 1, 0, 0, 76, 6, 77, +6, 78, 6, 249, 1, 250, 1, 249, 1, 0, 0, 76, 6, 78, 6, 79, 6, 249, 1, 249, +1, 250, 1, 0, 0, 77, 6, 80, 6, 81, 6, 243, 1, 244, 1, 243, 1, 0, 0, 77, +6, 81, 6, 78, 6, 243, 1, 243, 1, 244, 1, 0, 0, 80, 6, 82, 6, 83, 6, 251, +1, 252, 1, 251, 1, 0, 0, 80, 6, 83, 6, 81, 6, 251, 1, 251, 1, 252, 1, 0, +0, 82, 6, 76, 6, 79, 6, 247, 1, 248, 1, 247, 1, 0, 0, 82, 6, 79, 6, 83, +6, 247, 1, 247, 1, 248, 1, 0, 0, 72, 6, 68, 6, 74, 6, 253, 1, 253, 1, 112, +0, 0, 0, 69, 6, 68, 6, 72, 6, 112, 0, 253, 1, 253, 1, 0, 0, 80, 6, 76, +6, 82, 6, 254, 1, 254, 1, 255, 1, 0, 0, 80, 6, 77, 6, 76, 6, 254, 1, 255, +1, 254, 1, 0, 0, 73, 6, 75, 6, 71, 6, 0, 2, 219, 0, 0, 2, 0, 0, 70, +6, 73, 6, 71, 6, 219, 0, 0, 2, 0, 2, 0, 0, 81, 6, 83, 6, 79, 6, 1, +2, 2, 2, 1, 2, 0, 0, 81, 6, 79, 6, 78, 6, 1, 2, 1, 2, 2, 2, 0, +0, 84, 6, 85, 6, 86, 6, 3, 2, 4, 2, 3, 2, 0, 0, 84, 6, 86, 6, 87, +6, 3, 2, 3, 2, 4, 2, 0, 0, 85, 6, 88, 6, 89, 6, 5, 2, 6, 2, 5, +2, 0, 0, 85, 6, 89, 6, 86, 6, 5, 2, 5, 2, 6, 2, 0, 0, 88, 6, 90, +6, 91, 6, 7, 2, 8, 2, 7, 2, 0, 0, 88, 6, 91, 6, 89, 6, 7, 2, 7, +2, 8, 2, 0, 0, 90, 6, 92, 6, 93, 6, 9, 2, 10, 2, 9, 2, 0, 0, 90, +6, 93, 6, 91, 6, 9, 2, 9, 2, 10, 2, 0, 0, 92, 6, 94, 6, 95, 6, 11, +2, 12, 2, 11, 2, 0, 0, 92, 6, 95, 6, 93, 6, 11, 2, 11, 2, 12, 2, 0, +0, 94, 6, 96, 6, 97, 6, 13, 2, 14, 2, 13, 2, 0, 0, 94, 6, 97, 6, 95, +6, 13, 2, 13, 2, 14, 2, 0, 0, 96, 6, 98, 6, 99, 6, 15, 2, 16, 2, 15, +2, 0, 0, 96, 6, 99, 6, 97, 6, 15, 2, 15, 2, 16, 2, 0, 0, 98, 6, 100, +6, 101, 6, 17, 2, 18, 2, 17, 2, 0, 0, 98, 6, 101, 6, 99, 6, 17, 2, 17, +2, 18, 2, 0, 0, 100, 6, 102, 6, 103, 6, 19, 2, 20, 2, 19, 2, 0, 0, 100, +6, 103, 6, 101, 6, 19, 2, 19, 2, 20, 2, 0, 0, 102, 6, 104, 6, 105, 6, 21, +2, 22, 2, 21, 2, 0, 0, 102, 6, 105, 6, 103, 6, 21, 2, 21, 2, 22, 2, 0, +0, 104, 6, 106, 6, 107, 6, 23, 2, 24, 2, 23, 2, 0, 0, 104, 6, 107, 6, 105, +6, 23, 2, 23, 2, 24, 2, 0, 0, 106, 6, 108, 6, 109, 6, 25, 2, 26, 2, 25, +2, 0, 0, 106, 6, 109, 6, 107, 6, 25, 2, 25, 2, 26, 2, 0, 0, 108, 6, 110, +6, 111, 6, 27, 2, 28, 2, 27, 2, 0, 0, 108, 6, 111, 6, 109, 6, 27, 2, 27, +2, 28, 2, 0, 0, 110, 6, 112, 6, 113, 6, 29, 2, 30, 2, 29, 2, 0, 0, 110, +6, 113, 6, 111, 6, 29, 2, 29, 2, 30, 2, 0, 0, 112, 6, 114, 6, 115, 6, 31, +2, 32, 2, 31, 2, 0, 0, 112, 6, 115, 6, 113, 6, 31, 2, 31, 2, 32, 2, 0, +0, 114, 6, 116, 6, 117, 6, 59, 1, 60, 1, 59, 1, 0, 0, 114, 6, 117, 6, 115, +6, 59, 1, 59, 1, 60, 1, 0, 0, 116, 6, 118, 6, 119, 6, 33, 2, 34, 2, 33, +2, 0, 0, 116, 6, 119, 6, 117, 6, 33, 2, 33, 2, 34, 2, 0, 0, 118, 6, 120, +6, 121, 6, 35, 2, 36, 2, 35, 2, 0, 0, 118, 6, 121, 6, 119, 6, 35, 2, 35, +2, 36, 2, 0, 0, 120, 6, 122, 6, 123, 6, 37, 2, 38, 2, 37, 2, 0, 0, 120, +6, 123, 6, 121, 6, 37, 2, 37, 2, 38, 2, 0, 0, 122, 6, 124, 6, 125, 6, 39, +2, 40, 2, 39, 2, 0, 0, 122, 6, 125, 6, 123, 6, 39, 2, 39, 2, 40, 2, 0, +0, 124, 6, 126, 6, 127, 6, 41, 2, 42, 2, 41, 2, 0, 0, 124, 6, 127, 6, 125, +6, 41, 2, 41, 2, 42, 2, 0, 0, 126, 6, 128, 6, 129, 6, 43, 2, 44, 2, 43, +2, 0, 0, 126, 6, 129, 6, 127, 6, 43, 2, 43, 2, 44, 2, 0, 0, 128, 6, 130, +6, 131, 6, 45, 2, 46, 2, 45, 2, 0, 0, 128, 6, 131, 6, 129, 6, 45, 2, 45, +2, 46, 2, 0, 0, 130, 6, 132, 6, 133, 6, 47, 2, 48, 2, 47, 2, 0, 0, 130, +6, 133, 6, 131, 6, 47, 2, 47, 2, 48, 2, 0, 0, 132, 6, 134, 6, 135, 6, 49, +2, 50, 2, 49, 2, 0, 0, 132, 6, 135, 6, 133, 6, 49, 2, 49, 2, 50, 2, 0, +0, 134, 6, 136, 6, 137, 6, 51, 2, 52, 2, 53, 2, 0, 0, 134, 6, 137, 6, 135, +6, 51, 2, 53, 2, 54, 2, 0, 0, 136, 6, 138, 6, 139, 6, 52, 2, 55, 2, 56, +2, 0, 0, 136, 6, 139, 6, 137, 6, 52, 2, 56, 2, 53, 2, 0, 0, 138, 6, 140, +6, 141, 6, 55, 2, 57, 2, 58, 2, 0, 0, 138, 6, 141, 6, 139, 6, 55, 2, 58, +2, 56, 2, 0, 0, 140, 6, 142, 6, 143, 6, 57, 2, 59, 2, 60, 2, 0, 0, 140, +6, 143, 6, 141, 6, 57, 2, 60, 2, 58, 2, 0, 0, 142, 6, 144, 6, 145, 6, 59, +2, 61, 2, 62, 2, 0, 0, 142, 6, 145, 6, 143, 6, 59, 2, 62, 2, 60, 2, 0, +0, 144, 6, 146, 6, 147, 6, 61, 2, 63, 2, 64, 2, 0, 0, 144, 6, 147, 6, 145, +6, 61, 2, 64, 2, 62, 2, 0, 0, 146, 6, 148, 6, 149, 6, 63, 2, 65, 2, 66, +2, 0, 0, 146, 6, 149, 6, 147, 6, 63, 2, 66, 2, 64, 2, 0, 0, 148, 6, 150, +6, 151, 6, 65, 2, 67, 2, 68, 2, 0, 0, 148, 6, 151, 6, 149, 6, 65, 2, 68, +2, 66, 2, 0, 0, 150, 6, 152, 6, 153, 6, 69, 2, 70, 2, 69, 2, 0, 0, 150, +6, 153, 6, 151, 6, 69, 2, 69, 2, 70, 2, 0, 0, 152, 6, 154, 6, 155, 6, 71, +2, 72, 2, 71, 2, 0, 0, 152, 6, 155, 6, 153, 6, 71, 2, 71, 2, 72, 2, 0, +0, 154, 6, 156, 6, 157, 6, 73, 2, 74, 2, 73, 2, 0, 0, 154, 6, 157, 6, 155, +6, 73, 2, 73, 2, 74, 2, 0, 0, 156, 6, 158, 6, 159, 6, 75, 2, 76, 2, 75, +2, 0, 0, 156, 6, 159, 6, 157, 6, 75, 2, 75, 2, 76, 2, 0, 0, 158, 6, 160, +6, 161, 6, 77, 2, 78, 2, 77, 2, 0, 0, 158, 6, 161, 6, 159, 6, 77, 2, 77, +2, 78, 2, 0, 0, 160, 6, 162, 6, 163, 6, 79, 2, 80, 2, 79, 2, 0, 0, 160, +6, 163, 6, 161, 6, 79, 2, 79, 2, 80, 2, 0, 0, 162, 6, 164, 6, 165, 6, 81, +2, 82, 2, 81, 2, 0, 0, 162, 6, 165, 6, 163, 6, 81, 2, 81, 2, 82, 2, 0, +0, 164, 6, 166, 6, 167, 6, 111, 1, 112, 1, 111, 1, 0, 0, 164, 6, 167, 6, 165, +6, 111, 1, 111, 1, 112, 1, 0, 0, 166, 6, 168, 6, 169, 6, 83, 2, 84, 2, 83, +2, 0, 0, 166, 6, 169, 6, 167, 6, 83, 2, 83, 2, 84, 2, 0, 0, 168, 6, 170, +6, 171, 6, 85, 2, 86, 2, 85, 2, 0, 0, 168, 6, 171, 6, 169, 6, 85, 2, 85, +2, 86, 2, 0, 0, 170, 6, 172, 6, 173, 6, 87, 2, 88, 2, 87, 2, 0, 0, 170, +6, 173, 6, 171, 6, 87, 2, 87, 2, 88, 2, 0, 0, 172, 6, 174, 6, 175, 6, 89, +2, 90, 2, 89, 2, 0, 0, 172, 6, 175, 6, 173, 6, 89, 2, 89, 2, 90, 2, 0, +0, 174, 6, 176, 6, 177, 6, 121, 1, 122, 1, 121, 1, 0, 0, 174, 6, 177, 6, 175, +6, 121, 1, 121, 1, 122, 1, 0, 0, 176, 6, 178, 6, 179, 6, 91, 2, 92, 2, 91, +2, 0, 0, 176, 6, 179, 6, 177, 6, 91, 2, 91, 2, 92, 2, 0, 0, 178, 6, 180, +6, 181, 6, 93, 2, 94, 2, 93, 2, 0, 0, 178, 6, 181, 6, 179, 6, 93, 2, 93, +2, 94, 2, 0, 0, 180, 6, 182, 6, 183, 6, 95, 2, 96, 2, 95, 2, 0, 0, 180, +6, 183, 6, 181, 6, 95, 2, 95, 2, 96, 2, 0, 0, 182, 6, 184, 6, 185, 6, 97, +2, 98, 2, 97, 2, 0, 0, 182, 6, 185, 6, 183, 6, 97, 2, 97, 2, 98, 2, 0, +0, 184, 6, 186, 6, 187, 6, 99, 2, 100, 2, 99, 2, 0, 0, 184, 6, 187, 6, 185, +6, 99, 2, 99, 2, 100, 2, 0, 0, 186, 6, 188, 6, 189, 6, 101, 2, 102, 2, 101, +2, 0, 0, 186, 6, 189, 6, 187, 6, 101, 2, 101, 2, 102, 2, 0, 0, 188, 6, 190, +6, 191, 6, 103, 2, 104, 2, 103, 2, 0, 0, 188, 6, 191, 6, 189, 6, 103, 2, 103, +2, 104, 2, 0, 0, 190, 6, 192, 6, 193, 6, 105, 2, 106, 2, 105, 2, 0, 0, 190, +6, 193, 6, 191, 6, 105, 2, 105, 2, 106, 2, 0, 0, 192, 6, 194, 6, 195, 6, 107, +2, 108, 2, 107, 2, 0, 0, 192, 6, 195, 6, 193, 6, 107, 2, 107, 2, 108, 2, 0, +0, 194, 6, 196, 6, 197, 6, 109, 2, 110, 2, 109, 2, 0, 0, 194, 6, 197, 6, 195, +6, 109, 2, 109, 2, 110, 2, 0, 0, 196, 6, 84, 6, 87, 6, 111, 2, 21, 2, 111, +2, 0, 0, 196, 6, 87, 6, 197, 6, 111, 2, 111, 2, 21, 2, 0, 0, 112, 6, 116, +6, 114, 6, 112, 2, 113, 2, 114, 2, 0, 0, 110, 6, 116, 6, 112, 6, 115, 2, 113, +2, 112, 2, 0, 0, 110, 6, 118, 6, 116, 6, 115, 2, 116, 2, 113, 2, 0, 0, 174, +6, 178, 6, 176, 6, 117, 2, 118, 2, 119, 2, 0, 0, 174, 6, 180, 6, 178, 6, 117, +2, 120, 2, 118, 2, 0, 0, 174, 6, 182, 6, 180, 6, 117, 2, 121, 2, 120, 2, 0, +0, 174, 6, 184, 6, 182, 6, 117, 2, 122, 2, 121, 2, 0, 0, 174, 6, 186, 6, 184, +6, 117, 2, 123, 2, 122, 2, 0, 0, 108, 6, 118, 6, 110, 6, 124, 2, 116, 2, 115, +2, 0, 0, 108, 6, 120, 6, 118, 6, 124, 2, 125, 2, 116, 2, 0, 0, 106, 6, 120, +6, 108, 6, 126, 2, 125, 2, 124, 2, 0, 0, 106, 6, 122, 6, 120, 6, 126, 2, 127, +2, 125, 2, 0, 0, 106, 6, 124, 6, 122, 6, 126, 2, 116, 2, 127, 2, 0, 0, 106, +6, 126, 6, 124, 6, 126, 2, 128, 2, 116, 2, 0, 0, 106, 6, 128, 6, 126, 6, 126, +2, 129, 2, 128, 2, 0, 0, 104, 6, 128, 6, 106, 6, 102, 0, 129, 2, 126, 2, 0, +0, 104, 6, 130, 6, 128, 6, 102, 0, 130, 2, 129, 2, 0, 0, 104, 6, 132, 6, 130, +6, 102, 0, 131, 2, 130, 2, 0, 0, 104, 6, 134, 6, 132, 6, 102, 0, 132, 2, 131, +2, 0, 0, 104, 6, 136, 6, 134, 6, 102, 0, 133, 2, 132, 2, 0, 0, 104, 6, 138, +6, 136, 6, 102, 0, 134, 2, 133, 2, 0, 0, 104, 6, 140, 6, 138, 6, 102, 0, 135, +2, 134, 2, 0, 0, 104, 6, 142, 6, 140, 6, 102, 0, 136, 2, 135, 2, 0, 0, 104, +6, 144, 6, 142, 6, 102, 0, 137, 2, 136, 2, 0, 0, 104, 6, 146, 6, 144, 6, 102, +0, 138, 2, 137, 2, 0, 0, 104, 6, 148, 6, 146, 6, 102, 0, 139, 2, 138, 2, 0, +0, 104, 6, 150, 6, 148, 6, 102, 0, 140, 2, 139, 2, 0, 0, 104, 6, 152, 6, 150, +6, 102, 0, 157, 1, 140, 2, 0, 0, 104, 6, 154, 6, 152, 6, 102, 0, 98, 0, 157, +1, 0, 0, 102, 6, 154, 6, 104, 6, 141, 2, 98, 0, 102, 0, 0, 0, 102, 6, 156, +6, 154, 6, 141, 2, 189, 1, 98, 0, 0, 0, 102, 6, 158, 6, 156, 6, 141, 2, 185, +1, 189, 1, 0, 0, 102, 6, 160, 6, 158, 6, 141, 2, 142, 2, 185, 1, 0, 0, 102, +6, 162, 6, 160, 6, 141, 2, 143, 2, 142, 2, 0, 0, 100, 6, 162, 6, 102, 6, 144, +2, 143, 2, 141, 2, 0, 0, 100, 6, 164, 6, 162, 6, 144, 2, 145, 2, 143, 2, 0, +0, 100, 6, 166, 6, 164, 6, 144, 2, 146, 2, 145, 2, 0, 0, 98, 6, 166, 6, 100, +6, 147, 2, 146, 2, 144, 2, 0, 0, 96, 6, 166, 6, 98, 6, 126, 2, 146, 2, 147, +2, 0, 0, 94, 6, 166, 6, 96, 6, 148, 2, 146, 2, 126, 2, 0, 0, 92, 6, 166, +6, 94, 6, 149, 2, 146, 2, 148, 2, 0, 0, 90, 6, 166, 6, 92, 6, 150, 2, 146, +2, 149, 2, 0, 0, 90, 6, 168, 6, 166, 6, 150, 2, 151, 2, 146, 2, 0, 0, 88, +6, 168, 6, 90, 6, 152, 2, 151, 2, 150, 2, 0, 0, 85, 6, 168, 6, 88, 6, 193, +1, 151, 2, 152, 2, 0, 0, 84, 6, 168, 6, 85, 6, 149, 2, 151, 2, 193, 1, 0, +0, 196, 6, 168, 6, 84, 6, 101, 0, 151, 2, 149, 2, 0, 0, 194, 6, 168, 6, 196, +6, 153, 2, 151, 2, 101, 0, 0, 0, 194, 6, 170, 6, 168, 6, 153, 2, 104, 0, 151, +2, 0, 0, 192, 6, 170, 6, 194, 6, 154, 2, 104, 0, 153, 2, 0, 0, 190, 6, 170, +6, 192, 6, 155, 2, 104, 0, 154, 2, 0, 0, 188, 6, 170, 6, 190, 6, 129, 2, 104, +0, 155, 2, 0, 0, 186, 6, 170, 6, 188, 6, 123, 2, 104, 0, 129, 2, 0, 0, 174, +6, 170, 6, 186, 6, 117, 2, 104, 0, 123, 2, 0, 0, 174, 6, 172, 6, 170, 6, 117, +2, 3, 1, 104, 0, 0, 0, 113, 6, 115, 6, 117, 6, 156, 2, 157, 2, 158, 2, 0, +0, 111, 6, 113, 6, 117, 6, 159, 2, 156, 2, 158, 2, 0, 0, 111, 6, 117, 6, 119, +6, 159, 2, 158, 2, 235, 1, 0, 0, 175, 6, 177, 6, 179, 6, 160, 2, 161, 2, 162, +2, 0, 0, 175, 6, 179, 6, 181, 6, 160, 2, 162, 2, 163, 2, 0, 0, 175, 6, 181, +6, 183, 6, 160, 2, 163, 2, 156, 0, 0, 0, 175, 6, 183, 6, 185, 6, 160, 2, 156, +0, 164, 2, 0, 0, 175, 6, 185, 6, 187, 6, 160, 2, 164, 2, 165, 2, 0, 0, 109, +6, 111, 6, 119, 6, 166, 2, 159, 2, 235, 1, 0, 0, 109, 6, 119, 6, 121, 6, 166, +2, 235, 1, 167, 2, 0, 0, 107, 6, 109, 6, 121, 6, 210, 0, 166, 2, 167, 2, 0, +0, 107, 6, 121, 6, 123, 6, 210, 0, 167, 2, 148, 0, 0, 0, 107, 6, 123, 6, 125, +6, 210, 0, 148, 0, 168, 2, 0, 0, 107, 6, 125, 6, 127, 6, 210, 0, 168, 2, 169, +2, 0, 0, 107, 6, 127, 6, 129, 6, 210, 0, 169, 2, 170, 2, 0, 0, 105, 6, 107, +6, 129, 6, 171, 2, 210, 0, 170, 2, 0, 0, 105, 6, 129, 6, 131, 6, 171, 2, 170, +2, 172, 2, 0, 0, 105, 6, 131, 6, 133, 6, 171, 2, 172, 2, 173, 2, 0, 0, 105, +6, 133, 6, 135, 6, 171, 2, 173, 2, 174, 2, 0, 0, 105, 6, 135, 6, 137, 6, 171, +2, 174, 2, 175, 2, 0, 0, 105, 6, 137, 6, 139, 6, 171, 2, 175, 2, 217, 1, 0, +0, 105, 6, 139, 6, 141, 6, 171, 2, 217, 1, 218, 1, 0, 0, 105, 6, 141, 6, 143, +6, 171, 2, 218, 1, 176, 2, 0, 0, 105, 6, 143, 6, 145, 6, 171, 2, 176, 2, 177, +2, 0, 0, 105, 6, 145, 6, 147, 6, 171, 2, 177, 2, 0, 1, 0, 0, 105, 6, 147, +6, 149, 6, 171, 2, 0, 1, 178, 2, 0, 0, 105, 6, 149, 6, 151, 6, 171, 2, 178, +2, 179, 2, 0, 0, 105, 6, 151, 6, 153, 6, 171, 2, 179, 2, 180, 2, 0, 0, 105, +6, 153, 6, 155, 6, 171, 2, 180, 2, 181, 2, 0, 0, 103, 6, 105, 6, 155, 6, 182, +2, 171, 2, 181, 2, 0, 0, 103, 6, 155, 6, 157, 6, 182, 2, 181, 2, 183, 2, 0, +0, 103, 6, 157, 6, 159, 6, 182, 2, 183, 2, 184, 2, 0, 0, 103, 6, 159, 6, 161, +6, 182, 2, 184, 2, 185, 2, 0, 0, 103, 6, 161, 6, 163, 6, 182, 2, 185, 2, 186, +2, 0, 0, 101, 6, 103, 6, 163, 6, 194, 1, 182, 2, 186, 2, 0, 0, 101, 6, 163, +6, 165, 6, 194, 1, 186, 2, 187, 2, 0, 0, 101, 6, 165, 6, 167, 6, 194, 1, 187, +2, 188, 2, 0, 0, 99, 6, 101, 6, 167, 6, 189, 2, 194, 1, 188, 2, 0, 0, 97, +6, 99, 6, 167, 6, 190, 2, 189, 2, 188, 2, 0, 0, 95, 6, 97, 6, 167, 6, 191, +2, 190, 2, 188, 2, 0, 0, 93, 6, 95, 6, 167, 6, 192, 2, 191, 2, 188, 2, 0, +0, 91, 6, 93, 6, 167, 6, 193, 2, 192, 2, 188, 2, 0, 0, 91, 6, 167, 6, 169, +6, 193, 2, 188, 2, 194, 2, 0, 0, 89, 6, 91, 6, 169, 6, 195, 2, 193, 2, 194, +2, 0, 0, 86, 6, 89, 6, 169, 6, 139, 0, 195, 2, 194, 2, 0, 0, 87, 6, 86, +6, 169, 6, 165, 0, 139, 0, 194, 2, 0, 0, 197, 6, 87, 6, 169, 6, 196, 2, 165, +0, 194, 2, 0, 0, 195, 6, 197, 6, 169, 6, 197, 2, 196, 2, 194, 2, 0, 0, 195, +6, 169, 6, 171, 6, 197, 2, 194, 2, 198, 2, 0, 0, 193, 6, 195, 6, 171, 6, 199, +2, 197, 2, 198, 2, 0, 0, 191, 6, 193, 6, 171, 6, 200, 2, 199, 2, 198, 2, 0, +0, 189, 6, 191, 6, 171, 6, 170, 2, 200, 2, 198, 2, 0, 0, 187, 6, 189, 6, 171, +6, 165, 2, 170, 2, 198, 2, 0, 0, 175, 6, 187, 6, 171, 6, 160, 2, 165, 2, 198, +2, 0, 0, 175, 6, 171, 6, 173, 6, 160, 2, 198, 2, 191, 0, 0, 0, 0, 0, 1, +0, 2, 0, 201, 2, 202, 2, 203, 2, 1, 0, 3, 0, 2, 0, 4, 0, 201, 2, 203, +2, 204, 2, 1, 0, 5, 0, 4, 0, 6, 0, 201, 2, 204, 2, 205, 2, 1, 0, 7, +0, 6, 0, 8, 0, 201, 2, 205, 2, 206, 2, 1, 0, 9, 0, 8, 0, 10, 0, 201, +2, 206, 2, 207, 2, 1, 0, 11, 0, 10, 0, 12, 0, 201, 2, 207, 2, 208, 2, 1, +0, 13, 0, 12, 0, 14, 0, 201, 2, 208, 2, 209, 2, 1, 0, 15, 0, 14, 0, 16, +0, 201, 2, 209, 2, 210, 2, 1, 0, 17, 0, 16, 0, 18, 0, 201, 2, 210, 2, 211, +2, 1, 0, 19, 0, 18, 0, 20, 0, 201, 2, 211, 2, 212, 2, 1, 0, 21, 0, 20, +0, 22, 0, 201, 2, 212, 2, 213, 2, 1, 0, 23, 0, 22, 0, 24, 0, 201, 2, 213, +2, 214, 2, 1, 0, 25, 0, 24, 0, 26, 0, 201, 2, 214, 2, 215, 2, 1, 0, 27, +0, 26, 0, 28, 0, 201, 2, 215, 2, 216, 2, 1, 0, 29, 0, 28, 0, 30, 0, 201, +2, 216, 2, 217, 2, 1, 0, 31, 0, 30, 0, 32, 0, 201, 2, 217, 2, 218, 2, 1, +0, 33, 0, 32, 0, 34, 0, 201, 2, 218, 2, 219, 2, 1, 0, 35, 0, 34, 0, 36, +0, 201, 2, 219, 2, 220, 2, 1, 0, 37, 0, 36, 0, 38, 0, 201, 2, 220, 2, 221, +2, 1, 0, 39, 0, 38, 0, 40, 0, 201, 2, 221, 2, 222, 2, 1, 0, 41, 0, 40, +0, 42, 0, 201, 2, 222, 2, 223, 2, 1, 0, 43, 0, 42, 0, 44, 0, 201, 2, 223, +2, 224, 2, 1, 0, 45, 0, 44, 0, 46, 0, 201, 2, 224, 2, 225, 2, 1, 0, 47, +0, 46, 0, 48, 0, 201, 2, 225, 2, 226, 2, 1, 0, 49, 0, 48, 0, 50, 0, 201, +2, 226, 2, 227, 2, 1, 0, 51, 0, 50, 0, 52, 0, 201, 2, 227, 2, 228, 2, 1, +0, 53, 0, 52, 0, 54, 0, 201, 2, 228, 2, 229, 2, 1, 0, 55, 0, 54, 0, 56, +0, 201, 2, 229, 2, 230, 2, 1, 0, 57, 0, 56, 0, 58, 0, 201, 2, 230, 2, 231, +2, 1, 0, 59, 0, 58, 0, 60, 0, 201, 2, 231, 2, 232, 2, 1, 0, 61, 0, 60, +0, 62, 0, 201, 2, 232, 2, 233, 2, 1, 0, 63, 0, 62, 0, 64, 0, 201, 2, 233, +2, 234, 2, 1, 0, 65, 0, 64, 0, 66, 0, 201, 2, 234, 2, 235, 2, 1, 0, 67, +0, 66, 0, 68, 0, 201, 2, 235, 2, 236, 2, 1, 0, 69, 0, 68, 0, 70, 0, 201, +2, 236, 2, 237, 2, 1, 0, 71, 0, 70, 0, 72, 0, 201, 2, 237, 2, 238, 2, 1, +0, 73, 0, 72, 0, 74, 0, 201, 2, 238, 2, 239, 2, 1, 0, 75, 0, 74, 0, 76, +0, 201, 2, 239, 2, 240, 2, 1, 0, 77, 0, 76, 0, 78, 0, 201, 2, 240, 2, 241, +2, 1, 0, 79, 0, 78, 0, 80, 0, 201, 2, 241, 2, 242, 2, 1, 0, 81, 0, 80, +0, 82, 0, 201, 2, 242, 2, 243, 2, 1, 0, 83, 0, 82, 0, 84, 0, 201, 2, 243, +2, 244, 2, 1, 0, 85, 0, 84, 0, 86, 0, 201, 2, 244, 2, 245, 2, 1, 0, 87, +0, 86, 0, 88, 0, 201, 2, 245, 2, 246, 2, 1, 0, 89, 0, 88, 0, 90, 0, 201, +2, 246, 2, 247, 2, 1, 0, 91, 0, 90, 0, 92, 0, 201, 2, 247, 2, 248, 2, 1, +0, 93, 0, 92, 0, 94, 0, 201, 2, 248, 2, 249, 2, 1, 0, 95, 0, 94, 0, 96, +0, 201, 2, 249, 2, 250, 2, 1, 0, 97, 0, 96, 0, 98, 0, 201, 2, 250, 2, 251, +2, 1, 0, 99, 0, 98, 0, 100, 0, 201, 2, 251, 2, 202, 2, 1, 0, 1, 0, 101, +0, 102, 0, 202, 2, 252, 2, 253, 2, 1, 0, 1, 0, 102, 0, 2, 0, 202, 2, 253, +2, 203, 2, 1, 0, 2, 0, 102, 0, 103, 0, 203, 2, 253, 2, 254, 2, 1, 0, 2, +0, 103, 0, 4, 0, 203, 2, 254, 2, 204, 2, 1, 0, 4, 0, 103, 0, 104, 0, 204, +2, 254, 2, 255, 2, 1, 0, 4, 0, 104, 0, 6, 0, 204, 2, 255, 2, 205, 2, 1, +0, 6, 0, 104, 0, 105, 0, 205, 2, 255, 2, 0, 3, 1, 0, 6, 0, 105, 0, 8, +0, 205, 2, 0, 3, 206, 2, 1, 0, 8, 0, 105, 0, 106, 0, 206, 2, 0, 3, 1, +3, 1, 0, 8, 0, 106, 0, 10, 0, 206, 2, 1, 3, 207, 2, 1, 0, 10, 0, 106, +0, 107, 0, 207, 2, 1, 3, 2, 3, 1, 0, 10, 0, 107, 0, 12, 0, 207, 2, 2, +3, 208, 2, 1, 0, 12, 0, 107, 0, 108, 0, 208, 2, 2, 3, 3, 3, 1, 0, 12, +0, 108, 0, 14, 0, 208, 2, 3, 3, 209, 2, 1, 0, 14, 0, 108, 0, 109, 0, 209, +2, 3, 3, 4, 3, 1, 0, 14, 0, 109, 0, 16, 0, 209, 2, 4, 3, 210, 2, 1, +0, 16, 0, 109, 0, 110, 0, 210, 2, 4, 3, 5, 3, 1, 0, 16, 0, 110, 0, 18, +0, 210, 2, 5, 3, 211, 2, 1, 0, 18, 0, 110, 0, 111, 0, 211, 2, 5, 3, 6, +3, 1, 0, 18, 0, 111, 0, 20, 0, 211, 2, 6, 3, 212, 2, 1, 0, 20, 0, 111, +0, 112, 0, 212, 2, 6, 3, 7, 3, 1, 0, 20, 0, 112, 0, 22, 0, 212, 2, 7, +3, 213, 2, 1, 0, 22, 0, 112, 0, 113, 0, 213, 2, 7, 3, 8, 3, 1, 0, 22, +0, 113, 0, 24, 0, 213, 2, 8, 3, 214, 2, 1, 0, 24, 0, 113, 0, 114, 0, 214, +2, 8, 3, 9, 3, 1, 0, 24, 0, 114, 0, 26, 0, 214, 2, 9, 3, 215, 2, 1, +0, 26, 0, 114, 0, 115, 0, 215, 2, 9, 3, 10, 3, 1, 0, 26, 0, 115, 0, 28, +0, 215, 2, 10, 3, 216, 2, 1, 0, 28, 0, 115, 0, 116, 0, 216, 2, 10, 3, 11, +3, 1, 0, 28, 0, 116, 0, 30, 0, 216, 2, 11, 3, 217, 2, 1, 0, 30, 0, 116, +0, 117, 0, 217, 2, 11, 3, 12, 3, 1, 0, 30, 0, 117, 0, 32, 0, 217, 2, 12, +3, 218, 2, 1, 0, 32, 0, 117, 0, 118, 0, 218, 2, 12, 3, 13, 3, 1, 0, 32, +0, 118, 0, 34, 0, 218, 2, 13, 3, 219, 2, 1, 0, 34, 0, 118, 0, 119, 0, 219, +2, 13, 3, 14, 3, 1, 0, 34, 0, 119, 0, 36, 0, 219, 2, 14, 3, 220, 2, 1, +0, 36, 0, 119, 0, 120, 0, 220, 2, 14, 3, 15, 3, 1, 0, 36, 0, 120, 0, 38, +0, 220, 2, 15, 3, 221, 2, 1, 0, 38, 0, 120, 0, 121, 0, 221, 2, 15, 3, 16, +3, 1, 0, 38, 0, 121, 0, 40, 0, 221, 2, 16, 3, 222, 2, 1, 0, 40, 0, 121, +0, 122, 0, 222, 2, 16, 3, 17, 3, 1, 0, 40, 0, 122, 0, 42, 0, 222, 2, 17, +3, 223, 2, 1, 0, 42, 0, 122, 0, 123, 0, 223, 2, 17, 3, 18, 3, 1, 0, 42, +0, 123, 0, 44, 0, 223, 2, 18, 3, 224, 2, 1, 0, 44, 0, 123, 0, 124, 0, 224, +2, 18, 3, 19, 3, 1, 0, 44, 0, 124, 0, 46, 0, 224, 2, 19, 3, 225, 2, 1, +0, 46, 0, 124, 0, 125, 0, 225, 2, 19, 3, 20, 3, 1, 0, 46, 0, 125, 0, 48, +0, 225, 2, 20, 3, 226, 2, 1, 0, 48, 0, 125, 0, 126, 0, 226, 2, 20, 3, 21, +3, 1, 0, 48, 0, 126, 0, 50, 0, 226, 2, 21, 3, 227, 2, 1, 0, 50, 0, 126, +0, 127, 0, 227, 2, 21, 3, 22, 3, 1, 0, 50, 0, 127, 0, 52, 0, 227, 2, 22, +3, 228, 2, 1, 0, 52, 0, 127, 0, 128, 0, 228, 2, 22, 3, 23, 3, 1, 0, 52, +0, 128, 0, 54, 0, 228, 2, 23, 3, 229, 2, 1, 0, 54, 0, 128, 0, 129, 0, 229, +2, 23, 3, 24, 3, 1, 0, 54, 0, 129, 0, 56, 0, 229, 2, 24, 3, 230, 2, 1, +0, 56, 0, 129, 0, 130, 0, 230, 2, 24, 3, 25, 3, 1, 0, 56, 0, 130, 0, 58, +0, 230, 2, 25, 3, 231, 2, 1, 0, 58, 0, 130, 0, 131, 0, 231, 2, 25, 3, 26, +3, 1, 0, 58, 0, 131, 0, 60, 0, 231, 2, 26, 3, 232, 2, 1, 0, 60, 0, 131, +0, 132, 0, 232, 2, 26, 3, 27, 3, 1, 0, 60, 0, 132, 0, 62, 0, 232, 2, 27, +3, 233, 2, 1, 0, 62, 0, 132, 0, 133, 0, 233, 2, 27, 3, 28, 3, 1, 0, 62, +0, 133, 0, 64, 0, 233, 2, 28, 3, 234, 2, 1, 0, 64, 0, 133, 0, 134, 0, 234, +2, 28, 3, 29, 3, 1, 0, 64, 0, 134, 0, 66, 0, 234, 2, 29, 3, 235, 2, 1, +0, 66, 0, 134, 0, 135, 0, 235, 2, 29, 3, 30, 3, 1, 0, 66, 0, 135, 0, 68, +0, 235, 2, 30, 3, 236, 2, 1, 0, 68, 0, 135, 0, 136, 0, 236, 2, 30, 3, 31, +3, 1, 0, 68, 0, 136, 0, 70, 0, 236, 2, 31, 3, 237, 2, 1, 0, 70, 0, 136, +0, 137, 0, 237, 2, 31, 3, 32, 3, 1, 0, 70, 0, 137, 0, 72, 0, 237, 2, 32, +3, 238, 2, 1, 0, 72, 0, 137, 0, 138, 0, 238, 2, 32, 3, 33, 3, 1, 0, 72, +0, 138, 0, 74, 0, 238, 2, 33, 3, 239, 2, 1, 0, 74, 0, 138, 0, 139, 0, 239, +2, 33, 3, 34, 3, 1, 0, 74, 0, 139, 0, 76, 0, 239, 2, 34, 3, 240, 2, 1, +0, 76, 0, 139, 0, 140, 0, 240, 2, 34, 3, 35, 3, 1, 0, 76, 0, 140, 0, 78, +0, 240, 2, 35, 3, 241, 2, 1, 0, 78, 0, 140, 0, 141, 0, 241, 2, 35, 3, 36, +3, 1, 0, 78, 0, 141, 0, 80, 0, 241, 2, 36, 3, 242, 2, 1, 0, 80, 0, 141, +0, 142, 0, 242, 2, 36, 3, 37, 3, 1, 0, 80, 0, 142, 0, 82, 0, 242, 2, 37, +3, 243, 2, 1, 0, 82, 0, 142, 0, 143, 0, 243, 2, 37, 3, 38, 3, 1, 0, 82, +0, 143, 0, 84, 0, 243, 2, 38, 3, 244, 2, 1, 0, 84, 0, 143, 0, 144, 0, 244, +2, 38, 3, 39, 3, 1, 0, 84, 0, 144, 0, 86, 0, 244, 2, 39, 3, 245, 2, 1, +0, 86, 0, 144, 0, 145, 0, 245, 2, 39, 3, 40, 3, 1, 0, 86, 0, 145, 0, 88, +0, 245, 2, 40, 3, 246, 2, 1, 0, 88, 0, 145, 0, 146, 0, 246, 2, 40, 3, 41, +3, 1, 0, 88, 0, 146, 0, 90, 0, 246, 2, 41, 3, 247, 2, 1, 0, 90, 0, 146, +0, 147, 0, 247, 2, 41, 3, 42, 3, 1, 0, 90, 0, 147, 0, 92, 0, 247, 2, 42, +3, 248, 2, 1, 0, 92, 0, 147, 0, 148, 0, 248, 2, 42, 3, 43, 3, 1, 0, 92, +0, 148, 0, 94, 0, 248, 2, 43, 3, 249, 2, 1, 0, 94, 0, 148, 0, 149, 0, 249, +2, 43, 3, 44, 3, 1, 0, 94, 0, 149, 0, 96, 0, 249, 2, 44, 3, 250, 2, 1, +0, 96, 0, 149, 0, 150, 0, 250, 2, 44, 3, 45, 3, 1, 0, 96, 0, 150, 0, 98, +0, 250, 2, 45, 3, 251, 2, 1, 0, 98, 0, 150, 0, 151, 0, 251, 2, 45, 3, 252, +2, 1, 0, 98, 0, 151, 0, 100, 0, 251, 2, 252, 2, 202, 2, 1, 0, 101, 0, 152, +0, 153, 0, 252, 2, 46, 3, 47, 3, 1, 0, 101, 0, 153, 0, 102, 0, 252, 2, 47, +3, 253, 2, 1, 0, 102, 0, 153, 0, 154, 0, 253, 2, 47, 3, 48, 3, 1, 0, 102, +0, 154, 0, 103, 0, 253, 2, 48, 3, 254, 2, 1, 0, 103, 0, 154, 0, 155, 0, 254, +2, 48, 3, 49, 3, 1, 0, 103, 0, 155, 0, 104, 0, 254, 2, 49, 3, 255, 2, 1, +0, 104, 0, 155, 0, 156, 0, 255, 2, 49, 3, 50, 3, 1, 0, 104, 0, 156, 0, 105, +0, 255, 2, 50, 3, 0, 3, 1, 0, 105, 0, 156, 0, 157, 0, 0, 3, 50, 3, 51, +3, 1, 0, 105, 0, 157, 0, 106, 0, 0, 3, 51, 3, 1, 3, 1, 0, 106, 0, 157, +0, 158, 0, 1, 3, 51, 3, 52, 3, 1, 0, 106, 0, 158, 0, 107, 0, 1, 3, 52, +3, 2, 3, 1, 0, 107, 0, 158, 0, 159, 0, 2, 3, 52, 3, 53, 3, 1, 0, 107, +0, 159, 0, 108, 0, 2, 3, 53, 3, 3, 3, 1, 0, 108, 0, 159, 0, 160, 0, 3, +3, 53, 3, 54, 3, 1, 0, 108, 0, 160, 0, 109, 0, 3, 3, 54, 3, 4, 3, 1, +0, 109, 0, 160, 0, 161, 0, 4, 3, 54, 3, 55, 3, 1, 0, 109, 0, 161, 0, 110, +0, 4, 3, 55, 3, 5, 3, 1, 0, 110, 0, 161, 0, 162, 0, 5, 3, 55, 3, 56, +3, 1, 0, 110, 0, 162, 0, 111, 0, 5, 3, 56, 3, 6, 3, 1, 0, 111, 0, 162, +0, 163, 0, 6, 3, 56, 3, 57, 3, 1, 0, 111, 0, 163, 0, 112, 0, 6, 3, 57, +3, 7, 3, 1, 0, 112, 0, 163, 0, 164, 0, 7, 3, 57, 3, 58, 3, 1, 0, 112, +0, 164, 0, 113, 0, 7, 3, 58, 3, 8, 3, 1, 0, 113, 0, 164, 0, 165, 0, 8, +3, 58, 3, 59, 3, 1, 0, 113, 0, 165, 0, 114, 0, 8, 3, 59, 3, 9, 3, 1, +0, 114, 0, 165, 0, 166, 0, 9, 3, 59, 3, 60, 3, 1, 0, 114, 0, 166, 0, 115, +0, 9, 3, 60, 3, 10, 3, 1, 0, 115, 0, 166, 0, 167, 0, 10, 3, 60, 3, 61, +3, 1, 0, 115, 0, 167, 0, 116, 0, 10, 3, 61, 3, 11, 3, 1, 0, 116, 0, 167, +0, 168, 0, 11, 3, 61, 3, 62, 3, 1, 0, 116, 0, 168, 0, 117, 0, 11, 3, 62, +3, 12, 3, 1, 0, 117, 0, 168, 0, 169, 0, 12, 3, 62, 3, 63, 3, 1, 0, 117, +0, 169, 0, 118, 0, 12, 3, 63, 3, 13, 3, 1, 0, 118, 0, 169, 0, 170, 0, 13, +3, 63, 3, 64, 3, 1, 0, 118, 0, 170, 0, 119, 0, 13, 3, 64, 3, 14, 3, 1, +0, 119, 0, 170, 0, 171, 0, 14, 3, 64, 3, 65, 3, 1, 0, 119, 0, 171, 0, 120, +0, 14, 3, 65, 3, 15, 3, 1, 0, 120, 0, 171, 0, 172, 0, 15, 3, 65, 3, 66, +3, 1, 0, 120, 0, 172, 0, 121, 0, 15, 3, 66, 3, 16, 3, 1, 0, 121, 0, 172, +0, 173, 0, 16, 3, 66, 3, 67, 3, 1, 0, 121, 0, 173, 0, 122, 0, 16, 3, 67, +3, 17, 3, 1, 0, 122, 0, 173, 0, 174, 0, 17, 3, 67, 3, 68, 3, 1, 0, 122, +0, 174, 0, 123, 0, 17, 3, 68, 3, 18, 3, 1, 0, 123, 0, 174, 0, 175, 0, 18, +3, 68, 3, 69, 3, 1, 0, 123, 0, 175, 0, 124, 0, 18, 3, 69, 3, 19, 3, 1, +0, 124, 0, 175, 0, 176, 0, 19, 3, 69, 3, 70, 3, 1, 0, 124, 0, 176, 0, 125, +0, 19, 3, 70, 3, 20, 3, 1, 0, 125, 0, 176, 0, 177, 0, 20, 3, 70, 3, 71, +3, 1, 0, 125, 0, 177, 0, 126, 0, 20, 3, 71, 3, 21, 3, 1, 0, 126, 0, 177, +0, 178, 0, 21, 3, 71, 3, 72, 3, 1, 0, 126, 0, 178, 0, 127, 0, 21, 3, 72, +3, 22, 3, 1, 0, 127, 0, 178, 0, 179, 0, 22, 3, 72, 3, 73, 3, 1, 0, 127, +0, 179, 0, 128, 0, 22, 3, 73, 3, 23, 3, 1, 0, 128, 0, 179, 0, 180, 0, 23, +3, 73, 3, 74, 3, 1, 0, 128, 0, 180, 0, 129, 0, 23, 3, 74, 3, 24, 3, 1, +0, 129, 0, 180, 0, 181, 0, 24, 3, 74, 3, 75, 3, 1, 0, 129, 0, 181, 0, 130, +0, 24, 3, 75, 3, 25, 3, 1, 0, 130, 0, 181, 0, 182, 0, 25, 3, 75, 3, 76, +3, 1, 0, 130, 0, 182, 0, 131, 0, 25, 3, 76, 3, 26, 3, 1, 0, 131, 0, 182, +0, 183, 0, 26, 3, 76, 3, 77, 3, 1, 0, 131, 0, 183, 0, 132, 0, 26, 3, 77, +3, 27, 3, 1, 0, 132, 0, 183, 0, 184, 0, 27, 3, 77, 3, 78, 3, 1, 0, 132, +0, 184, 0, 133, 0, 27, 3, 78, 3, 28, 3, 1, 0, 133, 0, 184, 0, 185, 0, 28, +3, 78, 3, 79, 3, 1, 0, 133, 0, 185, 0, 134, 0, 28, 3, 79, 3, 29, 3, 1, +0, 134, 0, 185, 0, 186, 0, 29, 3, 79, 3, 80, 3, 1, 0, 134, 0, 186, 0, 135, +0, 29, 3, 80, 3, 30, 3, 1, 0, 135, 0, 186, 0, 187, 0, 30, 3, 80, 3, 81, +3, 1, 0, 135, 0, 187, 0, 136, 0, 30, 3, 81, 3, 31, 3, 1, 0, 136, 0, 187, +0, 188, 0, 31, 3, 81, 3, 82, 3, 1, 0, 136, 0, 188, 0, 137, 0, 31, 3, 82, +3, 32, 3, 1, 0, 137, 0, 188, 0, 189, 0, 32, 3, 82, 3, 83, 3, 1, 0, 137, +0, 189, 0, 138, 0, 32, 3, 83, 3, 33, 3, 1, 0, 138, 0, 189, 0, 190, 0, 33, +3, 83, 3, 84, 3, 1, 0, 138, 0, 190, 0, 139, 0, 33, 3, 84, 3, 34, 3, 1, +0, 139, 0, 190, 0, 191, 0, 34, 3, 84, 3, 85, 3, 1, 0, 139, 0, 191, 0, 140, +0, 34, 3, 85, 3, 35, 3, 1, 0, 140, 0, 191, 0, 192, 0, 35, 3, 85, 3, 86, +3, 1, 0, 140, 0, 192, 0, 141, 0, 35, 3, 86, 3, 36, 3, 1, 0, 141, 0, 192, +0, 193, 0, 36, 3, 86, 3, 87, 3, 1, 0, 141, 0, 193, 0, 142, 0, 36, 3, 87, +3, 37, 3, 1, 0, 142, 0, 193, 0, 194, 0, 37, 3, 87, 3, 88, 3, 1, 0, 142, +0, 194, 0, 143, 0, 37, 3, 88, 3, 38, 3, 1, 0, 143, 0, 194, 0, 195, 0, 38, +3, 88, 3, 89, 3, 1, 0, 143, 0, 195, 0, 144, 0, 38, 3, 89, 3, 39, 3, 1, +0, 144, 0, 195, 0, 196, 0, 39, 3, 89, 3, 90, 3, 1, 0, 144, 0, 196, 0, 145, +0, 39, 3, 90, 3, 40, 3, 1, 0, 145, 0, 196, 0, 197, 0, 40, 3, 90, 3, 91, +3, 1, 0, 145, 0, 197, 0, 146, 0, 40, 3, 91, 3, 41, 3, 1, 0, 146, 0, 197, +0, 198, 0, 41, 3, 91, 3, 92, 3, 1, 0, 146, 0, 198, 0, 147, 0, 41, 3, 92, +3, 42, 3, 1, 0, 147, 0, 198, 0, 199, 0, 42, 3, 92, 3, 93, 3, 1, 0, 147, +0, 199, 0, 148, 0, 42, 3, 93, 3, 43, 3, 1, 0, 148, 0, 199, 0, 200, 0, 43, +3, 93, 3, 94, 3, 1, 0, 148, 0, 200, 0, 149, 0, 43, 3, 94, 3, 44, 3, 1, +0, 149, 0, 200, 0, 201, 0, 44, 3, 94, 3, 95, 3, 1, 0, 149, 0, 201, 0, 150, +0, 44, 3, 95, 3, 45, 3, 1, 0, 150, 0, 201, 0, 202, 0, 45, 3, 95, 3, 46, +3, 1, 0, 150, 0, 202, 0, 151, 0, 45, 3, 46, 3, 252, 2, 1, 0, 152, 0, 203, +0, 204, 0, 46, 3, 96, 3, 97, 3, 1, 0, 152, 0, 204, 0, 153, 0, 46, 3, 97, +3, 47, 3, 1, 0, 153, 0, 204, 0, 205, 0, 47, 3, 97, 3, 98, 3, 1, 0, 153, +0, 205, 0, 154, 0, 47, 3, 98, 3, 48, 3, 1, 0, 154, 0, 205, 0, 206, 0, 48, +3, 98, 3, 99, 3, 1, 0, 154, 0, 206, 0, 155, 0, 48, 3, 99, 3, 49, 3, 1, +0, 155, 0, 206, 0, 207, 0, 49, 3, 99, 3, 100, 3, 1, 0, 155, 0, 207, 0, 156, +0, 49, 3, 100, 3, 50, 3, 1, 0, 156, 0, 207, 0, 208, 0, 50, 3, 100, 3, 101, +3, 1, 0, 156, 0, 208, 0, 157, 0, 50, 3, 101, 3, 51, 3, 1, 0, 157, 0, 208, +0, 209, 0, 51, 3, 101, 3, 102, 3, 1, 0, 157, 0, 209, 0, 158, 0, 51, 3, 102, +3, 52, 3, 1, 0, 158, 0, 209, 0, 210, 0, 52, 3, 102, 3, 103, 3, 1, 0, 158, +0, 210, 0, 159, 0, 52, 3, 103, 3, 53, 3, 1, 0, 159, 0, 210, 0, 211, 0, 53, +3, 103, 3, 104, 3, 1, 0, 159, 0, 211, 0, 160, 0, 53, 3, 104, 3, 54, 3, 1, +0, 160, 0, 211, 0, 212, 0, 54, 3, 104, 3, 105, 3, 1, 0, 160, 0, 212, 0, 161, +0, 54, 3, 105, 3, 55, 3, 1, 0, 161, 0, 212, 0, 213, 0, 55, 3, 105, 3, 106, +3, 1, 0, 161, 0, 213, 0, 162, 0, 55, 3, 106, 3, 56, 3, 1, 0, 162, 0, 213, +0, 214, 0, 56, 3, 106, 3, 107, 3, 1, 0, 162, 0, 214, 0, 163, 0, 56, 3, 107, +3, 57, 3, 1, 0, 163, 0, 214, 0, 215, 0, 57, 3, 107, 3, 108, 3, 1, 0, 163, +0, 215, 0, 164, 0, 57, 3, 108, 3, 58, 3, 1, 0, 164, 0, 215, 0, 216, 0, 58, +3, 108, 3, 109, 3, 1, 0, 164, 0, 216, 0, 165, 0, 58, 3, 109, 3, 59, 3, 1, +0, 165, 0, 216, 0, 217, 0, 59, 3, 109, 3, 110, 3, 1, 0, 165, 0, 217, 0, 166, +0, 59, 3, 110, 3, 60, 3, 1, 0, 166, 0, 217, 0, 218, 0, 60, 3, 110, 3, 111, +3, 1, 0, 166, 0, 218, 0, 167, 0, 60, 3, 111, 3, 61, 3, 1, 0, 167, 0, 218, +0, 219, 0, 61, 3, 111, 3, 112, 3, 1, 0, 167, 0, 219, 0, 168, 0, 61, 3, 112, +3, 62, 3, 1, 0, 168, 0, 219, 0, 220, 0, 62, 3, 112, 3, 113, 3, 1, 0, 168, +0, 220, 0, 169, 0, 62, 3, 113, 3, 63, 3, 1, 0, 169, 0, 220, 0, 221, 0, 63, +3, 113, 3, 114, 3, 1, 0, 169, 0, 221, 0, 170, 0, 63, 3, 114, 3, 64, 3, 1, +0, 170, 0, 221, 0, 222, 0, 64, 3, 114, 3, 115, 3, 1, 0, 170, 0, 222, 0, 171, +0, 64, 3, 115, 3, 65, 3, 1, 0, 171, 0, 222, 0, 223, 0, 65, 3, 115, 3, 116, +3, 1, 0, 171, 0, 223, 0, 172, 0, 65, 3, 116, 3, 66, 3, 1, 0, 172, 0, 223, +0, 224, 0, 66, 3, 116, 3, 117, 3, 1, 0, 172, 0, 224, 0, 173, 0, 66, 3, 117, +3, 67, 3, 1, 0, 173, 0, 224, 0, 225, 0, 67, 3, 117, 3, 118, 3, 1, 0, 173, +0, 225, 0, 174, 0, 67, 3, 118, 3, 68, 3, 1, 0, 174, 0, 225, 0, 226, 0, 68, +3, 118, 3, 119, 3, 1, 0, 174, 0, 226, 0, 175, 0, 68, 3, 119, 3, 69, 3, 1, +0, 175, 0, 226, 0, 227, 0, 69, 3, 119, 3, 120, 3, 1, 0, 175, 0, 227, 0, 176, +0, 69, 3, 120, 3, 70, 3, 1, 0, 176, 0, 227, 0, 228, 0, 70, 3, 120, 3, 121, +3, 1, 0, 176, 0, 228, 0, 177, 0, 70, 3, 121, 3, 71, 3, 1, 0, 177, 0, 228, +0, 229, 0, 71, 3, 121, 3, 122, 3, 1, 0, 177, 0, 229, 0, 178, 0, 71, 3, 122, +3, 72, 3, 1, 0, 178, 0, 229, 0, 230, 0, 72, 3, 122, 3, 123, 3, 1, 0, 178, +0, 230, 0, 179, 0, 72, 3, 123, 3, 73, 3, 1, 0, 179, 0, 230, 0, 231, 0, 73, +3, 123, 3, 124, 3, 1, 0, 179, 0, 231, 0, 180, 0, 73, 3, 124, 3, 74, 3, 1, +0, 180, 0, 231, 0, 232, 0, 74, 3, 124, 3, 125, 3, 1, 0, 180, 0, 232, 0, 181, +0, 74, 3, 125, 3, 75, 3, 1, 0, 181, 0, 232, 0, 233, 0, 75, 3, 125, 3, 126, +3, 1, 0, 181, 0, 233, 0, 182, 0, 75, 3, 126, 3, 76, 3, 1, 0, 182, 0, 233, +0, 234, 0, 76, 3, 126, 3, 127, 3, 1, 0, 182, 0, 234, 0, 183, 0, 76, 3, 127, +3, 77, 3, 1, 0, 183, 0, 234, 0, 235, 0, 77, 3, 127, 3, 128, 3, 1, 0, 183, +0, 235, 0, 184, 0, 77, 3, 128, 3, 78, 3, 1, 0, 184, 0, 235, 0, 236, 0, 78, +3, 128, 3, 129, 3, 1, 0, 184, 0, 236, 0, 185, 0, 78, 3, 129, 3, 79, 3, 1, +0, 185, 0, 236, 0, 237, 0, 79, 3, 129, 3, 130, 3, 1, 0, 185, 0, 237, 0, 186, +0, 79, 3, 130, 3, 80, 3, 1, 0, 186, 0, 237, 0, 238, 0, 80, 3, 130, 3, 131, +3, 1, 0, 186, 0, 238, 0, 187, 0, 80, 3, 131, 3, 81, 3, 1, 0, 187, 0, 238, +0, 239, 0, 81, 3, 131, 3, 132, 3, 1, 0, 187, 0, 239, 0, 188, 0, 81, 3, 132, +3, 82, 3, 1, 0, 188, 0, 239, 0, 240, 0, 82, 3, 132, 3, 133, 3, 1, 0, 188, +0, 240, 0, 189, 0, 82, 3, 133, 3, 83, 3, 1, 0, 189, 0, 240, 0, 241, 0, 83, +3, 133, 3, 134, 3, 1, 0, 189, 0, 241, 0, 190, 0, 83, 3, 134, 3, 84, 3, 1, +0, 190, 0, 241, 0, 242, 0, 84, 3, 134, 3, 135, 3, 1, 0, 190, 0, 242, 0, 191, +0, 84, 3, 135, 3, 85, 3, 1, 0, 191, 0, 242, 0, 243, 0, 85, 3, 135, 3, 136, +3, 1, 0, 191, 0, 243, 0, 192, 0, 85, 3, 136, 3, 86, 3, 1, 0, 192, 0, 243, +0, 244, 0, 86, 3, 136, 3, 137, 3, 1, 0, 192, 0, 244, 0, 193, 0, 86, 3, 137, +3, 87, 3, 1, 0, 193, 0, 244, 0, 245, 0, 87, 3, 137, 3, 138, 3, 1, 0, 193, +0, 245, 0, 194, 0, 87, 3, 138, 3, 88, 3, 1, 0, 194, 0, 245, 0, 246, 0, 88, +3, 138, 3, 139, 3, 1, 0, 194, 0, 246, 0, 195, 0, 88, 3, 139, 3, 89, 3, 1, +0, 195, 0, 246, 0, 247, 0, 89, 3, 139, 3, 140, 3, 1, 0, 195, 0, 247, 0, 196, +0, 89, 3, 140, 3, 90, 3, 1, 0, 196, 0, 247, 0, 248, 0, 90, 3, 140, 3, 141, +3, 1, 0, 196, 0, 248, 0, 197, 0, 90, 3, 141, 3, 91, 3, 1, 0, 197, 0, 248, +0, 249, 0, 91, 3, 141, 3, 142, 3, 1, 0, 197, 0, 249, 0, 198, 0, 91, 3, 142, +3, 92, 3, 1, 0, 198, 0, 249, 0, 250, 0, 92, 3, 142, 3, 143, 3, 1, 0, 198, +0, 250, 0, 199, 0, 92, 3, 143, 3, 93, 3, 1, 0, 199, 0, 250, 0, 251, 0, 93, +3, 143, 3, 144, 3, 1, 0, 199, 0, 251, 0, 200, 0, 93, 3, 144, 3, 94, 3, 1, +0, 200, 0, 251, 0, 252, 0, 94, 3, 144, 3, 145, 3, 1, 0, 200, 0, 252, 0, 201, +0, 94, 3, 145, 3, 95, 3, 1, 0, 201, 0, 252, 0, 253, 0, 95, 3, 145, 3, 96, +3, 1, 0, 201, 0, 253, 0, 202, 0, 95, 3, 96, 3, 46, 3, 1, 0, 203, 0, 254, +0, 255, 0, 96, 3, 146, 3, 147, 3, 1, 0, 203, 0, 255, 0, 204, 0, 96, 3, 147, +3, 97, 3, 1, 0, 204, 0, 255, 0, 0, 1, 97, 3, 147, 3, 148, 3, 1, 0, 204, +0, 0, 1, 205, 0, 97, 3, 148, 3, 98, 3, 1, 0, 205, 0, 0, 1, 1, 1, 98, +3, 148, 3, 149, 3, 1, 0, 205, 0, 1, 1, 206, 0, 98, 3, 149, 3, 99, 3, 1, +0, 206, 0, 1, 1, 2, 1, 99, 3, 149, 3, 150, 3, 1, 0, 206, 0, 2, 1, 207, +0, 99, 3, 150, 3, 100, 3, 1, 0, 207, 0, 2, 1, 3, 1, 100, 3, 150, 3, 151, +3, 1, 0, 207, 0, 3, 1, 208, 0, 100, 3, 151, 3, 101, 3, 1, 0, 208, 0, 3, +1, 4, 1, 101, 3, 151, 3, 152, 3, 1, 0, 208, 0, 4, 1, 209, 0, 101, 3, 152, +3, 102, 3, 1, 0, 209, 0, 4, 1, 5, 1, 102, 3, 152, 3, 153, 3, 1, 0, 209, +0, 5, 1, 210, 0, 102, 3, 153, 3, 103, 3, 1, 0, 210, 0, 5, 1, 6, 1, 103, +3, 153, 3, 154, 3, 1, 0, 210, 0, 6, 1, 211, 0, 103, 3, 154, 3, 104, 3, 1, +0, 211, 0, 6, 1, 7, 1, 104, 3, 154, 3, 155, 3, 1, 0, 211, 0, 7, 1, 212, +0, 104, 3, 155, 3, 105, 3, 1, 0, 212, 0, 7, 1, 8, 1, 105, 3, 155, 3, 156, +3, 1, 0, 212, 0, 8, 1, 213, 0, 105, 3, 156, 3, 106, 3, 1, 0, 213, 0, 8, +1, 9, 1, 106, 3, 156, 3, 157, 3, 1, 0, 213, 0, 9, 1, 214, 0, 106, 3, 157, +3, 107, 3, 1, 0, 214, 0, 9, 1, 10, 1, 107, 3, 157, 3, 158, 3, 1, 0, 214, +0, 10, 1, 215, 0, 107, 3, 158, 3, 108, 3, 1, 0, 215, 0, 10, 1, 11, 1, 108, +3, 158, 3, 159, 3, 1, 0, 215, 0, 11, 1, 216, 0, 108, 3, 159, 3, 109, 3, 1, +0, 216, 0, 11, 1, 12, 1, 109, 3, 159, 3, 160, 3, 1, 0, 216, 0, 12, 1, 217, +0, 109, 3, 160, 3, 110, 3, 1, 0, 217, 0, 12, 1, 13, 1, 110, 3, 160, 3, 161, +3, 1, 0, 217, 0, 13, 1, 218, 0, 110, 3, 161, 3, 111, 3, 1, 0, 218, 0, 13, +1, 14, 1, 111, 3, 161, 3, 162, 3, 1, 0, 218, 0, 14, 1, 219, 0, 111, 3, 162, +3, 112, 3, 1, 0, 219, 0, 14, 1, 15, 1, 112, 3, 162, 3, 163, 3, 1, 0, 219, +0, 15, 1, 220, 0, 112, 3, 163, 3, 113, 3, 1, 0, 220, 0, 15, 1, 16, 1, 113, +3, 163, 3, 164, 3, 1, 0, 220, 0, 16, 1, 221, 0, 113, 3, 164, 3, 114, 3, 1, +0, 221, 0, 16, 1, 17, 1, 114, 3, 164, 3, 165, 3, 1, 0, 221, 0, 17, 1, 222, +0, 114, 3, 165, 3, 115, 3, 1, 0, 222, 0, 17, 1, 18, 1, 115, 3, 165, 3, 166, +3, 1, 0, 222, 0, 18, 1, 223, 0, 115, 3, 166, 3, 116, 3, 1, 0, 223, 0, 18, +1, 19, 1, 116, 3, 166, 3, 167, 3, 1, 0, 223, 0, 19, 1, 224, 0, 116, 3, 167, +3, 117, 3, 1, 0, 224, 0, 19, 1, 20, 1, 117, 3, 167, 3, 168, 3, 1, 0, 224, +0, 20, 1, 225, 0, 117, 3, 168, 3, 118, 3, 1, 0, 225, 0, 20, 1, 21, 1, 118, +3, 168, 3, 169, 3, 1, 0, 225, 0, 21, 1, 226, 0, 118, 3, 169, 3, 119, 3, 1, +0, 226, 0, 21, 1, 22, 1, 119, 3, 169, 3, 170, 3, 1, 0, 226, 0, 22, 1, 227, +0, 119, 3, 170, 3, 120, 3, 1, 0, 227, 0, 22, 1, 23, 1, 120, 3, 170, 3, 171, +3, 1, 0, 227, 0, 23, 1, 228, 0, 120, 3, 171, 3, 121, 3, 1, 0, 228, 0, 23, +1, 24, 1, 121, 3, 171, 3, 172, 3, 1, 0, 228, 0, 24, 1, 229, 0, 121, 3, 172, +3, 122, 3, 1, 0, 229, 0, 24, 1, 25, 1, 122, 3, 172, 3, 173, 3, 1, 0, 229, +0, 25, 1, 230, 0, 122, 3, 173, 3, 123, 3, 1, 0, 230, 0, 25, 1, 26, 1, 123, +3, 173, 3, 174, 3, 1, 0, 230, 0, 26, 1, 231, 0, 123, 3, 174, 3, 124, 3, 1, +0, 231, 0, 26, 1, 27, 1, 124, 3, 174, 3, 175, 3, 1, 0, 231, 0, 27, 1, 232, +0, 124, 3, 175, 3, 125, 3, 1, 0, 232, 0, 27, 1, 28, 1, 125, 3, 175, 3, 176, +3, 1, 0, 232, 0, 28, 1, 233, 0, 125, 3, 176, 3, 126, 3, 1, 0, 233, 0, 28, +1, 29, 1, 126, 3, 176, 3, 177, 3, 1, 0, 233, 0, 29, 1, 234, 0, 126, 3, 177, +3, 127, 3, 1, 0, 234, 0, 29, 1, 30, 1, 127, 3, 177, 3, 178, 3, 1, 0, 234, +0, 30, 1, 235, 0, 127, 3, 178, 3, 128, 3, 1, 0, 235, 0, 30, 1, 31, 1, 128, +3, 178, 3, 179, 3, 1, 0, 235, 0, 31, 1, 236, 0, 128, 3, 179, 3, 129, 3, 1, +0, 236, 0, 31, 1, 32, 1, 129, 3, 179, 3, 180, 3, 1, 0, 236, 0, 32, 1, 237, +0, 129, 3, 180, 3, 130, 3, 1, 0, 237, 0, 32, 1, 33, 1, 130, 3, 180, 3, 181, +3, 1, 0, 237, 0, 33, 1, 238, 0, 130, 3, 181, 3, 131, 3, 1, 0, 238, 0, 33, +1, 34, 1, 131, 3, 181, 3, 182, 3, 1, 0, 238, 0, 34, 1, 239, 0, 131, 3, 182, +3, 132, 3, 1, 0, 239, 0, 34, 1, 35, 1, 132, 3, 182, 3, 183, 3, 1, 0, 239, +0, 35, 1, 240, 0, 132, 3, 183, 3, 133, 3, 1, 0, 240, 0, 35, 1, 36, 1, 133, +3, 183, 3, 184, 3, 1, 0, 240, 0, 36, 1, 241, 0, 133, 3, 184, 3, 134, 3, 1, +0, 241, 0, 36, 1, 37, 1, 134, 3, 184, 3, 185, 3, 1, 0, 241, 0, 37, 1, 242, +0, 134, 3, 185, 3, 135, 3, 1, 0, 242, 0, 37, 1, 38, 1, 135, 3, 185, 3, 186, +3, 1, 0, 242, 0, 38, 1, 243, 0, 135, 3, 186, 3, 136, 3, 1, 0, 243, 0, 38, +1, 39, 1, 136, 3, 186, 3, 187, 3, 1, 0, 243, 0, 39, 1, 244, 0, 136, 3, 187, +3, 137, 3, 1, 0, 244, 0, 39, 1, 40, 1, 137, 3, 187, 3, 188, 3, 1, 0, 244, +0, 40, 1, 245, 0, 137, 3, 188, 3, 138, 3, 1, 0, 245, 0, 40, 1, 41, 1, 138, +3, 188, 3, 189, 3, 1, 0, 245, 0, 41, 1, 246, 0, 138, 3, 189, 3, 139, 3, 1, +0, 246, 0, 41, 1, 42, 1, 139, 3, 189, 3, 190, 3, 1, 0, 246, 0, 42, 1, 247, +0, 139, 3, 190, 3, 140, 3, 1, 0, 247, 0, 42, 1, 43, 1, 140, 3, 190, 3, 191, +3, 1, 0, 247, 0, 43, 1, 248, 0, 140, 3, 191, 3, 141, 3, 1, 0, 248, 0, 43, +1, 44, 1, 141, 3, 191, 3, 192, 3, 1, 0, 248, 0, 44, 1, 249, 0, 141, 3, 192, +3, 142, 3, 1, 0, 249, 0, 44, 1, 45, 1, 142, 3, 192, 3, 193, 3, 1, 0, 249, +0, 45, 1, 250, 0, 142, 3, 193, 3, 143, 3, 1, 0, 250, 0, 45, 1, 46, 1, 143, +3, 193, 3, 194, 3, 1, 0, 250, 0, 46, 1, 251, 0, 143, 3, 194, 3, 144, 3, 1, +0, 251, 0, 46, 1, 47, 1, 144, 3, 194, 3, 195, 3, 1, 0, 251, 0, 47, 1, 252, +0, 144, 3, 195, 3, 145, 3, 1, 0, 252, 0, 47, 1, 48, 1, 145, 3, 195, 3, 146, +3, 1, 0, 252, 0, 48, 1, 253, 0, 145, 3, 146, 3, 96, 3, 1, 0, 254, 0, 49, +1, 50, 1, 146, 3, 196, 3, 197, 3, 1, 0, 254, 0, 50, 1, 255, 0, 146, 3, 197, +3, 147, 3, 1, 0, 255, 0, 50, 1, 51, 1, 147, 3, 197, 3, 198, 3, 1, 0, 255, +0, 51, 1, 0, 1, 147, 3, 198, 3, 148, 3, 1, 0, 0, 1, 51, 1, 52, 1, 148, +3, 198, 3, 199, 3, 1, 0, 0, 1, 52, 1, 1, 1, 148, 3, 199, 3, 149, 3, 1, +0, 1, 1, 52, 1, 53, 1, 149, 3, 199, 3, 200, 3, 1, 0, 1, 1, 53, 1, 2, +1, 149, 3, 200, 3, 150, 3, 1, 0, 2, 1, 53, 1, 54, 1, 150, 3, 200, 3, 201, +3, 1, 0, 2, 1, 54, 1, 3, 1, 150, 3, 201, 3, 151, 3, 1, 0, 3, 1, 54, +1, 55, 1, 151, 3, 201, 3, 202, 3, 1, 0, 3, 1, 55, 1, 4, 1, 151, 3, 202, +3, 152, 3, 1, 0, 4, 1, 55, 1, 56, 1, 152, 3, 202, 3, 203, 3, 1, 0, 4, +1, 56, 1, 5, 1, 152, 3, 203, 3, 153, 3, 1, 0, 5, 1, 56, 1, 57, 1, 153, +3, 203, 3, 204, 3, 1, 0, 5, 1, 57, 1, 6, 1, 153, 3, 204, 3, 154, 3, 1, +0, 6, 1, 57, 1, 58, 1, 154, 3, 204, 3, 205, 3, 1, 0, 6, 1, 58, 1, 7, +1, 154, 3, 205, 3, 155, 3, 1, 0, 7, 1, 58, 1, 59, 1, 155, 3, 205, 3, 206, +3, 1, 0, 7, 1, 59, 1, 8, 1, 155, 3, 206, 3, 156, 3, 1, 0, 8, 1, 59, +1, 60, 1, 156, 3, 206, 3, 207, 3, 1, 0, 8, 1, 60, 1, 9, 1, 156, 3, 207, +3, 157, 3, 1, 0, 9, 1, 60, 1, 61, 1, 157, 3, 207, 3, 208, 3, 1, 0, 9, +1, 61, 1, 10, 1, 157, 3, 208, 3, 158, 3, 1, 0, 10, 1, 61, 1, 62, 1, 158, +3, 208, 3, 209, 3, 1, 0, 10, 1, 62, 1, 11, 1, 158, 3, 209, 3, 159, 3, 1, +0, 11, 1, 62, 1, 63, 1, 159, 3, 209, 3, 210, 3, 1, 0, 11, 1, 63, 1, 12, +1, 159, 3, 210, 3, 160, 3, 1, 0, 12, 1, 63, 1, 64, 1, 160, 3, 210, 3, 211, +3, 1, 0, 12, 1, 64, 1, 13, 1, 160, 3, 211, 3, 161, 3, 1, 0, 13, 1, 64, +1, 65, 1, 161, 3, 211, 3, 212, 3, 1, 0, 13, 1, 65, 1, 14, 1, 161, 3, 212, +3, 162, 3, 1, 0, 14, 1, 65, 1, 66, 1, 162, 3, 212, 3, 213, 3, 1, 0, 14, +1, 66, 1, 15, 1, 162, 3, 213, 3, 163, 3, 1, 0, 15, 1, 66, 1, 67, 1, 163, +3, 213, 3, 214, 3, 1, 0, 15, 1, 67, 1, 16, 1, 163, 3, 214, 3, 164, 3, 1, +0, 16, 1, 67, 1, 68, 1, 164, 3, 214, 3, 215, 3, 1, 0, 16, 1, 68, 1, 17, +1, 164, 3, 215, 3, 165, 3, 1, 0, 17, 1, 68, 1, 69, 1, 165, 3, 215, 3, 216, +3, 1, 0, 17, 1, 69, 1, 18, 1, 165, 3, 216, 3, 166, 3, 1, 0, 18, 1, 69, +1, 70, 1, 166, 3, 216, 3, 217, 3, 1, 0, 18, 1, 70, 1, 19, 1, 166, 3, 217, +3, 167, 3, 1, 0, 19, 1, 70, 1, 71, 1, 167, 3, 217, 3, 218, 3, 1, 0, 19, +1, 71, 1, 20, 1, 167, 3, 218, 3, 168, 3, 1, 0, 20, 1, 71, 1, 72, 1, 168, +3, 218, 3, 219, 3, 1, 0, 20, 1, 72, 1, 21, 1, 168, 3, 219, 3, 169, 3, 1, +0, 21, 1, 72, 1, 73, 1, 169, 3, 219, 3, 220, 3, 1, 0, 21, 1, 73, 1, 22, +1, 169, 3, 220, 3, 170, 3, 1, 0, 22, 1, 73, 1, 74, 1, 170, 3, 220, 3, 221, +3, 1, 0, 22, 1, 74, 1, 23, 1, 170, 3, 221, 3, 171, 3, 1, 0, 23, 1, 74, +1, 75, 1, 171, 3, 221, 3, 222, 3, 1, 0, 23, 1, 75, 1, 24, 1, 171, 3, 222, +3, 172, 3, 1, 0, 24, 1, 75, 1, 76, 1, 172, 3, 222, 3, 223, 3, 1, 0, 24, +1, 76, 1, 25, 1, 172, 3, 223, 3, 173, 3, 1, 0, 25, 1, 76, 1, 77, 1, 173, +3, 223, 3, 224, 3, 1, 0, 25, 1, 77, 1, 26, 1, 173, 3, 224, 3, 174, 3, 1, +0, 26, 1, 77, 1, 78, 1, 174, 3, 224, 3, 225, 3, 1, 0, 26, 1, 78, 1, 27, +1, 174, 3, 225, 3, 175, 3, 1, 0, 27, 1, 78, 1, 79, 1, 175, 3, 225, 3, 226, +3, 1, 0, 27, 1, 79, 1, 28, 1, 175, 3, 226, 3, 176, 3, 1, 0, 28, 1, 79, +1, 80, 1, 176, 3, 226, 3, 227, 3, 1, 0, 28, 1, 80, 1, 29, 1, 176, 3, 227, +3, 177, 3, 1, 0, 29, 1, 80, 1, 81, 1, 177, 3, 227, 3, 228, 3, 1, 0, 29, +1, 81, 1, 30, 1, 177, 3, 228, 3, 178, 3, 1, 0, 30, 1, 81, 1, 82, 1, 178, +3, 228, 3, 229, 3, 1, 0, 30, 1, 82, 1, 31, 1, 178, 3, 229, 3, 179, 3, 1, +0, 31, 1, 82, 1, 83, 1, 179, 3, 229, 3, 230, 3, 1, 0, 31, 1, 83, 1, 32, +1, 179, 3, 230, 3, 180, 3, 1, 0, 32, 1, 83, 1, 84, 1, 180, 3, 230, 3, 231, +3, 1, 0, 32, 1, 84, 1, 33, 1, 180, 3, 231, 3, 181, 3, 1, 0, 33, 1, 84, +1, 85, 1, 181, 3, 231, 3, 232, 3, 1, 0, 33, 1, 85, 1, 34, 1, 181, 3, 232, +3, 182, 3, 1, 0, 34, 1, 85, 1, 86, 1, 182, 3, 232, 3, 233, 3, 1, 0, 34, +1, 86, 1, 35, 1, 182, 3, 233, 3, 183, 3, 1, 0, 35, 1, 86, 1, 87, 1, 183, +3, 233, 3, 234, 3, 1, 0, 35, 1, 87, 1, 36, 1, 183, 3, 234, 3, 184, 3, 1, +0, 36, 1, 87, 1, 88, 1, 184, 3, 234, 3, 235, 3, 1, 0, 36, 1, 88, 1, 37, +1, 184, 3, 235, 3, 185, 3, 1, 0, 37, 1, 88, 1, 89, 1, 185, 3, 235, 3, 236, +3, 1, 0, 37, 1, 89, 1, 38, 1, 185, 3, 236, 3, 186, 3, 1, 0, 38, 1, 89, +1, 90, 1, 186, 3, 236, 3, 237, 3, 1, 0, 38, 1, 90, 1, 39, 1, 186, 3, 237, +3, 187, 3, 1, 0, 39, 1, 90, 1, 91, 1, 187, 3, 237, 3, 238, 3, 1, 0, 39, +1, 91, 1, 40, 1, 187, 3, 238, 3, 188, 3, 1, 0, 40, 1, 91, 1, 92, 1, 188, +3, 238, 3, 239, 3, 1, 0, 40, 1, 92, 1, 41, 1, 188, 3, 239, 3, 189, 3, 1, +0, 41, 1, 92, 1, 93, 1, 189, 3, 239, 3, 240, 3, 1, 0, 41, 1, 93, 1, 42, +1, 189, 3, 240, 3, 190, 3, 1, 0, 42, 1, 93, 1, 94, 1, 190, 3, 240, 3, 241, +3, 1, 0, 42, 1, 94, 1, 43, 1, 190, 3, 241, 3, 191, 3, 1, 0, 43, 1, 94, +1, 95, 1, 191, 3, 241, 3, 242, 3, 1, 0, 43, 1, 95, 1, 44, 1, 191, 3, 242, +3, 192, 3, 1, 0, 44, 1, 95, 1, 96, 1, 192, 3, 242, 3, 243, 3, 1, 0, 44, +1, 96, 1, 45, 1, 192, 3, 243, 3, 193, 3, 1, 0, 45, 1, 96, 1, 97, 1, 193, +3, 243, 3, 244, 3, 1, 0, 45, 1, 97, 1, 46, 1, 193, 3, 244, 3, 194, 3, 1, +0, 46, 1, 97, 1, 98, 1, 194, 3, 244, 3, 245, 3, 1, 0, 46, 1, 98, 1, 47, +1, 194, 3, 245, 3, 195, 3, 1, 0, 47, 1, 98, 1, 99, 1, 195, 3, 245, 3, 196, +3, 1, 0, 47, 1, 99, 1, 48, 1, 195, 3, 196, 3, 146, 3, 1, 0, 49, 1, 100, +1, 101, 1, 196, 3, 246, 3, 247, 3, 1, 0, 49, 1, 101, 1, 50, 1, 196, 3, 247, +3, 197, 3, 1, 0, 50, 1, 101, 1, 102, 1, 197, 3, 247, 3, 248, 3, 1, 0, 50, +1, 102, 1, 51, 1, 197, 3, 248, 3, 198, 3, 1, 0, 51, 1, 102, 1, 103, 1, 198, +3, 248, 3, 249, 3, 1, 0, 51, 1, 103, 1, 52, 1, 198, 3, 249, 3, 199, 3, 1, +0, 52, 1, 103, 1, 104, 1, 199, 3, 249, 3, 250, 3, 1, 0, 52, 1, 104, 1, 53, +1, 199, 3, 250, 3, 200, 3, 1, 0, 53, 1, 104, 1, 105, 1, 200, 3, 250, 3, 251, +3, 1, 0, 53, 1, 105, 1, 54, 1, 200, 3, 251, 3, 201, 3, 1, 0, 54, 1, 105, +1, 106, 1, 201, 3, 251, 3, 252, 3, 1, 0, 54, 1, 106, 1, 55, 1, 201, 3, 252, +3, 202, 3, 1, 0, 55, 1, 106, 1, 107, 1, 202, 3, 252, 3, 253, 3, 1, 0, 55, +1, 107, 1, 56, 1, 202, 3, 253, 3, 203, 3, 1, 0, 56, 1, 107, 1, 108, 1, 203, +3, 253, 3, 254, 3, 1, 0, 56, 1, 108, 1, 57, 1, 203, 3, 254, 3, 204, 3, 1, +0, 57, 1, 108, 1, 109, 1, 204, 3, 254, 3, 255, 3, 1, 0, 57, 1, 109, 1, 58, +1, 204, 3, 255, 3, 205, 3, 1, 0, 58, 1, 109, 1, 110, 1, 205, 3, 255, 3, 0, +4, 1, 0, 58, 1, 110, 1, 59, 1, 205, 3, 0, 4, 206, 3, 1, 0, 59, 1, 110, +1, 111, 1, 206, 3, 0, 4, 1, 4, 1, 0, 59, 1, 111, 1, 60, 1, 206, 3, 1, +4, 207, 3, 1, 0, 60, 1, 111, 1, 112, 1, 207, 3, 1, 4, 2, 4, 1, 0, 60, +1, 112, 1, 61, 1, 207, 3, 2, 4, 208, 3, 1, 0, 61, 1, 112, 1, 113, 1, 208, +3, 2, 4, 3, 4, 1, 0, 61, 1, 113, 1, 62, 1, 208, 3, 3, 4, 209, 3, 1, +0, 62, 1, 113, 1, 114, 1, 209, 3, 3, 4, 4, 4, 1, 0, 62, 1, 114, 1, 63, +1, 209, 3, 4, 4, 210, 3, 1, 0, 63, 1, 114, 1, 115, 1, 210, 3, 4, 4, 5, +4, 1, 0, 63, 1, 115, 1, 64, 1, 210, 3, 5, 4, 211, 3, 1, 0, 64, 1, 115, +1, 116, 1, 211, 3, 5, 4, 6, 4, 1, 0, 64, 1, 116, 1, 65, 1, 211, 3, 6, +4, 212, 3, 1, 0, 65, 1, 116, 1, 117, 1, 212, 3, 6, 4, 7, 4, 1, 0, 65, +1, 117, 1, 66, 1, 212, 3, 7, 4, 213, 3, 1, 0, 66, 1, 117, 1, 118, 1, 213, +3, 7, 4, 8, 4, 1, 0, 66, 1, 118, 1, 67, 1, 213, 3, 8, 4, 214, 3, 1, +0, 67, 1, 118, 1, 119, 1, 214, 3, 8, 4, 9, 4, 1, 0, 67, 1, 119, 1, 68, +1, 214, 3, 9, 4, 215, 3, 1, 0, 68, 1, 119, 1, 120, 1, 215, 3, 9, 4, 10, +4, 1, 0, 68, 1, 120, 1, 69, 1, 215, 3, 10, 4, 216, 3, 1, 0, 69, 1, 120, +1, 121, 1, 216, 3, 10, 4, 11, 4, 1, 0, 69, 1, 121, 1, 70, 1, 216, 3, 11, +4, 217, 3, 1, 0, 70, 1, 121, 1, 122, 1, 217, 3, 11, 4, 12, 4, 1, 0, 70, +1, 122, 1, 71, 1, 217, 3, 12, 4, 218, 3, 1, 0, 71, 1, 122, 1, 123, 1, 218, +3, 12, 4, 13, 4, 1, 0, 71, 1, 123, 1, 72, 1, 218, 3, 13, 4, 219, 3, 1, +0, 72, 1, 123, 1, 124, 1, 219, 3, 13, 4, 14, 4, 1, 0, 72, 1, 124, 1, 73, +1, 219, 3, 14, 4, 220, 3, 1, 0, 73, 1, 124, 1, 125, 1, 220, 3, 14, 4, 15, +4, 1, 0, 73, 1, 125, 1, 74, 1, 220, 3, 15, 4, 221, 3, 1, 0, 74, 1, 125, +1, 126, 1, 221, 3, 15, 4, 16, 4, 1, 0, 74, 1, 126, 1, 75, 1, 221, 3, 16, +4, 222, 3, 1, 0, 75, 1, 126, 1, 127, 1, 222, 3, 16, 4, 17, 4, 1, 0, 75, +1, 127, 1, 76, 1, 222, 3, 17, 4, 223, 3, 1, 0, 76, 1, 127, 1, 128, 1, 223, +3, 17, 4, 18, 4, 1, 0, 76, 1, 128, 1, 77, 1, 223, 3, 18, 4, 224, 3, 1, +0, 77, 1, 128, 1, 129, 1, 224, 3, 18, 4, 19, 4, 1, 0, 77, 1, 129, 1, 78, +1, 224, 3, 19, 4, 225, 3, 1, 0, 78, 1, 129, 1, 130, 1, 225, 3, 19, 4, 20, +4, 1, 0, 78, 1, 130, 1, 79, 1, 225, 3, 20, 4, 226, 3, 1, 0, 79, 1, 130, +1, 131, 1, 226, 3, 20, 4, 21, 4, 1, 0, 79, 1, 131, 1, 80, 1, 226, 3, 21, +4, 227, 3, 1, 0, 80, 1, 131, 1, 132, 1, 227, 3, 21, 4, 22, 4, 1, 0, 80, +1, 132, 1, 81, 1, 227, 3, 22, 4, 228, 3, 1, 0, 81, 1, 132, 1, 133, 1, 228, +3, 22, 4, 23, 4, 1, 0, 81, 1, 133, 1, 82, 1, 228, 3, 23, 4, 229, 3, 1, +0, 82, 1, 133, 1, 134, 1, 229, 3, 23, 4, 24, 4, 1, 0, 82, 1, 134, 1, 83, +1, 229, 3, 24, 4, 230, 3, 1, 0, 83, 1, 134, 1, 135, 1, 230, 3, 24, 4, 25, +4, 1, 0, 83, 1, 135, 1, 84, 1, 230, 3, 25, 4, 231, 3, 1, 0, 84, 1, 135, +1, 136, 1, 231, 3, 25, 4, 26, 4, 1, 0, 84, 1, 136, 1, 85, 1, 231, 3, 26, +4, 232, 3, 1, 0, 85, 1, 136, 1, 137, 1, 232, 3, 26, 4, 27, 4, 1, 0, 85, +1, 137, 1, 86, 1, 232, 3, 27, 4, 233, 3, 1, 0, 86, 1, 137, 1, 138, 1, 233, +3, 27, 4, 28, 4, 1, 0, 86, 1, 138, 1, 87, 1, 233, 3, 28, 4, 234, 3, 1, +0, 87, 1, 138, 1, 139, 1, 234, 3, 28, 4, 29, 4, 1, 0, 87, 1, 139, 1, 88, +1, 234, 3, 29, 4, 235, 3, 1, 0, 88, 1, 139, 1, 140, 1, 235, 3, 29, 4, 30, +4, 1, 0, 88, 1, 140, 1, 89, 1, 235, 3, 30, 4, 236, 3, 1, 0, 89, 1, 140, +1, 141, 1, 236, 3, 30, 4, 31, 4, 1, 0, 89, 1, 141, 1, 90, 1, 236, 3, 31, +4, 237, 3, 1, 0, 90, 1, 141, 1, 142, 1, 237, 3, 31, 4, 32, 4, 1, 0, 90, +1, 142, 1, 91, 1, 237, 3, 32, 4, 238, 3, 1, 0, 91, 1, 142, 1, 143, 1, 238, +3, 32, 4, 33, 4, 1, 0, 91, 1, 143, 1, 92, 1, 238, 3, 33, 4, 239, 3, 1, +0, 92, 1, 143, 1, 144, 1, 239, 3, 33, 4, 34, 4, 1, 0, 92, 1, 144, 1, 93, +1, 239, 3, 34, 4, 240, 3, 1, 0, 93, 1, 144, 1, 145, 1, 240, 3, 34, 4, 35, +4, 1, 0, 93, 1, 145, 1, 94, 1, 240, 3, 35, 4, 241, 3, 1, 0, 94, 1, 145, +1, 146, 1, 241, 3, 35, 4, 36, 4, 1, 0, 94, 1, 146, 1, 95, 1, 241, 3, 36, +4, 242, 3, 1, 0, 95, 1, 146, 1, 147, 1, 242, 3, 36, 4, 37, 4, 1, 0, 95, +1, 147, 1, 96, 1, 242, 3, 37, 4, 243, 3, 1, 0, 96, 1, 147, 1, 148, 1, 243, +3, 37, 4, 38, 4, 1, 0, 96, 1, 148, 1, 97, 1, 243, 3, 38, 4, 244, 3, 1, +0, 97, 1, 148, 1, 149, 1, 244, 3, 38, 4, 39, 4, 1, 0, 97, 1, 149, 1, 98, +1, 244, 3, 39, 4, 245, 3, 1, 0, 98, 1, 149, 1, 150, 1, 245, 3, 39, 4, 246, +3, 1, 0, 98, 1, 150, 1, 99, 1, 245, 3, 246, 3, 196, 3, 1, 0, 100, 1, 151, +1, 152, 1, 246, 3, 40, 4, 41, 4, 1, 0, 100, 1, 152, 1, 101, 1, 246, 3, 41, +4, 247, 3, 1, 0, 101, 1, 152, 1, 153, 1, 247, 3, 41, 4, 42, 4, 1, 0, 101, +1, 153, 1, 102, 1, 247, 3, 42, 4, 248, 3, 1, 0, 102, 1, 153, 1, 154, 1, 248, +3, 42, 4, 43, 4, 1, 0, 102, 1, 154, 1, 103, 1, 248, 3, 43, 4, 249, 3, 1, +0, 103, 1, 154, 1, 155, 1, 249, 3, 43, 4, 44, 4, 1, 0, 103, 1, 155, 1, 104, +1, 249, 3, 44, 4, 250, 3, 1, 0, 104, 1, 155, 1, 156, 1, 250, 3, 44, 4, 45, +4, 1, 0, 104, 1, 156, 1, 105, 1, 250, 3, 45, 4, 251, 3, 1, 0, 105, 1, 156, +1, 157, 1, 251, 3, 45, 4, 46, 4, 1, 0, 105, 1, 157, 1, 106, 1, 251, 3, 46, +4, 252, 3, 1, 0, 106, 1, 157, 1, 158, 1, 252, 3, 46, 4, 47, 4, 1, 0, 106, +1, 158, 1, 107, 1, 252, 3, 47, 4, 253, 3, 1, 0, 107, 1, 158, 1, 159, 1, 253, +3, 47, 4, 48, 4, 1, 0, 107, 1, 159, 1, 108, 1, 253, 3, 48, 4, 254, 3, 1, +0, 108, 1, 159, 1, 160, 1, 254, 3, 48, 4, 49, 4, 1, 0, 108, 1, 160, 1, 109, +1, 254, 3, 49, 4, 255, 3, 1, 0, 109, 1, 160, 1, 161, 1, 255, 3, 49, 4, 50, +4, 1, 0, 109, 1, 161, 1, 110, 1, 255, 3, 50, 4, 0, 4, 1, 0, 110, 1, 161, +1, 162, 1, 0, 4, 50, 4, 51, 4, 1, 0, 110, 1, 162, 1, 111, 1, 0, 4, 51, +4, 1, 4, 1, 0, 111, 1, 162, 1, 163, 1, 1, 4, 51, 4, 52, 4, 1, 0, 111, +1, 163, 1, 112, 1, 1, 4, 52, 4, 2, 4, 1, 0, 112, 1, 163, 1, 164, 1, 2, +4, 52, 4, 53, 4, 1, 0, 112, 1, 164, 1, 113, 1, 2, 4, 53, 4, 3, 4, 1, +0, 113, 1, 164, 1, 165, 1, 3, 4, 53, 4, 54, 4, 1, 0, 113, 1, 165, 1, 114, +1, 3, 4, 54, 4, 4, 4, 1, 0, 114, 1, 165, 1, 166, 1, 4, 4, 54, 4, 55, +4, 1, 0, 114, 1, 166, 1, 115, 1, 4, 4, 55, 4, 5, 4, 1, 0, 115, 1, 166, +1, 167, 1, 5, 4, 55, 4, 56, 4, 1, 0, 115, 1, 167, 1, 116, 1, 5, 4, 56, +4, 6, 4, 1, 0, 116, 1, 167, 1, 168, 1, 6, 4, 56, 4, 57, 4, 1, 0, 116, +1, 168, 1, 117, 1, 6, 4, 57, 4, 7, 4, 1, 0, 117, 1, 168, 1, 169, 1, 7, +4, 57, 4, 58, 4, 1, 0, 117, 1, 169, 1, 118, 1, 7, 4, 58, 4, 8, 4, 1, +0, 118, 1, 169, 1, 170, 1, 8, 4, 58, 4, 59, 4, 1, 0, 118, 1, 170, 1, 119, +1, 8, 4, 59, 4, 9, 4, 1, 0, 119, 1, 170, 1, 171, 1, 9, 4, 59, 4, 60, +4, 1, 0, 119, 1, 171, 1, 120, 1, 9, 4, 60, 4, 10, 4, 1, 0, 120, 1, 171, +1, 172, 1, 10, 4, 60, 4, 61, 4, 1, 0, 120, 1, 172, 1, 121, 1, 10, 4, 61, +4, 11, 4, 1, 0, 121, 1, 172, 1, 173, 1, 11, 4, 61, 4, 62, 4, 1, 0, 121, +1, 173, 1, 122, 1, 11, 4, 62, 4, 12, 4, 1, 0, 122, 1, 173, 1, 174, 1, 12, +4, 62, 4, 63, 4, 1, 0, 122, 1, 174, 1, 123, 1, 12, 4, 63, 4, 13, 4, 1, +0, 123, 1, 174, 1, 175, 1, 13, 4, 63, 4, 64, 4, 1, 0, 123, 1, 175, 1, 124, +1, 13, 4, 64, 4, 14, 4, 1, 0, 124, 1, 175, 1, 176, 1, 14, 4, 64, 4, 65, +4, 1, 0, 124, 1, 176, 1, 125, 1, 14, 4, 65, 4, 15, 4, 1, 0, 125, 1, 176, +1, 177, 1, 15, 4, 65, 4, 66, 4, 1, 0, 125, 1, 177, 1, 126, 1, 15, 4, 66, +4, 16, 4, 1, 0, 126, 1, 177, 1, 178, 1, 16, 4, 66, 4, 67, 4, 1, 0, 126, +1, 178, 1, 127, 1, 16, 4, 67, 4, 17, 4, 1, 0, 127, 1, 178, 1, 179, 1, 17, +4, 67, 4, 68, 4, 1, 0, 127, 1, 179, 1, 128, 1, 17, 4, 68, 4, 18, 4, 1, +0, 128, 1, 179, 1, 180, 1, 18, 4, 68, 4, 69, 4, 1, 0, 128, 1, 180, 1, 129, +1, 18, 4, 69, 4, 19, 4, 1, 0, 129, 1, 180, 1, 181, 1, 19, 4, 69, 4, 70, +4, 1, 0, 129, 1, 181, 1, 130, 1, 19, 4, 70, 4, 20, 4, 1, 0, 130, 1, 181, +1, 182, 1, 20, 4, 70, 4, 71, 4, 1, 0, 130, 1, 182, 1, 131, 1, 20, 4, 71, +4, 21, 4, 1, 0, 131, 1, 182, 1, 183, 1, 21, 4, 71, 4, 72, 4, 1, 0, 131, +1, 183, 1, 132, 1, 21, 4, 72, 4, 22, 4, 1, 0, 132, 1, 183, 1, 184, 1, 22, +4, 72, 4, 73, 4, 1, 0, 132, 1, 184, 1, 133, 1, 22, 4, 73, 4, 23, 4, 1, +0, 133, 1, 184, 1, 185, 1, 23, 4, 73, 4, 74, 4, 1, 0, 133, 1, 185, 1, 134, +1, 23, 4, 74, 4, 24, 4, 1, 0, 134, 1, 185, 1, 186, 1, 24, 4, 74, 4, 75, +4, 1, 0, 134, 1, 186, 1, 135, 1, 24, 4, 75, 4, 25, 4, 1, 0, 135, 1, 186, +1, 187, 1, 25, 4, 75, 4, 76, 4, 1, 0, 135, 1, 187, 1, 136, 1, 25, 4, 76, +4, 26, 4, 1, 0, 136, 1, 187, 1, 188, 1, 26, 4, 76, 4, 77, 4, 1, 0, 136, +1, 188, 1, 137, 1, 26, 4, 77, 4, 27, 4, 1, 0, 137, 1, 188, 1, 189, 1, 27, +4, 77, 4, 78, 4, 1, 0, 137, 1, 189, 1, 138, 1, 27, 4, 78, 4, 28, 4, 1, +0, 138, 1, 189, 1, 190, 1, 28, 4, 78, 4, 79, 4, 1, 0, 138, 1, 190, 1, 139, +1, 28, 4, 79, 4, 29, 4, 1, 0, 139, 1, 190, 1, 191, 1, 29, 4, 79, 4, 80, +4, 1, 0, 139, 1, 191, 1, 140, 1, 29, 4, 80, 4, 30, 4, 1, 0, 140, 1, 191, +1, 192, 1, 30, 4, 80, 4, 81, 4, 1, 0, 140, 1, 192, 1, 141, 1, 30, 4, 81, +4, 31, 4, 1, 0, 141, 1, 192, 1, 193, 1, 31, 4, 81, 4, 82, 4, 1, 0, 141, +1, 193, 1, 142, 1, 31, 4, 82, 4, 32, 4, 1, 0, 142, 1, 193, 1, 194, 1, 32, +4, 82, 4, 83, 4, 1, 0, 142, 1, 194, 1, 143, 1, 32, 4, 83, 4, 33, 4, 1, +0, 143, 1, 194, 1, 195, 1, 33, 4, 83, 4, 84, 4, 1, 0, 143, 1, 195, 1, 144, +1, 33, 4, 84, 4, 34, 4, 1, 0, 144, 1, 195, 1, 196, 1, 34, 4, 84, 4, 85, +4, 1, 0, 144, 1, 196, 1, 145, 1, 34, 4, 85, 4, 35, 4, 1, 0, 145, 1, 196, +1, 197, 1, 35, 4, 85, 4, 86, 4, 1, 0, 145, 1, 197, 1, 146, 1, 35, 4, 86, +4, 36, 4, 1, 0, 146, 1, 197, 1, 198, 1, 36, 4, 86, 4, 87, 4, 1, 0, 146, +1, 198, 1, 147, 1, 36, 4, 87, 4, 37, 4, 1, 0, 147, 1, 198, 1, 199, 1, 37, +4, 87, 4, 88, 4, 1, 0, 147, 1, 199, 1, 148, 1, 37, 4, 88, 4, 38, 4, 1, +0, 148, 1, 199, 1, 200, 1, 38, 4, 88, 4, 89, 4, 1, 0, 148, 1, 200, 1, 149, +1, 38, 4, 89, 4, 39, 4, 1, 0, 149, 1, 200, 1, 201, 1, 39, 4, 89, 4, 40, +4, 1, 0, 149, 1, 201, 1, 150, 1, 39, 4, 40, 4, 246, 3, 1, 0, 151, 1, 202, +1, 203, 1, 40, 4, 90, 4, 91, 4, 1, 0, 151, 1, 203, 1, 152, 1, 40, 4, 91, +4, 41, 4, 1, 0, 152, 1, 203, 1, 204, 1, 41, 4, 91, 4, 92, 4, 1, 0, 152, +1, 204, 1, 153, 1, 41, 4, 92, 4, 42, 4, 1, 0, 153, 1, 204, 1, 205, 1, 42, +4, 92, 4, 93, 4, 1, 0, 153, 1, 205, 1, 154, 1, 42, 4, 93, 4, 43, 4, 1, +0, 154, 1, 205, 1, 206, 1, 43, 4, 93, 4, 94, 4, 1, 0, 154, 1, 206, 1, 155, +1, 43, 4, 94, 4, 44, 4, 1, 0, 155, 1, 206, 1, 207, 1, 44, 4, 94, 4, 95, +4, 1, 0, 155, 1, 207, 1, 156, 1, 44, 4, 95, 4, 45, 4, 1, 0, 156, 1, 207, +1, 208, 1, 45, 4, 95, 4, 96, 4, 1, 0, 156, 1, 208, 1, 157, 1, 45, 4, 96, +4, 46, 4, 1, 0, 157, 1, 208, 1, 209, 1, 46, 4, 96, 4, 97, 4, 1, 0, 157, +1, 209, 1, 158, 1, 46, 4, 97, 4, 47, 4, 1, 0, 158, 1, 209, 1, 210, 1, 47, +4, 97, 4, 98, 4, 1, 0, 158, 1, 210, 1, 159, 1, 47, 4, 98, 4, 48, 4, 1, +0, 159, 1, 210, 1, 211, 1, 48, 4, 98, 4, 99, 4, 1, 0, 159, 1, 211, 1, 160, +1, 48, 4, 99, 4, 49, 4, 1, 0, 160, 1, 211, 1, 212, 1, 49, 4, 99, 4, 100, +4, 1, 0, 160, 1, 212, 1, 161, 1, 49, 4, 100, 4, 50, 4, 1, 0, 161, 1, 212, +1, 213, 1, 50, 4, 100, 4, 101, 4, 1, 0, 161, 1, 213, 1, 162, 1, 50, 4, 101, +4, 51, 4, 1, 0, 162, 1, 213, 1, 214, 1, 51, 4, 101, 4, 102, 4, 1, 0, 162, +1, 214, 1, 163, 1, 51, 4, 102, 4, 52, 4, 1, 0, 163, 1, 214, 1, 215, 1, 52, +4, 102, 4, 103, 4, 1, 0, 163, 1, 215, 1, 164, 1, 52, 4, 103, 4, 53, 4, 1, +0, 164, 1, 215, 1, 216, 1, 53, 4, 103, 4, 104, 4, 1, 0, 164, 1, 216, 1, 165, +1, 53, 4, 104, 4, 54, 4, 1, 0, 165, 1, 216, 1, 217, 1, 54, 4, 104, 4, 105, +4, 1, 0, 165, 1, 217, 1, 166, 1, 54, 4, 105, 4, 55, 4, 1, 0, 166, 1, 217, +1, 218, 1, 55, 4, 105, 4, 106, 4, 1, 0, 166, 1, 218, 1, 167, 1, 55, 4, 106, +4, 56, 4, 1, 0, 167, 1, 218, 1, 219, 1, 56, 4, 106, 4, 107, 4, 1, 0, 167, +1, 219, 1, 168, 1, 56, 4, 107, 4, 57, 4, 1, 0, 168, 1, 219, 1, 220, 1, 57, +4, 107, 4, 108, 4, 1, 0, 168, 1, 220, 1, 169, 1, 57, 4, 108, 4, 58, 4, 1, +0, 169, 1, 220, 1, 221, 1, 58, 4, 108, 4, 109, 4, 1, 0, 169, 1, 221, 1, 170, +1, 58, 4, 109, 4, 59, 4, 1, 0, 170, 1, 221, 1, 222, 1, 59, 4, 109, 4, 110, +4, 1, 0, 170, 1, 222, 1, 171, 1, 59, 4, 110, 4, 60, 4, 1, 0, 171, 1, 222, +1, 223, 1, 60, 4, 110, 4, 111, 4, 1, 0, 171, 1, 223, 1, 172, 1, 60, 4, 111, +4, 61, 4, 1, 0, 172, 1, 223, 1, 224, 1, 61, 4, 111, 4, 112, 4, 1, 0, 172, +1, 224, 1, 173, 1, 61, 4, 112, 4, 62, 4, 1, 0, 173, 1, 224, 1, 225, 1, 62, +4, 112, 4, 113, 4, 1, 0, 173, 1, 225, 1, 174, 1, 62, 4, 113, 4, 63, 4, 1, +0, 174, 1, 225, 1, 226, 1, 63, 4, 113, 4, 114, 4, 1, 0, 174, 1, 226, 1, 175, +1, 63, 4, 114, 4, 64, 4, 1, 0, 175, 1, 226, 1, 227, 1, 64, 4, 114, 4, 115, +4, 1, 0, 175, 1, 227, 1, 176, 1, 64, 4, 115, 4, 65, 4, 1, 0, 176, 1, 227, +1, 228, 1, 65, 4, 115, 4, 116, 4, 1, 0, 176, 1, 228, 1, 177, 1, 65, 4, 116, +4, 66, 4, 1, 0, 177, 1, 228, 1, 229, 1, 66, 4, 116, 4, 117, 4, 1, 0, 177, +1, 229, 1, 178, 1, 66, 4, 117, 4, 67, 4, 1, 0, 178, 1, 229, 1, 230, 1, 67, +4, 117, 4, 118, 4, 1, 0, 178, 1, 230, 1, 179, 1, 67, 4, 118, 4, 68, 4, 1, +0, 179, 1, 230, 1, 231, 1, 68, 4, 118, 4, 119, 4, 1, 0, 179, 1, 231, 1, 180, +1, 68, 4, 119, 4, 69, 4, 1, 0, 180, 1, 231, 1, 232, 1, 69, 4, 119, 4, 120, +4, 1, 0, 180, 1, 232, 1, 181, 1, 69, 4, 120, 4, 70, 4, 1, 0, 181, 1, 232, +1, 233, 1, 70, 4, 120, 4, 121, 4, 1, 0, 181, 1, 233, 1, 182, 1, 70, 4, 121, +4, 71, 4, 1, 0, 182, 1, 233, 1, 234, 1, 71, 4, 121, 4, 122, 4, 1, 0, 182, +1, 234, 1, 183, 1, 71, 4, 122, 4, 72, 4, 1, 0, 183, 1, 234, 1, 235, 1, 72, +4, 122, 4, 123, 4, 1, 0, 183, 1, 235, 1, 184, 1, 72, 4, 123, 4, 73, 4, 1, +0, 184, 1, 235, 1, 236, 1, 73, 4, 123, 4, 124, 4, 1, 0, 184, 1, 236, 1, 185, +1, 73, 4, 124, 4, 74, 4, 1, 0, 185, 1, 236, 1, 237, 1, 74, 4, 124, 4, 125, +4, 1, 0, 185, 1, 237, 1, 186, 1, 74, 4, 125, 4, 75, 4, 1, 0, 186, 1, 237, +1, 238, 1, 75, 4, 125, 4, 126, 4, 1, 0, 186, 1, 238, 1, 187, 1, 75, 4, 126, +4, 76, 4, 1, 0, 187, 1, 238, 1, 239, 1, 76, 4, 126, 4, 127, 4, 1, 0, 187, +1, 239, 1, 188, 1, 76, 4, 127, 4, 77, 4, 1, 0, 188, 1, 239, 1, 240, 1, 77, +4, 127, 4, 128, 4, 1, 0, 188, 1, 240, 1, 189, 1, 77, 4, 128, 4, 78, 4, 1, +0, 189, 1, 240, 1, 241, 1, 78, 4, 128, 4, 129, 4, 1, 0, 189, 1, 241, 1, 190, +1, 78, 4, 129, 4, 79, 4, 1, 0, 190, 1, 241, 1, 242, 1, 79, 4, 129, 4, 130, +4, 1, 0, 190, 1, 242, 1, 191, 1, 79, 4, 130, 4, 80, 4, 1, 0, 191, 1, 242, +1, 243, 1, 80, 4, 130, 4, 131, 4, 1, 0, 191, 1, 243, 1, 192, 1, 80, 4, 131, +4, 81, 4, 1, 0, 192, 1, 243, 1, 244, 1, 81, 4, 131, 4, 132, 4, 1, 0, 192, +1, 244, 1, 193, 1, 81, 4, 132, 4, 82, 4, 1, 0, 193, 1, 244, 1, 245, 1, 82, +4, 132, 4, 133, 4, 1, 0, 193, 1, 245, 1, 194, 1, 82, 4, 133, 4, 83, 4, 1, +0, 194, 1, 245, 1, 246, 1, 83, 4, 133, 4, 134, 4, 1, 0, 194, 1, 246, 1, 195, +1, 83, 4, 134, 4, 84, 4, 1, 0, 195, 1, 246, 1, 247, 1, 84, 4, 134, 4, 135, +4, 1, 0, 195, 1, 247, 1, 196, 1, 84, 4, 135, 4, 85, 4, 1, 0, 196, 1, 247, +1, 248, 1, 85, 4, 135, 4, 136, 4, 1, 0, 196, 1, 248, 1, 197, 1, 85, 4, 136, +4, 86, 4, 1, 0, 197, 1, 248, 1, 249, 1, 86, 4, 136, 4, 137, 4, 1, 0, 197, +1, 249, 1, 198, 1, 86, 4, 137, 4, 87, 4, 1, 0, 198, 1, 249, 1, 250, 1, 87, +4, 137, 4, 138, 4, 1, 0, 198, 1, 250, 1, 199, 1, 87, 4, 138, 4, 88, 4, 1, +0, 199, 1, 250, 1, 251, 1, 88, 4, 138, 4, 139, 4, 1, 0, 199, 1, 251, 1, 200, +1, 88, 4, 139, 4, 89, 4, 1, 0, 200, 1, 251, 1, 252, 1, 89, 4, 139, 4, 90, +4, 1, 0, 200, 1, 252, 1, 201, 1, 89, 4, 90, 4, 40, 4, 1, 0, 202, 1, 253, +1, 254, 1, 90, 4, 140, 4, 141, 4, 1, 0, 202, 1, 254, 1, 203, 1, 90, 4, 141, +4, 91, 4, 1, 0, 203, 1, 254, 1, 255, 1, 91, 4, 141, 4, 142, 4, 1, 0, 203, +1, 255, 1, 204, 1, 91, 4, 142, 4, 92, 4, 1, 0, 204, 1, 255, 1, 0, 2, 92, +4, 142, 4, 143, 4, 1, 0, 204, 1, 0, 2, 205, 1, 92, 4, 143, 4, 93, 4, 1, +0, 205, 1, 0, 2, 1, 2, 93, 4, 143, 4, 144, 4, 1, 0, 205, 1, 1, 2, 206, +1, 93, 4, 144, 4, 94, 4, 1, 0, 206, 1, 1, 2, 2, 2, 94, 4, 144, 4, 145, +4, 1, 0, 206, 1, 2, 2, 207, 1, 94, 4, 145, 4, 95, 4, 1, 0, 207, 1, 2, +2, 3, 2, 95, 4, 145, 4, 146, 4, 1, 0, 207, 1, 3, 2, 208, 1, 95, 4, 146, +4, 96, 4, 1, 0, 208, 1, 3, 2, 4, 2, 96, 4, 146, 4, 147, 4, 1, 0, 208, +1, 4, 2, 209, 1, 96, 4, 147, 4, 97, 4, 1, 0, 209, 1, 4, 2, 5, 2, 97, +4, 147, 4, 148, 4, 1, 0, 209, 1, 5, 2, 210, 1, 97, 4, 148, 4, 98, 4, 1, +0, 210, 1, 5, 2, 6, 2, 98, 4, 148, 4, 149, 4, 1, 0, 210, 1, 6, 2, 211, +1, 98, 4, 149, 4, 99, 4, 1, 0, 211, 1, 6, 2, 7, 2, 99, 4, 149, 4, 150, +4, 1, 0, 211, 1, 7, 2, 212, 1, 99, 4, 150, 4, 100, 4, 1, 0, 212, 1, 7, +2, 8, 2, 100, 4, 150, 4, 151, 4, 1, 0, 212, 1, 8, 2, 213, 1, 100, 4, 151, +4, 101, 4, 1, 0, 213, 1, 8, 2, 9, 2, 101, 4, 151, 4, 152, 4, 1, 0, 213, +1, 9, 2, 214, 1, 101, 4, 152, 4, 102, 4, 1, 0, 214, 1, 9, 2, 10, 2, 102, +4, 152, 4, 153, 4, 1, 0, 214, 1, 10, 2, 215, 1, 102, 4, 153, 4, 103, 4, 1, +0, 215, 1, 10, 2, 11, 2, 103, 4, 153, 4, 154, 4, 1, 0, 215, 1, 11, 2, 216, +1, 103, 4, 154, 4, 104, 4, 1, 0, 216, 1, 11, 2, 12, 2, 104, 4, 154, 4, 155, +4, 1, 0, 216, 1, 12, 2, 217, 1, 104, 4, 155, 4, 105, 4, 1, 0, 217, 1, 12, +2, 13, 2, 105, 4, 155, 4, 156, 4, 1, 0, 217, 1, 13, 2, 218, 1, 105, 4, 156, +4, 106, 4, 1, 0, 218, 1, 13, 2, 14, 2, 106, 4, 156, 4, 157, 4, 1, 0, 218, +1, 14, 2, 219, 1, 106, 4, 157, 4, 107, 4, 1, 0, 219, 1, 14, 2, 15, 2, 107, +4, 157, 4, 158, 4, 1, 0, 219, 1, 15, 2, 220, 1, 107, 4, 158, 4, 108, 4, 1, +0, 220, 1, 15, 2, 16, 2, 108, 4, 158, 4, 159, 4, 1, 0, 220, 1, 16, 2, 221, +1, 108, 4, 159, 4, 109, 4, 1, 0, 221, 1, 16, 2, 17, 2, 109, 4, 159, 4, 160, +4, 1, 0, 221, 1, 17, 2, 222, 1, 109, 4, 160, 4, 110, 4, 1, 0, 222, 1, 17, +2, 18, 2, 110, 4, 160, 4, 161, 4, 1, 0, 222, 1, 18, 2, 223, 1, 110, 4, 161, +4, 111, 4, 1, 0, 223, 1, 18, 2, 19, 2, 111, 4, 161, 4, 162, 4, 1, 0, 223, +1, 19, 2, 224, 1, 111, 4, 162, 4, 112, 4, 1, 0, 224, 1, 19, 2, 20, 2, 112, +4, 162, 4, 163, 4, 1, 0, 224, 1, 20, 2, 225, 1, 112, 4, 163, 4, 113, 4, 1, +0, 225, 1, 20, 2, 21, 2, 113, 4, 163, 4, 164, 4, 1, 0, 225, 1, 21, 2, 226, +1, 113, 4, 164, 4, 114, 4, 1, 0, 226, 1, 21, 2, 22, 2, 114, 4, 164, 4, 165, +4, 1, 0, 226, 1, 22, 2, 227, 1, 114, 4, 165, 4, 115, 4, 1, 0, 227, 1, 22, +2, 23, 2, 115, 4, 165, 4, 166, 4, 1, 0, 227, 1, 23, 2, 228, 1, 115, 4, 166, +4, 116, 4, 1, 0, 228, 1, 23, 2, 24, 2, 116, 4, 166, 4, 167, 4, 1, 0, 228, +1, 24, 2, 229, 1, 116, 4, 167, 4, 117, 4, 1, 0, 229, 1, 24, 2, 25, 2, 117, +4, 167, 4, 168, 4, 1, 0, 229, 1, 25, 2, 230, 1, 117, 4, 168, 4, 118, 4, 1, +0, 230, 1, 25, 2, 26, 2, 118, 4, 168, 4, 169, 4, 1, 0, 230, 1, 26, 2, 231, +1, 118, 4, 169, 4, 119, 4, 1, 0, 231, 1, 26, 2, 27, 2, 119, 4, 169, 4, 170, +4, 1, 0, 231, 1, 27, 2, 232, 1, 119, 4, 170, 4, 120, 4, 1, 0, 232, 1, 27, +2, 28, 2, 120, 4, 170, 4, 171, 4, 1, 0, 232, 1, 28, 2, 233, 1, 120, 4, 171, +4, 121, 4, 1, 0, 233, 1, 28, 2, 29, 2, 121, 4, 171, 4, 172, 4, 1, 0, 233, +1, 29, 2, 234, 1, 121, 4, 172, 4, 122, 4, 1, 0, 234, 1, 29, 2, 30, 2, 122, +4, 172, 4, 173, 4, 1, 0, 234, 1, 30, 2, 235, 1, 122, 4, 173, 4, 123, 4, 1, +0, 235, 1, 30, 2, 31, 2, 123, 4, 173, 4, 174, 4, 1, 0, 235, 1, 31, 2, 236, +1, 123, 4, 174, 4, 124, 4, 1, 0, 236, 1, 31, 2, 32, 2, 124, 4, 174, 4, 175, +4, 1, 0, 236, 1, 32, 2, 237, 1, 124, 4, 175, 4, 125, 4, 1, 0, 237, 1, 32, +2, 33, 2, 125, 4, 175, 4, 176, 4, 1, 0, 237, 1, 33, 2, 238, 1, 125, 4, 176, +4, 126, 4, 1, 0, 238, 1, 33, 2, 34, 2, 126, 4, 176, 4, 177, 4, 1, 0, 238, +1, 34, 2, 239, 1, 126, 4, 177, 4, 127, 4, 1, 0, 239, 1, 34, 2, 35, 2, 127, +4, 177, 4, 178, 4, 1, 0, 239, 1, 35, 2, 240, 1, 127, 4, 178, 4, 128, 4, 1, +0, 240, 1, 35, 2, 36, 2, 128, 4, 178, 4, 179, 4, 1, 0, 240, 1, 36, 2, 241, +1, 128, 4, 179, 4, 129, 4, 1, 0, 241, 1, 36, 2, 37, 2, 129, 4, 179, 4, 180, +4, 1, 0, 241, 1, 37, 2, 242, 1, 129, 4, 180, 4, 130, 4, 1, 0, 242, 1, 37, +2, 38, 2, 130, 4, 180, 4, 181, 4, 1, 0, 242, 1, 38, 2, 243, 1, 130, 4, 181, +4, 131, 4, 1, 0, 243, 1, 38, 2, 39, 2, 131, 4, 181, 4, 182, 4, 1, 0, 243, +1, 39, 2, 244, 1, 131, 4, 182, 4, 132, 4, 1, 0, 244, 1, 39, 2, 40, 2, 132, +4, 182, 4, 183, 4, 1, 0, 244, 1, 40, 2, 245, 1, 132, 4, 183, 4, 133, 4, 1, +0, 245, 1, 40, 2, 41, 2, 133, 4, 183, 4, 184, 4, 1, 0, 245, 1, 41, 2, 246, +1, 133, 4, 184, 4, 134, 4, 1, 0, 246, 1, 41, 2, 42, 2, 134, 4, 184, 4, 185, +4, 1, 0, 246, 1, 42, 2, 247, 1, 134, 4, 185, 4, 135, 4, 1, 0, 247, 1, 42, +2, 43, 2, 135, 4, 185, 4, 186, 4, 1, 0, 247, 1, 43, 2, 248, 1, 135, 4, 186, +4, 136, 4, 1, 0, 248, 1, 43, 2, 44, 2, 136, 4, 186, 4, 187, 4, 1, 0, 248, +1, 44, 2, 249, 1, 136, 4, 187, 4, 137, 4, 1, 0, 249, 1, 44, 2, 45, 2, 137, +4, 187, 4, 188, 4, 1, 0, 249, 1, 45, 2, 250, 1, 137, 4, 188, 4, 138, 4, 1, +0, 250, 1, 45, 2, 46, 2, 138, 4, 188, 4, 189, 4, 1, 0, 250, 1, 46, 2, 251, +1, 138, 4, 189, 4, 139, 4, 1, 0, 251, 1, 46, 2, 47, 2, 139, 4, 189, 4, 140, +4, 1, 0, 251, 1, 47, 2, 252, 1, 139, 4, 140, 4, 90, 4, 1, 0, 253, 1, 48, +2, 49, 2, 140, 4, 190, 4, 191, 4, 1, 0, 253, 1, 49, 2, 254, 1, 140, 4, 191, +4, 141, 4, 1, 0, 254, 1, 49, 2, 50, 2, 141, 4, 191, 4, 192, 4, 1, 0, 254, +1, 50, 2, 255, 1, 141, 4, 192, 4, 142, 4, 1, 0, 255, 1, 50, 2, 51, 2, 142, +4, 192, 4, 193, 4, 1, 0, 255, 1, 51, 2, 0, 2, 142, 4, 193, 4, 143, 4, 1, +0, 0, 2, 51, 2, 52, 2, 143, 4, 193, 4, 194, 4, 1, 0, 0, 2, 52, 2, 1, +2, 143, 4, 194, 4, 144, 4, 1, 0, 1, 2, 52, 2, 53, 2, 144, 4, 194, 4, 195, +4, 1, 0, 1, 2, 53, 2, 2, 2, 144, 4, 195, 4, 145, 4, 1, 0, 2, 2, 53, +2, 54, 2, 145, 4, 195, 4, 196, 4, 1, 0, 2, 2, 54, 2, 3, 2, 145, 4, 196, +4, 146, 4, 1, 0, 3, 2, 54, 2, 55, 2, 146, 4, 196, 4, 197, 4, 1, 0, 3, +2, 55, 2, 4, 2, 146, 4, 197, 4, 147, 4, 1, 0, 4, 2, 55, 2, 56, 2, 147, +4, 197, 4, 198, 4, 1, 0, 4, 2, 56, 2, 5, 2, 147, 4, 198, 4, 148, 4, 1, +0, 5, 2, 56, 2, 57, 2, 148, 4, 198, 4, 199, 4, 1, 0, 5, 2, 57, 2, 6, +2, 148, 4, 199, 4, 149, 4, 1, 0, 6, 2, 57, 2, 58, 2, 149, 4, 199, 4, 200, +4, 1, 0, 6, 2, 58, 2, 7, 2, 149, 4, 200, 4, 150, 4, 1, 0, 7, 2, 58, +2, 59, 2, 150, 4, 200, 4, 201, 4, 1, 0, 7, 2, 59, 2, 8, 2, 150, 4, 201, +4, 151, 4, 1, 0, 8, 2, 59, 2, 60, 2, 151, 4, 201, 4, 202, 4, 1, 0, 8, +2, 60, 2, 9, 2, 151, 4, 202, 4, 152, 4, 1, 0, 9, 2, 60, 2, 61, 2, 152, +4, 202, 4, 203, 4, 1, 0, 9, 2, 61, 2, 10, 2, 152, 4, 203, 4, 153, 4, 1, +0, 10, 2, 61, 2, 62, 2, 153, 4, 203, 4, 204, 4, 1, 0, 10, 2, 62, 2, 11, +2, 153, 4, 204, 4, 154, 4, 1, 0, 11, 2, 62, 2, 63, 2, 154, 4, 204, 4, 205, +4, 1, 0, 11, 2, 63, 2, 12, 2, 154, 4, 205, 4, 155, 4, 1, 0, 12, 2, 63, +2, 64, 2, 155, 4, 205, 4, 206, 4, 1, 0, 12, 2, 64, 2, 13, 2, 155, 4, 206, +4, 156, 4, 1, 0, 13, 2, 64, 2, 65, 2, 156, 4, 206, 4, 207, 4, 1, 0, 13, +2, 65, 2, 14, 2, 156, 4, 207, 4, 157, 4, 1, 0, 14, 2, 65, 2, 66, 2, 157, +4, 207, 4, 208, 4, 1, 0, 14, 2, 66, 2, 15, 2, 157, 4, 208, 4, 158, 4, 1, +0, 15, 2, 66, 2, 67, 2, 158, 4, 208, 4, 209, 4, 1, 0, 15, 2, 67, 2, 16, +2, 158, 4, 209, 4, 159, 4, 1, 0, 16, 2, 67, 2, 68, 2, 159, 4, 209, 4, 210, +4, 1, 0, 16, 2, 68, 2, 17, 2, 159, 4, 210, 4, 160, 4, 1, 0, 17, 2, 68, +2, 69, 2, 160, 4, 210, 4, 211, 4, 1, 0, 17, 2, 69, 2, 18, 2, 160, 4, 211, +4, 161, 4, 1, 0, 18, 2, 69, 2, 70, 2, 161, 4, 211, 4, 212, 4, 1, 0, 18, +2, 70, 2, 19, 2, 161, 4, 212, 4, 162, 4, 1, 0, 19, 2, 70, 2, 71, 2, 162, +4, 212, 4, 213, 4, 1, 0, 19, 2, 71, 2, 20, 2, 162, 4, 213, 4, 163, 4, 1, +0, 20, 2, 71, 2, 72, 2, 163, 4, 213, 4, 214, 4, 1, 0, 20, 2, 72, 2, 21, +2, 163, 4, 214, 4, 164, 4, 1, 0, 21, 2, 72, 2, 73, 2, 164, 4, 214, 4, 215, +4, 1, 0, 21, 2, 73, 2, 22, 2, 164, 4, 215, 4, 165, 4, 1, 0, 22, 2, 73, +2, 74, 2, 165, 4, 215, 4, 216, 4, 1, 0, 22, 2, 74, 2, 23, 2, 165, 4, 216, +4, 166, 4, 1, 0, 23, 2, 74, 2, 75, 2, 166, 4, 216, 4, 217, 4, 1, 0, 23, +2, 75, 2, 24, 2, 166, 4, 217, 4, 167, 4, 1, 0, 24, 2, 75, 2, 76, 2, 167, +4, 217, 4, 218, 4, 1, 0, 24, 2, 76, 2, 25, 2, 167, 4, 218, 4, 168, 4, 1, +0, 25, 2, 76, 2, 77, 2, 168, 4, 218, 4, 219, 4, 1, 0, 25, 2, 77, 2, 26, +2, 168, 4, 219, 4, 169, 4, 1, 0, 26, 2, 77, 2, 78, 2, 169, 4, 219, 4, 220, +4, 1, 0, 26, 2, 78, 2, 27, 2, 169, 4, 220, 4, 170, 4, 1, 0, 27, 2, 78, +2, 79, 2, 170, 4, 220, 4, 221, 4, 1, 0, 27, 2, 79, 2, 28, 2, 170, 4, 221, +4, 171, 4, 1, 0, 28, 2, 79, 2, 80, 2, 171, 4, 221, 4, 222, 4, 1, 0, 28, +2, 80, 2, 29, 2, 171, 4, 222, 4, 172, 4, 1, 0, 29, 2, 80, 2, 81, 2, 172, +4, 222, 4, 223, 4, 1, 0, 29, 2, 81, 2, 30, 2, 172, 4, 223, 4, 173, 4, 1, +0, 30, 2, 81, 2, 82, 2, 173, 4, 223, 4, 224, 4, 1, 0, 30, 2, 82, 2, 31, +2, 173, 4, 224, 4, 174, 4, 1, 0, 31, 2, 82, 2, 83, 2, 174, 4, 224, 4, 225, +4, 1, 0, 31, 2, 83, 2, 32, 2, 174, 4, 225, 4, 175, 4, 1, 0, 32, 2, 83, +2, 84, 2, 175, 4, 225, 4, 226, 4, 1, 0, 32, 2, 84, 2, 33, 2, 175, 4, 226, +4, 176, 4, 1, 0, 33, 2, 84, 2, 85, 2, 176, 4, 226, 4, 227, 4, 1, 0, 33, +2, 85, 2, 34, 2, 176, 4, 227, 4, 177, 4, 1, 0, 34, 2, 85, 2, 86, 2, 177, +4, 227, 4, 228, 4, 1, 0, 34, 2, 86, 2, 35, 2, 177, 4, 228, 4, 178, 4, 1, +0, 35, 2, 86, 2, 87, 2, 178, 4, 228, 4, 229, 4, 1, 0, 35, 2, 87, 2, 36, +2, 178, 4, 229, 4, 179, 4, 1, 0, 36, 2, 87, 2, 88, 2, 179, 4, 229, 4, 230, +4, 1, 0, 36, 2, 88, 2, 37, 2, 179, 4, 230, 4, 180, 4, 1, 0, 37, 2, 88, +2, 89, 2, 180, 4, 230, 4, 231, 4, 1, 0, 37, 2, 89, 2, 38, 2, 180, 4, 231, +4, 181, 4, 1, 0, 38, 2, 89, 2, 90, 2, 181, 4, 231, 4, 232, 4, 1, 0, 38, +2, 90, 2, 39, 2, 181, 4, 232, 4, 182, 4, 1, 0, 39, 2, 90, 2, 91, 2, 182, +4, 232, 4, 233, 4, 1, 0, 39, 2, 91, 2, 40, 2, 182, 4, 233, 4, 183, 4, 1, +0, 40, 2, 91, 2, 92, 2, 183, 4, 233, 4, 234, 4, 1, 0, 40, 2, 92, 2, 41, +2, 183, 4, 234, 4, 184, 4, 1, 0, 41, 2, 92, 2, 93, 2, 184, 4, 234, 4, 235, +4, 1, 0, 41, 2, 93, 2, 42, 2, 184, 4, 235, 4, 185, 4, 1, 0, 42, 2, 93, +2, 94, 2, 185, 4, 235, 4, 236, 4, 1, 0, 42, 2, 94, 2, 43, 2, 185, 4, 236, +4, 186, 4, 1, 0, 43, 2, 94, 2, 95, 2, 186, 4, 236, 4, 237, 4, 1, 0, 43, +2, 95, 2, 44, 2, 186, 4, 237, 4, 187, 4, 1, 0, 44, 2, 95, 2, 96, 2, 187, +4, 237, 4, 238, 4, 1, 0, 44, 2, 96, 2, 45, 2, 187, 4, 238, 4, 188, 4, 1, +0, 45, 2, 96, 2, 97, 2, 188, 4, 238, 4, 239, 4, 1, 0, 45, 2, 97, 2, 46, +2, 188, 4, 239, 4, 189, 4, 1, 0, 46, 2, 97, 2, 98, 2, 189, 4, 239, 4, 190, +4, 1, 0, 46, 2, 98, 2, 47, 2, 189, 4, 190, 4, 140, 4, 1, 0, 48, 2, 99, +2, 100, 2, 190, 4, 240, 4, 241, 4, 1, 0, 48, 2, 100, 2, 49, 2, 190, 4, 241, +4, 191, 4, 1, 0, 49, 2, 100, 2, 101, 2, 191, 4, 241, 4, 242, 4, 1, 0, 49, +2, 101, 2, 50, 2, 191, 4, 242, 4, 192, 4, 1, 0, 50, 2, 101, 2, 102, 2, 192, +4, 242, 4, 243, 4, 1, 0, 50, 2, 102, 2, 51, 2, 192, 4, 243, 4, 193, 4, 1, +0, 51, 2, 102, 2, 103, 2, 193, 4, 243, 4, 244, 4, 1, 0, 51, 2, 103, 2, 52, +2, 193, 4, 244, 4, 194, 4, 1, 0, 52, 2, 103, 2, 104, 2, 194, 4, 244, 4, 245, +4, 1, 0, 52, 2, 104, 2, 53, 2, 194, 4, 245, 4, 195, 4, 1, 0, 53, 2, 104, +2, 105, 2, 195, 4, 245, 4, 246, 4, 1, 0, 53, 2, 105, 2, 54, 2, 195, 4, 246, +4, 196, 4, 1, 0, 54, 2, 105, 2, 106, 2, 196, 4, 246, 4, 247, 4, 1, 0, 54, +2, 106, 2, 55, 2, 196, 4, 247, 4, 197, 4, 1, 0, 55, 2, 106, 2, 107, 2, 197, +4, 247, 4, 248, 4, 1, 0, 55, 2, 107, 2, 56, 2, 197, 4, 248, 4, 198, 4, 1, +0, 56, 2, 107, 2, 108, 2, 198, 4, 248, 4, 249, 4, 1, 0, 56, 2, 108, 2, 57, +2, 198, 4, 249, 4, 199, 4, 1, 0, 57, 2, 108, 2, 109, 2, 199, 4, 249, 4, 250, +4, 1, 0, 57, 2, 109, 2, 58, 2, 199, 4, 250, 4, 200, 4, 1, 0, 58, 2, 109, +2, 110, 2, 200, 4, 250, 4, 251, 4, 1, 0, 58, 2, 110, 2, 59, 2, 200, 4, 251, +4, 201, 4, 1, 0, 59, 2, 110, 2, 111, 2, 201, 4, 251, 4, 252, 4, 1, 0, 59, +2, 111, 2, 60, 2, 201, 4, 252, 4, 202, 4, 1, 0, 60, 2, 111, 2, 112, 2, 202, +4, 252, 4, 253, 4, 1, 0, 60, 2, 112, 2, 61, 2, 202, 4, 253, 4, 203, 4, 1, +0, 61, 2, 112, 2, 113, 2, 203, 4, 253, 4, 254, 4, 1, 0, 61, 2, 113, 2, 62, +2, 203, 4, 254, 4, 204, 4, 1, 0, 62, 2, 113, 2, 114, 2, 204, 4, 254, 4, 255, +4, 1, 0, 62, 2, 114, 2, 63, 2, 204, 4, 255, 4, 205, 4, 1, 0, 63, 2, 114, +2, 115, 2, 205, 4, 255, 4, 0, 5, 1, 0, 63, 2, 115, 2, 64, 2, 205, 4, 0, +5, 206, 4, 1, 0, 64, 2, 115, 2, 116, 2, 206, 4, 0, 5, 1, 5, 1, 0, 64, +2, 116, 2, 65, 2, 206, 4, 1, 5, 207, 4, 1, 0, 65, 2, 116, 2, 117, 2, 207, +4, 1, 5, 2, 5, 1, 0, 65, 2, 117, 2, 66, 2, 207, 4, 2, 5, 208, 4, 1, +0, 66, 2, 117, 2, 118, 2, 208, 4, 2, 5, 3, 5, 1, 0, 66, 2, 118, 2, 67, +2, 208, 4, 3, 5, 209, 4, 1, 0, 67, 2, 118, 2, 119, 2, 209, 4, 3, 5, 4, +5, 1, 0, 67, 2, 119, 2, 68, 2, 209, 4, 4, 5, 210, 4, 1, 0, 68, 2, 119, +2, 120, 2, 210, 4, 4, 5, 5, 5, 1, 0, 68, 2, 120, 2, 69, 2, 210, 4, 5, +5, 211, 4, 1, 0, 69, 2, 120, 2, 121, 2, 211, 4, 5, 5, 6, 5, 1, 0, 69, +2, 121, 2, 70, 2, 211, 4, 6, 5, 212, 4, 1, 0, 70, 2, 121, 2, 122, 2, 212, +4, 6, 5, 7, 5, 1, 0, 70, 2, 122, 2, 71, 2, 212, 4, 7, 5, 213, 4, 1, +0, 71, 2, 122, 2, 123, 2, 213, 4, 7, 5, 8, 5, 1, 0, 71, 2, 123, 2, 72, +2, 213, 4, 8, 5, 214, 4, 1, 0, 72, 2, 123, 2, 124, 2, 214, 4, 8, 5, 9, +5, 1, 0, 72, 2, 124, 2, 73, 2, 214, 4, 9, 5, 215, 4, 1, 0, 73, 2, 124, +2, 125, 2, 215, 4, 9, 5, 10, 5, 1, 0, 73, 2, 125, 2, 74, 2, 215, 4, 10, +5, 216, 4, 1, 0, 74, 2, 125, 2, 126, 2, 216, 4, 10, 5, 11, 5, 1, 0, 74, +2, 126, 2, 75, 2, 216, 4, 11, 5, 217, 4, 1, 0, 75, 2, 126, 2, 127, 2, 217, +4, 11, 5, 12, 5, 1, 0, 75, 2, 127, 2, 76, 2, 217, 4, 12, 5, 218, 4, 1, +0, 76, 2, 127, 2, 128, 2, 218, 4, 12, 5, 13, 5, 1, 0, 76, 2, 128, 2, 77, +2, 218, 4, 13, 5, 219, 4, 1, 0, 77, 2, 128, 2, 129, 2, 219, 4, 13, 5, 14, +5, 1, 0, 77, 2, 129, 2, 78, 2, 219, 4, 14, 5, 220, 4, 1, 0, 78, 2, 129, +2, 130, 2, 220, 4, 14, 5, 15, 5, 1, 0, 78, 2, 130, 2, 79, 2, 220, 4, 15, +5, 221, 4, 1, 0, 79, 2, 130, 2, 131, 2, 221, 4, 15, 5, 16, 5, 1, 0, 79, +2, 131, 2, 80, 2, 221, 4, 16, 5, 222, 4, 1, 0, 80, 2, 131, 2, 132, 2, 222, +4, 16, 5, 17, 5, 1, 0, 80, 2, 132, 2, 81, 2, 222, 4, 17, 5, 223, 4, 1, +0, 81, 2, 132, 2, 133, 2, 223, 4, 17, 5, 18, 5, 1, 0, 81, 2, 133, 2, 82, +2, 223, 4, 18, 5, 224, 4, 1, 0, 82, 2, 133, 2, 134, 2, 224, 4, 18, 5, 19, +5, 1, 0, 82, 2, 134, 2, 83, 2, 224, 4, 19, 5, 225, 4, 1, 0, 83, 2, 134, +2, 135, 2, 225, 4, 19, 5, 20, 5, 1, 0, 83, 2, 135, 2, 84, 2, 225, 4, 20, +5, 226, 4, 1, 0, 84, 2, 135, 2, 136, 2, 226, 4, 20, 5, 21, 5, 1, 0, 84, +2, 136, 2, 85, 2, 226, 4, 21, 5, 227, 4, 1, 0, 85, 2, 136, 2, 137, 2, 227, +4, 21, 5, 22, 5, 1, 0, 85, 2, 137, 2, 86, 2, 227, 4, 22, 5, 228, 4, 1, +0, 86, 2, 137, 2, 138, 2, 228, 4, 22, 5, 23, 5, 1, 0, 86, 2, 138, 2, 87, +2, 228, 4, 23, 5, 229, 4, 1, 0, 87, 2, 138, 2, 139, 2, 229, 4, 23, 5, 24, +5, 1, 0, 87, 2, 139, 2, 88, 2, 229, 4, 24, 5, 230, 4, 1, 0, 88, 2, 139, +2, 140, 2, 230, 4, 24, 5, 25, 5, 1, 0, 88, 2, 140, 2, 89, 2, 230, 4, 25, +5, 231, 4, 1, 0, 89, 2, 140, 2, 141, 2, 231, 4, 25, 5, 26, 5, 1, 0, 89, +2, 141, 2, 90, 2, 231, 4, 26, 5, 232, 4, 1, 0, 90, 2, 141, 2, 142, 2, 232, +4, 26, 5, 27, 5, 1, 0, 90, 2, 142, 2, 91, 2, 232, 4, 27, 5, 233, 4, 1, +0, 91, 2, 142, 2, 143, 2, 233, 4, 27, 5, 28, 5, 1, 0, 91, 2, 143, 2, 92, +2, 233, 4, 28, 5, 234, 4, 1, 0, 92, 2, 143, 2, 144, 2, 234, 4, 28, 5, 29, +5, 1, 0, 92, 2, 144, 2, 93, 2, 234, 4, 29, 5, 235, 4, 1, 0, 93, 2, 144, +2, 145, 2, 235, 4, 29, 5, 30, 5, 1, 0, 93, 2, 145, 2, 94, 2, 235, 4, 30, +5, 236, 4, 1, 0, 94, 2, 145, 2, 146, 2, 236, 4, 30, 5, 31, 5, 1, 0, 94, +2, 146, 2, 95, 2, 236, 4, 31, 5, 237, 4, 1, 0, 95, 2, 146, 2, 147, 2, 237, +4, 31, 5, 32, 5, 1, 0, 95, 2, 147, 2, 96, 2, 237, 4, 32, 5, 238, 4, 1, +0, 96, 2, 147, 2, 148, 2, 238, 4, 32, 5, 33, 5, 1, 0, 96, 2, 148, 2, 97, +2, 238, 4, 33, 5, 239, 4, 1, 0, 97, 2, 148, 2, 149, 2, 239, 4, 33, 5, 240, +4, 1, 0, 97, 2, 149, 2, 98, 2, 239, 4, 240, 4, 190, 4, 1, 0, 99, 2, 150, +2, 151, 2, 240, 4, 34, 5, 35, 5, 1, 0, 99, 2, 151, 2, 100, 2, 240, 4, 35, +5, 241, 4, 1, 0, 100, 2, 151, 2, 152, 2, 241, 4, 35, 5, 36, 5, 1, 0, 100, +2, 152, 2, 101, 2, 241, 4, 36, 5, 242, 4, 1, 0, 101, 2, 152, 2, 153, 2, 242, +4, 36, 5, 37, 5, 1, 0, 101, 2, 153, 2, 102, 2, 242, 4, 37, 5, 243, 4, 1, +0, 102, 2, 153, 2, 154, 2, 243, 4, 37, 5, 38, 5, 1, 0, 102, 2, 154, 2, 103, +2, 243, 4, 38, 5, 244, 4, 1, 0, 103, 2, 154, 2, 155, 2, 244, 4, 38, 5, 39, +5, 1, 0, 103, 2, 155, 2, 104, 2, 244, 4, 39, 5, 245, 4, 1, 0, 104, 2, 155, +2, 156, 2, 245, 4, 39, 5, 40, 5, 1, 0, 104, 2, 156, 2, 105, 2, 245, 4, 40, +5, 246, 4, 1, 0, 105, 2, 156, 2, 157, 2, 246, 4, 40, 5, 41, 5, 1, 0, 105, +2, 157, 2, 106, 2, 246, 4, 41, 5, 247, 4, 1, 0, 106, 2, 157, 2, 158, 2, 247, +4, 41, 5, 42, 5, 1, 0, 106, 2, 158, 2, 107, 2, 247, 4, 42, 5, 248, 4, 1, +0, 107, 2, 158, 2, 159, 2, 248, 4, 42, 5, 43, 5, 1, 0, 107, 2, 159, 2, 108, +2, 248, 4, 43, 5, 249, 4, 1, 0, 108, 2, 159, 2, 160, 2, 249, 4, 43, 5, 44, +5, 1, 0, 108, 2, 160, 2, 109, 2, 249, 4, 44, 5, 250, 4, 1, 0, 109, 2, 160, +2, 161, 2, 250, 4, 44, 5, 45, 5, 1, 0, 109, 2, 161, 2, 110, 2, 250, 4, 45, +5, 251, 4, 1, 0, 110, 2, 161, 2, 162, 2, 251, 4, 45, 5, 46, 5, 1, 0, 110, +2, 162, 2, 111, 2, 251, 4, 46, 5, 252, 4, 1, 0, 111, 2, 162, 2, 163, 2, 252, +4, 46, 5, 47, 5, 1, 0, 111, 2, 163, 2, 112, 2, 252, 4, 47, 5, 253, 4, 1, +0, 112, 2, 163, 2, 164, 2, 253, 4, 47, 5, 48, 5, 1, 0, 112, 2, 164, 2, 113, +2, 253, 4, 48, 5, 254, 4, 1, 0, 113, 2, 164, 2, 165, 2, 254, 4, 48, 5, 49, +5, 1, 0, 113, 2, 165, 2, 114, 2, 254, 4, 49, 5, 255, 4, 1, 0, 114, 2, 165, +2, 166, 2, 255, 4, 49, 5, 50, 5, 1, 0, 114, 2, 166, 2, 115, 2, 255, 4, 50, +5, 0, 5, 1, 0, 115, 2, 166, 2, 167, 2, 0, 5, 50, 5, 51, 5, 1, 0, 115, +2, 167, 2, 116, 2, 0, 5, 51, 5, 1, 5, 1, 0, 116, 2, 167, 2, 168, 2, 1, +5, 51, 5, 52, 5, 1, 0, 116, 2, 168, 2, 117, 2, 1, 5, 52, 5, 2, 5, 1, +0, 117, 2, 168, 2, 169, 2, 2, 5, 52, 5, 53, 5, 1, 0, 117, 2, 169, 2, 118, +2, 2, 5, 53, 5, 3, 5, 1, 0, 118, 2, 169, 2, 170, 2, 3, 5, 53, 5, 54, +5, 1, 0, 118, 2, 170, 2, 119, 2, 3, 5, 54, 5, 4, 5, 1, 0, 119, 2, 170, +2, 171, 2, 4, 5, 54, 5, 55, 5, 1, 0, 119, 2, 171, 2, 120, 2, 4, 5, 55, +5, 5, 5, 1, 0, 120, 2, 171, 2, 172, 2, 5, 5, 55, 5, 56, 5, 1, 0, 120, +2, 172, 2, 121, 2, 5, 5, 56, 5, 6, 5, 1, 0, 121, 2, 172, 2, 173, 2, 6, +5, 56, 5, 57, 5, 1, 0, 121, 2, 173, 2, 122, 2, 6, 5, 57, 5, 7, 5, 1, +0, 122, 2, 173, 2, 174, 2, 7, 5, 57, 5, 58, 5, 1, 0, 122, 2, 174, 2, 123, +2, 7, 5, 58, 5, 8, 5, 1, 0, 123, 2, 174, 2, 175, 2, 8, 5, 58, 5, 59, +5, 1, 0, 123, 2, 175, 2, 124, 2, 8, 5, 59, 5, 9, 5, 1, 0, 124, 2, 175, +2, 176, 2, 9, 5, 59, 5, 60, 5, 1, 0, 124, 2, 176, 2, 125, 2, 9, 5, 60, +5, 10, 5, 1, 0, 125, 2, 176, 2, 177, 2, 10, 5, 60, 5, 61, 5, 1, 0, 125, +2, 177, 2, 126, 2, 10, 5, 61, 5, 11, 5, 1, 0, 126, 2, 177, 2, 178, 2, 11, +5, 61, 5, 62, 5, 1, 0, 126, 2, 178, 2, 127, 2, 11, 5, 62, 5, 12, 5, 1, +0, 127, 2, 178, 2, 179, 2, 12, 5, 62, 5, 63, 5, 1, 0, 127, 2, 179, 2, 128, +2, 12, 5, 63, 5, 13, 5, 1, 0, 128, 2, 179, 2, 180, 2, 13, 5, 63, 5, 64, +5, 1, 0, 128, 2, 180, 2, 129, 2, 13, 5, 64, 5, 14, 5, 1, 0, 129, 2, 180, +2, 181, 2, 14, 5, 64, 5, 65, 5, 1, 0, 129, 2, 181, 2, 130, 2, 14, 5, 65, +5, 15, 5, 1, 0, 130, 2, 181, 2, 182, 2, 15, 5, 65, 5, 66, 5, 1, 0, 130, +2, 182, 2, 131, 2, 15, 5, 66, 5, 16, 5, 1, 0, 131, 2, 182, 2, 183, 2, 16, +5, 66, 5, 67, 5, 1, 0, 131, 2, 183, 2, 132, 2, 16, 5, 67, 5, 17, 5, 1, +0, 132, 2, 183, 2, 184, 2, 17, 5, 67, 5, 68, 5, 1, 0, 132, 2, 184, 2, 133, +2, 17, 5, 68, 5, 18, 5, 1, 0, 133, 2, 184, 2, 185, 2, 18, 5, 68, 5, 69, +5, 1, 0, 133, 2, 185, 2, 134, 2, 18, 5, 69, 5, 19, 5, 1, 0, 134, 2, 185, +2, 186, 2, 19, 5, 69, 5, 70, 5, 1, 0, 134, 2, 186, 2, 135, 2, 19, 5, 70, +5, 20, 5, 1, 0, 135, 2, 186, 2, 187, 2, 20, 5, 70, 5, 71, 5, 1, 0, 135, +2, 187, 2, 136, 2, 20, 5, 71, 5, 21, 5, 1, 0, 136, 2, 187, 2, 188, 2, 21, +5, 71, 5, 72, 5, 1, 0, 136, 2, 188, 2, 137, 2, 21, 5, 72, 5, 22, 5, 1, +0, 137, 2, 188, 2, 189, 2, 22, 5, 72, 5, 73, 5, 1, 0, 137, 2, 189, 2, 138, +2, 22, 5, 73, 5, 23, 5, 1, 0, 138, 2, 189, 2, 190, 2, 23, 5, 73, 5, 74, +5, 1, 0, 138, 2, 190, 2, 139, 2, 23, 5, 74, 5, 24, 5, 1, 0, 139, 2, 190, +2, 191, 2, 24, 5, 74, 5, 75, 5, 1, 0, 139, 2, 191, 2, 140, 2, 24, 5, 75, +5, 25, 5, 1, 0, 140, 2, 191, 2, 192, 2, 25, 5, 75, 5, 76, 5, 1, 0, 140, +2, 192, 2, 141, 2, 25, 5, 76, 5, 26, 5, 1, 0, 141, 2, 192, 2, 193, 2, 26, +5, 76, 5, 77, 5, 1, 0, 141, 2, 193, 2, 142, 2, 26, 5, 77, 5, 27, 5, 1, +0, 142, 2, 193, 2, 194, 2, 27, 5, 77, 5, 78, 5, 1, 0, 142, 2, 194, 2, 143, +2, 27, 5, 78, 5, 28, 5, 1, 0, 143, 2, 194, 2, 195, 2, 28, 5, 78, 5, 79, +5, 1, 0, 143, 2, 195, 2, 144, 2, 28, 5, 79, 5, 29, 5, 1, 0, 144, 2, 195, +2, 196, 2, 29, 5, 79, 5, 80, 5, 1, 0, 144, 2, 196, 2, 145, 2, 29, 5, 80, +5, 30, 5, 1, 0, 145, 2, 196, 2, 197, 2, 30, 5, 80, 5, 81, 5, 1, 0, 145, +2, 197, 2, 146, 2, 30, 5, 81, 5, 31, 5, 1, 0, 146, 2, 197, 2, 198, 2, 31, +5, 81, 5, 82, 5, 1, 0, 146, 2, 198, 2, 147, 2, 31, 5, 82, 5, 32, 5, 1, +0, 147, 2, 198, 2, 199, 2, 32, 5, 82, 5, 83, 5, 1, 0, 147, 2, 199, 2, 148, +2, 32, 5, 83, 5, 33, 5, 1, 0, 148, 2, 199, 2, 200, 2, 33, 5, 83, 5, 34, +5, 1, 0, 148, 2, 200, 2, 149, 2, 33, 5, 34, 5, 240, 4, 1, 0, 150, 2, 201, +2, 202, 2, 34, 5, 84, 5, 85, 5, 1, 0, 150, 2, 202, 2, 151, 2, 34, 5, 85, +5, 35, 5, 1, 0, 151, 2, 202, 2, 203, 2, 35, 5, 85, 5, 86, 5, 1, 0, 151, +2, 203, 2, 152, 2, 35, 5, 86, 5, 36, 5, 1, 0, 152, 2, 203, 2, 204, 2, 36, +5, 86, 5, 87, 5, 1, 0, 152, 2, 204, 2, 153, 2, 36, 5, 87, 5, 37, 5, 1, +0, 153, 2, 204, 2, 205, 2, 37, 5, 87, 5, 88, 5, 1, 0, 153, 2, 205, 2, 154, +2, 37, 5, 88, 5, 38, 5, 1, 0, 154, 2, 205, 2, 206, 2, 38, 5, 88, 5, 89, +5, 1, 0, 154, 2, 206, 2, 155, 2, 38, 5, 89, 5, 39, 5, 1, 0, 155, 2, 206, +2, 207, 2, 39, 5, 89, 5, 90, 5, 1, 0, 155, 2, 207, 2, 156, 2, 39, 5, 90, +5, 40, 5, 1, 0, 156, 2, 207, 2, 208, 2, 40, 5, 90, 5, 91, 5, 1, 0, 156, +2, 208, 2, 157, 2, 40, 5, 91, 5, 41, 5, 1, 0, 157, 2, 208, 2, 209, 2, 41, +5, 91, 5, 92, 5, 1, 0, 157, 2, 209, 2, 158, 2, 41, 5, 92, 5, 42, 5, 1, +0, 158, 2, 209, 2, 210, 2, 42, 5, 92, 5, 93, 5, 1, 0, 158, 2, 210, 2, 159, +2, 42, 5, 93, 5, 43, 5, 1, 0, 159, 2, 210, 2, 211, 2, 43, 5, 93, 5, 94, +5, 1, 0, 159, 2, 211, 2, 160, 2, 43, 5, 94, 5, 44, 5, 1, 0, 160, 2, 211, +2, 212, 2, 44, 5, 94, 5, 95, 5, 1, 0, 160, 2, 212, 2, 161, 2, 44, 5, 95, +5, 45, 5, 1, 0, 161, 2, 212, 2, 213, 2, 45, 5, 95, 5, 96, 5, 1, 0, 161, +2, 213, 2, 162, 2, 45, 5, 96, 5, 46, 5, 1, 0, 162, 2, 213, 2, 214, 2, 46, +5, 96, 5, 97, 5, 1, 0, 162, 2, 214, 2, 163, 2, 46, 5, 97, 5, 47, 5, 1, +0, 163, 2, 214, 2, 215, 2, 47, 5, 97, 5, 98, 5, 1, 0, 163, 2, 215, 2, 164, +2, 47, 5, 98, 5, 48, 5, 1, 0, 164, 2, 215, 2, 216, 2, 48, 5, 98, 5, 99, +5, 1, 0, 164, 2, 216, 2, 165, 2, 48, 5, 99, 5, 49, 5, 1, 0, 165, 2, 216, +2, 217, 2, 49, 5, 99, 5, 100, 5, 1, 0, 165, 2, 217, 2, 166, 2, 49, 5, 100, +5, 50, 5, 1, 0, 166, 2, 217, 2, 218, 2, 50, 5, 100, 5, 101, 5, 1, 0, 166, +2, 218, 2, 167, 2, 50, 5, 101, 5, 51, 5, 1, 0, 167, 2, 218, 2, 219, 2, 51, +5, 101, 5, 102, 5, 1, 0, 167, 2, 219, 2, 168, 2, 51, 5, 102, 5, 52, 5, 1, +0, 168, 2, 219, 2, 220, 2, 52, 5, 102, 5, 103, 5, 1, 0, 168, 2, 220, 2, 169, +2, 52, 5, 103, 5, 53, 5, 1, 0, 169, 2, 220, 2, 221, 2, 53, 5, 103, 5, 104, +5, 1, 0, 169, 2, 221, 2, 170, 2, 53, 5, 104, 5, 54, 5, 1, 0, 170, 2, 221, +2, 222, 2, 54, 5, 104, 5, 105, 5, 1, 0, 170, 2, 222, 2, 171, 2, 54, 5, 105, +5, 55, 5, 1, 0, 171, 2, 222, 2, 223, 2, 55, 5, 105, 5, 106, 5, 1, 0, 171, +2, 223, 2, 172, 2, 55, 5, 106, 5, 56, 5, 1, 0, 172, 2, 223, 2, 224, 2, 56, +5, 106, 5, 107, 5, 1, 0, 172, 2, 224, 2, 173, 2, 56, 5, 107, 5, 57, 5, 1, +0, 173, 2, 224, 2, 225, 2, 57, 5, 107, 5, 108, 5, 1, 0, 173, 2, 225, 2, 174, +2, 57, 5, 108, 5, 58, 5, 1, 0, 174, 2, 225, 2, 226, 2, 58, 5, 108, 5, 109, +5, 1, 0, 174, 2, 226, 2, 175, 2, 58, 5, 109, 5, 59, 5, 1, 0, 175, 2, 226, +2, 227, 2, 59, 5, 109, 5, 110, 5, 1, 0, 175, 2, 227, 2, 176, 2, 59, 5, 110, +5, 60, 5, 1, 0, 176, 2, 227, 2, 228, 2, 60, 5, 110, 5, 111, 5, 1, 0, 176, +2, 228, 2, 177, 2, 60, 5, 111, 5, 61, 5, 1, 0, 177, 2, 228, 2, 229, 2, 61, +5, 111, 5, 112, 5, 1, 0, 177, 2, 229, 2, 178, 2, 61, 5, 112, 5, 62, 5, 1, +0, 178, 2, 229, 2, 230, 2, 62, 5, 112, 5, 113, 5, 1, 0, 178, 2, 230, 2, 179, +2, 62, 5, 113, 5, 63, 5, 1, 0, 179, 2, 230, 2, 231, 2, 63, 5, 113, 5, 114, +5, 1, 0, 179, 2, 231, 2, 180, 2, 63, 5, 114, 5, 64, 5, 1, 0, 180, 2, 231, +2, 232, 2, 64, 5, 114, 5, 115, 5, 1, 0, 180, 2, 232, 2, 181, 2, 64, 5, 115, +5, 65, 5, 1, 0, 181, 2, 232, 2, 233, 2, 65, 5, 115, 5, 116, 5, 1, 0, 181, +2, 233, 2, 182, 2, 65, 5, 116, 5, 66, 5, 1, 0, 182, 2, 233, 2, 234, 2, 66, +5, 116, 5, 117, 5, 1, 0, 182, 2, 234, 2, 183, 2, 66, 5, 117, 5, 67, 5, 1, +0, 183, 2, 234, 2, 235, 2, 67, 5, 117, 5, 118, 5, 1, 0, 183, 2, 235, 2, 184, +2, 67, 5, 118, 5, 68, 5, 1, 0, 184, 2, 235, 2, 236, 2, 68, 5, 118, 5, 119, +5, 1, 0, 184, 2, 236, 2, 185, 2, 68, 5, 119, 5, 69, 5, 1, 0, 185, 2, 236, +2, 237, 2, 69, 5, 119, 5, 120, 5, 1, 0, 185, 2, 237, 2, 186, 2, 69, 5, 120, +5, 70, 5, 1, 0, 186, 2, 237, 2, 238, 2, 70, 5, 120, 5, 121, 5, 1, 0, 186, +2, 238, 2, 187, 2, 70, 5, 121, 5, 71, 5, 1, 0, 187, 2, 238, 2, 239, 2, 71, +5, 121, 5, 122, 5, 1, 0, 187, 2, 239, 2, 188, 2, 71, 5, 122, 5, 72, 5, 1, +0, 188, 2, 239, 2, 240, 2, 72, 5, 122, 5, 123, 5, 1, 0, 188, 2, 240, 2, 189, +2, 72, 5, 123, 5, 73, 5, 1, 0, 189, 2, 240, 2, 241, 2, 73, 5, 123, 5, 124, +5, 1, 0, 189, 2, 241, 2, 190, 2, 73, 5, 124, 5, 74, 5, 1, 0, 190, 2, 241, +2, 242, 2, 74, 5, 124, 5, 125, 5, 1, 0, 190, 2, 242, 2, 191, 2, 74, 5, 125, +5, 75, 5, 1, 0, 191, 2, 242, 2, 243, 2, 75, 5, 125, 5, 126, 5, 1, 0, 191, +2, 243, 2, 192, 2, 75, 5, 126, 5, 76, 5, 1, 0, 192, 2, 243, 2, 244, 2, 76, +5, 126, 5, 127, 5, 1, 0, 192, 2, 244, 2, 193, 2, 76, 5, 127, 5, 77, 5, 1, +0, 193, 2, 244, 2, 245, 2, 77, 5, 127, 5, 128, 5, 1, 0, 193, 2, 245, 2, 194, +2, 77, 5, 128, 5, 78, 5, 1, 0, 194, 2, 245, 2, 246, 2, 78, 5, 128, 5, 129, +5, 1, 0, 194, 2, 246, 2, 195, 2, 78, 5, 129, 5, 79, 5, 1, 0, 195, 2, 246, +2, 247, 2, 79, 5, 129, 5, 130, 5, 1, 0, 195, 2, 247, 2, 196, 2, 79, 5, 130, +5, 80, 5, 1, 0, 196, 2, 247, 2, 248, 2, 80, 5, 130, 5, 131, 5, 1, 0, 196, +2, 248, 2, 197, 2, 80, 5, 131, 5, 81, 5, 1, 0, 197, 2, 248, 2, 249, 2, 81, +5, 131, 5, 132, 5, 1, 0, 197, 2, 249, 2, 198, 2, 81, 5, 132, 5, 82, 5, 1, +0, 198, 2, 249, 2, 250, 2, 82, 5, 132, 5, 133, 5, 1, 0, 198, 2, 250, 2, 199, +2, 82, 5, 133, 5, 83, 5, 1, 0, 199, 2, 250, 2, 251, 2, 83, 5, 133, 5, 84, +5, 1, 0, 199, 2, 251, 2, 200, 2, 83, 5, 84, 5, 34, 5, 1, 0, 201, 2, 252, +2, 253, 2, 84, 5, 134, 5, 135, 5, 1, 0, 201, 2, 253, 2, 202, 2, 84, 5, 135, +5, 85, 5, 1, 0, 202, 2, 253, 2, 254, 2, 85, 5, 135, 5, 136, 5, 1, 0, 202, +2, 254, 2, 203, 2, 85, 5, 136, 5, 86, 5, 1, 0, 203, 2, 254, 2, 255, 2, 86, +5, 136, 5, 137, 5, 1, 0, 203, 2, 255, 2, 204, 2, 86, 5, 137, 5, 87, 5, 1, +0, 204, 2, 255, 2, 0, 3, 87, 5, 137, 5, 138, 5, 1, 0, 204, 2, 0, 3, 205, +2, 87, 5, 138, 5, 88, 5, 1, 0, 205, 2, 0, 3, 1, 3, 88, 5, 138, 5, 139, +5, 1, 0, 205, 2, 1, 3, 206, 2, 88, 5, 139, 5, 89, 5, 1, 0, 206, 2, 1, +3, 2, 3, 89, 5, 139, 5, 140, 5, 1, 0, 206, 2, 2, 3, 207, 2, 89, 5, 140, +5, 90, 5, 1, 0, 207, 2, 2, 3, 3, 3, 90, 5, 140, 5, 141, 5, 1, 0, 207, +2, 3, 3, 208, 2, 90, 5, 141, 5, 91, 5, 1, 0, 208, 2, 3, 3, 4, 3, 91, +5, 141, 5, 142, 5, 1, 0, 208, 2, 4, 3, 209, 2, 91, 5, 142, 5, 92, 5, 1, +0, 209, 2, 4, 3, 5, 3, 92, 5, 142, 5, 143, 5, 1, 0, 209, 2, 5, 3, 210, +2, 92, 5, 143, 5, 93, 5, 1, 0, 210, 2, 5, 3, 6, 3, 93, 5, 143, 5, 144, +5, 1, 0, 210, 2, 6, 3, 211, 2, 93, 5, 144, 5, 94, 5, 1, 0, 211, 2, 6, +3, 7, 3, 94, 5, 144, 5, 145, 5, 1, 0, 211, 2, 7, 3, 212, 2, 94, 5, 145, +5, 95, 5, 1, 0, 212, 2, 7, 3, 8, 3, 95, 5, 145, 5, 146, 5, 1, 0, 212, +2, 8, 3, 213, 2, 95, 5, 146, 5, 96, 5, 1, 0, 213, 2, 8, 3, 9, 3, 96, +5, 146, 5, 147, 5, 1, 0, 213, 2, 9, 3, 214, 2, 96, 5, 147, 5, 97, 5, 1, +0, 214, 2, 9, 3, 10, 3, 97, 5, 147, 5, 148, 5, 1, 0, 214, 2, 10, 3, 215, +2, 97, 5, 148, 5, 98, 5, 1, 0, 215, 2, 10, 3, 11, 3, 98, 5, 148, 5, 149, +5, 1, 0, 215, 2, 11, 3, 216, 2, 98, 5, 149, 5, 99, 5, 1, 0, 216, 2, 11, +3, 12, 3, 99, 5, 149, 5, 150, 5, 1, 0, 216, 2, 12, 3, 217, 2, 99, 5, 150, +5, 100, 5, 1, 0, 217, 2, 12, 3, 13, 3, 100, 5, 150, 5, 151, 5, 1, 0, 217, +2, 13, 3, 218, 2, 100, 5, 151, 5, 101, 5, 1, 0, 218, 2, 13, 3, 14, 3, 101, +5, 151, 5, 152, 5, 1, 0, 218, 2, 14, 3, 219, 2, 101, 5, 152, 5, 102, 5, 1, +0, 219, 2, 14, 3, 15, 3, 102, 5, 152, 5, 153, 5, 1, 0, 219, 2, 15, 3, 220, +2, 102, 5, 153, 5, 103, 5, 1, 0, 220, 2, 15, 3, 16, 3, 103, 5, 153, 5, 154, +5, 1, 0, 220, 2, 16, 3, 221, 2, 103, 5, 154, 5, 104, 5, 1, 0, 221, 2, 16, +3, 17, 3, 104, 5, 154, 5, 155, 5, 1, 0, 221, 2, 17, 3, 222, 2, 104, 5, 155, +5, 105, 5, 1, 0, 222, 2, 17, 3, 18, 3, 105, 5, 155, 5, 156, 5, 1, 0, 222, +2, 18, 3, 223, 2, 105, 5, 156, 5, 106, 5, 1, 0, 223, 2, 18, 3, 19, 3, 106, +5, 156, 5, 157, 5, 1, 0, 223, 2, 19, 3, 224, 2, 106, 5, 157, 5, 107, 5, 1, +0, 224, 2, 19, 3, 20, 3, 107, 5, 157, 5, 158, 5, 1, 0, 224, 2, 20, 3, 225, +2, 107, 5, 158, 5, 108, 5, 1, 0, 225, 2, 20, 3, 21, 3, 108, 5, 158, 5, 159, +5, 1, 0, 225, 2, 21, 3, 226, 2, 108, 5, 159, 5, 109, 5, 1, 0, 226, 2, 21, +3, 22, 3, 109, 5, 159, 5, 160, 5, 1, 0, 226, 2, 22, 3, 227, 2, 109, 5, 160, +5, 110, 5, 1, 0, 227, 2, 22, 3, 23, 3, 110, 5, 160, 5, 161, 5, 1, 0, 227, +2, 23, 3, 228, 2, 110, 5, 161, 5, 111, 5, 1, 0, 228, 2, 23, 3, 24, 3, 111, +5, 161, 5, 162, 5, 1, 0, 228, 2, 24, 3, 229, 2, 111, 5, 162, 5, 112, 5, 1, +0, 229, 2, 24, 3, 25, 3, 112, 5, 162, 5, 163, 5, 1, 0, 229, 2, 25, 3, 230, +2, 112, 5, 163, 5, 113, 5, 1, 0, 230, 2, 25, 3, 26, 3, 113, 5, 163, 5, 164, +5, 1, 0, 230, 2, 26, 3, 231, 2, 113, 5, 164, 5, 114, 5, 1, 0, 231, 2, 26, +3, 27, 3, 114, 5, 164, 5, 165, 5, 1, 0, 231, 2, 27, 3, 232, 2, 114, 5, 165, +5, 115, 5, 1, 0, 232, 2, 27, 3, 28, 3, 115, 5, 165, 5, 166, 5, 1, 0, 232, +2, 28, 3, 233, 2, 115, 5, 166, 5, 116, 5, 1, 0, 233, 2, 28, 3, 29, 3, 116, +5, 166, 5, 167, 5, 1, 0, 233, 2, 29, 3, 234, 2, 116, 5, 167, 5, 117, 5, 1, +0, 234, 2, 29, 3, 30, 3, 117, 5, 167, 5, 168, 5, 1, 0, 234, 2, 30, 3, 235, +2, 117, 5, 168, 5, 118, 5, 1, 0, 235, 2, 30, 3, 31, 3, 118, 5, 168, 5, 169, +5, 1, 0, 235, 2, 31, 3, 236, 2, 118, 5, 169, 5, 119, 5, 1, 0, 236, 2, 31, +3, 32, 3, 119, 5, 169, 5, 170, 5, 1, 0, 236, 2, 32, 3, 237, 2, 119, 5, 170, +5, 120, 5, 1, 0, 237, 2, 32, 3, 33, 3, 120, 5, 170, 5, 171, 5, 1, 0, 237, +2, 33, 3, 238, 2, 120, 5, 171, 5, 121, 5, 1, 0, 238, 2, 33, 3, 34, 3, 121, +5, 171, 5, 172, 5, 1, 0, 238, 2, 34, 3, 239, 2, 121, 5, 172, 5, 122, 5, 1, +0, 239, 2, 34, 3, 35, 3, 122, 5, 172, 5, 173, 5, 1, 0, 239, 2, 35, 3, 240, +2, 122, 5, 173, 5, 123, 5, 1, 0, 240, 2, 35, 3, 36, 3, 123, 5, 173, 5, 174, +5, 1, 0, 240, 2, 36, 3, 241, 2, 123, 5, 174, 5, 124, 5, 1, 0, 241, 2, 36, +3, 37, 3, 124, 5, 174, 5, 175, 5, 1, 0, 241, 2, 37, 3, 242, 2, 124, 5, 175, +5, 125, 5, 1, 0, 242, 2, 37, 3, 38, 3, 125, 5, 175, 5, 176, 5, 1, 0, 242, +2, 38, 3, 243, 2, 125, 5, 176, 5, 126, 5, 1, 0, 243, 2, 38, 3, 39, 3, 126, +5, 176, 5, 177, 5, 1, 0, 243, 2, 39, 3, 244, 2, 126, 5, 177, 5, 127, 5, 1, +0, 244, 2, 39, 3, 40, 3, 127, 5, 177, 5, 178, 5, 1, 0, 244, 2, 40, 3, 245, +2, 127, 5, 178, 5, 128, 5, 1, 0, 245, 2, 40, 3, 41, 3, 128, 5, 178, 5, 179, +5, 1, 0, 245, 2, 41, 3, 246, 2, 128, 5, 179, 5, 129, 5, 1, 0, 246, 2, 41, +3, 42, 3, 129, 5, 179, 5, 180, 5, 1, 0, 246, 2, 42, 3, 247, 2, 129, 5, 180, +5, 130, 5, 1, 0, 247, 2, 42, 3, 43, 3, 130, 5, 180, 5, 181, 5, 1, 0, 247, +2, 43, 3, 248, 2, 130, 5, 181, 5, 131, 5, 1, 0, 248, 2, 43, 3, 44, 3, 131, +5, 181, 5, 182, 5, 1, 0, 248, 2, 44, 3, 249, 2, 131, 5, 182, 5, 132, 5, 1, +0, 249, 2, 44, 3, 45, 3, 132, 5, 182, 5, 183, 5, 1, 0, 249, 2, 45, 3, 250, +2, 132, 5, 183, 5, 133, 5, 1, 0, 250, 2, 45, 3, 46, 3, 133, 5, 183, 5, 134, +5, 1, 0, 250, 2, 46, 3, 251, 2, 133, 5, 134, 5, 84, 5, 1, 0, 252, 2, 47, +3, 48, 3, 134, 5, 184, 5, 185, 5, 1, 0, 252, 2, 48, 3, 253, 2, 134, 5, 185, +5, 135, 5, 1, 0, 253, 2, 48, 3, 49, 3, 135, 5, 185, 5, 186, 5, 1, 0, 253, +2, 49, 3, 254, 2, 135, 5, 186, 5, 136, 5, 1, 0, 254, 2, 49, 3, 50, 3, 136, +5, 186, 5, 187, 5, 1, 0, 254, 2, 50, 3, 255, 2, 136, 5, 187, 5, 137, 5, 1, +0, 255, 2, 50, 3, 51, 3, 137, 5, 187, 5, 188, 5, 1, 0, 255, 2, 51, 3, 0, +3, 137, 5, 188, 5, 138, 5, 1, 0, 0, 3, 51, 3, 52, 3, 138, 5, 188, 5, 189, +5, 1, 0, 0, 3, 52, 3, 1, 3, 138, 5, 189, 5, 139, 5, 1, 0, 1, 3, 52, +3, 53, 3, 139, 5, 189, 5, 190, 5, 1, 0, 1, 3, 53, 3, 2, 3, 139, 5, 190, +5, 140, 5, 1, 0, 2, 3, 53, 3, 54, 3, 140, 5, 190, 5, 191, 5, 1, 0, 2, +3, 54, 3, 3, 3, 140, 5, 191, 5, 141, 5, 1, 0, 3, 3, 54, 3, 55, 3, 141, +5, 191, 5, 192, 5, 1, 0, 3, 3, 55, 3, 4, 3, 141, 5, 192, 5, 142, 5, 1, +0, 4, 3, 55, 3, 56, 3, 142, 5, 192, 5, 193, 5, 1, 0, 4, 3, 56, 3, 5, +3, 142, 5, 193, 5, 143, 5, 1, 0, 5, 3, 56, 3, 57, 3, 143, 5, 193, 5, 194, +5, 1, 0, 5, 3, 57, 3, 6, 3, 143, 5, 194, 5, 144, 5, 1, 0, 6, 3, 57, +3, 58, 3, 144, 5, 194, 5, 195, 5, 1, 0, 6, 3, 58, 3, 7, 3, 144, 5, 195, +5, 145, 5, 1, 0, 7, 3, 58, 3, 59, 3, 145, 5, 195, 5, 196, 5, 1, 0, 7, +3, 59, 3, 8, 3, 145, 5, 196, 5, 146, 5, 1, 0, 8, 3, 59, 3, 60, 3, 146, +5, 196, 5, 197, 5, 1, 0, 8, 3, 60, 3, 9, 3, 146, 5, 197, 5, 147, 5, 1, +0, 9, 3, 60, 3, 61, 3, 147, 5, 197, 5, 198, 5, 1, 0, 9, 3, 61, 3, 10, +3, 147, 5, 198, 5, 148, 5, 1, 0, 10, 3, 61, 3, 62, 3, 148, 5, 198, 5, 199, +5, 1, 0, 10, 3, 62, 3, 11, 3, 148, 5, 199, 5, 149, 5, 1, 0, 11, 3, 62, +3, 63, 3, 149, 5, 199, 5, 200, 5, 1, 0, 11, 3, 63, 3, 12, 3, 149, 5, 200, +5, 150, 5, 1, 0, 12, 3, 63, 3, 64, 3, 150, 5, 200, 5, 201, 5, 1, 0, 12, +3, 64, 3, 13, 3, 150, 5, 201, 5, 151, 5, 1, 0, 13, 3, 64, 3, 65, 3, 151, +5, 201, 5, 202, 5, 1, 0, 13, 3, 65, 3, 14, 3, 151, 5, 202, 5, 152, 5, 1, +0, 14, 3, 65, 3, 66, 3, 152, 5, 202, 5, 203, 5, 1, 0, 14, 3, 66, 3, 15, +3, 152, 5, 203, 5, 153, 5, 1, 0, 15, 3, 66, 3, 67, 3, 153, 5, 203, 5, 204, +5, 1, 0, 15, 3, 67, 3, 16, 3, 153, 5, 204, 5, 154, 5, 1, 0, 16, 3, 67, +3, 68, 3, 154, 5, 204, 5, 205, 5, 1, 0, 16, 3, 68, 3, 17, 3, 154, 5, 205, +5, 155, 5, 1, 0, 17, 3, 68, 3, 69, 3, 155, 5, 205, 5, 206, 5, 1, 0, 17, +3, 69, 3, 18, 3, 155, 5, 206, 5, 156, 5, 1, 0, 18, 3, 69, 3, 70, 3, 156, +5, 206, 5, 207, 5, 1, 0, 18, 3, 70, 3, 19, 3, 156, 5, 207, 5, 157, 5, 1, +0, 19, 3, 70, 3, 71, 3, 157, 5, 207, 5, 208, 5, 1, 0, 19, 3, 71, 3, 20, +3, 157, 5, 208, 5, 158, 5, 1, 0, 20, 3, 71, 3, 72, 3, 158, 5, 208, 5, 209, +5, 1, 0, 20, 3, 72, 3, 21, 3, 158, 5, 209, 5, 159, 5, 1, 0, 21, 3, 72, +3, 73, 3, 159, 5, 209, 5, 210, 5, 1, 0, 21, 3, 73, 3, 22, 3, 159, 5, 210, +5, 160, 5, 1, 0, 22, 3, 73, 3, 74, 3, 160, 5, 210, 5, 211, 5, 1, 0, 22, +3, 74, 3, 23, 3, 160, 5, 211, 5, 161, 5, 1, 0, 23, 3, 74, 3, 75, 3, 161, +5, 211, 5, 212, 5, 1, 0, 23, 3, 75, 3, 24, 3, 161, 5, 212, 5, 162, 5, 1, +0, 24, 3, 75, 3, 76, 3, 162, 5, 212, 5, 213, 5, 1, 0, 24, 3, 76, 3, 25, +3, 162, 5, 213, 5, 163, 5, 1, 0, 25, 3, 76, 3, 77, 3, 163, 5, 213, 5, 214, +5, 1, 0, 25, 3, 77, 3, 26, 3, 163, 5, 214, 5, 164, 5, 1, 0, 26, 3, 77, +3, 78, 3, 164, 5, 214, 5, 215, 5, 1, 0, 26, 3, 78, 3, 27, 3, 164, 5, 215, +5, 165, 5, 1, 0, 27, 3, 78, 3, 79, 3, 165, 5, 215, 5, 216, 5, 1, 0, 27, +3, 79, 3, 28, 3, 165, 5, 216, 5, 166, 5, 1, 0, 28, 3, 79, 3, 80, 3, 166, +5, 216, 5, 217, 5, 1, 0, 28, 3, 80, 3, 29, 3, 166, 5, 217, 5, 167, 5, 1, +0, 29, 3, 80, 3, 81, 3, 167, 5, 217, 5, 218, 5, 1, 0, 29, 3, 81, 3, 30, +3, 167, 5, 218, 5, 168, 5, 1, 0, 30, 3, 81, 3, 82, 3, 168, 5, 218, 5, 219, +5, 1, 0, 30, 3, 82, 3, 31, 3, 168, 5, 219, 5, 169, 5, 1, 0, 31, 3, 82, +3, 83, 3, 169, 5, 219, 5, 220, 5, 1, 0, 31, 3, 83, 3, 32, 3, 169, 5, 220, +5, 170, 5, 1, 0, 32, 3, 83, 3, 84, 3, 170, 5, 220, 5, 221, 5, 1, 0, 32, +3, 84, 3, 33, 3, 170, 5, 221, 5, 171, 5, 1, 0, 33, 3, 84, 3, 85, 3, 171, +5, 221, 5, 222, 5, 1, 0, 33, 3, 85, 3, 34, 3, 171, 5, 222, 5, 172, 5, 1, +0, 34, 3, 85, 3, 86, 3, 172, 5, 222, 5, 223, 5, 1, 0, 34, 3, 86, 3, 35, +3, 172, 5, 223, 5, 173, 5, 1, 0, 35, 3, 86, 3, 87, 3, 173, 5, 223, 5, 224, +5, 1, 0, 35, 3, 87, 3, 36, 3, 173, 5, 224, 5, 174, 5, 1, 0, 36, 3, 87, +3, 88, 3, 174, 5, 224, 5, 225, 5, 1, 0, 36, 3, 88, 3, 37, 3, 174, 5, 225, +5, 175, 5, 1, 0, 37, 3, 88, 3, 89, 3, 175, 5, 225, 5, 226, 5, 1, 0, 37, +3, 89, 3, 38, 3, 175, 5, 226, 5, 176, 5, 1, 0, 38, 3, 89, 3, 90, 3, 176, +5, 226, 5, 227, 5, 1, 0, 38, 3, 90, 3, 39, 3, 176, 5, 227, 5, 177, 5, 1, +0, 39, 3, 90, 3, 91, 3, 177, 5, 227, 5, 228, 5, 1, 0, 39, 3, 91, 3, 40, +3, 177, 5, 228, 5, 178, 5, 1, 0, 40, 3, 91, 3, 92, 3, 178, 5, 228, 5, 229, +5, 1, 0, 40, 3, 92, 3, 41, 3, 178, 5, 229, 5, 179, 5, 1, 0, 41, 3, 92, +3, 93, 3, 179, 5, 229, 5, 230, 5, 1, 0, 41, 3, 93, 3, 42, 3, 179, 5, 230, +5, 180, 5, 1, 0, 42, 3, 93, 3, 94, 3, 180, 5, 230, 5, 231, 5, 1, 0, 42, +3, 94, 3, 43, 3, 180, 5, 231, 5, 181, 5, 1, 0, 43, 3, 94, 3, 95, 3, 181, +5, 231, 5, 232, 5, 1, 0, 43, 3, 95, 3, 44, 3, 181, 5, 232, 5, 182, 5, 1, +0, 44, 3, 95, 3, 96, 3, 182, 5, 232, 5, 233, 5, 1, 0, 44, 3, 96, 3, 45, +3, 182, 5, 233, 5, 183, 5, 1, 0, 45, 3, 96, 3, 97, 3, 183, 5, 233, 5, 184, +5, 1, 0, 45, 3, 97, 3, 46, 3, 183, 5, 184, 5, 134, 5, 1, 0, 47, 3, 98, +3, 99, 3, 184, 5, 234, 5, 235, 5, 1, 0, 47, 3, 99, 3, 48, 3, 184, 5, 235, +5, 185, 5, 1, 0, 48, 3, 99, 3, 100, 3, 185, 5, 235, 5, 236, 5, 1, 0, 48, +3, 100, 3, 49, 3, 185, 5, 236, 5, 186, 5, 1, 0, 49, 3, 100, 3, 101, 3, 186, +5, 236, 5, 237, 5, 1, 0, 49, 3, 101, 3, 50, 3, 186, 5, 237, 5, 187, 5, 1, +0, 50, 3, 101, 3, 102, 3, 187, 5, 237, 5, 238, 5, 1, 0, 50, 3, 102, 3, 51, +3, 187, 5, 238, 5, 188, 5, 1, 0, 51, 3, 102, 3, 103, 3, 188, 5, 238, 5, 239, +5, 1, 0, 51, 3, 103, 3, 52, 3, 188, 5, 239, 5, 189, 5, 1, 0, 52, 3, 103, +3, 104, 3, 189, 5, 239, 5, 240, 5, 1, 0, 52, 3, 104, 3, 53, 3, 189, 5, 240, +5, 190, 5, 1, 0, 53, 3, 104, 3, 105, 3, 190, 5, 240, 5, 241, 5, 1, 0, 53, +3, 105, 3, 54, 3, 190, 5, 241, 5, 191, 5, 1, 0, 54, 3, 105, 3, 106, 3, 191, +5, 241, 5, 242, 5, 1, 0, 54, 3, 106, 3, 55, 3, 191, 5, 242, 5, 192, 5, 1, +0, 55, 3, 106, 3, 107, 3, 192, 5, 242, 5, 243, 5, 1, 0, 55, 3, 107, 3, 56, +3, 192, 5, 243, 5, 193, 5, 1, 0, 56, 3, 107, 3, 108, 3, 193, 5, 243, 5, 244, +5, 1, 0, 56, 3, 108, 3, 57, 3, 193, 5, 244, 5, 194, 5, 1, 0, 57, 3, 108, +3, 109, 3, 194, 5, 244, 5, 245, 5, 1, 0, 57, 3, 109, 3, 58, 3, 194, 5, 245, +5, 195, 5, 1, 0, 58, 3, 109, 3, 110, 3, 195, 5, 245, 5, 246, 5, 1, 0, 58, +3, 110, 3, 59, 3, 195, 5, 246, 5, 196, 5, 1, 0, 59, 3, 110, 3, 111, 3, 196, +5, 246, 5, 247, 5, 1, 0, 59, 3, 111, 3, 60, 3, 196, 5, 247, 5, 197, 5, 1, +0, 60, 3, 111, 3, 112, 3, 197, 5, 247, 5, 248, 5, 1, 0, 60, 3, 112, 3, 61, +3, 197, 5, 248, 5, 198, 5, 1, 0, 61, 3, 112, 3, 113, 3, 198, 5, 248, 5, 249, +5, 1, 0, 61, 3, 113, 3, 62, 3, 198, 5, 249, 5, 199, 5, 1, 0, 62, 3, 113, +3, 114, 3, 199, 5, 249, 5, 250, 5, 1, 0, 62, 3, 114, 3, 63, 3, 199, 5, 250, +5, 200, 5, 1, 0, 63, 3, 114, 3, 115, 3, 200, 5, 250, 5, 251, 5, 1, 0, 63, +3, 115, 3, 64, 3, 200, 5, 251, 5, 201, 5, 1, 0, 64, 3, 115, 3, 116, 3, 201, +5, 251, 5, 252, 5, 1, 0, 64, 3, 116, 3, 65, 3, 201, 5, 252, 5, 202, 5, 1, +0, 65, 3, 116, 3, 117, 3, 202, 5, 252, 5, 253, 5, 1, 0, 65, 3, 117, 3, 66, +3, 202, 5, 253, 5, 203, 5, 1, 0, 66, 3, 117, 3, 118, 3, 203, 5, 253, 5, 254, +5, 1, 0, 66, 3, 118, 3, 67, 3, 203, 5, 254, 5, 204, 5, 1, 0, 67, 3, 118, +3, 119, 3, 204, 5, 254, 5, 255, 5, 1, 0, 67, 3, 119, 3, 68, 3, 204, 5, 255, +5, 205, 5, 1, 0, 68, 3, 119, 3, 120, 3, 205, 5, 255, 5, 0, 6, 1, 0, 68, +3, 120, 3, 69, 3, 205, 5, 0, 6, 206, 5, 1, 0, 69, 3, 120, 3, 121, 3, 206, +5, 0, 6, 1, 6, 1, 0, 69, 3, 121, 3, 70, 3, 206, 5, 1, 6, 207, 5, 1, +0, 70, 3, 121, 3, 122, 3, 207, 5, 1, 6, 2, 6, 1, 0, 70, 3, 122, 3, 71, +3, 207, 5, 2, 6, 208, 5, 1, 0, 71, 3, 122, 3, 123, 3, 208, 5, 2, 6, 3, +6, 1, 0, 71, 3, 123, 3, 72, 3, 208, 5, 3, 6, 209, 5, 1, 0, 72, 3, 123, +3, 124, 3, 209, 5, 3, 6, 4, 6, 1, 0, 72, 3, 124, 3, 73, 3, 209, 5, 4, +6, 210, 5, 1, 0, 73, 3, 124, 3, 125, 3, 210, 5, 4, 6, 5, 6, 1, 0, 73, +3, 125, 3, 74, 3, 210, 5, 5, 6, 211, 5, 1, 0, 74, 3, 125, 3, 126, 3, 211, +5, 5, 6, 6, 6, 1, 0, 74, 3, 126, 3, 75, 3, 211, 5, 6, 6, 212, 5, 1, +0, 75, 3, 126, 3, 127, 3, 212, 5, 6, 6, 7, 6, 1, 0, 75, 3, 127, 3, 76, +3, 212, 5, 7, 6, 213, 5, 1, 0, 76, 3, 127, 3, 128, 3, 213, 5, 7, 6, 8, +6, 1, 0, 76, 3, 128, 3, 77, 3, 213, 5, 8, 6, 214, 5, 1, 0, 77, 3, 128, +3, 129, 3, 214, 5, 8, 6, 9, 6, 1, 0, 77, 3, 129, 3, 78, 3, 214, 5, 9, +6, 215, 5, 1, 0, 78, 3, 129, 3, 130, 3, 215, 5, 9, 6, 10, 6, 1, 0, 78, +3, 130, 3, 79, 3, 215, 5, 10, 6, 216, 5, 1, 0, 79, 3, 130, 3, 131, 3, 216, +5, 10, 6, 11, 6, 1, 0, 79, 3, 131, 3, 80, 3, 216, 5, 11, 6, 217, 5, 1, +0, 80, 3, 131, 3, 132, 3, 217, 5, 11, 6, 12, 6, 1, 0, 80, 3, 132, 3, 81, +3, 217, 5, 12, 6, 218, 5, 1, 0, 81, 3, 132, 3, 133, 3, 218, 5, 12, 6, 13, +6, 1, 0, 81, 3, 133, 3, 82, 3, 218, 5, 13, 6, 219, 5, 1, 0, 82, 3, 133, +3, 134, 3, 219, 5, 13, 6, 14, 6, 1, 0, 82, 3, 134, 3, 83, 3, 219, 5, 14, +6, 220, 5, 1, 0, 83, 3, 134, 3, 135, 3, 220, 5, 14, 6, 15, 6, 1, 0, 83, +3, 135, 3, 84, 3, 220, 5, 15, 6, 221, 5, 1, 0, 84, 3, 135, 3, 136, 3, 221, +5, 15, 6, 16, 6, 1, 0, 84, 3, 136, 3, 85, 3, 221, 5, 16, 6, 222, 5, 1, +0, 85, 3, 136, 3, 137, 3, 222, 5, 16, 6, 17, 6, 1, 0, 85, 3, 137, 3, 86, +3, 222, 5, 17, 6, 223, 5, 1, 0, 86, 3, 137, 3, 138, 3, 223, 5, 17, 6, 18, +6, 1, 0, 86, 3, 138, 3, 87, 3, 223, 5, 18, 6, 224, 5, 1, 0, 87, 3, 138, +3, 139, 3, 224, 5, 18, 6, 19, 6, 1, 0, 87, 3, 139, 3, 88, 3, 224, 5, 19, +6, 225, 5, 1, 0, 88, 3, 139, 3, 140, 3, 225, 5, 19, 6, 20, 6, 1, 0, 88, +3, 140, 3, 89, 3, 225, 5, 20, 6, 226, 5, 1, 0, 89, 3, 140, 3, 141, 3, 226, +5, 20, 6, 21, 6, 1, 0, 89, 3, 141, 3, 90, 3, 226, 5, 21, 6, 227, 5, 1, +0, 90, 3, 141, 3, 142, 3, 227, 5, 21, 6, 22, 6, 1, 0, 90, 3, 142, 3, 91, +3, 227, 5, 22, 6, 228, 5, 1, 0, 91, 3, 142, 3, 143, 3, 228, 5, 22, 6, 23, +6, 1, 0, 91, 3, 143, 3, 92, 3, 228, 5, 23, 6, 229, 5, 1, 0, 92, 3, 143, +3, 144, 3, 229, 5, 23, 6, 24, 6, 1, 0, 92, 3, 144, 3, 93, 3, 229, 5, 24, +6, 230, 5, 1, 0, 93, 3, 144, 3, 145, 3, 230, 5, 24, 6, 25, 6, 1, 0, 93, +3, 145, 3, 94, 3, 230, 5, 25, 6, 231, 5, 1, 0, 94, 3, 145, 3, 146, 3, 231, +5, 25, 6, 26, 6, 1, 0, 94, 3, 146, 3, 95, 3, 231, 5, 26, 6, 232, 5, 1, +0, 95, 3, 146, 3, 147, 3, 232, 5, 26, 6, 27, 6, 1, 0, 95, 3, 147, 3, 96, +3, 232, 5, 27, 6, 233, 5, 1, 0, 96, 3, 147, 3, 148, 3, 233, 5, 27, 6, 234, +5, 1, 0, 96, 3, 148, 3, 97, 3, 233, 5, 234, 5, 184, 5, 1, 0, 98, 3, 149, +3, 150, 3, 234, 5, 28, 6, 29, 6, 1, 0, 98, 3, 150, 3, 99, 3, 234, 5, 29, +6, 235, 5, 1, 0, 99, 3, 150, 3, 151, 3, 235, 5, 29, 6, 30, 6, 1, 0, 99, +3, 151, 3, 100, 3, 235, 5, 30, 6, 236, 5, 1, 0, 100, 3, 151, 3, 152, 3, 236, +5, 30, 6, 31, 6, 1, 0, 100, 3, 152, 3, 101, 3, 236, 5, 31, 6, 237, 5, 1, +0, 101, 3, 152, 3, 153, 3, 237, 5, 31, 6, 32, 6, 1, 0, 101, 3, 153, 3, 102, +3, 237, 5, 32, 6, 238, 5, 1, 0, 102, 3, 153, 3, 154, 3, 238, 5, 32, 6, 33, +6, 1, 0, 102, 3, 154, 3, 103, 3, 238, 5, 33, 6, 239, 5, 1, 0, 103, 3, 154, +3, 155, 3, 239, 5, 33, 6, 34, 6, 1, 0, 103, 3, 155, 3, 104, 3, 239, 5, 34, +6, 240, 5, 1, 0, 104, 3, 155, 3, 156, 3, 240, 5, 34, 6, 35, 6, 1, 0, 104, +3, 156, 3, 105, 3, 240, 5, 35, 6, 241, 5, 1, 0, 105, 3, 156, 3, 157, 3, 241, +5, 35, 6, 36, 6, 1, 0, 105, 3, 157, 3, 106, 3, 241, 5, 36, 6, 242, 5, 1, +0, 106, 3, 157, 3, 158, 3, 242, 5, 36, 6, 37, 6, 1, 0, 106, 3, 158, 3, 107, +3, 242, 5, 37, 6, 243, 5, 1, 0, 107, 3, 158, 3, 159, 3, 243, 5, 37, 6, 38, +6, 1, 0, 107, 3, 159, 3, 108, 3, 243, 5, 38, 6, 244, 5, 1, 0, 108, 3, 159, +3, 160, 3, 244, 5, 38, 6, 39, 6, 1, 0, 108, 3, 160, 3, 109, 3, 244, 5, 39, +6, 245, 5, 1, 0, 109, 3, 160, 3, 161, 3, 245, 5, 39, 6, 40, 6, 1, 0, 109, +3, 161, 3, 110, 3, 245, 5, 40, 6, 246, 5, 1, 0, 110, 3, 161, 3, 162, 3, 246, +5, 40, 6, 41, 6, 1, 0, 110, 3, 162, 3, 111, 3, 246, 5, 41, 6, 247, 5, 1, +0, 111, 3, 162, 3, 163, 3, 247, 5, 41, 6, 42, 6, 1, 0, 111, 3, 163, 3, 112, +3, 247, 5, 42, 6, 248, 5, 1, 0, 112, 3, 163, 3, 164, 3, 248, 5, 42, 6, 43, +6, 1, 0, 112, 3, 164, 3, 113, 3, 248, 5, 43, 6, 249, 5, 1, 0, 113, 3, 164, +3, 165, 3, 249, 5, 43, 6, 44, 6, 1, 0, 113, 3, 165, 3, 114, 3, 249, 5, 44, +6, 250, 5, 1, 0, 114, 3, 165, 3, 166, 3, 250, 5, 44, 6, 45, 6, 1, 0, 114, +3, 166, 3, 115, 3, 250, 5, 45, 6, 251, 5, 1, 0, 115, 3, 166, 3, 167, 3, 251, +5, 45, 6, 46, 6, 1, 0, 115, 3, 167, 3, 116, 3, 251, 5, 46, 6, 252, 5, 1, +0, 116, 3, 167, 3, 168, 3, 252, 5, 46, 6, 47, 6, 1, 0, 116, 3, 168, 3, 117, +3, 252, 5, 47, 6, 253, 5, 1, 0, 117, 3, 168, 3, 169, 3, 253, 5, 47, 6, 48, +6, 1, 0, 117, 3, 169, 3, 118, 3, 253, 5, 48, 6, 254, 5, 1, 0, 118, 3, 169, +3, 170, 3, 254, 5, 48, 6, 49, 6, 1, 0, 118, 3, 170, 3, 119, 3, 254, 5, 49, +6, 255, 5, 1, 0, 119, 3, 170, 3, 171, 3, 255, 5, 49, 6, 50, 6, 1, 0, 119, +3, 171, 3, 120, 3, 255, 5, 50, 6, 0, 6, 1, 0, 120, 3, 171, 3, 172, 3, 0, +6, 50, 6, 51, 6, 1, 0, 120, 3, 172, 3, 121, 3, 0, 6, 51, 6, 1, 6, 1, +0, 121, 3, 172, 3, 173, 3, 1, 6, 51, 6, 52, 6, 1, 0, 121, 3, 173, 3, 122, +3, 1, 6, 52, 6, 2, 6, 1, 0, 122, 3, 173, 3, 174, 3, 2, 6, 52, 6, 53, +6, 1, 0, 122, 3, 174, 3, 123, 3, 2, 6, 53, 6, 3, 6, 1, 0, 123, 3, 174, +3, 175, 3, 3, 6, 53, 6, 54, 6, 1, 0, 123, 3, 175, 3, 124, 3, 3, 6, 54, +6, 4, 6, 1, 0, 124, 3, 175, 3, 176, 3, 4, 6, 54, 6, 55, 6, 1, 0, 124, +3, 176, 3, 125, 3, 4, 6, 55, 6, 5, 6, 1, 0, 125, 3, 176, 3, 177, 3, 5, +6, 55, 6, 56, 6, 1, 0, 125, 3, 177, 3, 126, 3, 5, 6, 56, 6, 6, 6, 1, +0, 126, 3, 177, 3, 178, 3, 6, 6, 56, 6, 57, 6, 1, 0, 126, 3, 178, 3, 127, +3, 6, 6, 57, 6, 7, 6, 1, 0, 127, 3, 178, 3, 179, 3, 7, 6, 57, 6, 58, +6, 1, 0, 127, 3, 179, 3, 128, 3, 7, 6, 58, 6, 8, 6, 1, 0, 128, 3, 179, +3, 180, 3, 8, 6, 58, 6, 59, 6, 1, 0, 128, 3, 180, 3, 129, 3, 8, 6, 59, +6, 9, 6, 1, 0, 129, 3, 180, 3, 181, 3, 9, 6, 59, 6, 60, 6, 1, 0, 129, +3, 181, 3, 130, 3, 9, 6, 60, 6, 10, 6, 1, 0, 130, 3, 181, 3, 182, 3, 10, +6, 60, 6, 61, 6, 1, 0, 130, 3, 182, 3, 131, 3, 10, 6, 61, 6, 11, 6, 1, +0, 131, 3, 182, 3, 183, 3, 11, 6, 61, 6, 62, 6, 1, 0, 131, 3, 183, 3, 132, +3, 11, 6, 62, 6, 12, 6, 1, 0, 132, 3, 183, 3, 184, 3, 12, 6, 62, 6, 63, +6, 1, 0, 132, 3, 184, 3, 133, 3, 12, 6, 63, 6, 13, 6, 1, 0, 133, 3, 184, +3, 185, 3, 13, 6, 63, 6, 64, 6, 1, 0, 133, 3, 185, 3, 134, 3, 13, 6, 64, +6, 14, 6, 1, 0, 134, 3, 185, 3, 186, 3, 14, 6, 64, 6, 65, 6, 1, 0, 134, +3, 186, 3, 135, 3, 14, 6, 65, 6, 15, 6, 1, 0, 135, 3, 186, 3, 187, 3, 15, +6, 65, 6, 66, 6, 1, 0, 135, 3, 187, 3, 136, 3, 15, 6, 66, 6, 16, 6, 1, +0, 136, 3, 187, 3, 188, 3, 16, 6, 66, 6, 67, 6, 1, 0, 136, 3, 188, 3, 137, +3, 16, 6, 67, 6, 17, 6, 1, 0, 137, 3, 188, 3, 189, 3, 17, 6, 67, 6, 68, +6, 1, 0, 137, 3, 189, 3, 138, 3, 17, 6, 68, 6, 18, 6, 1, 0, 138, 3, 189, +3, 190, 3, 18, 6, 68, 6, 69, 6, 1, 0, 138, 3, 190, 3, 139, 3, 18, 6, 69, +6, 19, 6, 1, 0, 139, 3, 190, 3, 191, 3, 19, 6, 69, 6, 70, 6, 1, 0, 139, +3, 191, 3, 140, 3, 19, 6, 70, 6, 20, 6, 1, 0, 140, 3, 191, 3, 192, 3, 20, +6, 70, 6, 71, 6, 1, 0, 140, 3, 192, 3, 141, 3, 20, 6, 71, 6, 21, 6, 1, +0, 141, 3, 192, 3, 193, 3, 21, 6, 71, 6, 72, 6, 1, 0, 141, 3, 193, 3, 142, +3, 21, 6, 72, 6, 22, 6, 1, 0, 142, 3, 193, 3, 194, 3, 22, 6, 72, 6, 73, +6, 1, 0, 142, 3, 194, 3, 143, 3, 22, 6, 73, 6, 23, 6, 1, 0, 143, 3, 194, +3, 195, 3, 23, 6, 73, 6, 74, 6, 1, 0, 143, 3, 195, 3, 144, 3, 23, 6, 74, +6, 24, 6, 1, 0, 144, 3, 195, 3, 196, 3, 24, 6, 74, 6, 75, 6, 1, 0, 144, +3, 196, 3, 145, 3, 24, 6, 75, 6, 25, 6, 1, 0, 145, 3, 196, 3, 197, 3, 25, +6, 75, 6, 76, 6, 1, 0, 145, 3, 197, 3, 146, 3, 25, 6, 76, 6, 26, 6, 1, +0, 146, 3, 197, 3, 198, 3, 26, 6, 76, 6, 77, 6, 1, 0, 146, 3, 198, 3, 147, +3, 26, 6, 77, 6, 27, 6, 1, 0, 147, 3, 198, 3, 199, 3, 27, 6, 77, 6, 28, +6, 1, 0, 147, 3, 199, 3, 148, 3, 27, 6, 28, 6, 234, 5, 1, 0, 149, 3, 200, +3, 201, 3, 28, 6, 78, 6, 79, 6, 1, 0, 149, 3, 201, 3, 150, 3, 28, 6, 79, +6, 29, 6, 1, 0, 150, 3, 201, 3, 202, 3, 29, 6, 79, 6, 80, 6, 1, 0, 150, +3, 202, 3, 151, 3, 29, 6, 80, 6, 30, 6, 1, 0, 151, 3, 202, 3, 203, 3, 30, +6, 80, 6, 81, 6, 1, 0, 151, 3, 203, 3, 152, 3, 30, 6, 81, 6, 31, 6, 1, +0, 152, 3, 203, 3, 204, 3, 31, 6, 81, 6, 82, 6, 1, 0, 152, 3, 204, 3, 153, +3, 31, 6, 82, 6, 32, 6, 1, 0, 153, 3, 204, 3, 205, 3, 32, 6, 82, 6, 83, +6, 1, 0, 153, 3, 205, 3, 154, 3, 32, 6, 83, 6, 33, 6, 1, 0, 154, 3, 205, +3, 206, 3, 33, 6, 83, 6, 84, 6, 1, 0, 154, 3, 206, 3, 155, 3, 33, 6, 84, +6, 34, 6, 1, 0, 155, 3, 206, 3, 207, 3, 34, 6, 84, 6, 85, 6, 1, 0, 155, +3, 207, 3, 156, 3, 34, 6, 85, 6, 35, 6, 1, 0, 156, 3, 207, 3, 208, 3, 35, +6, 85, 6, 86, 6, 1, 0, 156, 3, 208, 3, 157, 3, 35, 6, 86, 6, 36, 6, 1, +0, 157, 3, 208, 3, 209, 3, 36, 6, 86, 6, 87, 6, 1, 0, 157, 3, 209, 3, 158, +3, 36, 6, 87, 6, 37, 6, 1, 0, 158, 3, 209, 3, 210, 3, 37, 6, 87, 6, 88, +6, 1, 0, 158, 3, 210, 3, 159, 3, 37, 6, 88, 6, 38, 6, 1, 0, 159, 3, 210, +3, 211, 3, 38, 6, 88, 6, 89, 6, 1, 0, 159, 3, 211, 3, 160, 3, 38, 6, 89, +6, 39, 6, 1, 0, 160, 3, 211, 3, 212, 3, 39, 6, 89, 6, 90, 6, 1, 0, 160, +3, 212, 3, 161, 3, 39, 6, 90, 6, 40, 6, 1, 0, 161, 3, 212, 3, 213, 3, 40, +6, 90, 6, 91, 6, 1, 0, 161, 3, 213, 3, 162, 3, 40, 6, 91, 6, 41, 6, 1, +0, 162, 3, 213, 3, 214, 3, 41, 6, 91, 6, 92, 6, 1, 0, 162, 3, 214, 3, 163, +3, 41, 6, 92, 6, 42, 6, 1, 0, 163, 3, 214, 3, 215, 3, 42, 6, 92, 6, 93, +6, 1, 0, 163, 3, 215, 3, 164, 3, 42, 6, 93, 6, 43, 6, 1, 0, 164, 3, 215, +3, 216, 3, 43, 6, 93, 6, 94, 6, 1, 0, 164, 3, 216, 3, 165, 3, 43, 6, 94, +6, 44, 6, 1, 0, 165, 3, 216, 3, 217, 3, 44, 6, 94, 6, 95, 6, 1, 0, 165, +3, 217, 3, 166, 3, 44, 6, 95, 6, 45, 6, 1, 0, 166, 3, 217, 3, 218, 3, 45, +6, 95, 6, 96, 6, 1, 0, 166, 3, 218, 3, 167, 3, 45, 6, 96, 6, 46, 6, 1, +0, 167, 3, 218, 3, 219, 3, 46, 6, 96, 6, 97, 6, 1, 0, 167, 3, 219, 3, 168, +3, 46, 6, 97, 6, 47, 6, 1, 0, 168, 3, 219, 3, 220, 3, 47, 6, 97, 6, 98, +6, 1, 0, 168, 3, 220, 3, 169, 3, 47, 6, 98, 6, 48, 6, 1, 0, 169, 3, 220, +3, 221, 3, 48, 6, 98, 6, 99, 6, 1, 0, 169, 3, 221, 3, 170, 3, 48, 6, 99, +6, 49, 6, 1, 0, 170, 3, 221, 3, 222, 3, 49, 6, 99, 6, 100, 6, 1, 0, 170, +3, 222, 3, 171, 3, 49, 6, 100, 6, 50, 6, 1, 0, 171, 3, 222, 3, 223, 3, 50, +6, 100, 6, 101, 6, 1, 0, 171, 3, 223, 3, 172, 3, 50, 6, 101, 6, 51, 6, 1, +0, 172, 3, 223, 3, 224, 3, 51, 6, 101, 6, 102, 6, 1, 0, 172, 3, 224, 3, 173, +3, 51, 6, 102, 6, 52, 6, 1, 0, 173, 3, 224, 3, 225, 3, 52, 6, 102, 6, 103, +6, 1, 0, 173, 3, 225, 3, 174, 3, 52, 6, 103, 6, 53, 6, 1, 0, 174, 3, 225, +3, 226, 3, 53, 6, 103, 6, 104, 6, 1, 0, 174, 3, 226, 3, 175, 3, 53, 6, 104, +6, 54, 6, 1, 0, 175, 3, 226, 3, 227, 3, 54, 6, 104, 6, 105, 6, 1, 0, 175, +3, 227, 3, 176, 3, 54, 6, 105, 6, 55, 6, 1, 0, 176, 3, 227, 3, 228, 3, 55, +6, 105, 6, 106, 6, 1, 0, 176, 3, 228, 3, 177, 3, 55, 6, 106, 6, 56, 6, 1, +0, 177, 3, 228, 3, 229, 3, 56, 6, 106, 6, 107, 6, 1, 0, 177, 3, 229, 3, 178, +3, 56, 6, 107, 6, 57, 6, 1, 0, 178, 3, 229, 3, 230, 3, 57, 6, 107, 6, 108, +6, 1, 0, 178, 3, 230, 3, 179, 3, 57, 6, 108, 6, 58, 6, 1, 0, 179, 3, 230, +3, 231, 3, 58, 6, 108, 6, 109, 6, 1, 0, 179, 3, 231, 3, 180, 3, 58, 6, 109, +6, 59, 6, 1, 0, 180, 3, 231, 3, 232, 3, 59, 6, 109, 6, 110, 6, 1, 0, 180, +3, 232, 3, 181, 3, 59, 6, 110, 6, 60, 6, 1, 0, 181, 3, 232, 3, 233, 3, 60, +6, 110, 6, 111, 6, 1, 0, 181, 3, 233, 3, 182, 3, 60, 6, 111, 6, 61, 6, 1, +0, 182, 3, 233, 3, 234, 3, 61, 6, 111, 6, 112, 6, 1, 0, 182, 3, 234, 3, 183, +3, 61, 6, 112, 6, 62, 6, 1, 0, 183, 3, 234, 3, 235, 3, 62, 6, 112, 6, 113, +6, 1, 0, 183, 3, 235, 3, 184, 3, 62, 6, 113, 6, 63, 6, 1, 0, 184, 3, 235, +3, 236, 3, 63, 6, 113, 6, 114, 6, 1, 0, 184, 3, 236, 3, 185, 3, 63, 6, 114, +6, 64, 6, 1, 0, 185, 3, 236, 3, 237, 3, 64, 6, 114, 6, 115, 6, 1, 0, 185, +3, 237, 3, 186, 3, 64, 6, 115, 6, 65, 6, 1, 0, 186, 3, 237, 3, 238, 3, 65, +6, 115, 6, 116, 6, 1, 0, 186, 3, 238, 3, 187, 3, 65, 6, 116, 6, 66, 6, 1, +0, 187, 3, 238, 3, 239, 3, 66, 6, 116, 6, 117, 6, 1, 0, 187, 3, 239, 3, 188, +3, 66, 6, 117, 6, 67, 6, 1, 0, 188, 3, 239, 3, 240, 3, 67, 6, 117, 6, 118, +6, 1, 0, 188, 3, 240, 3, 189, 3, 67, 6, 118, 6, 68, 6, 1, 0, 189, 3, 240, +3, 241, 3, 68, 6, 118, 6, 119, 6, 1, 0, 189, 3, 241, 3, 190, 3, 68, 6, 119, +6, 69, 6, 1, 0, 190, 3, 241, 3, 242, 3, 69, 6, 119, 6, 120, 6, 1, 0, 190, +3, 242, 3, 191, 3, 69, 6, 120, 6, 70, 6, 1, 0, 191, 3, 242, 3, 243, 3, 70, +6, 120, 6, 121, 6, 1, 0, 191, 3, 243, 3, 192, 3, 70, 6, 121, 6, 71, 6, 1, +0, 192, 3, 243, 3, 244, 3, 71, 6, 121, 6, 122, 6, 1, 0, 192, 3, 244, 3, 193, +3, 71, 6, 122, 6, 72, 6, 1, 0, 193, 3, 244, 3, 245, 3, 72, 6, 122, 6, 123, +6, 1, 0, 193, 3, 245, 3, 194, 3, 72, 6, 123, 6, 73, 6, 1, 0, 194, 3, 245, +3, 246, 3, 73, 6, 123, 6, 124, 6, 1, 0, 194, 3, 246, 3, 195, 3, 73, 6, 124, +6, 74, 6, 1, 0, 195, 3, 246, 3, 247, 3, 74, 6, 124, 6, 125, 6, 1, 0, 195, +3, 247, 3, 196, 3, 74, 6, 125, 6, 75, 6, 1, 0, 196, 3, 247, 3, 248, 3, 75, +6, 125, 6, 126, 6, 1, 0, 196, 3, 248, 3, 197, 3, 75, 6, 126, 6, 76, 6, 1, +0, 197, 3, 248, 3, 249, 3, 76, 6, 126, 6, 127, 6, 1, 0, 197, 3, 249, 3, 198, +3, 76, 6, 127, 6, 77, 6, 1, 0, 198, 3, 249, 3, 250, 3, 77, 6, 127, 6, 78, +6, 1, 0, 198, 3, 250, 3, 199, 3, 77, 6, 78, 6, 28, 6, 1, 0, 200, 3, 251, +3, 252, 3, 78, 6, 128, 6, 129, 6, 1, 0, 200, 3, 252, 3, 201, 3, 78, 6, 129, +6, 79, 6, 1, 0, 201, 3, 252, 3, 253, 3, 79, 6, 129, 6, 130, 6, 1, 0, 201, +3, 253, 3, 202, 3, 79, 6, 130, 6, 80, 6, 1, 0, 202, 3, 253, 3, 254, 3, 80, +6, 130, 6, 131, 6, 1, 0, 202, 3, 254, 3, 203, 3, 80, 6, 131, 6, 81, 6, 1, +0, 203, 3, 254, 3, 255, 3, 81, 6, 131, 6, 132, 6, 1, 0, 203, 3, 255, 3, 204, +3, 81, 6, 132, 6, 82, 6, 1, 0, 204, 3, 255, 3, 0, 4, 82, 6, 132, 6, 133, +6, 1, 0, 204, 3, 0, 4, 205, 3, 82, 6, 133, 6, 83, 6, 1, 0, 205, 3, 0, +4, 1, 4, 83, 6, 133, 6, 134, 6, 1, 0, 205, 3, 1, 4, 206, 3, 83, 6, 134, +6, 84, 6, 1, 0, 206, 3, 1, 4, 2, 4, 84, 6, 134, 6, 135, 6, 1, 0, 206, +3, 2, 4, 207, 3, 84, 6, 135, 6, 85, 6, 1, 0, 207, 3, 2, 4, 3, 4, 85, +6, 135, 6, 136, 6, 1, 0, 207, 3, 3, 4, 208, 3, 85, 6, 136, 6, 86, 6, 1, +0, 208, 3, 3, 4, 4, 4, 86, 6, 136, 6, 137, 6, 1, 0, 208, 3, 4, 4, 209, +3, 86, 6, 137, 6, 87, 6, 1, 0, 209, 3, 4, 4, 5, 4, 87, 6, 137, 6, 138, +6, 1, 0, 209, 3, 5, 4, 210, 3, 87, 6, 138, 6, 88, 6, 1, 0, 210, 3, 5, +4, 6, 4, 88, 6, 138, 6, 139, 6, 1, 0, 210, 3, 6, 4, 211, 3, 88, 6, 139, +6, 89, 6, 1, 0, 211, 3, 6, 4, 7, 4, 89, 6, 139, 6, 140, 6, 1, 0, 211, +3, 7, 4, 212, 3, 89, 6, 140, 6, 90, 6, 1, 0, 212, 3, 7, 4, 8, 4, 90, +6, 140, 6, 141, 6, 1, 0, 212, 3, 8, 4, 213, 3, 90, 6, 141, 6, 91, 6, 1, +0, 213, 3, 8, 4, 9, 4, 91, 6, 141, 6, 142, 6, 1, 0, 213, 3, 9, 4, 214, +3, 91, 6, 142, 6, 92, 6, 1, 0, 214, 3, 9, 4, 10, 4, 92, 6, 142, 6, 143, +6, 1, 0, 214, 3, 10, 4, 215, 3, 92, 6, 143, 6, 93, 6, 1, 0, 215, 3, 10, +4, 11, 4, 93, 6, 143, 6, 144, 6, 1, 0, 215, 3, 11, 4, 216, 3, 93, 6, 144, +6, 94, 6, 1, 0, 216, 3, 11, 4, 12, 4, 94, 6, 144, 6, 145, 6, 1, 0, 216, +3, 12, 4, 217, 3, 94, 6, 145, 6, 95, 6, 1, 0, 217, 3, 12, 4, 13, 4, 95, +6, 145, 6, 146, 6, 1, 0, 217, 3, 13, 4, 218, 3, 95, 6, 146, 6, 96, 6, 1, +0, 218, 3, 13, 4, 14, 4, 96, 6, 146, 6, 147, 6, 1, 0, 218, 3, 14, 4, 219, +3, 96, 6, 147, 6, 97, 6, 1, 0, 219, 3, 14, 4, 15, 4, 97, 6, 147, 6, 148, +6, 1, 0, 219, 3, 15, 4, 220, 3, 97, 6, 148, 6, 98, 6, 1, 0, 220, 3, 15, +4, 16, 4, 98, 6, 148, 6, 149, 6, 1, 0, 220, 3, 16, 4, 221, 3, 98, 6, 149, +6, 99, 6, 1, 0, 221, 3, 16, 4, 17, 4, 99, 6, 149, 6, 150, 6, 1, 0, 221, +3, 17, 4, 222, 3, 99, 6, 150, 6, 100, 6, 1, 0, 222, 3, 17, 4, 18, 4, 100, +6, 150, 6, 151, 6, 1, 0, 222, 3, 18, 4, 223, 3, 100, 6, 151, 6, 101, 6, 1, +0, 223, 3, 18, 4, 19, 4, 101, 6, 151, 6, 152, 6, 1, 0, 223, 3, 19, 4, 224, +3, 101, 6, 152, 6, 102, 6, 1, 0, 224, 3, 19, 4, 20, 4, 102, 6, 152, 6, 153, +6, 1, 0, 224, 3, 20, 4, 225, 3, 102, 6, 153, 6, 103, 6, 1, 0, 225, 3, 20, +4, 21, 4, 103, 6, 153, 6, 154, 6, 1, 0, 225, 3, 21, 4, 226, 3, 103, 6, 154, +6, 104, 6, 1, 0, 226, 3, 21, 4, 22, 4, 104, 6, 154, 6, 155, 6, 1, 0, 226, +3, 22, 4, 227, 3, 104, 6, 155, 6, 105, 6, 1, 0, 227, 3, 22, 4, 23, 4, 105, +6, 155, 6, 156, 6, 1, 0, 227, 3, 23, 4, 228, 3, 105, 6, 156, 6, 106, 6, 1, +0, 228, 3, 23, 4, 24, 4, 106, 6, 156, 6, 157, 6, 1, 0, 228, 3, 24, 4, 229, +3, 106, 6, 157, 6, 107, 6, 1, 0, 229, 3, 24, 4, 25, 4, 107, 6, 157, 6, 158, +6, 1, 0, 229, 3, 25, 4, 230, 3, 107, 6, 158, 6, 108, 6, 1, 0, 230, 3, 25, +4, 26, 4, 108, 6, 158, 6, 159, 6, 1, 0, 230, 3, 26, 4, 231, 3, 108, 6, 159, +6, 109, 6, 1, 0, 231, 3, 26, 4, 27, 4, 109, 6, 159, 6, 160, 6, 1, 0, 231, +3, 27, 4, 232, 3, 109, 6, 160, 6, 110, 6, 1, 0, 232, 3, 27, 4, 28, 4, 110, +6, 160, 6, 161, 6, 1, 0, 232, 3, 28, 4, 233, 3, 110, 6, 161, 6, 111, 6, 1, +0, 233, 3, 28, 4, 29, 4, 111, 6, 161, 6, 162, 6, 1, 0, 233, 3, 29, 4, 234, +3, 111, 6, 162, 6, 112, 6, 1, 0, 234, 3, 29, 4, 30, 4, 112, 6, 162, 6, 163, +6, 1, 0, 234, 3, 30, 4, 235, 3, 112, 6, 163, 6, 113, 6, 1, 0, 235, 3, 30, +4, 31, 4, 113, 6, 163, 6, 164, 6, 1, 0, 235, 3, 31, 4, 236, 3, 113, 6, 164, +6, 114, 6, 1, 0, 236, 3, 31, 4, 32, 4, 114, 6, 164, 6, 165, 6, 1, 0, 236, +3, 32, 4, 237, 3, 114, 6, 165, 6, 115, 6, 1, 0, 237, 3, 32, 4, 33, 4, 115, +6, 165, 6, 166, 6, 1, 0, 237, 3, 33, 4, 238, 3, 115, 6, 166, 6, 116, 6, 1, +0, 238, 3, 33, 4, 34, 4, 116, 6, 166, 6, 167, 6, 1, 0, 238, 3, 34, 4, 239, +3, 116, 6, 167, 6, 117, 6, 1, 0, 239, 3, 34, 4, 35, 4, 117, 6, 167, 6, 168, +6, 1, 0, 239, 3, 35, 4, 240, 3, 117, 6, 168, 6, 118, 6, 1, 0, 240, 3, 35, +4, 36, 4, 118, 6, 168, 6, 169, 6, 1, 0, 240, 3, 36, 4, 241, 3, 118, 6, 169, +6, 119, 6, 1, 0, 241, 3, 36, 4, 37, 4, 119, 6, 169, 6, 170, 6, 1, 0, 241, +3, 37, 4, 242, 3, 119, 6, 170, 6, 120, 6, 1, 0, 242, 3, 37, 4, 38, 4, 120, +6, 170, 6, 171, 6, 1, 0, 242, 3, 38, 4, 243, 3, 120, 6, 171, 6, 121, 6, 1, +0, 243, 3, 38, 4, 39, 4, 121, 6, 171, 6, 172, 6, 1, 0, 243, 3, 39, 4, 244, +3, 121, 6, 172, 6, 122, 6, 1, 0, 244, 3, 39, 4, 40, 4, 122, 6, 172, 6, 173, +6, 1, 0, 244, 3, 40, 4, 245, 3, 122, 6, 173, 6, 123, 6, 1, 0, 245, 3, 40, +4, 41, 4, 123, 6, 173, 6, 174, 6, 1, 0, 245, 3, 41, 4, 246, 3, 123, 6, 174, +6, 124, 6, 1, 0, 246, 3, 41, 4, 42, 4, 124, 6, 174, 6, 175, 6, 1, 0, 246, +3, 42, 4, 247, 3, 124, 6, 175, 6, 125, 6, 1, 0, 247, 3, 42, 4, 43, 4, 125, +6, 175, 6, 176, 6, 1, 0, 247, 3, 43, 4, 248, 3, 125, 6, 176, 6, 126, 6, 1, +0, 248, 3, 43, 4, 44, 4, 126, 6, 176, 6, 177, 6, 1, 0, 248, 3, 44, 4, 249, +3, 126, 6, 177, 6, 127, 6, 1, 0, 249, 3, 44, 4, 45, 4, 127, 6, 177, 6, 128, +6, 1, 0, 249, 3, 45, 4, 250, 3, 127, 6, 128, 6, 78, 6, 1, 0, 251, 3, 46, +4, 47, 4, 128, 6, 178, 6, 179, 6, 1, 0, 251, 3, 47, 4, 252, 3, 128, 6, 179, +6, 129, 6, 1, 0, 252, 3, 47, 4, 48, 4, 129, 6, 179, 6, 180, 6, 1, 0, 252, +3, 48, 4, 253, 3, 129, 6, 180, 6, 130, 6, 1, 0, 253, 3, 48, 4, 49, 4, 130, +6, 180, 6, 181, 6, 1, 0, 253, 3, 49, 4, 254, 3, 130, 6, 181, 6, 131, 6, 1, +0, 254, 3, 49, 4, 50, 4, 131, 6, 181, 6, 182, 6, 1, 0, 254, 3, 50, 4, 255, +3, 131, 6, 182, 6, 132, 6, 1, 0, 255, 3, 50, 4, 51, 4, 132, 6, 182, 6, 183, +6, 1, 0, 255, 3, 51, 4, 0, 4, 132, 6, 183, 6, 133, 6, 1, 0, 0, 4, 51, +4, 52, 4, 133, 6, 183, 6, 184, 6, 1, 0, 0, 4, 52, 4, 1, 4, 133, 6, 184, +6, 134, 6, 1, 0, 1, 4, 52, 4, 53, 4, 134, 6, 184, 6, 185, 6, 1, 0, 1, +4, 53, 4, 2, 4, 134, 6, 185, 6, 135, 6, 1, 0, 2, 4, 53, 4, 54, 4, 135, +6, 185, 6, 186, 6, 1, 0, 2, 4, 54, 4, 3, 4, 135, 6, 186, 6, 136, 6, 1, +0, 3, 4, 54, 4, 55, 4, 136, 6, 186, 6, 187, 6, 1, 0, 3, 4, 55, 4, 4, +4, 136, 6, 187, 6, 137, 6, 1, 0, 4, 4, 55, 4, 56, 4, 137, 6, 187, 6, 188, +6, 1, 0, 4, 4, 56, 4, 5, 4, 137, 6, 188, 6, 138, 6, 1, 0, 5, 4, 56, +4, 57, 4, 138, 6, 188, 6, 189, 6, 1, 0, 5, 4, 57, 4, 6, 4, 138, 6, 189, +6, 139, 6, 1, 0, 6, 4, 57, 4, 58, 4, 139, 6, 189, 6, 190, 6, 1, 0, 6, +4, 58, 4, 7, 4, 139, 6, 190, 6, 140, 6, 1, 0, 7, 4, 58, 4, 59, 4, 140, +6, 190, 6, 191, 6, 1, 0, 7, 4, 59, 4, 8, 4, 140, 6, 191, 6, 141, 6, 1, +0, 8, 4, 59, 4, 60, 4, 141, 6, 191, 6, 192, 6, 1, 0, 8, 4, 60, 4, 9, +4, 141, 6, 192, 6, 142, 6, 1, 0, 9, 4, 60, 4, 61, 4, 142, 6, 192, 6, 193, +6, 1, 0, 9, 4, 61, 4, 10, 4, 142, 6, 193, 6, 143, 6, 1, 0, 10, 4, 61, +4, 62, 4, 143, 6, 193, 6, 194, 6, 1, 0, 10, 4, 62, 4, 11, 4, 143, 6, 194, +6, 144, 6, 1, 0, 11, 4, 62, 4, 63, 4, 144, 6, 194, 6, 195, 6, 1, 0, 11, +4, 63, 4, 12, 4, 144, 6, 195, 6, 145, 6, 1, 0, 12, 4, 63, 4, 64, 4, 145, +6, 195, 6, 196, 6, 1, 0, 12, 4, 64, 4, 13, 4, 145, 6, 196, 6, 146, 6, 1, +0, 13, 4, 64, 4, 65, 4, 146, 6, 196, 6, 197, 6, 1, 0, 13, 4, 65, 4, 14, +4, 146, 6, 197, 6, 147, 6, 1, 0, 14, 4, 65, 4, 66, 4, 147, 6, 197, 6, 198, +6, 1, 0, 14, 4, 66, 4, 15, 4, 147, 6, 198, 6, 148, 6, 1, 0, 15, 4, 66, +4, 67, 4, 148, 6, 198, 6, 199, 6, 1, 0, 15, 4, 67, 4, 16, 4, 148, 6, 199, +6, 149, 6, 1, 0, 16, 4, 67, 4, 68, 4, 149, 6, 199, 6, 200, 6, 1, 0, 16, +4, 68, 4, 17, 4, 149, 6, 200, 6, 150, 6, 1, 0, 17, 4, 68, 4, 69, 4, 150, +6, 200, 6, 201, 6, 1, 0, 17, 4, 69, 4, 18, 4, 150, 6, 201, 6, 151, 6, 1, +0, 18, 4, 69, 4, 70, 4, 151, 6, 201, 6, 202, 6, 1, 0, 18, 4, 70, 4, 19, +4, 151, 6, 202, 6, 152, 6, 1, 0, 19, 4, 70, 4, 71, 4, 152, 6, 202, 6, 203, +6, 1, 0, 19, 4, 71, 4, 20, 4, 152, 6, 203, 6, 153, 6, 1, 0, 20, 4, 71, +4, 72, 4, 153, 6, 203, 6, 204, 6, 1, 0, 20, 4, 72, 4, 21, 4, 153, 6, 204, +6, 154, 6, 1, 0, 21, 4, 72, 4, 73, 4, 154, 6, 204, 6, 205, 6, 1, 0, 21, +4, 73, 4, 22, 4, 154, 6, 205, 6, 155, 6, 1, 0, 22, 4, 73, 4, 74, 4, 155, +6, 205, 6, 206, 6, 1, 0, 22, 4, 74, 4, 23, 4, 155, 6, 206, 6, 156, 6, 1, +0, 23, 4, 74, 4, 75, 4, 156, 6, 206, 6, 207, 6, 1, 0, 23, 4, 75, 4, 24, +4, 156, 6, 207, 6, 157, 6, 1, 0, 24, 4, 75, 4, 76, 4, 157, 6, 207, 6, 208, +6, 1, 0, 24, 4, 76, 4, 25, 4, 157, 6, 208, 6, 158, 6, 1, 0, 25, 4, 76, +4, 77, 4, 158, 6, 208, 6, 209, 6, 1, 0, 25, 4, 77, 4, 26, 4, 158, 6, 209, +6, 159, 6, 1, 0, 26, 4, 77, 4, 78, 4, 159, 6, 209, 6, 210, 6, 1, 0, 26, +4, 78, 4, 27, 4, 159, 6, 210, 6, 160, 6, 1, 0, 27, 4, 78, 4, 79, 4, 160, +6, 210, 6, 211, 6, 1, 0, 27, 4, 79, 4, 28, 4, 160, 6, 211, 6, 161, 6, 1, +0, 28, 4, 79, 4, 80, 4, 161, 6, 211, 6, 212, 6, 1, 0, 28, 4, 80, 4, 29, +4, 161, 6, 212, 6, 162, 6, 1, 0, 29, 4, 80, 4, 81, 4, 162, 6, 212, 6, 213, +6, 1, 0, 29, 4, 81, 4, 30, 4, 162, 6, 213, 6, 163, 6, 1, 0, 30, 4, 81, +4, 82, 4, 163, 6, 213, 6, 214, 6, 1, 0, 30, 4, 82, 4, 31, 4, 163, 6, 214, +6, 164, 6, 1, 0, 31, 4, 82, 4, 83, 4, 164, 6, 214, 6, 215, 6, 1, 0, 31, +4, 83, 4, 32, 4, 164, 6, 215, 6, 165, 6, 1, 0, 32, 4, 83, 4, 84, 4, 165, +6, 215, 6, 216, 6, 1, 0, 32, 4, 84, 4, 33, 4, 165, 6, 216, 6, 166, 6, 1, +0, 33, 4, 84, 4, 85, 4, 166, 6, 216, 6, 217, 6, 1, 0, 33, 4, 85, 4, 34, +4, 166, 6, 217, 6, 167, 6, 1, 0, 34, 4, 85, 4, 86, 4, 167, 6, 217, 6, 218, +6, 1, 0, 34, 4, 86, 4, 35, 4, 167, 6, 218, 6, 168, 6, 1, 0, 35, 4, 86, +4, 87, 4, 168, 6, 218, 6, 219, 6, 1, 0, 35, 4, 87, 4, 36, 4, 168, 6, 219, +6, 169, 6, 1, 0, 36, 4, 87, 4, 88, 4, 169, 6, 219, 6, 220, 6, 1, 0, 36, +4, 88, 4, 37, 4, 169, 6, 220, 6, 170, 6, 1, 0, 37, 4, 88, 4, 89, 4, 170, +6, 220, 6, 221, 6, 1, 0, 37, 4, 89, 4, 38, 4, 170, 6, 221, 6, 171, 6, 1, +0, 38, 4, 89, 4, 90, 4, 171, 6, 221, 6, 222, 6, 1, 0, 38, 4, 90, 4, 39, +4, 171, 6, 222, 6, 172, 6, 1, 0, 39, 4, 90, 4, 91, 4, 172, 6, 222, 6, 223, +6, 1, 0, 39, 4, 91, 4, 40, 4, 172, 6, 223, 6, 173, 6, 1, 0, 40, 4, 91, +4, 92, 4, 173, 6, 223, 6, 224, 6, 1, 0, 40, 4, 92, 4, 41, 4, 173, 6, 224, +6, 174, 6, 1, 0, 41, 4, 92, 4, 93, 4, 174, 6, 224, 6, 225, 6, 1, 0, 41, +4, 93, 4, 42, 4, 174, 6, 225, 6, 175, 6, 1, 0, 42, 4, 93, 4, 94, 4, 175, +6, 225, 6, 226, 6, 1, 0, 42, 4, 94, 4, 43, 4, 175, 6, 226, 6, 176, 6, 1, +0, 43, 4, 94, 4, 95, 4, 176, 6, 226, 6, 227, 6, 1, 0, 43, 4, 95, 4, 44, +4, 176, 6, 227, 6, 177, 6, 1, 0, 44, 4, 95, 4, 96, 4, 177, 6, 227, 6, 178, +6, 1, 0, 44, 4, 96, 4, 45, 4, 177, 6, 178, 6, 128, 6, 1, 0, 46, 4, 97, +4, 98, 4, 178, 6, 228, 6, 229, 6, 1, 0, 46, 4, 98, 4, 47, 4, 178, 6, 229, +6, 179, 6, 1, 0, 47, 4, 98, 4, 99, 4, 179, 6, 229, 6, 230, 6, 1, 0, 47, +4, 99, 4, 48, 4, 179, 6, 230, 6, 180, 6, 1, 0, 48, 4, 99, 4, 100, 4, 180, +6, 230, 6, 231, 6, 1, 0, 48, 4, 100, 4, 49, 4, 180, 6, 231, 6, 181, 6, 1, +0, 49, 4, 100, 4, 101, 4, 181, 6, 231, 6, 232, 6, 1, 0, 49, 4, 101, 4, 50, +4, 181, 6, 232, 6, 182, 6, 1, 0, 50, 4, 101, 4, 102, 4, 182, 6, 232, 6, 233, +6, 1, 0, 50, 4, 102, 4, 51, 4, 182, 6, 233, 6, 183, 6, 1, 0, 51, 4, 102, +4, 103, 4, 183, 6, 233, 6, 234, 6, 1, 0, 51, 4, 103, 4, 52, 4, 183, 6, 234, +6, 184, 6, 1, 0, 52, 4, 103, 4, 104, 4, 184, 6, 234, 6, 235, 6, 1, 0, 52, +4, 104, 4, 53, 4, 184, 6, 235, 6, 185, 6, 1, 0, 53, 4, 104, 4, 105, 4, 185, +6, 235, 6, 236, 6, 1, 0, 53, 4, 105, 4, 54, 4, 185, 6, 236, 6, 186, 6, 1, +0, 54, 4, 105, 4, 106, 4, 186, 6, 236, 6, 237, 6, 1, 0, 54, 4, 106, 4, 55, +4, 186, 6, 237, 6, 187, 6, 1, 0, 55, 4, 106, 4, 107, 4, 187, 6, 237, 6, 238, +6, 1, 0, 55, 4, 107, 4, 56, 4, 187, 6, 238, 6, 188, 6, 1, 0, 56, 4, 107, +4, 108, 4, 188, 6, 238, 6, 239, 6, 1, 0, 56, 4, 108, 4, 57, 4, 188, 6, 239, +6, 189, 6, 1, 0, 57, 4, 108, 4, 109, 4, 189, 6, 239, 6, 240, 6, 1, 0, 57, +4, 109, 4, 58, 4, 189, 6, 240, 6, 190, 6, 1, 0, 58, 4, 109, 4, 110, 4, 190, +6, 240, 6, 241, 6, 1, 0, 58, 4, 110, 4, 59, 4, 190, 6, 241, 6, 191, 6, 1, +0, 59, 4, 110, 4, 111, 4, 191, 6, 241, 6, 242, 6, 1, 0, 59, 4, 111, 4, 60, +4, 191, 6, 242, 6, 192, 6, 1, 0, 60, 4, 111, 4, 112, 4, 192, 6, 242, 6, 243, +6, 1, 0, 60, 4, 112, 4, 61, 4, 192, 6, 243, 6, 193, 6, 1, 0, 61, 4, 112, +4, 113, 4, 193, 6, 243, 6, 244, 6, 1, 0, 61, 4, 113, 4, 62, 4, 193, 6, 244, +6, 194, 6, 1, 0, 62, 4, 113, 4, 114, 4, 194, 6, 244, 6, 245, 6, 1, 0, 62, +4, 114, 4, 63, 4, 194, 6, 245, 6, 195, 6, 1, 0, 63, 4, 114, 4, 115, 4, 195, +6, 245, 6, 246, 6, 1, 0, 63, 4, 115, 4, 64, 4, 195, 6, 246, 6, 196, 6, 1, +0, 64, 4, 115, 4, 116, 4, 196, 6, 246, 6, 247, 6, 1, 0, 64, 4, 116, 4, 65, +4, 196, 6, 247, 6, 197, 6, 1, 0, 65, 4, 116, 4, 117, 4, 197, 6, 247, 6, 248, +6, 1, 0, 65, 4, 117, 4, 66, 4, 197, 6, 248, 6, 198, 6, 1, 0, 66, 4, 117, +4, 118, 4, 198, 6, 248, 6, 249, 6, 1, 0, 66, 4, 118, 4, 67, 4, 198, 6, 249, +6, 199, 6, 1, 0, 67, 4, 118, 4, 119, 4, 199, 6, 249, 6, 250, 6, 1, 0, 67, +4, 119, 4, 68, 4, 199, 6, 250, 6, 200, 6, 1, 0, 68, 4, 119, 4, 120, 4, 200, +6, 250, 6, 251, 6, 1, 0, 68, 4, 120, 4, 69, 4, 200, 6, 251, 6, 201, 6, 1, +0, 69, 4, 120, 4, 121, 4, 201, 6, 251, 6, 252, 6, 1, 0, 69, 4, 121, 4, 70, +4, 201, 6, 252, 6, 202, 6, 1, 0, 70, 4, 121, 4, 122, 4, 202, 6, 252, 6, 253, +6, 1, 0, 70, 4, 122, 4, 71, 4, 202, 6, 253, 6, 203, 6, 1, 0, 71, 4, 122, +4, 123, 4, 203, 6, 253, 6, 254, 6, 1, 0, 71, 4, 123, 4, 72, 4, 203, 6, 254, +6, 204, 6, 1, 0, 72, 4, 123, 4, 124, 4, 204, 6, 254, 6, 255, 6, 1, 0, 72, +4, 124, 4, 73, 4, 204, 6, 255, 6, 205, 6, 1, 0, 73, 4, 124, 4, 125, 4, 205, +6, 255, 6, 0, 7, 1, 0, 73, 4, 125, 4, 74, 4, 205, 6, 0, 7, 206, 6, 1, +0, 74, 4, 125, 4, 126, 4, 206, 6, 0, 7, 1, 7, 1, 0, 74, 4, 126, 4, 75, +4, 206, 6, 1, 7, 207, 6, 1, 0, 75, 4, 126, 4, 127, 4, 207, 6, 1, 7, 2, +7, 1, 0, 75, 4, 127, 4, 76, 4, 207, 6, 2, 7, 208, 6, 1, 0, 76, 4, 127, +4, 128, 4, 208, 6, 2, 7, 3, 7, 1, 0, 76, 4, 128, 4, 77, 4, 208, 6, 3, +7, 209, 6, 1, 0, 77, 4, 128, 4, 129, 4, 209, 6, 3, 7, 4, 7, 1, 0, 77, +4, 129, 4, 78, 4, 209, 6, 4, 7, 210, 6, 1, 0, 78, 4, 129, 4, 130, 4, 210, +6, 4, 7, 5, 7, 1, 0, 78, 4, 130, 4, 79, 4, 210, 6, 5, 7, 211, 6, 1, +0, 79, 4, 130, 4, 131, 4, 211, 6, 5, 7, 6, 7, 1, 0, 79, 4, 131, 4, 80, +4, 211, 6, 6, 7, 212, 6, 1, 0, 80, 4, 131, 4, 132, 4, 212, 6, 6, 7, 7, +7, 1, 0, 80, 4, 132, 4, 81, 4, 212, 6, 7, 7, 213, 6, 1, 0, 81, 4, 132, +4, 133, 4, 213, 6, 7, 7, 8, 7, 1, 0, 81, 4, 133, 4, 82, 4, 213, 6, 8, +7, 214, 6, 1, 0, 82, 4, 133, 4, 134, 4, 214, 6, 8, 7, 9, 7, 1, 0, 82, +4, 134, 4, 83, 4, 214, 6, 9, 7, 215, 6, 1, 0, 83, 4, 134, 4, 135, 4, 215, +6, 9, 7, 10, 7, 1, 0, 83, 4, 135, 4, 84, 4, 215, 6, 10, 7, 216, 6, 1, +0, 84, 4, 135, 4, 136, 4, 216, 6, 10, 7, 11, 7, 1, 0, 84, 4, 136, 4, 85, +4, 216, 6, 11, 7, 217, 6, 1, 0, 85, 4, 136, 4, 137, 4, 217, 6, 11, 7, 12, +7, 1, 0, 85, 4, 137, 4, 86, 4, 217, 6, 12, 7, 218, 6, 1, 0, 86, 4, 137, +4, 138, 4, 218, 6, 12, 7, 13, 7, 1, 0, 86, 4, 138, 4, 87, 4, 218, 6, 13, +7, 219, 6, 1, 0, 87, 4, 138, 4, 139, 4, 219, 6, 13, 7, 14, 7, 1, 0, 87, +4, 139, 4, 88, 4, 219, 6, 14, 7, 220, 6, 1, 0, 88, 4, 139, 4, 140, 4, 220, +6, 14, 7, 15, 7, 1, 0, 88, 4, 140, 4, 89, 4, 220, 6, 15, 7, 221, 6, 1, +0, 89, 4, 140, 4, 141, 4, 221, 6, 15, 7, 16, 7, 1, 0, 89, 4, 141, 4, 90, +4, 221, 6, 16, 7, 222, 6, 1, 0, 90, 4, 141, 4, 142, 4, 222, 6, 16, 7, 17, +7, 1, 0, 90, 4, 142, 4, 91, 4, 222, 6, 17, 7, 223, 6, 1, 0, 91, 4, 142, +4, 143, 4, 223, 6, 17, 7, 18, 7, 1, 0, 91, 4, 143, 4, 92, 4, 223, 6, 18, +7, 224, 6, 1, 0, 92, 4, 143, 4, 144, 4, 224, 6, 18, 7, 19, 7, 1, 0, 92, +4, 144, 4, 93, 4, 224, 6, 19, 7, 225, 6, 1, 0, 93, 4, 144, 4, 145, 4, 225, +6, 19, 7, 20, 7, 1, 0, 93, 4, 145, 4, 94, 4, 225, 6, 20, 7, 226, 6, 1, +0, 94, 4, 145, 4, 146, 4, 226, 6, 20, 7, 21, 7, 1, 0, 94, 4, 146, 4, 95, +4, 226, 6, 21, 7, 227, 6, 1, 0, 95, 4, 146, 4, 147, 4, 227, 6, 21, 7, 228, +6, 1, 0, 95, 4, 147, 4, 96, 4, 227, 6, 228, 6, 178, 6, 1, 0, 97, 4, 148, +4, 149, 4, 228, 6, 22, 7, 23, 7, 1, 0, 97, 4, 149, 4, 98, 4, 228, 6, 23, +7, 229, 6, 1, 0, 98, 4, 149, 4, 150, 4, 229, 6, 23, 7, 24, 7, 1, 0, 98, +4, 150, 4, 99, 4, 229, 6, 24, 7, 230, 6, 1, 0, 99, 4, 150, 4, 151, 4, 230, +6, 24, 7, 25, 7, 1, 0, 99, 4, 151, 4, 100, 4, 230, 6, 25, 7, 231, 6, 1, +0, 100, 4, 151, 4, 152, 4, 231, 6, 25, 7, 26, 7, 1, 0, 100, 4, 152, 4, 101, +4, 231, 6, 26, 7, 232, 6, 1, 0, 101, 4, 152, 4, 153, 4, 232, 6, 26, 7, 27, +7, 1, 0, 101, 4, 153, 4, 102, 4, 232, 6, 27, 7, 233, 6, 1, 0, 102, 4, 153, +4, 154, 4, 233, 6, 27, 7, 28, 7, 1, 0, 102, 4, 154, 4, 103, 4, 233, 6, 28, +7, 234, 6, 1, 0, 103, 4, 154, 4, 155, 4, 234, 6, 28, 7, 29, 7, 1, 0, 103, +4, 155, 4, 104, 4, 234, 6, 29, 7, 235, 6, 1, 0, 104, 4, 155, 4, 156, 4, 235, +6, 29, 7, 30, 7, 1, 0, 104, 4, 156, 4, 105, 4, 235, 6, 30, 7, 236, 6, 1, +0, 105, 4, 156, 4, 157, 4, 236, 6, 30, 7, 31, 7, 1, 0, 105, 4, 157, 4, 106, +4, 236, 6, 31, 7, 237, 6, 1, 0, 106, 4, 157, 4, 158, 4, 237, 6, 31, 7, 32, +7, 1, 0, 106, 4, 158, 4, 107, 4, 237, 6, 32, 7, 238, 6, 1, 0, 107, 4, 158, +4, 159, 4, 238, 6, 32, 7, 33, 7, 1, 0, 107, 4, 159, 4, 108, 4, 238, 6, 33, +7, 239, 6, 1, 0, 108, 4, 159, 4, 160, 4, 239, 6, 33, 7, 34, 7, 1, 0, 108, +4, 160, 4, 109, 4, 239, 6, 34, 7, 240, 6, 1, 0, 109, 4, 160, 4, 161, 4, 240, +6, 34, 7, 35, 7, 1, 0, 109, 4, 161, 4, 110, 4, 240, 6, 35, 7, 241, 6, 1, +0, 110, 4, 161, 4, 162, 4, 241, 6, 35, 7, 36, 7, 1, 0, 110, 4, 162, 4, 111, +4, 241, 6, 36, 7, 242, 6, 1, 0, 111, 4, 162, 4, 163, 4, 242, 6, 36, 7, 37, +7, 1, 0, 111, 4, 163, 4, 112, 4, 242, 6, 37, 7, 243, 6, 1, 0, 112, 4, 163, +4, 164, 4, 243, 6, 37, 7, 38, 7, 1, 0, 112, 4, 164, 4, 113, 4, 243, 6, 38, +7, 244, 6, 1, 0, 113, 4, 164, 4, 165, 4, 244, 6, 38, 7, 39, 7, 1, 0, 113, +4, 165, 4, 114, 4, 244, 6, 39, 7, 245, 6, 1, 0, 114, 4, 165, 4, 166, 4, 245, +6, 39, 7, 40, 7, 1, 0, 114, 4, 166, 4, 115, 4, 245, 6, 40, 7, 246, 6, 1, +0, 115, 4, 166, 4, 167, 4, 246, 6, 40, 7, 41, 7, 1, 0, 115, 4, 167, 4, 116, +4, 246, 6, 41, 7, 247, 6, 1, 0, 116, 4, 167, 4, 168, 4, 247, 6, 41, 7, 42, +7, 1, 0, 116, 4, 168, 4, 117, 4, 247, 6, 42, 7, 248, 6, 1, 0, 117, 4, 168, +4, 169, 4, 248, 6, 42, 7, 43, 7, 1, 0, 117, 4, 169, 4, 118, 4, 248, 6, 43, +7, 249, 6, 1, 0, 118, 4, 169, 4, 170, 4, 249, 6, 43, 7, 44, 7, 1, 0, 118, +4, 170, 4, 119, 4, 249, 6, 44, 7, 250, 6, 1, 0, 119, 4, 170, 4, 171, 4, 250, +6, 44, 7, 45, 7, 1, 0, 119, 4, 171, 4, 120, 4, 250, 6, 45, 7, 251, 6, 1, +0, 120, 4, 171, 4, 172, 4, 251, 6, 45, 7, 46, 7, 1, 0, 120, 4, 172, 4, 121, +4, 251, 6, 46, 7, 252, 6, 1, 0, 121, 4, 172, 4, 173, 4, 252, 6, 46, 7, 47, +7, 1, 0, 121, 4, 173, 4, 122, 4, 252, 6, 47, 7, 253, 6, 1, 0, 122, 4, 173, +4, 174, 4, 253, 6, 47, 7, 48, 7, 1, 0, 122, 4, 174, 4, 123, 4, 253, 6, 48, +7, 254, 6, 1, 0, 123, 4, 174, 4, 175, 4, 254, 6, 48, 7, 49, 7, 1, 0, 123, +4, 175, 4, 124, 4, 254, 6, 49, 7, 255, 6, 1, 0, 124, 4, 175, 4, 176, 4, 255, +6, 49, 7, 50, 7, 1, 0, 124, 4, 176, 4, 125, 4, 255, 6, 50, 7, 0, 7, 1, +0, 125, 4, 176, 4, 177, 4, 0, 7, 50, 7, 51, 7, 1, 0, 125, 4, 177, 4, 126, +4, 0, 7, 51, 7, 1, 7, 1, 0, 126, 4, 177, 4, 178, 4, 1, 7, 51, 7, 52, +7, 1, 0, 126, 4, 178, 4, 127, 4, 1, 7, 52, 7, 2, 7, 1, 0, 127, 4, 178, +4, 179, 4, 2, 7, 52, 7, 53, 7, 1, 0, 127, 4, 179, 4, 128, 4, 2, 7, 53, +7, 3, 7, 1, 0, 128, 4, 179, 4, 180, 4, 3, 7, 53, 7, 54, 7, 1, 0, 128, +4, 180, 4, 129, 4, 3, 7, 54, 7, 4, 7, 1, 0, 129, 4, 180, 4, 181, 4, 4, +7, 54, 7, 55, 7, 1, 0, 129, 4, 181, 4, 130, 4, 4, 7, 55, 7, 5, 7, 1, +0, 130, 4, 181, 4, 182, 4, 5, 7, 55, 7, 56, 7, 1, 0, 130, 4, 182, 4, 131, +4, 5, 7, 56, 7, 6, 7, 1, 0, 131, 4, 182, 4, 183, 4, 6, 7, 56, 7, 57, +7, 1, 0, 131, 4, 183, 4, 132, 4, 6, 7, 57, 7, 7, 7, 1, 0, 132, 4, 183, +4, 184, 4, 7, 7, 57, 7, 58, 7, 1, 0, 132, 4, 184, 4, 133, 4, 7, 7, 58, +7, 8, 7, 1, 0, 133, 4, 184, 4, 185, 4, 8, 7, 58, 7, 59, 7, 1, 0, 133, +4, 185, 4, 134, 4, 8, 7, 59, 7, 9, 7, 1, 0, 134, 4, 185, 4, 186, 4, 9, +7, 59, 7, 60, 7, 1, 0, 134, 4, 186, 4, 135, 4, 9, 7, 60, 7, 10, 7, 1, +0, 135, 4, 186, 4, 187, 4, 10, 7, 60, 7, 61, 7, 1, 0, 135, 4, 187, 4, 136, +4, 10, 7, 61, 7, 11, 7, 1, 0, 136, 4, 187, 4, 188, 4, 11, 7, 61, 7, 62, +7, 1, 0, 136, 4, 188, 4, 137, 4, 11, 7, 62, 7, 12, 7, 1, 0, 137, 4, 188, +4, 189, 4, 12, 7, 62, 7, 63, 7, 1, 0, 137, 4, 189, 4, 138, 4, 12, 7, 63, +7, 13, 7, 1, 0, 138, 4, 189, 4, 190, 4, 13, 7, 63, 7, 64, 7, 1, 0, 138, +4, 190, 4, 139, 4, 13, 7, 64, 7, 14, 7, 1, 0, 139, 4, 190, 4, 191, 4, 14, +7, 64, 7, 65, 7, 1, 0, 139, 4, 191, 4, 140, 4, 14, 7, 65, 7, 15, 7, 1, +0, 140, 4, 191, 4, 192, 4, 15, 7, 65, 7, 66, 7, 1, 0, 140, 4, 192, 4, 141, +4, 15, 7, 66, 7, 16, 7, 1, 0, 141, 4, 192, 4, 193, 4, 16, 7, 66, 7, 67, +7, 1, 0, 141, 4, 193, 4, 142, 4, 16, 7, 67, 7, 17, 7, 1, 0, 142, 4, 193, +4, 194, 4, 17, 7, 67, 7, 68, 7, 1, 0, 142, 4, 194, 4, 143, 4, 17, 7, 68, +7, 18, 7, 1, 0, 143, 4, 194, 4, 195, 4, 18, 7, 68, 7, 69, 7, 1, 0, 143, +4, 195, 4, 144, 4, 18, 7, 69, 7, 19, 7, 1, 0, 144, 4, 195, 4, 196, 4, 19, +7, 69, 7, 70, 7, 1, 0, 144, 4, 196, 4, 145, 4, 19, 7, 70, 7, 20, 7, 1, +0, 145, 4, 196, 4, 197, 4, 20, 7, 70, 7, 71, 7, 1, 0, 145, 4, 197, 4, 146, +4, 20, 7, 71, 7, 21, 7, 1, 0, 146, 4, 197, 4, 198, 4, 21, 7, 71, 7, 22, +7, 1, 0, 146, 4, 198, 4, 147, 4, 21, 7, 22, 7, 228, 6, 1, 0, 148, 4, 199, +4, 200, 4, 22, 7, 72, 7, 73, 7, 1, 0, 148, 4, 200, 4, 149, 4, 22, 7, 73, +7, 23, 7, 1, 0, 149, 4, 200, 4, 201, 4, 23, 7, 73, 7, 74, 7, 1, 0, 149, +4, 201, 4, 150, 4, 23, 7, 74, 7, 24, 7, 1, 0, 150, 4, 201, 4, 202, 4, 24, +7, 74, 7, 75, 7, 1, 0, 150, 4, 202, 4, 151, 4, 24, 7, 75, 7, 25, 7, 1, +0, 151, 4, 202, 4, 203, 4, 25, 7, 75, 7, 76, 7, 1, 0, 151, 4, 203, 4, 152, +4, 25, 7, 76, 7, 26, 7, 1, 0, 152, 4, 203, 4, 204, 4, 26, 7, 76, 7, 77, +7, 1, 0, 152, 4, 204, 4, 153, 4, 26, 7, 77, 7, 27, 7, 1, 0, 153, 4, 204, +4, 205, 4, 27, 7, 77, 7, 78, 7, 1, 0, 153, 4, 205, 4, 154, 4, 27, 7, 78, +7, 28, 7, 1, 0, 154, 4, 205, 4, 206, 4, 28, 7, 78, 7, 79, 7, 1, 0, 154, +4, 206, 4, 155, 4, 28, 7, 79, 7, 29, 7, 1, 0, 155, 4, 206, 4, 207, 4, 29, +7, 79, 7, 80, 7, 1, 0, 155, 4, 207, 4, 156, 4, 29, 7, 80, 7, 30, 7, 1, +0, 156, 4, 207, 4, 208, 4, 30, 7, 80, 7, 81, 7, 1, 0, 156, 4, 208, 4, 157, +4, 30, 7, 81, 7, 31, 7, 1, 0, 157, 4, 208, 4, 209, 4, 31, 7, 81, 7, 82, +7, 1, 0, 157, 4, 209, 4, 158, 4, 31, 7, 82, 7, 32, 7, 1, 0, 158, 4, 209, +4, 210, 4, 32, 7, 82, 7, 83, 7, 1, 0, 158, 4, 210, 4, 159, 4, 32, 7, 83, +7, 33, 7, 1, 0, 159, 4, 210, 4, 211, 4, 33, 7, 83, 7, 84, 7, 1, 0, 159, +4, 211, 4, 160, 4, 33, 7, 84, 7, 34, 7, 1, 0, 160, 4, 211, 4, 212, 4, 34, +7, 84, 7, 85, 7, 1, 0, 160, 4, 212, 4, 161, 4, 34, 7, 85, 7, 35, 7, 1, +0, 161, 4, 212, 4, 213, 4, 35, 7, 85, 7, 86, 7, 1, 0, 161, 4, 213, 4, 162, +4, 35, 7, 86, 7, 36, 7, 1, 0, 162, 4, 213, 4, 214, 4, 36, 7, 86, 7, 87, +7, 1, 0, 162, 4, 214, 4, 163, 4, 36, 7, 87, 7, 37, 7, 1, 0, 163, 4, 214, +4, 215, 4, 37, 7, 87, 7, 88, 7, 1, 0, 163, 4, 215, 4, 164, 4, 37, 7, 88, +7, 38, 7, 1, 0, 164, 4, 215, 4, 216, 4, 38, 7, 88, 7, 89, 7, 1, 0, 164, +4, 216, 4, 165, 4, 38, 7, 89, 7, 39, 7, 1, 0, 165, 4, 216, 4, 217, 4, 39, +7, 89, 7, 90, 7, 1, 0, 165, 4, 217, 4, 166, 4, 39, 7, 90, 7, 40, 7, 1, +0, 166, 4, 217, 4, 218, 4, 40, 7, 90, 7, 91, 7, 1, 0, 166, 4, 218, 4, 167, +4, 40, 7, 91, 7, 41, 7, 1, 0, 167, 4, 218, 4, 219, 4, 41, 7, 91, 7, 92, +7, 1, 0, 167, 4, 219, 4, 168, 4, 41, 7, 92, 7, 42, 7, 1, 0, 168, 4, 219, +4, 220, 4, 42, 7, 92, 7, 93, 7, 1, 0, 168, 4, 220, 4, 169, 4, 42, 7, 93, +7, 43, 7, 1, 0, 169, 4, 220, 4, 221, 4, 43, 7, 93, 7, 94, 7, 1, 0, 169, +4, 221, 4, 170, 4, 43, 7, 94, 7, 44, 7, 1, 0, 170, 4, 221, 4, 222, 4, 44, +7, 94, 7, 95, 7, 1, 0, 170, 4, 222, 4, 171, 4, 44, 7, 95, 7, 45, 7, 1, +0, 171, 4, 222, 4, 223, 4, 45, 7, 95, 7, 96, 7, 1, 0, 171, 4, 223, 4, 172, +4, 45, 7, 96, 7, 46, 7, 1, 0, 172, 4, 223, 4, 224, 4, 46, 7, 96, 7, 97, +7, 1, 0, 172, 4, 224, 4, 173, 4, 46, 7, 97, 7, 47, 7, 1, 0, 173, 4, 224, +4, 225, 4, 47, 7, 97, 7, 98, 7, 1, 0, 173, 4, 225, 4, 174, 4, 47, 7, 98, +7, 48, 7, 1, 0, 174, 4, 225, 4, 226, 4, 48, 7, 98, 7, 99, 7, 1, 0, 174, +4, 226, 4, 175, 4, 48, 7, 99, 7, 49, 7, 1, 0, 175, 4, 226, 4, 227, 4, 49, +7, 99, 7, 100, 7, 1, 0, 175, 4, 227, 4, 176, 4, 49, 7, 100, 7, 50, 7, 1, +0, 176, 4, 227, 4, 228, 4, 50, 7, 100, 7, 101, 7, 1, 0, 176, 4, 228, 4, 177, +4, 50, 7, 101, 7, 51, 7, 1, 0, 177, 4, 228, 4, 229, 4, 51, 7, 101, 7, 102, +7, 1, 0, 177, 4, 229, 4, 178, 4, 51, 7, 102, 7, 52, 7, 1, 0, 178, 4, 229, +4, 230, 4, 52, 7, 102, 7, 103, 7, 1, 0, 178, 4, 230, 4, 179, 4, 52, 7, 103, +7, 53, 7, 1, 0, 179, 4, 230, 4, 231, 4, 53, 7, 103, 7, 104, 7, 1, 0, 179, +4, 231, 4, 180, 4, 53, 7, 104, 7, 54, 7, 1, 0, 180, 4, 231, 4, 232, 4, 54, +7, 104, 7, 105, 7, 1, 0, 180, 4, 232, 4, 181, 4, 54, 7, 105, 7, 55, 7, 1, +0, 181, 4, 232, 4, 233, 4, 55, 7, 105, 7, 106, 7, 1, 0, 181, 4, 233, 4, 182, +4, 55, 7, 106, 7, 56, 7, 1, 0, 182, 4, 233, 4, 234, 4, 56, 7, 106, 7, 107, +7, 1, 0, 182, 4, 234, 4, 183, 4, 56, 7, 107, 7, 57, 7, 1, 0, 183, 4, 234, +4, 235, 4, 57, 7, 107, 7, 108, 7, 1, 0, 183, 4, 235, 4, 184, 4, 57, 7, 108, +7, 58, 7, 1, 0, 184, 4, 235, 4, 236, 4, 58, 7, 108, 7, 109, 7, 1, 0, 184, +4, 236, 4, 185, 4, 58, 7, 109, 7, 59, 7, 1, 0, 185, 4, 236, 4, 237, 4, 59, +7, 109, 7, 110, 7, 1, 0, 185, 4, 237, 4, 186, 4, 59, 7, 110, 7, 60, 7, 1, +0, 186, 4, 237, 4, 238, 4, 60, 7, 110, 7, 111, 7, 1, 0, 186, 4, 238, 4, 187, +4, 60, 7, 111, 7, 61, 7, 1, 0, 187, 4, 238, 4, 239, 4, 61, 7, 111, 7, 112, +7, 1, 0, 187, 4, 239, 4, 188, 4, 61, 7, 112, 7, 62, 7, 1, 0, 188, 4, 239, +4, 240, 4, 62, 7, 112, 7, 113, 7, 1, 0, 188, 4, 240, 4, 189, 4, 62, 7, 113, +7, 63, 7, 1, 0, 189, 4, 240, 4, 241, 4, 63, 7, 113, 7, 114, 7, 1, 0, 189, +4, 241, 4, 190, 4, 63, 7, 114, 7, 64, 7, 1, 0, 190, 4, 241, 4, 242, 4, 64, +7, 114, 7, 115, 7, 1, 0, 190, 4, 242, 4, 191, 4, 64, 7, 115, 7, 65, 7, 1, +0, 191, 4, 242, 4, 243, 4, 65, 7, 115, 7, 116, 7, 1, 0, 191, 4, 243, 4, 192, +4, 65, 7, 116, 7, 66, 7, 1, 0, 192, 4, 243, 4, 244, 4, 66, 7, 116, 7, 117, +7, 1, 0, 192, 4, 244, 4, 193, 4, 66, 7, 117, 7, 67, 7, 1, 0, 193, 4, 244, +4, 245, 4, 67, 7, 117, 7, 118, 7, 1, 0, 193, 4, 245, 4, 194, 4, 67, 7, 118, +7, 68, 7, 1, 0, 194, 4, 245, 4, 246, 4, 68, 7, 118, 7, 119, 7, 1, 0, 194, +4, 246, 4, 195, 4, 68, 7, 119, 7, 69, 7, 1, 0, 195, 4, 246, 4, 247, 4, 69, +7, 119, 7, 120, 7, 1, 0, 195, 4, 247, 4, 196, 4, 69, 7, 120, 7, 70, 7, 1, +0, 196, 4, 247, 4, 248, 4, 70, 7, 120, 7, 121, 7, 1, 0, 196, 4, 248, 4, 197, +4, 70, 7, 121, 7, 71, 7, 1, 0, 197, 4, 248, 4, 249, 4, 71, 7, 121, 7, 72, +7, 1, 0, 197, 4, 249, 4, 198, 4, 71, 7, 72, 7, 22, 7, 1, 0, 250, 4, 200, +4, 199, 4, 122, 7, 73, 7, 72, 7, 1, 0, 251, 4, 201, 4, 200, 4, 122, 7, 74, +7, 73, 7, 1, 0, 252, 4, 202, 4, 201, 4, 122, 7, 75, 7, 74, 7, 1, 0, 253, +4, 203, 4, 202, 4, 122, 7, 76, 7, 75, 7, 1, 0, 254, 4, 204, 4, 203, 4, 122, +7, 77, 7, 76, 7, 1, 0, 255, 4, 205, 4, 204, 4, 122, 7, 78, 7, 77, 7, 1, +0, 0, 5, 206, 4, 205, 4, 122, 7, 79, 7, 78, 7, 1, 0, 1, 5, 207, 4, 206, +4, 122, 7, 80, 7, 79, 7, 1, 0, 2, 5, 208, 4, 207, 4, 122, 7, 81, 7, 80, +7, 1, 0, 3, 5, 209, 4, 208, 4, 122, 7, 82, 7, 81, 7, 1, 0, 4, 5, 210, +4, 209, 4, 122, 7, 83, 7, 82, 7, 1, 0, 5, 5, 211, 4, 210, 4, 122, 7, 84, +7, 83, 7, 1, 0, 6, 5, 212, 4, 211, 4, 122, 7, 85, 7, 84, 7, 1, 0, 7, +5, 213, 4, 212, 4, 122, 7, 86, 7, 85, 7, 1, 0, 8, 5, 214, 4, 213, 4, 122, +7, 87, 7, 86, 7, 1, 0, 9, 5, 215, 4, 214, 4, 122, 7, 88, 7, 87, 7, 1, +0, 10, 5, 216, 4, 215, 4, 122, 7, 89, 7, 88, 7, 1, 0, 11, 5, 217, 4, 216, +4, 122, 7, 90, 7, 89, 7, 1, 0, 12, 5, 218, 4, 217, 4, 122, 7, 91, 7, 90, +7, 1, 0, 13, 5, 219, 4, 218, 4, 122, 7, 92, 7, 91, 7, 1, 0, 14, 5, 220, +4, 219, 4, 122, 7, 93, 7, 92, 7, 1, 0, 15, 5, 221, 4, 220, 4, 122, 7, 94, +7, 93, 7, 1, 0, 16, 5, 222, 4, 221, 4, 122, 7, 95, 7, 94, 7, 1, 0, 17, +5, 223, 4, 222, 4, 122, 7, 96, 7, 95, 7, 1, 0, 18, 5, 224, 4, 223, 4, 122, +7, 97, 7, 96, 7, 1, 0, 19, 5, 225, 4, 224, 4, 122, 7, 98, 7, 97, 7, 1, +0, 20, 5, 226, 4, 225, 4, 122, 7, 99, 7, 98, 7, 1, 0, 21, 5, 227, 4, 226, +4, 122, 7, 100, 7, 99, 7, 1, 0, 22, 5, 228, 4, 227, 4, 122, 7, 101, 7, 100, +7, 1, 0, 23, 5, 229, 4, 228, 4, 122, 7, 102, 7, 101, 7, 1, 0, 24, 5, 230, +4, 229, 4, 122, 7, 103, 7, 102, 7, 1, 0, 25, 5, 231, 4, 230, 4, 122, 7, 104, +7, 103, 7, 1, 0, 26, 5, 232, 4, 231, 4, 122, 7, 105, 7, 104, 7, 1, 0, 27, +5, 233, 4, 232, 4, 122, 7, 106, 7, 105, 7, 1, 0, 28, 5, 234, 4, 233, 4, 122, +7, 107, 7, 106, 7, 1, 0, 29, 5, 235, 4, 234, 4, 122, 7, 108, 7, 107, 7, 1, +0, 30, 5, 236, 4, 235, 4, 122, 7, 109, 7, 108, 7, 1, 0, 31, 5, 237, 4, 236, +4, 122, 7, 110, 7, 109, 7, 1, 0, 32, 5, 238, 4, 237, 4, 122, 7, 111, 7, 110, +7, 1, 0, 33, 5, 239, 4, 238, 4, 122, 7, 112, 7, 111, 7, 1, 0, 34, 5, 240, +4, 239, 4, 122, 7, 113, 7, 112, 7, 1, 0, 35, 5, 241, 4, 240, 4, 122, 7, 114, +7, 113, 7, 1, 0, 36, 5, 242, 4, 241, 4, 122, 7, 115, 7, 114, 7, 1, 0, 37, +5, 243, 4, 242, 4, 122, 7, 116, 7, 115, 7, 1, 0, 38, 5, 244, 4, 243, 4, 122, +7, 117, 7, 116, 7, 1, 0, 39, 5, 245, 4, 244, 4, 122, 7, 118, 7, 117, 7, 1, +0, 40, 5, 246, 4, 245, 4, 122, 7, 119, 7, 118, 7, 1, 0, 41, 5, 247, 4, 246, +4, 122, 7, 120, 7, 119, 7, 1, 0, 42, 5, 248, 4, 247, 4, 122, 7, 121, 7, 120, +7, 1, 0, 43, 5, 249, 4, 248, 4, 122, 7, 72, 7, 121, 7, 1, 0, 66, 77, 54, +4, 1, 0, 0, 0, 0, 0, 54, 4, 0, 0, 40, 0, 0, 0, 0, 1, 0, 0, 0, +1, 0, 0, 1, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 11, 1, 0, 203, 17, 1, 0, 145, +13, 1, 0, 208, 21, 1, 0, 205, 19, 1, 0, 205, 22, 1, 0, 203, 22, 1, 1, 133, +13, 1, 0, 205, 24, 3, 0, 58, 7, 1, 0, 205, 26, 6, 0, 207, 31, 10, 0, 208, +34, 16, 1, 21, 4, 2, 0, 66, 16, 10, 0, 228, 31, 1, 1, 217, 28, 1, 0, 213, +27, 1, 1, 213, 29, 1, 0, 207, 25, 1, 1, 207, 27, 1, 0, 205, 25, 1, 0, 205, +27, 1, 0, 203, 26, 1, 1, 197, 23, 1, 0, 188, 24, 1, 1, 180, 24, 1, 0, 221, +31, 2, 0, 209, 27, 2, 0, 199, 27, 2, 0, 193, 27, 2, 1, 104, 13, 1, 0, 101, +13, 1, 0, 241, 34, 3, 1, 216, 31, 3, 0, 215, 29, 3, 1, 213, 29, 3, 0, 211, +29, 3, 0, 209, 29, 3, 0, 207, 27, 3, 1, 207, 29, 3, 5, 205, 29, 3, 1, 204, +27, 3, 0, 202, 29, 3, 1, 168, 23, 2, 0, 162, 23, 2, 0, 155, 22, 2, 0, 149, +21, 2, 0, 77, 11, 1, 1, 65, 9, 1, 0, 190, 27, 3, 1, 186, 27, 3, 0, 182, +26, 3, 0, 169, 25, 3, 1, 108, 16, 2, 1, 214, 31, 5, 0, 93, 14, 2, 1, 49, +7, 1, 0, 209, 31, 5, 1, 189, 28, 5, 255, 187, 28, 5, 1, 126, 19, 3, 1, 210, +33, 6, 0, 207, 31, 6, 0, 202, 32, 6, 0, 182, 27, 5, 0, 179, 27, 5, 0, 174, +27, 5, 0, 171, 27, 5, 0, 120, 19, 4, 0, 105, 17, 4, 0, 174, 29, 7, 0, 206, +36, 11, 0, 135, 23, 7, 0, 210, 38, 12, 0, 121, 21, 7, 0, 132, 26, 10, 255, 100, +21, 9, 0, 212, 47, 22, 0, 164, 37, 18, 0, 109, 25, 13, 0, 87, 21, 11, 0, 101, +25, 14, 119, 52, 14, 9, 127, 90, 26, 17, 0, 213, 31, 1, 0, 211, 29, 1, 0, 209, +29, 1, 119, 207, 31, 1, 0, 207, 29, 1, 0, 205, 29, 1, 0, 135, 19, 1, 119, 127, +18, 1, 0, 121, 17, 1, 0, 103, 15, 1, 255, 101, 15, 1, 1, 98, 14, 1, 0, 213, +33, 3, 1, 213, 31, 3, 1, 211, 31, 3, 119, 209, 31, 3, 0, 207, 31, 3, 119, 205, +31, 3, 0, 198, 29, 3, 1, 194, 29, 3, 0, 140, 21, 2, 0, 130, 19, 2, 1, 84, +13, 1, 0, 71, 11, 1, 0, 228, 34, 4, 1, 190, 29, 3, 0, 183, 29, 3, 0, 179, +29, 3, 1, 178, 27, 3, 1, 175, 29, 3, 0, 174, 26, 3, 1, 171, 28, 3, 0, 116, +18, 2, 1, 112, 17, 2, 255, 61, 9, 1, 1, 58, 9, 1, 1, 54, 9, 1, 0, 220, +34, 5, 0, 185, 29, 4, 0, 133, 21, 3, 0, 130, 21, 3, 127, 234, 37, 6, 0, 198, +31, 5, 1, 123, 19, 3, 2, 38, 6, 1, 0, 250, 43, 7, 0, 214, 34, 6, 1, 207, +33, 6, 0, 164, 27, 5, 0, 241, 40, 8, 0, 216, 37, 7, 255, 182, 30, 6, 0, 178, +30, 6, 0, 148, 24, 5, 0, 225, 38, 8, 0, 194, 32, 7, 0, 190, 32, 7, 119, 186, +31, 7, 0, 157, 27, 6, 0, 199, 34, 8, 127, 141, 24, 6, 1, 98, 17, 4, 0, 217, +39, 10, 1, 209, 36, 9, 0, 130, 23, 6, 0, 169, 30, 8, 0, 236, 45, 12, 0, 227, +43, 12, 0, 220, 42, 12, 255, 173, 35, 10, 1, 126, 23, 7, 0, 180, 34, 11, 0, 213, +43, 14, 0, 187, 36, 12, 0, 193, 38, 13, 0, 204, 41, 15, 0, 120, 24, 9, 127, 140, +29, 12, 0, 228, 50, 20, 0, 201, 44, 18, 0, 158, 35, 15, 1, 148, 32, 14, 0, 123, +28, 13, 0, 113, 28, 14, 0, 74, 18, 9, 1, 132, 33, 17, 0, 60, 15, 8, 0, 236, +63, 35, 1, 122, 32, 18, 0, 143, 39, 22, 0, 215, 62, 37, 0, 109, 34, 22, 1, 227, +75, 50, 0, 71, 24, 16, 0, 213, 74, 50, 0, 184, 65, 45, 0, 163, 59, 42, 0, 224, +92, 69, 0, 87, 35, 27, 0, 32, 14, 11, 0, 251, 56, 15, 0, 236, 54, 17, 0, 191, +43, 14, 0, 215, 50, 16, 1, 249, 61, 22, 0, 177, 43, 17, 0, 233, 60, 25, 0, 218, +56, 26, 0, 249, 72, 36, 0, 248, 82, 49, 0, 237, 86, 55, 0, 249, 113, 84, 0, 227, +110, 87, 0, 233, 125, 103, 1, 204, 52, 15, 0, 227, 67, 27, 0, 190, 56, 24, 0, 251, +92, 57, 0, 240, 101, 68, 0, 252, 85, 38, 0, 231, 78, 35, 0, 249, 147, 121, 0, 250, +77, 25, 0, 235, 88, 41, 0, 206, 75, 29, 0, 251, 105, 53, 0, 241, 102, 51, 1, 251, +95, 33, 0, 252, 112, 59, 0, 241, 114, 61, 0, 241, 128, 84, 0, 249, 177, 149, 0, 251, +106, 43, 0, 226, 99, 44, 0, 252, 123, 65, 0, 253, 136, 86, 0, 250, 201, 178, 0, 195, +87, 35, 0, 251, 120, 54, 0, 251, 119, 45, 0, 242, 128, 66, 1, 249, 136, 73, 0, 251, +124, 50, 0, 209, 108, 47, 1, 228, 121, 54, 0, 249, 144, 78, 0, 253, 223, 204, 0, 250, +136, 57, 1, 246, 149, 81, 0, 251, 156, 89, 0, 251, 134, 47, 1, 250, 144, 62, 0, 228, +131, 59, 0, 235, 141, 69, 0, 239, 144, 74, 0, 238, 142, 62, 1, 219, 128, 57, 0, 228, +139, 64, 0, 251, 156, 80, 0, 251, 154, 66, 0, 243, 151, 67, 0, 247, 158, 77, 1, 235, +155, 84, 0, 251, 168, 92, 0, 252, 172, 101, 0, 251, 153, 60, 0, 248, 158, 69, 1, 253, +238, 223, 0, 251, 163, 67, 0, 251, 166, 72, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 38, 38, 38, 38, +38, 38, 38, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 89, 40, 40, 40, 38, 40, 38, 38, 38, 38, 38, 38, 38, +38, 40, 40, 38, 38, 38, 38, 38, 38, 40, 40, 40, 40, 40, 38, 87, 38, 40, 40, 38, +38, 38, 38, 38, 38, 40, 38, 38, 40, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +38, 38, 38, 38, 38, 38, 38, 40, 40, 40, 40, 40, 37, 86, 28, 38, 38, 38, 38, 38, +38, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 38, 40, 40, 40, 40, 40, 86, 86, 37, 37, 37, 37, 37, +37, 28, 28, 28, 37, 37, 28, 37, 18, 18, 37, 37, 18, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 40, 41, 40, 37, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, +18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 38, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 37, 18, 36, 18, 18, 18, 18, 18, 18, 18, +38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 41, 41, 43, 127, 103, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, +30, 50, 50, 50, 30, 43, 40, 40, 40, 40, 140, 140, 50, 50, 50, 50, 50, 50, 51, 50, +51, 50, 50, 51, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, +51, 52, 59, 43, 38, 40, 40, 43, 141, 60, 51, 52, 52, 52, 52, 52, 26, 111, 43, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 41, 41, 40, 40, 38, 43, 156, 137, 26, 115, 115, 115, 115, 115, 115, 115, 115, +53, 53, 115, 53, 53, 53, 53, 53, 53, 53, 53, 44, 44, 44, 44, 44, 44, 44, 44, 44, +44, 67, 43, 38, 41, 41, 23, 43, 42, 42, 42, 42, 43, 43, 42, 43, 29, 23, 23, 23, +23, 23, 23, 43, 42, 42, 42, 23, 23, 23, 42, 37, 18, 37, 38, 40, 40, 40, 40, 40, +40, 40, 40, 40, 38, 41, 71, 143, 46, 46, 46, 46, 46, 46, 46, 143, 50, 37, 40, 37, +18, 18, 18, 18, 18, 18, 18, 37, 18, 37, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, +85, 85, 85, 85, 85, 18, 37, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 40, 41, 102, 144, +104, 59, 123, 65, 52, 113, 26, 113, 113, 113, 115, 115, 115, 115, 115, 44, 115, 53, 53, 45, +44, 30, 37, 40, 40, 37, 174, 173, 45, 44, 45, 45, 45, 45, 45, 45, 45, 46, 46, 45, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 138, 47, 47, 47, 47, 47, 47, 91, 138, 141, +36, 41, 86, 43, 170, 84, 105, 105, 105, 105, 91, 91, 92, 73, 59, 37, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 37, 103, 136, +127, 37, 40, 18, 158, 176, 178, 54, 54, 54, 54, 54, 54, 94, 94, 94, 94, 95, 95, 96, +96, 96, 96, 96, 56, 96, 56, 56, 56, 56, 107, 56, 107, 107, 107, 107, 108, 77, 142, 27, +30, 91, 117, 93, 93, 93, 93, 93, 93, 117, 117, 93, 93, 93, 93, 117, 118, 117, 117, 93, +93, 92, 93, 92, 92, 93, 106, 46, 51, 22, 37, 38, 40, 40, 40, 40, 40, 40, 40, 41, +18, 41, 84, 184, 129, 129, 129, 129, 129, 129, 13, 57, 143, 27, 41, 52, 113, 26, 113, 26, +113, 113, 113, 26, 113, 26, 113, 26, 113, 26, 113, 113, 113, 26, 26, 26, 26, 26, 26, 26, +26, 30, 40, 37, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 10, 63, 132, 101, 43, 43, 29, 29, 127, +127, 127, 140, 140, 140, 140, 127, 140, 140, 140, 140, 141, 140, 140, 110, 50, 25, 29, 38, 40, +38, 16, 176, 184, 150, 141, 136, 136, 136, 136, 136, 136, 136, 66, 66, 66, 137, 137, 137, 137, +71, 114, 71, 114, 67, 68, 68, 68, 68, 53, 150, 150, 116, 45, 68, 127, 37, 41, 86, 41, +168, 184, 143, 133, 143, 143, 133, 143, 46, 143, 140, 38, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 64, 133, 138, 141, 36, 41, 18, +140, 84, 184, 76, 145, 73, 73, 73, 73, 149, 149, 149, 149, 149, 149, 155, 155, 155, 155, 155, +155, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 117, 54, 155, 141, 15, 52, 48, 13, 57, +57, 57, 129, 57, 129, 57, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 57, 57, 57, 57, +57, 57, 57, 9, 107, 106, 26, 41, 38, 40, 40, 40, 40, 40, 40, 40, 18, 58, 146, 83, +169, 48, 169, 169, 169, 169, 49, 48, 150, 27, 104, 56, 9, 49, 49, 49, 49, 49, 119, 49, +119, 119, 119, 119, 119, 9, 9, 9, 9, 9, 108, 108, 108, 108, 108, 108, 48, 96, 105, 52, +42, 28, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 22, 8, 55, 122, 109, 15, 27, 131, 140, 79, 170, 168, 80, 80, 80, 80, +80, 80, 82, 80, 80, 82, 80, 80, 82, 82, 167, 64, 27, 89, 40, 40, 40, 34, 170, 184, +80, 80, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, +82, 82, 82, 77, 82, 82, 82, 81, 161, 67, 43, 72, 40, 41, 86, 40, 161, 13, 80, 82, +77, 82, 81, 80, 68, 142, 43, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 127, 137, 45, 53, 64, 37, 41, 18, 144, 82, 13, 84, +84, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, +81, 81, 81, 81, 81, 169, 178, 77, 91, 143, 127, 27, 50, 94, 49, 107, 56, 107, 56, 107, +107, 107, 107, 107, 107, 107, 107, 48, 48, 107, 48, 48, 48, 48, 107, 48, 107, 107, 107, 48, +48, 108, 56, 47, 103, 38, 40, 40, 40, 40, 40, 40, 37, 58, 69, 108, 169, 178, 14, 14, +14, 169, 146, 117, 137, 16, 104, 107, 57, 49, 108, 108, 49, 49, 49, 49, 49, 119, 119, 119, +9, 119, 9, 9, 121, 121, 9, 119, 119, 49, 119, 49, 49, 120, 119, 48, 106, 52, 37, 38, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 22, +28, 139, 134, 130, 130, 139, 79, 80, 169, 120, 83, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 57, 57, 57, 129, 107, 62, 33, 34, 41, 40, 40, 27, 174, 184, 81, 57, 57, 57, +57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 57, 129, 48, 30, 109, 148, 41, 40, 86, 40, 162, 184, 81, 129, 57, 57, 129, 108, +50, 55, 101, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 41, 101, 64, 30, 30, 25, 104, 63, 38, 41, 18, 64, 173, 129, 81, 57, 57, 57, 57, +57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, +57, 57, 57, 107, 45, 136, 127, 34, 30, 92, 56, 56, 48, 48, 48, 48, 48, 48, 48, 48, +48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 107, 107, 56, 96, 31, 54, 54, 94, 94, +106, 113, 37, 40, 40, 40, 40, 40, 87, 62, 145, 70, 107, 121, 121, 121, 57, 49, 93, 138, +141, 18, 29, 117, 107, 56, 107, 107, 107, 107, 107, 107, 107, 48, 107, 48, 107, 48, 48, 48, +48, 107, 107, 107, 107, 107, 107, 56, 56, 56, 96, 56, 107, 31, 46, 23, 37, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 23, 55, 163, 189, 189, 189, +201, 167, 56, 56, 96, 32, 32, 32, 94, 32, 32, 94, 32, 32, 32, 32, 94, 94, 32, 32, +32, 56, 149, 126, 130, 122, 43, 40, 40, 27, 174, 184, 161, 70, 32, 94, 94, 32, 32, 32, +32, 32, 32, 32, 32, 94, 32, 32, 32, 32, 32, 94, 32, 94, 32, 32, 32, 32, 32, 56, +106, 27, 33, 131, 43, 40, 87, 37, 166, 121, 149, 96, 32, 32, 56, 69, 17, 126, 55, 41, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 11, 55, 16, +122, 74, 55, 55, 132, 41, 40, 87, 132, 174, 108, 167, 32, 32, 94, 94, 32, 32, 32, 95, +95, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 94, 32, 32, 94, 94, 94, 56, 61, +25, 144, 63, 18, 29, 47, 92, 117, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, +56, 56, 56, 56, 96, 96, 56, 96, 95, 94, 54, 118, 93, 106, 91, 106, 92, 91, 52, 38, +40, 40, 40, 40, 89, 99, 143, 125, 117, 94, 95, 94, 96, 118, 46, 68, 140, 18, 29, 105, +118, 32, 48, 108, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +107, 107, 56, 146, 94, 54, 117, 93, 93, 117, 117, 47, 29, 37, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 131, 175, 194, 194, 177, 79, 92, 92, 91, 91, +91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 7, 92, 133, 172, +189, 147, 23, 40, 20, 27, 174, 83, 166, 105, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, +91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 93, 45, 126, 185, 147, +43, 40, 38, 36, 165, 169, 166, 91, 91, 91, 106, 47, 126, 130, 122, 41, 41, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 39, 10, 122, 33, 33, 134, 164, 156, 15, 33, +62, 43, 40, 86, 11, 165, 146, 166, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, +91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, 46, 17, 122, 62, 100, +23, 45, 105, 105, 106, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 61, 61, 61, 61, +106, 128, 93, 117, 117, 118, 118, 117, 128, 105, 47, 45, 46, 46, 45, 29, 40, 40, 40, 40, +89, 97, 150, 138, 47, 91, 91, 91, 106, 105, 115, 104, 144, 87, 43, 46, 106, 91, 54, 54, +54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 118, 118, 54, 54, 54, 54, +54, 118, 69, 91, 105, 105, 105, 91, 44, 43, 37, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 6, 27, 180, 183, 181, 182, 187, 46, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 44, 45, 45, 45, 45, 45, 45, 46, 156, 177, 194, 152, 29, 40, +20, 131, 181, 169, 79, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 65, 191, 189, 153, 23, 40, 20, 62, +190, 77, 154, 45, 45, 45, 45, 67, 186, 189, 147, 42, 41, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 22, 6, 39, 152, 130, 185, 185, 160, 143, 65, 134, 130, 131, 43, 40, 87, +62, 190, 75, 154, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 26, 15, 126, 62, 40, 41, 113, 45, 44, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 105, 125, +128, 69, 61, 124, 105, 138, 47, 53, 25, 52, 26, 30, 41, 40, 40, 40, 89, 97, 142, 53, +53, 44, 45, 45, 45, 44, 29, 58, 132, 20, 43, 115, 47, 46, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 124, 125, 92, 69, 117, 117, 93, 125, 105, +138, 44, 44, 44, 44, 25, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 22, +16, 175, 84, 178, 181, 78, 50, 25, 30, 30, 50, 30, 29, 20, 38, 39, 40, 40, 40, 39, +40, 40, 38, 40, 39, 24, 50, 30, 30, 25, 160, 203, 196, 78, 5, 40, 20, 135, 180, 84, +187, 140, 30, 30, 30, 24, 1, 23, 63, 40, 39, 40, 20, 88, 89, 40, 20, 22, 42, 41, +22, 90, 22, 41, 22, 41, 90, 6, 157, 202, 202, 153, 8, 40, 20, 62, 201, 167, 164, 25, +30, 30, 25, 144, 193, 194, 153, 20, 22, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, +6, 157, 172, 193, 194, 172, 157, 110, 26, 11, 193, 172, 131, 42, 40, 20, 74, 201, 145, 164, +30, 30, 30, 30, 24, 24, 42, 42, 41, 43, 90, 41, 41, 43, 41, 43, 43, 43, 90, 43, +43, 41, 43, 41, 41, 41, 29, 147, 185, 185, 131, 42, 37, 30, 52, 30, 50, 52, 51, 51, +51, 51, 51, 51, 51, 51, 51, 111, 51, 51, 111, 111, 111, 113, 116, 133, 143, 143, 47, 138, +143, 143, 143, 133, 110, 85, 18, 18, 86, 40, 40, 40, 22, 97, 127, 50, 103, 104, 30, 30, +50, 29, 15, 126, 55, 42, 41, 50, 115, 52, 44, 115, 53, 53, 44, 53, 53, 53, 44, 53, +53, 53, 53, 53, 133, 53, 116, 133, 46, 145, 73, 125, 124, 145, 138, 138, 138, 133, 110, 43, +29, 29, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 4, 192, 174, 84, 181, +163, 16, 27, 27, 27, 16, 15, 126, 139, 104, 45, 105, 91, 7, 91, 91, 7, 91, 7, 7, +79, 192, 109, 16, 27, 16, 163, 196, 196, 192, 6, 40, 20, 147, 180, 173, 78, 15, 27, 27, +16, 163, 201, 138, 2, 47, 47, 47, 47, 47, 47, 47, 47, 46, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 180, 182, 192, 6, 40, 20, 148, 201, 166, 192, 27, 27, 27, 16, 152, +202, 203, 78, 21, 22, 40, 40, 40, 40, 40, 40, 40, 40, 20, 6, 19, 172, 202, 202, 202, +172, 152, 27, 16, 17, 163, 194, 194, 74, 6, 40, 20, 157, 201, 165, 78, 15, 27, 27, 16, +152, 160, 26, 26, 52, 52, 52, 52, 52, 52, 52, 51, 52, 51, 51, 51, 51, 51, 51, 51, +25, 25, 25, 51, 78, 172, 147, 23, 18, 37, 90, 34, 15, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 97, 97, 135, 122, 122, 131, 144, 114, 150, 154, 116, 154, +156, 139, 126, 126, 139, 40, 40, 40, 22, 131, 148, 72, 34, 27, 27, 27, 27, 109, 33, 130, +147, 23, 38, 87, 50, 37, 40, 41, 41, 43, 41, 90, 41, 41, 41, 43, 43, 41, 41, 41, +102, 43, 103, 127, 104, 104, 110, 51, 114, 133, 116, 133, 133, 133, 123, 122, 109, 15, 16, 22, +41, 40, 40, 40, 40, 40, 40, 40, 40, 40, 39, 135, 180, 176, 181, 193, 130, 33, 33, 33, +33, 130, 134, 144, 138, 76, 170, 174, 162, 174, 162, 174, 166, 174, 174, 161, 174, 175, 130, 33, +33, 33, 185, 206, 206, 192, 1, 40, 22, 157, 180, 174, 191, 33, 33, 33, 33, 189, 197, 180, +166, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 79, 79, 79, 79, 79, 79, +165, 79, 180, 192, 5, 40, 20, 62, 180, 79, 191, 33, 33, 33, 33, 130, 196, 196, 78, 23, +20, 40, 40, 40, 40, 40, 40, 88, 19, 4, 147, 177, 196, 196, 196, 193, 134, 33, 33, 33, +33, 185, 196, 203, 157, 6, 40, 20, 160, 175, 156, 191, 33, 33, 33, 33, 189, 195, 201, 158, +158, 158, 158, 158, 159, 158, 159, 158, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +187, 175, 74, 23, 131, 122, 35, 27, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 109, 109, 109, 151, 130, 134, 151, 188, 190, 190, 154, 154, 154, 199, 186, 186, +186, 97, 40, 40, 22, 148, 153, 147, 134, 130, 33, 33, 33, 33, 189, 189, 153, 23, 37, 27, +22, 27, 15, 15, 15, 15, 15, 27, 15, 27, 15, 15, 15, 15, 15, 15, 15, 15, 122, 122, +109, 126, 126, 126, 139, 187, 154, 154, 154, 154, 154, 74, 134, 151, 152, 97, 22, 40, 40, 40, +40, 40, 40, 40, 40, 40, 3, 192, 174, 174, 177, 185, 130, 130, 185, 130, 130, 134, 158, 162, +174, 190, 201, 164, 164, 164, 164, 164, 164, 144, 175, 79, 181, 175, 185, 130, 130, 130, 193, 206, +206, 179, 1, 40, 22, 157, 179, 174, 172, 185, 130, 130, 130, 189, 206, 206, 175, 144, 160, 160, +164, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 132, +20, 40, 20, 148, 179, 190, 193, 130, 130, 130, 130, 189, 198, 206, 192, 6, 89, 40, 40, 40, +40, 40, 22, 1, 1, 78, 203, 206, 206, 196, 193, 130, 130, 130, 130, 130, 130, 193, 220, 196, +78, 6, 40, 19, 157, 175, 159, 172, 130, 130, 130, 130, 189, 196, 196, 78, 72, 74, 74, 74, +74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 148, 74, 63, 23, +131, 163, 151, 152, 152, 152, 152, 152, 152, 151, 152, 151, 152, 126, 151, 152, 151, 126, 151, 151, +152, 152, 163, 186, 186, 189, 186, 186, 199, 190, 201, 201, 201, 201, 191, 200, 191, 188, 90, 22, +22, 148, 153, 163, 186, 130, 130, 130, 130, 185, 194, 194, 78, 6, 58, 163, 139, 109, 109, 109, +126, 109, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 152, 186, 185, 185, +151, 163, 187, 190, 190, 201, 190, 199, 191, 186, 186, 147, 22, 40, 40, 40, 40, 40, 40, 40, +40, 20, 74, 180, 166, 179, 204, 185, 189, 189, 185, 185, 194, 180, 166, 190, 78, 157, 131, 98, +55, 55, 55, 55, 55, 17, 192, 201, 180, 195, 207, 185, 185, 185, 204, 216, 216, 175, 1, 20, +20, 74, 179, 190, 195, 189, 185, 189, 185, 204, 216, 216, 177, 0, 85, 97, 97, 97, 97, 97, +98, 97, 98, 98, 98, 36, 36, 37, 37, 37, 37, 37, 99, 36, 87, 20, 40, 40, 19, 148, +179, 164, 195, 185, 189, 189, 185, 207, 206, 206, 175, 6, 20, 40, 40, 40, 40, 21, 1, 12, +182, 206, 216, 206, 196, 207, 185, 185, 189, 189, 189, 189, 185, 204, 206, 198, 78, 1, 40, 21, +78, 177, 157, 194, 185, 189, 189, 185, 204, 206, 206, 192, 39, 38, 100, 100, 100, 38, 38, 38, +100, 100, 100, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 20, 20, 22, 58, 147, 153, 147, +153, 147, 147, 147, 153, 153, 147, 147, 147, 153, 153, 153, 153, 153, 153, 147, 147, 147, 147, 157, +157, 191, 207, 207, 205, 209, 222, 201, 209, 209, 205, 207, 208, 163, 90, 22, 21, 72, 186, 189, +189, 189, 189, 189, 185, 207, 202, 203, 192, 1, 58, 152, 152, 153, 153, 152, 153, 152, 153, 152, +153, 139, 152, 139, 152, 153, 139, 152, 139, 139, 153, 153, 153, 152, 163, 191, 189, 207, 200, 201, +201, 201, 201, 209, 200, 205, 205, 163, 23, 20, 40, 40, 40, 40, 40, 40, 40, 21, 78, 154, +180, 203, 204, 207, 207, 207, 189, 213, 221, 216, 187, 74, 85, 19, 21, 21, 6, 6, 6, 6, +6, 0, 78, 201, 180, 203, 204, 207, 207, 207, 210, 221, 221, 179, 1, 40, 20, 72, 179, 164, +203, 207, 207, 207, 185, 217, 221, 221, 175, 0, 1, 6, 5, 6, 1, 6, 6, 5, 6, 1, +21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 20, 40, 40, 40, 19, 74, 179, 175, 211, 207, +207, 207, 207, 204, 216, 216, 175, 6, 20, 40, 40, 40, 4, 1, 192, 198, 216, 221, 206, 213, +207, 207, 207, 207, 207, 207, 207, 207, 207, 210, 216, 206, 78, 1, 40, 21, 78, 177, 163, 195, +207, 207, 207, 207, 210, 206, 206, 157, 1, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 21, +20, 20, 20, 20, 20, 20, 20, 20, 20, 40, 40, 40, 40, 22, 41, 41, 41, 41, 41, 41, +41, 102, 90, 22, 23, 23, 23, 6, 23, 6, 23, 6, 6, 5, 6, 6, 1, 188, 208, 212, +208, 209, 222, 218, 222, 218, 218, 208, 211, 200, 41, 22, 21, 72, 172, 193, 207, 204, 207, 207, +207, 204, 196, 196, 192, 6, 40, 101, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 132, 62, +62, 62, 62, 62, 62, 62, 132, 132, 58, 101, 102, 188, 205, 207, 208, 209, 222, 209, 209, 209, +208, 204, 208, 200, 23, 20, 40, 40, 40, 40, 40, 40, 40, 42, 78, 26, 182, 219, 212, 212, +212, 212, 210, 216, 252, 206, 11, 4, 22, 40, 40, 132, 74, 11, 43, 64, 43, 29, 78, 78, +179, 214, 217, 212, 212, 212, 219, 221, 231, 179, 1, 40, 20, 72, 179, 78, 214, 217, 212, 212, +207, 219, 221, 231, 179, 24, 72, 72, 144, 72, 160, 72, 72, 144, 72, 72, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 72, 177, 191, 219, 212, 212, 212, 212, 217, +221, 221, 175, 6, 20, 40, 39, 1, 6, 179, 216, 231, 221, 206, 213, 207, 212, 212, 212, 212, +212, 212, 212, 212, 207, 214, 221, 206, 78, 1, 40, 21, 78, 195, 189, 213, 212, 212, 212, 212, +213, 216, 216, 175, 6, 63, 41, 63, 43, 102, 132, 102, 72, 132, 63, 41, 88, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 22, 6, 6, 6, +23, 23, 102, 102, 102, 102, 102, 64, 64, 64, 102, 43, 64, 192, 211, 204, 211, 229, 228, 228, +229, 218, 211, 214, 214, 205, 39, 22, 21, 72, 172, 202, 210, 212, 212, 212, 212, 217, 206, 206, +175, 6, 40, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 6, 6, 24, 6, 24, 23, 6, +24, 6, 24, 6, 24, 6, 1, 157, 208, 204, 211, 218, 222, 228, 228, 218, 218, 211, 211, 205, +21, 22, 40, 40, 40, 40, 40, 40, 20, 148, 175, 12, 215, 223, 217, 224, 217, 212, 234, 252, +221, 175, 0, 88, 40, 40, 132, 175, 197, 198, 198, 198, 198, 198, 206, 179, 177, 214, 223, 217, +217, 212, 226, 231, 231, 179, 0, 101, 20, 148, 177, 163, 215, 217, 217, 224, 212, 226, 231, 231, +206, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 179, 42, 20, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 21, 72, 195, 193, 215, 217, 217, 224, 217, 219, 231, 221, 175, 6, +89, 5, 0, 159, 197, 221, 252, 221, 206, 224, 212, 224, 217, 224, 217, 217, 224, 217, 224, 217, +212, 220, 231, 216, 78, 0, 40, 21, 157, 195, 193, 219, 217, 224, 217, 217, 226, 221, 221, 198, +198, 197, 198, 197, 198, 198, 197, 198, 197, 197, 197, 175, 1, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 21, 23, 132, 188, 192, 200, 200, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 208, 211, 210, 211, 225, 237, 237, 237, 237, 237, 225, 214, +225, 205, 41, 22, 21, 64, 195, 213, 213, 224, 217, 217, 217, 223, 206, 206, 175, 1, 40, 40, +40, 40, 40, 40, 40, 22, 5, 24, 157, 78, 148, 74, 157, 188, 157, 157, 188, 188, 188, 188, +188, 188, 188, 208, 211, 217, 214, 229, 241, 229, 229, 229, 214, 214, 214, 205, 23, 22, 40, 40, +40, 40, 40, 40, 21, 78, 192, 172, 225, 232, 227, 227, 224, 232, 216, 231, 197, 0, 21, 40, +40, 20, 72, 182, 198, 221, 231, 231, 231, 231, 252, 206, 203, 215, 232, 227, 227, 224, 230, 221, +221, 179, 0, 40, 20, 72, 177, 189, 226, 232, 227, 227, 224, 230, 221, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 198, 6, 21, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 21, 11, 195, 194, 220, 227, 227, 227, 224, 226, 231, 221, 175, 1, 4, 8, 175, 206, +252, 252, 221, 234, 224, 224, 227, 227, 227, 227, 227, 232, 219, 227, 227, 227, 224, 234, 231, 216, +164, 1, 101, 21, 74, 195, 202, 220, 227, 227, 227, 224, 234, 221, 231, 252, 231, 252, 231, 252, +231, 231, 231, 231, 231, 252, 231, 182, 0, 41, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 21, 19, 148, 192, 208, 214, 225, 226, 226, 226, 226, 226, 226, 226, 226, +226, 230, 226, 226, 230, 226, 225, 225, 245, 245, 245, 245, 251, 245, 226, 226, 239, 192, 41, 22, +21, 64, 203, 220, 226, 232, 227, 227, 227, 226, 216, 216, 175, 1, 20, 40, 40, 40, 40, 89, +21, 23, 72, 188, 203, 214, 218, 211, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 225, +214, 214, 225, 240, 240, 240, 240, 240, 225, 225, 225, 205, 6, 22, 40, 40, 40, 40, 40, 40, +23, 192, 126, 194, 230, 250, 236, 236, 232, 233, 216, 206, 175, 0, 88, 40, 40, 20, 72, 195, +33, 206, 216, 216, 216, 216, 216, 216, 206, 233, 236, 236, 236, 232, 243, 216, 216, 179, 1, 40, +20, 72, 195, 189, 220, 236, 236, 236, 232, 243, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 221, 221, 221, 197, 10, 21, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 148, +182, 202, 234, 236, 236, 236, 235, 243, 231, 221, 175, 0, 12, 179, 216, 252, 252, 216, 244, 235, +236, 236, 236, 236, 236, 236, 236, 233, 234, 236, 236, 236, 235, 248, 252, 216, 78, 0, 88, 21, +12, 203, 213, 234, 236, 236, 236, 232, 243, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 252, 231, 182, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 20, +21, 22, 209, 214, 239, 243, 233, 230, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 246, 254, 254, 254, 254, 254, 246, 233, 234, 233, 188, 19, 20, 23, 10, 214, 206, +233, 236, 236, 236, 232, 246, 216, 221, 179, 1, 40, 40, 40, 40, 90, 6, 72, 200, 211, 225, +226, 230, 230, 230, 230, 230, 230, 230, 230, 230, 233, 230, 233, 233, 233, 230, 230, 239, 251, 254, +251, 254, 253, 246, 230, 234, 238, 200, 1, 40, 40, 40, 40, 40, 40, 40, 21, 175, 130, 202, +243, 254, 251, 251, 253, 234, 216, 198, 72, 6, 40, 40, 40, 22, 74, 195, 185, 219, 253, 244, +244, 250, 244, 244, 254, 251, 251, 253, 251, 253, 248, 216, 206, 175, 1, 40, 22, 74, 203, 193, +243, 254, 251, 251, 253, 251, 244, 250, 244, 244, 250, 244, 244, 244, 244, 244, 244, 251, 216, 221, +182, 10, 22, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 72, 203, 213, 234, 253, +251, 251, 253, 243, 221, 221, 175, 12, 197, 221, 231, 221, 249, 250, 250, 253, 251, 251, 251, 251, +254, 251, 219, 196, 249, 254, 251, 253, 250, 249, 231, 216, 78, 1, 88, 6, 78, 203, 226, 248, +253, 251, 253, 251, 251, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 250, 248, 231, 231, 182, +0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 43, 208, 234, 248, +234, 234, 243, 233, 233, 239, 239, 239, 239, 239, 239, 239, 239, 246, 246, 246, 246, 246, 251, 251, +251, 251, 251, 253, 246, 248, 248, 249, 215, 160, 21, 40, 21, 29, 214, 249, 249, 254, 251, 253, +250, 248, 231, 231, 175, 1, 40, 40, 40, 20, 23, 74, 218, 233, 234, 234, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 243, 233, 233, 233, 246, 254, 251, 254, 254, 253, 254, 248, +234, 248, 215, 78, 1, 40, 40, 40, 40, 40, 40, 40, 6, 175, 189, 210, 243, 254, 254, 254, +254, 234, 206, 203, 40, 21, 40, 40, 40, 20, 148, 195, 193, 226, 254, 254, 254, 254, 254, 254, +253, 254, 254, 254, 254, 254, 243, 206, 206, 175, 1, 40, 22, 72, 203, 202, 243, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 253, 254, 253, 254, 253, 254, 206, 216, 182, 10, 22, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 72, 203, 219, 234, 254, 254, 254, 253, 248, +216, 216, 182, 198, 221, 221, 216, 254, 253, 253, 254, 254, 254, 254, 254, 254, 243, 226, 210, 220, +248, 254, 254, 254, 253, 249, 221, 206, 78, 1, 41, 21, 78, 215, 220, 249, 254, 254, 254, 254, +254, 251, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 248, 221, 221, 182, 0, 41, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 6, 6, 218, 249, 249, 249, 248, 247, 242, 242, +237, 237, 241, 241, 241, 241, 241, 242, 242, 240, 245, 251, 251, 245, 251, 251, 251, 245, 251, 246, +249, 249, 249, 234, 188, 42, 20, 40, 21, 23, 203, 206, 248, 254, 254, 254, 253, 249, 231, 221, +78, 6, 40, 40, 40, 5, 157, 225, 248, 248, 248, 248, 233, 239, 238, 238, 242, 242, 242, 242, +242, 242, 238, 245, 245, 251, 251, 251, 251, 245, 251, 251, 251, 251, 248, 249, 249, 249, 229, 12, +6, 40, 40, 40, 40, 40, 40, 40, 6, 192, 204, 210, 236, 244, 244, 244, 244, 220, 196, 195, +10, 21, 40, 40, 40, 20, 148, 195, 202, 219, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 250, 230, 206, 196, 175, 1, 40, 22, 132, 203, 213, 230, 244, 244, 244, 244, 244, 250, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 206, 206, 203, 10, 22, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 21, 72, 203, 220, 234, 244, 244, 244, 250, 243, 206, 206, 206, 216, +206, 206, 251, 250, 244, 244, 244, 244, 244, 244, 244, 243, 220, 226, 230, 220, 234, 244, 244, 244, +250, 234, 216, 206, 78, 1, 40, 5, 78, 215, 234, 234, 250, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 250, 243, 216, 216, 182, 0, 41, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 23, 6, 218, 248, 248, 249, 249, 242, 241, 241, 241, 237, 241, 241, 241, +241, 241, 241, 237, 237, 240, 240, 245, 245, 244, 245, 245, 245, 244, 251, 248, 249, 249, 249, 205, +6, 90, 40, 40, 21, 64, 203, 220, 234, 244, 250, 244, 236, 243, 221, 221, 179, 0, 40, 40, +21, 160, 239, 249, 249, 249, 247, 242, 241, 237, 237, 241, 241, 241, 241, 241, 241, 237, 242, 240, +245, 245, 245, 251, 245, 251, 251, 251, 251, 246, 249, 249, 249, 225, 64, 1, 88, 40, 40, 40, +40, 40, 40, 40, 6, 192, 202, 213, 232, 232, 232, 232, 232, 219, 203, 195, 63, 23, 40, 40, +40, 20, 132, 195, 213, 219, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 196, +196, 192, 6, 40, 22, 58, 203, 226, 226, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 219, 220, 198, 177, 10, 22, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 6, 148, 203, 234, 226, 235, 232, 232, 232, 226, 220, 206, 206, 206, 230, 232, 232, 232, +232, 232, 232, 232, 236, 236, 230, 226, 225, 177, 215, 220, 230, 232, 232, 232, 235, 230, 206, 198, +78, 1, 40, 21, 78, 215, 220, 230, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 235, 230, 206, 216, 177, 1, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +90, 1, 200, 233, 248, 243, 247, 241, 228, 241, 237, 241, 237, 237, 241, 241, 241, 229, 229, 229, +237, 237, 240, 232, 240, 236, 232, 236, 236, 243, 243, 233, 243, 248, 218, 20, 20, 40, 40, 40, +21, 11, 211, 196, 226, 236, 232, 232, 235, 226, 221, 216, 179, 1, 40, 21, 132, 225, 248, 246, +249, 247, 241, 241, 241, 241, 237, 241, 241, 241, 241, 241, 241, 237, 237, 240, 240, 236, 245, 236, +236, 236, 236, 236, 243, 234, 248, 249, 239, 192, 1, 40, 40, 40, 40, 40, 40, 40, 40, 40, +6, 192, 219, 219, 223, 224, 224, 224, 227, 210, 194, 172, 74, 6, 40, 40, 40, 20, 38, 211, +226, 210, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 210, 202, 195, 188, 6, 40, +22, 38, 203, 230, 219, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 203, 196, 177, 41, 22, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 62, +203, 226, 219, 224, 224, 224, 224, 223, 196, 196, 215, 227, 224, 224, 224, 224, 224, 224, 224, 227, +219, 219, 219, 195, 157, 132, 196, 219, 219, 224, 227, 224, 224, 219, 206, 196, 78, 6, 40, 21, +78, 203, 219, 219, 224, 227, 227, 227, 227, 227, 227, 227, 227, 224, 227, 224, 227, 227, 224, 224, +219, 206, 206, 177, 1, 20, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 6, 64, 214, 243, +226, 247, 228, 228, 228, 228, 241, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 225, 232, 232, +232, 232, 236, 233, 233, 230, 226, 236, 233, 218, 40, 22, 40, 40, 40, 40, 21, 144, 194, 213, +219, 227, 224, 227, 224, 226, 216, 216, 175, 1, 40, 19, 218, 234, 226, 234, 242, 228, 228, 241, +241, 237, 237, 237, 237, 241, 229, 229, 229, 229, 229, 227, 237, 232, 232, 232, 232, 236, 245, 234, +243, 226, 243, 239, 200, 5, 22, 40, 40, 40, 40, 40, 40, 40, 40, 40, 23, 147, 225, 219, +217, 217, 212, 217, 217, 212, 193, 189, 153, 23, 41, 40, 40, 20, 40, 195, 226, 219, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 227, 223, 202, 193, 147, 29, 40, 22, 20, 211, 226, +213, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 224, 223, 224, 223, 223, 224, 223, 213, 202, +172, 42, 22, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 23, 58, 195, 219, 210, 217, +217, 217, 217, 217, 203, 213, 217, 217, 212, 217, 217, 217, 217, 217, 217, 223, 210, 210, 205, 63, +21, 72, 203, 210, 210, 217, 212, 217, 217, 210, 196, 203, 78, 6, 40, 21, 157, 211, 210, 213, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 210, 196, 196, 177, +6, 20, 40, 40, 40, 40, 40, 40, 40, 40, 40, 20, 1, 205, 226, 219, 225, 241, 222, 222, +228, 229, 241, 229, 238, 230, 226, 230, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 214, +210, 219, 230, 225, 205, 102, 21, 40, 40, 40, 40, 40, 21, 72, 177, 194, 202, 217, 217, 217, +212, 210, 220, 206, 175, 1, 23, 74, 239, 226, 226, 239, 228, 222, 228, 228, 241, 241, 237, 238, +239, 238, 238, 238, 238, 238, 239, 239, 226, 236, 236, 239, 230, 230, 226, 219, 232, 230, 225, 200, +6, 23, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 22, 37, 213, 219, 212, 212, 212, 212, +212, 204, 185, 33, 126, 40, 22, 40, 40, 20, 28, 193, 226, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 204, 139, 23, 40, 41, 19, 194, 219, 219, 213, 213, 223, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 210, 213, 213, 213, 210, 191, 41, 22, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 22, 62, 208, 210, 194, 212, 207, 212, 207, 212, +204, 212, 212, 207, 212, 212, 207, 212, 212, 212, 217, 202, 204, 192, 40, 23, 22, 74, 194, 202, +217, 212, 212, 212, 207, 212, 202, 202, 74, 6, 40, 23, 157, 195, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 193, 204, 204, 202, 177, 4, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 22, 23, 218, 213, 213, 225, 228, 222, 222, 228, 228, 229, 226, +219, 210, 217, 210, 210, 217, 210, 217, 210, 217, 210, 217, 210, 217, 210, 213, 219, 225, 208, 188, +40, 21, 40, 40, 40, 40, 40, 40, 23, 72, 193, 189, 185, 189, 185, 185, 185, 185, 189, 202, +175, 6, 21, 200, 226, 210, 226, 228, 222, 222, 228, 228, 229, 225, 226, 225, 223, 219, 219, 223, +219, 223, 219, 223, 219, 219, 214, 213, 213, 210, 213, 226, 226, 218, 188, 21, 21, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 21, 205, 213, 204, 207, 189, 207, 207, 207, 186, 33, +126, 131, 43, 22, 40, 40, 88, 163, 191, 200, 200, 191, 200, 191, 200, 191, 200, 191, 200, 191, +191, 191, 191, 200, 191, 131, 23, 40, 40, 20, 163, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 153, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 22, 58, 172, 204, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 204, 204, 193, 191, 157, 22, 23, 40, 22, 148, 193, 193, 193, 207, 207, 207, +207, 193, 193, 172, 147, 23, 40, 22, 148, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 188, 22, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 23, 132, 211, 211, 217, 229, 201, 201, 209, 222, 218, 225, 225, 213, 210, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 208, 208, 205, 192, 132, 21, 21, 40, 40, 40, +40, 40, 40, 40, 22, 63, 192, 191, 163, 163, 163, 163, 163, 163, 163, 191, 78, 6, 41, 208, +213, 217, 225, 222, 222, 209, 228, 228, 237, 225, 219, 210, 213, 210, 213, 213, 210, 213, 210, 213, +210, 210, 213, 210, 213, 214, 211, 208, 192, 132, 21, 21, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 6, 192, 217, 204, 185, 185, 185, 185, 185, 185, 152, 16, 122, 62, 22, +40, 40, 40, 40, 28, 28, 28, 20, 28, 28, 20, 20, 20, 20, 20, 20, 20, 20, 20, 28, +40, 40, 20, 40, 40, 40, 20, 20, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 38, 28, 38, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 22, 58, 186, 189, 189, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 207, 189, +189, 189, 152, 63, 23, 22, 40, 40, 22, 148, 189, 189, 189, 185, 185, 185, 185, 185, 185, 151, +135, 23, 40, 40, 40, 58, 63, 63, 58, 58, 58, 58, 63, 63, 63, 63, 63, 63, 63, 63, +63, 63, 63, 63, 63, 63, 58, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 6, +157, 208, 204, 208, 218, 187, 199, 199, 209, 218, 219, 223, 214, 200, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 74, 148, 101, 21, 21, 22, 40, 40, 40, 40, 40, 40, 40, 40, +40, 89, 63, 132, 132, 132, 132, 132, 132, 132, 132, 63, 40, 20, 132, 211, 205, 211, 218, 201, +201, 209, 209, 218, 214, 219, 214, 211, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 200, +200, 192, 188, 148, 21, 21, 20, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 21, 72, 205, 204, 185, 130, 130, 130, 130, 130, 151, 58, 22, 58, 63, 100, 87, 40, 22, +23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 22, 40, 40, +40, 40, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 22, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 22, 40, +151, 185, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 185, 185, 130, 151, 135, 41, 23, +20, 40, 40, 40, 22, 148, 151, 130, 130, 130, 130, 130, 130, 130, 33, 33, 131, 43, 40, 40, +22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 22, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 6, 157, 205, 205, 208, +209, 159, 199, 199, 188, 205, 210, 211, 208, 102, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, +6, 6, 6, 6, 23, 22, 41, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 89, 22, 23, +23, 23, 23, 23, 23, 23, 23, 23, 22, 20, 132, 208, 200, 211, 205, 187, 199, 199, 199, 208, +210, 223, 211, 192, 102, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 41, 22, 21, 6, 6, +22, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 20, 29, 192, +193, 185, 33, 33, 33, 33, 33, 33, 147, 104, 50, 103, 64, 132, 58, 37, 37, 37, 37, 38, +38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 40, 40, 40, 40, 40, 90, 38, +38, 37, 37, 38, 38, 37, 38, 38, 38, 38, 37, 38, 38, 100, 38, 38, 38, 38, 38, 38, +88, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 40, 40, 40, 22, 40, 152, 130, 151, 33, +33, 33, 33, 33, 33, 33, 33, 134, 130, 134, 134, 139, 62, 23, 42, 40, 40, 40, 40, 40, +20, 148, 151, 134, 126, 33, 33, 33, 33, 33, 126, 109, 62, 43, 40, 40, 89, 20, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 41, 40, 40, 41, 41, 40, 6, 157, 205, 205, 205, 200, 111, 158, 144, +148, 200, 211, 211, 208, 135, 90, 88, 101, 132, 132, 102, 102, 132, 63, 101, 101, 101, 101, 101, +101, 101, 90, 22, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, +41, 41, 41, 41, 40, 20, 132, 208, 200, 212, 209, 159, 187, 160, 148, 205, 211, 210, 205, 62, +0, 6, 6, 23, 6, 6, 23, 6, 23, 23, 23, 23, 23, 43, 43, 102, 90, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 19, 159, 186, 185, 109, 27, +27, 15, 27, 15, 122, 72, 123, 115, 26, 65, 59, 104, 103, 104, 127, 103, 103, 127, 127, 103, +103, 127, 103, 127, 127, 127, 103, 103, 144, 102, 40, 40, 40, 41, 72, 140, 103, 127, 127, 127, +127, 127, 64, 127, 64, 127, 127, 127, 64, 43, 64, 64, 64, 64, 64, 64, 43, 64, 64, 64, +64, 64, 64, 64, 64, 64, 64, 63, 40, 40, 22, 40, 147, 126, 139, 27, 27, 27, 27, 27, +27, 15, 126, 126, 126, 139, 131, 102, 23, 22, 40, 40, 40, 40, 40, 40, 89, 132, 153, 139, +139, 27, 27, 27, 27, 122, 34, 97, 132, 41, 40, 40, 63, 72, 62, 58, 58, 58, 58, 58, +58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 62, 62, 62, 58, 58, 58, +55, 55, 62, 55, 55, 131, 101, 23, 135, 200, 200, 191, 209, 53, 116, 111, 141, 199, 204, 204, +204, 205, 192, 163, 188, 152, 152, 152, 152, 139, 139, 139, 139, 139, 139, 139, 139, 139, 135, 41, +41, 40, 40, 40, 40, 40, 40, 40, 20, 40, 148, 122, 122, 34, 122, 34, 122, 34, 122, 131, +58, 22, 100, 205, 191, 208, 192, 137, 136, 140, 104, 188, 204, 211, 208, 200, 157, 157, 153, 157, +147, 147, 135, 135, 135, 135, 135, 122, 135, 122, 122, 122, 62, 40, 41, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 87, 29, 160, 151, 126, 38, 29, 90, 41, 42, +89, 101, 140, 71, 133, 46, 45, 133, 133, 133, 45, 133, 133, 53, 133, 133, 133, 53, 133, 53, +53, 116, 53, 53, 137, 144, 87, 40, 40, 43, 78, 72, 115, 68, 115, 67, 67, 115, 67, 113, +67, 113, 113, 113, 113, 113, 113, 113, 113, 113, 66, 66, 112, 52, 66, 65, 65, 65, 123, 111, +123, 111, 141, 64, 38, 40, 20, 43, 74, 135, 72, 90, 90, 90, 23, 90, 99, 122, 147, 131, +148, 72, 41, 22, 20, 40, 40, 40, 40, 40, 40, 40, 20, 72, 74, 148, 72, 41, 41, 90, +41, 64, 103, 43, 63, 40, 40, 20, 64, 78, 72, 43, 64, 102, 102, 102, 102, 63, 102, 63, +101, 63, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 55, 55, 55, 62, 97, 55, 55, 97, +34, 74, 132, 22, 88, 191, 200, 186, 200, 150, 47, 133, 116, 137, 199, 207, 204, 207, 204, 207, +207, 186, 186, 151, 134, 134, 126, 126, 33, 126, 33, 126, 33, 126, 109, 131, 40, 40, 40, 40, +40, 40, 40, 40, 20, 58, 72, 135, 109, 109, 126, 126, 126, 126, 126, 126, 135, 23, 88, 200, +191, 200, 200, 133, 133, 114, 114, 158, 200, 207, 204, 193, 207, 172, 200, 186, 186, 151, 151, 151, +126, 126, 126, 126, 126, 126, 126, 33, 139, 62, 41, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 20, 140, 160, 109, 55, 51, 52, 51, 51, 51, 25, 30, 59, +154, 133, 143, 138, 47, 47, 47, 138, 47, 47, 46, 47, 46, 46, 46, 47, 46, 46, 46, 47, +46, 140, 86, 40, 40, 29, 164, 147, 133, 46, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, +45, 45, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 68, 144, +37, 40, 20, 43, 144, 64, 141, 25, 51, 51, 50, 103, 132, 64, 144, 144, 64, 22, 20, 40, +40, 40, 40, 40, 40, 40, 40, 40, 20, 72, 159, 144, 141, 51, 51, 25, 50, 60, 52, 51, +64, 38, 40, 20, 72, 164, 140, 141, 50, 50, 50, 50, 50, 50, 50, 50, 50, 30, 30, 30, +30, 30, 30, 104, 104, 104, 104, 104, 104, 104, 104, 103, 103, 103, 103, 103, 24, 64, 132, 89, +23, 163, 186, 163, 186, 190, 91, 47, 47, 47, 45, 164, 163, 191, 189, 191, 186, 163, 153, 135, +131, 97, 37, 20, 40, 38, 38, 38, 18, 16, 27, 34, 62, 40, 40, 40, 40, 40, 40, 40, +89, 97, 142, 137, 102, 27, 34, 34, 34, 34, 27, 34, 62, 22, 22, 163, 191, 152, 207, 150, +47, 46, 143, 45, 158, 191, 207, 207, 193, 207, 189, 186, 152, 126, 126, 109, 15, 15, 15, 15, +15, 15, 15, 15, 109, 135, 58, 41, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 38, 20, 158, 72, 122, 104, 53, 44, 44, 53, 53, 44, 44, 115, 115, 150, 133, +143, 45, 143, 45, 143, 45, 143, 133, 45, 133, 143, 133, 45, 133, 143, 145, 105, 141, 18, 40, +40, 29, 187, 74, 154, 133, 133, 45, 133, 45, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 53, 133, 47, 45, 140, 36, 40, 20, 43, +158, 141, 150, 44, 44, 115, 142, 140, 142, 158, 140, 102, 20, 20, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 20, 64, 156, 136, 154, 44, 53, 44, 115, 68, 44, 115, 64, 37, 40, 20, +64, 158, 137, 154, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 67, 67, 67, 67, 67, +67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 137, 26, 141, 64, 40, 23, 135, 186, 152, +152, 188, 105, 93, 106, 124, 91, 91, 143, 71, 154, 71, 154, 154, 150, 143, 45, 46, 46, 45, +45, 45, 45, 45, 44, 51, 22, 89, 102, 64, 38, 40, 40, 40, 40, 40, 89, 97, 137, 46, +71, 136, 66, 112, 112, 111, 103, 101, 132, 20, 22, 135, 191, 147, 186, 199, 105, 91, 105, 105, +105, 133, 164, 188, 188, 188, 188, 188, 160, 140, 141, 104, 50, 51, 50, 50, 50, 51, 30, 20, +17, 85, 62, 63, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +86, 103, 190, 141, 41, 66, 46, 47, 47, 47, 47, 47, 47, 47, 46, 46, 46, 46, 46, 46, +46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 138, 69, 69, 142, 18, 40, 40, 29, 190, 159, +143, 47, 46, 47, 46, 47, 46, 46, 47, 46, 47, 46, 46, 46, 46, 46, 46, 46, 46, 46, +47, 46, 46, 47, 46, 47, 46, 46, 47, 106, 105, 141, 35, 40, 20, 103, 156, 71, 143, 47, +45, 67, 137, 71, 156, 140, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +20, 72, 154, 150, 143, 47, 47, 47, 47, 143, 47, 45, 127, 36, 41, 87, 144, 190, 133, 165, +47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, +47, 47, 47, 47, 47, 47, 47, 46, 45, 71, 64, 38, 22, 90, 152, 152, 131, 152, 159, 69, +118, 93, 61, 93, 118, 31, 31, 32, 32, 31, 31, 31, 31, 118, 117, 93, 128, 92, 92, 92, +92, 91, 45, 25, 30, 50, 127, 40, 40, 40, 40, 40, 89, 62, 150, 145, 46, 47, 105, 47, +105, 46, 52, 104, 64, 20, 40, 40, 151, 152, 135, 186, 133, 69, 93, 92, 92, 93, 93, 106, +124, 106, 106, 124, 106, 92, 92, 92, 7, 91, 91, 105, 105, 2, 91, 45, 51, 29, 43, 127, +102, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 18, 103, 165, +154, 104, 115, 91, 128, 92, 128, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, +92, 92, 92, 92, 92, 92, 69, 56, 96, 136, 18, 40, 40, 103, 79, 156, 76, 128, 92, 92, +92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, +92, 92, 92, 106, 61, 31, 69, 142, 34, 41, 87, 103, 143, 143, 162, 47, 150, 133, 143, 156, +64, 87, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 20, 64, 165, 143, +76, 92, 92, 92, 92, 125, 61, 138, 140, 36, 41, 38, 140, 79, 145, 162, 92, 92, 92, 92, +92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, +92, 92, 92, 91, 47, 143, 127, 38, 40, 42, 37, 109, 34, 29, 109, 140, 128, 54, 118, 118, +54, 31, 96, 56, 56, 107, 56, 56, 56, 96, 96, 32, 32, 94, 31, 31, 94, 32, 94, 106, +44, 115, 67, 141, 102, 40, 40, 40, 89, 62, 143, 69, 106, 106, 92, 92, 93, 91, 45, 112, +144, 87, 40, 22, 55, 134, 102, 122, 139, 143, 117, 118, 93, 69, 118, 31, 32, 96, 56, 56, +96, 32, 32, 31, 54, 118, 118, 118, 117, 117, 93, 118, 92, 45, 26, 26, 60, 43, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 18, 103, 166, 162, 112, 44, +106, 94, 96, 96, 96, 96, 96, 96, 96, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 96, +96, 94, 146, 119, 14, 68, 16, 40, 38, 103, 174, 150, 80, 96, 96, 32, 32, 32, 32, 32, +32, 32, 32, 32, 32, 96, 96, 32, 32, 32, 32, 32, 32, 96, 32, 32, 32, 32, 32, 32, +96, 48, 146, 71, 27, 41, 87, 103, 166, 145, 145, 138, 145, 162, 142, 38, 87, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 89, 144, 162, 73, 117, 96, 96, 32, +96, 54, 32, 61, 141, 34, 40, 86, 140, 166, 155, 168, 96, 32, 32, 32, 96, 32, 96, 96, +32, 96, 32, 32, 32, 32, 96, 96, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 96, 54, +93, 138, 140, 37, 40, 40, 22, 37, 85, 52, 44, 40, 50, 106, 95, 56, 56, 107, 107, 107, +48, 108, 48, 107, 48, 108, 48, 108, 108, 108, 108, 108, 108, 49, 49, 49, 56, 105, 46, 45, +142, 40, 40, 40, 87, 97, 145, 146, 70, 94, 96, 32, 96, 54, 105, 133, 140, 87, 40, 40, +42, 27, 15, 26, 37, 122, 143, 118, 54, 94, 96, 56, 56, 107, 107, 48, 48, 107, 107, 107, +107, 107, 107, 56, 107, 56, 107, 107, 107, 56, 91, 45, 44, 67, 64, 86, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 18, 42, 165, 170, 143, 44, 47, 54, 48, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 119, 13, +57, 133, 27, 40, 38, 30, 170, 166, 169, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 57, 108, 71, +122, 40, 86, 104, 76, 61, 124, 161, 162, 140, 86, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 87, 144, 161, 161, 169, 49, 49, 49, 49, 169, 108, 70, +59, 34, 40, 86, 141, 170, 70, 84, 119, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 119, 48, 32, 155, 140, 37, +40, 40, 40, 40, 43, 51, 46, 47, 44, 26, 47, 31, 107, 48, 108, 119, 57, 57, 121, 57, +129, 57, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 13, 57, 94, 105, 105, 68, 40, 38, +38, 131, 75, 169, 48, 108, 49, 49, 119, 48, 92, 138, 141, 18, 40, 40, 40, 40, 40, 30, +47, 53, 103, 44, 117, 56, 48, 107, 107, 48, 108, 49, 108, 108, 49, 9, 9, 9, 121, 57, +9, 9, 121, 121, 9, 57, 57, 32, 47, 47, 133, 140, 86, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 41, 86, 86, 71, 170, 173, 145, 105, 7, 54, 107, 108, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 49, 121, 13, 13, 133, 27, 40, +38, 30, 173, 76, 169, 120, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 9, 119, 119, 119, 119, 9, 9, 119, 119, 9, 49, 120, 13, 129, 143, 27, 41, 86, 110, +161, 146, 77, 166, 43, 87, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 87, 140, 82, 146, 14, 119, 119, 119, 119, 49, 57, 107, 136, 27, 41, 18, +142, 168, 107, 169, 9, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 9, 119, 119, 119, 49, 49, 119, 49, 119, 9, 108, 48, 70, 59, 18, 40, 40, 40, 40, +38, 29, 44, 105, 106, 105, 47, 105, 93, 118, 56, 48, 48, 48, 49, 57, 57, 129, 129, 129, +129, 129, 129, 129, 129, 129, 57, 121, 119, 9, 49, 54, 93, 93, 133, 38, 18, 131, 70, 129, +121, 49, 119, 49, 9, 108, 94, 125, 142, 18, 40, 40, 40, 40, 40, 30, 44, 105, 47, 45, +45, 91, 54, 56, 48, 9, 57, 121, 57, 129, 129, 129, 129, 129, 129, 129, 13, 129, 13, 129, +13, 129, 129, 13, 108, 92, 91, 138, 104, 18, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 38, 86, 103, 150, 162, 173, 80, 161, 118, 117, 117, 117, 117, 117, 118, +118, 118, 118, 118, 118, 118, 118, 54, 54, 54, 70, 107, 171, 143, 27, 40, 38, 30, 176, 80, +146, 94, 94, 95, 32, 32, 32, 32, 96, 96, 32, 96, 96, 96, 96, 96, 56, 56, 56, 56, +56, 56, 56, 56, 107, 56, 107, 56, 107, 57, 83, 143, 15, 41, 18, 25, 81, 84, 136, 37, +38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +87, 140, 178, 49, 49, 49, 49, 49, 49, 49, 13, 171, 71, 27, 40, 18, 156, 178, 129, 121, +9, 120, 121, 121, 121, 121, 121, 121, 121, 57, 57, 57, 57, 57, 57, 57, 57, 57, 129, 57, +129, 129, 129, 129, 129, 129, 129, 129, 13, 14, 136, 18, 40, 40, 40, 40, 40, 40, 43, 113, +105, 117, 31, 56, 107, 48, 169, 48, 48, 48, 108, 49, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 13, 13, 13, 13, 13, 13, 9, 107, 107, 73, 41, 34, 107, 13, 13, 13, 13, 13, +13, 13, 13, 169, 137, 16, 40, 40, 40, 40, 40, 40, 50, 46, 92, 93, 106, 93, 31, 96, +107, 107, 107, 107, 108, 49, 121, 57, 57, 57, 57, 57, 57, 57, 57, 57, 129, 129, 129, 129, +129, 121, 96, 118, 128, 137, 27, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 38, 38, 41, 142, 165, 76, 173, 168, 77, 77, 77, 70, 77, 77, 77, 77, 77, +77, 77, 77, 77, 77, 77, 77, 77, 77, 150, 16, 40, 40, 103, 82, 77, 77, 77, 81, 77, +81, 77, 81, 77, 81, 146, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, +81, 81, 81, 81, 81, 169, 81, 150, 27, 40, 37, 104, 138, 123, 18, 38, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 127, 169, 171, +14, 14, 14, 14, 14, 14, 83, 81, 136, 27, 41, 18, 136, 81, 83, 171, 171, 171, 171, 171, +171, 171, 83, 171, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, +83, 83, 83, 83, 184, 169, 136, 18, 40, 40, 40, 40, 40, 40, 40, 40, 43, 113, 105, 54, +56, 56, 56, 56, 56, 56, 56, 56, 119, 57, 121, 121, 121, 121, 121, 121, 121, 9, 9, 121, +121, 121, 9, 121, 120, 107, 107, 107, 138, 127, 80, 83, 83, 83, 83, 83, 83, 83, 83, 169, +154, 16, 40, 40, 40, 40, 40, 40, 38, 43, 113, 105, 54, 107, 108, 119, 119, 108, 49, 119, +49, 9, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 49, +108, 107, 133, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +38, 87, 38, 40, 43, 127, 123, 113, 113, 66, 113, 66, 66, 113, 113, 113, 113, 113, 113, 113, +113, 66, 66, 113, 52, 43, 40, 40, 40, 41, 111, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 65, 103, 38, 40, 40, 41, 41, 38, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 113, 113, 113, 113, 113, 115, +115, 113, 115, 65, 43, 38, 40, 40, 43, 52, 115, 113, 115, 113, 115, 115, 115, 115, 115, 115, +115, 115, 113, 113, 113, 113, 113, 113, 115, 113, 115, 113, 115, 113, 115, 113, 115, 113, 115, 113, +115, 65, 43, 40, 40, 40, 40, 40, 40, 40, 40, 38, 38, 40, 43, 50, 51, 51, 51, 51, +51, 51, 51, 51, 52, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 52, 52, +52, 52, 52, 113, 51, 43, 50, 52, 52, 52, 52, 52, 52, 52, 113, 123, 103, 38, 40, 40, +40, 40, 40, 40, 40, 38, 38, 43, 52, 46, 105, 105, 105, 105, 105, 91, 105, 91, 128, 93, +117, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 106, 106, 106, 46, 43, +38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 87, +86, 86, 87, 87, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 37, 37, 37, +37, 38, 40, 40, 40, 40, 86, 86, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 40, +41, 40, 40, 40, 37, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 18, 18, 18, 18, 18, 18, 18, 18, 18, 37, +40, 41, 40, 40, 40, 86, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, +18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 37, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 38, 37, 37, 37, 37, 37, 37, 37, 37, 37, 18, +18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 37, 18, +38, 41, 86, 18, 18, 18, 18, 18, 18, 18, 18, 18, 38, 40, 40, 40, 40, 40, 40, 40, +40, 40, 38, 37, 37, 40, 41, 41, 22, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 40, 40, 41, 43, 43, 43, 29, 41, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 37, 37, 37, 37, 37, 37, 37, 37, 37, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, +18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 37, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, +41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, +41, 41, 41, 41, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, +40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 66, 77, 54, 4, 1, 0, 0, 0, 0, +0, 54, 4, 0, 0, 40, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 8, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 29, 20, 62, 0, 100, 90, 101, 0, 93, 73, 94, 0, 48, 26, 44, +0, 26, 10, 22, 0, 54, 10, 22, 0, 130, 121, 123, 1, 71, 9, 22, 0, 70, 6, 14, +0, 43, 14, 17, 0, 58, 22, 26, 0, 86, 6, 14, 0, 109, 6, 13, 1, 94, 6, 12, +0, 104, 2, 6, 0, 114, 6, 10, 1, 105, 17, 18, 0, 110, 2, 2, 1, 103, 2, 2, +0, 110, 6, 6, 1, 106, 6, 6, 0, 94, 6, 6, 0, 90, 6, 6, 0, 86, 6, 6, +1, 71, 6, 6, 0, 62, 6, 6, 1, 108, 12, 11, 0, 100, 12, 11, 0, 54, 6, 6, +0, 39, 6, 6, 0, 78, 14, 14, 1, 98, 20, 19, 0, 89, 19, 18, 0, 70, 14, 14, +1, 30, 6, 6, 0, 22, 6, 6, 1, 13, 6, 6, 0, 30, 14, 14, 0, 110, 6, 2, +0, 106, 6, 2, 1, 123, 5, 3, 5, 115, 5, 3, 1, 101, 6, 4, 0, 122, 14, 11, +1, 116, 13, 11, 0, 94, 12, 10, 0, 114, 21, 19, 0, 106, 27, 24, 0, 101, 50, 48, +1, 94, 6, 2, 0, 90, 6, 2, 1, 59, 16, 14, 0, 109, 38, 35, 0, 94, 38, 35, +1, 122, 51, 47, 1, 149, 133, 132, 0, 123, 12, 3, 1, 115, 11, 4, 0, 108, 12, 4, +1, 100, 12, 4, 255, 116, 20, 11, 1, 118, 30, 23, 1, 94, 12, 3, 0, 118, 16, 6, +0, 124, 21, 10, 0, 108, 20, 11, 0, 98, 20, 11, 0, 122, 41, 32, 0, 118, 17, 2, +0, 113, 18, 6, 0, 114, 18, 2, 0, 123, 20, 3, 0, 118, 22, 6, 0, 114, 22, 6, +0, 123, 28, 12, 0, 95, 30, 20, 0, 118, 22, 2, 255, 114, 22, 2, 0, 109, 21, 3, +0, 99, 21, 4, 0, 118, 26, 6, 0, 116, 28, 11, 0, 109, 28, 12, 119, 114, 26, 6, +127, 100, 28, 11, 0, 111, 40, 22, 0, 118, 26, 2, 0, 114, 26, 2, 119, 123, 28, 3, +0, 118, 30, 6, 0, 114, 30, 6, 0, 86, 24, 6, 119, 117, 35, 12, 0, 123, 36, 13, +0, 118, 30, 2, 255, 109, 28, 3, 1, 119, 34, 6, 0, 109, 36, 13, 1, 114, 30, 2, +1, 125, 36, 3, 119, 100, 29, 4, 0, 112, 34, 6, 119, 101, 35, 12, 0, 70, 36, 24, +1, 118, 34, 2, 0, 114, 34, 2, 0, 119, 38, 6, 1, 114, 38, 7, 0, 123, 44, 13, +0, 121, 71, 50, 1, 118, 38, 2, 0, 119, 42, 6, 0, 116, 44, 12, 1, 98, 44, 20, +1, 120, 57, 28, 0, 108, 56, 32, 1, 111, 88, 78, 0, 125, 44, 2, 1, 114, 38, 2, +255, 109, 37, 3, 1, 99, 37, 5, 1, 113, 42, 6, 0, 109, 45, 12, 0, 76, 31, 9, +0, 138, 87, 62, 0, 38, 30, 26, 127, 150, 120, 105, 0, 94, 82, 76, 1, 118, 42, 2, +2, 114, 42, 2, 0, 119, 46, 6, 0, 125, 52, 13, 1, 137, 105, 88, 0, 118, 46, 2, +0, 114, 46, 6, 0, 58, 26, 6, 255, 116, 52, 13, 0, 114, 46, 2, 0, 123, 52, 3, +0, 108, 45, 3, 0, 108, 52, 14, 0, 118, 52, 3, 119, 114, 51, 3, 0, 99, 46, 5, +0, 99, 50, 13, 127, 101, 70, 48, 1, 149, 74, 11, 0, 125, 62, 13, 1, 42, 22, 6, +0, 123, 60, 3, 0, 109, 52, 3, 0, 110, 60, 15, 0, 117, 60, 3, 0, 102, 54, 6, +255, 116, 63, 13, 1, 110, 109, 108, 0, 120, 73, 21, 0, 128, 82, 34, 0, 109, 60, 3, +0, 123, 70, 4, 0, 88, 50, 6, 0, 108, 71, 28, 127, 116, 69, 4, 0, 101, 61, 6, +0, 98, 64, 15, 0, 108, 68, 4, 1, 118, 92, 52, 0, 111, 77, 16, 0, 119, 81, 4, +0, 18, 14, 6, 1, 26, 22, 14, 0, 72, 59, 30, 0, 90, 67, 12, 1, 104, 85, 41, +0, 137, 131, 114, 0, 50, 46, 30, 0, 110, 106, 83, 1, 151, 152, 146, 0, 55, 71, 45, +0, 96, 103, 94, 0, 6, 22, 10, 0, 34, 98, 50, 0, 30, 78, 50, 0, 30, 106, 66, +0, 10, 42, 26, 0, 22, 70, 46, 0, 30, 86, 58, 0, 59, 90, 75, 0, 22, 78, 54, +1, 10, 70, 46, 0, 30, 70, 54, 0, 22, 54, 42, 0, 39, 89, 71, 0, 30, 62, 50, +0, 46, 78, 66, 0, 22, 70, 54, 0, 30, 78, 62, 0, 38, 78, 66, 0, 10, 54, 42, +1, 22, 78, 62, 0, 44, 102, 86, 0, 11, 86, 68, 0, 10, 70, 58, 0, 22, 62, 54, +0, 30, 70, 62, 0, 22, 70, 62, 0, 12, 42, 38, 0, 10, 58, 54, 0, 26, 79, 75, +0, 62, 104, 103, 0, 6, 26, 26, 0, 22, 54, 54, 1, 30, 62, 62, 0, 38, 78, 78, +0, 42, 86, 86, 0, 22, 42, 42, 0, 46, 78, 78, 0, 54, 90, 90, 0, 30, 50, 50, +0, 22, 30, 30, 0, 10, 77, 81, 0, 26, 98, 106, 0, 16, 60, 66, 0, 40, 65, 69, +0, 108, 124, 127, 0, 42, 90, 102, 1, 60, 70, 73, 0, 42, 74, 86, 0, 58, 90, 102, +1, 46, 70, 78, 0, 110, 140, 152, 0, 38, 66, 78, 0, 41, 95, 122, 1, 10, 42, 63, +0, 26, 74, 106, 0, 58, 107, 140, 1, 24, 48, 66, 0, 26, 42, 54, 0, 88, 109, 124, +0, 22, 54, 84, 0, 42, 74, 102, 1, 10, 26, 42, 0, 41, 50, 59, 0, 28, 80, 134, +0, 34, 74, 118, 0, 59, 90, 122, 0, 21, 59, 110, 1, 42, 58, 85, 0, 58, 74, 102, +0, 58, 70, 90, 0, 58, 78, 118, 0, 6, 10, 26, 1, 6, 18, 74, 0, 70, 75, 102, +0, 11, 16, 101, 0, 0, 0, 0, 0, 34, 35, 34, 35, 34, 34, 36, 34, 35, 34, 36, +34, 35, 34, 36, 34, 35, 34, 35, 36, 34, 35, 34, 35, 34, 35, 35, 34, 34, 35, 35, +34, 34, 36, 34, 34, 35, 34, 35, 34, 34, 34, 35, 34, 34, 35, 35, 34, 34, 36, 34, +35, 34, 34, 34, 36, 34, 34, 34, 36, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, +34, 34, 35, 34, 34, 34, 34, 35, 34, 35, 34, 29, 34, 34, 34, 34, 29, 35, 34, 29, +34, 34, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, +35, 29, 29, 34, 34, 29, 35, 29, 29, 34, 29, 29, 34, 29, 34, 34, 34, 34, 34, 29, +35, 29, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 34, 29, 34, +29, 34, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 29, 29, 34, 29, +29, 35, 29, 34, 34, 29, 35, 29, 34, 34, 34, 34, 34, 29, 34, 35, 29, 34, 29, 35, +34, 34, 34, 35, 29, 35, 34, 34, 29, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 35, 34, 35, 34, +35, 34, 35, 34, 34, 35, 34, 34, 35, 35, 34, 35, 34, 36, 34, 35, 34, 36, 34, 35, +34, 36, 34, 34, 34, 35, 34, 35, 34, 35, 34, 34, 35, 35, 34, 34, 35, 34, 34, 34, +35, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 35, 34, +34, 34, 35, 35, 34, 34, 36, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, +35, 34, 34, 29, 34, 34, 29, 35, 34, 34, 34, 34, 35, 34, 29, 35, 34, 29, 29, 34, +34, 34, 29, 29, 34, 29, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, 35, 29, 34, +29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 35, 29, 34, 29, 29, +29, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 29, 34, 34, 29, 29, 34, 29, 34, +29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, +29, 34, 29, 29, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, +29, 34, 29, 35, 29, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 29, 34, 34, 34, 34, +34, 34, 29, 35, 34, 34, 34, 29, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 35, 34, 34, 35, 35, 34, +34, 34, 35, 35, 34, 34, 34, 36, 34, 34, 35, 35, 35, 34, 35, 35, 35, 34, 35, 35, +35, 34, 35, 35, 34, 34, 36, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 36, 34, 34, 35, 35, 34, 35, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 35, 29, 29, 35, 29, 34, 29, 29, 34, 34, +29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 35, 29, 34, 34, +29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 29, 34, +29, 34, 29, 35, 29, 34, 34, 34, 34, 29, 29, 34, 34, 34, 29, 34, 34, 29, 29, 34, +29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 35, 29, 34, 34, +34, 29, 29, 34, 34, 29, 29, 34, 29, 29, 29, 35, 29, 34, 29, 34, 34, 34, 29, 34, +34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 35, 34, 34, 35, 29, 34, 34, 34, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, +34, 35, 34, 34, 34, 34, 35, 35, 34, 34, 34, 34, 36, 34, 34, 35, 34, 34, 34, 34, +35, 35, 35, 34, 34, 36, 34, 35, 34, 35, 34, 35, 34, 35, 34, 35, 34, 34, 35, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, +34, 34, 34, 34, 29, 35, 29, 34, 34, 29, 29, 29, 34, 34, 34, 29, 34, 29, 29, 34, +34, 29, 34, 34, 29, 34, 29, 34, 29, 35, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, +34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 29, 29, 34, 29, 34, 34, 34, 29, +34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 29, 29, 34, 34, 29, 29, 34, 29, 29, +29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, +34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 35, 29, +34, 29, 35, 29, 34, 29, 34, 29, 34, 34, 29, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 35, 34, 34, 34, 34, +35, 34, 34, 34, 36, 34, 36, 34, 34, 34, 34, 35, 35, 34, 35, 35, 34, 35, 34, 35, +35, 34, 34, 35, 35, 34, 35, 35, 35, 34, 35, 34, 36, 34, 35, 35, 34, 35, 35, 34, +34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 35, 34, 34, 34, 34, 34, 34, 29, 34, 34, 29, 34, 34, 34, 34, 29, 29, 34, +34, 29, 34, 29, 34, 29, 34, 34, 29, 29, 29, 29, 34, 34, 34, 29, 34, 29, 34, 34, +29, 34, 29, 34, 29, 29, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, +35, 29, 34, 29, 35, 29, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, +34, 34, 34, 29, 34, 29, 29, 34, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, +29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 34, 34, 29, 34, 34, 29, 29, 34, 34, 29, +34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, +34, 34, 34, 34, 34, 34, 35, 34, 29, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 36, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 35, 34, +34, 36, 34, 35, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, +35, 34, 34, 34, 34, 34, 34, 34, 35, 29, 29, 34, 29, 34, 34, 29, 34, 29, 29, 34, +29, 29, 34, 34, 29, 34, 34, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, +34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, +29, 35, 29, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 35, 34, 29, 34, 29, 35, +29, 34, 34, 29, 29, 34, 34, 29, 34, 29, 29, 29, 29, 35, 29, 29, 29, 34, 34, 29, +29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, +34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 35, +34, 29, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +35, 35, 34, 34, 34, 36, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 36, 34, 34, +34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 35, 34, 34, 35, +34, 35, 34, 35, 35, 34, 36, 34, 35, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 29, 34, 35, 29, +34, 29, 34, 29, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, +29, 34, 29, 29, 34, 34, 34, 29, 29, 34, 29, 34, 29, 29, 34, 34, 29, 34, 29, 34, +34, 29, 29, 34, 29, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, +34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 34, +34, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, 29, 34, +29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, +34, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 35, 29, 34, 35, 29, 34, 34, 34, 34, +34, 34, 29, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 35, 34, +36, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 35, 34, 35, 34, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +34, 35, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 34, +34, 34, 29, 34, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, +29, 29, 29, 34, 34, 29, 34, 29, 34, 34, 29, 29, 29, 34, 29, 29, 29, 34, 34, 29, +34, 34, 34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, 34, +34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 29, 34, 34, 29, 29, 29, 34, +34, 34, 29, 34, 34, 29, 29, 34, 34, 29, 29, 34, 29, 34, 34, 29, 34, 34, 34, 29, +34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, +29, 29, 34, 29, 34, 29, 35, 29, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 36, 34, 35, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 34, 29, +29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, +29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 29, 34, 29, 29, 34, 29, +34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, +34, 34, 34, 34, 34, 29, 29, 34, 34, 34, 34, 34, 29, 34, 34, 29, 29, 34, 29, 29, +29, 34, 34, 29, 34, 29, 34, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, +29, 34, 29, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 29, +34, 29, 29, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 34, 29, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 29, 29, 34, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, +34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 34, 29, 29, 34, 34, 34, 29, 35, 29, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, +34, 34, 35, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, +29, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, +29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 34, 34, 29, 34, +29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 35, 34, 34, 36, 34, 34, 35, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 29, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 29, 34, 29, 34, +29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, +29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, +34, 34, 29, 34, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 34, 34, 34, +34, 34, 29, 34, 29, 35, 29, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, +29, 34, 34, 34, 34, 29, 34, 34, 34, 29, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, +34, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 34, 29, 34, +29, 35, 29, 35, 29, 34, 29, 29, 29, 34, 34, 29, 29, 29, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 29, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 29, 34, 35, +34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, +29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, +29, 34, 34, 29, 34, 34, 34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 34, 34, +34, 29, 34, 29, 35, 34, 34, 29, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 29, +29, 35, 29, 29, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, +34, 29, 29, 29, 34, 29, 29, 29, 34, 34, 34, 34, 29, 34, 35, 29, 34, 35, 29, 34, +35, 29, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 29, 34, 34, 34, 34, +34, 35, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, +29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, +34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 35, +29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 35, +29, 34, 34, 34, 35, 29, 34, 34, 29, 35, 34, 29, 35, 34, 29, 34, 34, 29, 29, 35, +29, 34, 34, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, +29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 34, 29, +29, 29, 34, 34, 29, 29, 29, 34, 34, 34, 29, 35, 34, 29, 35, 34, 29, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 29, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +34, 34, 34, 34, 34, 35, 34, 34, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, +29, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, +29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, +29, 29, 29, 29, 29, 34, 29, 29, 35, 29, 29, 29, 34, 29, 29, 29, 34, 34, 34, 34, +34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, +34, 35, 29, 34, 34, 29, 34, 34, 29, 34, 34, 29, 35, 29, 34, 29, 35, 29, 29, 29, +29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, +29, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, +29, 34, 34, 29, 34, 29, 34, 29, 34, 35, 29, 34, 35, 29, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, +34, 34, 34, 35, 34, 35, 29, 35, 34, 34, 34, 34, 29, 34, 35, 34, 34, 34, 34, 34, +34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 29, +34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, +29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, +29, 29, 29, 34, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, +29, 35, 29, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 35, 29, 34, 34, 34, +34, 34, 34, 34, 35, 29, 35, 29, 29, 34, 34, 29, 29, 34, 34, 34, 34, 29, 29, 34, +29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, +34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 34, 29, 34, +34, 34, 34, 34, 34, 29, 34, 35, 29, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 35, 34, 34, 34, 35, 29, 34, +34, 29, 34, 34, 29, 34, 34, 34, 35, 34, 34, 29, 34, 35, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, +34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, +34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, +34, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, +29, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 29, 29, 34, 34, 34, 29, 34, +34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, +29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 35, 29, 34, 29, 34, 34, 34, 29, 34, 34, +34, 35, 29, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 34, 34, 29, 34, 34, +34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, +29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 34, 34, +29, 34, 29, 34, 29, 29, 29, 34, 29, 35, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, +34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 35, 29, 34, +34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 29, 29, 29, 35, 29, 29, 29, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, +29, 34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 35, 29, 34, 29, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, +34, 34, 35, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 34, 34, +35, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 29, 34, 34, 29, +34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, +29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, +29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, +34, 34, 34, 29, 29, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, 34, +34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, +34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, +34, 29, 34, 34, 29, 34, 34, 34, 34, 29, 35, 29, 35, 29, 34, 34, 34, 34, 34, 29, +35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, +29, 35, 29, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 35, 29, 34, 29, 34, 29, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, 29, 34, 34, 29, 29, 34, +29, 29, 34, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, +29, 34, 29, 34, 29, 29, 29, 29, 29, 34, 34, 34, 29, 34, 34, 29, 29, 29, 34, 34, +34, 34, 29, 29, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, +29, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, +34, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, 29, +29, 34, 29, 29, 34, 34, 29, 34, 29, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 29, 34, 34, 35, 34, 34, 35, 34, +34, 34, 34, 35, 34, 34, 34, 34, 34, 29, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, +34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, +29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, +29, 29, 34, 29, 34, 29, 29, 29, 35, 29, 29, 34, 34, 34, 29, 34, 29, 29, 34, 34, +34, 34, 29, 29, 34, 34, 29, 29, 34, 34, 34, 29, 35, 29, 34, 34, 29, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 29, 34, 29, 34, 34, +29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, +29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 34, 29, 34, 34, +29, 29, 34, 34, 34, 29, 35, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 35, 34, 34, +34, 34, 35, 34, 34, 34, 35, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, +34, 34, 29, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, +34, 34, 29, 29, 35, 29, 34, 34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, +29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, +29, 34, 34, 34, 29, 34, 34, 29, 29, 29, 29, 34, 29, 35, 29, 29, 29, 29, 34, 34, +29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 29, +34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 35, 29, 34, 34, 29, 34, 29, +29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, +29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 29, 34, 34, 34, 29, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, +34, 34, 34, 29, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, +29, 34, 29, 34, 34, 29, 34, 34, 35, 29, 34, 34, 34, 29, 34, 35, 29, 29, 35, 29, +29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, +34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, +34, 34, 29, 34, 34, 34, 34, 29, 35, 34, 29, 35, 34, 34, 34, 35, 29, 34, 34, 29, +34, 35, 29, 34, 34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, +29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 34, 29, 29, 29, 29, 34, 34, 29, 29, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, +29, 34, 29, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 29, 34, 29, 34, 34, +29, 35, 29, 29, 29, 29, 35, 29, 34, 34, 29, 29, 34, 34, 29, 35, 29, 34, 29, 29, +34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, +29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, +34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 34, 34, 29, 34, 34, +29, 34, 34, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 29, 34, 34, 34, 34, 29, 35, 29, 34, 34, 29, 34, 34, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 34, 29, 29, 34, 34, 34, 34, 29, 29, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 29, 34, 29, 34, +34, 34, 29, 34, 35, 29, 34, 35, 29, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, 34, +34, 29, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, +34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 29, +29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, +34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 34, 29, 34, 29, 34, 34, 29, +34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, 34, 29, 34, 34, 34, 34, +34, 34, 34, 34, 35, 29, 35, 29, 35, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, +34, 29, 34, 29, 29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 29, 34, 34, 34, 29, 34, 29, 34, 35, 29, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 29, 35, 34, +29, 35, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, +29, 34, 34, 29, 35, 29, 34, 29, 29, 29, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, +34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, +34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, +29, 29, 29, 34, 29, 34, 29, 35, 29, 34, 34, 34, 34, 34, 29, 34, 35, 29, 34, 34, +29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 29, 34, +34, 29, 29, 34, 29, 34, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, +29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, +34, 34, 34, 34, 29, 29, 34, 34, 34, 34, 29, 35, 34, 34, 29, 34, 34, 34, 34, 34, +34, 35, 29, 34, 34, 34, 35, 34, 29, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 34, 29, 34, 34, 29, 34, 34, +34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 29, 29, 35, +29, 35, 29, 34, 34, 34, 34, 29, 29, 29, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, +29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, +29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 34, 34, 34, 29, 35, 29, 34, 35, 29, 34, 34, 34, 34, 34, 34, 29, +35, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 34, +29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, +34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, +34, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 35, +29, 35, 29, 34, 35, 29, 34, 35, 34, 29, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, +29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 35, 29, 29, 34, 29, 34, 34, +29, 29, 34, 34, 34, 34, 29, 34, 29, 29, 34, 34, 29, 34, 34, 29, 34, 34, 29, 29, +34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, +29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, +29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 34, 29, +29, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, +29, 34, 29, 34, 29, 34, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, +34, 34, 34, 34, 29, 34, 29, 35, 29, 34, 34, 34, 34, 29, 34, 29, 29, 34, 29, 29, +34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 34, 29, 29, 34, 29, +34, 34, 34, 34, 34, 29, 34, 29, 35, 29, 34, 35, 34, 29, 35, 29, 34, 34, 34, 34, +34, 34, 35, 29, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 34, 34, +29, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, +29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 29, 29, 34, 29, 34, 34, 29, 29, +29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, +29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, +29, 29, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, +29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 35, 29, 34, 29, 34, 34, 34, +35, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 29, 34, 29, 34, 29, 34, 34, +34, 29, 35, 29, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 34, 29, 34, 29, 34, 29, 34, +29, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 35, 29, 35, 29, 34, 34, 34, 29, 34, +34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +35, 29, 34, 29, 35, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, +29, 34, 29, 29, 34, 29, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, +29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, +29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, +29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, +29, 35, 29, 34, 29, 35, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 35, +29, 34, 34, 29, 34, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 34, 34, 34, 29, 35, +34, 29, 35, 29, 34, 29, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, +34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, +29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, +29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, +34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, +29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, +29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 34, 29, 34, +29, 35, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 34, 29, 29, 35, 29, 34, 34, 34, 29, 35, 34, 29, 34, 34, 34, +29, 34, 29, 35, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 35, 29, 34, 34, 29, 29, +34, 29, 34, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, +29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, +29, 29, 29, 34, 29, 34, 29, 29, 35, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, +34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, +34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, +34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, +29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, +34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, +29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, 34, +29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 34, 29, 34, 34, 34, 29, 34, 29, 29, 35, 29, 34, 29, 34, 34, 34, 29, +34, 34, 29, 35, 29, 34, 34, 34, 34, 29, 34, 29, 35, 29, 35, 29, 34, 29, 29, 29, +34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, +29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, +29, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, +34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 34, 35, 34, +34, 34, 29, 35, 29, 29, 34, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, 29, 29, +34, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, +29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, +29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, +29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 34, 29, 34, 34, 29, 34, 29, +34, 34, 34, 29, 29, 29, 34, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, 35, 29, 34, 34, 34, 34, +34, 34, 29, 34, 34, 34, 29, 35, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, +29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 34, 29, 29, +29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, +29, 35, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 35, 34, 34, +34, 34, 34, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, +29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, +29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, +29, 34, 29, 34, 29, 34, 34, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 29, 29, 34, +34, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 34, 34, 29, +34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 35, 29, 34, 34, 34, 29, 34, 35, 29, +34, 34, 34, 29, 35, 29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, +29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, +29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, 34, 29, 35, 29, +34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 35, 34, 29, 34, 34, 34, 34, 34, 34, +34, 35, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, +34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, +34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 34, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, 29, 29, 29, 34, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, +34, 29, 34, 29, 29, 34, 34, 34, 29, 35, 29, 34, 35, 29, 34, 29, 35, 29, 29, 34, +29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, +29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 34, 29, 34, 29, 34, +29, 34, 29, 34, 34, 29, 34, 34, 34, 35, 29, 34, 29, 34, 29, 34, 34, 34, 34, 34, +29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 29, 34, 29, 34, 29, 29, 34, 29, +34, 34, 29, 35, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, +34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, +29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, +29, 29, 29, 34, 34, 29, 29, 29, 34, 29, 34, 34, 34, 29, 29, 29, 34, 29, 34, 29, +34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 34, 29, 29, 34, 34, +34, 29, 34, 29, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 34, 29, 34, 34, 29, 34, +29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, +34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, +29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 34, 29, 29, 34, 34, 29, +29, 34, 34, 29, 29, 29, 35, 29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, 29, +34, 34, 34, 29, 34, 34, 34, 29, 34, 29, 35, 29, 34, 34, 34, 34, 34, 29, 29, 29, +34, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, +29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, +34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, +29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 34, 29, +34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, +34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 29, 34, 29, 29, 29, 29, 34, +29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, +34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, +34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 35, +29, 34, 34, 35, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 34, 29, 29, 29, 34, +29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, +34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, +34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 35, 29, 34, 29, 34, 34, 29, 29, +34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, +34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, +34, 34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 29, +34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, +29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 29, 29, 29, 34, 34, 29, 29, 34, 34, 29, +34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 35, 29, 34, +29, 35, 29, 35, 29, 34, 29, 34, 34, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, +34, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, +34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, +29, 35, 29, 29, 29, 35, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 35, 29, 29, +35, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, +29, 34, 29, 29, 34, 34, 29, 34, 29, 29, 34, 34, 34, 29, 35, 34, 29, 34, 34, 29, +34, 34, 34, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, +29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, +29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, +29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 35, 29, 34, 34, 34, 29, 34, 29, +34, 29, 35, 29, 29, 29, 34, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, +34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, +28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, +29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, +34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 35, 29, 35, 29, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 34, +29, 34, 29, 34, 34, 34, 34, 29, 34, 34, 29, 29, 34, 34, 29, 35, 29, 29, 29, 29, +34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, +29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 29, +29, 29, 34, 29, 34, 29, 34, 34, 29, 29, 35, 29, 29, 29, 29, 34, 29, 35, 29, 34, +34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 28, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, +29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, +34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 34, 34, 29, 34, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, +29, 34, 29, 34, 29, 34, 34, 34, 34, 29, 34, 29, 29, 34, 34, 34, 29, 29, 34, 29, +29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, +29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 34, 29, 29, 34, 29, +34, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 34, 34, +29, 35, 29, 34, 34, 34, 29, 34, 34, 29, 35, 29, 34, 29, 29, 29, 34, 29, 29, 34, +29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 28, 29, 29, 29, +28, 29, 29, 29, 29, 29, 29, 28, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, +29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, +34, 29, 29, 34, 29, 34, 34, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 34, 34, 29, 34, 29, 29, 34, 34, +29, 29, 34, 29, 29, 29, 29, 34, 34, 29, 29, 29, 34, 34, 29, 34, 29, 34, 29, 29, +29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, +29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 29, 34, 29, 29, 34, 29, 29, 34, 34, +29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 34, 29, 34, 29, +34, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, +34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 28, +29, 28, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 29, +34, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, 29, 34, 34, 29, +29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, +29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 34, 34, 29, +34, 34, 29, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, +29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, +29, 29, 34, 34, 29, 34, 29, 35, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, +34, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 34, +29, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, +29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 28, 29, 29, 28, 34, 29, 29, 29, 28, +29, 29, 29, 28, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, +29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 34, 29, 29, 34, 34, 29, 29, 29, +34, 29, 34, 29, 35, 29, 29, 29, 29, 29, 29, 34, 34, 29, 29, 29, 34, 29, 34, 29, +29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, +29, 29, 29, 29, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 34, +29, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, +29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 34, 29, 29, +34, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, +34, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, 29, 34, +29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 28, 29, 29, +28, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, +29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, 29, +29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, 34, 29, 29, 29, 29, 29, 34, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, +34, 29, 35, 29, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 29, 29, 34, 29, 29, +29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 34, 29, 34, 29, 34, +34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, +34, 29, 34, 29, 34, 29, 35, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, +29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 28, 29, 28, 29, 34, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, +29, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, 29, 34, 29, 34, 34, 34, 29, 34, +29, 29, 29, 34, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, +34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, +29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, +29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, +29, 29, 29, 29, 29, 29, 29, 34, 29, 35, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, +29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, +29, 29, 29, 29, 34, 29, 34, 34, 29, 29, 35, 29, 34, 29, 34, 34, 29, 34, 29, 29, +34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 28, 29, 29, 29, 29, 28, 29, 29, +29, 29, 29, 28, 29, 29, 29, 28, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, +34, 29, 29, 29, 34, 29, 29, 34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, +34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, +34, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 34, 34, 29, 29, 34, 34, 34, +29, 34, 34, 34, 29, 29, 34, 29, 29, 29, 35, 29, 29, 29, 34, 29, 29, 29, 34, 29, +29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 35, 29, 29, 29, 34, 34, 29, 34, 29, +34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, +34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 34, 29, 28, 29, 29, 29, 29, +29, 28, 29, 29, 29, 29, 29, 28, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, +29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 34, 29, 34, +29, 34, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, +34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, +34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 34, 29, 29, 29, 34, 29, 29, 29, +34, 34, 34, 34, 34, 34, 29, 35, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, +34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +29, 34, 34, 29, 29, 34, 29, 29, 34, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, +29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 35, 29, 29, +29, 29, 34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 28, 29, 28, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 28, +29, 29, 28, 34, 29, 28, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, +29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 29, 34, +34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, +34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 29, 34, 29, +34, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, +34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, +29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, +29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 34, 28, 29, 29, 29, 29, 29, 29, 28, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, +29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 34, 29, 29, 29, 29, 29, +34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, +29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, +34, 29, 34, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 34, 34, 29, 34, 34, +34, 34, 34, 29, 29, 29, 29, 29, 34, 29, 35, 29, 34, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, +29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 34, +29, 35, 29, 34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, +29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 34, +29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, +29, 34, 29, 29, 34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, +29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, +29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 35, 29, 34, 29, 34, 34, 34, 29, 29, 29, 34, 29, +34, 34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 34, 34, 34, 29, 29, 34, 29, 34, 29, +29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, +29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, +29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 28, 29, 29, 29, 29, 28, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, +29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, +29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, +29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 34, 29, 29, +34, 34, 29, 34, 29, 35, 29, 35, 29, 34, 34, 34, 34, 34, 29, 29, 34, 29, 29, 34, +34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, +34, 29, 34, 34, 29, 35, 29, 29, 29, 29, 35, 29, 34, 34, 29, 34, 34, 29, 34, 34, +29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, +29, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, +34, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 34, 29, +29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, +29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, +29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, +34, 29, 34, 29, 35, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 29, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, +34, 29, 34, 34, 34, 34, 29, 35, 29, 29, 34, 34, 34, 29, 34, 34, 29, 34, 34, 29, +34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, +34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, +34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, +29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, +29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, +29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 34, 29, 35, 29, 34, 34, 34, 29, 35, +29, 34, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, +29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, +29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, +34, 34, 34, 29, 35, 34, 34, 34, 29, 35, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, +34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 34, 29, 34, 29, 34, 29, 29, +34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, +29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, +29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, +29, 29, 34, 29, 29, 34, 29, 29, 34, 34, 29, 35, 29, 35, 29, 34, 34, 34, 34, 29, +34, 34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 35, 29, 29, 29, 34, 29, 34, 29, 34, +29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, +29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, 29, 29, 29, 29, 29, 34, +29, 34, 29, 34, 34, 34, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, +29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, +29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, +29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, +34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, +34, 29, 34, 34, 29, 29, 35, 29, 34, 29, 35, 34, 29, 34, 29, 35, 29, 34, 29, 29, +34, 34, 34, 29, 29, 34, 29, 29, 34, 34, 29, 34, 34, 29, 29, 29, 29, 34, 29, 29, +29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, +34, 29, 29, 34, 34, 29, 29, 29, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 34, +29, 29, 29, 35, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, +29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 28, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, +29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, +29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, +29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, +34, 34, 29, 35, 29, 35, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, +34, 29, 34, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, +29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, +29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 29, 29, 34, 29, +35, 29, 35, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 35, 29, 34, 29, +35, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, +29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, +29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, +34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, +34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 35, 29, 35, 29, 34, +29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, +29, 34, 34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, +29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 29, +34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 35, 29, 35, 29, 34, 29, 34, +34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, +29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, +29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, +34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, +29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, +29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, +34, 34, 34, 29, 34, 29, 34, 29, 35, 29, 29, 34, 29, 29, 29, 29, 34, 34, 29, 29, +29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, +34, 29, 34, 34, 34, 29, 35, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 35, +29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 29, 29, 34, 29, +29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, +29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, +34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, +29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 34, 34, 29, 35, 29, 34, 34, 34, 29, 35, 29, 34, 29, 34, 29, 34, +34, 34, 29, 35, 29, 29, 34, 29, 34, 34, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, +29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 35, 34, 29, 35, 34, 34, +34, 34, 29, 34, 34, 34, 34, 29, 34, 29, 35, 29, 34, 29, 34, 29, 29, 29, 29, 29, +35, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, +34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 34, +29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 29, 35, 29, 35, 29, 34, 34, 34, 34, 34, 34, 34, 29, 35, 29, 29, +34, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, +34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, +29, 29, 34, 34, 29, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, +34, 34, 34, 29, 34, 34, 29, 35, 29, 34, 29, 29, 34, 34, 29, 34, 29, 34, 34, 29, +34, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, +29, 34, 34, 29, 29, 34, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, +29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, +29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, +29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, +34, 29, 29, 34, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 34, 29, 34, +34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, +29, 34, 29, 34, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 34, 29, 29, 29, 29, 34, +29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 29, 29, +34, 29, 35, 29, 34, 29, 34, 34, 29, 35, 34, 34, 29, 35, 29, 34, 34, 34, 34, 34, +34, 34, 34, 29, 29, 34, 34, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 34, 29, 34, +34, 29, 35, 29, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, 34, 34, 29, 34, 29, 34, +34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, +29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, +29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, +29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, +29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 34, 34, +29, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 34, +34, 34, 34, 34, 34, 34, 29, 34, 29, 35, 29, 34, 34, 29, 34, 29, 29, 34, 29, 34, +29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, +34, 29, 34, 29, 29, 34, 34, 29, 29, 34, 29, 29, 29, 34, 34, 34, 29, 35, 29, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 29, 34, 34, +34, 29, 29, 34, 34, 29, 34, 29, 34, 34, 34, 34, 29, 34, 34, 29, 34, 34, 29, 34, +29, 29, 34, 29, 29, 29, 34, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 29, 34, 29, +34, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, +29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, +29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, +29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, +29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, +34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 34, 29, 29, +34, 29, 29, 29, 29, 34, 29, 29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, +29, 34, 34, 34, 29, 34, 29, 35, 29, 35, 29, 35, 29, 34, 29, 34, 29, 29, 34, 34, +29, 34, 34, 29, 35, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, +34, 29, 29, 34, 34, 29, 34, 34, 29, 34, 29, 29, 35, 29, 34, 35, 29, 34, 34, 29, +35, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 35, 29, 34, 29, 34, 34, 29, +29, 34, 29, 35, 29, 29, 29, 29, 34, 29, 35, 29, 34, 29, 34, 34, 29, 29, 34, 29, +34, 34, 29, 29, 29, 34, 29, 34, 34, 29, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, +29, 34, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, +29, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, +29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, +29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 35, 29, 34, 34, +34, 29, 35, 29, 34, 29, 29, 29, 35, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, +29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 34, 34, 34, 34, +29, 34, 34, 29, 34, 34, 29, 35, 29, 35, 29, 29, 34, 34, 34, 34, 29, 35, 34, 29, +35, 34, 34, 35, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 29, +34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 34, 29, 29, 34, 34, +34, 34, 29, 34, 29, 35, 29, 29, 29, 29, 34, 29, 35, 29, 29, 34, 29, 29, 34, 29, +29, 34, 29, 34, 29, 35, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, +34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, +29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, +29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 34, +34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 34, 29, 29, 35, 29, 34, 34, 34, 29, 34, +29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 34, 29, 34, 29, 34, 34, 29, +34, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, +34, 34, 34, 29, 34, 29, 35, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, +34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 29, 34, 29, +34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 34, 29, 29, 29, 35, 29, +34, 29, 34, 34, 34, 34, 29, 34, 29, 35, 29, 34, 29, 34, 29, 35, 29, 34, 29, 29, +34, 29, 34, 34, 29, 29, 34, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, +29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, +34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, +34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 29, +29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, +34, 29, 29, 34, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 34, 34, +29, 34, 29, 34, 34, 34, 29, 35, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 29, 34, +34, 34, 34, 29, 34, 34, 29, 34, 29, 29, 29, 34, 34, 29, 29, 34, 29, 34, 29, 29, +35, 29, 29, 34, 29, 29, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 29, 34, 34, +29, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 35, 34, 35, 29, 34, 34, 34, 34, +34, 34, 29, 34, 34, 34, 34, 29, 35, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, +34, 34, 34, 29, 34, 29, 35, 29, 34, 29, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, +29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 29, 34, 34, 34, 29, 29, 34, +29, 34, 29, 29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, +29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, +34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, +34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 35, 29, 34, +29, 35, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, +34, 29, 34, 29, 29, 35, 29, 34, 29, 34, 34, 29, 34, 34, 34, 29, 29, 29, 29, 35, +29, 29, 34, 34, 29, 34, 34, 29, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 29, 34, 34, 29, 35, 29, 34, +34, 34, 34, 34, 29, 35, 29, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, +34, 34, 29, 34, 35, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 34, +34, 34, 34, 34, 34, 29, 35, 34, 29, 34, 34, 34, 29, 29, 35, 29, 34, 29, 34, 29, +34, 29, 29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, +34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, +29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, +29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 34, 34, 29, 29, 34, 29, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, +34, 29, 34, 29, 34, 34, 29, 35, 29, 34, 29, 34, 34, 34, 34, 29, 29, 34, 34, 29, +35, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, +34, 34, 29, 35, 29, 35, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 35, 34, 34, 29, 35, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, +34, 34, 34, 34, 29, 35, 34, 34, 29, 34, 29, 34, 34, 34, 34, 34, 29, 29, 35, 34, +29, 35, 29, 35, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, +34, 34, 29, 34, 34, 34, 34, 29, 34, 34, 29, 29, 34, 34, 34, 29, 29, 34, 34, 29, +29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 29, 29, 29, 29, 29, +34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, +29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, +34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 29, 29, 29, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, +34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, +29, 35, 29, 29, 29, 34, 34, 29, 29, 34, 34, 34, 34, 29, 34, 29, 29, 34, 34, 29, +34, 34, 29, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, +34, 29, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 35, +34, 34, 34, 34, 35, 34, 29, 34, 35, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, +34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 35, 29, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +29, 34, 29, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, 34, 29, 34, 34, 29, 29, 29, +35, 29, 34, 34, 34, 29, 34, 29, 29, 34, 29, 34, 34, 34, 29, 29, 29, 34, 29, 29, +29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, +29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 29, +29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 34, 29, 34, 34, +34, 29, 34, 34, 34, 29, 29, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, +34, 34, 29, 34, 34, 29, 35, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 29, +34, 34, 34, 34, 34, 29, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, +34, 34, 35, 29, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 29, 29, 35, 29, 34, 35, 29, 34, 34, 34, 29, 35, +29, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 29, 35, 29, 35, 34, 34, 34, +29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 29, 29, 29, +29, 34, 29, 34, 34, 29, 35, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, +29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, 34, +29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 34, +29, 34, 34, 29, 29, 34, 34, 29, 29, 29, 35, 29, 34, 29, 29, 34, 34, 29, 29, 34, +29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 29, 34, 29, 29, +29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 34, +34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 29, 34, 29, +34, 34, 34, 29, 35, 29, 35, 29, 34, 29, 29, 29, 29, 34, 34, 34, 34, 29, 34, 29, +34, 29, 29, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, +29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, +29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, +34, 29, 29, 29, 34, 34, 29, 29, 29, 34, 34, 29, 29, 29, 34, 34, 29, 29, 34, 34, +29, 34, 29, 34, 29, 29, 34, 34, 29, 29, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 29, 29, 34, 34, 29, 29, 29, 34, 34, 34, 34, 29, 34, 35, 34, +34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 29, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 29, 34, 35, 29, 34, 34, +29, 29, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 35, 34, 34, 34, 34, +35, 34, 34, 34, 34, 34, 34, 29, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, +29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 29, 34, 29, 29, 34, 34, 29, 34, 34, +29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, +34, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, +29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, +29, 29, 29, 29, 34, 34, 29, 34, 34, 29, 29, 34, 29, 34, 34, 29, 29, 29, 35, 29, +34, 29, 34, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 29, 34, 34, 29, 29, +34, 34, 29, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 34, 29, 34, +29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 35, 29, 34, 29, 34, 34, 34, 34, +34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, +34, 34, 34, 35, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +35, 29, 29, 34, 34, 29, 35, 29, 34, 34, 29, 34, 29, 29, 34, 34, 29, 29, 29, 29, +34, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, +34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, +29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 35, 29, 29, 29, 34, 29, 34, 29, +34, 29, 29, 29, 34, 34, 29, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, +34, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 29, 29, 34, 34, 29, 34, 29, +34, 29, 29, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, +34, 29, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, +34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 35, 29, 34, 34, 29, 35, 34, 29, +34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 29, 29, 34, 34, 34, 34, 29, 29, 34, 29, +29, 29, 35, 29, 34, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 29, +34, 29, 34, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, +29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 34, 34, 34, 29, 29, +34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, +29, 29, 34, 34, 29, 29, 34, 34, 29, 34, 29, 35, 29, 29, 34, 29, 29, 34, 29, 29, +34, 34, 29, 29, 34, 34, 29, 29, 34, 34, 34, 29, 29, 34, 29, 34, 29, 34, 34, 34, +29, 34, 34, 34, 29, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +29, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, +29, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 29, 34, 34, 35, 29, 34, 35, 29, 35, 34, 29, 34, 34, 34, 34, 29, 35, +29, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, 34, 29, 35, +29, 34, 29, 34, 34, 34, 29, 35, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, +34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, +29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 34, 29, 34, 29, 34, +29, 29, 29, 34, 29, 29, 34, 34, 29, 29, 34, 34, 34, 29, 34, 29, 35, 29, 34, 29, +34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, +29, 29, 34, 34, 29, 29, 34, 29, 34, 29, 35, 29, 29, 34, 29, 29, 34, 29, 34, 34, +34, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 35, 34, +34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 34, 35, 29, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 29, 34, 34, 34, +34, 34, 29, 35, 29, 34, 34, 29, 35, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, +34, 34, 34, 34, 34, 29, 35, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, +29, 29, 29, 29, 34, 34, 29, 34, 34, 34, 34, 29, 29, 34, 34, 29, 29, 34, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, +34, 29, 29, 29, 29, 29, 29, 29, 34, 34, 29, 29, 35, 29, 34, 34, 34, 34, 29, 29, +34, 34, 29, 34, 29, 35, 29, 29, 29, 34, 29, 29, 29, 29, 34, 34, 29, 34, 29, 34, +34, 29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 34, 34, 29, 29, 29, 34, 34, 29, 34, +29, 34, 29, 35, 29, 29, 29, 29, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +34, 35, 29, 34, 34, 35, 29, 34, 29, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, 35, +34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 35, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, +29, 35, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 34, 29, +34, 34, 29, 34, 29, 29, 34, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, +34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, +29, 34, 29, 34, 29, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, +29, 29, 34, 34, 34, 29, 34, 34, 34, 29, 29, 29, 34, 29, 29, 34, 29, 29, 34, 34, +29, 29, 34, 34, 29, 34, 29, 29, 29, 34, 34, 34, 29, 29, 34, 29, 34, 34, 29, 29, +34, 34, 34, 29, 34, 29, 34, 29, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, +34, 34, 34, 34, 34, 34, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 34, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, +35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 34, 29, 34, 34, +34, 34, 34, 34, 29, 34, 29, 34, 34, 29, 35, 29, 29, 34, 34, 34, 29, 29, 34, 34, +34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, +29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, +34, 29, 34, 29, 34, 34, 29, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 29, 29, +29, 34, 29, 29, 29, 35, 29, 34, 29, 34, 29, 34, 34, 34, 29, 29, 29, 34, 29, 29, +34, 29, 34, 34, 34, 29, 29, 29, 34, 34, 34, 29, 29, 29, 34, 34, 29, 29, 29, 34, +34, 34, 34, 34, 29, 34, 29, 34, 34, 34, 34, 35, 29, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 34, 34, 29, 34, +34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 29, 34, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, +34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 35, +34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 29, 34, 34, 29, 34, +29, 34, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 29, 34, 34, 29, 34, +29, 29, 29, 34, 34, 34, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, +29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 34, 34, 29, 34, 34, 29, 29, 29, 34, +34, 29, 34, 34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 34, 29, 34, 34, 29, +34, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 29, 29, 34, 34, 29, 29, 29, +29, 34, 34, 29, 34, 29, 29, 29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 29, 34, 34, +34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 29, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 29, 34, +34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, +34, 35, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 29, 34, +34, 34, 34, 34, 34, 29, 35, 29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, +29, 29, 29, 34, 29, 35, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, +34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 34, 34, 34, 29, 34, 29, 35, 29, 34, +34, 34, 29, 34, 34, 34, 34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 34, 34, 29, +34, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 34, 29, 35, 29, 34, 34, +29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 35, 29, 29, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 29, 35, 34, 34, 29, 35, 34, 34, 34, +34, 35, 34, 34, 29, 34, 35, 29, 35, 34, 29, 34, 34, 34, 35, 29, 35, 34, 34, 34, +34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 35, +34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +34, 35, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, +34, 35, 29, 34, 34, 34, 34, 34, 29, 34, 34, 29, 29, 34, 34, 34, 34, 34, 34, 29, +34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, +29, 29, 34, 34, 29, 34, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 35, 29, +29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 29, +29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 35, 29, 29, 29, 34, 34, 29, 34, 34, +34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 29, 34, 29, 34, 34, 34, +34, 29, 35, 34, 29, 34, 34, 34, 34, 29, 35, 34, 29, 34, 34, 34, 29, 34, 34, 34, +34, 35, 29, 34, 34, 29, 35, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 35, 34, 34, +29, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, +34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 35, 34, 34, 34, 29, 34, 34, 34, +34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, 34, 34, +29, 34, 34, 34, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 29, +34, 29, 29, 34, 34, 34, 34, 29, 34, 34, 29, 29, 34, 34, 29, 34, 34, 29, 29, 35, +29, 29, 34, 29, 29, 29, 35, 29, 34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 29, +29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, +34, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, +35, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 34, +29, 35, 29, 34, 34, 34, 34, 34, 29, 35, 34, 34, 34, 29, 34, 35, 34, 34, 34, 35, +34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 29, +34, 29, 29, 34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 34, +29, 29, 29, 35, 29, 29, 29, 35, 29, 34, 29, 34, 34, 29, 35, 29, 34, 34, 29, 35, +29, 35, 29, 29, 29, 35, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, +29, 34, 29, 34, 29, 29, 29, 29, 35, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 34, +34, 29, 34, 34, 34, 34, 29, 29, 34, 29, 34, 34, 34, 29, 34, 35, 34, 29, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 29, 35, 29, 34, 29, 34, +34, 34, 34, 34, 34, 34, 29, 34, 34, 35, 29, 34, 34, 35, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, +34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 29, 35, 29, 34, +35, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 29, 35, 29, +34, 29, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, 29, +34, 34, 34, 29, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, +34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 34, 29, 29, 29, 35, 29, 34, 34, 29, 29, +34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 29, 35, 29, 34, +29, 34, 34, 34, 34, 34, 34, 34, 29, 35, 29, 34, 29, 35, 34, 34, 34, 34, 34, 29, +35, 34, 34, 34, 34, 34, 34, 34, 29, 35, 29, 34, 29, 34, 34, 34, 29, 35, 29, 34, +34, 34, 34, 34, 34, 29, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, +34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 34, 35, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 29, 34, 34, 29, 35, 29, +34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 35, 29, 34, 34, 34, 29, 35, +29, 29, 29, 29, 35, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, 29, 34, 29, 29, 34, +34, 29, 34, 29, 34, 34, 34, 29, 29, 34, 34, 34, 34, 29, 34, 34, 29, 34, 34, 34, +29, 29, 34, 29, 34, 34, 29, 34, 29, 35, 29, 29, 29, 29, 34, 29, 34, 29, 29, 34, +34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 29, 34, +29, 29, 34, 29, 34, 29, 34, 34, 34, 29, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, +34, 29, 34, 34, 34, 29, 35, 29, 34, 34, 34, 29, 34, 29, 35, 34, 29, 34, 34, 34, +34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 35, 35, 34, 35, 34, +34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 29, 35, 34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 34, 34, +34, 34, 29, 35, 34, 34, 34, 35, 34, 29, 34, 34, 34, 29, 35, 29, 34, 34, 34, 29, +29, 34, 34, 34, 34, 29, 35, 29, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 34, +29, 29, 29, 34, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 35, 29, 29, 29, +34, 29, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 34, 34, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 29, 35, 34, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, 29, +34, 29, 34, 29, 35, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, +29, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 35, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, +34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 29, 34, 34, 34, 34, 34, +34, 35, 34, 34, 29, 34, 34, 34, 34, 29, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, +34, 34, 34, 29, 34, 35, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 29, +34, 29, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 34, 34, 29, +29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, +34, 29, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, +29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 29, 34, +34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, +29, 34, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 29, 35, 34, 35, 34, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 35, 34, 35, 34, 34, 34, 35, 34, 35, 35, 34, 35, 34, 35, 34, +35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 29, 34, 34, 34, 29, 34, 34, +34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 35, +29, 34, 34, 34, 29, 34, 34, 34, 34, 29, 35, 29, 29, 34, 29, 35, 29, 34, 29, 34, +29, 34, 34, 29, 29, 34, 34, 29, 29, 29, 34, 34, 29, 29, 29, 34, 34, 29, 29, 29, +34, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 34, 34, 29, 29, 34, 34, 29, +34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, +34, 34, 34, 35, 29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 29, +34, 34, 34, 29, 34, 29, 29, 29, 34, 29, 34, 34, 29, 34, 29, 35, 29, 34, 29, 34, +34, 29, 35, 34, 35, 29, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 34, 35, 34, 35, 34, 35, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 35, 34, +34, 34, 34, 34, 35, 34, 34, 35, 34, 35, 35, 34, 34, 36, 34, 34, 35, 34, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, +29, 34, 34, 34, 34, 29, 35, 29, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 29, 35, 29, 35, 29, 34, 29, 29, 34, 29, 34, 29, 34, 34, 29, 34, +29, 34, 29, 34, 34, 34, 29, 29, 34, 34, 29, 29, 34, 29, 34, 34, 34, 29, 34, 34, +29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, 34, +34, 34, 34, 34, 34, 34, 29, 29, 34, 29, 34, 29, 34, 34, 34, 34, 34, 34, 34, 29, +34, 34, 34, 29, 34, 29, 35, 29, 34, 34, 34, 29, 35, 29, 34, 34, 34, 29, 34, 34, +34, 34, 34, 34, 29, 34, 29, 34, 34, 29, 29, 29, 35, 29, 34, 29, 35, 29, 34, 29, +34, 29, 35, 29, 34, 34, 35, 34, 35, 29, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 34, 34, 34, 36, 34, 34, 34, 34, 35, 34, 34, 34, 34, 36, 34, 34, 35, +34, 35, 35, 34, 34, 36, 34, 36, 34, 35, 34, 35, 35, 34, 34, 34, 35, 34, 34, 35, +34, 35, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 29, 34, 34, +35, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, 34, 34, 29, 29, 34, 29, 34, 29, 29, +29, 29, 34, 34, 29, 29, 34, 34, 29, 29, 34, 29, 29, 35, 29, 34, 29, 34, 29, 29, +29, 34, 34, 29, 34, 34, 29, 34, 34, 29, 29, 35, 29, 29, 34, 29, 34, 29, 34, 29, +34, 29, 35, 29, 34, 34, 29, 35, 29, 29, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, +34, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 29, 34, 29, 29, +34, 34, 29, 34, 34, 34, 34, 34, 29, 29, 34, 34, 29, 35, 29, 34, 34, 34, 29, 35, +29, 34, 29, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +36, 34, 34, 34, 34, 35, 35, 34, 35, 34, 35, 34, 34, 35, 34, 35, 34, 34, 34, 35, +35, 34, 34, 34, 35, 34, 35, 34, 35, 35, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, +34, 36, 34, 34, 35, 34, 35, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 29, 34, 34, 34, +34, 34, 34, 29, 34, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, +29, 34, 29, 29, 34, 34, 29, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 29, +34, 29, 34, 29, 34, 34, 34, 29, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 29, +34, 34, 34, 29, 34, 35, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 34, 29, +29, 34, 29, 34, 35, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 29, +29, 29, 34, 29, 34, 34, 29, 35, 29, 34, 29, 35, 29, 35, 29, 34, 34, 34, 34, 34, +34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, +35, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 36, 34, 34, 34, 34, 34, 35, +35, 34, 34, 34, 35, 34, 34, 35, 34, 35, 34, 34, 35, 35, 35, 34, 34, 36, 34, 35, +35, 34, 35, 35, 34, 34, 34, 36, 34, 34, 36, 34, 34, 35, 35, 35, 34, 34, 34, 36, +34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, +34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, +29, 34, 34, 34, 34, 34, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, +29, 29, 29, 34, 34, 29, 29, 34, 29, 34, 34, 29, 29, 29, 34, 34, 29, 29, 34, 29, +29, 29, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 35, 29, 35, 29, 29, 34, 34, +34, 29, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 29, 29, +29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 34, 34, 34, +29, 34, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 36, 34, 35, 34, 35, 34, 36, 34, 35, +34, 35, 35, 34, 35, 35, 34, 34, 35, 35, 34, 36, 34, 34, 34, 34, 35, 34, 35, 34, +36, 34, 35, 34, 35, 34, 34, 34, 36, 34, 34, 34, 36, 34, 35, 34, 34, 35, 34, 36, +34, 34, 34, 34, 34, 35, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 29, 35, 29, 34, 29, 34, 34, 29, +29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 34, 34, +29, 34, 29, 34, 29, 29, 29, 34, 29, 35, 29, 34, 29, 35, 29, 34, 29, 35, 29, 29, +34, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 35, 34, 34, 34, +34, 29, 35, 34, 34, 34, 34, 29, 34, 29, 29, 34, 29, 34, 34, 34, 34, 29, 35, 29, +34, 34, 34, 29, 34, 34, 34, 29, 34, 34, 29, 29, 34, 29, 29, 34, 34, 29, 34, 29, +35, 29, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, +34, 35, 35, 34, 35, 35, 35, 34, 34, 34, 36, 34, 34, 34, 35, 35, 34, 34, 35, 34, +35, 34, 35, 35, 35, 34, 34, 34, 35, 35, 35, 34, 35, 35, 35, 34, 34, 35, 35, 34, +34, 36, 34, 34, 34, 35, 35, 35, 34, 35, 35, 35, 34, 35, 34, 34, 34, 34, 36, 34, +34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 29, 35, 29, 34, 29, 34, +34, 29, 35, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 34, +29, 34, 29, 29, 34, 29, 29, 29, 35, 29, 29, 29, 35, 29, 34, 34, 29, 34, 29, 34, +29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 34, 29, 35, 34, 29, 34, +29, 34, 29, 34, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 34, +34, 29, 34, 34, 34, 29, 34, 34, 34, 34, 29, 34, 29, 35, 29, 34, 29, 34, 29, 35, +29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 36, 34, 34, 34, 35, +34, 34, 34, 36, 34, 35, 34, 35, 34, 36, 34, 35, 34, 35, 34, 36, 34, 36, 34, 35, +34, 36, 34, 36, 34, 35, 35, 35, 35, 34, 34, 35, 36, 34, 35, 35, 35, 34, 35, 34, +36, 34, 35, 34, 35, 34, 35, 34, 36, 34, 34, 36, 34, 34, 34, 35, 34, 35, 34, 36, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, +34, 34, 34, 34, 34, 29, 34, 35, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, +34, 29, 34, 29, 29, 34, 29, 29, 34, 29, 34, 34, 29, 29, 34, 29, 34, 29, 29, 34, +29, 34, 34, 34, 29, 34, 34, 34, 29, 29, 34, 29, 34, 29, 35, 29, 35, 34, 29, 34, +29, 34, 29, 34, 29, 34, 34, 34, 34, 35, 29, 35, 29, 34, 34, 34, 34, 34, 34, 34, +29, 34, 29, 35, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, +34, 29, 34, 29, 29, 34, 34, 29, 34, 29, 34, 29, 35, 29, 34, 29, 29, 34, 34, 34, +34, 29, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 35, 35, 34, 35, 35, 35, 34, +36, 34, 35, 35, 35, 34, 35, 34, 36, 34, 35, 34, 35, 34, 35, 35, 35, 34, 35, 34, +35, 34, 35, 34, 34, 36, 35, 34, 34, 35, 34, 35, 34, 34, 35, 35, 34, 35, 35, 35, +34, 35, 35, 34, 34, 35, 34, 34, 36, 34, 34, 35, 35, 34, 34, 34, 34, 34, 34, 34, +35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, +34, 34, 34, 29, 34, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 29, 34, +29, 29, 34, 29, 29, 29, 29, 34, 34, 34, 34, 29, 34, 29, 34, 29, 35, 29, 29, 29, +29, 29, 29, 29, 29, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, 34, 29, 35, 29, 34, 29, +34, 34, 34, 29, 34, 34, 29, 34, 34, 29, 34, 29, 35, 29, 34, 29, 29, 34, 29, 34, +34, 29, 34, 34, 29, 34, 34, 29, 29, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 34, +29, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, +34, 34, 35, 34, 35, 34, 34, 35, 34, 34, 34, 35, 35, 35, 34, 35, 34, 35, 35, 35, +35, 35, 35, 34, 34, 35, 35, 35, 35, 35, 34, 35, 34, 36, 34, 35, 34, 36, 34, 35, +35, 34, 35, 36, 35, 34, 35, 35, 35, 35, 34, 35, 35, 35, 34, 34, 35, 35, 35, 34, +36, 34, 36, 34, 34, 34, 35, 34, 34, 34, 36, 34, 34, 34, 35, 34, 34, 34, 35, 34, +35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, +34, 34, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, 29, 34, 29, 29, 34, 29, 29, 34, +29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, +34, 29, 29, 34, 34, 34, 29, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 35, 29, 35, 29, 29, 34, 34, +29, 34, 34, 29, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 34, 29, 34, 34, 29, 29, +34, 29, 34, 34, 34, 29, 34, 34, 29, 34, 34, 34, 29, 34, 34, 34, 35, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, +35, 34, 35, 34, 35, 34, 36, 34, 34, 35, 34, 36, 35, 34, 35, 35, 34, 35, 34, 35, +36, 34, 35, 35, 34, 35, 35, 35, 34, 35, 34, 35, 36, 34, 35, 34, 36, 35, 34, 35, +34, 35, 35, 35, 34, 34, 36, 34, 35, 34, 35, 36, 34, 35, 34, 35, 34, 34, 34, 35, +35, 34, 35, 34, 35, 35, 34, 34, 35, 35, 35, 34, 35, 34, 34, 35, 35, 34, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 29, 34, 34, 34, 29, 34, 34, 34, 34, +29, 34, 29, 29, 29, 35, 29, 29, 29, 34, 34, 29, 29, 29, 34, 29, 34, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, 34, 29, 35, 29, 34, +29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 29, 34, +29, 34, 34, 29, 34, 29, 34, 29, 35, 29, 34, 29, 34, 34, 34, 29, 34, 29, 29, 35, +29, 34, 29, 34, 34, 34, 29, 34, 29, 34, 34, 29, 34, 29, 35, 29, 34, 29, 34, 29, +34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 35, +34, 35, 34, 35, 35, 36, 35, 34, 35, 35, 36, 34, 35, 35, 36, 34, 35, 35, 35, 34, +36, 35, 34, 34, 35, 34, 36, 34, 35, 35, 36, 35, 35, 34, 35, 35, 36, 35, 35, 34, +36, 35, 34, 35, 34, 36, 34, 35, 35, 35, 35, 35, 35, 34, 36, 34, 34, 35, 35, 34, +34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 35, 34, 34, 34, 35, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 29, 34, 34, 34, 34, 34, 34, +34, 29, 34, 34, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, +29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 34, +34, 34, 29, 34, 29, 35, 29, 34, 34, 34, 34, 34, 34, 29, 34, 35, 34, 34, 34, 34, +34, 34, 34, 34, 29, 35, 29, 34, 34, 34, 29, 34, 34, 34, 34, 29, 35, 29, 35, 34, +29, 34, 35, 34, 29, 34, 29, 34, 29, 35, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, +34, 29, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 35, 34, 35, 36, 34, 36, 35, +34, 35, 34, 35, 35, 35, 34, 36, 34, 35, 34, 35, 34, 36, 34, 35, 34, 35, 35, 36, +34, 35, 35, 35, 35, 35, 34, 35, 34, 36, 34, 35, 34, 35, 35, 35, 35, 34, 35, 35, +35, 35, 35, 35, 35, 34, 35, 34, 35, 35, 34, 35, 35, 34, 35, 34, 36, 34, 35, 34, +35, 35, 34, 36, 34, 34, 34, 34, 36, 34, 34, 34, 35, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, +34, 35, 34, 34, 35, 34, 29, 34, 34, 34, 34, 29, 34, 29, 34, 29, 34, 34, 29, 29, +29, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, +29, 34, 29, 34, 29, 34, 29, 34, 34, 34, 29, 35, 29, 34, 29, 34, 29, 34, 34, 29, +35, 34, 34, 34, 34, 34, 34, 35, 34, 35, 34, 29, 34, 34, 34, 34, 34, 29, 34, 34, +34, 29, 34, 34, 34, 29, 35, 34, 34, 29, 34, 34, 34, 29, 34, 29, 35, 34, 29, 34, +34, 29, 34, 34, 29, 29, 29, 34, 29, 34, 29, 29, 35, 29, 29, 34, 29, 34, 29, 34, +34, 34, 29, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, +34, 34, 35, 34, 34, 35, 34, 34, 35, 35, 34, 34, 34, 35, 34, 35, 36, 34, 35, 35, +35, 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 36, 35, 34, 35, 34, 35, 35, 35, 34, +35, 35, 36, 35, 35, 35, 35, 36, 35, 35, 35, 34, 36, 35, 35, 35, 34, 35, 35, 35, +35, 36, 35, 35, 35, 34, 36, 34, 35, 34, 35, 35, 34, 34, 35, 34, 34, 35, 34, 34, +34, 35, 35, 34, 34, 35, 35, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, +34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 29, 34, 34, 34, 34, 29, 34, +29, 29, 29, 29, 29, 29, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 34, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 34, 35, 34, +35, 34, 34, 34, 34, 34, 34, 35, 34, 29, 34, 29, 34, 35, 34, 34, 34, 35, 34, 34, +34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 29, 34, 34, 34, 34, 29, 34, +34, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 34, 34, 29, 35, 29, 34, 35, 34, +34, 34, 35, 34, 34, 35, 34, 34, 35, 34, 35, 34, 34, 34, 35, 34, 35, 34, 34, 34, +34, 34, 35, 34, 35, 34, 35, 36, 35, 35, 36, 35, 35, 35, 35, 36, 35, 35, 36, 35, +35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 36, 35, 35, 35, +35, 36, 35, 35, 35, 35, 35, 35, 35, 35, 34, 36, 35, 35, 35, 34, 35, 34, 35, 34, +35, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 36, 34, 35, 34, 34, +36, 34, 34, 35, 34, 35, 35, 35, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 35, 35, 34, 35, 34, 34, 35, 34, 35, 35, 34, 34, 34, 34, +34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 29, 29, 29, 29, 34, 34, 29, 34, 34, 29, +34, 34, 34, 34, 29, 29, 34, 34, 29, 34, 29, 34, 29, 34, 29, 34, 29, 34, 34, 34, +34, 29, 29, 34, 34, 34, 29, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 35, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, +34, 29, 35, 29, 34, 35, 34, 34, 34, 35, 34, 29, 34, 34, 34, 34, 34, 29, 34, 29, +29, 35, 29, 35, 29, 34, 34, 29, 34, 29, 34, 29, 34, 35, 34, 34, 35, 34, 34, 34, +34, 34, 34, 34, 34, 34, 34, 35, 35, 34, 35, 34, 34, 34, 34, 36, 34, 35, 35, 36, +35, 36, 35, 35, 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 35, +35, 35, 35, 35, 36, 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 36, 35, 35, 35, 35, +35, 36, 35, 35, 35, 36, 35, 35, 35, 35, 34, 36, 35, 35, 36, 35, 35, 34, 36, 34, +34, 34, 35, 34, 29, 34, 34, 34, 34, 34, 34, 35, 34, 36, 34, 35, 34, 34, 35, 35, +35, 34, 35, 35, 35, 34, 36, 34, 34, 35, 35, 35, 34, 35, 34, 36, 34, 35, 35, 34, +35, 34, 34, 35, 34, 34, 35, 35, 34, 35, 34, 34, 34, 35, 35, 34, 35, 34, 34, 34, +35, 34, 34, 34, 29, 34, 34, 35, 34, 35, 34, 34, 35, 34, 34, 34, 34, 29, 34, 34, +29, 34, 34, 29, 34, 29, 34, 29, 35, 29, 29, 34, 34, 34, 29, 34, 34, 34, 35, 34, +34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, +34, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, +34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 29, 34, 29, +35, 29, 34, 35, 29, 35, 34, 35, 34, 34, 34, 34, 34, 35, 35, 34, 35, 34, 36, 34, +34, 36, 35, 34, 34, 35, 34, 35, 35, 35, 35, 34, 35, 35, 35, 35, 35, 35, 35, 36, +35, 36, 35, 35, 35, 36, 35, 35, 36, 35, 36, 36, 35, 35, 35, 35, 35, 36, 35, 35, +35, 35, 36, 35, 35, 35, 36, 35, 35, 36, 36, 35, 35, 35, 36, 35, 35, 35, 36, 35, +35, 35, 34, 35, 35, 35, 35, 35, 34, 35, 35, 36, 34, 35, 34, 34, 35, 29, 29, 29, +34, 29, 29, 148, 34, 35, 34, 35, 35, 35, 35, 34, 35, 35, 34, 35, 36, 35, 35, 35, +35, 35, 34, 36, 35, 35, 34, 35, 35, 35, 35, 34, 34, 34, 34, 36, 34, 36, 35, 35, +35, 35, 34, 35, 34, 35, 34, 35, 35, 34, 34, 36, 34, 35, 35, 35, 34, 35, 34, 34, +29, 35, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 34, +34, 34, 29, 34, 29, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, +34, 36, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 35, +34, 35, 34, 35, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 29, 34, 29, 35, 34, 29, 34, 34, +34, 34, 34, 34, 34, 35, 34, 35, 35, 34, 35, 35, 35, 34, 34, 35, 34, 35, 35, 35, +35, 35, 35, 35, 35, 35, 34, 35, 35, 35, 35, 36, 35, 35, 35, 35, 36, 36, 35, 36, +36, 35, 36, 35, 35, 36, 35, 35, 35, 36, 36, 35, 36, 35, 35, 36, 35, 36, 35, 35, +36, 36, 35, 35, 36, 35, 35, 36, 36, 36, 35, 35, 36, 35, 36, 35, 35, 35, 35, 35, +35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 34, 34, 29, 29, 29, 29, 148, 148, 170, 170, +170, 34, 34, 34, 35, 35, 35, 34, 34, 35, 34, 35, 35, 35, 36, 35, 36, 35, 35, 35, +35, 36, 35, 35, 35, 35, 35, 35, 36, 35, 34, 35, 35, 34, 35, 34, 35, 35, 36, 35, +36, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 34, 35, 34, 34, 34, 35, 34, 34, 36, +34, 34, 36, 34, 35, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, +34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 35, 34, 34, 35, +34, 36, 34, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 34, +35, 35, 34, 36, 34, 34, 34, 34, 34, 35, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, +34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 29, 35, 34, 34, 34, 34, 35, 34, +35, 34, 35, 35, 34, 34, 35, 35, 35, 35, 35, 36, 35, 35, 35, 35, 34, 35, 35, 36, +35, 35, 36, 35, 35, 35, 36, 35, 35, 35, 36, 36, 35, 35, 35, 36, 35, 36, 36, 35, +35, 35, 35, 36, 35, 36, 35, 36, 36, 35, 36, 35, 36, 35, 36, 35, 36, 35, 36, 35, +36, 36, 36, 35, 36, 35, 35, 35, 36, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, +34, 35, 35, 36, 34, 34, 34, 148, 29, 148, 148, 148, 9, 125, 125, 37, 34, 34, 34, 36, +34, 35, 35, 36, 36, 35, 35, 36, 35, 35, 35, 35, 35, 35, 35, 36, 35, 35, 35, 35, +35, 35, 34, 36, 34, 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 34, 35, 35, 35, 36, +35, 35, 36, 35, 35, 36, 35, 35, 36, 34, 34, 34, 34, 35, 35, 34, 35, 35, 34, 35, +34, 34, 35, 35, 35, 35, 34, 35, 35, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 36, 34, 35, 34, 34, 34, 35, +34, 34, 35, 34, 35, 34, 34, 34, 34, 35, 34, 35, 35, 35, 34, 36, 34, 35, 34, 34, +34, 34, 36, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 35, 34, +35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 35, 34, 35, 35, 35, 34, +35, 35, 36, 35, 34, 35, 35, 35, 34, 35, 35, 35, 36, 35, 35, 35, 35, 35, 35, 36, +35, 35, 35, 36, 36, 35, 36, 36, 36, 35, 36, 36, 36, 35, 35, 35, 36, 36, 35, 35, +35, 35, 36, 35, 35, 36, 36, 36, 35, 36, 35, 36, 35, 36, 36, 35, 36, 35, 35, 36, +35, 35, 36, 36, 35, 35, 36, 36, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 35, 34, +35, 34, 29, 34, 148, 148, 37, 125, 125, 125, 170, 148, 34, 34, 34, 35, 35, 36, 36, 36, +36, 36, 36, 36, 36, 35, 36, 35, 36, 36, 35, 35, 36, 35, 36, 35, 35, 36, 35, 35, +35, 35, 35, 35, 34, 35, 35, 35, 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 34, 35, 35, 35, 36, 35, 35, 36, 35, 36, 35, 34, 36, 34, 35, 34, +34, 34, 35, 34, 34, 34, 35, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 34, 34, 34, 35, 34, 35, 34, 35, 34, 35, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 34, 36, 34, 36, 34, 35, 34, 35, 35, 35, 35, 35, 35, 35, 35, 34, 35, +35, 34, 35, 34, 36, 34, 34, 34, 34, 34, 35, 34, 35, 34, 34, 34, 34, 35, 34, 29, +35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 34, 35, 34, 34, 36, 35, 35, 35, 34, +35, 35, 36, 37, 170, 35, 169, 35, 35, 35, 35, 35, 36, 35, 36, 36, 35, 35, 35, 35, +35, 35, 36, 35, 36, 35, 36, 36, 36, 35, 36, 36, 35, 35, 35, 36, 36, 36, 35, 36, +36, 35, 36, 35, 35, 35, 36, 36, 36, 35, 35, 36, 36, 36, 36, 35, 35, 36, 35, 36, +35, 36, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 35, 36, 34, 34, 34, 29, 148, 148, +148, 148, 175, 175, 175, 125, 148, 148, 148, 34, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, +35, 35, 36, 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 35, 35, 34, 36, 35, 35, 36, +35, 35, 35, 35, 35, 36, 35, 35, 35, 36, 35, 35, 36, 36, 35, 36, 36, 35, 36, 35, +35, 34, 35, 35, 36, 36, 35, 35, 35, 35, 34, 35, 35, 35, 36, 34, 35, 36, 34, 35, +35, 35, 35, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, 35, 34, 34, 36, 34, 34, +35, 35, 34, 36, 34, 36, 34, 35, 34, 35, 34, 34, 35, 34, 34, 34, 34, 34, 35, 35, +35, 35, 35, 35, 35, 36, 35, 36, 35, 34, 35, 34, 35, 34, 34, 34, 34, 34, 34, 35, +34, 34, 34, 34, 35, 35, 34, 36, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, 34, +35, 34, 34, 34, 35, 34, 34, 35, 34, 35, 35, 34, 36, 35, 34, 36, 35, 34, 35, 170, +169, 170, 37, 169, 35, 36, 35, 35, 35, 36, 35, 36, 35, 35, 36, 36, 35, 36, 36, 35, +36, 36, 36, 36, 35, 35, 35, 35, 35, 36, 35, 35, 36, 35, 36, 35, 35, 35, 35, 36, +36, 35, 36, 35, 35, 36, 36, 36, 35, 36, 36, 35, 36, 36, 36, 35, 35, 35, 35, 36, +36, 36, 36, 36, 36, 36, 36, 36, 35, 169, 34, 148, 148, 135, 135, 120, 171, 178, 187, 200, +186, 175, 148, 34, 36, 36, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 35, 36, +35, 36, 35, 36, 35, 36, 35, 35, 36, 35, 34, 35, 35, 35, 35, 35, 34, 36, 35, 36, +35, 35, 35, 36, 35, 35, 35, 35, 35, 36, 36, 36, 35, 35, 35, 34, 35, 35, 36, 36, +35, 35, 36, 35, 36, 35, 35, 36, 35, 35, 35, 35, 35, 34, 35, 34, 35, 34, 34, 34, +34, 35, 34, 35, 34, 34, 34, 35, 35, 34, 35, 34, 34, 34, 34, 35, 35, 34, 35, 34, +35, 34, 35, 35, 34, 34, 34, 35, 34, 34, 35, 34, 34, 35, 35, 35, 35, 36, 35, 35, +35, 35, 35, 35, 35, 36, 35, 36, 35, 34, 36, 34, 35, 34, 36, 34, 34, 35, 34, 35, +35, 34, 35, 34, 35, 34, 35, 34, 34, 34, 34, 34, 35, 29, 34, 35, 34, 29, 35, 34, +34, 34, 36, 34, 35, 34, 34, 35, 35, 34, 35, 35, 35, 169, 170, 169, 37, 170, 34, 169, +35, 35, 35, 36, 36, 35, 36, 35, 35, 35, 35, 35, 36, 35, 36, 35, 36, 36, 35, 35, +35, 35, 36, 35, 35, 35, 36, 35, 36, 35, 35, 35, 36, 35, 36, 35, 35, 36, 36, 35, +35, 36, 36, 35, 36, 36, 35, 36, 35, 35, 35, 35, 35, 36, 35, 35, 35, 35, 36, 36, +36, 36, 36, 36, 35, 34, 29, 148, 135, 135, 158, 178, 103, 178, 221, 232, 182, 175, 148, 148, +34, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 35, 35, 35, 36, 36, 36, 36, 35, +35, 35, 35, 34, 35, 34, 35, 36, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +35, 35, 36, 36, 36, 35, 36, 35, 36, 35, 36, 35, 35, 35, 36, 36, 35, 36, 36, 35, +35, 35, 35, 35, 36, 36, 35, 35, 36, 35, 35, 36, 35, 34, 36, 34, 35, 34, 34, 34, +34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 36, 34, 35, 36, 34, 34, +34, 35, 35, 34, 35, 34, 34, 34, 34, 35, 35, 35, 36, 35, 35, 35, 36, 35, 35, 36, +35, 35, 35, 35, 34, 34, 34, 34, 34, 35, 35, 34, 34, 34, 34, 34, 34, 34, 36, 34, +34, 35, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 29, 34, 34, 34, 35, 34, 34, 34, +35, 34, 35, 36, 34, 34, 36, 35, 36, 37, 34, 37, 34, 169, 34, 36, 35, 36, 36, 36, +35, 36, 35, 36, 35, 35, 35, 35, 36, 35, 35, 36, 35, 36, 35, 35, 36, 35, 35, 35, +35, 36, 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 35, 36, 36, +36, 35, 36, 35, 36, 35, 35, 36, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 35, +34, 36, 148, 148, 148, 135, 145, 207, 242, 178, 178, 171, 120, 135, 148, 34, 34, 34, 36, 36, +36, 36, 36, 36, 36, 36, 36, 35, 36, 36, 35, 36, 36, 35, 35, 35, 35, 36, 35, 35, +35, 36, 35, 35, 34, 35, 34, 36, 35, 35, 36, 35, 35, 35, 35, 35, 36, 35, 36, 36, +36, 36, 36, 36, 35, 35, 35, 35, 35, 36, 36, 36, 36, 35, 35, 35, 36, 36, 35, 36, +35, 35, 35, 35, 35, 35, 35, 35, 34, 34, 34, 34, 34, 35, 34, 35, 34, 34, 34, 34, +35, 34, 35, 34, 34, 34, 34, 36, 34, 35, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 36, 35, 35, 36, 35, 35, 35, 36, 35, 36, 36, 36, 35, 35, 35, 35, 36, +34, 35, 34, 36, 35, 35, 34, 35, 35, 34, 34, 36, 35, 35, 35, 35, 34, 34, 34, 34, +34, 35, 34, 34, 35, 29, 34, 29, 35, 34, 35, 34, 34, 35, 36, 35, 34, 34, 34, 34, +35, 35, 34, 215, 200, 187, 34, 35, 36, 35, 35, 35, 36, 36, 36, 36, 36, 36, 35, 35, +35, 36, 35, 35, 35, 35, 36, 36, 36, 36, 35, 34, 35, 35, 36, 35, 35, 35, 35, 36, +35, 35, 35, 35, 36, 35, 35, 36, 35, 35, 36, 36, 36, 36, 35, 35, 35, 35, 35, 35, +35, 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, 36, 36, 35, 35, 36, 34, 34, 29, 148, +135, 100, 249, 214, 200, 214, 150, 153, 135, 135, 148, 178, 135, 175, 35, 36, 36, 35, 36, 36, +36, 35, 36, 36, 35, 36, 36, 36, 35, 36, 36, 35, 35, 35, 36, 35, 34, 35, 34, 35, +35, 35, 35, 34, 35, 34, 35, 35, 35, 36, 35, 35, 35, 35, 36, 36, 35, 36, 36, 35, +36, 35, 35, 36, 36, 36, 36, 35, 36, 36, 35, 36, 35, 35, 36, 35, 36, 35, 35, 36, +35, 35, 36, 34, 35, 36, 34, 35, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, +34, 35, 35, 34, 36, 35, 35, 34, 35, 34, 34, 35, 35, 35, 34, 34, 34, 35, 34, 35, +36, 35, 36, 35, 36, 36, 36, 35, 36, 36, 35, 36, 36, 35, 35, 34, 36, 34, 35, 34, +35, 35, 34, 34, 35, 35, 34, 35, 35, 34, 35, 34, 35, 34, 34, 34, 34, 34, 34, 34, +29, 29, 34, 34, 29, 34, 34, 29, 34, 34, 29, 34, 35, 34, 35, 34, 35, 35, 29, 199, +200, 208, 183, 175, 35, 36, 36, 36, 35, 36, 36, 36, 36, 35, 34, 36, 35, 35, 35, 36, +35, 36, 35, 36, 35, 35, 34, 36, 35, 35, 34, 35, 36, 35, 35, 35, 35, 35, 36, 35, +35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 35, 35, 35, 36, 35, 35, 36, 34, +35, 35, 35, 36, 35, 35, 35, 35, 35, 36, 34, 34, 34, 34, 148, 28, 135, 231, 234, 183, +232, 172, 143, 153, 135, 148, 29, 186, 170, 36, 35, 36, 36, 36, 36, 35, 35, 36, 36, 36, +36, 35, 36, 35, 35, 35, 35, 35, 36, 35, 35, 34, 36, 34, 35, 34, 35, 35, 34, 35, +36, 35, 35, 34, 35, 35, 35, 36, 35, 36, 36, 36, 36, 36, 35, 35, 35, 35, 36, 35, +36, 36, 36, 36, 36, 35, 36, 36, 36, 36, 36, 36, 35, 36, 35, 35, 35, 35, 35, 35, +35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, +34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 35, 36, 35, 35, 36, +36, 35, 36, 36, 36, 36, 36, 35, 35, 35, 36, 35, 35, 34, 36, 35, 35, 34, 34, 34, +34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 29, 34, 34, 34, 34, 29, 29, 29, +29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 34, 29, 35, 34, 34, 34, 4, 228, 221, 200, +125, 36, 34, 35, 35, 35, 36, 36, 35, 35, 35, 34, 34, 35, 35, 35, 35, 35, 35, 35, +35, 35, 35, 34, 35, 35, 35, 35, 34, 35, 35, 34, 34, 35, 34, 35, 34, 36, 34, 35, +34, 36, 35, 35, 35, 36, 35, 35, 35, 35, 35, 35, 34, 34, 34, 35, 35, 35, 34, 35, +35, 35, 34, 35, 35, 34, 34, 35, 29, 29, 148, 135, 223, 243, 239, 208, 208, 163, 153, 135, +135, 148, 148, 148, 34, 34, 35, 35, 36, 35, 35, 35, 36, 35, 35, 35, 35, 35, 36, 35, +35, 35, 36, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 35, +34, 36, 35, 35, 35, 35, 35, 36, 35, 35, 36, 35, 35, 36, 35, 36, 36, 35, 35, 35, +35, 35, 35, 36, 35, 36, 35, 35, 35, 36, 35, 35, 36, 35, 34, 34, 34, 34, 34, 35, +34, 29, 34, 35, 29, 34, 34, 29, 34, 34, 29, 34, 34, 34, 35, 34, 34, 35, 34, 29, +34, 34, 35, 34, 34, 34, 35, 34, 34, 34, 36, 35, 35, 35, 35, 36, 35, 36, 36, 36, +36, 35, 35, 36, 35, 34, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, +35, 29, 34, 34, 34, 34, 29, 29, 29, 34, 29, 34, 34, 29, 29, 29, 28, 29, 29, 29, +29, 34, 29, 29, 29, 34, 29, 34, 29, 34, 35, 34, 34, 34, 32, 178, 220, 183, 170, 35, +34, 35, 34, 34, 34, 34, 34, 29, 34, 34, 35, 35, 36, 34, 35, 36, 34, 35, 35, 34, +34, 34, 35, 34, 35, 34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, 34, +34, 34, 34, 35, 34, 35, 34, 34, 35, 34, 35, 34, 34, 34, 34, 36, 35, 34, 35, 34, +35, 35, 34, 29, 29, 29, 135, 67, 247, 231, 219, 180, 208, 161, 143, 135, 135, 148, 148, 29, +34, 35, 36, 35, 35, 35, 36, 35, 35, 35, 34, 35, 36, 35, 35, 35, 35, 34, 34, 35, +34, 34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, +35, 36, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 35, 35, 36, 36, +35, 35, 35, 36, 35, 35, 34, 35, 34, 35, 34, 34, 35, 34, 34, 29, 29, 34, 34, 29, +35, 29, 29, 29, 29, 29, 34, 34, 34, 29, 34, 35, 34, 34, 29, 34, 34, 29, 34, 34, +34, 34, 29, 34, 35, 35, 35, 35, 36, 35, 35, 35, 36, 35, 35, 35, 35, 35, 35, 34, +34, 34, 35, 34, 34, 34, 34, 35, 34, 34, 34, 35, 34, 34, 35, 34, 29, 34, 34, 34, +29, 34, 34, 34, 34, 34, 29, 29, 34, 29, 29, 28, 29, 29, 29, 29, 29, 28, 34, 29, +29, 29, 29, 34, 34, 35, 34, 35, 34, 34, 29, 34, 29, 215, 189, 202, 219, 29, 34, 34, +34, 34, 29, 34, 29, 34, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, +34, 34, 35, 29, 34, 29, 34, 34, 29, 34, 34, 35, 34, 34, 34, 34, 34, 35, 34, 34, +35, 34, 35, 34, 34, 29, 34, 34, 34, 35, 34, 34, 34, 29, 34, 34, 34, 29, 29, 29, +148, 135, 103, 2, 244, 227, 193, 184, 208, 225, 135, 135, 135, 148, 29, 34, 35, 34, 35, 34, +35, 34, 34, 34, 35, 35, 35, 34, 35, 34, 34, 34, 34, 35, 34, 34, 35, 34, 29, 29, +34, 29, 35, 34, 29, 34, 34, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 35, +36, 35, 35, 36, 35, 35, 36, 35, 35, 35, 34, 35, 35, 35, 35, 35, 36, 35, 35, 35, +34, 35, 35, 35, 34, 34, 34, 29, 34, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 34, +29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 29, 34, 29, +34, 34, 35, 35, 34, 36, 35, 35, 35, 36, 35, 35, 35, 36, 34, 34, 35, 34, 34, 29, +34, 35, 34, 34, 34, 34, 34, 34, 29, 34, 29, 29, 34, 34, 34, 34, 29, 29, 29, 29, +29, 29, 34, 29, 29, 34, 29, 29, 28, 29, 29, 29, 10, 29, 28, 29, 29, 29, 29, 29, +34, 29, 34, 34, 34, 36, 35, 34, 34, 29, 218, 235, 242, 29, 3, 3, 28, 29, 34, 34, +29, 29, 34, 29, 29, 34, 35, 29, 34, 35, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, +29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 35, 29, 34, 29, 34, 34, 34, 29, +34, 29, 29, 29, 34, 34, 29, 34, 29, 34, 29, 29, 34, 29, 29, 28, 28, 145, 214, 244, +232, 250, 190, 189, 193, 192, 135, 135, 148, 148, 148, 34, 34, 34, 34, 35, 34, 34, 35, 34, +34, 35, 34, 34, 34, 29, 35, 34, 35, 34, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, +34, 29, 29, 29, 34, 34, 29, 34, 34, 34, 34, 34, 35, 34, 34, 35, 34, 34, 34, 34, +34, 34, 34, 29, 29, 34, 35, 36, 35, 35, 34, 34, 34, 35, 36, 34, 36, 34, 35, 34, +34, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 28, 28, 29, 28, 29, 29, 29, 29, +29, 34, 29, 29, 29, 29, 34, 35, 34, 35, 34, 29, 29, 29, 29, 34, 29, 29, 34, 34, +35, 34, 35, 36, 35, 35, 35, 35, 35, 35, 34, 34, 35, 34, 35, 29, 34, 29, 29, 29, +29, 34, 29, 34, 29, 34, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 34, 29, 29, 34, +29, 29, 29, 29, 28, 28, 29, 233, 208, 29, 28, 29, 28, 29, 29, 29, 29, 29, 34, 29, +29, 29, 35, 34, 34, 34, 29, 145, 9, 29, 1, 209, 219, 29, 29, 34, 34, 34, 29, 29, +36, 35, 34, 34, 34, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, +29, 29, 34, 29, 34, 28, 29, 29, 29, 29, 34, 29, 29, 29, 34, 34, 29, 29, 29, 29, +29, 29, 29, 29, 34, 29, 29, 29, 28, 28, 28, 135, 135, 135, 218, 239, 245, 228, 202, 208, +163, 153, 135, 135, 28, 148, 29, 29, 34, 35, 29, 34, 29, 34, 29, 29, 29, 34, 34, 34, +34, 34, 34, 29, 34, 34, 29, 34, 29, 29, 28, 34, 29, 29, 29, 29, 29, 29, 29, 29, +28, 29, 29, 29, 29, 29, 29, 29, 29, 34, 34, 34, 34, 35, 34, 34, 34, 34, 34, 36, +34, 34, 35, 35, 35, 35, 35, 35, 34, 34, 34, 35, 34, 34, 29, 29, 29, 34, 29, 29, +29, 29, 28, 29, 29, 28, 29, 28, 29, 29, 29, 29, 28, 29, 28, 28, 29, 29, 28, 29, +29, 29, 29, 29, 34, 34, 34, 29, 29, 29, 29, 34, 34, 34, 29, 34, 36, 34, 34, 34, +34, 34, 36, 34, 29, 34, 35, 29, 34, 34, 29, 34, 34, 29, 29, 34, 29, 29, 29, 29, +29, 29, 34, 29, 29, 34, 29, 34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 29, +28, 28, 25, 53, 221, 190, 24, 29, 29, 29, 28, 29, 29, 29, 29, 29, 34, 34, 34, 34, +29, 29, 29, 25, 28, 28, 228, 183, 189, 213, 10, 28, 29, 29, 28, 35, 36, 35, 29, 29, +29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 28, 29, 29, 28, 29, +28, 29, 29, 29, 29, 29, 29, 34, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, 29, 29, +29, 29, 29, 29, 29, 148, 135, 135, 143, 143, 175, 234, 217, 229, 206, 199, 163, 143, 135, 135, +135, 28, 29, 29, 29, 34, 34, 29, 34, 29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 34, +29, 34, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, +34, 29, 34, 29, 29, 29, 34, 34, 29, 34, 34, 34, 34, 29, 29, 34, 29, 34, 35, 35, +35, 35, 35, 35, 35, 34, 29, 34, 29, 34, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, +28, 29, 28, 28, 28, 29, 28, 28, 29, 29, 28, 28, 28, 29, 29, 29, 29, 29, 28, 29, +29, 29, 28, 29, 29, 29, 29, 34, 34, 29, 34, 34, 34, 34, 34, 34, 35, 34, 29, 34, +34, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 34, 29, 29, 29, 28, 29, 29, 29, 28, 29, 29, 28, 28, 28, 28, +219, 220, 3, 28, 29, 28, 29, 29, 28, 29, 29, 29, 34, 28, 29, 29, 29, 29, 29, 29, +29, 29, 9, 191, 208, 198, 4, 29, 29, 29, 29, 29, 36, 35, 29, 28, 29, 29, 28, 29, +29, 28, 29, 29, 28, 28, 28, 28, 29, 28, 29, 29, 28, 29, 29, 28, 29, 29, 29, 28, +29, 28, 29, 28, 29, 29, 28, 29, 34, 34, 29, 29, 29, 29, 29, 29, 29, 34, 28, 29, +135, 28, 135, 120, 143, 150, 178, 243, 184, 210, 195, 201, 171, 153, 143, 135, 135, 51, 28, 29, +29, 34, 29, 35, 28, 29, 28, 34, 28, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, +29, 29, 29, 34, 28, 29, 29, 29, 28, 29, 29, 28, 29, 28, 29, 29, 28, 29, 28, 34, +29, 29, 29, 34, 29, 29, 29, 29, 34, 29, 29, 29, 34, 29, 34, 34, 34, 35, 34, 34, +34, 35, 34, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, +28, 28, 28, 28, 29, 28, 28, 28, 28, 28, 29, 29, 28, 29, 29, 28, 28, 28, 29, 28, +29, 28, 29, 29, 29, 29, 34, 29, 34, 34, 34, 29, 29, 29, 29, 29, 28, 29, 29, 29, +34, 34, 29, 29, 29, 29, 29, 29, 28, 29, 28, 29, 28, 29, 29, 29, 28, 29, 29, 29, +29, 29, 28, 29, 29, 29, 29, 28, 29, 29, 28, 29, 29, 28, 28, 28, 58, 51, 28, 28, +28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 24, +223, 241, 29, 29, 29, 28, 29, 28, 35, 35, 29, 29, 28, 29, 29, 29, 29, 29, 28, 28, +28, 28, 28, 29, 29, 29, 28, 29, 28, 28, 28, 29, 28, 28, 29, 29, 29, 29, 28, 29, +29, 29, 29, 29, 28, 29, 29, 29, 29, 28, 29, 29, 28, 29, 29, 28, 28, 135, 120, 143, +160, 219, 115, 227, 210, 210, 206, 198, 153, 139, 143, 120, 135, 28, 28, 29, 29, 29, 29, 28, +29, 29, 29, 28, 29, 29, 28, 29, 29, 29, 29, 29, 29, 28, 29, 28, 29, 29, 29, 28, +29, 29, 28, 29, 28, 29, 29, 28, 29, 28, 29, 28, 29, 29, 29, 28, 29, 29, 29, 29, +29, 34, 34, 29, 29, 29, 34, 29, 29, 34, 34, 29, 34, 34, 34, 35, 34, 29, 34, 29, +34, 28, 29, 29, 34, 28, 29, 28, 29, 29, 29, 29, 28, 28, 28, 28, 28, 28, 29, 29, +28, 28, 28, 28, 28, 29, 29, 29, 29, 28, 28, 29, 29, 29, 29, 29, 29, 28, 29, 29, +29, 34, 28, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, +29, 28, 29, 28, 29, 29, 29, 29, 28, 25, 25, 28, 28, 170, 34, 25, 25, 28, 28, 28, +28, 29, 29, 29, 28, 29, 28, 29, 29, 28, 29, 29, 34, 29, 29, 25, 252, 0, 28, 28, +29, 29, 29, 28, 29, 34, 28, 28, 28, 28, 29, 28, 29, 28, 28, 25, 28, 28, 28, 29, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 28, 29, 28, 29, +29, 29, 28, 29, 28, 29, 29, 29, 29, 29, 28, 25, 135, 135, 120, 153, 153, 239, 91, 175, +202, 183, 205, 236, 171, 153, 120, 143, 120, 135, 25, 28, 28, 29, 29, 29, 29, 28, 29, 28, +28, 28, 28, 28, 28, 28, 29, 28, 29, 28, 29, 29, 28, 29, 28, 29, 29, 28, 29, 29, +29, 28, 28, 29, 28, 29, 28, 29, 29, 28, 29, 29, 29, 28, 29, 28, 34, 28, 29, 29, +29, 29, 29, 29, 29, 28, 29, 29, 34, 29, 29, 29, 29, 29, 35, 29, 28, 29, 29, 29, +28, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, 28, 28, 28, 28, +28, 29, 28, 28, 28, 28, 28, 28, 29, 29, 29, 28, 29, 28, 29, 29, 29, 28, 29, 29, +28, 34, 29, 28, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, +29, 28, 29, 28, 29, 28, 29, 28, 29, 29, 28, 29, 28, 29, 28, 29, 29, 29, 28, 29, +28, 28, 28, 28, 28, 25, 24, 37, 207, 202, 220, 178, 10, 51, 28, 28, 28, 28, 28, 28, +29, 29, 29, 28, 28, 28, 28, 29, 28, 29, 28, 28, 241, 4, 28, 29, 29, 29, 29, 28, +29, 35, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 28, 29, 29, +29, 29, 28, 29, 28, 28, 28, 135, 135, 143, 143, 150, 139, 210, 233, 239, 203, 215, 198, 204, +171, 163, 158, 143, 143, 51, 28, 25, 28, 28, 28, 28, 28, 29, 29, 28, 28, 28, 28, 28, +28, 28, 28, 28, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 28, 34, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 28, 28, +28, 28, 28, 25, 28, 28, 28, 29, 29, 28, 29, 25, 28, 25, 25, 28, 28, 28, 28, 28, +25, 25, 28, 28, 28, 28, 29, 29, 29, 29, 28, 29, 29, 28, 29, 28, 29, 28, 29, 29, +28, 29, 29, 28, 29, 29, 28, 29, 28, 29, 28, 29, 29, 29, 28, 29, 28, 29, 29, 29, +29, 29, 28, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, +25, 79, 37, 222, 223, 212, 203, 199, 201, 208, 125, 100, 28, 25, 28, 28, 25, 28, 29, 28, +28, 28, 29, 29, 29, 29, 28, 28, 28, 7, 28, 29, 28, 28, 28, 28, 25, 28, 28, 28, +28, 28, 25, 28, 28, 28, 28, 25, 28, 28, 25, 25, 28, 28, 28, 25, 28, 28, 25, 25, +28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, 28, 28, 29, 28, 29, 29, 29, +28, 28, 25, 51, 120, 143, 143, 163, 171, 36, 254, 208, 196, 202, 185, 203, 207, 158, 133, 139, +143, 120, 51, 25, 25, 28, 25, 28, 25, 28, 25, 25, 28, 28, 25, 28, 28, 28, 28, 28, +28, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 29, 28, 29, 29, 28, 29, 28, 29, 28, 29, 29, 29, 29, 29, 29, +28, 29, 28, 29, 28, 29, 29, 28, 29, 29, 29, 28, 28, 29, 25, 28, 25, 28, 28, 28, +28, 28, 28, 29, 28, 28, 28, 28, 25, 25, 28, 28, 28, 28, 28, 28, 25, 28, 28, 28, +28, 28, 28, 28, 28, 29, 29, 28, 29, 29, 28, 29, 29, 29, 28, 28, 29, 28, 29, 29, +28, 29, 29, 29, 28, 29, 29, 29, 29, 28, 29, 29, 29, 28, 29, 28, 29, 28, 28, 28, +29, 29, 28, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 184, 204, +225, 208, 199, 185, 204, 202, 208, 53, 79, 28, 28, 25, 28, 25, 25, 25, 28, 28, 28, 28, +28, 28, 28, 28, 25, 28, 29, 28, 28, 28, 28, 28, 28, 28, 25, 28, 28, 28, 25, 28, +25, 25, 25, 25, 28, 25, 25, 25, 28, 25, 25, 25, 24, 25, 25, 28, 25, 25, 25, 28, +28, 25, 28, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 28, 143, +143, 150, 139, 163, 239, 233, 239, 204, 192, 192, 208, 190, 192, 178, 190, 103, 139, 120, 25, 25, +28, 25, 25, 25, 28, 25, 25, 25, 25, 25, 28, 25, 25, 25, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 25, 28, 25, 28, 28, 28, 28, 25, 28, 28, 28, 28, 25, 28, +28, 28, 28, 28, 28, 29, 29, 28, 29, 29, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, +29, 28, 29, 29, 29, 28, 28, 25, 28, 25, 28, 25, 25, 25, 28, 28, 28, 28, 28, 28, +25, 28, 28, 28, 25, 28, 28, 25, 25, 28, 25, 25, 28, 25, 25, 25, 28, 28, 28, 29, +28, 28, 28, 28, 28, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 29, +29, 28, 28, 28, 28, 29, 29, 28, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, +28, 28, 28, 28, 25, 28, 28, 25, 28, 25, 28, 24, 25, 125, 191, 195, 249, 213, 207, 236, +253, 223, 234, 208, 122, 100, 25, 25, 24, 25, 25, 25, 28, 25, 25, 25, 28, 25, 25, 25, +28, 28, 28, 28, 28, 25, 28, 28, 28, 25, 28, 25, 25, 28, 25, 25, 25, 28, 25, 25, +25, 25, 25, 28, 25, 25, 25, 25, 25, 25, 24, 25, 24, 25, 28, 25, 25, 25, 25, 25, +28, 25, 28, 25, 28, 28, 28, 28, 28, 28, 28, 25, 28, 25, 143, 143, 120, 150, 153, 163, +208, 233, 239, 180, 237, 227, 212, 214, 197, 220, 220, 208, 163, 79, 100, 28, 24, 25, 28, 25, +28, 28, 28, 25, 25, 25, 25, 25, 28, 25, 25, 28, 25, 25, 28, 25, 25, 25, 28, 25, +25, 25, 28, 25, 25, 28, 25, 25, 25, 25, 28, 25, 25, 25, 25, 28, 28, 28, 28, 28, +28, 28, 28, 29, 29, 28, 28, 29, 29, 28, 28, 28, 29, 29, 29, 34, 29, 29, 29, 28, +28, 28, 28, 28, 25, 25, 25, 25, 28, 28, 25, 28, 28, 28, 25, 25, 28, 28, 28, 25, +25, 28, 28, 28, 25, 25, 24, 25, 25, 25, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 25, 24, 25, 25, 25, 25, 28, +28, 25, 25, 25, 28, 28, 24, 25, 29, 125, 198, 184, 242, 242, 195, 203, 249, 249, 182, 204, +227, 113, 24, 25, 25, 25, 25, 25, 25, 25, 25, 28, 25, 25, 28, 25, 28, 28, 25, 28, +28, 25, 25, 25, 28, 25, 25, 28, 25, 25, 28, 25, 25, 24, 24, 25, 24, 28, 24, 24, +24, 24, 25, 24, 24, 24, 24, 24, 25, 24, 24, 25, 24, 25, 25, 25, 25, 25, 28, 25, +25, 28, 28, 25, 28, 28, 28, 25, 25, 51, 143, 143, 139, 150, 150, 162, 236, 241, 239, 180, +234, 214, 185, 197, 184, 204, 197, 208, 215, 139, 100, 24, 25, 24, 25, 25, 25, 25, 25, 28, +25, 24, 28, 25, 25, 25, 25, 25, 25, 25, 25, 25, 28, 25, 25, 25, 28, 25, 25, 28, +25, 25, 25, 25, 28, 25, 25, 25, 25, 28, 25, 25, 28, 25, 25, 28, 25, 28, 28, 28, +28, 28, 29, 29, 28, 28, 29, 29, 28, 29, 28, 28, 28, 28, 28, 28, 28, 25, 25, 25, +28, 25, 25, 25, 25, 25, 25, 25, 28, 28, 28, 25, 25, 25, 28, 28, 28, 28, 25, 25, +28, 24, 25, 25, 25, 25, 25, 25, 25, 28, 25, 25, 28, 28, 28, 28, 28, 28, 25, 25, +28, 28, 28, 25, 28, 25, 25, 28, 28, 28, 28, 28, 25, 25, 25, 28, 28, 28, 28, 28, +28, 25, 28, 28, 25, 28, 28, 25, 25, 218, 135, 28, 29, 29, 25, 59, 25, 28, 25, 25, +25, 25, 24, 28, 206, 35, 206, 210, 236, 217, 208, 213, 249, 197, 183, 213, 240, 235, 136, 24, +25, 24, 24, 25, 24, 25, 24, 24, 25, 25, 25, 28, 25, 25, 28, 25, 25, 25, 28, 25, +25, 25, 25, 25, 24, 25, 24, 25, 25, 24, 25, 24, 24, 24, 24, 25, 24, 25, 24, 25, +24, 25, 24, 24, 24, 25, 24, 25, 24, 24, 25, 24, 25, 25, 25, 25, 28, 25, 25, 25, +28, 25, 25, 25, 25, 24, 143, 143, 142, 150, 138, 178, 236, 4, 202, 200, 208, 231, 185, 208, +206, 206, 189, 202, 193, 78, 100, 24, 24, 24, 25, 24, 25, 24, 24, 24, 28, 24, 24, 24, +25, 25, 25, 24, 25, 24, 28, 25, 24, 25, 28, 24, 24, 24, 24, 24, 25, 24, 25, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 28, 25, 25, 28, 25, 28, 28, 28, 28, 28, 29, +28, 28, 28, 28, 28, 25, 28, 28, 28, 28, 28, 28, 28, 25, 28, 25, 25, 25, 25, 25, +24, 25, 25, 28, 25, 25, 25, 25, 25, 25, 25, 28, 25, 25, 25, 25, 25, 25, 24, 25, +28, 25, 25, 28, 25, 25, 25, 28, 25, 25, 25, 25, 28, 25, 28, 25, 28, 25, 28, 25, +25, 25, 28, 25, 25, 28, 25, 25, 25, 28, 25, 28, 28, 28, 28, 25, 25, 28, 25, 25, +28, 28, 28, 28, 197, 221, 201, 208, 221, 208, 208, 125, 42, 91, 25, 25, 25, 28, 23, 34, +233, 240, 184, 180, 247, 245, 227, 253, 235, 155, 245, 213, 204, 221, 145, 119, 24, 24, 25, 24, +24, 24, 25, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 24, 25, 24, 25, 24, +25, 24, 25, 24, 24, 24, 24, 25, 24, 24, 25, 24, 24, 24, 24, 24, 25, 119, 25, 24, +24, 24, 24, 24, 25, 24, 24, 24, 24, 24, 25, 24, 24, 24, 24, 28, 25, 25, 25, 24, +24, 25, 143, 150, 150, 158, 150, 165, 220, 234, 203, 206, 205, 208, 218, 188, 199, 210, 207, 218, +79, 79, 100, 59, 24, 24, 24, 24, 24, 25, 24, 24, 24, 25, 24, 25, 25, 24, 25, 24, +24, 24, 24, 24, 25, 24, 24, 25, 24, 25, 24, 25, 24, 24, 24, 25, 24, 24, 24, 25, +24, 25, 24, 28, 24, 25, 25, 28, 25, 25, 25, 28, 28, 28, 29, 28, 28, 28, 28, 25, +28, 28, 28, 28, 28, 28, 28, 25, 25, 28, 25, 24, 25, 25, 25, 24, 25, 24, 28, 25, +25, 28, 24, 28, 25, 25, 25, 25, 25, 25, 25, 25, 24, 24, 25, 25, 25, 25, 25, 25, +24, 25, 28, 25, 25, 25, 25, 25, 28, 25, 25, 25, 25, 28, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 28, 25, 25, 28, 28, 25, 25, 25, 28, 25, 25, 25, 28, 25, 24, 28, +208, 208, 203, 205, 225, 227, 201, 183, 145, 120, 25, 50, 24, 50, 29, 233, 208, 247, 210, 180, +239, 227, 183, 235, 155, 155, 227, 213, 190, 191, 225, 176, 18, 24, 24, 79, 25, 24, 24, 25, +24, 24, 24, 25, 24, 25, 24, 25, 24, 25, 24, 25, 24, 24, 24, 25, 24, 25, 24, 25, +24, 25, 24, 24, 24, 25, 79, 24, 25, 79, 100, 79, 79, 100, 42, 50, 120, 59, 79, 100, +24, 24, 24, 24, 25, 24, 24, 25, 24, 25, 24, 24, 24, 24, 24, 24, 25, 120, 119, 150, +150, 158, 149, 158, 208, 234, 205, 208, 208, 188, 206, 184, 200, 207, 178, 143, 215, 222, 9, 70, +49, 49, 50, 50, 50, 24, 24, 25, 24, 24, 24, 25, 24, 24, 24, 25, 24, 25, 79, 24, +24, 25, 24, 66, 24, 24, 25, 24, 24, 25, 42, 24, 50, 24, 25, 24, 24, 24, 24, 24, +25, 24, 24, 24, 24, 28, 25, 25, 25, 28, 25, 25, 25, 25, 25, 25, 28, 24, 24, 25, +28, 25, 24, 25, 25, 25, 24, 24, 25, 24, 24, 25, 24, 24, 24, 24, 25, 25, 25, 24, +25, 25, 25, 24, 25, 28, 25, 25, 25, 24, 24, 25, 28, 24, 25, 24, 25, 24, 24, 24, +24, 25, 24, 25, 25, 25, 28, 25, 25, 24, 25, 25, 25, 28, 24, 28, 24, 28, 25, 28, +25, 25, 25, 28, 25, 25, 28, 25, 25, 25, 25, 28, 25, 25, 28, 24, 28, 227, 207, 213, +253, 249, 216, 188, 202, 200, 199, 171, 25, 29, 215, 213, 200, 240, 223, 206, 211, 227, 232, 235, +245, 225, 215, 191, 222, 204, 225, 224, 53, 49, 24, 24, 24, 100, 24, 24, 25, 24, 25, 24, +24, 24, 24, 24, 25, 24, 24, 79, 24, 25, 24, 24, 24, 24, 100, 24, 24, 79, 62, 100, +24, 119, 79, 120, 100, 79, 100, 100, 79, 100, 62, 50, 120, 62, 66, 102, 59, 50, 25, 24, +24, 24, 24, 24, 24, 24, 24, 25, 24, 25, 62, 25, 49, 120, 120, 139, 150, 153, 152, 165, +200, 245, 247, 211, 199, 200, 207, 206, 191, 204, 135, 193, 220, 207, 184, 59, 18, 49, 49, 50, +50, 79, 49, 24, 25, 21, 25, 24, 24, 24, 25, 24, 95, 49, 24, 24, 100, 66, 25, 24, +24, 62, 24, 24, 25, 24, 25, 24, 24, 25, 24, 24, 25, 24, 25, 24, 24, 24, 25, 24, +25, 24, 28, 24, 25, 28, 25, 25, 28, 24, 28, 25, 24, 113, 219, 160, 100, 79, 25, 24, +25, 25, 24, 25, 24, 24, 25, 24, 24, 25, 24, 25, 24, 25, 24, 25, 24, 25, 24, 25, +24, 24, 25, 28, 25, 25, 25, 24, 24, 24, 24, 24, 24, 79, 24, 25, 24, 24, 24, 24, +24, 25, 24, 24, 25, 24, 25, 25, 25, 25, 24, 24, 24, 25, 24, 24, 24, 28, 24, 25, +25, 25, 25, 25, 25, 28, 24, 25, 25, 25, 25, 24, 24, 239, 207, 212, 253, 253, 249, 219, +193, 183, 186, 231, 220, 202, 225, 217, 249, 249, 179, 213, 202, 209, 155, 179, 213, 204, 198, 223, +214, 212, 198, 213, 209, 66, 62, 24, 100, 24, 24, 79, 24, 25, 24, 24, 24, 25, 24, 25, +24, 58, 25, 24, 24, 24, 24, 102, 84, 25, 24, 100, 79, 100, 62, 79, 50, 120, 79, 119, +79, 79, 95, 79, 79, 100, 21, 50, 120, 62, 62, 100, 59, 50, 23, 24, 24, 24, 24, 24, +24, 100, 59, 21, 50, 24, 24, 95, 49, 100, 143, 119, 120, 150, 152, 204, 233, 235, 218, 206, +200, 192, 203, 208, 191, 184, 210, 205, 199, 198, 207, 84, 38, 49, 50, 49, 49, 62, 100, 79, +45, 48, 48, 27, 79, 59, 79, 120, 79, 24, 59, 100, 62, 53, 53, 27, 100, 100, 59, 49, +100, 95, 58, 24, 50, 49, 49, 50, 24, 49, 24, 24, 50, 24, 100, 24, 24, 24, 24, 28, +25, 25, 28, 25, 24, 24, 24, 24, 50, 225, 232, 208, 187, 218, 180, 218, 53, 95, 25, 24, +25, 100, 24, 25, 24, 24, 24, 24, 24, 24, 24, 24, 25, 24, 24, 24, 25, 24, 24, 24, +24, 25, 24, 49, 25, 24, 25, 24, 25, 24, 79, 24, 24, 24, 25, 24, 25, 24, 25, 24, +24, 24, 24, 25, 24, 24, 25, 24, 25, 24, 25, 24, 25, 24, 25, 25, 24, 25, 24, 25, +24, 24, 24, 25, 24, 25, 24, 24, 24, 248, 208, 216, 253, 253, 2, 1, 127, 212, 248, 228, +208, 213, 238, 217, 222, 239, 223, 195, 223, 228, 235, 209, 227, 191, 204, 228, 225, 214, 214, 204, +209, 127, 62, 79, 100, 100, 25, 24, 24, 84, 24, 24, 24, 24, 24, 24, 24, 58, 78, 100, +49, 24, 24, 100, 84, 79, 100, 100, 79, 100, 62, 100, 22, 119, 79, 95, 100, 59, 100, 95, +79, 101, 62, 23, 95, 62, 79, 95, 58, 49, 24, 23, 24, 23, 50, 24, 79, 100, 59, 21, +50, 50, 49, 100, 62, 59, 119, 143, 150, 142, 158, 239, 246, 240, 237, 241, 203, 208, 208, 196, +203, 206, 191, 197, 198, 210, 206, 193, 38, 49, 23, 23, 49, 42, 42, 119, 62, 52, 48, 27, +49, 100, 120, 100, 79, 49, 49, 79, 62, 31, 48, 31, 79, 100, 59, 49, 100, 100, 59, 49, +49, 50, 24, 49, 49, 24, 23, 24, 24, 62, 79, 49, 49, 24, 24, 24, 24, 24, 24, 24, +100, 24, 49, 22, 28, 211, 194, 190, 213, 200, 199, 183, 155, 223, 100, 100, 24, 100, 24, 100, +49, 49, 49, 25, 24, 79, 24, 79, 24, 84, 24, 49, 24, 24, 24, 50, 24, 50, 24, 24, +24, 24, 24, 79, 24, 24, 24, 49, 24, 24, 62, 79, 62, 24, 24, 25, 24, 25, 62, 24, +25, 24, 24, 24, 24, 25, 24, 24, 24, 24, 24, 25, 24, 24, 24, 24, 100, 24, 25, 24, +24, 24, 25, 24, 24, 208, 201, 231, 253, 216, 216, 1, 250, 245, 245, 245, 228, 2, 1, 227, +236, 213, 223, 191, 223, 213, 205, 231, 231, 227, 229, 208, 199, 208, 208, 197, 235, 235, 25, 79, +100, 100, 100, 100, 102, 100, 24, 24, 49, 120, 79, 58, 24, 39, 78, 100, 21, 23, 50, 100, +100, 100, 100, 100, 79, 95, 42, 78, 42, 119, 78, 119, 78, 78, 95, 78, 79, 95, 42, 49, +95, 59, 79, 100, 59, 49, 24, 24, 24, 24, 24, 23, 79, 100, 62, 49, 49, 49, 50, 62, +78, 59, 78, 120, 139, 133, 162, 234, 246, 227, 233, 233, 215, 189, 205, 198, 196, 192, 184, 206, +198, 215, 191, 220, 120, 38, 18, 49, 18, 42, 42, 42, 95, 27, 20, 82, 21, 21, 95, 100, +78, 18, 42, 42, 78, 27, 16, 78, 100, 100, 59, 49, 100, 101, 79, 18, 49, 49, 49, 24, +24, 24, 24, 24, 50, 62, 100, 49, 49, 21, 100, 100, 100, 24, 100, 79, 79, 79, 24, 42, +47, 208, 217, 200, 197, 200, 197, 190, 204, 208, 212, 100, 78, 25, 79, 79, 100, 49, 49, 79, +119, 25, 24, 24, 24, 79, 62, 24, 24, 50, 24, 24, 49, 24, 79, 62, 100, 79, 62, 100, +100, 79, 79, 49, 24, 24, 79, 66, 102, 62, 79, 62, 79, 79, 25, 24, 120, 24, 50, 25, +24, 79, 100, 62, 79, 50, 24, 24, 24, 25, 25, 24, 25, 24, 24, 24, 25, 24, 24, 79, +24, 225, 208, 249, 2, 208, 205, 1, 245, 245, 240, 250, 250, 250, 249, 248, 249, 227, 249, 223, +227, 203, 206, 191, 203, 249, 248, 217, 223, 205, 204, 206, 217, 2, 113, 78, 100, 95, 79, 100, +120, 100, 62, 23, 49, 119, 58, 39, 24, 57, 77, 83, 49, 49, 42, 100, 95, 78, 95, 100, +78, 78, 59, 78, 49, 119, 79, 95, 95, 79, 78, 100, 79, 95, 58, 18, 95, 62, 58, 95, +58, 42, 49, 23, 24, 18, 49, 49, 79, 95, 58, 42, 42, 18, 50, 18, 59, 95, 79, 100, +128, 139, 158, 231, 233, 236, 236, 237, 212, 198, 196, 214, 198, 195, 191, 215, 200, 208, 190, 201, +193, 69, 49, 18, 49, 42, 42, 18, 66, 48, 48, 27, 78, 79, 95, 100, 95, 18, 18, 18, +23, 53, 48, 97, 95, 78, 59, 18, 95, 95, 58, 39, 42, 49, 49, 49, 23, 23, 23, 23, +23, 59, 100, 18, 18, 49, 119, 100, 100, 79, 100, 100, 79, 95, 18, 21, 213, 209, 200, 192, +197, 216, 200, 195, 184, 215, 235, 48, 100, 120, 79, 100, 100, 84, 49, 79, 100, 100, 100, 79, +100, 100, 100, 84, 49, 49, 50, 50, 49, 50, 62, 62, 100, 79, 62, 79, 79, 100, 79, 49, +49, 42, 100, 100, 59, 100, 66, 79, 79, 79, 79, 79, 21, 49, 24, 23, 22, 66, 100, 62, +79, 24, 50, 24, 50, 50, 79, 100, 100, 24, 79, 120, 100, 59, 24, 53, 49, 3, 220, 213, +235, 250, 250, 232, 250, 248, 2, 2, 250, 248, 248, 240, 249, 247, 236, 247, 249, 227, 212, 198, +211, 249, 2, 249, 215, 215, 236, 227, 249, 127, 179, 69, 95, 95, 100, 95, 95, 100, 49, 49, +42, 119, 70, 59, 23, 57, 83, 95, 42, 49, 49, 95, 95, 79, 100, 78, 79, 95, 90, 58, +18, 119, 78, 98, 100, 70, 95, 78, 79, 95, 38, 49, 95, 59, 79, 95, 59, 18, 23, 23, +49, 49, 42, 42, 79, 95, 59, 18, 42, 49, 49, 42, 49, 95, 119, 100, 150, 144, 158, 237, +236, 219, 215, 246, 239, 206, 180, 229, 193, 184, 206, 203, 182, 207, 198, 203, 202, 91, 39, 39, +42, 39, 42, 18, 27, 54, 54, 26, 59, 95, 95, 95, 78, 17, 42, 18, 21, 47, 54, 97, +100, 78, 58, 42, 95, 101, 78, 14, 18, 42, 18, 49, 18, 49, 49, 49, 18, 59, 95, 42, +18, 42, 95, 100, 95, 79, 100, 100, 79, 79, 39, 3, 206, 186, 200, 213, 190, 192, 214, 207, +198, 198, 196, 221, 53, 104, 78, 100, 78, 95, 100, 62, 79, 79, 79, 95, 79, 79, 100, 79, +66, 49, 18, 49, 49, 49, 79, 62, 24, 79, 62, 100, 78, 100, 79, 49, 18, 42, 119, 78, +79, 95, 84, 27, 66, 59, 100, 18, 49, 49, 24, 50, 50, 100, 100, 59, 79, 49, 21, 62, +42, 62, 79, 100, 100, 79, 84, 119, 79, 84, 75, 24, 23, 28, 201, 207, 250, 235, 250, 248, +248, 249, 250, 248, 248, 248, 250, 2, 249, 223, 242, 247, 249, 248, 214, 229, 247, 253, 253, 249, +218, 206, 212, 205, 195, 1, 145, 78, 95, 95, 100, 95, 95, 100, 49, 23, 42, 101, 69, 57, +23, 56, 83, 95, 42, 23, 23, 100, 95, 73, 95, 95, 78, 95, 95, 18, 49, 110, 79, 104, +100, 79, 86, 100, 77, 95, 42, 18, 95, 70, 59, 95, 59, 49, 23, 23, 18, 21, 18, 21, +79, 95, 58, 42, 18, 49, 23, 18, 49, 58, 119, 100, 150, 139, 226, 246, 236, 237, 236, 246, +239, 223, 198, 210, 214, 203, 218, 211, 198, 193, 184, 180, 198, 184, 39, 79, 39, 42, 20, 49, +95, 26, 26, 42, 42, 95, 100, 119, 78, 18, 18, 42, 20, 59, 82, 95, 95, 78, 58, 18, +95, 95, 78, 42, 20, 18, 49, 18, 49, 23, 23, 23, 23, 59, 82, 16, 20, 42, 95, 95, +95, 78, 95, 95, 79, 95, 65, 214, 179, 200, 192, 213, 187, 187, 195, 200, 213, 191, 199, 203, +221, 242, 100, 78, 79, 78, 65, 95, 78, 100, 100, 100, 100, 78, 95, 100, 65, 59, 49, 45, +24, 27, 79, 58, 78, 79, 59, 78, 79, 78, 78, 20, 23, 23, 95, 78, 59, 98, 79, 95, +66, 82, 23, 23, 18, 23, 49, 42, 49, 79, 95, 59, 79, 18, 23, 23, 45, 50, 79, 79, +120, 79, 100, 120, 79, 100, 66, 53, 23, 23, 125, 203, 248, 249, 248, 248, 248, 248, 235, 248, +250, 240, 248, 248, 250, 240, 247, 247, 231, 213, 229, 249, 179, 248, 250, 249, 249, 228, 208, 206, +214, 225, 79, 86, 100, 95, 78, 100, 104, 95, 23, 23, 42, 119, 70, 57, 23, 57, 82, 95, +42, 21, 23, 90, 95, 79, 95, 104, 79, 94, 94, 47, 21, 119, 78, 110, 87, 73, 95, 87, +79, 95, 69, 21, 95, 59, 79, 95, 69, 18, 23, 23, 75, 52, 27, 21, 78, 95, 59, 41, +42, 49, 39, 49, 38, 59, 119, 100, 128, 118, 223, 233, 251, 208, 244, 247, 247, 216, 199, 205, +214, 214, 205, 202, 203, 206, 206, 204, 210, 135, 78, 39, 39, 39, 58, 82, 43, 41, 18, 41, +42, 100, 94, 95, 94, 20, 20, 26, 48, 47, 80, 95, 89, 78, 58, 49, 95, 104, 78, 16, +48, 23, 18, 42, 39, 49, 49, 23, 49, 58, 102, 48, 47, 42, 119, 95, 95, 78, 100, 95, +78, 76, 66, 208, 209, 200, 127, 213, 182, 183, 209, 179, 209, 183, 195, 184, 220, 212, 78, 101, +100, 78, 95, 84, 79, 58, 95, 95, 78, 95, 82, 82, 100, 79, 79, 47, 48, 52, 58, 79, +78, 78, 59, 78, 95, 100, 78, 31, 48, 52, 90, 79, 79, 95, 100, 95, 78, 27, 48, 52, +42, 18, 49, 23, 79, 59, 95, 59, 79, 21, 47, 48, 27, 42, 79, 95, 95, 79, 79, 119, +79, 95, 42, 42, 23, 21, 197, 220, 2, 2, 253, 248, 249, 2, 235, 250, 250, 213, 213, 2, +2, 250, 250, 250, 248, 227, 240, 240, 248, 240, 247, 247, 247, 249, 192, 222, 199, 249, 79, 86, +95, 95, 83, 95, 95, 90, 23, 49, 58, 101, 69, 12, 23, 57, 219, 34, 19, 39, 62, 94, +95, 77, 86, 83, 79, 88, 100, 48, 54, 107, 79, 104, 86, 83, 80, 86, 78, 86, 21, 21, +84, 58, 79, 89, 58, 18, 42, 23, 67, 54, 53, 18, 95, 95, 57, 18, 18, 18, 42, 18, +42, 79, 139, 105, 133, 141, 193, 233, 236, 235, 245, 248, 228, 239, 216, 227, 223, 205, 225, 192, +211, 206, 203, 206, 198, 215, 38, 78, 39, 39, 46, 92, 41, 14, 19, 42, 78, 95, 80, 95, +80, 21, 21, 27, 54, 67, 95, 80, 98, 78, 70, 18, 98, 119, 58, 47, 54, 61, 18, 20, +21, 49, 23, 49, 49, 57, 102, 52, 47, 20, 95, 95, 95, 78, 95, 95, 78, 95, 242, 200, +192, 192, 194, 196, 192, 192, 209, 209, 209, 209, 192, 198, 200, 127, 105, 73, 95, 82, 79, 80, +119, 39, 20, 82, 100, 79, 82, 78, 95, 82, 79, 82, 47, 26, 78, 58, 78, 79, 58, 78, +58, 95, 79, 80, 16, 44, 95, 95, 62, 104, 79, 119, 58, 18, 27, 20, 21, 49, 23, 84, +65, 23, 119, 42, 78, 18, 42, 42, 42, 42, 79, 79, 119, 79, 78, 119, 78, 95, 62, 23, +23, 49, 193, 208, 2, 250, 116, 1, 1, 2, 228, 235, 230, 127, 248, 245, 2, 253, 248, 253, +247, 248, 250, 248, 247, 247, 250, 248, 239, 182, 187, 220, 187, 54, 47, 78, 98, 104, 78, 98, +94, 95, 21, 39, 42, 99, 29, 241, 23, 56, 28, 5, 38, 17, 58, 94, 98, 70, 95, 104, +77, 89, 83, 67, 67, 89, 76, 94, 98, 77, 71, 100, 70, 79, 52, 54, 92, 59, 78, 95, +63, 19, 20, 42, 16, 52, 44, 49, 79, 88, 59, 26, 26, 42, 39, 39, 39, 77, 119, 90, +150, 138, 197, 233, 237, 232, 240, 233, 245, 217, 199, 236, 191, 206, 213, 237, 215, 180, 184, 206, +206, 189, 98, 20, 70, 38, 83, 74, 71, 88, 83, 101, 104, 57, 86, 98, 96, 52, 54, 44, +26, 58, 104, 86, 95, 86, 58, 38, 95, 101, 76, 41, 19, 18, 38, 38, 49, 39, 49, 23, +38, 59, 87, 19, 18, 42, 104, 95, 86, 78, 95, 95, 77, 100, 233, 205, 192, 200, 188, 198, +192, 186, 192, 200, 217, 200, 209, 192, 208, 179, 192, 25, 73, 100, 95, 79, 118, 42, 42, 212, +206, 215, 100, 95, 79, 82, 82, 79, 62, 18, 78, 58, 78, 78, 79, 58, 90, 42, 95, 100, +79, 49, 104, 78, 69, 119, 95, 95, 70, 18, 49, 49, 38, 42, 79, 60, 42, 98, 39, 42, +79, 20, 42, 39, 21, 84, 84, 95, 95, 79, 100, 119, 79, 95, 49, 23, 49, 23, 34, 220, +249, 253, 1, 179, 127, 209, 217, 224, 1, 226, 248, 250, 227, 176, 253, 179, 248, 230, 238, 250, +1, 2, 2, 250, 225, 186, 204, 205, 217, 54, 83, 78, 94, 104, 77, 100, 94, 86, 21, 39, +38, 98, 5, 29, 23, 40, 88, 88, 49, 39, 58, 90, 88, 77, 87, 94, 70, 96, 89, 46, +42, 104, 77, 104, 86, 77, 83, 89, 78, 86, 57, 27, 87, 78, 78, 95, 27, 48, 52, 42, +17, 49, 18, 39, 79, 104, 69, 52, 54, 27, 39, 19, 79, 52, 114, 107, 130, 141, 231, 239, +210, 247, 240, 241, 227, 190, 180, 184, 184, 212, 198, 184, 200, 200, 195, 212, 206, 206, 178, 145, +61, 56, 73, 96, 69, 47, 52, 69, 40, 58, 94, 94, 88, 46, 61, 58, 39, 20, 89, 86, +98, 87, 57, 38, 94, 110, 78, 18, 38, 38, 38, 20, 19, 39, 21, 21, 21, 70, 80, 18, +41, 42, 104, 94, 95, 80, 89, 94, 68, 120, 206, 211, 219, 197, 192, 203, 200, 192, 200, 186, +193, 194, 217, 187, 194, 200, 232, 178, 83, 110, 86, 76, 119, 40, 33, 225, 220, 206, 29, 70, +78, 79, 95, 100, 79, 95, 70, 100, 58, 78, 70, 95, 78, 81, 31, 84, 87, 95, 104, 76, +59, 104, 87, 119, 78, 38, 39, 38, 42, 78, 69, 59, 90, 42, 38, 59, 77, 49, 42, 59, +82, 90, 100, 79, 90, 100, 78, 110, 78, 105, 42, 23, 23, 49, 21, 51, 206, 232, 235, 127, +253, 249, 249, 245, 235, 227, 249, 249, 201, 225, 253, 1, 155, 1, 2, 1, 179, 127, 249, 217, +200, 200, 198, 213, 238, 13, 83, 80, 104, 104, 77, 86, 94, 90, 58, 39, 58, 95, 71, 40, +42, 40, 88, 104, 38, 21, 21, 86, 87, 78, 88, 94, 77, 88, 90, 48, 54, 93, 78, 104, +98, 76, 72, 95, 77, 94, 41, 21, 87, 59, 78, 80, 65, 54, 54, 19, 42, 39, 39, 23, +77, 98, 16, 54, 54, 26, 39, 39, 79, 145, 109, 140, 142, 167, 231, 239, 236, 236, 244, 247, +206, 198, 213, 208, 198, 218, 203, 202, 200, 192, 199, 184, 198, 184, 206, 202, 125, 125, 143, 89, +65, 54, 54, 44, 20, 78, 86, 94, 94, 41, 41, 38, 41, 38, 105, 86, 94, 87, 57, 38, +94, 104, 76, 41, 38, 38, 38, 19, 38, 39, 49, 39, 39, 78, 88, 41, 18, 41, 96, 94, +86, 76, 94, 94, 68, 24, 184, 211, 237, 215, 236, 192, 192, 196, 192, 197, 206, 203, 209, 200, +209, 217, 183, 173, 119, 110, 95, 76, 119, 41, 127, 203, 184, 206, 37, 68, 59, 119, 77, 105, +78, 73, 79, 76, 98, 69, 79, 78, 87, 47, 54, 52, 73, 87, 94, 78, 70, 104, 95, 104, +77, 38, 38, 39, 95, 73, 58, 101, 57, 38, 38, 58, 79, 38, 23, 46, 90, 95, 77, 90, +107, 73, 95, 119, 78, 90, 42, 95, 21, 23, 42, 42, 28, 251, 208, 232, 234, 234, 247, 240, +238, 250, 249, 224, 214, 249, 1, 253, 249, 248, 253, 248, 201, 214, 249, 213, 182, 186, 186, 225, +116, 54, 82, 80, 94, 88, 77, 98, 86, 98, 21, 42, 58, 88, 71, 40, 42, 88, 88, 99, +19, 39, 42, 98, 86, 78, 86, 94, 77, 104, 90, 67, 67, 106, 78, 99, 87, 87, 76, 86, +76, 94, 57, 41, 87, 57, 78, 86, 68, 26, 57, 42, 41, 38, 39, 39, 78, 95, 68, 26, +26, 38, 38, 58, 77, 85, 114, 141, 152, 162, 214, 234, 239, 240, 225, 233, 236, 208, 225, 208, +184, 191, 208, 200, 208, 189, 206, 204, 206, 184, 184, 206, 198, 207, 148, 94, 57, 52, 54, 15, +73, 71, 70, 104, 104, 41, 41, 38, 17, 21, 88, 98, 98, 95, 70, 17, 88, 92, 73, 41, +38, 15, 44, 41, 39, 42, 21, 17, 21, 78, 86, 41, 17, 38, 104, 104, 94, 76, 98, 86, +73, 109, 228, 206, 215, 231, 211, 204, 186, 186, 192, 182, 189, 207, 182, 192, 197, 192, 200, 167, +95, 104, 86, 77, 99, 41, 175, 206, 210, 201, 207, 59, 41, 95, 83, 119, 68, 38, 73, 58, +76, 100, 88, 73, 70, 65, 54, 67, 83, 87, 98, 87, 57, 110, 77, 104, 70, 38, 21, 73, +72, 38, 72, 57, 19, 38, 42, 95, 69, 38, 82, 95, 104, 69, 90, 107, 78, 90, 119, 69, +95, 100, 68, 83, 21, 49, 21, 18, 42, 45, 100, 51, 51, 175, 220, 204, 208, 228, 247, 1, +1, 1, 2, 253, 188, 202, 253, 249, 213, 239, 236, 176, 127, 204, 183, 200, 54, 54, 81, 86, +94, 104, 71, 94, 98, 98, 42, 20, 57, 94, 71, 56, 21, 71, 88, 104, 19, 21, 49, 89, +98, 78, 76, 94, 70, 104, 71, 47, 21, 90, 73, 104, 98, 77, 76, 87, 78, 88, 58, 39, +77, 70, 78, 86, 68, 39, 21, 17, 39, 42, 52, 26, 95, 88, 63, 57, 39, 38, 58, 70, +85, 114, 114, 142, 162, 149, 242, 239, 247, 235, 232, 240, 192, 192, 208, 236, 184, 212, 228, 206, +201, 200, 188, 206, 184, 210, 211, 210, 184, 198, 37, 95, 56, 41, 52, 67, 60, 38, 57, 89, +96, 38, 38, 41, 38, 21, 104, 94, 98, 76, 70, 41, 101, 67, 54, 15, 26, 52, 52, 41, +38, 39, 21, 21, 17, 70, 86, 15, 52, 49, 89, 94, 86, 76, 105, 80, 78, 242, 232, 231, +194, 227, 212, 196, 183, 200, 192, 192, 199, 192, 197, 206, 189, 200, 221, 175, 95, 99, 94, 77, +128, 40, 29, 233, 208, 191, 206, 135, 17, 78, 89, 110, 76, 21, 72, 73, 17, 69, 78, 80, +81, 65, 44, 69, 87, 98, 86, 87, 58, 104, 87, 104, 70, 38, 87, 70, 38, 83, 58, 38, +39, 69, 90, 70, 68, 87, 83, 96, 80, 95, 105, 72, 95, 90, 86, 95, 95, 60, 60, 95, +21, 42, 49, 21, 17, 41, 71, 76, 70, 21, 37, 221, 208, 249, 248, 249, 2, 2, 249, 249, +213, 213, 249, 249, 226, 191, 191, 192, 249, 213, 200, 187, 21, 52, 63, 86, 94, 104, 69, 80, +98, 86, 21, 20, 58, 94, 71, 40, 21, 56, 88, 104, 38, 17, 21, 94, 94, 77, 86, 94, +77, 94, 90, 52, 54, 106, 95, 104, 86, 77, 77, 98, 77, 89, 57, 17, 87, 70, 70, 86, +70, 38, 42, 21, 21, 52, 54, 46, 68, 89, 68, 38, 38, 70, 73, 95, 115, 109, 109, 141, +154, 236, 236, 231, 204, 235, 236, 213, 217, 187, 228, 240, 222, 236, 210, 184, 237, 206, 184, 203, +206, 180, 210, 210, 184, 210, 251, 28, 68, 61, 54, 54, 19, 41, 69, 104, 96, 41, 38, 41, +38, 39, 94, 86, 94, 87, 56, 38, 89, 54, 54, 69, 20, 54, 54, 19, 41, 39, 49, 42, +21, 57, 86, 46, 54, 54, 76, 94, 76, 87, 88, 88, 3, 239, 205, 208, 186, 185, 197, 196, +211, 198, 208, 192, 191, 185, 208, 208, 208, 209, 224, 127, 87, 110, 86, 76, 99, 57, 41, 193, +205, 227, 180, 29, 17, 77, 98, 110, 47, 42, 85, 77, 38, 70, 76, 77, 85, 54, 26, 41, +72, 87, 104, 76, 70, 94, 95, 104, 70, 63, 80, 58, 90, 57, 17, 39, 19, 90, 57, 17, +77, 83, 96, 89, 83, 89, 80, 83, 101, 80, 95, 80, 60, 81, 69, 72, 21, 49, 21, 42, +38, 41, 88, 72, 69, 44, 54, 3, 252, 231, 238, 248, 211, 223, 236, 215, 253, 214, 201, 214, +239, 219, 78, 219, 222, 194, 208, 173, 54, 54, 82, 86, 94, 94, 76, 98, 94, 98, 42, 39, +58, 88, 71, 56, 42, 56, 71, 104, 39, 49, 42, 98, 98, 78, 87, 94, 70, 94, 86, 52, +54, 99, 83, 88, 98, 77, 76, 98, 77, 94, 57, 39, 87, 57, 70, 86, 68, 39, 21, 42, +39, 61, 54, 44, 70, 94, 70, 41, 70, 58, 95, 78, 112, 157, 156, 152, 178, 239, 246, 235, +236, 235, 217, 200, 192, 209, 203, 206, 203, 211, 206, 198, 210, 206, 196, 199, 195, 206, 215, 180, +180, 180, 251, 170, 80, 71, 26, 61, 41, 38, 77, 88, 110, 41, 41, 41, 38, 17, 94, 94, +86, 87, 57, 41, 94, 60, 61, 89, 41, 44, 43, 38, 41, 17, 21, 39, 39, 78, 88, 15, +61, 46, 94, 94, 80, 87, 88, 51, 233, 222, 208, 208, 194, 204, 183, 192, 182, 192, 186, 196, +206, 198, 191, 185, 184, 206, 204, 200, 115, 106, 80, 76, 110, 56, 19, 206, 198, 195, 210, 251, +25, 77, 98, 88, 67, 54, 67, 72, 39, 78, 78, 77, 52, 54, 16, 41, 98, 87, 98, 86, +57, 104, 87, 104, 77, 80, 19, 72, 57, 41, 38, 42, 95, 69, 17, 78, 90, 89, 73, 83, +80, 73, 90, 80, 73, 95, 81, 69, 60, 69, 82, 26, 49, 42, 21, 49, 17, 41, 94, 76, +70, 41, 67, 47, 125, 233, 228, 217, 207, 198, 231, 223, 237, 208, 208, 208, 194, 70, 76, 5, +207, 198, 220, 7, 54, 54, 60, 86, 94, 98, 70, 98, 98, 98, 21, 42, 58, 94, 68, 56, +42, 71, 88, 106, 17, 21, 21, 94, 83, 76, 86, 94, 78, 104, 86, 63, 20, 94, 77, 94, +80, 72, 77, 89, 76, 98, 16, 21, 80, 65, 21, 90, 70, 17, 21, 49, 39, 17, 19, 19, +52, 52, 83, 68, 70, 100, 115, 90, 105, 143, 114, 115, 239, 233, 231, 1, 240, 234, 235, 192, +187, 192, 211, 212, 208, 184, 211, 191, 204, 215, 184, 198, 206, 200, 203, 206, 203, 206, 206, 178, +80, 71, 41, 41, 19, 60, 72, 38, 117, 41, 38, 38, 41, 39, 88, 94, 94, 87, 56, 38, +96, 56, 38, 76, 68, 41, 41, 41, 41, 39, 42, 21, 21, 70, 86, 19, 42, 21, 89, 89, +80, 86, 89, 3, 239, 222, 203, 223, 223, 205, 208, 200, 192, 186, 186, 206, 184, 191, 206, 225, +194, 184, 184, 225, 179, 103, 119, 76, 99, 41, 14, 239, 207, 191, 202, 198, 100, 77, 86, 110, +73, 46, 60, 77, 38, 70, 77, 86, 73, 44, 57, 83, 38, 105, 80, 87, 70, 104, 76, 104, +77, 76, 90, 69, 42, 26, 58, 90, 69, 57, 95, 90, 80, 90, 95, 83, 101, 80, 83, 96, +95, 63, 73, 83, 72, 69, 69, 72, 49, 21, 42, 21, 20, 41, 88, 46, 52, 19, 38, 17, +38, 178, 220, 236, 204, 211, 223, 249, 211, 218, 222, 148, 118, 72, 68, 108, 178, 241, 220, 10, +19, 44, 73, 94, 94, 94, 70, 104, 80, 98, 42, 49, 58, 88, 71, 56, 21, 56, 71, 104, +39, 42, 49, 90, 94, 78, 71, 87, 70, 104, 80, 57, 17, 94, 95, 104, 87, 77, 72, 90, +77, 83, 18, 54, 81, 52, 54, 93, 70, 38, 21, 42, 21, 39, 41, 21, 54, 54, 111, 70, +79, 109, 109, 107, 121, 173, 178, 229, 244, 194, 237, 222, 232, 225, 222, 192, 208, 231, 213, 227, +211, 198, 236, 198, 200, 213, 180, 180, 184, 200, 208, 188, 191, 191, 207, 175, 98, 71, 41, 26, +81, 81, 40, 38, 77, 77, 41, 38, 39, 21, 94, 94, 86, 87, 70, 38, 71, 47, 65, 73, +63, 46, 47, 41, 38, 39, 39, 42, 17, 70, 76, 46, 54, 67, 88, 104, 72, 83, 141, 178, +222, 222, 236, 227, 198, 206, 197, 192, 192, 196, 200, 196, 206, 198, 213, 238, 200, 185, 208, 213, +220, 208, 215, 10, 129, 40, 16, 171, 208, 202, 199, 207, 66, 72, 98, 104, 77, 42, 78, 77, +41, 70, 77, 86, 68, 21, 96, 63, 78, 76, 98, 98, 58, 94, 87, 104, 73, 70, 96, 42, +48, 21, 80, 69, 17, 83, 69, 90, 89, 73, 83, 92, 82, 83, 89, 80, 83, 83, 90, 41, +73, 38, 73, 57, 42, 49, 21, 42, 49, 41, 89, 67, 54, 49, 41, 39, 21, 52, 175, 222, +178, 164, 221, 214, 237, 229, 239, 175, 99, 78, 72, 99, 145, 208, 233, 28, 42, 41, 70, 86, +98, 94, 70, 80, 98, 80, 21, 20, 38, 94, 71, 40, 21, 71, 88, 104, 41, 38, 19, 98, +86, 104, 88, 94, 77, 88, 94, 57, 17, 86, 83, 88, 98, 76, 77, 90, 72, 77, 52, 54, +89, 61, 54, 93, 70, 41, 39, 21, 39, 41, 38, 57, 54, 54, 107, 87, 90, 114, 157, 107, +119, 125, 233, 232, 217, 186, 232, 245, 179, 209, 240, 212, 180, 214, 208, 184, 184, 198, 206, 203, +214, 208, 188, 251, 205, 200, 206, 207, 211, 206, 210, 170, 78, 71, 26, 48, 67, 41, 41, 38, +41, 98, 78, 41, 39, 17, 104, 94, 94, 86, 57, 41, 58, 54, 48, 80, 43, 48, 54, 19, +39, 58, 21, 39, 21, 58, 88, 26, 52, 61, 94, 98, 86, 76, 104, 175, 233, 215, 222, 232, +222, 191, 192, 208, 192, 192, 192, 182, 185, 190, 240, 228, 181, 192, 192, 206, 36, 215, 221, 221, +51, 80, 42, 54, 127, 241, 198, 202, 4, 83, 86, 110, 76, 38, 94, 58, 16, 82, 68, 87, +68, 92, 63, 58, 88, 19, 104, 86, 69, 104, 87, 104, 77, 77, 94, 67, 54, 61, 77, 17, +78, 69, 77, 72, 83, 92, 83, 82, 80, 72, 95, 83, 70, 80, 58, 96, 19, 73, 76, 65, +49, 21, 42, 21, 26, 41, 88, 61, 54, 26, 38, 41, 39, 17, 38, 66, 62, 93, 222, 220, +180, 211, 220, 220, 100, 73, 87, 88, 97, 234, 9, 76, 17, 41, 63, 94, 86, 104, 71, 89, +86, 94, 42, 38, 57, 94, 71, 56, 42, 71, 71, 96, 60, 47, 69, 88, 86, 101, 129, 94, +78, 94, 88, 47, 52, 83, 77, 94, 98, 76, 87, 86, 77, 86, 57, 58, 72, 70, 65, 86, +69, 38, 21, 42, 17, 21, 21, 26, 96, 111, 110, 87, 98, 90, 119, 105, 193, 206, 184, 235, +209, 225, 236, 247, 214, 209, 247, 236, 225, 235, 225, 191, 210, 206, 210, 206, 210, 203, 208, 210, +180, 211, 198, 206, 184, 180, 36, 175, 87, 72, 18, 52, 93, 19, 40, 38, 41, 19, 76, 105, +41, 38, 98, 94, 86, 86, 57, 38, 20, 67, 67, 43, 57, 61, 61, 19, 38, 78, 39, 38, +39, 78, 86, 46, 54, 54, 80, 88, 86, 76, 94, 3, 243, 217, 227, 245, 192, 203, 240, 211, +191, 192, 186, 204, 197, 231, 239, 239, 216, 192, 192, 183, 185, 199, 200, 232, 192, 94, 89, 61, +26, 49, 125, 207, 210, 75, 80, 104, 86, 89, 57, 21, 54, 67, 69, 87, 76, 80, 70, 80, +19, 65, 74, 80, 57, 104, 76, 104, 77, 78, 104, 65, 46, 44, 78, 78, 69, 19, 87, 94, +96, 73, 82, 72, 107, 73, 73, 76, 77, 83, 72, 19, 73, 69, 72, 60, 42, 21, 49, 42, +38, 38, 94, 72, 69, 19, 42, 21, 39, 42, 21, 17, 63, 87, 84, 10, 3, 218, 175, 241, +24, 78, 87, 104, 77, 237, 4, 65, 52, 52, 78, 86, 94, 86, 86, 98, 87, 104, 58, 16, +60, 117, 71, 56, 42, 88, 88, 117, 115, 109, 47, 98, 87, 104, 110, 128, 78, 88, 90, 21, +54, 93, 95, 89, 90, 87, 95, 98, 71, 98, 41, 21, 87, 70, 58, 86, 70, 17, 21, 49, +49, 21, 54, 85, 100, 133, 128, 98, 95, 119, 119, 178, 201, 208, 225, 250, 208, 225, 236, 236, +239, 232, 212, 245, 232, 245, 208, 195, 203, 211, 211, 208, 211, 184, 215, 211, 210, 241, 190, 210, +184, 251, 251, 175, 76, 71, 21, 42, 69, 74, 81, 82, 60, 82, 82, 90, 73, 41, 94, 88, +89, 111, 68, 40, 39, 83, 76, 68, 68, 38, 17, 38, 38, 39, 21, 39, 39, 57, 86, 44, +67, 61, 89, 94, 76, 87, 86, 115, 232, 232, 248, 249, 2, 248, 214, 211, 206, 194, 193, 191, +182, 249, 209, 212, 225, 228, 192, 176, 200, 208, 192, 208, 191, 72, 101, 81, 41, 41, 24, 36, +36, 25, 76, 88, 104, 88, 38, 44, 54, 67, 68, 87, 86, 76, 94, 86, 26, 52, 52, 98, +70, 94, 86, 105, 76, 77, 99, 21, 42, 16, 77, 56, 52, 21, 74, 94, 106, 76, 77, 110, +80, 81, 87, 96, 57, 72, 19, 95, 57, 101, 64, 41, 49, 42, 21, 21, 39, 41, 110, 77, +78, 46, 54, 21, 21, 49, 49, 38, 70, 76, 76, 86, 82, 75, 58, 95, 95, 87, 98, 104, +73, 125, 4, 81, 54, 54, 65, 88, 88, 86, 86, 80, 98, 86, 26, 54, 115, 117, 88, 56, +21, 88, 93, 138, 114, 109, 67, 87, 106, 129, 111, 94, 77, 94, 86, 61, 61, 96, 78, 94, +89, 77, 86, 98, 86, 86, 58, 39, 87, 68, 70, 86, 68, 38, 21, 42, 21, 61, 54, 61, +105, 133, 141, 119, 120, 139, 175, 202, 232, 232, 225, 236, 211, 222, 236, 233, 234, 221, 203, 206, +206, 204, 196, 198, 205, 195, 199, 208, 190, 191, 191, 188, 208, 195, 210, 184, 184, 215, 206, 184, +58, 71, 52, 54, 26, 57, 81, 64, 81, 80, 74, 89, 94, 77, 86, 94, 60, 93, 74, 73, +38, 86, 86, 56, 68, 68, 79, 70, 70, 39, 17, 21, 17, 78, 94, 41, 19, 39, 104, 101, +86, 76, 89, 95, 3, 234, 234, 253, 216, 194, 206, 206, 182, 193, 191, 191, 190, 213, 245, 229, +213, 234, 244, 173, 182, 211, 185, 208, 3, 94, 65, 81, 90, 58, 96, 28, 34, 72, 88, 104, +94, 86, 41, 38, 19, 57, 70, 76, 87, 77, 86, 86, 26, 54, 54, 73, 70, 104, 86, 99, +77, 70, 96, 54, 54, 82, 70, 69, 67, 54, 92, 98, 110, 76, 78, 105, 88, 72, 72, 58, +80, 57, 73, 80, 92, 60, 41, 57, 21, 21, 42, 49, 21, 20, 104, 77, 69, 26, 54, 61, +42, 41, 14, 41, 57, 86, 87, 94, 70, 42, 57, 86, 88, 77, 87, 88, 69, 171, 140, 95, +61, 67, 58, 9, 194, 113, 80, 98, 87, 90, 69, 54, 54, 133, 89, 56, 79, 88, 142, 100, +66, 112, 82, 94, 130, 119, 141, 86, 70, 94, 80, 21, 52, 60, 68, 86, 94, 70, 87, 94, +87, 98, 58, 17, 87, 70, 70, 87, 70, 39, 42, 21, 39, 39, 26, 78, 129, 141, 133, 119, +139, 143, 211, 235, 235, 237, 220, 239, 241, 239, 236, 212, 192, 209, 179, 212, 198, 206, 203, 196, +206, 198, 203, 204, 193, 210, 198, 208, 185, 198, 203, 211, 210, 184, 206, 207, 37, 89, 81, 69, +58, 41, 19, 57, 19, 41, 38, 57, 89, 95, 86, 88, 87, 72, 96, 89, 76, 63, 96, 69, +92, 80, 86, 87, 38, 17, 39, 39, 39, 57, 86, 41, 19, 19, 104, 104, 86, 86, 88, 88, +113, 239, 216, 227, 205, 235, 204, 169, 215, 197, 184, 219, 178, 206, 245, 1, 178, 211, 173, 176, +195, 184, 210, 202, 3, 80, 87, 78, 89, 87, 99, 79, 24, 72, 98, 104, 104, 86, 38, 39, +17, 58, 68, 87, 87, 76, 83, 86, 19, 46, 60, 92, 69, 92, 83, 105, 77, 78, 110, 60, +44, 58, 73, 68, 69, 26, 87, 89, 110, 77, 76, 110, 87, 87, 80, 72, 46, 73, 70, 90, +63, 57, 56, 57, 42, 42, 21, 42, 42, 19, 88, 76, 77, 39, 120, 39, 17, 242, 242, 59, +70, 76, 86, 86, 95, 39, 57, 98, 94, 77, 98, 86, 87, 133, 61, 16, 52, 48, 207, 239, +178, 117, 83, 94, 87, 94, 58, 16, 90, 139, 24, 98, 79, 71, 117, 150, 49, 66, 65, 128, +128, 129, 117, 87, 78, 94, 76, 85, 67, 15, 70, 86, 105, 76, 87, 98, 76, 98, 57, 38, +86, 69, 78, 86, 68, 38, 39, 42, 39, 58, 69, 57, 129, 141, 133, 122, 119, 175, 198, 234, +239, 184, 205, 236, 233, 227, 225, 200, 200, 127, 215, 203, 203, 206, 206, 210, 184, 206, 216, 217, +192, 198, 198, 203, 206, 184, 188, 206, 210, 210, 215, 184, 210, 160, 80, 81, 61, 74, 93, 74, +74, 92, 74, 93, 90, 72, 87, 87, 110, 87, 77, 101, 98, 77, 89, 89, 93, 138, 83, 70, +19, 39, 38, 38, 17, 58, 94, 40, 38, 38, 88, 98, 89, 80, 94, 88, 242, 232, 190, 205, +249, 225, 217, 214, 223, 184, 170, 191, 187, 218, 236, 225, 216, 220, 171, 226, 231, 189, 211, 205, +175, 87, 79, 87, 78, 98, 104, 47, 48, 85, 87, 94, 104, 88, 38, 38, 38, 57, 70, 87, +94, 78, 80, 86, 38, 39, 16, 54, 82, 96, 90, 94, 87, 78, 104, 58, 21, 58, 77, 70, +38, 58, 101, 95, 99, 70, 77, 110, 76, 77, 96, 14, 21, 61, 83, 80, 20, 19, 57, 41, +42, 18, 42, 21, 42, 41, 81, 78, 66, 59, 100, 135, 24, 23, 4, 206, 58, 76, 76, 86, +87, 38, 58, 128, 110, 73, 87, 128, 103, 178, 208, 248, 109, 248, 239, 193, 89, 76, 98, 94, +76, 104, 58, 66, 75, 100, 95, 71, 21, 71, 71, 128, 60, 85, 102, 130, 128, 119, 141, 104, +78, 88, 86, 61, 52, 41, 69, 87, 98, 87, 76, 98, 98, 87, 57, 38, 87, 68, 58, 86, +76, 38, 17, 21, 39, 16, 67, 97, 120, 138, 150, 122, 139, 193, 207, 192, 212, 186, 236, 239, +233, 218, 228, 200, 194, 192, 211, 211, 208, 191, 184, 210, 207, 214, 204, 185, 196, 205, 190, 210, +206, 190, 185, 206, 184, 36, 184, 210, 251, 36, 84, 60, 73, 81, 60, 81, 81, 81, 60, 60, +80, 90, 86, 87, 86, 98, 110, 104, 90, 110, 70, 80, 83, 106, 133, 70, 41, 17, 38, 38, +38, 77, 94, 38, 38, 39, 94, 105, 86, 76, 88, 88, 125, 232, 227, 232, 2, 249, 231, 213, +217, 127, 190, 169, 219, 184, 215, 236, 214, 200, 193, 233, 208, 215, 227, 194, 153, 102, 95, 78, +86, 87, 104, 61, 67, 67, 76, 104, 104, 86, 38, 17, 39, 58, 70, 86, 86, 76, 86, 86, +17, 39, 61, 54, 67, 94, 76, 104, 95, 83, 69, 70, 41, 21, 78, 70, 41, 89, 73, 101, +83, 80, 77, 104, 86, 77, 104, 85, 54, 61, 72, 41, 20, 18, 41, 18, 23, 23, 51, 10, +7, 5, 4, 5, 10, 13, 52, 103, 125, 24, 17, 24, 68, 87, 87, 98, 87, 39, 57, 98, +104, 105, 163, 220, 220, 220, 206, 223, 155, 238, 249, 99, 80, 76, 88, 94, 87, 94, 58, 47, +46, 111, 88, 56, 42, 71, 99, 94, 54, 109, 115, 139, 129, 118, 138, 104, 73, 104, 80, 52, +54, 26, 70, 86, 94, 87, 95, 104, 86, 86, 57, 17, 87, 77, 58, 86, 70, 41, 39, 21, +39, 67, 109, 85, 137, 152, 162, 133, 175, 239, 240, 239, 213, 211, 211, 191, 234, 208, 217, 194, +191, 191, 199, 195, 192, 200, 188, 203, 213, 199, 190, 204, 185, 191, 207, 206, 206, 198, 198, 190, +208, 203, 184, 210, 191, 222, 125, 93, 108, 93, 92, 93, 92, 93, 92, 107, 90, 95, 104, 83, +110, 94, 104, 133, 128, 105, 86, 73, 71, 96, 77, 110, 58, 38, 38, 39, 58, 58, 99, 38, +70, 78, 98, 105, 94, 76, 88, 86, 10, 207, 212, 222, 211, 215, 214, 212, 184, 194, 187, 169, +170, 184, 198, 213, 239, 192, 227, 206, 204, 192, 214, 218, 79, 100, 100, 79, 95, 86, 104, 68, +38, 83, 94, 94, 104, 86, 41, 39, 39, 57, 68, 86, 98, 73, 86, 86, 39, 17, 20, 44, +44, 92, 94, 94, 110, 104, 58, 73, 39, 58, 70, 70, 58, 105, 98, 86, 110, 78, 83, 94, +76, 73, 99, 73, 21, 72, 77, 39, 42, 23, 5, 35, 219, 241, 220, 220, 233, 29, 104, 76, +57, 61, 54, 52, 42, 49, 39, 17, 70, 87, 87, 86, 87, 39, 57, 105, 94, 88, 161, 221, +192, 212, 184, 247, 248, 223, 237, 92, 99, 88, 76, 86, 77, 94, 115, 54, 114, 94, 56, 56, +49, 71, 72, 96, 46, 54, 108, 139, 119, 119, 133, 95, 78, 86, 86, 61, 67, 20, 70, 86, +94, 76, 76, 105, 86, 95, 41, 19, 86, 77, 58, 76, 70, 38, 42, 21, 39, 66, 114, 92, +137, 141, 165, 139, 215, 222, 240, 208, 214, 233, 241, 195, 205, 222, 204, 214, 195, 207, 205, 199, +195, 213, 214, 195, 196, 191, 204, 208, 203, 212, 191, 184, 206, 219, 191, 191, 206, 185, 203, 196, +192, 228, 222, 20, 41, 19, 41, 41, 41, 41, 41, 73, 74, 92, 72, 90, 128, 120, 104, 110, +128, 119, 130, 104, 70, 56, 104, 77, 110, 70, 70, 70, 70, 78, 130, 77, 77, 58, 87, 104, +94, 86, 94, 100, 170, 206, 211, 190, 191, 213, 194, 191, 219, 178, 187, 175, 191, 205, 207, 192, +187, 213, 205, 211, 191, 213, 188, 219, 100, 33, 120, 78, 87, 79, 119, 69, 62, 81, 87, 104, +104, 86, 38, 21, 17, 58, 70, 87, 89, 96, 110, 86, 39, 21, 39, 21, 52, 52, 94, 94, +128, 69, 79, 52, 20, 58, 78, 70, 41, 86, 90, 94, 99, 73, 69, 63, 76, 77, 110, 56, +39, 95, 83, 17, 38, 21, 29, 251, 125, 10, 3, 175, 103, 41, 104, 78, 70, 19, 61, 26, +39, 42, 21, 38, 68, 76, 104, 76, 87, 39, 57, 87, 104, 95, 113, 233, 206, 184, 212, 213, +202, 222, 161, 114, 247, 247, 145, 97, 87, 147, 131, 54, 85, 88, 63, 56, 21, 56, 71, 99, +38, 21, 100, 141, 120, 120, 139, 129, 118, 117, 86, 83, 21, 38, 78, 87, 94, 87, 95, 88, +98, 76, 65, 47, 83, 72, 58, 52, 61, 20, 49, 62, 58, 58, 100, 78, 143, 152, 114, 103, +207, 198, 185, 214, 212, 237, 219, 184, 203, 182, 193, 200, 190, 197, 197, 195, 198, 185, 205, 206, +198, 198, 184, 212, 217, 190, 184, 206, 219, 210, 241, 215, 191, 198, 198, 198, 190, 198, 210, 79, +41, 38, 41, 38, 38, 39, 38, 17, 87, 88, 90, 87, 133, 129, 134, 99, 128, 104, 110, 141, +119, 73, 104, 110, 80, 89, 57, 38, 38, 77, 141, 68, 38, 39, 104, 104, 110, 77, 99, 51, +233, 203, 199, 208, 231, 223, 193, 187, 182, 193, 178, 178, 175, 206, 202, 193, 178, 222, 190, 214, +222, 203, 211, 218, 51, 143, 102, 84, 95, 100, 104, 47, 54, 52, 86, 104, 104, 88, 38, 17, +21, 58, 70, 110, 117, 95, 110, 104, 39, 79, 39, 26, 54, 67, 89, 128, 98, 69, 54, 109, +69, 58, 78, 68, 58, 87, 86, 105, 110, 63, 82, 52, 60, 71, 104, 72, 38, 72, 87, 18, +18, 10, 8, 27, 42, 18, 21, 18, 42, 16, 67, 46, 58, 70, 103, 10, 78, 79, 39, 70, +16, 52, 83, 99, 107, 47, 46, 118, 117, 172, 184, 211, 247, 206, 215, 208, 245, 54, 99, 106, +145, 3, 115, 145, 149, 159, 79, 79, 58, 94, 71, 56, 21, 56, 71, 94, 38, 17, 21, 141, +129, 120, 119, 118, 105, 138, 79, 104, 83, 65, 95, 80, 128, 77, 118, 94, 98, 95, 52, 54, +81, 78, 60, 54, 54, 19, 21, 49, 21, 100, 100, 95, 139, 151, 166, 202, 198, 184, 198, 191, +241, 237, 215, 206, 196, 186, 206, 191, 186, 209, 192, 192, 192, 187, 203, 191, 184, 206, 229, 213, +208, 192, 211, 198, 210, 184, 222, 223, 192, 202, 203, 203, 195, 207, 233, 49, 17, 39, 41, 38, +38, 70, 17, 38, 39, 76, 99, 87, 87, 118, 133, 128, 89, 133, 128, 133, 141, 118, 104, 95, +104, 73, 96, 70, 70, 77, 94, 41, 38, 78, 77, 128, 110, 104, 89, 51, 207, 207, 205, 193, +191, 184, 186, 187, 191, 219, 197, 204, 219, 180, 191, 178, 178, 184, 195, 225, 225, 197, 204, 197, +175, 113, 143, 102, 97, 139, 81, 95, 47, 74, 98, 105, 104, 94, 41, 38, 17, 58, 70, 110, +128, 94, 94, 80, 79, 21, 79, 70, 26, 81, 94, 94, 105, 78, 26, 81, 69, 78, 78, 70, +41, 87, 98, 86, 110, 70, 46, 54, 61, 86, 77, 89, 70, 83, 76, 77, 178, 222, 10, 16, +18, 42, 18, 49, 79, 61, 54, 115, 21, 62, 125, 175, 123, 103, 62, 79, 52, 54, 112, 120, +81, 54, 109, 168, 215, 203, 213, 200, 217, 231, 239, 253, 52, 138, 70, 128, 94, 105, 133, 157, +108, 104, 78, 39, 57, 94, 68, 56, 42, 56, 71, 99, 41, 39, 58, 130, 110, 119, 150, 118, +119, 138, 95, 90, 109, 109, 102, 128, 111, 133, 128, 139, 110, 101, 65, 61, 89, 76, 58, 67, +67, 19, 17, 21, 79, 79, 78, 95, 139, 152, 175, 246, 219, 203, 204, 206, 241, 241, 213, 196, +191, 182, 206, 184, 211, 205, 204, 185, 214, 200, 209, 187, 211, 213, 192, 191, 185, 203, 203, 204, +210, 210, 184, 198, 185, 206, 215, 208, 201, 211, 178, 39, 21, 42, 20, 39, 78, 38, 39, 21, +70, 38, 77, 94, 94, 110, 137, 128, 133, 104, 141, 141, 110, 141, 128, 94, 63, 108, 93, 106, +57, 58, 117, 41, 59, 70, 94, 94, 94, 104, 133, 125, 210, 191, 214, 214, 203, 191, 204, 170, +193, 185, 236, 207, 198, 205, 199, 178, 197, 206, 211, 195, 200, 197, 223, 218, 148, 135, 113, 122, +105, 95, 79, 94, 78, 98, 77, 104, 88, 80, 57, 38, 38, 57, 77, 110, 128, 104, 110, 106, +58, 79, 58, 69, 79, 115, 96, 119, 128, 98, 70, 70, 38, 78, 90, 70, 38, 87, 98, 94, +99, 73, 63, 60, 19, 46, 81, 90, 90, 88, 66, 233, 210, 233, 103, 52, 21, 21, 91, 24, +23, 10, 206, 122, 95, 82, 229, 193, 175, 123, 58, 59, 93, 114, 119, 175, 125, 157, 173, 220, +208, 175, 204, 208, 220, 242, 157, 109, 54, 65, 58, 104, 141, 119, 128, 133, 120, 96, 21, 39, +57, 94, 56, 56, 21, 71, 71, 104, 38, 41, 21, 130, 83, 129, 141, 142, 119, 149, 105, 100, +145, 109, 114, 129, 133, 133, 141, 141, 142, 110, 77, 21, 110, 87, 41, 95, 76, 38, 21, 49, +21, 58, 91, 95, 129, 152, 135, 233, 212, 203, 213, 234, 237, 206, 208, 190, 184, 206, 203, 195, +189, 213, 197, 203, 208, 205, 182, 198, 198, 196, 193, 196, 204, 198, 184, 210, 206, 206, 180, 206, +210, 210, 241, 206, 84, 95, 79, 39, 39, 39, 39, 38, 38, 39, 39, 39, 38, 38, 38, 77, +80, 111, 141, 133, 141, 133, 119, 138, 141, 118, 142, 117, 100, 96, 83, 72, 89, 58, 94, 76, +70, 77, 94, 94, 110, 119, 125, 205, 214, 216, 193, 186, 208, 211, 207, 192, 191, 206, 199, 185, +198, 215, 204, 192, 186, 198, 198, 198, 208, 212, 191, 206, 193, 103, 113, 102, 84, 119, 139, 77, +128, 87, 87, 70, 90, 96, 79, 49, 38, 58, 76, 119, 128, 94, 99, 104, 39, 21, 91, 95, +109, 114, 73, 141, 133, 94, 79, 70, 58, 58, 78, 70, 41, 76, 86, 94, 110, 70, 56, 38, +41, 48, 52, 94, 88, 110, 37, 251, 180, 207, 103, 85, 61, 100, 178, 233, 241, 206, 239, 4, +119, 145, 234, 206, 9, 100, 79, 70, 86, 121, 136, 139, 141, 120, 236, 190, 162, 151, 253, 246, +242, 106, 138, 54, 54, 79, 77, 104, 128, 129, 153, 128, 107, 107, 49, 17, 57, 104, 68, 56, +42, 56, 71, 99, 19, 41, 58, 104, 110, 120, 141, 142, 141, 149, 104, 119, 100, 136, 134, 152, +153, 141, 136, 138, 141, 139, 90, 58, 98, 87, 58, 88, 76, 38, 39, 21, 79, 70, 100, 82, +129, 149, 150, 210, 184, 205, 214, 208, 247, 222, 204, 155, 188, 211, 196, 208, 185, 203, 190, 222, +206, 185, 203, 205, 208, 211, 203, 213, 207, 198, 198, 191, 195, 205, 198, 241, 251, 211, 148, 95, +86, 77, 21, 39, 39, 78, 39, 39, 39, 39, 39, 79, 79, 39, 39, 38, 104, 149, 150, 133, +149, 128, 111, 130, 133, 128, 119, 133, 107, 104, 94, 104, 94, 138, 79, 94, 58, 70, 94, 106, +139, 125, 202, 195, 192, 190, 193, 195, 191, 211, 207, 195, 203, 203, 198, 198, 203, 206, 191, 208, +197, 191, 184, 212, 217, 214, 191, 222, 208, 175, 143, 103, 102, 120, 87, 119, 110, 119, 70, 57, +98, 96, 54, 67, 77, 77, 104, 110, 133, 119, 104, 119, 38, 79, 100, 77, 92, 92, 110, 80, +104, 104, 76, 70, 70, 58, 70, 76, 58, 87, 90, 88, 99, 78, 57, 41, 19, 67, 61, 89, +86, 108, 179, 206, 206, 175, 120, 58, 70, 100, 215, 206, 206, 210, 233, 178, 150, 143, 175, 206, +193, 143, 58, 70, 104, 76, 97, 141, 85, 223, 220, 172, 159, 138, 159, 154, 78, 107, 139, 121, +95, 79, 58, 104, 128, 129, 133, 130, 101, 104, 58, 41, 57, 94, 56, 56, 21, 56, 76, 105, +16, 23, 31, 94, 87, 121, 141, 128, 137, 158, 143, 100, 120, 142, 142, 152, 149, 141, 153, 149, +152, 133, 85, 100, 112, 73, 58, 80, 72, 41, 21, 49, 21, 79, 79, 115, 107, 152, 151, 241, +206, 189, 197, 239, 208, 208, 214, 217, 227, 190, 194, 186, 190, 196, 186, 203, 203, 208, 202, 197, +217, 203, 180, 210, 215, 184, 207, 207, 222, 205, 123, 91, 143, 120, 117, 128, 119, 105, 79, 21, +79, 21, 39, 39, 58, 58, 78, 39, 79, 39, 70, 70, 70, 104, 141, 141, 130, 138, 128, 110, +106, 149, 129, 106, 136, 128, 95, 118, 130, 110, 141, 94, 133, 87, 96, 138, 24, 206, 206, 204, +213, 212, 205, 203, 206, 184, 184, 184, 206, 184, 198, 203, 193, 190, 206, 196, 190, 223, 214, 197, +211, 188, 203, 193, 208, 185, 135, 115, 113, 119, 119, 119, 138, 110, 73, 47, 82, 89, 21, 26, +38, 77, 87, 110, 133, 110, 104, 117, 78, 120, 100, 73, 120, 100, 88, 38, 87, 77, 58, 58, +78, 58, 78, 70, 58, 77, 90, 81, 110, 87, 70, 39, 39, 39, 82, 92, 86, 145, 242, 210, +193, 91, 78, 73, 87, 91, 198, 206, 184, 206, 215, 207, 75, 173, 145, 241, 215, 123, 60, 73, +96, 122, 171, 94, 4, 220, 221, 103, 165, 149, 138, 141, 110, 118, 138, 98, 91, 48, 79, 139, +117, 142, 118, 128, 119, 105, 26, 23, 31, 98, 58, 57, 21, 56, 70, 101, 47, 54, 52, 95, +87, 120, 133, 137, 133, 149, 120, 166, 114, 141, 141, 153, 152, 152, 152, 149, 152, 137, 67, 109, +122, 110, 57, 81, 83, 38, 58, 79, 39, 26, 114, 54, 107, 141, 153, 0, 205, 192, 190, 212, +203, 205, 212, 208, 208, 208, 192, 208, 208, 200, 192, 203, 196, 197, 195, 198, 199, 205, 206, 184, +206, 207, 198, 36, 219, 175, 21, 120, 138, 128, 119, 142, 94, 77, 21, 39, 39, 21, 79, 79, +91, 78, 58, 78, 39, 79, 39, 39, 38, 70, 129, 149, 163, 142, 139, 141, 141, 128, 133, 141, +133, 141, 141, 104, 110, 133, 141, 138, 139, 141, 133, 138, 102, 206, 218, 192, 214, 197, 195, 190, +191, 198, 36, 184, 185, 203, 207, 195, 189, 206, 191, 212, 212, 197, 200, 190, 197, 207, 191, 198, +184, 222, 212, 145, 115, 139, 95, 110, 149, 119, 97, 54, 114, 90, 54, 52, 41, 58, 86, 87, +110, 110, 128, 128, 95, 120, 100, 107, 145, 109, 69, 83, 69, 77, 58, 39, 78, 78, 98, 77, +77, 83, 87, 94, 110, 78, 57, 21, 39, 58, 52, 59, 145, 232, 206, 241, 120, 120, 82, 134, +25, 251, 207, 211, 184, 206, 206, 233, 198, 166, 109, 125, 10, 125, 4, 22, 143, 144, 175, 139, +113, 166, 166, 140, 142, 139, 133, 133, 110, 137, 141, 105, 67, 109, 85, 128, 141, 129, 139, 133, +105, 104, 31, 54, 52, 86, 70, 38, 23, 78, 76, 118, 15, 66, 58, 95, 87, 87, 128, 143, +137, 149, 105, 112, 119, 142, 142, 152, 152, 158, 141, 162, 152, 141, 120, 95, 128, 110, 77, 87, +87, 38, 21, 79, 49, 49, 52, 26, 87, 133, 149, 242, 239, 193, 198, 191, 212, 190, 213, 205, +199, 199, 202, 202, 205, 196, 204, 182, 213, 186, 188, 196, 186, 199, 191, 211, 186, 212, 91, 135, +79, 100, 79, 21, 110, 129, 130, 141, 105, 78, 79, 21, 79, 49, 21, 78, 79, 79, 39, 58, +91, 58, 79, 78, 39, 58, 39, 106, 152, 147, 141, 152, 129, 104, 130, 150, 141, 128, 130, 141, +133, 111, 138, 130, 147, 96, 138, 138, 150, 204, 214, 191, 185, 202, 190, 211, 193, 210, 210, 198, +189, 185, 206, 206, 184, 207, 203, 195, 191, 190, 205, 214, 225, 231, 205, 198, 206, 215, 201, 193, +122, 153, 139, 119, 149, 128, 119, 67, 131, 106, 61, 46, 39, 58, 104, 110, 89, 118, 128, 138, +120, 123, 120, 95, 92, 108, 130, 99, 58, 65, 58, 21, 91, 95, 98, 78, 58, 104, 105, 86, +138, 94, 76, 79, 79, 58, 67, 157, 243, 207, 170, 75, 68, 140, 131, 112, 51, 233, 206, 203, +190, 206, 203, 203, 206, 135, 161, 123, 4, 175, 236, 0, 158, 215, 9, 152, 142, 101, 90, 128, +141, 133, 128, 133, 143, 129, 141, 101, 95, 97, 73, 128, 128, 137, 137, 139, 78, 94, 58, 27, +57, 95, 76, 57, 23, 56, 71, 110, 42, 21, 23, 94, 86, 95, 139, 137, 129, 152, 120, 120, +160, 142, 137, 152, 149, 141, 158, 149, 149, 133, 104, 100, 137, 110, 58, 77, 86, 38, 21, 49, +58, 52, 54, 85, 73, 128, 133, 103, 240, 227, 185, 206, 198, 214, 208, 195, 195, 208, 214, 204, +204, 202, 198, 204, 192, 199, 196, 208, 208, 185, 197, 191, 207, 103, 77, 95, 98, 78, 58, 78, +104, 128, 133, 141, 101, 79, 100, 100, 100, 58, 79, 100, 58, 39, 79, 79, 100, 100, 91, 78, +58, 38, 38, 69, 128, 149, 141, 142, 150, 138, 129, 141, 138, 150, 134, 152, 141, 143, 128, 138, +130, 149, 139, 149, 153, 208, 204, 197, 204, 205, 205, 195, 185, 191, 196, 211, 206, 184, 206, 210, +180, 211, 191, 206, 198, 198, 203, 213, 208, 231, 218, 198, 198, 184, 191, 202, 237, 153, 139, 110, +150, 133, 89, 59, 94, 86, 70, 39, 38, 77, 128, 110, 111, 105, 141, 141, 95, 95, 120, 98, +122, 115, 122, 72, 101, 112, 38, 70, 119, 141, 90, 139, 101, 95, 98, 139, 141, 119, 105, 100, +100, 95, 79, 171, 207, 148, 158, 135, 171, 137, 78, 104, 154, 171, 172, 218, 239, 190, 212, 211, +213, 113, 109, 115, 78, 110, 144, 53, 119, 102, 128, 133, 121, 100, 86, 133, 152, 110, 133, 141, +133, 141, 141, 119, 100, 79, 77, 133, 139, 129, 129, 133, 87, 104, 23, 42, 58, 89, 70, 56, +23, 71, 71, 110, 57, 39, 23, 105, 95, 87, 128, 95, 105, 138, 95, 98, 120, 142, 150, 152, +152, 158, 152, 162, 152, 139, 104, 78, 137, 128, 58, 87, 99, 70, 79, 21, 39, 46, 67, 16, +78, 87, 110, 87, 127, 221, 214, 211, 189, 202, 208, 196, 199, 185, 213, 214, 196, 198, 241, 206, +189, 207, 208, 188, 222, 215, 199, 206, 210, 51, 95, 95, 78, 78, 79, 95, 110, 129, 130, 141, +129, 78, 120, 95, 120, 95, 95, 95, 95, 95, 95, 95, 120, 100, 78, 78, 70, 39, 78, 78, +98, 153, 138, 130, 152, 141, 152, 152, 130, 138, 162, 128, 152, 138, 128, 139, 130, 133, 149, 133, +133, 202, 208, 214, 204, 190, 204, 204, 211, 212, 206, 184, 184, 206, 191, 206, 210, 184, 206, 184, +211, 211, 212, 193, 205, 214, 231, 208, 184, 206, 198, 185, 202, 212, 110, 150, 138, 130, 130, 98, +101, 96, 70, 39, 78, 95, 110, 119, 128, 110, 128, 138, 95, 120, 120, 120, 109, 109, 95, 105, +133, 70, 58, 100, 133, 110, 121, 104, 110, 78, 118, 130, 138, 110, 89, 120, 100, 120, 103, 233, +238, 156, 25, 241, 178, 87, 83, 97, 112, 112, 131, 10, 241, 207, 206, 206, 178, 140, 114, 136, +120, 78, 100, 78, 104, 118, 110, 129, 129, 78, 104, 141, 150, 133, 133, 141, 137, 142, 150, 119, +100, 58, 79, 133, 128, 118, 98, 139, 77, 105, 21, 49, 57, 94, 68, 56, 21, 71, 88, 142, +57, 21, 21, 95, 87, 87, 94, 129, 95, 133, 87, 87, 120, 133, 141, 152, 141, 141, 152, 149, +152, 133, 98, 100, 137, 119, 73, 87, 104, 39, 78, 78, 19, 38, 38, 41, 70, 87, 80, 77, +98, 125, 233, 197, 209, 204, 186, 197, 195, 191, 188, 192, 204, 237, 206, 198, 180, 185, 205, 195, +191, 206, 206, 184, 135, 119, 78, 95, 95, 78, 78, 78, 139, 134, 141, 141, 128, 95, 95, 100, +95, 160, 119, 119, 119, 143, 143, 119, 119, 95, 78, 95, 78, 78, 95, 101, 105, 98, 111, 141, +130, 152, 162, 149, 141, 152, 141, 152, 141, 152, 141, 138, 130, 149, 141, 162, 100, 233, 190, 204, +212, 199, 204, 214, 193, 207, 184, 207, 195, 206, 206, 211, 211, 203, 203, 206, 210, 206, 191, 198, +213, 214, 214, 200, 205, 236, 184, 184, 210, 206, 125, 128, 141, 150, 107, 133, 106, 80, 70, 78, +78, 79, 130, 110, 128, 128, 139, 138, 100, 120, 143, 95, 108, 131, 134, 130, 79, 69, 119, 128, +119, 147, 133, 104, 87, 78, 118, 133, 149, 128, 110, 95, 143, 171, 245, 246, 113, 165, 36, 239, +109, 101, 136, 136, 150, 111, 152, 142, 144, 35, 198, 206, 135, 129, 98, 98, 101, 78, 78, 78, +110, 118, 128, 133, 143, 100, 98, 128, 137, 141, 141, 141, 128, 152, 149, 101, 78, 78, 98, 128, +133, 95, 110, 110, 78, 105, 23, 21, 57, 94, 76, 71, 79, 88, 99, 138, 76, 39, 79, 105, +87, 120, 94, 98, 105, 141, 73, 100, 123, 129, 133, 141, 150, 133, 142, 141, 152, 128, 104, 100, +137, 110, 86, 104, 99, 77, 79, 79, 49, 21, 79, 38, 78, 86, 90, 76, 87, 171, 241, 239, +228, 200, 209, 192, 192, 200, 200, 204, 196, 197, 206, 211, 206, 184, 180, 191, 189, 206, 184, 206, +175, 105, 100, 78, 79, 100, 78, 95, 138, 121, 141, 152, 134, 143, 95, 119, 120, 120, 119, 143, +119, 119, 139, 153, 120, 120, 100, 78, 95, 78, 95, 105, 139, 107, 95, 141, 162, 165, 157, 163, +140, 158, 122, 136, 151, 147, 162, 141, 133, 161, 1, 212, 206, 180, 212, 192, 190, 184, 211, 192, +225, 192, 206, 208, 196, 198, 212, 190, 205, 211, 199, 191, 206, 204, 205, 191, 203, 225, 222, 227, +208, 240, 210, 184, 189, 206, 202, 178, 105, 138, 118, 150, 133, 104, 83, 59, 78, 95, 133, 128, +138, 110, 142, 138, 118, 120, 120, 105, 91, 100, 141, 94, 78, 100, 130, 118, 152, 143, 118, 78, +78, 100, 119, 134, 149, 128, 128, 120, 135, 233, 234, 171, 153, 150, 241, 217, 164, 162, 133, 105, +141, 141, 133, 152, 134, 171, 202, 233, 233, 91, 136, 120, 120, 100, 120, 98, 94, 105, 111, 133, +137, 100, 94, 128, 137, 133, 150, 141, 139, 141, 133, 101, 84, 115, 82, 128, 139, 118, 87, 110, +101, 94, 21, 39, 86, 139, 88, 78, 100, 88, 117, 149, 100, 78, 100, 139, 110, 96, 129, 143, +104, 137, 100, 109, 114, 101, 133, 129, 138, 133, 133, 150, 133, 110, 94, 77, 128, 133, 87, 120, +110, 69, 58, 21, 21, 54, 54, 39, 70, 87, 90, 83, 77, 144, 208, 239, 236, 209, 188, 199, +195, 192, 217, 199, 200, 213, 185, 193, 205, 210, 198, 206, 210, 184, 206, 169, 139, 139, 95, 95, +98, 95, 87, 105, 98, 129, 141, 134, 120, 98, 119, 119, 95, 95, 120, 129, 160, 129, 139, 119, +120, 120, 95, 78, 78, 95, 160, 119, 119, 118, 119, 134, 161, 233, 232, 234, 243, 239, 245, 235, +235, 179, 53, 167, 152, 236, 220, 206, 210, 211, 203, 199, 196, 191, 195, 205, 208, 190, 193, 210, +206, 184, 223, 222, 198, 184, 211, 198, 198, 205, 192, 208, 191, 208, 235, 225, 231, 228, 236, 191, +186, 199, 205, 237, 120, 149, 105, 141, 133, 128, 101, 78, 78, 77, 133, 141, 150, 110, 133, 138, +95, 123, 120, 101, 145, 109, 104, 94, 121, 133, 96, 165, 130, 141, 98, 87, 78, 101, 112, 130, +149, 141, 139, 119, 123, 28, 100, 143, 120, 171, 233, 231, 157, 158, 90, 122, 133, 142, 121, 136, +153, 141, 167, 241, 241, 4, 85, 166, 123, 143, 33, 27, 130, 118, 128, 128, 129, 78, 86, 128, +128, 133, 141, 141, 128, 133, 141, 100, 114, 109, 61, 141, 133, 119, 110, 139, 104, 139, 79, 78, +119, 141, 99, 99, 100, 99, 129, 149, 105, 120, 100, 141, 128, 128, 139, 137, 105, 133, 90, 61, +92, 119, 128, 153, 138, 129, 133, 133, 133, 143, 110, 78, 128, 133, 87, 128, 99, 79, 78, 100, +78, 73, 69, 39, 58, 87, 133, 104, 129, 120, 211, 239, 227, 214, 206, 198, 205, 195, 212, 213, +192, 208, 199, 207, 205, 206, 206, 241, 125, 191, 34, 135, 129, 119, 119, 119, 95, 95, 95, 123, +118, 143, 95, 120, 95, 119, 120, 105, 120, 119, 95, 143, 139, 139, 119, 95, 90, 120, 79, 78, +95, 119, 143, 95, 100, 78, 134, 109, 234, 215, 214, 214, 232, 225, 235, 232, 243, 239, 243, 225, +182, 233, 191, 184, 206, 184, 204, 192, 197, 184, 184, 198, 197, 204, 206, 180, 185, 191, 212, 223, +206, 184, 211, 191, 203, 203, 199, 190, 193, 211, 228, 227, 231, 249, 209, 208, 193, 206, 198, 202, +175, 149, 99, 152, 141, 119, 95, 98, 100, 95, 133, 141, 138, 111, 139, 152, 119, 143, 120, 119, +136, 114, 86, 120, 130, 130, 154, 34, 75, 104, 95, 78, 100, 142, 119, 152, 162, 152, 141, 119, +160, 153, 120, 163, 29, 252, 218, 158, 149, 141, 122, 114, 142, 143, 152, 152, 141, 128, 138, 175, +160, 59, 129, 25, 103, 147, 0, 4, 130, 133, 128, 128, 118, 73, 101, 121, 153, 141, 141, 138, +137, 133, 152, 90, 90, 85, 101, 111, 117, 118, 119, 141, 128, 141, 100, 120, 110, 141, 117, 105, +120, 99, 117, 149, 110, 120, 123, 152, 150, 133, 133, 137, 104, 73, 52, 79, 58, 110, 128, 137, +133, 119, 129, 138, 141, 105, 114, 100, 112, 133, 104, 137, 133, 58, 79, 78, 79, 91, 78, 58, +87, 87, 134, 117, 139, 4, 236, 236, 223, 222, 241, 241, 184, 184, 211, 187, 213, 184, 206, 219, +188, 207, 219, 119, 142, 129, 121, 129, 89, 105, 110, 105, 119, 100, 98, 101, 118, 98, 120, 119, +101, 107, 105, 119, 98, 101, 139, 139, 129, 139, 139, 105, 95, 78, 78, 78, 119, 143, 119, 120, +95, 101, 229, 235, 231, 210, 206, 184, 180, 198, 236, 206, 215, 206, 194, 204, 208, 185, 208, 199, +223, 191, 215, 196, 197, 193, 237, 197, 214, 192, 190, 211, 199, 206, 180, 208, 205, 184, 211, 205, +198, 206, 213, 204, 191, 184, 232, 211, 236, 208, 227, 191, 203, 190, 191, 189, 223, 136, 133, 141, +133, 128, 119, 119, 95, 119, 150, 130, 141, 106, 141, 141, 120, 120, 120, 105, 100, 119, 121, 159, +138, 162, 178, 233, 178, 142, 105, 119, 141, 137, 158, 128, 158, 141, 133, 95, 143, 120, 163, 160, +251, 247, 158, 162, 149, 165, 136, 161, 154, 152, 152, 152, 153, 129, 162, 142, 110, 119, 119, 75, +3, 3, 252, 254, 66, 142, 133, 110, 112, 84, 161, 105, 138, 133, 141, 141, 139, 141, 152, 105, +78, 100, 52, 69, 110, 118, 128, 141, 142, 153, 120, 123, 137, 158, 110, 117, 143, 107, 117, 159, +143, 119, 143, 152, 152, 141, 141, 137, 110, 69, 52, 54, 73, 100, 128, 137, 128, 133, 128, 141, +133, 129, 115, 109, 108, 133, 105, 104, 128, 95, 78, 78, 100, 78, 78, 49, 105, 138, 141, 148, +135, 241, 233, 222, 227, 239, 222, 241, 206, 184, 229, 247, 218, 184, 180, 184, 206, 125, 142, 142, +121, 134, 107, 121, 130, 112, 120, 107, 121, 121, 121, 121, 107, 121, 101, 119, 150, 142, 150, 121, +121, 142, 111, 129, 143, 119, 143, 139, 118, 101, 78, 95, 139, 119, 118, 95, 95, 172, 239, 225, +214, 184, 215, 206, 219, 251, 184, 191, 180, 203, 215, 212, 205, 189, 185, 203, 185, 212, 191, 204, +204, 208, 200, 205, 191, 188, 195, 190, 205, 206, 184, 192, 208, 198, 203, 203, 212, 223, 192, 192, +208, 203, 234, 225, 215, 210, 210, 184, 204, 199, 185, 204, 208, 178, 99, 150, 141, 128, 105, 120, +143, 129, 149, 141, 141, 133, 133, 150, 95, 120, 123, 95, 90, 139, 149, 152, 51, 143, 178, 233, +120, 129, 139, 152, 128, 141, 107, 142, 137, 136, 110, 123, 120, 143, 123, 4, 207, 109, 162, 150, +159, 146, 158, 154, 158, 159, 152, 152, 141, 128, 162, 70, 0, 153, 95, 105, 3, 239, 4, 254, +75, 142, 133, 107, 108, 109, 114, 142, 141, 141, 153, 128, 128, 133, 141, 87, 65, 54, 52, 21, +142, 105, 129, 149, 141, 152, 143, 119, 141, 149, 99, 119, 143, 99, 99, 152, 137, 143, 160, 162, +141, 158, 152, 141, 110, 128, 58, 61, 89, 104, 128, 128, 128, 133, 134, 141, 152, 133, 138, 108, +133, 153, 118, 121, 99, 77, 100, 79, 100, 100, 100, 143, 79, 4, 237, 239, 252, 215, 4, 233, +222, 240, 247, 239, 237, 222, 203, 227, 236, 239, 215, 241, 219, 167, 156, 159, 167, 156, 167, 167, +167, 156, 156, 156, 156, 161, 156, 167, 156, 156, 161, 156, 156, 161, 156, 156, 156, 156, 147, 147, +119, 98, 78, 95, 123, 95, 94, 119, 143, 119, 118, 119, 158, 197, 234, 209, 196, 204, 208, 229, +223, 198, 212, 211, 206, 206, 251, 211, 211, 180, 210, 184, 189, 206, 203, 213, 204, 204, 192, 197, +192, 211, 195, 211, 184, 191, 208, 203, 198, 184, 184, 205, 200, 213, 191, 185, 195, 214, 237, 225, +235, 239, 203, 184, 241, 222, 209, 155, 235, 242, 128, 141, 141, 104, 105, 119, 119, 129, 141, 133, +150, 128, 133, 130, 78, 100, 78, 95, 119, 152, 158, 37, 241, 215, 100, 91, 120, 101, 153, 118, +141, 134, 141, 104, 141, 121, 105, 120, 120, 160, 120, 241, 171, 158, 138, 133, 147, 53, 151, 161, +149, 149, 152, 165, 141, 128, 162, 150, 53, 175, 143, 153, 171, 160, 154, 7, 95, 129, 141, 111, +134, 108, 140, 152, 141, 141, 130, 141, 128, 141, 133, 100, 128, 74, 26, 105, 104, 118, 141, 165, +142, 162, 143, 143, 142, 158, 138, 99, 143, 99, 118, 159, 141, 119, 160, 152, 152, 141, 152, 158, +87, 106, 114, 47, 106, 128, 141, 142, 138, 128, 149, 153, 138, 141, 140, 115, 136, 138, 128, 139, +130, 95, 78, 78, 100, 143, 123, 148, 233, 125, 33, 48, 237, 91, 135, 252, 239, 246, 234, 114, +175, 241, 241, 206, 237, 241, 252, 218, 147, 141, 111, 134, 141, 141, 137, 133, 130, 106, 110, 134, +128, 134, 139, 111, 106, 134, 106, 96, 134, 111, 96, 107, 107, 121, 121, 130, 119, 98, 104, 120, +120, 119, 139, 119, 105, 119, 143, 134, 171, 222, 234, 235, 188, 220, 197, 188, 203, 203, 203, 198, +214, 205, 198, 205, 207, 180, 206, 212, 210, 211, 207, 203, 191, 203, 190, 214, 225, 213, 211, 189, +184, 184, 189, 184, 210, 211, 223, 192, 197, 208, 192, 205, 211, 236, 227, 219, 245, 221, 208, 170, +35, 187, 6, 177, 179, 225, 151, 138, 141, 128, 119, 119, 119, 129, 150, 141, 141, 128, 128, 130, +78, 95, 78, 119, 168, 152, 143, 241, 195, 222, 5, 104, 119, 152, 121, 141, 119, 152, 120, 162, +133, 120, 143, 143, 143, 153, 160, 206, 166, 151, 149, 149, 171, 251, 175, 167, 158, 159, 152, 152, +141, 128, 149, 152, 163, 252, 100, 143, 123, 236, 113, 139, 110, 134, 150, 133, 130, 161, 114, 152, +152, 162, 159, 152, 162, 152, 162, 133, 133, 75, 114, 89, 77, 129, 141, 159, 142, 158, 153, 139, +142, 149, 117, 107, 120, 99, 117, 159, 143, 153, 153, 152, 165, 138, 141, 141, 150, 78, 48, 109, +117, 143, 141, 158, 152, 141, 133, 152, 143, 134, 114, 109, 154, 152, 141, 142, 149, 105, 119, 160, +143, 163, 171, 233, 3, 159, 141, 104, 139, 119, 163, 135, 239, 246, 246, 171, 173, 239, 237, 164, +152, 100, 140, 144, 152, 139, 142, 139, 139, 121, 121, 139, 111, 139, 104, 107, 118, 129, 118, 150, +106, 134, 142, 133, 110, 133, 142, 129, 150, 150, 129, 150, 137, 137, 160, 143, 122, 119, 143, 118, +139, 119, 107, 171, 234, 211, 180, 215, 207, 223, 205, 211, 213, 196, 198, 190, 192, 205, 221, 205, +190, 191, 210, 184, 210, 212, 190, 184, 198, 198, 203, 213, 211, 213, 212, 198, 184, 206, 206, 184, +206, 191, 204, 191, 185, 204, 203, 212, 219, 215, 235, 250, 225, 210, 219, 161, 173, 154, 173, 109, +144, 178, 156, 152, 158, 128, 101, 118, 119, 129, 149, 141, 138, 141, 134, 138, 87, 78, 120, 141, +130, 152, 172, 233, 196, 205, 191, 153, 136, 141, 141, 141, 142, 142, 152, 141, 119, 119, 143, 143, +100, 153, 164, 233, 25, 168, 158, 9, 198, 198, 208, 213, 158, 159, 162, 152, 158, 128, 162, 133, +143, 160, 143, 103, 3, 51, 33, 105, 133, 118, 152, 141, 140, 109, 157, 158, 162, 165, 152, 165, +168, 158, 152, 134, 138, 109, 54, 78, 104, 133, 150, 149, 141, 162, 143, 143, 165, 149, 137, 99, +123, 129, 129, 159, 133, 139, 143, 159, 152, 152, 152, 98, 128, 134, 83, 67, 134, 131, 152, 152, +152, 163, 152, 141, 141, 128, 139, 136, 141, 149, 141, 158, 162, 139, 153, 143, 158, 160, 170, 233, +218, 152, 141, 104, 105, 143, 150, 129, 149, 156, 246, 244, 226, 173, 173, 141, 152, 152, 173, 166, +157, 154, 156, 156, 167, 156, 167, 156, 167, 156, 156, 167, 156, 154, 156, 156, 167, 168, 156, 167, +167, 167, 156, 156, 156, 167, 147, 156, 165, 160, 153, 114, 151, 143, 140, 105, 129, 139, 139, 182, +221, 203, 206, 211, 191, 180, 215, 213, 214, 209, 217, 209, 209, 216, 206, 222, 208, 197, 203, 208, +215, 215, 215, 206, 206, 211, 212, 193, 204, 217, 195, 213, 207, 36, 198, 204, 206, 206, 215, 205, +208, 203, 223, 239, 225, 227, 244, 235, 230, 211, 35, 115, 145, 162, 161, 157, 130, 149, 133, 149, +138, 110, 114, 145, 122, 110, 149, 141, 141, 141, 128, 150, 87, 121, 138, 129, 136, 158, 219, 206, +184, 206, 178, 162, 121, 152, 153, 152, 128, 152, 129, 139, 119, 143, 120, 160, 143, 143, 172, 206, +35, 163, 208, 233, 195, 197, 214, 198, 163, 168, 149, 165, 141, 133, 152, 150, 119, 163, 7, 0, +123, 3, 10, 142, 138, 118, 149, 141, 133, 131, 136, 149, 165, 152, 159, 165, 162, 165, 159, 152, +136, 131, 81, 143, 110, 105, 141, 149, 142, 162, 143, 139, 141, 159, 117, 105, 100, 99, 99, 162, +142, 153, 143, 162, 165, 141, 150, 152, 90, 133, 140, 100, 141, 152, 162, 165, 162, 141, 152, 149, +141, 118, 154, 143, 136, 158, 142, 133, 149, 129, 160, 153, 154, 160, 233, 202, 239, 152, 152, 110, +139, 139, 150, 139, 162, 141, 142, 158, 161, 168, 162, 139, 141, 139, 154, 157, 147, 134, 138, 142, +142, 141, 138, 142, 117, 142, 133, 106, 106, 110, 119, 106, 106, 133, 111, 130, 141, 130, 134, 139, +141, 106, 106, 95, 143, 154, 162, 154, 157, 166, 109, 107, 139, 163, 160, 207, 208, 188, 210, 211, +211, 215, 191, 211, 200, 217, 216, 217, 187, 200, 190, 236, 235, 221, 203, 205, 212, 206, 203, 206, +219, 211, 191, 198, 199, 204, 208, 200, 200, 198, 198, 203, 205, 211, 207, 203, 212, 206, 214, 222, +208, 227, 208, 205, 234, 193, 138, 237, 239, 203, 178, 178, 150, 147, 141, 149, 151, 112, 161, 166, +114, 153, 142, 152, 150, 149, 134, 149, 101, 162, 130, 136, 147, 153, 233, 198, 185, 207, 191, 162, +152, 141, 130, 92, 163, 133, 105, 119, 120, 143, 143, 143, 120, 153, 127, 202, 206, 233, 184, 184, +212, 193, 211, 197, 167, 159, 165, 149, 141, 150, 159, 150, 153, 160, 9, 135, 252, 3, 119, 119, +150, 128, 162, 141, 130, 160, 151, 158, 165, 149, 165, 165, 158, 168, 158, 162, 149, 140, 85, 129, +95, 130, 128, 159, 158, 152, 160, 153, 158, 162, 138, 99, 91, 99, 119, 159, 142, 143, 160, 152, +152, 149, 119, 134, 134, 123, 109, 109, 102, 141, 165, 162, 162, 152, 152, 153, 149, 118, 114, 166, +147, 149, 141, 142, 162, 139, 150, 158, 171, 178, 236, 201, 239, 153, 149, 150, 142, 143, 153, 160, +152, 150, 152, 150, 162, 165, 162, 142, 150, 138, 153, 163, 141, 141, 142, 133, 130, 121, 122, 128, +111, 121, 121, 118, 134, 107, 121, 106, 110, 104, 129, 139, 141, 150, 117, 141, 137, 133, 160, 153, +119, 119, 143, 137, 136, 151, 147, 142, 142, 143, 9, 222, 208, 208, 200, 222, 211, 206, 191, 211, +209, 200, 192, 192, 182, 199, 192, 227, 212, 206, 191, 197, 203, 207, 214, 207, 195, 205, 211, 205, +188, 208, 208, 186, 203, 199, 205, 213, 213, 205, 239, 210, 218, 216, 208, 208, 225, 217, 203, 206, +170, 154, 100, 241, 223, 208, 222, 222, 237, 103, 161, 156, 166, 157, 136, 154, 154, 152, 152, 141, +141, 152, 138, 111, 141, 143, 141, 149, 152, 236, 233, 185, 208, 222, 4, 128, 130, 110, 118, 130, +128, 119, 160, 120, 143, 160, 120, 143, 143, 154, 179, 206, 184, 212, 206, 213, 227, 198, 210, 178, +168, 162, 152, 141, 158, 141, 149, 141, 150, 164, 239, 0, 0, 3, 119, 139, 133, 129, 159, 142, +156, 166, 157, 142, 159, 162, 165, 162, 159, 165, 159, 158, 112, 109, 109, 120, 142, 143, 119, 159, +142, 162, 143, 139, 142, 149, 130, 118, 100, 88, 93, 162, 137, 143, 143, 152, 153, 152, 119, 160, +134, 150, 92, 157, 152, 152, 165, 162, 149, 153, 152, 141, 149, 141, 122, 114, 141, 162, 141, 129, +159, 158, 103, 236, 239, 236, 207, 184, 236, 141, 162, 141, 129, 160, 143, 143, 152, 142, 139, 142, +158, 162, 162, 160, 158, 137, 161, 166, 156, 162, 168, 167, 168, 168, 162, 162, 167, 168, 168, 167, +159, 168, 159, 159, 159, 159, 168, 168, 156, 156, 167, 156, 156, 167, 162, 167, 156, 156, 156, 156, +167, 156, 167, 156, 139, 142, 135, 234, 217, 213, 214, 223, 222, 214, 247, 223, 214, 200, 200, 192, +192, 200, 200, 227, 191, 184, 203, 205, 195, 213, 202, 191, 195, 213, 198, 189, 191, 192, 208, 199, +211, 214, 228, 228, 213, 192, 192, 214, 205, 223, 214, 214, 228, 222, 231, 218, 166, 142, 178, 208, +200, 208, 192, 211, 220, 239, 211, 159, 166, 157, 129, 167, 149, 158, 141, 142, 149, 149, 120, 152, +121, 141, 141, 141, 45, 239, 184, 198, 203, 213, 219, 29, 133, 94, 130, 105, 98, 95, 143, 143, +143, 143, 143, 139, 120, 173, 208, 215, 210, 184, 198, 191, 211, 192, 233, 29, 165, 162, 152, 162, +141, 150, 162, 152, 91, 0, 254, 103, 168, 161, 172, 119, 133, 142, 162, 152, 152, 114, 151, 165, +158, 162, 159, 165, 162, 168, 162, 165, 158, 157, 136, 143, 152, 143, 119, 165, 142, 152, 143, 160, +142, 149, 107, 99, 91, 118, 99, 147, 139, 119, 120, 162, 152, 152, 118, 119, 119, 153, 140, 143, +165, 162, 162, 165, 152, 152, 142, 159, 136, 141, 147, 153, 162, 168, 162, 162, 159, 125, 252, 233, +219, 206, 206, 241, 241, 150, 168, 133, 139, 143, 139, 160, 165, 142, 133, 143, 168, 162, 159, 142, +152, 134, 154, 166, 114, 150, 150, 147, 152, 149, 159, 152, 142, 152, 142, 138, 142, 141, 142, 142, +133, 137, 133, 150, 134, 138, 136, 141, 122, 112, 153, 142, 122, 130, 140, 130, 150, 136, 139, 141, +162, 163, 147, 178, 239, 222, 212, 214, 228, 238, 253, 253, 214, 200, 209, 235, 209, 228, 214, 213, +213, 202, 199, 199, 223, 193, 198, 210, 191, 203, 184, 210, 206, 189, 189, 212, 213, 213, 214, 217, +213, 192, 214, 209, 217, 200, 213, 225, 231, 239, 214, 156, 136, 114, 214, 225, 213, 213, 187, 187, +179, 208, 239, 199, 145, 111, 165, 131, 158, 147, 158, 149, 165, 129, 159, 141, 149, 149, 141, 139, +175, 233, 210, 206, 186, 199, 206, 233, 242, 162, 110, 105, 120, 119, 143, 120, 143, 143, 160, 175, +160, 173, 240, 227, 212, 211, 191, 184, 191, 200, 242, 139, 141, 149, 162, 141, 141, 128, 159, 152, +79, 252, 251, 91, 163, 143, 119, 119, 133, 150, 159, 158, 158, 163, 167, 162, 168, 168, 165, 159, +158, 168, 159, 162, 159, 160, 151, 133, 143, 120, 119, 159, 142, 152, 160, 119, 152, 149, 117, 88, +100, 99, 99, 149, 142, 143, 160, 152, 152, 138, 139, 119, 119, 119, 166, 166, 154, 152, 159, 158, +152, 165, 152, 152, 158, 152, 161, 166, 161, 125, 171, 144, 37, 233, 233, 215, 198, 251, 37, 9, +28, 159, 159, 137, 129, 160, 160, 163, 168, 152, 139, 158, 162, 168, 165, 142, 162, 152, 153, 165, +158, 152, 152, 137, 142, 130, 134, 142, 142, 142, 141, 133, 139, 142, 142, 122, 141, 134, 139, 134, +122, 141, 139, 134, 158, 163, 143, 121, 137, 128, 139, 143, 143, 139, 139, 143, 142, 143, 158, 172, +220, 192, 195, 213, 2, 2, 248, 253, 217, 217, 187, 212, 229, 227, 212, 227, 197, 195, 203, 196, +204, 205, 184, 206, 198, 184, 206, 180, 203, 184, 184, 203, 192, 249, 247, 247, 127, 228, 217, 217, +194, 234, 235, 227, 225, 235, 217, 139, 139, 178, 234, 192, 214, 212, 213, 228, 127, 187, 187, 200, +220, 218, 162, 156, 158, 152, 162, 165, 141, 152, 134, 141, 162, 165, 140, 87, 236, 239, 210, 211, +211, 206, 206, 206, 233, 158, 142, 98, 119, 95, 119, 160, 120, 95, 143, 233, 193, 218, 242, 249, +223, 211, 249, 223, 234, 178, 154, 167, 141, 149, 152, 162, 141, 141, 162, 152, 160, 252, 252, 143, +165, 119, 160, 129, 150, 137, 162, 162, 156, 166, 157, 165, 165, 159, 168, 165, 165, 162, 165, 158, +159, 166, 166, 119, 139, 119, 118, 159, 142, 152, 143, 143, 141, 158, 99, 99, 100, 117, 110, 159, +142, 119, 143, 152, 165, 162, 142, 119, 120, 105, 151, 157, 165, 158, 162, 152, 165, 152, 152, 165, +152, 158, 162, 173, 246, 252, 239, 222, 233, 233, 237, 207, 222, 125, 119, 143, 137, 159, 158, 141, +150, 160, 165, 163, 153, 162, 152, 152, 162, 168, 159, 142, 162, 141, 161, 166, 157, 159, 159, 167, +162, 162, 168, 162, 162, 159, 159, 162, 159, 162, 154, 162, 154, 154, 156, 167, 162, 159, 159, 168, +167, 160, 162, 168, 167, 160, 129, 150, 139, 139, 139, 139, 139, 150, 150, 10, 222, 208, 198, 229, +2, 2, 2, 2, 240, 232, 2, 223, 232, 235, 242, 238, 231, 198, 203, 192, 208, 203, 206, 204, +206, 206, 188, 206, 215, 211, 211, 185, 127, 2, 249, 229, 253, 244, 192, 192, 200, 238, 235, 239, +232, 235, 102, 152, 164, 236, 234, 213, 197, 211, 198, 206, 194, 155, 176, 116, 183, 207, 178, 152, +152, 162, 159, 150, 162, 128, 162, 159, 158, 153, 173, 84, 233, 208, 208, 231, 184, 210, 206, 206, +206, 241, 79, 150, 119, 95, 90, 119, 119, 119, 51, 239, 247, 206, 215, 247, 226, 191, 223, 204, +0, 137, 114, 113, 152, 149, 152, 152, 158, 133, 162, 152, 120, 239, 53, 150, 139, 139, 150, 139, +152, 150, 168, 158, 162, 157, 156, 158, 168, 165, 165, 168, 162, 168, 158, 162, 158, 161, 161, 139, +119, 119, 142, 162, 158, 165, 143, 119, 141, 149, 138, 105, 100, 117, 117, 159, 158, 143, 160, 162, +152, 137, 149, 142, 139, 139, 160, 152, 162, 168, 162, 165, 162, 158, 152, 152, 168, 158, 0, 254, +232, 232, 227, 239, 239, 239, 241, 241, 210, 180, 160, 158, 150, 162, 159, 139, 139, 165, 143, 0, +0, 167, 123, 252, 161, 173, 5, 158, 145, 150, 156, 166, 157, 156, 147, 154, 147, 154, 154, 147, +154, 159, 161, 173, 152, 149, 159, 152, 149, 149, 142, 138, 142, 133, 142, 152, 141, 142, 137, 150, +152, 163, 150, 143, 129, 143, 142, 143, 150, 163, 165, 160, 36, 219, 204, 231, 249, 217, 2, 253, +246, 235, 155, 250, 232, 236, 245, 232, 222, 186, 186, 205, 198, 210, 184, 184, 184, 184, 206, 216, +217, 214, 212, 217, 1, 2, 2, 2, 248, 243, 209, 192, 225, 232, 246, 222, 240, 233, 158, 158, +191, 208, 225, 245, 227, 207, 211, 198, 200, 209, 200, 200, 209, 213, 233, 160, 168, 152, 150, 159, +154, 165, 162, 158, 129, 166, 166, 148, 233, 215, 213, 227, 233, 198, 206, 203, 213, 236, 241, 175, +156, 156, 154, 114, 156, 161, 236, 236, 242, 223, 229, 242, 247, 229, 197, 233, 175, 142, 171, 254, +178, 159, 165, 162, 158, 152, 162, 152, 163, 164, 158, 163, 153, 150, 160, 150, 150, 150, 162, 162, +158, 143, 162, 168, 165, 168, 168, 168, 165, 165, 168, 165, 168, 165, 150, 139, 143, 158, 149, 119, +142, 159, 160, 143, 158, 149, 117, 99, 100, 117, 117, 159, 133, 143, 153, 168, 141, 152, 139, 141, +165, 129, 163, 160, 168, 162, 162, 162, 158, 152, 162, 168, 164, 239, 246, 246, 233, 233, 233, 233, +153, 143, 160, 218, 241, 241, 29, 158, 158, 162, 159, 152, 139, 172, 143, 113, 172, 173, 166, 175, +252, 239, 171, 158, 162, 152, 142, 136, 139, 139, 139, 152, 139, 133, 141, 137, 142, 139, 161, 166, +136, 139, 137, 142, 139, 142, 142, 142, 139, 129, 139, 142, 150, 150, 139, 139, 142, 152, 159, 160, +121, 139, 139, 142, 160, 172, 163, 148, 241, 191, 249, 216, 245, 2, 2, 2, 2, 1, 1, 232, +232, 225, 216, 205, 232, 225, 191, 223, 212, 184, 206, 210, 184, 190, 212, 192, 214, 217, 227, 187, +217, 217, 2, 2, 2, 235, 2, 214, 214, 2, 232, 231, 244, 178, 158, 103, 202, 213, 213, 206, +215, 198, 203, 204, 187, 216, 217, 217, 179, 176, 248, 226, 168, 162, 159, 150, 162, 168, 162, 147, +154, 172, 164, 159, 222, 206, 204, 198, 184, 206, 203, 185, 211, 206, 207, 194, 152, 154, 108, 154, +122, 241, 212, 127, 249, 212, 206, 206, 253, 212, 218, 233, 178, 152, 150, 160, 173, 168, 162, 152, +141, 150, 159, 150, 150, 139, 140, 166, 173, 163, 165, 139, 162, 152, 168, 158, 158, 139, 162, 162, +168, 168, 168, 168, 162, 168, 168, 168, 168, 165, 153, 139, 142, 165, 119, 158, 152, 162, 143, 143, +152, 162, 117, 117, 100, 99, 117, 159, 152, 139, 139, 162, 119, 158, 142, 105, 152, 150, 160, 166, +165, 168, 162, 165, 162, 152, 168, 173, 246, 237, 236, 233, 239, 241, 239, 48, 159, 142, 158, 172, +233, 233, 251, 148, 163, 165, 162, 141, 129, 165, 165, 171, 239, 254, 242, 154, 162, 168, 168, 152, +152, 152, 139, 142, 142, 150, 142, 139, 142, 142, 139, 142, 139, 129, 136, 156, 139, 139, 139, 139, +129, 139, 139, 139, 129, 139, 129, 142, 142, 139, 129, 119, 139, 119, 150, 159, 150, 139, 150, 150, +163, 157, 167, 171, 239, 2, 2, 204, 2, 2, 223, 231, 238, 6, 155, 253, 227, 248, 225, 227, +176, 231, 236, 234, 225, 179, 249, 229, 208, 212, 211, 206, 239, 232, 232, 214, 192, 228, 2, 2, +248, 234, 235, 249, 214, 228, 228, 240, 237, 79, 150, 218, 220, 192, 200, 203, 206, 212, 213, 217, +217, 209, 209, 231, 213, 209, 179, 246, 175, 162, 150, 162, 162, 152, 162, 156, 172, 241, 206, 157, +204, 210, 206, 210, 206, 203, 192, 208, 211, 219, 206, 184, 219, 184, 120, 129, 175, 180, 218, 191, +211, 211, 191, 127, 249, 229, 212, 210, 198, 164, 144, 178, 10, 168, 162, 159, 152, 150, 159, 152, +163, 150, 152, 156, 161, 142, 160, 150, 150, 158, 168, 168, 158, 142, 162, 159, 168, 168, 168, 168, +168, 168, 168, 168, 163, 166, 172, 158, 162, 119, 142, 162, 119, 159, 160, 129, 165, 149, 117, 99, +100, 117, 117, 152, 159, 142, 139, 162, 152, 107, 162, 153, 101, 162, 161, 157, 122, 150, 162, 152, +162, 162, 157, 243, 246, 218, 237, 236, 239, 241, 246, 171, 171, 242, 171, 163, 242, 252, 206, 36, +160, 168, 8, 102, 158, 22, 135, 236, 254, 236, 152, 150, 162, 159, 152, 139, 150, 141, 128, 139, +128, 139, 129, 139, 150, 139, 142, 139, 128, 105, 139, 139, 128, 129, 118, 105, 118, 139, 104, 129, +139, 119, 139, 121, 139, 137, 143, 119, 119, 143, 119, 129, 162, 168, 156, 168, 154, 156, 159, 145, +238, 238, 229, 248, 253, 2, 201, 196, 238, 155, 249, 247, 248, 225, 250, 2, 253, 253, 231, 239, +232, 232, 223, 244, 179, 229, 193, 227, 225, 225, 225, 225, 200, 253, 253, 248, 245, 235, 2, 225, +214, 240, 249, 234, 187, 154, 48, 208, 223, 204, 214, 208, 191, 188, 208, 214, 213, 225, 214, 214, +227, 228, 225, 207, 10, 152, 162, 152, 141, 152, 149, 153, 3, 207, 211, 223, 184, 206, 206, 198, +211, 203, 191, 206, 206, 180, 206, 211, 203, 207, 184, 9, 211, 222, 208, 213, 227, 212, 222, 227, +248, 245, 228, 190, 233, 219, 191, 207, 222, 215, 135, 172, 152, 142, 159, 158, 171, 143, 143, 160, +160, 150, 163, 142, 162, 152, 168, 158, 158, 163, 154, 158, 168, 168, 168, 168, 168, 168, 165, 152, +153, 157, 156, 162, 137, 142, 165, 119, 158, 165, 143, 141, 159, 141, 138, 118, 100, 117, 117, 149, +150, 158, 162, 139, 158, 153, 122, 152, 152, 101, 161, 166, 144, 142, 159, 165, 152, 152, 163, 161, +247, 250, 236, 241, 0, 239, 241, 171, 178, 144, 160, 153, 171, 178, 171, 160, 120, 168, 227, 218, +148, 36, 252, 252, 171, 152, 152, 150, 152, 165, 149, 139, 142, 150, 134, 140, 121, 111, 139, 128, +139, 129, 128, 105, 139, 110, 98, 104, 120, 105, 98, 76, 77, 89, 104, 120, 105, 119, 119, 139, +139, 142, 128, 121, 104, 128, 139, 133, 139, 134, 133, 139, 142, 139, 150, 165, 187, 220, 212, 245, +2, 250, 247, 2, 245, 253, 253, 217, 253, 249, 238, 238, 116, 176, 248, 231, 250, 246, 246, 232, +232, 228, 1, 220, 225, 209, 192, 200, 227, 228, 248, 253, 2, 1, 2, 236, 231, 212, 193, 227, +166, 178, 234, 216, 195, 203, 204, 204, 196, 208, 199, 213, 192, 166, 173, 173, 176, 179, 173, 167, +159, 162, 162, 152, 162, 159, 134, 237, 202, 193, 195, 203, 198, 184, 212, 212, 213, 208, 210, 251, +215, 223, 192, 214, 216, 190, 211, 206, 225, 245, 232, 200, 228, 203, 231, 200, 194, 209, 200, 206, +193, 207, 198, 184, 198, 222, 241, 207, 103, 137, 168, 120, 239, 172, 29, 78, 165, 150, 165, 158, +162, 165, 168, 162, 156, 166, 173, 168, 168, 162, 165, 162, 168, 168, 162, 152, 122, 166, 173, 119, +143, 152, 97, 134, 152, 118, 153, 165, 139, 138, 138, 117, 100, 99, 138, 149, 105, 120, 136, 121, +118, 141, 150, 120, 133, 143, 115, 157, 151, 150, 162, 142, 162, 149, 158, 173, 235, 236, 233, 215, +239, 239, 3, 145, 171, 139, 153, 160, 153, 165, 163, 165, 158, 168, 249, 247, 241, 125, 10, 160, +159, 133, 78, 119, 152, 159, 162, 105, 142, 128, 143, 173, 151, 141, 158, 141, 152, 158, 153, 134, +134, 122, 130, 134, 134, 134, 144, 112, 107, 112, 112, 136, 136, 140, 136, 154, 159, 163, 163, 153, +153, 143, 143, 160, 151, 167, 167, 163, 154, 165, 165, 165, 166, 204, 211, 1, 155, 248, 249, 249, +179, 179, 245, 245, 2, 1, 224, 235, 250, 247, 235, 245, 232, 224, 235, 235, 244, 232, 235, 240, +225, 235, 217, 236, 220, 232, 235, 2, 2, 1, 225, 231, 213, 204, 220, 242, 156, 239, 211, 196, +212, 198, 196, 188, 211, 211, 190, 207, 213, 161, 152, 168, 227, 145, 152, 131, 166, 173, 167, 167, +172, 135, 219, 206, 194, 203, 210, 218, 184, 212, 214, 183, 200, 197, 197, 212, 231, 127, 208, 199, +1, 155, 234, 240, 245, 234, 240, 229, 248, 214, 231, 227, 185, 182, 204, 210, 190, 190, 204, 203, +212, 205, 218, 202, 220, 164, 168, 152, 239, 160, 160, 160, 153, 160, 163, 139, 150, 158, 168, 162, +154, 166, 167, 162, 168, 168, 158, 162, 168, 159, 162, 150, 151, 157, 115, 150, 149, 100, 150, 165, +118, 121, 154, 121, 129, 139, 138, 99, 100, 99, 121, 138, 95, 119, 121, 154, 119, 100, 152, 119, +98, 149, 134, 97, 162, 150, 149, 142, 161, 167, 162, 232, 234, 239, 236, 247, 246, 236, 246, 239, +154, 129, 143, 153, 153, 143, 160, 153, 137, 168, 167, 127, 127, 140, 165, 167, 127, 164, 0, 57, +163, 149, 149, 139, 137, 128, 161, 166, 157, 154, 147, 154, 154, 147, 131, 112, 136, 154, 154, 154, +131, 136, 130, 134, 122, 130, 136, 112, 136, 154, 147, 154, 154, 150, 112, 144, 140, 144, 136, 151, +156, 154, 156, 154, 167, 162, 156, 161, 157, 166, 240, 1, 2, 2, 2, 2, 2, 179, 250, 1, +249, 225, 240, 235, 238, 249, 240, 240, 235, 235, 245, 240, 225, 235, 234, 245, 221, 240, 253, 239, +245, 245, 2, 2, 253, 249, 250, 248, 197, 222, 3, 44, 57, 236, 198, 192, 203, 191, 203, 203, +211, 215, 203, 237, 31, 151, 168, 154, 10, 150, 178, 237, 240, 236, 210, 210, 207, 241, 204, 213, +226, 198, 206, 127, 187, 187, 212, 200, 202, 191, 127, 209, 208, 201, 192, 199, 127, 127, 232, 245, +248, 225, 249, 247, 249, 2, 248, 229, 203, 191, 211, 191, 242, 231, 227, 223, 227, 204, 198, 213, +201, 125, 168, 162, 254, 144, 165, 153, 143, 163, 139, 142, 149, 142, 168, 159, 152, 151, 167, 168, +168, 165, 168, 168, 162, 162, 165, 158, 162, 102, 134, 149, 98, 119, 149, 105, 120, 154, 134, 119, +98, 106, 117, 88, 100, 99, 99, 138, 98, 120, 120, 120, 130, 134, 83, 139, 128, 78, 115, 109, +136, 141, 159, 150, 223, 223, 157, 243, 234, 233, 206, 246, 246, 240, 237, 241, 150, 142, 139, 160, +143, 160, 153, 143, 160, 162, 152, 122, 140, 138, 141, 122, 161, 128, 102, 139, 142, 149, 162, 129, +142, 150, 128, 151, 129, 141, 106, 139, 128, 104, 98, 98, 94, 94, 94, 95, 98, 77, 76, 86, +72, 77, 76, 77, 77, 94, 86, 104, 129, 90, 76, 76, 89, 89, 86, 121, 110, 96, 139, 111, +134, 158, 167, 156, 165, 172, 247, 247, 2, 245, 2, 2, 253, 248, 217, 248, 250, 238, 245, 155, +224, 179, 226, 249, 235, 245, 253, 249, 179, 227, 225, 232, 235, 245, 247, 226, 2, 250, 2, 2, +185, 1, 1, 225, 205, 207, 27, 17, 38, 223, 205, 197, 204, 203, 198, 212, 218, 236, 231, 160, +141, 154, 161, 219, 148, 172, 233, 202, 198, 184, 210, 251, 191, 229, 214, 192, 187, 206, 211, 228, +132, 213, 215, 211, 214, 211, 197, 213, 200, 220, 239, 228, 127, 249, 244, 247, 223, 186, 181, 236, +253, 116, 186, 192, 223, 236, 223, 223, 247, 223, 247, 229, 217, 214, 191, 228, 210, 206, 167, 152, +103, 160, 143, 143, 160, 160, 139, 137, 150, 134, 168, 162, 156, 166, 157, 162, 168, 168, 168, 158, +165, 149, 158, 141, 136, 109, 115, 83, 101, 128, 100, 95, 130, 119, 123, 120, 100, 110, 117, 88, +100, 99, 99, 138, 100, 120, 120, 120, 123, 107, 101, 87, 143, 119, 85, 109, 131, 137, 152, 161, +127, 168, 166, 244, 239, 237, 222, 236, 246, 246, 219, 252, 122, 128, 160, 143, 160, 153, 160, 143, +119, 159, 149, 105, 98, 127, 238, 172, 129, 127, 142, 139, 158, 162, 149, 139, 141, 150, 163, 160, +161, 142, 153, 134, 122, 112, 97, 97, 102, 97, 122, 107, 85, 85, 97, 97, 122, 97, 122, 92, +92, 112, 153, 154, 153, 134, 136, 139, 150, 152, 154, 152, 165, 162, 158, 165, 165, 168, 138, 154, +157, 156, 143, 240, 2, 2, 253, 2, 2, 127, 2, 232, 230, 224, 2, 253, 116, 232, 235, 127, +229, 221, 235, 227, 235, 249, 241, 248, 1, 247, 214, 235, 2, 253, 2, 2, 192, 1, 217, 204, +220, 10, 41, 39, 39, 216, 236, 223, 212, 206, 218, 216, 204, 236, 158, 142, 138, 194, 233, 206, +207, 210, 206, 206, 191, 208, 205, 226, 249, 176, 216, 127, 249, 242, 213, 235, 248, 208, 202, 240, +235, 234, 212, 197, 240, 239, 227, 240, 231, 240, 240, 219, 125, 186, 200, 235, 248, 223, 183, 186, +218, 193, 206, 242, 247, 247, 213, 214, 225, 208, 206, 204, 182, 208, 125, 141, 142, 160, 143, 160, +143, 119, 143, 129, 158, 139, 168, 152, 156, 157, 167, 168, 168, 168, 168, 162, 162, 165, 162, 150, +131, 109, 85, 100, 141, 87, 101, 136, 95, 91, 120, 120, 98, 110, 134, 88, 100, 88, 118, 130, +78, 91, 100, 100, 100, 79, 152, 95, 77, 141, 101, 112, 152, 138, 150, 173, 209, 168, 223, 244, +234, 237, 251, 233, 246, 246, 243, 246, 158, 101, 139, 160, 153, 160, 143, 160, 119, 159, 141, 129, +140, 231, 243, 53, 110, 142, 104, 129, 150, 159, 162, 129, 158, 141, 161, 166, 157, 156, 156, 156, +154, 156, 131, 108, 131, 131, 114, 151, 108, 130, 108, 131, 136, 108, 106, 107, 130, 108, 130, 108, +131, 138, 111, 128, 133, 151, 149, 131, 154, 154, 147, 147, 154, 137, 150, 139, 154, 141, 142, 158, +115, 235, 2, 2, 236, 249, 2, 248, 235, 2, 249, 223, 240, 245, 235, 224, 235, 235, 220, 245, +253, 231, 241, 249, 245, 232, 243, 2, 2, 2, 248, 2, 1, 1, 247, 240, 208, 125, 39, 218, +208, 216, 212, 227, 217, 231, 211, 217, 253, 236, 100, 153, 109, 239, 206, 198, 204, 211, 223, 229, +217, 200, 187, 248, 1, 249, 2, 2, 245, 245, 127, 245, 228, 225, 225, 1, 250, 240, 232, 245, +244, 0, 231, 244, 232, 235, 232, 232, 225, 186, 228, 235, 225, 195, 236, 218, 215, 215, 191, 213, +204, 193, 222, 227, 247, 213, 180, 218, 197, 206, 148, 162, 139, 143, 143, 120, 160, 119, 119, 139, +141, 137, 162, 158, 150, 140, 151, 162, 168, 168, 168, 162, 141, 162, 141, 130, 141, 108, 101, 152, +77, 100, 149, 100, 100, 100, 100, 100, 79, 107, 99, 88, 100, 99, 99, 138, 78, 100, 100, 91, +100, 100, 95, 111, 142, 90, 161, 109, 140, 141, 138, 226, 208, 159, 239, 239, 245, 244, 233, 236, +239, 246, 243, 246, 3, 159, 119, 153, 153, 143, 160, 153, 143, 149, 149, 150, 94, 218, 192, 160, +141, 104, 120, 119, 158, 152, 159, 139, 142, 142, 134, 151, 111, 128, 137, 104, 104, 104, 104, 110, +89, 120, 145, 52, 111, 106, 106, 106, 96, 106, 89, 92, 74, 74, 92, 74, 81, 93, 108, 122, +121, 101, 112, 136, 136, 151, 112, 151, 149, 156, 154, 156, 173, 161, 152, 150, 158, 127, 245, 2, +237, 242, 245, 240, 231, 253, 248, 245, 209, 245, 209, 235, 235, 1, 246, 227, 116, 247, 233, 246, +240, 246, 221, 227, 249, 248, 246, 251, 232, 245, 244, 239, 211, 204, 207, 207, 198, 213, 212, 187, +253, 245, 238, 1, 238, 227, 160, 171, 216, 207, 191, 195, 205, 197, 205, 217, 179, 116, 240, 239, +176, 217, 239, 240, 245, 235, 248, 212, 214, 227, 235, 244, 234, 245, 235, 238, 235, 232, 247, 244, +235, 238, 235, 235, 235, 253, 127, 235, 225, 188, 227, 228, 211, 211, 213, 213, 237, 211, 211, 203, +227, 236, 190, 211, 206, 205, 191, 160, 150, 143, 120, 120, 143, 143, 160, 105, 150, 150, 168, 152, +156, 166, 161, 158, 168, 168, 162, 158, 152, 158, 142, 141, 140, 145, 114, 95, 121, 143, 95, 100, +100, 100, 91, 100, 78, 105, 99, 88, 100, 99, 99, 138, 78, 100, 100, 100, 100, 100, 100, 123, +133, 119, 85, 109, 136, 129, 178, 234, 242, 138, 3, 239, 245, 227, 234, 233, 236, 244, 243, 227, +243, 2, 103, 103, 120, 143, 153, 123, 123, 162, 162, 128, 117, 212, 145, 152, 119, 118, 107, 119, +137, 159, 165, 129, 150, 141, 140, 173, 140, 150, 134, 129, 121, 121, 139, 121, 120, 122, 114, 114, +130, 131, 131, 130, 108, 111, 108, 96, 108, 130, 130, 108, 130, 152, 141, 107, 134, 121, 134, 139, +153, 142, 141, 158, 141, 142, 138, 154, 166, 157, 150, 152, 165, 164, 220, 127, 248, 235, 235, 235, +249, 253, 235, 228, 245, 235, 155, 253, 248, 250, 249, 249, 253, 250, 245, 248, 161, 79, 152, 186, +222, 232, 245, 240, 239, 242, 218, 248, 242, 175, 215, 207, 207, 187, 226, 223, 242, 226, 209, 253, +249, 228, 222, 221, 222, 184, 207, 206, 190, 191, 239, 225, 228, 245, 244, 0, 249, 206, 210, 227, +235, 249, 228, 234, 225, 214, 225, 232, 228, 244, 240, 240, 235, 235, 248, 235, 155, 245, 245, 250, +228, 253, 247, 247, 204, 208, 197, 200, 214, 213, 204, 212, 237, 236, 223, 184, 190, 213, 203, 192, +197, 206, 206, 158, 143, 120, 160, 143, 120, 143, 143, 119, 158, 129, 159, 158, 154, 109, 156, 162, +152, 168, 165, 165, 152, 141, 141, 120, 136, 109, 114, 119, 149, 119, 120, 100, 100, 100, 100, 100, +78, 105, 137, 99, 120, 99, 117, 150, 98, 120, 100, 91, 100, 100, 120, 120, 119, 141, 120, 107, +152, 172, 178, 183, 178, 152, 240, 244, 245, 236, 240, 240, 236, 239, 225, 200, 209, 225, 231, 233, +175, 171, 135, 215, 125, 168, 159, 164, 91, 222, 178, 141, 129, 104, 118, 95, 143, 162, 162, 118, +133, 139, 161, 109, 157, 149, 147, 151, 149, 154, 147, 138, 131, 130, 114, 136, 108, 134, 112, 81, +111, 92, 81, 89, 92, 92, 81, 97, 61, 81, 107, 108, 131, 136, 153, 152, 149, 149, 154, 162, +156, 154, 164, 167, 168, 167, 168, 168, 168, 168, 208, 245, 176, 248, 235, 238, 238, 1, 1, 1, +232, 1, 248, 250, 224, 155, 1, 247, 1, 1, 116, 112, 128, 117, 133, 178, 242, 116, 109, 157, +102, 101, 93, 114, 54, 93, 38, 10, 242, 236, 249, 226, 218, 249, 217, 194, 191, 191, 184, 231, +236, 211, 199, 193, 198, 206, 231, 191, 198, 247, 224, 204, 239, 1, 235, 253, 242, 223, 245, 235, +179, 179, 245, 240, 248, 240, 247, 239, 239, 225, 215, 236, 224, 1, 253, 116, 190, 183, 248, 249, +229, 213, 194, 247, 247, 249, 247, 247, 223, 249, 231, 184, 206, 212, 197, 209, 193, 241, 172, 162, +143, 143, 120, 100, 120, 120, 143, 119, 133, 105, 158, 142, 137, 140, 151, 158, 118, 165, 159, 152, +149, 153, 142, 137, 152, 112, 143, 149, 105, 123, 120, 120, 100, 91, 100, 100, 98, 128, 117, 99, +120, 99, 99, 149, 98, 123, 120, 100, 100, 120, 120, 100, 160, 101, 156, 109, 136, 162, 163, 175, +178, 166, 243, 239, 227, 246, 235, 247, 236, 236, 231, 220, 234, 197, 215, 218, 234, 239, 222, 208, +226, 173, 178, 222, 207, 208, 212, 160, 152, 128, 110, 105, 137, 152, 149, 105, 142, 133, 134, 136, +106, 120, 90, 90, 89, 104, 98, 72, 76, 79, 109, 54, 83, 92, 108, 108, 92, 108, 93, 92, +61, 92, 93, 61, 92, 73, 106, 108, 140, 108, 108, 108, 112, 139, 134, 142, 150, 151, 152, 158, +142, 136, 150, 154, 142, 159, 154, 178, 199, 217, 1, 1, 238, 224, 2, 245, 245, 245, 232, 235, +245, 245, 200, 166, 156, 157, 143, 90, 117, 110, 111, 70, 110, 72, 96, 106, 109, 109, 83, 19, +104, 41, 70, 72, 84, 236, 217, 127, 242, 222, 217, 216, 205, 207, 236, 222, 237, 213, 214, 225, +239, 220, 236, 212, 215, 179, 179, 197, 248, 224, 235, 247, 218, 235, 245, 235, 228, 231, 236, 247, +233, 227, 227, 240, 236, 236, 239, 240, 235, 245, 232, 240, 208, 221, 240, 253, 249, 247, 248, 249, +1, 247, 3, 226, 217, 216, 127, 155, 155, 176, 236, 216, 237, 241, 113, 129, 120, 120, 79, 120, +164, 145, 144, 119, 129, 119, 159, 133, 114, 109, 161, 139, 118, 159, 165, 153, 152, 141, 150, 134, +151, 115, 114, 118, 120, 120, 143, 120, 120, 100, 120, 91, 95, 130, 134, 99, 120, 117, 99, 138, +95, 100, 100, 100, 120, 123, 120, 120, 120, 120, 115, 109, 147, 162, 103, 239, 167, 167, 247, 240, +239, 235, 235, 223, 233, 197, 236, 246, 239, 239, 223, 223, 211, 213, 227, 222, 195, 225, 214, 206, +210, 185, 207, 215, 153, 111, 104, 139, 134, 149, 158, 98, 133, 142, 140, 120, 112, 94, 110, 118, +120, 104, 120, 105, 83, 82, 67, 67, 60, 54, 52, 73, 21, 52, 19, 57, 52, 52, 57, 19, +57, 86, 82, 97, 112, 97, 136, 144, 134, 136, 122, 151, 152, 152, 150, 158, 152, 158, 152, 158, +152, 154, 162, 157, 181, 214, 250, 244, 221, 234, 216, 225, 235, 232, 235, 240, 245, 235, 208, 168, +134, 145, 109, 161, 141, 141, 128, 98, 149, 94, 149, 73, 67, 114, 64, 41, 115, 48, 58, 78, +78, 120, 231, 213, 187, 236, 240, 245, 246, 225, 244, 244, 234, 228, 214, 239, 220, 222, 245, 249, +247, 1, 206, 198, 228, 230, 235, 236, 225, 235, 237, 215, 241, 239, 227, 231, 247, 250, 235, 1, +246, 253, 244, 208, 212, 208, 248, 249, 240, 232, 227, 226, 217, 253, 223, 247, 226, 237, 198, 203, +215, 180, 224, 224, 194, 226, 178, 204, 245, 242, 118, 129, 120, 95, 100, 160, 188, 171, 167, 100, +128, 105, 149, 129, 140, 109, 114, 95, 118, 162, 165, 128, 141, 150, 142, 110, 147, 109, 161, 120, +123, 143, 120, 91, 120, 120, 100, 100, 95, 130, 117, 99, 143, 117, 107, 147, 78, 100, 123, 120, +120, 120, 120, 120, 120, 160, 154, 122, 130, 152, 144, 239, 175, 9, 239, 240, 227, 235, 240, 239, +239, 214, 243, 234, 192, 247, 225, 200, 194, 203, 193, 197, 222, 208, 208, 205, 206, 184, 191, 205, +233, 145, 140, 107, 134, 149, 149, 119, 158, 128, 143, 166, 109, 154, 156, 147, 156, 156, 147, 114, +147, 140, 96, 99, 21, 54, 67, 21, 109, 54, 19, 57, 52, 54, 57, 41, 38, 57, 61, 93, +108, 114, 131, 147, 114, 151, 147, 156, 147, 151, 147, 147, 154, 147, 154, 147, 154, 154, 162, 154, +157, 178, 175, 10, 51, 178, 188, 221, 235, 179, 248, 226, 2, 2, 211, 159, 152, 114, 109, 131, +130, 139, 104, 86, 149, 86, 138, 41, 78, 130, 41, 63, 162, 167, 58, 17, 100, 100, 10, 245, +217, 231, 240, 239, 231, 235, 229, 235, 235, 243, 240, 217, 176, 223, 227, 239, 223, 253, 231, 229, +250, 240, 223, 245, 248, 228, 246, 239, 236, 236, 247, 250, 225, 209, 1, 2, 248, 2, 248, 221, +181, 183, 249, 239, 227, 232, 179, 250, 248, 249, 215, 206, 248, 223, 205, 207, 191, 192, 217, 217, +191, 206, 186, 234, 127, 94, 110, 118, 95, 100, 79, 103, 239, 175, 120, 95, 110, 98, 149, 133, +95, 101, 73, 90, 98, 149, 142, 110, 141, 128, 129, 141, 139, 112, 151, 120, 120, 120, 120, 120, +120, 123, 120, 120, 78, 110, 131, 99, 123, 117, 99, 131, 95, 120, 120, 120, 120, 143, 120, 160, +143, 152, 151, 161, 154, 141, 159, 242, 246, 246, 221, 247, 227, 235, 241, 237, 237, 240, 244, 244, +245, 239, 227, 231, 213, 193, 223, 205, 203, 199, 208, 201, 225, 196, 206, 210, 208, 208, 208, 151, +150, 162, 159, 118, 133, 150, 107, 136, 120, 109, 115, 96, 83, 96, 80, 83, 80, 72, 41, 19, +20, 52, 52, 87, 60, 74, 58, 86, 46, 44, 40, 38, 38, 19, 38, 68, 77, 94, 100, 94, +118, 118, 118, 95, 98, 98, 98, 98, 118, 118, 118, 105, 139, 95, 98, 105, 96, 178, 175, 137, +145, 109, 102, 54, 155, 232, 250, 245, 192, 202, 208, 164, 130, 140, 52, 107, 117, 118, 104, 87, +149, 79, 138, 72, 48, 133, 157, 239, 140, 124, 235, 1, 9, 8, 178, 244, 247, 231, 232, 225, +245, 239, 228, 207, 236, 207, 236, 223, 125, 231, 228, 226, 219, 222, 155, 1, 232, 239, 233, 235, +236, 239, 243, 244, 246, 235, 247, 226, 192, 186, 223, 214, 229, 228, 240, 239, 249, 231, 235, 250, +236, 248, 1, 1, 1, 1, 192, 197, 253, 248, 212, 223, 214, 238, 187, 186, 182, 185, 208, 173, +63, 87, 110, 101, 91, 97, 176, 127, 95, 160, 206, 164, 127, 140, 149, 105, 122, 54, 113, 87, +110, 158, 137, 78, 139, 133, 153, 134, 147, 161, 151, 152, 160, 143, 143, 143, 100, 143, 120, 120, +95, 122, 117, 99, 120, 99, 117, 141, 100, 120, 120, 143, 91, 143, 143, 143, 143, 142, 161, 166, +157, 150, 162, 53, 246, 236, 247, 250, 246, 234, 236, 239, 244, 225, 235, 209, 200, 239, 206, 191, +203, 207, 223, 213, 196, 203, 204, 204, 204, 214, 185, 185, 188, 213, 221, 208, 145, 162, 162, 110, +133, 158, 104, 118, 85, 124, 114, 94, 90, 100, 77, 98, 77, 77, 70, 19, 42, 54, 54, 90, +87, 76, 96, 80, 47, 52, 19, 41, 39, 39, 70, 38, 78, 78, 98, 98, 95, 98, 98, 100, +95, 98, 98, 100, 95, 95, 98, 120, 98, 87, 78, 139, 194, 222, 201, 187, 1, 132, 38, 104, +141, 94, 104, 159, 115, 109, 134, 76, 44, 127, 109, 67, 133, 98, 94, 84, 212, 75, 117, 68, +244, 238, 245, 252, 208, 243, 235, 238, 241, 233, 244, 239, 247, 240, 236, 235, 235, 239, 211, 164, +147, 146, 223, 233, 233, 211, 208, 192, 226, 231, 234, 235, 232, 240, 232, 235, 243, 227, 179, 1, +245, 235, 155, 179, 213, 211, 212, 223, 213, 205, 211, 227, 1, 1, 235, 234, 253, 1, 1, 1, +249, 253, 179, 179, 201, 208, 208, 199, 213, 209, 224, 224, 218, 206, 199, 167, 63, 57, 89, 69, +239, 116, 138, 117, 48, 200, 178, 164, 239, 145, 168, 107, 114, 109, 67, 78, 110, 133, 133, 104, +128, 133, 128, 143, 156, 124, 161, 142, 143, 143, 120, 160, 143, 100, 160, 120, 95, 130, 108, 99, +120, 117, 99, 131, 95, 143, 143, 120, 143, 143, 143, 160, 143, 141, 158, 151, 152, 152, 163, 211, +239, 246, 237, 236, 240, 234, 239, 232, 235, 235, 235, 235, 192, 186, 214, 225, 213, 242, 213, 199, +184, 206, 188, 206, 203, 199, 195, 208, 208, 196, 191, 207, 220, 178, 147, 133, 133, 162, 137, 105, +100, 90, 90, 73, 83, 73, 73, 77, 78, 78, 81, 15, 26, 54, 67, 106, 87, 106, 64, 41, +54, 54, 58, 19, 39, 39, 38, 38, 78, 78, 87, 95, 100, 95, 95, 95, 98, 95, 98, 95, +78, 100, 95, 78, 78, 95, 95, 178, 221, 192, 209, 214, 214, 232, 74, 101, 90, 106, 110, 128, +108, 67, 136, 114, 121, 114, 48, 242, 106, 101, 104, 247, 229, 99, 138, 72, 232, 155, 2, 231, +200, 200, 232, 235, 244, 227, 227, 235, 240, 231, 247, 238, 239, 239, 156, 146, 146, 124, 245, 217, +223, 191, 186, 214, 213, 240, 235, 179, 228, 155, 245, 244, 230, 238, 249, 127, 213, 248, 250, 249, +249, 249, 249, 247, 223, 211, 218, 193, 206, 249, 155, 250, 155, 155, 1, 116, 179, 155, 174, 116, +208, 208, 202, 225, 209, 1, 216, 197, 213, 212, 225, 179, 173, 71, 80, 41, 205, 241, 51, 117, +109, 209, 203, 206, 198, 160, 218, 165, 69, 61, 73, 38, 86, 94, 133, 105, 139, 110, 143, 141, +141, 136, 154, 141, 143, 143, 143, 143, 143, 143, 120, 143, 95, 130, 117, 118, 120, 117, 118, 149, +119, 120, 160, 120, 160, 143, 160, 153, 160, 162, 152, 119, 158, 158, 191, 207, 232, 244, 233, 239, +245, 247, 234, 225, 235, 235, 235, 214, 196, 192, 227, 248, 214, 222, 185, 208, 208, 203, 184, 206, +196, 208, 207, 191, 203, 185, 206, 207, 204, 193, 153, 162, 158, 142, 149, 149, 149, 152, 150, 141, +147, 138, 130, 130, 134, 114, 54, 115, 19, 58, 65, 94, 87, 99, 57, 73, 61, 44, 41, 38, +17, 39, 38, 38, 38, 39, 78, 78, 95, 95, 100, 95, 95, 100, 95, 78, 78, 79, 78, 78, +100, 100, 117, 166, 221, 192, 192, 209, 217, 209, 67, 57, 85, 115, 81, 72, 93, 53, 46, 74, +108, 108, 114, 245, 156, 118, 3, 220, 193, 97, 96, 27, 127, 179, 234, 247, 200, 200, 208, 240, +248, 241, 247, 235, 239, 223, 231, 240, 234, 236, 147, 124, 157, 226, 244, 155, 229, 208, 195, 223, +249, 242, 125, 218, 235, 235, 235, 232, 225, 229, 249, 201, 198, 195, 223, 249, 249, 253, 253, 1, +1, 1, 1, 253, 248, 240, 248, 253, 1, 249, 226, 155, 55, 6, 155, 127, 3, 223, 179, 224, +127, 200, 212, 191, 181, 186, 173, 249, 48, 86, 119, 10, 201, 206, 5, 42, 23, 78, 117, 148, +207, 210, 210, 236, 78, 79, 39, 38, 94, 86, 86, 87, 130, 130, 129, 150, 142, 160, 141, 165, +143, 160, 153, 160, 143, 160, 143, 143, 100, 133, 138, 99, 120, 99, 99, 138, 143, 143, 143, 153, +153, 160, 153, 153, 153, 165, 152, 139, 152, 158, 178, 195, 225, 228, 228, 213, 245, 250, 206, 212, +235, 235, 214, 182, 208, 225, 214, 231, 227, 192, 212, 190, 190, 207, 206, 198, 185, 206, 191, 189, +206, 185, 203, 236, 191, 220, 171, 138, 159, 134, 139, 131, 138, 131, 131, 131, 108, 131, 108, 92, +93, 93, 109, 114, 38, 19, 58, 90, 83, 104, 41, 94, 52, 52, 19, 41, 39, 39, 39, 17, +39, 39, 38, 78, 100, 78, 59, 95, 78, 78, 78, 78, 39, 20, 78, 78, 39, 39, 89, 48, +220, 192, 228, 192, 192, 209, 32, 17, 31, 136, 89, 74, 112, 235, 92, 89, 58, 108, 155, 245, +116, 122, 240, 215, 210, 212, 37, 170, 187, 114, 236, 233, 220, 183, 214, 192, 221, 201, 221, 239, +236, 180, 208, 231, 222, 198, 149, 146, 145, 232, 239, 239, 223, 213, 223, 242, 223, 247, 223, 235, +235, 224, 230, 234, 247, 253, 228, 234, 214, 1, 179, 249, 247, 248, 253, 253, 253, 1, 253, 228, +1, 1, 248, 249, 237, 218, 179, 238, 155, 187, 198, 187, 190, 214, 224, 179, 214, 212, 186, 185, +175, 133, 94, 89, 70, 61, 211, 220, 220, 51, 54, 52, 42, 49, 95, 131, 178, 207, 241, 148, +79, 39, 39, 17, 98, 98, 87, 70, 139, 130, 120, 133, 152, 119, 141, 152, 160, 153, 160, 153, +153, 153, 153, 143, 143, 141, 138, 99, 120, 99, 117, 149, 139, 143, 143, 160, 153, 163, 160, 153, +160, 152, 158, 119, 152, 168, 173, 207, 185, 235, 179, 213, 228, 235, 241, 241, 228, 235, 245, 228, +228, 228, 228, 203, 199, 192, 190, 191, 198, 212, 190, 196, 205, 206, 206, 198, 206, 206, 206, 191, +206, 206, 170, 148, 158, 159, 150, 134, 139, 134, 129, 129, 120, 118, 105, 119, 98, 87, 101, 80, +85, 47, 60, 95, 86, 104, 58, 88, 54, 54, 57, 38, 39, 38, 17, 38, 38, 17, 39, 17, +70, 78, 69, 58, 70, 70, 70, 70, 39, 70, 70, 69, 38, 41, 41, 10, 220, 192, 249, 217, +199, 229, 232, 53, 38, 41, 88, 64, 46, 253, 61, 88, 146, 176, 235, 155, 145, 16, 247, 185, +184, 228, 231, 215, 222, 223, 102, 125, 175, 187, 235, 214, 178, 173, 167, 127, 204, 191, 238, 179, +203, 171, 146, 146, 112, 218, 239, 227, 228, 247, 236, 249, 248, 249, 249, 235, 235, 224, 235, 239, +231, 245, 1, 2, 249, 249, 247, 249, 248, 253, 249, 249, 1, 1, 248, 1, 127, 145, 242, 223, +228, 2, 238, 235, 216, 196, 191, 191, 200, 209, 209, 211, 215, 204, 205, 207, 219, 70, 84, 3, +95, 145, 206, 10, 136, 69, 46, 44, 38, 17, 39, 88, 131, 208, 222, 78, 21, 39, 39, 38, +94, 104, 76, 70, 110, 110, 110, 142, 139, 120, 165, 142, 160, 163, 153, 160, 160, 153, 160, 143, +143, 138, 138, 129, 120, 117, 129, 159, 121, 153, 160, 153, 160, 153, 160, 153, 160, 158, 162, 129, +165, 152, 161, 207, 198, 195, 214, 192, 214, 225, 241, 218, 232, 235, 232, 217, 227, 200, 213, 211, +203, 195, 208, 208, 203, 197, 190, 204, 214, 205, 198, 215, 191, 184, 206, 207, 205, 184, 206, 241, +125, 141, 159, 159, 159, 159, 159, 147, 159, 147, 147, 154, 147, 114, 131, 108, 54, 54, 67, 104, +94, 99, 58, 86, 93, 81, 41, 38, 38, 41, 38, 38, 41, 41, 41, 57, 69, 70, 77, 69, +79, 63, 73, 83, 73, 69, 19, 70, 19, 38, 41, 10, 202, 212, 198, 209, 225, 212, 193, 222, +10, 71, 40, 60, 46, 253, 61, 109, 155, 235, 228, 114, 99, 236, 208, 221, 200, 179, 194, 223, +223, 171, 142, 150, 129, 134, 116, 116, 166, 149, 159, 127, 220, 250, 127, 176, 174, 146, 117, 147, +124, 116, 244, 248, 245, 233, 253, 1, 253, 1, 250, 245, 235, 199, 232, 247, 231, 238, 245, 1, +248, 253, 249, 253, 253, 253, 249, 249, 1, 1, 127, 249, 249, 228, 212, 187, 235, 228, 225, 217, +182, 186, 190, 190, 200, 200, 206, 184, 237, 208, 192, 193, 220, 25, 95, 233, 155, 213, 36, 71, +19, 74, 54, 21, 42, 39, 21, 38, 71, 221, 208, 70, 42, 21, 17, 38, 88, 98, 87, 78, +110, 110, 120, 141, 142, 143, 141, 162, 160, 153, 160, 165, 153, 160, 153, 153, 129, 149, 152, 117, +120, 117, 117, 138, 139, 153, 160, 153, 153, 160, 153, 160, 153, 165, 141, 143, 158, 162, 153, 206, +203, 203, 192, 209, 208, 243, 222, 239, 245, 235, 209, 223, 227, 192, 197, 199, 202, 212, 194, 205, +205, 207, 195, 196, 207, 198, 206, 207, 188, 222, 208, 183, 201, 207, 185, 189, 207, 207, 218, 118, +160, 153, 139, 110, 121, 107, 118, 104, 104, 95, 98, 73, 97, 67, 92, 87, 98, 110, 57, 94, +88, 96, 19, 38, 21, 21, 46, 19, 58, 81, 47, 82, 47, 97, 85, 112, 112, 92, 112, 108, +122, 112, 81, 89, 81, 106, 92, 33, 220, 208, 219, 175, 176, 214, 215, 236, 233, 58, 114, 1, +124, 43, 25, 222, 222, 3, 145, 52, 219, 220, 200, 200, 183, 209, 176, 207, 223, 110, 104, 139, +117, 129, 130, 157, 147, 154, 213, 217, 239, 239, 191, 220, 124, 146, 146, 52, 245, 1, 247, 1, +1, 244, 250, 247, 248, 250, 250, 250, 155, 222, 248, 250, 248, 250, 248, 248, 155, 1, 248, 247, +248, 1, 245, 217, 179, 116, 228, 214, 217, 235, 213, 219, 218, 223, 212, 218, 208, 204, 186, 193, +192, 238, 223, 215, 206, 204, 200, 192, 222, 241, 210, 203, 179, 217, 208, 48, 13, 25, 54, 52, +21, 21, 21, 17, 78, 232, 178, 63, 21, 49, 38, 41, 89, 94, 86, 78, 118, 98, 128, 134, +143, 143, 141, 153, 143, 160, 153, 160, 160, 153, 160, 153, 139, 152, 138, 117, 143, 117, 141, 162, +129, 160, 153, 160, 160, 153, 160, 153, 160, 152, 158, 119, 152, 162, 162, 163, 210, 206, 218, 214, +249, 223, 239, 246, 228, 116, 249, 227, 236, 206, 185, 198, 210, 196, 198, 206, 223, 210, 184, 198, +206, 219, 91, 152, 208, 198, 198, 145, 114, 186, 198, 184, 198, 241, 210, 206, 175, 166, 114, 151, +147, 136, 151, 136, 136, 112, 144, 97, 101, 79, 82, 105, 73, 99, 57, 70, 87, 80, 89, 41, +42, 54, 67, 81, 92, 92, 92, 93, 92, 92, 92, 108, 111, 108, 111, 138, 130, 99, 99, 72, +80, 99, 93, 73, 136, 154, 101, 101, 61, 208, 223, 242, 194, 251, 0, 253, 1, 114, 212, 198, +220, 103, 109, 239, 233, 203, 215, 183, 155, 208, 211, 193, 239, 127, 153, 152, 150, 143, 142, 163, +137, 222, 233, 197, 203, 204, 199, 190, 168, 146, 109, 243, 250, 235, 155, 243, 156, 131, 179, 235, +1, 248, 232, 224, 224, 248, 247, 248, 2, 248, 248, 247, 250, 253, 2, 2, 240, 242, 2, 2, +249, 248, 235, 209, 245, 228, 247, 247, 249, 249, 206, 198, 204, 205, 193, 190, 204, 200, 192, 233, +210, 191, 197, 203, 190, 198, 184, 206, 127, 209, 225, 127, 27, 25, 44, 42, 42, 17, 42, 17, +70, 140, 110, 70, 21, 42, 41, 38, 80, 94, 87, 77, 110, 83, 104, 141, 137, 100, 141, 137, +143, 160, 160, 153, 153, 160, 153, 160, 139, 149, 149, 117, 120, 117, 117, 149, 139, 160, 153, 153, +160, 153, 160, 143, 160, 142, 152, 139, 165, 162, 159, 160, 206, 215, 206, 215, 213, 218, 237, 239, +227, 192, 208, 211, 206, 206, 215, 206, 191, 198, 211, 237, 212, 227, 231, 223, 204, 242, 39, 41, +145, 198, 201, 193, 115, 178, 185, 215, 202, 206, 200, 200, 178, 156, 154, 154, 164, 154, 136, 154, +136, 115, 109, 109, 107, 82, 92, 69, 69, 104, 57, 40, 71, 105, 69, 96, 90, 108, 93, 89, +94, 74, 88, 64, 80, 64, 80, 80, 99, 101, 96, 111, 106, 99, 96, 99, 93, 96, 72, 80, +64, 64, 60, 64, 60, 28, 233, 127, 226, 36, 210, 219, 223, 208, 202, 208, 178, 139, 191, 198, +186, 185, 189, 195, 225, 227, 214, 1, 209, 232, 226, 143, 178, 234, 145, 149, 197, 207, 182, 185, +213, 187, 234, 171, 146, 146, 114, 224, 132, 235, 250, 1, 168, 146, 157, 235, 176, 235, 224, 224, +235, 227, 250, 238, 248, 227, 250, 1, 248, 155, 1, 155, 116, 249, 1, 253, 247, 225, 224, 2, +247, 226, 249, 247, 249, 249, 215, 241, 196, 192, 197, 213, 233, 198, 211, 191, 196, 249, 236, 210, +223, 229, 184, 208, 228, 214, 204, 208, 10, 27, 17, 18, 49, 17, 18, 27, 81, 63, 99, 58, +67, 14, 21, 46, 48, 97, 86, 78, 110, 87, 73, 141, 134, 78, 139, 142, 120, 143, 160, 160, +143, 160, 153, 160, 139, 152, 138, 129, 143, 117, 99, 149, 139, 143, 160, 143, 143, 160, 143, 143, +143, 150, 150, 119, 142, 162, 159, 172, 207, 210, 184, 191, 203, 190, 236, 243, 240, 192, 223, 191, +191, 207, 191, 198, 205, 214, 217, 236, 212, 212, 214, 214, 203, 215, 10, 41, 109, 233, 198, 151, +113, 241, 103, 147, 178, 203, 218, 197, 201, 178, 164, 151, 197, 103, 167, 154, 147, 136, 109, 109, +72, 80, 73, 69, 80, 70, 57, 47, 47, 72, 118, 72, 72, 68, 72, 72, 64, 26, 21, 21, +41, 38, 41, 38, 83, 112, 106, 111, 106, 92, 102, 112, 92, 82, 106, 81, 81, 81, 74, 74, +72, 4, 207, 214, 231, 231, 223, 210, 210, 198, 223, 249, 191, 202, 195, 184, 198, 185, 198, 191, +240, 222, 197, 127, 225, 214, 239, 190, 204, 213, 216, 171, 226, 222, 213, 208, 217, 229, 239, 226, +157, 168, 146, 157, 1, 116, 253, 238, 157, 146, 166, 245, 253, 245, 224, 238, 228, 226, 217, 223, +208, 155, 155, 1, 1, 127, 127, 253, 247, 253, 2, 249, 249, 235, 224, 179, 249, 253, 249, 248, +249, 247, 247, 215, 211, 187, 217, 227, 233, 184, 184, 211, 213, 214, 197, 218, 197, 217, 200, 179, +179, 231, 191, 206, 222, 220, 57, 18, 24, 49, 49, 202, 200, 145, 96, 17, 67, 54, 52, 52, +54, 67, 87, 78, 110, 87, 70, 104, 101, 100, 128, 139, 91, 143, 143, 143, 160, 139, 143, 160, +118, 152, 138, 99, 143, 117, 129, 149, 95, 120, 120, 123, 120, 120, 120, 123, 120, 139, 141, 119, +142, 165, 159, 153, 215, 210, 191, 193, 191, 210, 239, 243, 237, 191, 206, 203, 203, 185, 199, 188, +236, 213, 200, 197, 237, 215, 184, 207, 196, 202, 214, 242, 156, 178, 219, 64, 84, 210, 184, 175, +175, 184, 189, 193, 192, 201, 220, 219, 115, 203, 232, 181, 143, 143, 136, 131, 80, 69, 65, 80, +41, 56, 65, 48, 54, 15, 72, 72, 38, 38, 38, 38, 38, 42, 54, 54, 19, 38, 19, 98, +89, 89, 81, 81, 85, 108, 93, 93, 93, 93, 61, 46, 46, 46, 74, 46, 48, 222, 212, 213, +227, 209, 179, 203, 185, 199, 191, 197, 199, 198, 206, 241, 251, 233, 241, 212, 179, 207, 191, 216, +208, 213, 213, 222, 195, 205, 239, 246, 246, 234, 231, 197, 216, 227, 213, 225, 234, 217, 187, 239, +248, 155, 224, 253, 253, 145, 250, 229, 223, 235, 235, 245, 225, 213, 197, 182, 192, 1, 179, 127, +179, 179, 179, 229, 247, 155, 253, 247, 155, 230, 238, 1, 179, 179, 253, 127, 2, 249, 2, 245, +236, 239, 127, 229, 236, 231, 227, 195, 223, 196, 190, 190, 193, 192, 200, 179, 217, 200, 193, 210, +212, 208, 194, 60, 64, 66, 10, 200, 233, 233, 152, 42, 44, 61, 44, 60, 61, 92, 98, 87, +110, 86, 70, 105, 78, 79, 87, 101, 79, 120, 120, 123, 120, 123, 100, 120, 95, 137, 138, 117, +143, 99, 117, 138, 100, 120, 100, 100, 79, 91, 79, 100, 100, 121, 119, 78, 142, 152, 149, 152, +135, 210, 206, 191, 191, 180, 233, 244, 236, 233, 195, 202, 198, 185, 203, 203, 199, 199, 206, 211, +211, 184, 203, 203, 199, 208, 200, 208, 184, 160, 207, 60, 120, 207, 198, 206, 207, 191, 185, 198, +198, 198, 184, 241, 125, 178, 220, 239, 167, 147, 154, 147, 108, 131, 166, 3, 25, 40, 94, 92, +46, 41, 41, 77, 110, 41, 38, 41, 38, 19, 60, 44, 41, 39, 96, 70, 41, 38, 41, 21, +48, 54, 63, 38, 70, 38, 41, 41, 17, 41, 41, 17, 219, 208, 240, 1, 127, 247, 226, 197, +198, 191, 180, 184, 206, 191, 207, 239, 206, 241, 236, 227, 209, 200, 239, 222, 195, 213, 214, 200, +195, 198, 222, 186, 208, 214, 227, 228, 214, 196, 213, 209, 209, 214, 234, 239, 242, 223, 247, 242, +239, 239, 223, 205, 235, 235, 227, 231, 248, 235, 229, 217, 1, 1, 1, 1, 249, 249, 1, 249, +249, 179, 253, 1, 1, 155, 217, 226, 217, 179, 253, 249, 235, 2, 253, 231, 236, 250, 209, 242, +223, 224, 1, 212, 206, 196, 208, 195, 191, 200, 209, 179, 253, 208, 223, 215, 210, 199, 226, 57, +88, 131, 3, 53, 24, 175, 178, 30, 42, 49, 21, 17, 21, 87, 86, 78, 104, 80, 77, 105, +77, 49, 73, 95, 21, 100, 79, 79, 100, 79, 100, 100, 95, 133, 138, 129, 143, 99, 99, 138, +98, 100, 79, 79, 49, 79, 79, 79, 21, 98, 104, 95, 143, 142, 149, 152, 158, 215, 206, 198, +211, 219, 233, 246, 239, 222, 208, 200, 188, 198, 206, 202, 184, 185, 208, 203, 203, 195, 196, 208, +208, 214, 204, 223, 251, 35, 122, 101, 10, 198, 203, 196, 192, 198, 206, 184, 36, 180, 180, 175, +233, 222, 239, 84, 134, 121, 89, 242, 178, 200, 232, 220, 25, 42, 44, 96, 92, 41, 38, 38, +76, 111, 58, 38, 38, 41, 38, 39, 57, 107, 76, 41, 38, 17, 38, 49, 54, 67, 19, 70, +38, 38, 38, 57, 57, 57, 21, 53, 75, 52, 75, 48, 227, 242, 211, 191, 184, 206, 202, 206, +180, 210, 184, 184, 180, 233, 236, 226, 235, 155, 227, 206, 203, 188, 220, 208, 213, 198, 198, 195, +213, 205, 203, 225, 223, 191, 208, 214, 225, 228, 248, 185, 193, 215, 236, 231, 247, 231, 214, 214, +245, 235, 228, 240, 240, 228, 227, 2, 253, 249, 248, 127, 247, 247, 249, 247, 228, 235, 228, 1, +250, 0, 242, 217, 228, 127, 179, 179, 235, 235, 228, 217, 228, 209, 235, 240, 227, 247, 176, 211, +237, 204, 192, 204, 190, 213, 192, 209, 179, 229, 229, 217, 227, 234, 48, 15, 56, 107, 62, 41, +80, 57, 10, 30, 17, 20, 19, 39, 38, 76, 83, 87, 110, 80, 73, 105, 87, 21, 77, 70, +21, 49, 21, 79, 79, 21, 91, 78, 78, 130, 117, 117, 143, 88, 99, 150, 78, 100, 91, 79, +21, 79, 49, 21, 21, 119, 77, 58, 118, 141, 149, 153, 152, 158, 199, 220, 211, 206, 185, 205, +239, 236, 206, 190, 194, 201, 185, 184, 184, 198, 214, 228, 236, 203, 200, 214, 192, 197, 204, 229, +171, 25, 99, 82, 219, 198, 191, 198, 198, 206, 190, 191, 210, 35, 210, 168, 173, 245, 246, 178, +131, 131, 93, 171, 222, 201, 221, 194, 47, 54, 47, 15, 60, 89, 69, 41, 38, 63, 72, 83, +60, 83, 81, 60, 81, 60, 41, 38, 38, 38, 19, 17, 19, 19, 41, 17, 19, 20, 57, 74, +93, 74, 82, 223, 3, 117, 106, 84, 178, 240, 239, 233, 239, 244, 247, 207, 180, 36, 180, 198, +198, 233, 211, 223, 179, 228, 214, 203, 191, 207, 213, 190, 205, 208, 203, 208, 212, 208, 214, 214, +205, 191, 188, 205, 214, 214, 229, 215, 215, 215, 231, 212, 223, 192, 227, 240, 205, 223, 212, 194, +249, 227, 248, 238, 248, 248, 253, 249, 253, 253, 248, 226, 245, 235, 253, 1, 225, 222, 0, 239, +235, 179, 179, 127, 228, 155, 217, 116, 224, 127, 187, 238, 231, 233, 238, 218, 251, 203, 192, 213, +216, 197, 200, 155, 179, 217, 223, 217, 209, 179, 116, 81, 25, 233, 32, 80, 83, 89, 70, 42, +21, 21, 49, 39, 17, 80, 80, 76, 110, 77, 78, 88, 78, 17, 77, 95, 42, 21, 49, 21, +49, 79, 79, 79, 59, 130, 117, 117, 143, 99, 88, 131, 95, 79, 21, 79, 49, 21, 21, 49, +49, 78, 104, 70, 118, 133, 141, 128, 152, 159, 165, 210, 184, 203, 198, 191, 236, 239, 239, 206, +215, 203, 203, 203, 208, 214, 214, 200, 208, 208, 205, 192, 213, 227, 212, 193, 115, 96, 96, 24, +206, 205, 198, 184, 206, 198, 198, 198, 184, 180, 211, 197, 242, 53, 103, 136, 3, 3, 89, 77, +178, 220, 127, 17, 19, 61, 40, 21, 48, 61, 80, 92, 81, 81, 96, 89, 96, 74, 89, 89, +89, 89, 89, 80, 81, 81, 81, 81, 90, 90, 81, 92, 92, 81, 90, 41, 42, 84, 81, 81, +226, 204, 233, 242, 99, 114, 176, 214, 206, 206, 211, 198, 206, 206, 210, 215, 190, 182, 195, 197, +217, 213, 208, 202, 211, 193, 212, 211, 211, 204, 191, 204, 214, 228, 217, 228, 208, 205, 205, 217, +228, 217, 212, 219, 210, 212, 197, 223, 191, 206, 223, 231, 231, 231, 212, 216, 192, 227, 248, 249, +2, 238, 224, 249, 253, 155, 1, 1, 235, 235, 228, 235, 235, 230, 247, 247, 155, 187, 228, 179, +179, 235, 228, 1, 127, 253, 230, 230, 127, 179, 177, 224, 236, 211, 192, 213, 209, 229, 187, 228, +228, 179, 217, 209, 217, 214, 178, 82, 4, 206, 24, 63, 80, 58, 17, 42, 42, 42, 21, 42, +38, 83, 76, 87, 110, 76, 78, 104, 78, 39, 76, 78, 21, 49, 42, 21, 49, 21, 79, 21, +78, 112, 112, 99, 143, 88, 88, 93, 78, 79, 79, 21, 42, 49, 49, 42, 21, 78, 77, 39, +90, 133, 141, 139, 152, 149, 138, 153, 184, 206, 203, 211, 239, 233, 225, 238, 205, 206, 218, 204, +207, 190, 208, 201, 214, 200, 214, 213, 223, 223, 231, 211, 215, 60, 66, 204, 205, 202, 196, 205, +207, 206, 36, 36, 241, 211, 225, 227, 239, 246, 247, 164, 103, 161, 161, 115, 109, 187, 157, 17, +41, 38, 38, 42, 54, 67, 38, 64, 80, 74, 80, 64, 64, 64, 64, 64, 60, 64, 64, 60, +64, 64, 64, 64, 64, 64, 60, 64, 64, 64, 40, 57, 3, 239, 9, 43, 212, 239, 220, 213, +131, 40, 54, 2, 210, 251, 247, 246, 239, 234, 241, 211, 223, 190, 206, 198, 211, 203, 218, 223, +203, 203, 211, 184, 203, 223, 206, 203, 213, 209, 214, 227, 214, 212, 217, 228, 211, 197, 230, 200, +208, 231, 213, 236, 203, 204, 212, 217, 223, 236, 227, 236, 239, 224, 224, 247, 249, 224, 6, 238, +238, 238, 238, 155, 235, 235, 235, 235, 235, 230, 224, 228, 223, 215, 249, 228, 235, 228, 238, 235, +253, 1, 155, 6, 155, 209, 1, 155, 1, 228, 253, 249, 213, 116, 209, 217, 229, 223, 216, 229, +214, 225, 127, 154, 241, 66, 57, 104, 73, 21, 21, 52, 114, 49, 21, 21, 17, 87, 86, 76, +110, 80, 70, 94, 70, 21, 87, 78, 42, 21, 49, 21, 42, 49, 21, 49, 58, 93, 99, 99, +120, 88, 88, 99, 38, 21, 49, 49, 21, 21, 42, 21, 42, 78, 77, 70, 78, 110, 141, 133, +141, 162, 141, 141, 218, 199, 205, 207, 206, 203, 208, 215, 211, 36, 184, 190, 204, 196, 197, 208, +200, 214, 197, 213, 212, 213, 209, 209, 190, 223, 207, 222, 223, 213, 196, 195, 204, 203, 215, 211, +213, 213, 249, 213, 240, 232, 246, 239, 234, 220, 222, 220, 217, 187, 225, 46, 60, 69, 63, 57, +46, 57, 41, 38, 41, 38, 38, 41, 41, 12, 19, 41, 41, 39, 78, 63, 65, 82, 46, 63, +16, 19, 41, 38, 38, 38, 38, 76, 54, 221, 207, 49, 13, 220, 225, 145, 95, 90, 57, 47, +239, 252, 36, 215, 236, 125, 242, 205, 221, 225, 207, 191, 203, 185, 214, 208, 205, 208, 208, 233, +190, 212, 195, 205, 195, 204, 209, 217, 223, 231, 209, 227, 193, 197, 223, 223, 194, 223, 218, 215, +236, 236, 236, 213, 227, 208, 223, 231, 231, 1, 2, 2, 1, 1, 228, 155, 1, 250, 253, 209, +235, 238, 238, 232, 228, 235, 155, 225, 237, 1, 224, 235, 235, 1, 155, 176, 229, 127, 179, 1, +155, 179, 179, 176, 179, 127, 217, 226, 217, 127, 228, 217, 216, 194, 179, 179, 179, 176, 166, 211, +241, 5, 81, 73, 17, 42, 14, 72, 65, 49, 49, 42, 39, 76, 86, 78, 110, 72, 76, 90, +78, 17, 77, 78, 21, 42, 21, 49, 21, 42, 21, 21, 38, 76, 99, 88, 100, 56, 71, 80, +38, 17, 21, 42, 42, 42, 21, 49, 21, 78, 87, 39, 119, 110, 111, 133, 153, 152, 149, 141, +139, 160, 241, 36, 206, 215, 0, 180, 180, 198, 195, 212, 227, 249, 213, 213, 213, 214, 192, 227, +223, 196, 217, 225, 192, 192, 192, 216, 213, 188, 191, 191, 214, 231, 204, 208, 196, 190, 216, 227, +217, 214, 223, 213, 213, 196, 212, 223, 214, 234, 232, 166, 74, 74, 89, 89, 38, 41, 38, 41, +38, 38, 41, 38, 26, 54, 52, 19, 58, 101, 83, 73, 46, 54, 52, 16, 54, 54, 19, 41, +41, 58, 87, 40, 53, 214, 208, 51, 190, 208, 223, 93, 72, 86, 89, 57, 41, 9, 247, 19, +17, 99, 99, 146, 48, 48, 200, 245, 217, 185, 205, 220, 195, 203, 209, 192, 204, 211, 207, 196, +208, 216, 214, 228, 225, 225, 223, 229, 249, 249, 223, 249, 247, 247, 249, 249, 249, 223, 223, 242, +212, 218, 191, 212, 215, 155, 179, 2, 2, 238, 224, 155, 238, 238, 209, 238, 238, 235, 232, 236, +193, 212, 236, 225, 127, 224, 235, 209, 127, 179, 209, 179, 209, 155, 155, 176, 176, 176, 179, 179, +179, 179, 179, 127, 209, 209, 217, 187, 192, 127, 127, 187, 228, 146, 109, 223, 24, 19, 19, 39, +17, 23, 41, 146, 54, 23, 42, 21, 39, 87, 86, 76, 110, 87, 78, 89, 78, 62, 77, 77, +49, 21, 49, 42, 21, 49, 42, 39, 38, 76, 99, 88, 100, 71, 56, 71, 73, 17, 49, 42, +21, 21, 49, 21, 49, 78, 104, 20, 98, 118, 141, 107, 141, 152, 141, 152, 139, 120, 184, 184, +236, 222, 233, 221, 186, 196, 199, 185, 195, 213, 228, 214, 192, 216, 205, 237, 231, 214, 192, 192, +214, 192, 228, 192, 204, 185, 208, 214, 127, 135, 113, 214, 203, 193, 197, 231, 227, 225, 225, 225, +196, 200, 200, 194, 204, 178, 205, 178, 63, 44, 38, 76, 68, 41, 38, 38, 38, 41, 19, 38, +26, 54, 54, 38, 80, 83, 80, 74, 61, 54, 54, 19, 54, 54, 41, 19, 58, 105, 56, 19, +18, 71, 101, 37, 207, 198, 50, 38, 41, 76, 101, 96, 41, 16, 245, 38, 88, 67, 106, 99, +99, 99, 124, 228, 225, 201, 204, 223, 208, 191, 204, 213, 213, 196, 195, 222, 227, 249, 229, 249, +1, 249, 249, 217, 247, 247, 249, 253, 249, 247, 226, 253, 249, 179, 249, 238, 238, 253, 253, 248, +249, 1, 245, 1, 248, 1, 6, 1, 235, 238, 224, 230, 225, 199, 201, 213, 245, 245, 209, 240, +249, 223, 228, 217, 200, 209, 183, 217, 155, 176, 155, 155, 155, 155, 155, 155, 127, 1, 127, 179, +228, 200, 176, 127, 127, 127, 127, 217, 124, 115, 242, 68, 17, 38, 17, 21, 39, 42, 21, 23, +21, 18, 21, 17, 38, 86, 76, 87, 118, 87, 70, 98, 78, 17, 87, 78, 21, 42, 21, 21, +49, 49, 21, 39, 73, 74, 56, 56, 79, 56, 56, 57, 96, 58, 21, 21, 49, 49, 21, 49, +21, 78, 77, 20, 101, 119, 141, 110, 141, 165, 141, 158, 143, 160, 206, 206, 206, 233, 186, 208, +199, 196, 205, 211, 190, 208, 228, 245, 225, 208, 241, 236, 225, 213, 192, 187, 192, 214, 227, 213, +214, 227, 228, 228, 127, 161, 93, 171, 246, 222, 227, 239, 231, 225, 247, 245, 248, 213, 200, 192, +192, 217, 65, 43, 89, 46, 46, 12, 85, 44, 41, 44, 60, 60, 60, 60, 65, 61, 64, 65, +90, 86, 94, 60, 65, 82, 74, 82, 81, 46, 82, 60, 80, 56, 41, 57, 43, 58, 41, 139, +198, 210, 40, 46, 61, 15, 56, 86, 88, 16, 232, 31, 81, 220, 236, 99, 99, 146, 149, 167, +222, 204, 192, 223, 223, 212, 223, 204, 212, 217, 227, 227, 231, 247, 253, 253, 249, 249, 249, 247, +249, 247, 247, 231, 226, 228, 249, 249, 227, 249, 253, 248, 1, 155, 224, 253, 245, 1, 155, 1, +250, 2, 1, 127, 235, 235, 230, 230, 245, 220, 200, 195, 235, 235, 245, 236, 218, 219, 127, 179, +179, 228, 179, 155, 224, 209, 155, 155, 179, 155, 1, 179, 179, 127, 209, 200, 209, 179, 179, 179, +226, 187, 209, 238, 166, 217, 23, 21, 21, 17, 49, 39, 21, 18, 31, 116, 16, 21, 42, 21, +38, 76, 77, 77, 99, 87, 73, 89, 78, 21, 73, 70, 49, 21, 42, 49, 42, 21, 49, 57, +107, 41, 56, 71, 21, 71, 56, 41, 78, 70, 49, 21, 21, 49, 21, 79, 91, 101, 105, 78, +98, 110, 141, 110, 141, 149, 141, 141, 143, 175, 206, 251, 180, 215, 215, 203, 204, 228, 211, 191, +212, 206, 191, 247, 227, 200, 214, 214, 192, 214, 192, 208, 200, 209, 225, 214, 192, 228, 179, 228, +232, 225, 17, 25, 178, 214, 221, 228, 200, 240, 250, 228, 227, 213, 192, 214, 208, 242, 52, 58, +19, 54, 54, 42, 54, 47, 77, 96, 47, 82, 82, 97, 82, 42, 97, 97, 80, 98, 73, 92, +85, 92, 92, 92, 97, 54, 54, 52, 40, 38, 92, 93, 93, 67, 93, 134, 233, 9, 93, 67, +52, 46, 57, 57, 115, 25, 32, 53, 194, 207, 202, 212, 146, 117, 146, 167, 178, 206, 241, 215, +218, 249, 248, 249, 249, 240, 245, 235, 245, 2, 2, 224, 1, 1, 1, 253, 253, 1, 253, 248, +249, 248, 248, 249, 249, 1, 253, 253, 253, 155, 248, 250, 232, 245, 155, 1, 2, 2, 1, 238, +238, 250, 224, 235, 230, 230, 225, 214, 209, 202, 212, 217, 208, 217, 179, 209, 209, 179, 6, 174, +224, 179, 179, 209, 224, 230, 127, 2, 179, 174, 1, 127, 155, 224, 224, 224, 235, 232, 2, 114, +235, 32, 42, 17, 49, 21, 21, 18, 42, 21, 209, 230, 146, 23, 49, 39, 17, 87, 86, 76, +110, 76, 77, 94, 78, 17, 77, 78, 21, 42, 49, 42, 21, 42, 21, 70, 78, 41, 56, 56, +21, 56, 56, 19, 73, 69, 21, 79, 79, 91, 79, 79, 79, 95, 128, 59, 105, 129, 141, 118, +141, 159, 141, 152, 143, 206, 210, 184, 211, 237, 236, 214, 225, 213, 217, 191, 191, 195, 197, 239, +239, 214, 209, 228, 213, 214, 213, 217, 228, 192, 214, 217, 209, 209, 155, 209, 3, 53, 17, 39, +39, 131, 225, 207, 198, 193, 213, 217, 240, 231, 218, 225, 234, 48, 54, 74, 96, 67, 67, 16, +67, 92, 72, 90, 81, 92, 92, 74, 74, 81, 81, 92, 90, 68, 105, 89, 72, 80, 80, 72, +73, 61, 54, 61, 19, 110, 71, 41, 57, 41, 41, 21, 102, 19, 19, 47, 42, 19, 57, 88, +232, 228, 53, 10, 220, 203, 198, 222, 115, 146, 149, 146, 127, 221, 206, 233, 247, 253, 155, 238, +248, 235, 235, 235, 235, 253, 235, 235, 2, 245, 1, 248, 253, 248, 253, 253, 253, 248, 247, 248, +253, 253, 248, 249, 248, 238, 232, 250, 248, 250, 179, 1, 238, 224, 2, 1, 230, 238, 238, 238, +238, 235, 232, 238, 179, 183, 200, 209, 127, 127, 179, 228, 228, 179, 155, 155, 209, 179, 179, 209, +224, 224, 209, 209, 116, 1, 179, 1, 179, 127, 132, 113, 113, 103, 13, 52, 179, 49, 42, 21, +42, 21, 42, 21, 23, 248, 230, 238, 49, 18, 21, 21, 39, 87, 76, 87, 110, 77, 78, 98, +57, 39, 77, 70, 21, 49, 49, 21, 21, 49, 42, 69, 78, 19, 56, 56, 42, 56, 56, 41, +95, 69, 79, 49, 79, 100, 100, 100, 100, 105, 128, 77, 98, 129, 141, 110, 153, 152, 141, 158, +105, 123, 210, 206, 208, 246, 222, 213, 223, 204, 227, 227, 213, 204, 192, 186, 213, 228, 192, 227, +249, 194, 217, 238, 176, 214, 228, 217, 209, 232, 115, 16, 21, 61, 19, 17, 3, 53, 105, 203, +211, 212, 227, 227, 227, 208, 223, 208, 220, 47, 61, 63, 63, 96, 81, 81, 97, 94, 87, 83, +105, 92, 81, 81, 81, 81, 81, 64, 73, 82, 94, 80, 74, 81, 64, 74, 60, 82, 61, 74, +80, 68, 41, 41, 38, 38, 38, 41, 41, 41, 38, 42, 54, 46, 56, 115, 234, 236, 239, 213, +207, 198, 215, 205, 197, 146, 149, 161, 178, 212, 157, 157, 245, 235, 228, 227, 248, 235, 232, 235, +235, 235, 235, 235, 235, 232, 235, 1, 250, 244, 253, 1, 1, 1, 1, 248, 247, 248, 250, 245, +245, 250, 250, 245, 238, 248, 253, 1, 230, 230, 6, 235, 187, 228, 209, 214, 201, 235, 1, 127, +1, 1, 1, 179, 179, 2, 127, 176, 155, 224, 224, 179, 209, 155, 127, 187, 1, 194, 217, 238, +224, 1, 1, 217, 217, 209, 145, 100, 63, 42, 42, 27, 58, 21, 42, 49, 21, 78, 63, 88, +226, 209, 230, 127, 23, 21, 42, 42, 38, 76, 87, 77, 104, 86, 77, 98, 58, 41, 72, 78, +42, 21, 21, 42, 49, 42, 21, 69, 73, 38, 68, 71, 21, 71, 68, 57, 78, 69, 79, 100, +100, 100, 100, 120, 120, 143, 130, 98, 118, 137, 149, 134, 141, 138, 149, 152, 139, 119, 103, 207, +208, 254, 222, 197, 185, 190, 213, 228, 209, 225, 192, 208, 197, 197, 196, 229, 227, 214, 228, 228, +200, 228, 127, 209, 221, 242, 68, 60, 54, 61, 38, 38, 21, 53, 112, 239, 208, 213, 242, 231, +214, 249, 229, 214, 221, 53, 52, 69, 58, 74, 92, 74, 61, 106, 83, 129, 94, 101, 118, 81, +81, 90, 80, 92, 101, 89, 80, 89, 65, 42, 52, 26, 54, 52, 38, 58, 41, 38, 38, 38, +41, 38, 38, 41, 38, 41, 38, 44, 61, 19, 58, 54, 233, 239, 251, 198, 191, 198, 211, 196, +190, 99, 171, 220, 229, 187, 217, 228, 232, 157, 157, 201, 225, 155, 235, 235, 235, 235, 235, 235, +245, 235, 235, 245, 250, 238, 247, 249, 1, 1, 253, 248, 250, 248, 244, 245, 240, 248, 2, 248, +249, 247, 240, 248, 224, 224, 6, 155, 217, 186, 188, 208, 213, 179, 209, 179, 155, 179, 179, 176, +179, 179, 1, 1, 238, 230, 238, 179, 127, 179, 179, 179, 155, 238, 217, 217, 224, 230, 127, 179, +179, 179, 228, 28, 58, 21, 39, 49, 21, 49, 21, 21, 57, 82, 131, 179, 235, 209, 235, 2, +42, 21, 23, 42, 39, 86, 86, 73, 104, 80, 77, 94, 58, 20, 72, 78, 21, 49, 42, 21, +42, 49, 21, 69, 78, 17, 56, 56, 21, 71, 56, 58, 73, 83, 91, 100, 100, 120, 120, 143, +143, 139, 136, 119, 139, 150, 149, 142, 152, 149, 152, 158, 139, 163, 178, 184, 206, 231, 200, 200, +236, 191, 205, 236, 234, 245, 225, 214, 214, 216, 214, 197, 227, 225, 200, 214, 214, 214, 213, 192, +200, 75, 76, 96, 44, 41, 41, 20, 49, 54, 114, 213, 202, 206, 212, 247, 234, 3, 54, 54, +208, 48, 54, 96, 89, 89, 89, 89, 89, 93, 106, 110, 133, 157, 132, 147, 89, 80, 89, 89, +74, 92, 90, 76, 61, 54, 54, 42, 52, 54, 40, 40, 17, 41, 41, 41, 41, 41, 41, 41, +38, 19, 41, 38, 38, 57, 86, 59, 246, 239, 233, 252, 222, 191, 208, 225, 93, 146, 173, 221, +228, 200, 213, 192, 228, 166, 182, 228, 235, 250, 1, 245, 245, 2, 235, 245, 235, 235, 235, 250, +250, 6, 224, 238, 247, 250, 235, 155, 179, 253, 250, 2, 253, 253, 250, 213, 183, 209, 247, 235, +235, 1, 179, 127, 200, 186, 183, 194, 209, 217, 209, 155, 155, 179, 155, 179, 179, 230, 238, 1, +155, 224, 155, 176, 179, 2, 155, 179, 179, 179, 1, 209, 209, 1, 1, 1, 176, 179, 203, 51, +70, 18, 20, 42, 21, 42, 18, 21, 60, 84, 225, 179, 155, 179, 249, 23, 42, 48, 33, 23, +17, 77, 88, 76, 96, 90, 77, 86, 58, 17, 83, 65, 42, 21, 49, 21, 49, 21, 42, 69, +73, 38, 68, 56, 42, 71, 56, 38, 101, 90, 100, 100, 123, 143, 143, 143, 120, 163, 141, 118, +139, 142, 162, 141, 158, 152, 162, 142, 118, 153, 172, 178, 239, 231, 217, 229, 223, 208, 225, 209, +228, 227, 223, 208, 187, 223, 236, 227, 227, 231, 192, 192, 192, 192, 194, 192, 221, 3, 88, 83, +21, 61, 60, 63, 61, 67, 81, 106, 219, 206, 212, 206, 233, 197, 113, 67, 92, 81, 61, 63, +69, 63, 58, 69, 69, 83, 78, 138, 124, 176, 176, 132, 156, 46, 74, 81, 81, 81, 60, 80, +68, 61, 81, 73, 81, 74, 65, 63, 60, 21, 21, 21, 21, 49, 69, 65, 69, 65, 73, 60, +60, 81, 70, 70, 95, 75, 235, 235, 240, 236, 193, 155, 155, 117, 117, 227, 234, 226, 192, 217, +214, 239, 189, 240, 155, 238, 235, 179, 245, 224, 155, 230, 224, 155, 155, 238, 224, 238, 155, 155, +1, 179, 1, 253, 238, 253, 253, 253, 245, 235, 235, 235, 209, 235, 235, 234, 247, 179, 217, 188, +186, 190, 228, 209, 238, 238, 238, 155, 155, 224, 224, 230, 6, 224, 155, 2, 1, 155, 1, 176, +1, 116, 1, 179, 2, 217, 179, 1, 127, 228, 6, 6, 155, 179, 208, 175, 67, 67, 88, 14, +13, 14, 20, 42, 69, 109, 155, 155, 179, 209, 226, 39, 21, 23, 23, 18, 17, 87, 98, 76, +104, 86, 77, 98, 58, 38, 72, 78, 21, 42, 21, 42, 21, 49, 49, 63, 82, 39, 56, 56, +42, 71, 56, 70, 101, 118, 100, 120, 143, 143, 160, 143, 163, 153, 152, 160, 142, 141, 159, 141, +152, 159, 152, 141, 139, 178, 145, 226, 239, 236, 250, 217, 217, 214, 208, 214, 222, 236, 214, 214, +249, 228, 214, 214, 225, 228, 194, 192, 192, 200, 200, 200, 209, 223, 88, 72, 54, 67, 57, 63, +47, 67, 43, 40, 52, 232, 245, 250, 208, 208, 82, 73, 114, 109, 80, 74, 64, 81, 92, 97, +112, 93, 122, 156, 176, 166, 176, 176, 126, 114, 80, 81, 74, 81, 81, 92, 57, 41, 41, 44, +21, 61, 114, 3, 103, 91, 14, 41, 19, 42, 21, 21, 21, 42, 58, 57, 57, 44, 71, 80, +89, 86, 166, 225, 243, 239, 228, 176, 238, 200, 85, 144, 225, 231, 197, 197, 216, 196, 201, 235, +126, 126, 235, 224, 230, 224, 155, 230, 177, 155, 179, 155, 238, 235, 228, 235, 179, 176, 127, 155, +230, 224, 225, 217, 235, 230, 235, 235, 230, 235, 230, 230, 127, 238, 200, 188, 183, 192, 1, 238, +224, 177, 224, 209, 238, 238, 209, 1, 224, 174, 55, 6, 1, 155, 155, 6, 174, 1, 179, 127, +176, 1, 176, 179, 127, 238, 230, 55, 174, 176, 176, 174, 132, 155, 176, 3, 103, 171, 226, 16, +23, 60, 179, 179, 238, 2, 49, 42, 21, 42, 21, 42, 38, 76, 98, 87, 110, 76, 87, 86, +58, 42, 82, 78, 21, 49, 42, 21, 49, 42, 21, 73, 78, 17, 56, 71, 21, 71, 71, 57, +79, 136, 119, 143, 143, 143, 153, 160, 160, 150, 161, 173, 161, 163, 162, 149, 152, 159, 165, 141, +121, 178, 137, 187, 246, 236, 216, 231, 231, 225, 209, 227, 227, 208, 228, 209, 194, 245, 245, 227, +227, 231, 217, 228, 214, 213, 214, 214, 225, 232, 223, 88, 44, 40, 41, 17, 48, 54, 47, 41, +17, 48, 145, 127, 116, 54, 47, 157, 155, 132, 114, 82, 74, 61, 92, 61, 108, 108, 93, 163, +176, 176, 176, 176, 155, 132, 65, 57, 43, 63, 46, 57, 41, 41, 78, 97, 58, 54, 6, 155, +224, 1, 127, 48, 17, 38, 39, 38, 17, 39, 21, 21, 42, 52, 61, 90, 71, 83, 89, 10, +4, 231, 232, 232, 224, 179, 183, 146, 166, 220, 208, 225, 200, 213, 214, 155, 146, 132, 226, 209, +230, 235, 224, 235, 235, 235, 235, 245, 235, 225, 238, 224, 228, 217, 217, 155, 224, 209, 155, 176, +6, 230, 209, 209, 179, 1, 235, 155, 238, 238, 238, 217, 200, 155, 127, 127, 238, 230, 238, 177, +177, 224, 224, 230, 6, 224, 224, 224, 235, 179, 127, 179, 235, 1, 209, 238, 6, 177, 6, 176, +116, 155, 224, 155, 176, 179, 174, 179, 245, 238, 245, 245, 235, 235, 226, 52, 42, 42, 249, 238, +109, 21, 18, 42, 18, 49, 42, 21, 39, 87, 98, 77, 99, 86, 83, 83, 47, 54, 85, 70, +21, 42, 49, 21, 42, 21, 20, 90, 42, 38, 71, 56, 21, 71, 68, 77, 79, 101, 141, 120, +119, 160, 172, 116, 124, 147, 167, 132, 156, 152, 162, 152, 165, 159, 149, 158, 129, 171, 217, 238, +235, 213, 213, 225, 227, 227, 240, 250, 209, 200, 235, 179, 192, 187, 217, 228, 227, 235, 235, 235, +238, 227, 227, 214, 229, 213, 234, 217, 145, 59, 60, 69, 67, 67, 53, 5, 65, 63, 93, 108, +93, 93, 145, 224, 224, 176, 179, 85, 61, 67, 61, 67, 61, 114, 67, 156, 132, 132, 176, 238, +6, 177, 126, 131, 41, 18, 42, 52, 41, 78, 83, 39, 23, 54, 126, 55, 177, 55, 55, 132, +42, 38, 17, 21, 39, 17, 39, 21, 52, 54, 61, 86, 86, 94, 94, 89, 89, 53, 246, 246, +232, 179, 224, 179, 216, 208, 227, 225, 228, 225, 214, 119, 59, 92, 31, 235, 235, 238, 235, 235, +237, 216, 224, 209, 155, 232, 230, 224, 235, 179, 209, 155, 217, 217, 209, 176, 177, 224, 179, 179, +176, 127, 179, 209, 209, 238, 224, 238, 238, 155, 6, 155, 155, 224, 230, 224, 224, 224, 230, 177, +177, 155, 235, 235, 230, 155, 155, 155, 1, 209, 230, 230, 155, 116, 155, 155, 155, 155, 176, 1, +209, 200, 209, 217, 179, 224, 116, 1, 1, 1, 21, 14, 14, 18, 226, 224, 132, 124, 25, 24, +42, 21, 21, 42, 39, 77, 94, 87, 110, 87, 76, 77, 61, 54, 61, 58, 49, 21, 42, 49, +21, 58, 83, 58, 21, 58, 56, 56, 42, 71, 56, 76, 91, 100, 119, 154, 143, 153, 160, 173, +224, 176, 124, 124, 165, 165, 159, 158, 162, 159, 165, 136, 105, 178, 220, 235, 235, 209, 223, 225, +225, 227, 248, 245, 192, 187, 209, 192, 209, 192, 192, 178, 234, 235, 235, 235, 235, 235, 214, 249, +231, 217, 209, 208, 213, 51, 236, 48, 65, 46, 25, 178, 124, 74, 73, 61, 166, 132, 176, 179, +155, 6, 155, 21, 120, 74, 41, 57, 69, 69, 19, 161, 174, 132, 155, 55, 177, 55, 177, 166, +42, 99, 67, 61, 78, 101, 20, 39, 21, 145, 174, 114, 53, 52, 109, 146, 22, 42, 21, 49, +42, 21, 39, 42, 49, 83, 94, 88, 87, 94, 80, 83, 80, 80, 240, 243, 245, 235, 235, 235, +224, 235, 227, 193, 214, 227, 213, 196, 239, 239, 109, 52, 53, 224, 238, 235, 204, 248, 230, 235, +238, 6, 177, 177, 177, 235, 209, 155, 230, 217, 179, 155, 224, 224, 174, 179, 155, 176, 155, 179, +127, 238, 238, 238, 238, 224, 155, 224, 6, 6, 177, 1, 235, 238, 250, 224, 177, 155, 1, 155, +238, 155, 176, 174, 155, 1, 177, 224, 228, 213, 127, 179, 155, 1, 1, 179, 174, 155, 209, 179, +127, 218, 2, 55, 224, 245, 24, 103, 226, 49, 229, 238, 230, 55, 248, 3, 42, 42, 39, 39, +17, 83, 101, 72, 110, 86, 87, 86, 58, 19, 63, 57, 21, 49, 21, 21, 42, 92, 69, 42, +21, 38, 71, 71, 42, 56, 56, 77, 79, 100, 123, 134, 166, 166, 143, 163, 163, 166, 6, 127, +145, 167, 168, 165, 167, 167, 168, 152, 127, 247, 235, 235, 235, 243, 249, 240, 248, 224, 228, 232, +235, 235, 209, 188, 200, 235, 1, 159, 132, 235, 235, 235, 235, 235, 221, 227, 214, 225, 214, 213, +223, 212, 231, 214, 225, 227, 48, 238, 126, 61, 46, 109, 6, 55, 155, 225, 179, 155, 167, 171, +155, 166, 65, 73, 80, 72, 72, 171, 132, 132, 132, 132, 174, 174, 176, 174, 132, 176, 174, 144, +136, 117, 106, 112, 112, 134, 122, 97, 82, 65, 80, 81, 81, 81, 80, 81, 81, 81, 93, 82, +21, 88, 90, 77, 94, 77, 78, 96, 80, 106, 78, 225, 246, 234, 224, 235, 235, 235, 214, 191, +223, 227, 226, 214, 221, 221, 145, 61, 116, 235, 82, 116, 245, 232, 179, 235, 238, 179, 6, 55, +6, 179, 209, 238, 177, 55, 124, 126, 224, 224, 224, 209, 176, 1, 155, 176, 1, 238, 238, 179, +238, 209, 155, 155, 224, 55, 177, 209, 209, 230, 230, 177, 55, 6, 174, 155, 6, 155, 179, 224, +174, 55, 6, 179, 179, 226, 217, 253, 179, 209, 1, 2, 176, 155, 174, 176, 179, 2, 6, 177, +230, 238, 2, 225, 209, 228, 2, 224, 249, 253, 245, 242, 42, 42, 21, 17, 38, 72, 89, 77, +104, 87, 77, 100, 59, 42, 52, 52, 21, 42, 21, 52, 54, 26, 21, 21, 78, 58, 56, 56, +21, 71, 68, 57, 79, 100, 120, 143, 156, 161, 139, 153, 160, 176, 176, 124, 166, 173, 173, 167, +127, 176, 161, 228, 235, 235, 235, 235, 232, 235, 1, 1, 1, 239, 247, 238, 235, 235, 235, 200, +181, 235, 235, 178, 179, 235, 235, 232, 235, 235, 225, 213, 214, 213, 225, 213, 227, 225, 228, 213, +208, 220, 179, 115, 85, 85, 97, 92, 92, 52, 97, 116, 235, 155, 176, 176, 174, 224, 114, 74, +106, 106, 93, 115, 174, 126, 55, 177, 174, 55, 55, 55, 174, 155, 176, 126, 126, 114, 147, 159, +147, 131, 93, 108, 108, 92, 61, 61, 74, 61, 61, 61, 61, 61, 61, 61, 21, 95, 88, 98, +76, 95, 96, 88, 94, 73, 72, 95, 241, 220, 224, 235, 236, 197, 214, 208, 214, 225, 232, 221, +208, 3, 27, 41, 235, 244, 42, 52, 42, 223, 232, 37, 228, 179, 124, 177, 6, 235, 209, 217, +230, 6, 146, 124, 230, 6, 155, 155, 174, 55, 174, 155, 155, 209, 238, 253, 216, 127, 235, 230, +209, 174, 6, 199, 231, 177, 177, 238, 238, 238, 127, 179, 6, 6, 174, 174, 127, 6, 155, 179, +179, 127, 127, 228, 1, 179, 179, 1, 209, 179, 176, 224, 224, 224, 55, 55, 224, 224, 179, 1, +1, 155, 217, 223, 212, 127, 1, 48, 18, 21, 17, 42, 41, 86, 94, 76, 110, 86, 115, 209, +26, 19, 54, 54, 42, 49, 20, 61, 67, 21, 42, 58, 94, 44, 73, 71, 21, 71, 56, 69, +79, 100, 100, 91, 143, 143, 150, 160, 163, 166, 132, 166, 166, 173, 166, 127, 173, 176, 228, 232, +245, 235, 250, 235, 235, 238, 174, 6, 238, 1, 224, 235, 235, 235, 235, 235, 243, 235, 235, 221, +232, 245, 245, 250, 235, 235, 209, 228, 179, 217, 217, 217, 209, 224, 224, 228, 239, 212, 179, 231, +196, 155, 116, 25, 73, 124, 116, 100, 109, 155, 6, 155, 55, 126, 108, 82, 81, 81, 81, 92, +48, 179, 6, 132, 132, 176, 155, 155, 55, 6, 176, 179, 176, 176, 166, 132, 124, 157, 114, 108, +112, 92, 81, 92, 97, 92, 61, 85, 97, 61, 61, 61, 82, 83, 89, 90, 80, 87, 89, 94, +96, 68, 89, 80, 76, 116, 244, 218, 227, 243, 243, 244, 237, 240, 53, 25, 42, 58, 41, 41, +42, 42, 12, 145, 45, 41, 71, 74, 83, 114, 225, 228, 67, 82, 109, 177, 177, 124, 146, 124, +179, 179, 1, 176, 179, 1, 155, 174, 1, 249, 209, 209, 238, 217, 179, 209, 238, 127, 173, 187, +187, 187, 209, 235, 217, 223, 1, 1, 179, 6, 55, 177, 177, 176, 195, 208, 190, 238, 179, 2, +1, 2, 228, 155, 235, 1, 179, 224, 228, 224, 55, 55, 6, 155, 155, 1, 155, 155, 6, 55, +55, 174, 155, 55, 109, 23, 49, 21, 62, 86, 98, 77, 110, 98, 72, 73, 90, 57, 61, 46, +21, 42, 39, 46, 21, 42, 21, 77, 76, 70, 77, 76, 42, 56, 44, 60, 79, 138, 117, 149, +121, 136, 162, 142, 121, 171, 166, 132, 176, 116, 173, 176, 176, 176, 253, 240, 235, 232, 235, 232, +235, 235, 224, 224, 155, 155, 1, 235, 235, 235, 235, 235, 235, 235, 235, 235, 176, 232, 235, 235, +235, 245, 245, 209, 245, 238, 1, 245, 230, 230, 230, 253, 228, 225, 238, 228, 223, 249, 238, 1, +12, 74, 109, 115, 53, 217, 6, 155, 132, 67, 20, 19, 38, 58, 41, 41, 61, 48, 124, 6, +126, 55, 116, 127, 127, 116, 132, 145, 109, 124, 109, 124, 124, 124, 124, 147, 72, 57, 57, 57, +57, 57, 47, 49, 44, 57, 57, 61, 42, 65, 61, 49, 16, 40, 86, 61, 54, 57, 38, 38, +88, 83, 100, 84, 145, 239, 239, 75, 84, 83, 69, 41, 70, 96, 57, 42, 41, 38, 18, 72, +76, 46, 132, 54, 16, 1, 24, 41, 41, 114, 224, 155, 2, 47, 6, 235, 127, 155, 230, 217, +1, 55, 174, 55, 127, 217, 127, 179, 235, 216, 225, 226, 228, 226, 242, 2, 228, 228, 238, 2, +127, 1, 238, 238, 226, 127, 6, 55, 177, 155, 202, 199, 206, 214, 55, 224, 55, 155, 1, 1, +224, 155, 179, 240, 212, 179, 230, 230, 177, 177, 177, 6, 6, 155, 55, 55, 55, 132, 146, 114, +65, 98, 89, 90, 84, 109, 100, 86, 70, 100, 94, 65, 54, 48, 70, 21, 21, 59, 86, 107, +69, 90, 71, 73, 80, 58, 77, 76, 21, 64, 54, 54, 20, 138, 138, 138, 100, 137, 149, 150, +143, 163, 166, 116, 116, 145, 127, 176, 179, 155, 176, 235, 238, 235, 235, 235, 235, 235, 224, 224, +224, 155, 1, 176, 155, 224, 224, 235, 232, 232, 235, 1, 67, 1, 235, 235, 209, 240, 232, 228, +124, 238, 230, 230, 176, 114, 127, 161, 226, 214, 245, 1, 109, 17, 48, 238, 54, 40, 19, 67, +230, 155, 55, 174, 55, 109, 60, 69, 56, 57, 44, 57, 54, 55, 132, 177, 177, 6, 116, 127, +145, 116, 116, 132, 116, 124, 166, 166, 109, 124, 109, 124, 78, 58, 38, 38, 38, 57, 57, 56, +14, 56, 94, 63, 65, 93, 57, 19, 41, 58, 80, 21, 54, 19, 38, 80, 58, 94, 68, 72, +72, 100, 79, 81, 82, 84, 82, 90, 78, 38, 41, 42, 20, 42, 88, 80, 7, 155, 126, 54, +42, 48, 44, 57, 95, 109, 55, 6, 32, 132, 177, 6, 228, 209, 177, 6, 1, 174, 55, 55, +6, 1, 209, 1, 217, 174, 126, 116, 235, 1, 209, 217, 127, 238, 228, 226, 228, 2, 238, 213, +216, 127, 55, 174, 174, 174, 217, 231, 209, 235, 155, 155, 224, 126, 176, 155, 176, 197, 209, 176, +176, 6, 6, 174, 177, 177, 177, 177, 177, 55, 55, 174, 155, 127, 157, 161, 145, 145, 242, 24, +98, 145, 95, 76, 78, 78, 104, 59, 46, 31, 63, 23, 18, 57, 94, 104, 59, 99, 77, 70, +78, 58, 95, 58, 21, 44, 67, 52, 57, 142, 128, 138, 87, 143, 149, 129, 139, 160, 159, 156, +115, 161, 164, 166, 176, 176, 155, 235, 245, 235, 250, 235, 235, 235, 177, 55, 1, 2, 179, 155, +235, 235, 224, 230, 230, 209, 235, 235, 1, 179, 155, 2, 155, 155, 145, 109, 124, 109, 124, 109, +109, 48, 99, 116, 52, 171, 224, 238, 48, 41, 19, 54, 176, 127, 48, 47, 209, 209, 224, 55, +132, 81, 80, 60, 81, 74, 81, 81, 52, 124, 126, 6, 230, 1, 127, 127, 116, 116, 116, 124, +109, 166, 174, 132, 109, 124, 124, 116, 115, 40, 17, 38, 18, 38, 14, 19, 18, 78, 57, 56, +93, 57, 41, 38, 38, 38, 88, 27, 65, 19, 94, 79, 94, 79, 95, 95, 82, 95, 82, 84, +82, 95, 82, 82, 65, 65, 65, 82, 65, 101, 100, 83, 127, 55, 52, 49, 23, 42, 58, 88, +59, 109, 6, 116, 47, 155, 116, 54, 127, 217, 217, 6, 116, 179, 55, 55, 177, 55, 132, 127, +174, 55, 55, 177, 55, 1, 1, 116, 1, 6, 155, 155, 1, 1, 1, 228, 155, 177, 177, 55, +224, 1, 174, 174, 224, 1, 174, 1, 1, 6, 126, 55, 176, 227, 155, 177, 177, 55, 223, 239, +230, 230, 230, 177, 177, 55, 55, 230, 1, 240, 235, 224, 224, 232, 227, 79, 87, 79, 95, 95, +79, 79, 95, 59, 38, 39, 59, 49, 49, 58, 95, 104, 59, 98, 76, 70, 83, 58, 79, 77, +23, 57, 58, 42, 49, 117, 88, 137, 78, 120, 149, 120, 119, 143, 165, 150, 129, 152, 166, 166, +176, 126, 126, 174, 176, 235, 235, 245, 235, 155, 174, 176, 245, 214, 216, 217, 244, 236, 231, 209, +1, 2, 217, 209, 245, 250, 238, 127, 109, 115, 122, 238, 238, 116, 54, 124, 245, 235, 226, 115, +16, 11, 238, 235, 21, 17, 63, 155, 230, 235, 209, 155, 179, 209, 55, 124, 76, 58, 68, 78, +72, 63, 43, 63, 21, 67, 179, 155, 126, 116, 127, 127, 127, 145, 145, 145, 124, 178, 179, 127, +109, 109, 124, 124, 124, 124, 17, 42, 18, 18, 47, 54, 16, 78, 58, 73, 58, 20, 20, 38, +18, 46, 52, 60, 18, 95, 73, 78, 58, 79, 78, 78, 100, 82, 82, 82, 78, 82, 65, 78, +78, 78, 83, 78, 78, 78, 78, 39, 46, 116, 61, 17, 39, 38, 89, 59, 40, 31, 47, 18, +45, 23, 75, 16, 6, 155, 245, 179, 217, 116, 6, 55, 174, 155, 55, 55, 55, 55, 55, 177, +55, 6, 6, 155, 55, 177, 55, 55, 55, 55, 55, 55, 109, 145, 54, 157, 132, 174, 177, 177, +55, 174, 177, 55, 177, 55, 55, 55, 224, 116, 115, 109, 124, 132, 1, 67, 54, 230, 230, 230, +6, 55, 174, 132, 1, 249, 3, 115, 3, 4, 100, 78, 79, 78, 95, 95, 78, 100, 95, 59, +18, 39, 59, 23, 23, 59, 95, 95, 58, 98, 82, 23, 78, 59, 84, 78, 23, 57, 20, 14, +42, 129, 128, 142, 79, 100, 138, 120, 101, 160, 142, 147, 161, 136, 157, 155, 174, 174, 174, 177, +174, 174, 6, 235, 235, 155, 179, 179, 216, 203, 236, 211, 203, 207, 234, 247, 234, 232, 240, 244, +245, 155, 127, 100, 78, 100, 143, 116, 155, 6, 235, 245, 247, 227, 31, 20, 3, 249, 109, 116, +2, 18, 56, 179, 235, 127, 179, 224, 155, 224, 124, 93, 80, 80, 73, 72, 69, 72, 65, 60, +69, 77, 124, 132, 155, 127, 116, 173, 173, 166, 145, 109, 145, 145, 173, 172, 157, 124, 166, 132, +126, 126, 109, 44, 19, 42, 23, 48, 31, 95, 58, 78, 38, 20, 18, 18, 42, 31, 48, 75, +65, 58, 95, 78, 100, 78, 78, 120, 78, 102, 97, 102, 82, 97, 102, 97, 97, 102, 97, 97, +97, 97, 82, 78, 82, 114, 126, 124, 74, 77, 58, 39, 39, 18, 18, 41, 39, 41, 39, 44, +61, 109, 55, 224, 155, 155, 55, 177, 126, 126, 55, 177, 126, 177, 55, 55, 6, 6, 55, 6, +230, 177, 126, 54, 55, 55, 55, 114, 78, 78, 79, 72, 69, 126, 177, 177, 55, 55, 6, 126, +55, 126, 126, 174, 176, 92, 95, 83, 88, 88, 114, 146, 126, 55, 174, 126, 109, 46, 60, 74, +47, 81, 95, 101, 78, 100, 78, 79, 95, 79, 95, 95, 79, 95, 95, 65, 52, 52, 59, 23, +49, 42, 95, 119, 59, 105, 85, 48, 95, 59, 79, 78, 23, 57, 52, 52, 42, 118, 76, 142, +79, 100, 139, 100, 100, 123, 142, 161, 124, 140, 142, 167, 167, 124, 126, 55, 174, 155, 177, 174, +179, 179, 155, 227, 204, 212, 6, 235, 247, 250, 171, 145, 116, 161, 144, 47, 112, 92, 95, 78, +120, 143, 101, 85, 116, 238, 235, 1, 1, 1, 127, 22, 226, 238, 155, 54, 2, 238, 1, 54, +1, 132, 47, 5, 9, 116, 147, 65, 82, 84, 92, 82, 101, 82, 95, 96, 96, 89, 132, 55, +126, 176, 176, 126, 126, 176, 166, 176, 173, 173, 166, 132, 132, 132, 132, 174, 174, 177, 126, 85, +85, 85, 47, 113, 59, 78, 58, 100, 38, 39, 18, 39, 42, 20, 23, 82, 78, 98, 58, 79, +78, 78, 120, 100, 95, 58, 59, 58, 59, 59, 59, 59, 59, 59, 26, 26, 27, 26, 27, 27, +26, 26, 81, 126, 6, 124, 18, 39, 20, 20, 42, 20, 39, 39, 18, 42, 42, 81, 82, 132, +55, 55, 55, 6, 55, 177, 177, 55, 177, 55, 6, 132, 54, 12, 30, 124, 53, 11, 27, 38, +124, 55, 114, 119, 59, 100, 58, 79, 157, 132, 132, 132, 124, 126, 116, 11, 27, 64, 64, 60, +90, 78, 98, 100, 78, 18, 65, 82, 48, 109, 13, 27, 38, 82, 50, 79, 39, 78, 95, 119, +78, 95, 78, 79, 95, 79, 95, 100, 78, 79, 95, 66, 48, 54, 66, 23, 23, 62, 95, 100, +59, 118, 81, 47, 78, 59, 79, 79, 23, 65, 54, 48, 62, 105, 95, 105, 42, 100, 137, 79, +79, 91, 139, 151, 123, 121, 143, 141, 141, 139, 124, 174, 174, 155, 177, 224, 155, 174, 225, 227, +236, 213, 155, 116, 163, 143, 101, 120, 122, 94, 77, 68, 80, 59, 73, 100, 132, 6, 6, 126, +124, 132, 109, 98, 95, 140, 2, 103, 1, 132, 238, 32, 14, 155, 253, 53, 114, 132, 174, 126, +26, 60, 65, 46, 16, 65, 65, 65, 65, 60, 46, 65, 67, 132, 55, 177, 126, 132, 194, 178, +145, 145, 124, 124, 109, 145, 145, 124, 132, 132, 116, 132, 116, 132, 126, 67, 42, 66, 85, 47, +95, 78, 58, 95, 39, 21, 22, 18, 18, 42, 78, 78, 78, 79, 28, 199, 139, 101, 126, 132, +58, 100, 102, 102, 120, 24, 102, 122, 120, 102, 102, 102, 102, 47, 97, 97, 102, 82, 47, 92, +61, 132, 224, 54, 92, 90, 81, 90, 81, 81, 81, 82, 81, 95, 17, 20, 60, 179, 116, 127, +155, 6, 55, 177, 177, 55, 55, 54, 50, 50, 50, 18, 21, 45, 21, 42, 18, 65, 120, 59, +81, 97, 93, 119, 48, 124, 74, 63, 82, 18, 39, 23, 23, 59, 68, 58, 95, 79, 78, 100, +65, 39, 18, 18, 32, 1, 49, 22, 120, 79, 18, 100, 42, 78, 79, 100, 79, 78, 100, 79, +100, 79, 100, 79, 79, 100, 100, 62, 23, 50, 62, 23, 24, 49, 100, 98, 62, 98, 78, 59, +79, 58, 79, 78, 23, 58, 47, 31, 49, 139, 95, 119, 49, 62, 142, 79, 59, 91, 143, 113, +109, 119, 120, 139, 150, 120, 119, 149, 152, 124, 155, 174, 174, 174, 177, 230, 214, 226, 165, 119, +122, 163, 149, 131, 134, 108, 111, 111, 101, 99, 105, 108, 147, 55, 55, 55, 177, 177, 109, 92, +97, 175, 103, 61, 85, 52, 28, 16, 61, 116, 48, 124, 132, 224, 132, 126, 132, 116, 52, 52, +47, 60, 65, 26, 16, 155, 6, 6, 224, 126, 177, 126, 174, 132, 166, 178, 145, 145, 109, 132, +126, 132, 126, 132, 126, 132, 116, 127, 126, 6, 155, 145, 69, 31, 48, 53, 59, 100, 59, 100, +20, 31, 47, 42, 18, 79, 79, 100, 72, 148, 184, 177, 132, 117, 55, 109, 24, 62, 79, 100, +100, 24, 84, 84, 84, 84, 24, 102, 102, 102, 82, 84, 82, 102, 102, 47, 102, 97, 47, 102, +102, 97, 102, 97, 97, 82, 97, 97, 82, 82, 73, 100, 79, 18, 39, 83, 178, 238, 174, 132, +6, 230, 145, 50, 50, 24, 50, 50, 49, 49, 49, 50, 66, 79, 58, 115, 126, 177, 177, 132, +98, 124, 177, 102, 50, 23, 24, 50, 24, 57, 58, 58, 100, 79, 95, 95, 100, 65, 65, 73, +78, 25, 24, 95, 27, 22, 100, 100, 66, 48, 52, 120, 100, 100, 100, 79, 79, 59, 100, 79, +79, 79, 100, 79, 48, 48, 62, 24, 49, 49, 100, 100, 62, 119, 78, 79, 79, 62, 79, 78, +24, 58, 49, 50, 49, 139, 95, 119, 49, 62, 119, 49, 62, 79, 79, 113, 91, 100, 119, 119, +143, 119, 139, 139, 139, 118, 154, 132, 157, 156, 174, 174, 161, 143, 167, 154, 139, 118, 158, 141, +140, 122, 97, 119, 122, 119, 119, 130, 122, 150, 159, 157, 126, 132, 156, 152, 136, 232, 224, 174, +174, 155, 93, 82, 155, 230, 116, 115, 155, 242, 60, 102, 156, 6, 55, 55, 55, 54, 46, 14, +14, 127, 155, 6, 55, 6, 6, 6, 132, 127, 116, 132, 116, 116, 116, 132, 124, 132, 124, 132, +132, 132, 116, 145, 127, 1, 132, 1, 12, 21, 24, 45, 95, 79, 59, 79, 31, 48, 54, 84, +119, 79, 95, 79, 83, 127, 55, 177, 55, 109, 124, 114, 59, 24, 79, 62, 45, 59, 27, 59, +59, 45, 45, 59, 26, 26, 66, 24, 66, 66, 66, 66, 66, 24, 66, 66, 66, 91, 66, 79, +66, 84, 79, 91, 84, 84, 24, 73, 31, 31, 161, 125, 242, 173, 59, 25, 25, 127, 24, 18, +24, 50, 50, 50, 49, 24, 49, 25, 100, 59, 24, 109, 126, 124, 124, 124, 102, 132, 132, 12, +24, 50, 24, 24, 23, 59, 70, 66, 79, 79, 79, 100, 95, 95, 84, 84, 47, 95, 95, 49, +42, 59, 75, 24, 45, 48, 24, 100, 24, 79, 79, 24, 24, 25, 24, 79, 79, 79, 24, 62, +24, 24, 62, 50, 50, 49, 24, 79, 24, 119, 100, 62, 24, 62, 79, 79, 24, 58, 24, 49, +24, 24, 95, 119, 50, 62, 24, 49, 21, 24, 95, 113, 48, 119, 91, 120, 139, 119, 120, 139, +150, 119, 139, 150, 138, 150, 140, 140, 139, 143, 160, 151, 147, 151, 114, 140, 108, 122, 97, 97, +97, 97, 97, 119, 122, 121, 108, 112, 107, 107, 114, 124, 132, 132, 124, 124, 1, 48, 24, 25, +124, 54, 54, 53, 53, 75, 124, 51, 47, 54, 55, 55, 55, 1, 1, 145, 46, 14, 48, 2, +179, 217, 127, 2, 127, 127, 116, 109, 132, 132, 132, 132, 126, 132, 116, 132, 132, 155, 55, 155, +2, 116, 1, 55, 124, 24, 52, 24, 59, 24, 59, 24, 45, 53, 53, 58, 59, 79, 79, 59, +144, 109, 124, 124, 124, 127, 132, 145, 58, 79, 24, 24, 119, 113, 97, 97, 25, 24, 24, 25, +92, 223, 109, 97, 24, 97, 25, 24, 85, 97, 97, 24, 82, 97, 82, 24, 47, 82, 82, 47, +54, 114, 61, 126, 55, 187, 226, 226, 99, 79, 18, 24, 53, 24, 49, 24, 25, 24, 25, 24, +24, 25, 24, 100, 25, 24, 24, 24, 25, 24, 25, 79, 16, 100, 50, 24, 23, 24, 23, 24, +23, 58, 70, 79, 100, 79, 79, 100, 100, 66, 84, 82, 84, 66, 47, 47, 75, 24, 24, 24, +24, 32, 45, 24, 78, 24, 25, 24, 25, 24, 24, 24, 25, 24, 25, 24, 24, 52, 24, 25, +24, 24, 100, 24, 62, 119, 24, 24, 79, 24, 79, 24, 24, 58, 24, 24, 25, 119, 95, 24, +49, 25, 24, 24, 75, 52, 25, 75, 48, 66, 79, 139, 100, 100, 79, 143, 120, 100, 139, 158, +142, 134, 151, 109, 151, 120, 143, 120, 143, 122, 143, 120, 120, 102, 84, 59, 84, 65, 100, 82, +100, 102, 120, 120, 120, 102, 142, 109, 124, 109, 24, 25, 109, 124, 28, 24, 25, 58, 67, 145, +58, 48, 10, 242, 2, 109, 109, 124, 155, 1, 238, 6, 6, 109, 52, 13, 31, 51, 1, 238, +230, 155, 1, 132, 132, 132, 116, 116, 116, 132, 132, 116, 1, 1, 6, 55, 6, 55, 55, 6, +1, 116, 127, 24, 59, 24, 49, 24, 24, 25, 24, 18, 100, 79, 79, 24, 78, 100, 25, 24, +79, 28, 25, 24, 24, 24, 24, 25, 24, 24, 25, 24, 24, 25, 24, 25, 28, 229, 115, 79, +25, 24, 24, 79, 24, 25, 24, 25, 24, 25, 24, 66, 24, 66, 66, 24, 115, 126, 126, 174, +116, 115, 25, 24, 49, 24, 25, 24, 24, 24, 49, 24, 24, 25, 24, 24, 25, 24, 24, 24, +25, 25, 24, 25, 24, 79, 79, 82, 62, 25, 24, 24, 24, 24, 24, 24, 24, 59, 78, 66, +79, 79, 79, 24, 100, 62, 62, 45, 45, 24, 45, 45, 45, 49, 50, 49, 24, 24, 24, 24, +25, 25, 24, 24, 25, 25, 25, 25, 24, 24, 24, 25, 24, 25, 24, 24, 24, 25, 24, 25, +24, 24, 25, 24, 25, 24, 25, 24, 24, 25, 24, 24, 24, 24, 24, 25, 24, 24, 25, 24, +24, 25, 24, 24, 75, 24, 62, 79, 100, 79, 120, 100, 139, 100, 143, 150, 139, 120, 115, 173, +115, 120, 160, 95, 100, 100, 79, 79, 62, 59, 59, 91, 18, 49, 59, 49, 59, 62, 59, 62, +79, 59, 59, 50, 49, 24, 50, 24, 21, 21, 24, 24, 24, 49, 32, 53, 49, 24, 24, 53, +155, 177, 174, 54, 132, 132, 176, 132, 55, 55, 55, 48, 109, 48, 47, 48, 177, 55, 126, 155, +6, 126, 116, 132, 132, 6, 55, 127, 218, 132, 126, 55, 6, 55, 132, 44, 53, 48, 24, 25, +24, 24, 25, 24, 24, 24, 25, 24, 59, 59, 24, 79, 24, 79, 79, 24, 24, 42, 79, 24, +25, 24, 24, 24, 25, 24, 24, 25, 24, 24, 25, 25, 78, 79, 78, 25, 24, 25, 24, 25, +24, 24, 24, 24, 25, 24, 25, 24, 25, 24, 25, 24, 25, 52, 127, 9, 24, 24, 84, 65, +24, 25, 24, 25, 24, 25, 24, 25, 24, 25, 25, 24, 25, 25, 24, 25, 24, 24, 24, 24, +24, 24, 59, 62, 24, 24, 24, 25, 24, 25, 24, 24, 24, 58, 24, 79, 24, 24, 25, 24, +24, 25, 24, 50, 49, 50, 24, 50, 24, 25, 24, 25, 24, 25, 24, 24, 24, 25, 25, 25, +25, 25, 25, 28, 25, 28, 25, 24, 25, 24, 25, 25, 25, 24, 25, 24, 25, 25, 24, 24, +24, 24, 24, 25, 24, 24, 24, 25, 24, 25, 24, 24, 24, 25, 24, 24, 25, 24, 24, 25, +24, 25, 24, 24, 24, 24, 24, 100, 100, 120, 100, 139, 143, 139, 91, 123, 102, 100, 100, 100, +123, 91, 91, 91, 91, 59, 24, 50, 24, 24, 50, 24, 24, 62, 91, 91, 62, 91, 59, 91, +24, 50, 24, 24, 25, 25, 25, 25, 24, 24, 24, 24, 24, 49, 49, 49, 20, 75, 52, 132, +126, 55, 6, 127, 1, 55, 1, 1, 55, 6, 48, 21, 54, 126, 124, 109, 113, 31, 124, 52, +84, 47, 54, 124, 78, 116, 55, 126, 126, 55, 132, 25, 24, 24, 25, 24, 24, 25, 24, 25, +24, 25, 24, 24, 24, 24, 24, 24, 24, 25, 24, 25, 24, 25, 24, 25, 24, 28, 24, 25, +24, 24, 25, 24, 25, 24, 25, 24, 25, 24, 25, 24, 24, 24, 24, 24, 25, 25, 25, 25, +24, 24, 24, 25, 24, 24, 24, 24, 24, 24, 25, 25, 24, 25, 24, 25, 24, 24, 24, 24, +25, 24, 25, 25, 28, 25, 24, 25, 25, 25, 25, 25, 28, 25, 28, 25, 25, 24, 25, 24, +24, 25, 24, 24, 24, 24, 25, 24, 24, 24, 24, 59, 25, 24, 24, 24, 25, 24, 24, 24, +25, 24, 25, 24, 25, 24, 25, 24, 24, 24, 25, 25, 25, 25, 25, 25, 28, 25, 28, 25, +25, 28, 25, 25, 25, 25, 25, 25, 25, 24, 25, 24, 25, 24, 25, 24, 25, 24, 25, 25, +24, 24, 25, 24, 25, 24, 24, 24, 25, 24, 25, 28, 25, 25, 25, 24, 25, 25, 24, 24, +25, 24, 25, 24, 25, 24, 120, 143, 113, 115, 75, 97, 115, 102, 100, 91, 123, 91, 91, 24, +91, 25, 24, 24, 24, 24, 50, 24, 49, 50, 24, 24, 62, 24, 24, 62, 25, 24, 24, 25, +24, 25, 24, 25, 25, 24, 25, 24, 25, 24, 24, 24, 25, 25, 24, 24, 91, 226, 155, 116, +132, 116, 132, 132, 155, 155, 53, 22, 24, 53, 18, 18, 50, 25, 49, 24, 25, 24, 28, 49, +18, 25, 24, 33, 33, 22, 33, 25, 25, 28, 24, 24, 25, 24, 24, 24, 25, 25, 24, 24, +25, 24, 25, 24, 25, 24, 24, 24, 25, 24, 25, 24, 25, 24, 28, 25, 25, 28, 25, 25, +25, 25, 25, 28, 25, 25, 25, 25, 25, 28, 25, 25, 25, 24, 25, 24, 25, 24, 25, 25, +25, 25, 25, 25, 25, 25, 24, 24, 25, 24, 24, 25, 25, 25, 24, 25, 25, 25, 28, 25, +28, 25, 25, 25, 24, 25, 28, 24, 25, 25, 25, 25, 25, 25, 24, 25, 28, 24, 25, 25, +24, 25, 24, 24, 24, 24, 25, 24, 24, 24, 25, 25, 24, 25, 25, 25, 24, 28, 24, 24, +24, 24, 25, 24, 25, 25, 25, 25, 25, 25, 28, 25, 25, 28, 28, 25, 28, 25, 28, 25, +28, 25, 28, 28, 25, 25, 25, 25, 25, 25, 25, 25, 25, 28, 25, 24, 24, 25, 24, 25, +25, 24, 25, 25, 24, 25, 25, 25, 25, 28, 25, 25, 25, 28, 28, 28, 25, 25, 25, 28, +25, 24, 25, 25, 24, 145, 75, 115, 145, 75, 62, 91, 91, 24, 123, 33, 50, 24, 24, 24, +24, 25, 24, 25, 24, 24, 25, 24, 25, 24, 25, 24, 24, 25, 25, 25, 25, 25, 25, 25, +25, 25, 24, 24, 24, 24, 25, 25, 24, 25, 25, 24, 25, 50, 24, 23, 24, 24, 49, 24, +25, 24, 24, 25, 24, 25, 28, 24, 24, 24, 28, 24, 25, 25, 25, 25, 28, 25, 28, 25, +28, 28, 25, 28, 25, 25, 25, 28, 25, 25, 25, 28, 24, 25, 25, 24, 24, 24, 24, 25, +24, 25, 25, 25, 24, 28, 24, 28, 25, 28, 25, 25, 25, 25, 25, 25, 25, 28, 25, 25, +28, 25, 25, 25, 25, 28, 25, 25, 28, 25, 25, 28, 25, 25, 25, 25, 28, 24, 24, 25, +25, 25, 25, 28, 25, 24, 25, 25, 25, 25, 25, 24, 25, 25, 25, 28, 28, 25, 25, 25, +28, 25, 25, 25, 28, 25, 25, 28, 25, 24, 28, 25, 25, 25, 25, 25, 25, 24, 25, 24, +25, 25, 24, 25, 24, 25, 25, 25, 25, 24, 25, 25, 25, 24, 25, 25, 25, 25, 25, 25, +25, 28, 25, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 28, +25, 28, 24, 25, 28, 25, 25, 28, 25, 25, 25, 25, 25, 25, 24, 25, 25, 25, 24, 25, +25, 25, 25, 25, 28, 25, 25, 28, 28, 25, 28, 25, 25, 28, 25, 25, 25, 28, 25, 25, +25, 25, 24, 113, 24, 91, 62, 25, 123, 24, 24, 24, 24, 25, 24, 25, 24, 24, 24, 24, +25, 24, 24, 24, 24, 25, 24, 25, 28, 25, 25, 25, 28, 25, 25, 25, 25, 25, 25, 24, +25, 25, 24, 25, 25, 24, 25, 24, 24, 25, 24, 24, 25, 25, 25, 25, 24, 25, 24, 25, +25, 25, 24, 25, 28, 24, 25, 25, 25, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 25, +28, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 25, 24, 25, 24, 25, 25, 25, 25, 25, +25, 25, 25, 28, 25, 28, 28, 25, 28, 25, 28, 28, 28, 28, 28, 28, 28, 25, 28, 25, +28, 25, 28, 28, 25, 28, 25, 25, 25, 28, 28, 28, 25, 28, 25, 25, 28, 25, 28, 25, +25, 28, 24, 25, 25, 25, 28, 25, 25, 25, 25, 24, 25, 25, 28, 25, 28, 25, 28, 25, +25, 28, 28, 25, 25, 28, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 25, 28, 25, 24, +25, 24, 28, 25, 28, 25, 28, 25, 25, 28, 24, 28, 25, 24, 25, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, 28, 28, 28, 25, 25, 25, 28, 25, +28, 25, 25, 28, 28, 28, 25, 25, 25, 25, 25, 25, 25, 28, 25, 25, 28, 25, 25, 28, +28, 28, 25, 25, 28, 28, 28, 28, 28, 28, 28, 28, 25, 25, 25, 25, 25, 28, 25, 28, +25, 25, 24, 25, 25, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 25, 25, 24, +25, 24, 25, 25, 25, 25, 28, 25, 28, 28, 28, 25, 24, 25, 25, 25, 25, 28, 25, 25, +28, 25, 25, 28, 25, 25, 28, 25, 25, 25, 28, 25, 25, 25, 25, 25, 25, 28, 25, 28, +25, 28, 25, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 25, 28, 25, +25, 28, 28, 25, 25, 25, 24, 24, 25, 24, 25, 25, 28, 25, 28, 25, 28, 25, 28, 28, +28, 28, 25, 28, 28, 28, 28, 25, 28, 28, 28, 28, 25, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 25, 25, 25, 25, +28, 28, 28, 28, 28, 25, 25, 25, 25, 25, 25, 25, 28, 28, 25, 28, 28, 25, 28, 28, +25, 25, 25, 25, 28, 28, 28, 25, 25, 28, 28, 28, 25, 25, 25, 28, 25, 25, 24, 25, +25, 25, 25, 25, 25, 28, 25, 28, 28, 28, 25, 28, 28, 28, 28, 28, 29, 28, 28, 29, +29, 28, 28, 28, 29, 29, 28, 29, 28, 28, 28, 28, 28, 25, 28, 25, 28, 28, 28, 25, +28, 25, 25, 28, 25, 25, 28, 25, 25, 25, 25, 25, 28, 28, 25, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 25, 28, 25, 28, 28, 28, 28, 28, 28, 25, 25, 28, +25, 25, 28, 25, 25, 28, 25, 25, 25, 28, 25, 25, 25, 28, 25, 25, 25, 28, 25, 25, +25, 25, 25, 28, 25, 25, 25, 28, 25, 25, 25, 28, 25, 28, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 28, 28, 28, 25, 28, 25, 25, 25, 25, 25, 28, 25, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 29, 28, 28, 28, 28, 28, 28, 25, 28, 28, 25, 25, 25, +28, 25, 24, 25, 25, 25, 28, 25, 25, 28, 25, 28, 25, 28, 28, 28, 25, 25, 28, 28, +28, 28, 28, 28, 29, 28, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 28, 28, 28, 28, 25, +25, 28, 28, 29, 29, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 25, 28, 28, 28, 25, 25, 25, 28, 25, 28, 25, 25, 28, 25, 28, +25, 28, 25, 28, 25, 28, 28, 28, 28, 28, 29, 29, 29, 28, 29, 29, 28, 29, 29, 29, +29, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, +25, 28, 28, 28, 28, 28, 25, 28, 28, 28, 28, 28, 28, 29, 29, 29, 28, 29, 29, 29, +29, 29, 28, 28, 28, 28, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 28, +25, 25, 28, 25, 25, 28, 25, 28, 25, 28, 25, 28, 25, 25, 25, 25, 25, 28, 25, 25, +25, 28, 25, 25, 25, 28, 25, 25, 28, 28, 25, 28, 25, 28, 28, 25, 28, 25, 28, 28, +28, 28, 28, 28, 25, 25, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 29, 28, 29, 28, 29, 28, 28, 28, 25, 28, 25, 28, 28, 28, 25, 25, 25, 28, 25, +25, 25, 25, 25, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, +29, 29, 28, 29, 29, 29, 28, 28, 29, 29, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, +28, 28, 28, 28, 29, 28, 28, 28, 25, 28, 28, 29, 28, 28, 25, 28, 25, 28, 29, 28, +28, 29, 28, 28, 28, 28, 28, 29, 28, 28, 28, 28, 29, 28, 28, 28, 29, 28, 28, 28, +29, 28, 28, 28, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +25, 28, 25, 28, 28, 29, 28, 28, 29, 29, 29, 28, 28, 29, 28, 28, 29, 29, 34, 29, +29, 29, 28, 28, 29, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 29, 28, 29, 28, 28, +29, 29, 28, 29, 28, 29, 28, 29, 28, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 25, 28, 25, 28, 25, 25, 25, 28, 25, 28, 25, 25, 25, 28, 28, 28, 25, +28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, 28, 28, 28, 28, 29, 28, 29, 28, +29, 28, 29, 28, 28, 28, 28, 28, 28, 25, 28, 25, 28, 25, 25, 25, 28, 25, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 29, 29, 28, 29, 29, 29, +28, 29, 29, 29, 29, 28, 29, 29, 28, 28, 28, 29, 29, 29, 28, 29, 29, 34, 28, 29, +29, 28, 28, 28, 28, 28, 29, 29, 28, 28, 28, 28, 28, 28, 29, 28, 28, 28, 29, 28, +29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 28, 29, 28, 28, 29, 28, +28, 28, 28, 28, 28, 25, 28, 28, 28, 29, 28, 28, 29, 28, 28, 28, 29, 28, 28, 28, +28, 29, 28, 29, 28, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 34, 28, 29, 28, +28, 28, 29, 28, 28, 28, 28, 29, 28, 28, 29, 28, 28, 28, 25, 28, 28, 28, 28, 28, +28, 28, 29, 29, 29, 29, 29, 28, 29, 28, 29, 29, 29, 29, 29, 29, 28, 28, 29, 29, +29, 29, 29, 29, 28, 29, 29, 28, 29, 28, 29, 29, 28, 28, 28, 29, 28, 28, 28, 28, +28, 28, 28, 28, 25, 28, 28, 28, 28, 28, 28, 28, 25, 28, 28, 25, 28, 28, 28, 28, +25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, +29, 28, 29, 28, 29, 28, 28, 28, 29, 29, 28, 28, 28, 29, 29, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 29, 28, 28, 28, 28, 29, 28, 29, 29, 28, 29, 29, 28, 28, 29, 29, 28, 29, +28, 29, 29, 28, 29, 29, 29, 28, 29, 28, 29, 28, 29, 29, 29, 28, 29, 28, 28, 28, +28, 29, 29, 28, 29, 29, 28, 28, 28, 29, 28, 29, 28, 29, 28, 28, 29, 28, 28, 29, +28, 29, 28, 28, 29, 28, 28, 28, 28, 29, 28, 29, 29, 28, 28, 28, 29, 34, 25, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, 28, 28, 28, 29, 28, 29, +29, 29, 29, 29, 29, 29, 28, 34, 29, 34, 29, 34, 29, 29, 29, 29, 28, 29, 29, 29, +29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 28, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 28, 29, 29, 29, 28, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +29, 28, 28, 28, 29, 28, 28, 28, 29, 28, 29, 29, 28, 29, 28, 29, 29, 28, 29, 29, +29, 28, 29, 29, 29, 28, 29, 29, 29, 28, 28, 29, 28, 29, 28, 28, 28, 28, 28, 28, +28, 25, 28, 25, 28, 28, 25, 25, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, +28, 28, 28, 29, 29, 28, 29, 29, 29, 28, 29, 29, 29, 28, 29, 29, 29, 28, 29, 29, +29, 28, 29, 29, 29, 29, 29, 29, 29, 28, 28, 29, 29, 29, 29, 28, 34, 29, 29, 29, +28, 28, 28, 28, 28, 28, 29, 29, 28, 29, 29, 29, 28, 29, 29, 28, 34, 29, 29, 28, +34, 29, 29, 28, 29, 29, 29, 28, 29, 28, 29, 29, 28, 28, 28, 28, 29, 29, 28, 29, +28, 28, 28, 28, 29, 29, 28, 28, 29, 29, 29, 28, 28, 29, 29, 29, 28, 29, 29, 29, +29, 29, 29, 29, 29, 29, 34, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 28, 29, 29, 28, 68, 84, 48, 49, 214, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 66, 105, 116, 109, 97, 112, +115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 49, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 54, 4, 1, 0, 83, 206, 2, 0, 0, 0, 0, 0, +255, 255, 255, 255, 0, 0, 0, 0, 2, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 54, 4, 1, 0, 29, 202, 1, 0, 0, 0, 0, 0, 255, 255, +255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 9, 0, 0, 0, 71, 101, 111, 109, 101, 116, +114, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 202, 1, 0, 24, +0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 77, +84, 78, 66, 240, 0, 0, 0, 5, 0, 1, 2, 115, 112, 105, 110, 0, 4, 0, 0, 0, +142, 182, 0, 0, 2, 0, 0, 0, 83, 66, 75, 66, 4, 0, 0, 0, 44, 0, 0, 0, +16, 0, 0, 0, 23, 0, 0, 0, 30, 0, 0, 0, 37, 0, 0, 0, 66, 79, 78, 69, +48, 49, 0, 66, 79, 78, 69, 48, 50, 0, 66, 79, 78, 69, 48, 51, 0, 66, 79, 78, +69, 48, 52, 0, 17, 2, 1, 16, 48, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, +0, 0, 0, 0, 88, 255, 255, 63, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +17, 2, 1, 16, 48, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, +88, 255, 255, 63, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +189, 55, 134, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 191, 17, 2, 1, 16, +48, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 88, 255, 255, 63, +0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 1, 16, 48, 0, 0, 0, +0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 88, 255, 255, 63, 0, 0, 128, 63, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 68, 84, 48, 49, 215, 0, 0, 0, 0, 0, 0, 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 77, 111, 116, +105, 111, 110, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 48, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 1, 0, 0, 135, 211, 3, 0, 0, +0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 5, 0, 0, 0, 66, +111, 100, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 211, 3, 0, +40, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 7, 0, 0, 0, +72, 101, 97, 100, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, +0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, +}; +int genesis3d_act_length = sizeof(genesis3d_act); + diff --git a/G3D/Entities/ENTITIES.H b/G3D/Entities/ENTITIES.H new file mode 100644 index 0000000..602a09e --- /dev/null +++ b/G3D/Entities/ENTITIES.H @@ -0,0 +1,142 @@ +/****************************************************************************************/ +/* Entities.h */ +/* */ +/* Author: Eli Boling / John Pollard */ +/* Description: EntitySet creation / Entity Compiler */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_ENTITIES_H +#define GE_ENTITIES_H + +#include +#include + +#include "BaseType.h" +#include "Errorlog.h" +#include "Vec3d.h" +#include "System.h" +#include "World.h" +#include "Ram.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//===================================================================================== +// Defines / Structure defines +//===================================================================================== +// Enumerated types +typedef enum +{ + TYPE_INT, + TYPE_FLOAT, + TYPE_COLOR, + TYPE_POINT, + TYPE_STRING, + TYPE_MODEL, + TYPE_STRUCT, + TYPE_PTR, +} geEntity_ClassType; + +typedef struct geEntity_Class geEntity_Class; + +// Fields within a geEntity_Class +typedef struct geEntity_Field +{ + char *Name; // Name of the field + geEntity_Class *TypeClass; // Atomic class the defines field + int32 Offset; // Offset in Entity's UserData + + struct geEntity_Field *Next; // Next Field list + +} geEntity_Field; + +typedef struct geEntity_Class +{ + char *Name; // Class Name + geEntity_ClassType Type; // Type of class + int32 TypeSize; + geEntity_Field *Fields; // Fields in this Class + int32 FieldSize; // Size of all fields + + struct geEntity_Class *Next; + +} geEntity_Class; + +typedef struct geEntity_Epair +{ + struct geEntity_Epair *Next; + char *Key; + char *Value; +} geEntity_Epair; + +typedef struct geEntity +{ + geEntity_Class *Class; // Class data + + geEntity_Epair *Epairs; // Parsed epair list from entity string list + + void *UserData; // User structure parsed from entity +} geEntity; + +typedef struct geEntity_EntitySet +{ + struct geEntity_EntitySet *Next; // Next entity in this set + struct geEntity_EntitySet *Current; // Current entity set as an iterator + + geBoolean OwnsEntities; // GE_TRUE if + + geEntity *Entity; // The entity + geEntity_Class *Classes; // List of classes for set + +} geEntity_EntitySet; + + +//===================================================================================== +// Function prototypes +//===================================================================================== +geBoolean Ent_WorldInit(geWorld *World); +void Ent_WorldShutdown(geWorld *World); + +geEntity *geEntity_Create(void); +void geEntity_Destroy(geEntity *Entity); +geBoolean geEntity_GetModelNumForKey(geEntity *Entity, const char *Key, int32 *ModelNum); +geBoolean geEntity_AddEpair(geEntity *Entity, geEntity_Epair *Epair); +const char *geEntity_GetStringForKey(const geEntity *Entity, const char *Key); +geEntity_Epair *geEntity_EpairCreate(void); +void geEntity_EpairDestroy(geEntity_Epair *Epair); +geEntity_Field *geEntity_FieldCreate(const char *Name, int32 Offset, geEntity_Class *TypeClass); +void geEntity_FieldDestroy(geEntity_Field *Field); +geEntity_Class *geEntity_ClassCreate(geEntity_ClassType Type, const char *Name, int32 TypeSize); +void geEntity_ClassDestroy(geEntity_Class *Class); +geBoolean geEntity_ClassAddField(geEntity_Class *Class, geEntity_Field *Field); +geEntity_Field *geEntity_ClassFindFieldByName(geEntity_Class *Class, const char *Name); +geEntity_EntitySet *geEntity_EntitySetCreate(void); +void geEntity_EntitySetDestroy(geEntity_EntitySet *EntitySet); +geEntity_Class *geEntity_EntitySetFindClassByName(geEntity_EntitySet *Set, const char *Name); +geEntity *geEntity_EntitySetFindEntityByName(geEntity_EntitySet *EntitySet, const char *Name); +GENESISAPI void geEntity_GetName(const geEntity *Entity, char *Buff, int MaxLen); +geBoolean geEntity_EntitySetAddEntity(geEntity_EntitySet *EntitySet, geEntity *Entity); +GENESISAPI geEntity *geEntity_EntitySetGetNextEntity(geEntity_EntitySet *EntitySet, geEntity *Entity); +geBoolean geEntity_EntitySetAddClass(geEntity_EntitySet *EntitySet, geEntity_Class *Class); +geEntity_EntitySet *LoadEntitySet(const char *EntityData, int32 EntityDataSize); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Entities/Entities.c b/G3D/Entities/Entities.c new file mode 100644 index 0000000..5ffb034 --- /dev/null +++ b/G3D/Entities/Entities.c @@ -0,0 +1,1117 @@ +/****************************************************************************************/ +/* Entities.c */ +/* */ +/* Author: Eli Boling / John Pollard */ +/* Description: EntitySet creation / Entity Compiler */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "Entities.h" +#include "BaseType.h" +#include "Errorlog.h" +#include "Vec3d.h" +#include "Ram.h" + +// These are temporary until we find a better way to get models pointers into the entity stuff +#include "World.h" +#include "GBSPFile.h" + + +//===================================================================================== +// Local Static Globals +//===================================================================================== + +//===================================================================================== +// Local Static Function prototypes +//===================================================================================== +static geWorld *GWorld; // Temp global world for testing new entity stuff + +//==================================================================================== +//==================================================================================== +static geBoolean InsertEntityInClassList(geWorld *World, geEntity *Entity) +{ + const char *EntClassName; + geWorld_EntClassSet *WSet; + int32 i; + + if (!Entity->Class) // Ignore all no classes + return GE_TRUE; + + assert(Entity->Class->Name); // Must have a class name + + EntClassName = Entity->Class->Name; + + WSet = World->EntClassSets; + + for (i=0; i< World->NumEntClassSets; i++) + { + if (!WSet[i].ClassName) + continue; + + if (!stricmp(WSet[i].ClassName, EntClassName)) + { + // Add entity to this class set... + if (!geEntity_EntitySetAddEntity(WSet[i].Set, Entity)) + return GE_FALSE; + + return GE_TRUE; + } + } + + if (i >= MAX_WORLD_ENT_CLASS_SETS) + return GE_FALSE; // oh well... + + // Create a new entity set + WSet[i].Set = geEntity_EntitySetCreate(); + + // Insert the entity into a new class set + WSet[i].ClassName = EntClassName; + geEntity_EntitySetAddEntity(WSet[i].Set, Entity); + + World->NumEntClassSets++; + + return GE_TRUE; +} + +//==================================================================================== +// Ent_WorldInit +// Lets this module initialize data that it owns in the world +//==================================================================================== +geBoolean Ent_WorldInit(geWorld *World) +{ + GBSP_BSPData *BSP; + geEntity_EntitySet *EntitySet; + geEntity *Entity; + + assert(World != NULL); + + GWorld = World; + + World->NumEntClassSets = 0; + + if ( ! World->CurrentBSP ) + return GE_TRUE; + + BSP = &(World->CurrentBSP->BSPData); + + if (BSP->NumGFXEntData == 0) + return GE_TRUE; // Nothing to do... + + EntitySet = LoadEntitySet(BSP->GFXEntData, BSP->NumGFXEntData); + + if (!EntitySet) + return GE_FALSE; + + // Insert default set... + World->EntClassSets[0].ClassName = NULL; + World->EntClassSets[0].Set = EntitySet; + World->NumEntClassSets++; + + // Build class sets + Entity = NULL; + while (1) + { + Entity = geEntity_EntitySetGetNextEntity(EntitySet, Entity); + + if (!Entity) + break; // Done + + InsertEntityInClassList(World, Entity); + } + + return GE_TRUE; +} + +//==================================================================================== +// Ent_WorldShutdown +// Lets this module shutdown data that it owns in the world +//==================================================================================== +void Ent_WorldShutdown(geWorld *World) +{ + int32 i; + + assert(World); + + for (i=0; i< World->NumEntClassSets; i++) + geEntity_EntitySetDestroy(World->EntClassSets[i].Set); +} + +//==================================================================================== +// CopyString +//==================================================================================== +static char *CopyString(const char *String) +{ + char *NewString; + + NewString = geRam_Allocate(strlen(String)+1); + + if (!NewString) + return NULL; + + strcpy(NewString, String); + + return NewString; +} + +//==================================================================================== +// geEntity_Create +//==================================================================================== +geEntity *geEntity_Create(void) +{ + geEntity *Entity; + + Entity = geRam_Allocate(sizeof(geEntity)); + + if (!Entity) + return NULL; + + memset(Entity, 0, sizeof(geEntity)); + + return Entity; +} + +//==================================================================================== +// geEntity_Destroy +// NOTE - This currently does garbage collection on the epairs that were inserted in the entity +//==================================================================================== +void geEntity_Destroy(geEntity *Entity) +{ + geEntity_Epair *Epair, *Next; + + assert(Entity); + + for (Epair = Entity->Epairs; Epair; Epair = Next) + { + Next = Epair->Next; + + geEntity_EpairDestroy(Epair); + } + + if (Entity->UserData) + geRam_Free(Entity->UserData); + + geRam_Free(Entity); +} + +//==================================================================================== +// geEntity_GetUserData +//==================================================================================== +GENESISAPI void *geEntity_GetUserData(geEntity *Entity) +{ + assert(Entity); + + return Entity->UserData; +} + +//==================================================================================== +// geEntity_GetModelNumForKey +//==================================================================================== +geBoolean geEntity_GetModelNumForKey(geEntity *Entity, const char *Key, int32 *ModelNum) +{ + geEntity_Epair *Epair; + int32 Value; + + for (Epair = Entity->Epairs; Epair; Epair = Epair->Next) + { + if (!stricmp(Epair->Key, Key)) + { + if (Epair->Value[0] == '*') + sscanf(Epair->Value+1, "%d", &Value); + else + sscanf(Epair->Value, "%d", &Value); + + *ModelNum = (int32)Value; + return GE_TRUE; + } + } + return GE_FALSE; // not found ! + +} + +//==================================================================================== +// geEntity_AddEpair +//==================================================================================== +geBoolean geEntity_AddEpair(geEntity *Entity, geEntity_Epair *Epair) +{ + geEntity_Epair *Ep; + + assert(Entity); + assert(Epair); + + assert(Epair->Next == NULL); // Make sure this is a fresh one (ahh yahh) + + if (!Entity->Epairs) + { + Entity->Epairs = Epair; + return GE_TRUE; + } + + // Jump to end of list + for (Ep = Entity->Epairs; Ep->Next; Ep = Ep->Next); + + Ep->Next = Epair; + + return GE_TRUE; +} + +//==================================================================================== +// geEntity_GetStringForKey +//==================================================================================== +const char *geEntity_GetStringForKey(const geEntity *Entity, const char *Key) +{ + geEntity_Epair *Epair; + + for (Epair = Entity->Epairs; Epair; Epair = Epair->Next) + { + if (!stricmp(Epair->Key, Key)) + { + return Epair->Value; + } + } + return NULL; // not found! +} + +//==================================================================================== +// geEntity_EpairCreate +//==================================================================================== +geEntity_Epair *geEntity_EpairCreate(void) +{ + geEntity_Epair *Epair; + + Epair = geRam_Allocate(sizeof(geEntity_Epair)); + + if (!Epair) + return NULL; + + memset(Epair, 0, sizeof(geEntity_Epair)); + + return Epair; +} + +//==================================================================================== +// geEntity_EpairDestroy +//==================================================================================== +void geEntity_EpairDestroy(geEntity_Epair *Epair) +{ + assert(Epair); + + if (Epair->Key) + geRam_Free(Epair->Key); + + if (Epair->Value) + geRam_Free(Epair->Value); + + geRam_Free(Epair); +} + +//==================================================================================== +// geEntity_FieldCreate +//==================================================================================== +geEntity_Field *geEntity_FieldCreate(const char *Name, int32 Offset, geEntity_Class *TypeClass) +{ + geEntity_Field *Field; + + Field = GE_RAM_ALLOCATE_STRUCT(geEntity_Field); + + if (!Field) + return NULL; + + memset(Field, 0, sizeof(geEntity_Field)); + + if (Name) + Field->Name = CopyString(Name); + + Field->Offset = Offset; + Field->TypeClass = TypeClass; + + return Field; +} + +//==================================================================================== +// geEntity_FieldDestroy +//==================================================================================== +void geEntity_FieldDestroy(geEntity_Field *Field) +{ + assert(Field); + + if (Field->Name) + geRam_Free(Field->Name); + + geRam_Free(Field); +} + +//==================================================================================== +// geEntity_ClassCreate +//==================================================================================== +geEntity_Class *geEntity_ClassCreate(geEntity_ClassType Type, const char *Name, int32 TypeSize) +{ + geEntity_Class *Class; + + Class = GE_RAM_ALLOCATE_STRUCT(geEntity_Class); + + if (!Class) + return NULL; + + memset(Class, 0, sizeof(geEntity_Class)); + + Class->Type = Type; + + if (Name) + Class->Name = CopyString(Name); + + Class->TypeSize = TypeSize; + + return Class; +} + +//==================================================================================== +// geEntity_ClassDestroy +//==================================================================================== +void geEntity_ClassDestroy(geEntity_Class *Class) +{ + geEntity_Field *Field, *NextField; + assert(Class); + + for (Field = Class->Fields; Field; Field = NextField ) + { + NextField = Field->Next; + geEntity_FieldDestroy(Field); + } + if (Class->Name) + geRam_Free(Class->Name); + + geRam_Free(Class); +} + +//==================================================================================== +// geEntity_ClassAddField +//==================================================================================== +geBoolean geEntity_ClassAddField(geEntity_Class *Class, geEntity_Field *Field) +{ + assert(Class); + assert(Field); + + // Put at the beggining + Field->Next = Class->Fields; + Class->Fields = Field; + + // Grow fieldsize by Fields TypeClass size + Class->FieldSize += Field->TypeClass->TypeSize; + + return GE_TRUE; +} + +//==================================================================================== +// geEntity_ClassFindFieldByName +//==================================================================================== +geEntity_Field *geEntity_ClassFindFieldByName(geEntity_Class *Class, const char *Name) +{ + geEntity_Field *Field; + + assert(Class); + + for (Field = Class->Fields; Field; Field = Field->Next) + { + if (!stricmp(Field->Name, Name)) + return Field; + + } + + return NULL; +} + +//==================================================================================== +// geEntity_EntitySetCreate +//==================================================================================== +geEntity_EntitySet *geEntity_EntitySetCreate(void) +{ + geEntity_EntitySet *EntitySet; + + EntitySet = geRam_Allocate(sizeof(geEntity_EntitySet)); + + if (!EntitySet) + return NULL; + + memset(EntitySet, 0, sizeof(geEntity_EntitySet)); + + return EntitySet; +} + +//==================================================================================== +// geEntity_EntitySetDestroy +// NOTE - This does garbage collection to anything added the the set +//==================================================================================== +void geEntity_EntitySetDestroy(geEntity_EntitySet *EntitySet) +{ + geEntity_EntitySet *Set, *Next; + geEntity_Class *Class, *NextClass; + + assert(EntitySet); + + if (EntitySet->OwnsEntities) // Free stuff if we created all this stuff + { + for (Class = EntitySet->Classes; Class; Class = NextClass) + { + NextClass = Class->Next; + + geEntity_ClassDestroy(Class); + } + + for (Set = EntitySet; Set; Set = Next) + { + Next = Set->Next; + if (Set->Entity) + geEntity_Destroy(Set->Entity); + } + } + + // Finclaly destroy the sets themselves... + for (Set = EntitySet; Set; Set = Next) + { + Next = Set->Next; + + geRam_Free(Set); + } +} + +//==================================================================================== +// geEntity_EntitySetFindClassByName +//==================================================================================== +geEntity_Class *geEntity_EntitySetFindClassByName(geEntity_EntitySet *Set, const char *Name) +{ + geEntity_Class *Class; + + assert(Set); + + for (Class = Set->Classes; Class; Class = Class->Next) + { + if (!stricmp(Class->Name, Name)) + return Class; + } + + return NULL; // Not found!!! +} + +GENESISAPI void geEntity_GetName(const geEntity *Entity, char *Buff, int MaxLen) +{ + const char * EntName; + int Length; + + assert(Entity); + assert(Buff); + + EntName = geEntity_GetStringForKey(Entity, "%Name%"); + assert(EntName); + Length = strlen(EntName) + 1; + memcpy(Buff, EntName, min(Length, MaxLen)); +} + +//==================================================================================== +// geEntity_EntitySetFindEntityByName +//==================================================================================== +geEntity *geEntity_EntitySetFindEntityByName(geEntity_EntitySet *EntitySet, const char *Name) +{ + const char *EntName; + geEntity_EntitySet *Set; + + assert(EntitySet); + assert(Name); + + for (Set = EntitySet; Set; Set = Set->Next) + { + EntName = geEntity_GetStringForKey(Set->Entity, "%Name%"); + + if (!EntName) + continue; + + if (!stricmp(Name, EntName)) + return Set->Entity; + } + + return NULL; +} + +//==================================================================================== +// geEntity_EntitySetAddEntity +//==================================================================================== +geBoolean geEntity_EntitySetAddEntity(geEntity_EntitySet *EntitySet, geEntity *Entity) +{ + geEntity_EntitySet *NewSet, *Set; + + assert(EntitySet); + assert(Entity); + + // If no entities in list, just make this one the first + if (!EntitySet->Entity) + { + assert(EntitySet->Next == NULL); + assert(EntitySet->Current == NULL); + + EntitySet->Entity = Entity; + return GE_TRUE; + } + + NewSet = geEntity_EntitySetCreate(); + + if (!NewSet) + return GE_FALSE; + + // Store the entity + NewSet->Entity = Entity; + + // Jump to end of list (we allways want them to work on the first set in the list...) + for (Set = EntitySet; Set->Next; Set = Set->Next); + + // Add the newset + Set->Next = NewSet; +return GE_TRUE; +} + +//==================================================================================== +// geEntity_EntitySetGetNextEntity +//==================================================================================== +GENESISAPI geEntity *geEntity_EntitySetGetNextEntity(geEntity_EntitySet *EntitySet, geEntity *Entity) +{ + geEntity_EntitySet *Set, *NextSet; + + assert(EntitySet); + + if (!Entity) + { + EntitySet->Current = EntitySet; + return EntitySet->Entity; + } + + assert(EntitySet->Current); + + // Search is easy if this was the last entity we returned + if (EntitySet->Current->Entity == Entity) + { + NextSet = EntitySet->Current->Next; + + if (!NextSet) + return NULL; // No more in the list + + EntitySet->Current = NextSet; + return NextSet->Entity; + } + + // Must do a search now, that'll teach'em to jump around... + for (Set = EntitySet; Set; Set = Set->Next) + { + assert(Set->Entity); + + if (Set->Entity == Entity) + { + NextSet = Set->Next; + + EntitySet->Current = NextSet; + return NextSet->Entity; + } + } + + return NULL; +} + +//==================================================================================== +// geEntity_EntitySetAddClass +//==================================================================================== +geBoolean geEntity_EntitySetAddClass(geEntity_EntitySet *EntitySet, geEntity_Class *Class) +{ + assert(EntitySet); + assert(Class); + + assert(Class->Next == NULL); // We want fresh ones only + + // Just put in front of list + Class->Next = EntitySet->Classes; + EntitySet->Classes = Class; + + return GE_TRUE; +} + +//==================================================================================== +// BuildClassTypes +//==================================================================================== +static geBoolean BuildClassTypes(geEntity_EntitySet *EntitySet) +{ + const char *Name; + geEntity_Class *Class; + geEntity_EntitySet *Set; + + // Fill in the pre-defined atomic types + Class = geEntity_ClassCreate(TYPE_INT, "int", sizeof(int32)); + geEntity_EntitySetAddClass(EntitySet, Class); +// +// For Reality Factory floating point data type in entities +// is set to be geFloat, not float as in Gedit +// + Class = geEntity_ClassCreate(TYPE_FLOAT, "geFloat", sizeof(geFloat)); + geEntity_EntitySetAddClass(EntitySet, Class); + + Class = geEntity_ClassCreate(TYPE_COLOR, "color", sizeof(GE_RGBA)); + geEntity_EntitySetAddClass(EntitySet, Class); + + Class = geEntity_ClassCreate(TYPE_POINT, "point", sizeof(geVec3d)); + geEntity_EntitySetAddClass(EntitySet, Class); + + Class = geEntity_ClassCreate(TYPE_STRING, "string", sizeof(char *)); + geEntity_EntitySetAddClass(EntitySet, Class); + + Class = geEntity_ClassCreate(TYPE_PTR, "ptr", sizeof(void *)); + geEntity_EntitySetAddClass(EntitySet, Class); + + Class = geEntity_ClassCreate(TYPE_MODEL, "model", sizeof(void*)); + geEntity_EntitySetAddClass(EntitySet, Class); + + // Find all the %typedef% keywords, and allocate them as TYPE_STRUCT's + for (Set = EntitySet; Set; Set = Set->Next) + { + geEntity *Entity; + + Entity = Set->Entity; + + Name = geEntity_GetStringForKey(Entity, "classname"); + + if (!Name) + continue; + + if (stricmp(Name, "%typedef%")) // No %typedef% info + continue; + + Name = geEntity_GetStringForKey(Entity, "%typename%"); + + if (!Name) + return GE_FALSE; + + Class = geEntity_ClassCreate(TYPE_STRUCT, Name, sizeof(void*)); + + if (!Class) + goto ExitWithError; + + if (!geEntity_EntitySetAddClass(EntitySet, Class)) + goto ExitWithError; + } + + for (Set = EntitySet; Set; Set = Set->Next) + { + geEntity *Entity; + geEntity_Epair *Epair; + + Entity = Set->Entity; + + Name = geEntity_GetStringForKey(Entity, "classname"); + + if (!Name) // Not a class entity (Error?) + continue; + + if (stricmp(Name, "%typedef%")) // Not a typedef + continue; + + Name = geEntity_GetStringForKey(Entity, "%typename%"); + + if (!Name) + return GE_FALSE; + + Class = geEntity_EntitySetFindClassByName(EntitySet, Name); + + if (!Class) + continue; // Oops, this %typedef% will have no fields + + for (Epair = Entity->Epairs; Epair; Epair = Epair->Next) + { + geEntity_Class *TypeClass; + geEntity_Field *Field; + + // Skip classname and %typename% + if (!stricmp(Epair->Key, "classname")) + continue; + if (!stricmp(Epair->Key, "%typename%")) + continue; + + assert(stricmp(Epair->Key, "%defaultvalue%")); +// +// 18/11/00 Changed engine to accept float as well as geFloat +// in entity definition +// + if(!stricmp(Epair->Value, "float")) + TypeClass = geEntity_EntitySetFindClassByName(EntitySet, "geFloat"); + else + TypeClass = geEntity_EntitySetFindClassByName(EntitySet, Epair->Value); + + if (!TypeClass) + goto ExitWithError; // Type not defined for this field!!! + + Field = geEntity_FieldCreate(Epair->Key, Class->FieldSize, TypeClass); + + if (!Field) + goto ExitWithError; + + if (!geEntity_ClassAddField(Class, Field)) + goto ExitWithError; + + Epair = Epair->Next; + assert(Epair); + assert(!stricmp(Epair->Key, "%defaultvalue%")); + + } + } + + return GE_TRUE; + + // ** ERROR ** + ExitWithError: + { + if (Class) + geEntity_ClassDestroy(Class); + + return GE_FALSE; + } +} + +//==================================================================================== +// ParseTypedUserData +//==================================================================================== +static geBoolean ParseClassUserData(geEntity_EntitySet *EntitySet, geEntity *Entity) +{ + geEntity_Epair *Epair; + + if (!Entity->Class) + return GE_TRUE; + + for (Epair = Entity->Epairs; Epair; Epair = Epair->Next) + { + char *UData; + geEntity_Field *Field; + + // Skip %name% and classname keywords in entity + if (!stricmp(Epair->Key, "classname")) + continue; + + if (Epair->Key[0] == '%') // Skip special names + continue; + + // Find the field in this class + Field = geEntity_ClassFindFieldByName(Entity->Class, Epair->Key); + + if (!Field) + return GE_FALSE; + //continue; + + UData = Entity->UserData; + + switch (Field->TypeClass->Type) + { + double f; + double X, Y, Z; + int32 M; + geEntity *Ent; + + case TYPE_INT: + sscanf(Epair->Value, "%d", UData + Field->Offset); + break; + + case TYPE_FLOAT: + sscanf(Epair->Value, "%lf", &f); + *(geFloat *)(UData + Field->Offset) = (geFloat)f; + break; + + case TYPE_POINT: + sscanf(Epair->Value, "%lf %lf %lf", &X, &Y, &Z); + ((geVec3d *)(UData + Field->Offset))->X = (geFloat)X; + ((geVec3d *)(UData + Field->Offset))->Y = (geFloat)Y; + ((geVec3d *)(UData + Field->Offset))->Z = (geFloat)Z; + break; + + case TYPE_COLOR: + sscanf(Epair->Value, "%lf %lf %lf", &X, &Y, &Z); + ((GE_RGBA *)(UData + Field->Offset))->r = (geFloat)X; + ((GE_RGBA *)(UData + Field->Offset))->g = (geFloat)Y; + ((GE_RGBA *)(UData + Field->Offset))->b = (geFloat)Z; + ((GE_RGBA *)(UData + Field->Offset))->a = 0.0f; + break; + + case TYPE_STRING: + // Point to string in Epair + *(char **)(UData + Field->Offset) = Epair->Value; + break; + + case TYPE_PTR: + // Must be some arbitrary pointer definition the user had in the private section. + // Always initialize these to NULL. + *(void **)(UData + Field->Offset) = NULL; + break; + + case TYPE_MODEL: + + Ent = geEntity_EntitySetFindEntityByName(EntitySet, Epair->Value); + + if (!Ent) + { + geErrorLog_Add(GE_ERR_MODEL_NOT_FOUND, NULL); + return GE_FALSE; + } + + if (!geEntity_GetModelNumForKey(Ent, "Model", &M)) + { + geErrorLog_Add(GE_ERR_MODEL_NOT_IN_ENTITY, NULL); + return GE_FALSE; + } + + // Point their structure directly to the model + *(geWorld_Model**)(UData + Field->Offset) = &GWorld->CurrentBSP->Models[M]; + + break; + + case TYPE_STRUCT: + Ent = geEntity_EntitySetFindEntityByName(EntitySet, Epair->Value); + + if (!Ent) + return GE_FALSE; + + // Point the void to the other entity + *(void **)(UData + Field->Offset) = Ent->UserData; + + assert(*(void **)(UData + Field->Offset) != NULL); + break; + + default: + //assert(!"Illegal top type"); + geErrorLog_Add(GE_ERR_INVALID_ENTITY_FIELD_TYPE, NULL); + return GE_FALSE; + } + } + + return GE_TRUE; +} + +//==================================================================================== +// ParseClassData +//==================================================================================== +static geBoolean ParseClassData(geEntity_EntitySet *EntitySet) +{ + geEntity_EntitySet *Set; + const char *Name; + + // + // Do this in two passes. First pass, we setup the entities, and allocate all the user data. + // Second pass, we actually parse the user data. This is so that we can resolve forward + // references in the user structures in the bsp file. + // + + + for (Set = EntitySet; Set; Set = Set->Next) + { + geEntity *Entity; + geEntity_Class *Class; + + Entity = Set->Entity; + + Name = geEntity_GetStringForKey(Entity, "classname"); + + if (!Name) + continue; + + Class = geEntity_EntitySetFindClassByName(EntitySet, Name); + + Entity->Class = NULL; + Entity->UserData = NULL; + + if (!Class) // Oops, this entity will not show up, it was not %typedef%'d + continue; + + // Let this entity remember it's type class + Entity->Class = Class; + // Make user data big enough to hold all possible data from class type + Entity->UserData = GE_RAM_ALLOCATE_ARRAY(char, Class->FieldSize); + + if (!Entity->UserData) + { + geErrorLog_Add(GE_ERR_GET_ENTITY_DATA_ERROR, NULL); + return GE_FALSE; + } + + // Clear the userdata + memset(Entity->UserData, 0, Class->FieldSize); + } + + for (Set = EntitySet; Set; Set = Set->Next) + { + geEntity *Entity; + + Entity = Set->Entity; + + Name = geEntity_GetStringForKey(Entity, "classname"); + + if (!Name) + continue; + + if (!ParseClassUserData(EntitySet, Entity)) + { + geErrorLog_Add(GE_ERR_GET_ENTITY_DATA_ERROR, NULL); + return GE_FALSE; + } + } + + return GE_TRUE; +} + +//==================================================================================== +// geEntity_EntitySetBuildClasses +//==================================================================================== +geBoolean geEntity_EntitySetBuildClasses(geEntity_EntitySet *Set) +{ + if (!BuildClassTypes(Set)) + return GE_FALSE; + + if (!ParseClassData(Set)) + return GE_FALSE; + + return GE_TRUE; +} + +//==================================================================================== +// geEntity_EntitySetLoadEntities +//==================================================================================== +geBoolean geEntity_EntitySetLoadEntities(geEntity_EntitySet *EntitySet, geVFile *VFile) +{ + int32 i, NumEntities; + + if (!geVFile_Read(VFile, &NumEntities, sizeof(int32))) + return GE_FALSE; + + for (i=0; i< NumEntities; i++) + { + geEntity *Entity; + int32 e, NumEpairs; + + // Create the entity + Entity = geEntity_Create(); + + if (!Entity) + return GE_FALSE; + + // Add it to the main set + if (!geEntity_EntitySetAddEntity(EntitySet, Entity)) + return GE_FALSE; + + // Load epairs + if (!geVFile_Read(VFile, &NumEpairs, sizeof(int32))) + return GE_FALSE; + + for (e=0; eKey = GE_RAM_ALLOCATE_ARRAY(char, Size); + + if (!Epair->Key) + return GE_FALSE; + + // Read the key + if (!geVFile_Read(VFile, Epair->Key, sizeof(char)*Size)) + return GE_FALSE; + + // Get the Value Size + if (!geVFile_Read(VFile, &Size, sizeof(int32))) + return GE_FALSE; + + Epair->Value = GE_RAM_ALLOCATE_ARRAY(char, Size); + + if (!Epair->Value) + return GE_FALSE; + + // Read the Value + if (!geVFile_Read(VFile, Epair->Value, sizeof(char)*Size)) + return GE_FALSE; + + // Add the epair to the entity + if (!geEntity_AddEpair(Entity, Epair)) + return GE_FALSE; + } + + } + + return GE_TRUE; + +} + +//==================================================================================== +// geEntity_LoadEntitySet +//==================================================================================== +geEntity_EntitySet *LoadEntitySet(const char *EntityData, int32 EntityDataSize) +{ + geEntity_EntitySet *EntitySet; + geVFile_MemoryContext Context; + geVFile *MemFile; + + // Default some NULLS here + EntitySet = NULL; + MemFile = NULL; + + // Setup the context for the memfile + Context.Data = (void*)EntityData; + Context.DataLength = EntityDataSize; + + MemFile = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_MEMORY, NULL, &Context, GE_VFILE_OPEN_READONLY); + + if (!MemFile) + return FALSE; + + // Create the entityset + EntitySet = geEntity_EntitySetCreate(); + + if (!EntitySet) // Out of memory!! + goto ExitWithError; + + EntitySet->OwnsEntities = GE_TRUE; // So this set will be the one to free everything... + + if (!geEntity_EntitySetLoadEntities(EntitySet, MemFile)) + goto ExitWithError; + + geVFile_Close(MemFile); + MemFile = NULL; + + if (!geEntity_EntitySetBuildClasses(EntitySet)) + goto ExitWithError; + + return EntitySet; + + // ** ERROR ** + ExitWithError: + { + if (EntitySet) + geEntity_EntitySetDestroy(EntitySet); + + if (MemFile) + geVFile_Close(MemFile); + + return NULL; + } +} diff --git a/G3D/Font/font.H b/G3D/Font/font.H new file mode 100644 index 0000000..9370505 --- /dev/null +++ b/G3D/Font/font.H @@ -0,0 +1,269 @@ +/****************************************************************************************/ +/* FONT.H */ +/* */ +/* Author: Thom Robertson */ +/* Description: Bitmapped font support interface */ +/* This implementation supports any TrueType fonts provided by Windows */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_FONT_H +#define GE_FONT_H + +// includes +#include "genesis.h" +#include "basetype.h" +#include "bitmap.h" +// ************************** +// to use this API: + +// 2. geFont_CreateFont(). + +// 3. (Optionally) geFont_AddCharacters(). +// 3A. Otherwise, IF you intend to use geFont_DrawText(), call geFont_AddBitmapBuffer(). + +// 4. Between geEngine_BeginFrame() and geEngine_EndFrame(), and after geEngine_RenderWorld(), +// geFont_DrawText(). You may call geFont_DrawTextToBitmap() anytime, though. + +// 5. When finished, geFont_Destroy(). + + + +//*************************************************************************************** +// these are bit flags for _DrawText(). Currently only _WORDWRAP is implemented, and without +// it, the function will still wrap, just not on word boundaries. +// Note that these will fail for non ascii fonts. +#define GE_FONT_WRAP 0x00000001 // wrap to fit inside the drawing rect +#define GE_FONT_WORDWRAP 0x00000002 // wrap on word boundaries +#define GE_FONT_JUST_RETURN_FIT 0x00000004 // returns number of characters that fit in drawing rectangle, WITHOUT drawing anything. +#define GE_FONT_JUSTIFY_RIGHT 0x00000008 +#define GE_FONT_JUSTIFY_CENTER 0x00000010 + +#ifdef __cplusplus +extern "C" { +#endif + +// opaque structure headers. +typedef struct geFont geFont; // an instance of a font + + +//*************************************************************************************** +GENESISAPI geFont *GENESISCC geFont_Create(const geEngine *Engine, const char *fontNameString, + const int fontSize, + const int fontWeight , const geBoolean antialiased) ; + // Creates a font, and returns a pointer to it. + // Pass in the string name of the TrueType font (case sensitive), and the height in pixels. + + // ARGUMENTS: + // fontNameString - char pointer to a string containing the case sensitive name of the font. + // fontSize - the pixel height of the requested font. + + // RETURNS: + // success: pointer to the newly created font. + // failure: NULL. + + // NOTE: the new font set has NO actual characters in it at first. You must add characters + // to it with the _AddCharacters() function before you can use the font. + // NOTE: all fonts start out with a grayscale palette, with the range 0 to 128. + +//*************************************************************************************** +GENESISAPI void GENESISCC geFont_CreateRef(geFont *font); + + +//*************************************************************************************** +GENESISAPI void GENESISCC geFont_Destroy(geFont **font); + // destroys a font. + + // ARGUMENTS: + // font - pointer to the font to be destroyed. + + // RETURNS: + // nothing. + +//*************************************************************************************** +GENESISAPI geBoolean GENESISCC geFont_AddCharacters(geFont *font, + unsigned char leastIndex, + unsigned char mostIndex + ); + // Adds a set of characters to the font defined by the ascii range passed in + // (leastIndex and mostIndex, inclusive). + + // ARGUMENTS: + // font - pointer to the font to add characters to. + // e - pointer to a valid geEngine. + // leastIndex and mostIndex - the ASCII range of characters to add. + // cellBuffer - an allocated hunk of ram to temproarily store the character image + // bufferSize - length of the above buffer + + // RETURNS: + // success: GE_TRUE. + // failure: GE_FALSE. + + // NOTES: + // This is the function that actually uses the + // Win32 GetGlyphOutline() function to draw the character onto a geBitmap, which can be + // blitted to the screen. + + +//******************************************************************************* +GENESISAPI void GENESISCC geFont_DestroyBitmapBuffer( geFont *font ); + // destroys any valid "scratch-pad" buffer attached to the geFont. + // ARGUMENTS: + // font - pointer to the geFont. + // + // NOTES: + // you'll rarely need to call this function; it's called by geFont_Destroy() anyway. + // Calling this function with a geFont that has no initialized buffer doesn't + // hurt anything. + +//******************************************************************************* +GENESISAPI geBoolean GENESISCC geFont_AddBitmapBuffer( + geFont *font, const uint32 width, const uint32 height); + // Adds a geBitmap to the geFont, to be used as a temporary "scratch-pad". This is + // required for using geFont_DrawText() when no characters have been added. + + // ARGUMENTS: + // font - pointer to the geFont to add a buffer to. + // width and height - the size of the buffer to create. Make sure this size is >= + // the biggest rectagle of text you'll want to write to the screen using this geFont + // and DrawText(). + + // RETURNS: + // success: GE_TRUE. + // failure: GE_FALSE. + + // NOTES: + // You don't need to call this function IF you _AddCharacters() to this geFont. + // You call this function for each geFont you need to use. geFont's don't share buffers. + // if you call this function on a geFont that already has a valid buffer, the buffer is + // destroyed, and replaced by the new one. + +//*************************************************************************************** +GENESISAPI geBoolean GENESISCC geFont_DrawText(geFont *font, const char *textString, + const GE_Rect *Rect, const GE_RGBA *Color, + uint32 flags, const GE_Rect *clipRect); + // This is the function you put between geEngine_BeginFrame() and _EndFrame(), the function + // that draws text to the screen. + + // ARGUMENTS: + // font - pointer to the font to draw with. IF the font has NO characters in it + // (added by geFont_AddCharacters() ) then a different, more windows-intensive way is + // used to draw out the characters. + // textString - pointer to the text string to output to the screen. + // Rect - screen rectangle to place the text within. + // Color - RGB color the text should be. + // flags - a bitfield of GE_FONT_ values. + // clipRect - pointer to a screen rectangle to clip the text to. MAY BE NULL, in which + // case the text is only clipped by the boundaries of the screen. + + // RETURNS: + // success: GE_TRUE. + // failure: GE_FALSE. + + // NOTES: + // Assuming you've added characters to the font, characters which have NOT been added + // WILL cause an assert if you try to draw them. + // Only GE_FONTSET_WORDWRAP is meaningfull right now. Using any other flags will cause + // an assert. + // As stated above, you can use an entirely different way of creating a string, by + // making a font with no characters in it. This + // jumps through Windows DIB hoops, and draws the text in a non-anti-aliased, but + // (hopefully) more unicode-tolerant way (DrawText() ). + + +//*************************************************************************************** +GENESISAPI geBoolean GENESISCC geFont_DrawTextToBitmap(geFont *font, const char *textString, + const GE_Rect *Rect, const GE_RGBA *Color, + uint32 flags, const GE_Rect *clipRect, + geBitmap *targetBitmap); + // This is the function you put between geEngine_BeginFrame() and _EndFrame(), the function + // that draws text to the screen. + + // ARGUMENTS: + // font - pointer to the font to draw with. IF the font has NO characters in it + // (added by geFont_AddCharacters() ) then a different, more windows-intensive way is + // used to draw out the characters. + // textString - pointer to the text string to output to the screen. + // Rect - screen rectangle to place the text within. + // Color - RGB color the text should be. + // flags - a bitfield of GE_FONT_ values. + // clipRect - pointer to a screen rectangle to clip the text to. MAY BE NULL, in which + // case the text is only clipped by the boundaries of the screen. + // targetBitmap - pointer to a target bitmap to draw the text into. MAY NOT BE NULL, + // and MUST BE GE_PIXELFORMAT_8BIT. + + // RETURNS: + // success: GE_TRUE. + // failure: GE_FALSE. + + // NOTES: + // Assuming you've added characters to the font, characters which have NOT been added + // WILL cause an assert if you try to draw them. + // Only GE_FONTSET_WORDWRAP is meaningfull right now. Using any other flags will cause + // an assert. + // As stated above, you can use an entirely different way of creating a string, by + // making a font with no characters in it. This + // jumps through Windows DIB hoops, and draws the text in a non-anti-aliased, but + // (hopefully) more unicode-tolerant way (DrawText() ). + // The Color argument is will be used to modify the existing palette of the targetBitmap + // passed in. Therefore, you won't be able to _DrawTextToBitmap() a red piece of text, + // then a green piece, then a blue piece. You'll end up with three lines of blue text. + + +//*************************************************************************************** +GENESISAPI int32 GENESISCC geFont_GetStringPixelWidth (geFont *font, const char *textString); +GENESISAPI int32 GENESISCC geFont_GetStringPixelHeight(geFont *font, const char *textString); + // These two functions return the pixel width and height of the string passed in. + + // ARGUMENTS: + // font - pointer to the font to draw with. + // textString - pointer to the text string to output to the screen. + + // RETURNS: + // success: a positive value in pixels. IF the text passed in contains characters + // which haven't been added to the font yet, BUT other characters HAVE + // been added, the function asserts. + // failure: -1. + // NOTES: + // these two functions assume no text wrapping! + +//*************************************************************************************** +GENESISAPI geBitmap* GENESISCC geFont_GetBuffer(geFont *font); + // This function returns a pointer to the drawing buffer contained by the font. + + // ARGUMENTS: + // font - pointer to the font. + + // RETURNS: + // a valid pointer to a geBitmap, OR NULL, signifying that the buffer wasn't initialized. + + +//*************************************************************************************** +GENESISAPI geBoolean GENESISCC geFont_GetCharMap(geFont *font, uint8 character, GE_Rect *Rect, + geBitmap **targetBitmap, int32 *fullWidth, int32 *fullHeight, + int32 *offsetX, int32 *offsetY); + +//*************************************************************************************** +GENESISAPI void GENESISCC geFont_EnableAntialiasing(geFont *font, const geBoolean anti); +//*************************************************************************************** +GENESISAPI geBoolean GENESISCC geFont_IsAntialiased(geFont *font); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Font/font.c b/G3D/Font/font.c new file mode 100644 index 0000000..1c9f94d --- /dev/null +++ b/G3D/Font/font.c @@ -0,0 +1,1366 @@ +/****************************************************************************************/ +/* FONT.C */ +/* */ +/* Author: Thom Robertson */ +/* Description: Bitmapped font support implementation */ +/* This implementation supports any TrueType fonts provided by Windows */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define WIN32_LEAN_AND_MEAN +#pragma warning(disable : 4201 4214 4115) +#include +#include +#pragma warning(default : 4201 4214 4115) + +#include "extbox.h" +#include "ram.h" +#include "wgClip.h" + +#include +#include + +#include "font.h" + +#pragma warning (disable:4514) // unreferenced inline function (caused by Windows) + +//*************************************************************************************** +GENESISAPI geBoolean GENESISCC geFont_TestDraw(geFont *font, int16 x, int16 y, int16 index); + // This is a debugging function that you shouldn't have to use. It outputs an entire + // bitmap full of characters to the screen and the x,y location. + + // ARGUMENTS: + // font - pointer to the font to draw with. + // x and y - screen location to draw the upper left corner of the bitamp at. + // index - which bitmap to draw. + + // RETURNS: + // success: GE_TRUE + // failure: GE_FALSE + + // NOTES: + // Since fonts can be of an arbitrary point size, an arbitrary amount of 256x256 + // bitmaps is required to represent all of the characters. The index argument lets you + // pick which bitmap in the list to display. + + + +//******************************************************************************* +typedef struct geFontBitmap +{ + void *next; + geBitmap *map; + int16 freeX, freeY; // place the next character here. + +} geFontBitmap; + +//******************************************************************************* +typedef struct geFontCharacterRecord +{ + geFontBitmap *bitmapUsed; // NULL == not initialized yet. + GE_Rect bitmapRect; + int32 offsetX, offsetY, fullWidth; + +} geFontCharacterRecord; + +//******************************************************************************* +typedef struct geFont +{ + char fontNameString[64]; + int16 fontSize; + int16 fontWeight; + geFontBitmap *bitmapList; + geFontCharacterRecord characterArray[256]; + const geEngine *Engine; + geBitmap *buffer; + + geBoolean antialiased; + + int32 refCount; + +} geFont; + + + +GENESISAPI geBoolean GENESISCC geFont_DrawUsingDIB(geFont *font, const char *textString, + RECT box, geBitmap *targetBitmap, + const GE_RGBA *Color, uint32 flags); + +//******************************************************************************* +//******************************************************************************* +GENESISAPI geFont *GENESISCC geFont_Create(const geEngine *Engine, const char *fontNameString, + const int fontSize, const int fontWeight, + const geBoolean anti) +{ + geFont *font; + int i; + + // create a new font + font = GE_RAM_ALLOCATE_STRUCT(geFont); + assert(font); + + // initalize the new font to having no data in it. + font->bitmapList = NULL; + for (i = 0; i < 256; i++) + font->characterArray[i].bitmapUsed = NULL; + + strncpy(font->fontNameString, fontNameString,64); + font->fontNameString[63] = 0; + + font->fontSize = fontSize; + font->fontWeight = fontWeight; + + font->Engine = Engine; + + font->buffer = NULL; + + font->refCount = 1; + + font->antialiased = anti; + + return font; +} + +//*************************************************************************************** +GENESISAPI void GENESISCC geFont_CreateRef(geFont *font) +{ + assert(font); + font->refCount++; +} + + +//******************************************************************************* +GENESISAPI void GENESISCC geFont_Destroy(geFont **font) +{ + + geFontBitmap *curFontBitmap, *tempFontBitmap; + + assert(*font); + + (*font)->refCount--; + + // don't destroy this font if there's still a reference out there. + if ((*font)->refCount > 0) + return; + + geFont_DestroyBitmapBuffer(*font); + + curFontBitmap = (*font)->bitmapList; + while (curFontBitmap) + { + tempFontBitmap = curFontBitmap->next; + + geEngine_RemoveBitmap((geEngine *) (*font)->Engine, curFontBitmap->map); + + geBitmap_Destroy(&(curFontBitmap->map)); + geRam_Free(curFontBitmap); + curFontBitmap = tempFontBitmap; + } + + geRam_Free(*font); + (*font) = NULL; + +} + +//**************************************************************************** +FIXED PASCAL NEAR FixedFromDouble(double d) +{ + long l; + + l = (long) (d * 65536L); + return *(FIXED *)&l; +} + +//******************************************************************************* +static void IdentityMat(LPMAT2 lpMat) +{ + lpMat->eM11 = FixedFromDouble(1); + lpMat->eM12 = FixedFromDouble(0); + lpMat->eM21 = FixedFromDouble(0); + lpMat->eM22 = FixedFromDouble(1); +} + +//******************************************************************************* +void PlaceLetter(int16 locX, int16 locY, geFont *font, geFontBitmap *fontMap, + uint32 asciiValue, unsigned char *cellBuffer, DWORD bufferSize) +{ + GLYPHMETRICS glyphMetrics; + HDC hdc; + MAT2 mat2; + int32 success, bufferReturnSize; + uint32 x,y; + unsigned char *destBits; + int bufferWidth, possibleH; + char c; + int16 mapWidth, mapHeight; + HFONT win32Font, win32OldFont; + geBitmap *lock; + geBitmap_Info Info; + geBitmap_Info SecondaryInfo; + + uint32 ggoFormat; + + IdentityMat(&mat2); + + + mapWidth = geBitmap_Width (fontMap->map); + mapHeight = geBitmap_Height(fontMap->map); + + win32Font = CreateFont( -1 * font->fontSize, + 0,0,0, font->fontWeight, + 0,0,0,0,OUT_TT_ONLY_PRECIS ,0,0,0, font->fontNameString); + + hdc = GetDC(GetDesktopWindow()); + assert(hdc); + + c = (char)asciiValue; + + if (font->antialiased) + ggoFormat = GGO_GRAY8_BITMAP; + else + ggoFormat = GGO_BITMAP; + + win32OldFont = SelectObject( hdc, win32Font); + bufferReturnSize = GetGlyphOutline( hdc, asciiValue, ggoFormat, + &glyphMetrics, 0, NULL, &mat2); + success = GetGlyphOutline( hdc, asciiValue, ggoFormat, + &glyphMetrics, bufferSize, cellBuffer, &mat2); + assert(GDI_ERROR != success); +// success = GetGlyphOutline( hdc, asciiValue, GGO_METRICS, &glyphMetrics, 0, NULL, &mat2); +// assert(GDI_ERROR != success); + SelectObject( hdc, win32OldFont); + + ReleaseDC(GetDesktopWindow(),hdc); + + DeleteObject(win32Font); + + // get buffer width +// bufferWidth = glyphMetrics.gmCellIncX - glyphMetrics.gmptGlyphOrigin.x; +// bufferWidth = glyphMetrics.gmBlackBoxX; + if (glyphMetrics.gmBlackBoxY) + { + possibleH = glyphMetrics.gmBlackBoxY-1; + do + { + possibleH++; + bufferWidth = bufferReturnSize / possibleH; + } while (bufferWidth * possibleH != bufferReturnSize); + } + else + bufferWidth = glyphMetrics.gmBlackBoxX; + + if (GGO_BITMAP == ggoFormat) + { + bufferWidth/= 8; + if (bufferWidth <= 0) + bufferWidth = 1; + } + + + // make sure it's double-word aligned. + while (bufferWidth%4) + bufferWidth++; + + font->characterArray[asciiValue].bitmapUsed = fontMap; + font->characterArray[asciiValue].bitmapRect.Left = fontMap->freeX; + font->characterArray[asciiValue].bitmapRect.Top = fontMap->freeY; + font->characterArray[asciiValue].bitmapRect.Right = fontMap->freeX + + glyphMetrics.gmBlackBoxX; + font->characterArray[asciiValue].bitmapRect.Bottom = fontMap->freeY + + glyphMetrics.gmBlackBoxY; + font->characterArray[asciiValue].offsetX = glyphMetrics.gmptGlyphOrigin.x; + font->characterArray[asciiValue].offsetY = glyphMetrics.gmptGlyphOrigin.y; + font->characterArray[asciiValue].fullWidth = glyphMetrics.gmCellIncX; + + glyphMetrics.gmptGlyphOrigin.y = glyphMetrics.gmptGlyphOrigin.y - glyphMetrics.gmBlackBoxY; + + + // lock the fontMap surface... + success = geBitmap_LockForWrite( fontMap->map, &lock, + 0,0); + success = geBitmap_GetInfo(lock, &Info, &SecondaryInfo); + mapWidth = Info.Stride; + + destBits = geBitmap_GetBits(lock); + + // clear the character space to 0s... + if (GGO_BITMAP == ggoFormat) + { + + for ( y = 0; + y < glyphMetrics.gmBlackBoxY; + y++) + { + for (x = 0; + x < glyphMetrics.gmBlackBoxX; + x++) + { + uint8 temp, mask; + temp = cellBuffer[y * bufferWidth + x/8]; + mask = 1 << (7 - (x % 8)); + + if (mask&temp) + destBits[(y+locY)*mapWidth + (x+locX)] = 255; + else + destBits[(y+locY)*mapWidth + (x+locX)] = 0; + } + } + } + else + { + for ( y = 0; + y < glyphMetrics.gmBlackBoxY; + y++) + { + for (x = 0; + x < glyphMetrics.gmBlackBoxX; + x++) + { + int temp; + temp = 4 * cellBuffer[y * bufferWidth + x]; + if (temp> 255) + temp = 255; + destBits[(y+locY)*mapWidth + (x+locX)] = temp; + } + } + } + success = geBitmap_UnLock(lock); +} + +//******************************************************************************* +GENESISAPI geBoolean GENESISCC geFont_AddCharacters(geFont *font, + unsigned char leastIndex, + unsigned char mostIndex + ) +{ + MAT2 mat2; + GLYPHMETRICS glyphMetrics; + HDC hdc; + DWORD success; + unsigned char asciiValue; + int placedLetter; + int16 mapWidth, mapHeight; + HFONT win32Font, win32OldFont; + geFontBitmap *fontBitmap; + geBitmap_Palette *Palette; + int i; + unsigned char *cellBuffer; + DWORD bufferSize; + + uint32 ggoFormat; + + mat2.eM11.fract = 0; + mat2.eM11.value = 1; + mat2.eM12.fract = 0; + mat2.eM12.value = 0; + mat2.eM21.fract = 0; + mat2.eM21.value = 0; + mat2.eM22.fract = 0; + mat2.eM22.value = 1; + + // get the character bitmap + bufferSize = 32768; + cellBuffer = GE_RAM_ALLOCATE_ARRAY(unsigned char, bufferSize); + memset(cellBuffer,0xee,bufferSize); + + + for (asciiValue = leastIndex; asciiValue <= mostIndex; asciiValue++) + { + placedLetter = FALSE; + + if (font->antialiased) + ggoFormat = GGO_GRAY8_BITMAP; + else + ggoFormat = GGO_BITMAP; + + // find out the dimensions of the character + win32Font = CreateFont( -1 * font->fontSize, + 0,0,0, font->fontWeight, + 0,0,0,0,OUT_TT_ONLY_PRECIS ,0,0,0, font->fontNameString); + + hdc = GetDC(GetDesktopWindow()); + assert(hdc); + + win32OldFont = SelectObject( hdc, win32Font); + success = GetGlyphOutline( hdc, asciiValue, ggoFormat, + &glyphMetrics, bufferSize, cellBuffer, &mat2); + SelectObject( hdc, win32OldFont); + + ReleaseDC(GetDesktopWindow(),hdc); + + DeleteObject(win32Font); + + fontBitmap = font->bitmapList; + while (fontBitmap) + { + // will it fit into the current bitmap? + mapWidth = geBitmap_Width (fontBitmap->map); + mapHeight = geBitmap_Height(fontBitmap->map); + + // if there's enough vertical space... + if ((int32)glyphMetrics.gmBlackBoxY <= (mapHeight-1) - fontBitmap->freeY) + { + // if there's enough horizontal space... + if (glyphMetrics.gmCellIncX <= (mapWidth-1) - fontBitmap->freeX) + { + // place the letter! + PlaceLetter(fontBitmap->freeX, fontBitmap->freeY, font, + fontBitmap, asciiValue, cellBuffer, bufferSize); + placedLetter = TRUE; + fontBitmap->freeX = fontBitmap->freeX + glyphMetrics.gmBlackBoxX; + } + else + { + fontBitmap->freeY = fontBitmap->freeY + font->fontSize; + fontBitmap->freeX = 0; + // if there's enough vertical space... + if ((int32)glyphMetrics.gmBlackBoxY <= (mapHeight-1) - fontBitmap->freeY) + { + // if there's enough horizontal space... + if (glyphMetrics.gmCellIncX <= (mapWidth-1) - fontBitmap->freeX) + { + // place the letter! + PlaceLetter(fontBitmap->freeX, fontBitmap->freeY, font, + fontBitmap, asciiValue, cellBuffer, bufferSize); + placedLetter = TRUE; + fontBitmap->freeX = fontBitmap->freeX + glyphMetrics.gmBlackBoxX; + } + } + } + } + fontBitmap = fontBitmap->next; + } + + if (!placedLetter) + { + // gotta create a new font bitmap. + fontBitmap = GE_RAM_ALLOCATE_STRUCT(geFontBitmap); + assert(fontBitmap); + fontBitmap->next = font->bitmapList; + font->bitmapList = fontBitmap; + fontBitmap->freeX = 0; + fontBitmap->freeY = 0; + fontBitmap->map = geBitmap_Create(256,256, 1, GE_PIXELFORMAT_8BIT); + + // and a pallette for it. + Palette = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_XRGB, 256); + + for (i = 0; i < 256; i++) + { + success = geBitmap_Palette_SetEntryColor(Palette, i, i, i, i, i); + assert(success); + + } + + success = geBitmap_SetPalette(fontBitmap->map, Palette); + assert(success); + + success = geBitmap_SetColorKey(fontBitmap->map, TRUE, 0 ,FALSE ); + + + success = geBitmap_Palette_Destroy(&Palette); + assert(success); + + + success = geEngine_AddBitmap((geEngine *)font->Engine, fontBitmap->map); + assert(success); + + PlaceLetter(fontBitmap->freeX, fontBitmap->freeY, font, + fontBitmap, asciiValue, cellBuffer, bufferSize); + fontBitmap->freeX = fontBitmap->freeX + glyphMetrics.gmBlackBoxX; + + + } + + } + + geRam_Free(cellBuffer); + + return TRUE; +} + +//******************************************************************************* +GENESISAPI geBoolean GENESISCC geFont_DrawText(geFont *font, const char *textString, + const GE_Rect *Rect, const GE_RGBA *Color, + uint32 flags, const GE_Rect *clipRect) +{ + + int32 x,y,i; + int32 tempX;//, tempY; + int32 lineLen; + + uint32 colorArray[256]; + geFloat fcolorX, fcolorR, fcolorG, fcolorB; + + int32 stringLen; + int32 currentCharIndex; + int32 lineEndIndex=0; + geFontCharacterRecord *charRec; + + geBoolean success; + geBoolean longEnough, endOfText; + + GE_Rect artRect; + RECT box; + int32 resultX, resultY; + + geFontBitmap *lastBitmap; + geBitmap_Palette * palette; + + // unimplemented flags which we don't want you to use yet. + assert(!(flags & GE_FONT_WRAP )); + assert(!(flags & GE_FONT_JUST_RETURN_FIT)); + assert(!(flags & GE_FONT_JUSTIFY_RIGHT )); + assert(!(flags & GE_FONT_JUSTIFY_CENTER )); + + lastBitmap = NULL; + x = 0; + y = 0; + stringLen = strlen(textString); + currentCharIndex = 0; + + if (font->bitmapList) // if this font has character bitmaps... + { + + while (currentCharIndex < stringLen) + { + // skip leading white space for this line. + while (isspace(textString[currentCharIndex]) && currentCharIndex < stringLen) + currentCharIndex++; + + // if, because of the whitespace skip, we're out of text, exit the loop. + if (currentCharIndex >= stringLen) + break; + + lineLen = 0; + lineEndIndex = currentCharIndex; + longEnough = FALSE; + endOfText = FALSE; + while (!longEnough) + { + charRec = &(font->characterArray[textString[lineEndIndex]]); + + // if the character has art... + if (charRec->bitmapUsed) + { + + if (Rect->Left + lineLen + (charRec->fullWidth) > + Rect->Right) + longEnough = TRUE; + else + { + lineLen = lineLen + (charRec->fullWidth); + lineEndIndex++; + if (lineEndIndex >= stringLen) + { + longEnough = TRUE; + endOfText = TRUE; + } + } + } + else + { + lineEndIndex++; + if (lineEndIndex >= stringLen) + { + longEnough = TRUE; + endOfText = TRUE; + } + } + } + + // if we're word-wrapping, back up to BEFORE the last hunk of whitespace. + if (flags & GE_FONT_WORDWRAP && !endOfText) + { + tempX = lineEndIndex; + while (tempX > currentCharIndex && !isspace(textString[tempX])) + tempX--; + + if (isspace(textString[tempX])) + { + while (tempX > currentCharIndex && isspace(textString[tempX])) + tempX--; + + lineEndIndex = tempX; + } + } + + // aaannnddd, DRAW! + for (; currentCharIndex <= lineEndIndex && currentCharIndex < stringLen; currentCharIndex++) + { + charRec = &(font->characterArray[textString[currentCharIndex]]); + + if (charRec->bitmapUsed) + { + + if (charRec->bitmapUsed != lastBitmap) + { + + lastBitmap = charRec->bitmapUsed; + + palette = geBitmap_GetPalette(lastBitmap->map); + assert(palette); + + for (i = 0; i < 256; i++) + { + + fcolorR = Color->r * i / 255; + fcolorG = Color->g * i / 255; + fcolorB = Color->b * i / 255; + fcolorX = Color->a * i / 255; + + colorArray[i] = gePixelFormat_ComposePixel( GE_PIXELFORMAT_32BIT_XRGB, (int)fcolorR, (int)fcolorG, (int)fcolorB, (int)fcolorX); + } + + success = geBitmap_Palette_SetData( palette ,colorArray,GE_PIXELFORMAT_32BIT_XRGB, 256); + + success = geBitmap_SetPalette(lastBitmap->map, palette); + assert(success); + + } + + + if (clipRect) + { + artRect = charRec->bitmapRect; + + if ( CalculateClipping( &artRect, &resultX, &resultY, + Rect->Left + x + charRec->offsetX, + Rect->Top + y + (font->fontSize - charRec->offsetY), + *clipRect, GE_CLIP_CORNER) + ) + { + success = geEngine_DrawBitmap(font->Engine, charRec->bitmapUsed->map, + &artRect, resultX, resultY); + } + + } + else + { + success = geEngine_DrawBitmap(font->Engine, charRec->bitmapUsed->map, + &(charRec->bitmapRect), Rect->Left + x + charRec->offsetX, + Rect->Top + y + (font->fontSize - charRec->offsetY)); + } + x += charRec->fullWidth; + } + else + { + // we reached this point because we're trying to draw a character that + // hasn't been added to the font yet using geFont_AddCharacters(). + assert(0); + } + + } + y += font->fontSize; + x = 0; + } + } + else // this font has no attached bitmaps, sooo, we do it another way! + { + + // at this point, we're trying to put text to the screen using DrawText() and + // a DIB. This process REQUIRES an initialized geBitmap as a go-between. + // Is it initialized? + assert(font->buffer); + + box.left = 0; + box.right = Rect->Right - Rect->Left; + box.top = 0; + box.bottom = Rect->Bottom - Rect->Top; + + // does the buffer have sufficient dimensions? + assert (box.right <= geBitmap_Width (font->buffer)); + assert (box.bottom <= geBitmap_Height(font->buffer)); + + artRect.Left = box.left; + artRect.Right = box.right; + artRect.Top = box.top; + artRect.Bottom = box.bottom; + + success = geFont_DrawTextToBitmap(font, textString, &artRect, Color, + flags, NULL, font->buffer); + + if (clipRect) + { + if ( CalculateClipping( &artRect, &resultX, &resultY, + Rect->Left, + Rect->Top, + *clipRect, GE_CLIP_CORNER) + ) + { + success = geEngine_DrawBitmap(font->Engine, font->buffer, + &artRect, resultX, resultY); + } + } + else + { + success = geEngine_DrawBitmap(font->Engine, font->buffer, + &artRect, Rect->Left, Rect->Top); + } + } + + return lineEndIndex; +} + + +//******************************************************************************* +GENESISAPI void GENESISCC geFont_DestroyBitmapBuffer( geFont *font ) +{ + geBoolean success; + assert(font); + if (font->buffer) + { + success = geEngine_RemoveBitmap((geEngine *)font->Engine, font->buffer); + assert(success); + + geBitmap_Destroy(&font->buffer); + } + +} + +//******************************************************************************* +GENESISAPI geBoolean GENESISCC geFont_AddBitmapBuffer( + geFont *font, const uint32 width, const uint32 height) +{ + geBoolean success; + geBitmap_Palette * palette; + int i; + + assert(font); + + assert(width < 1000); // just checking for absurd values that indicate + assert(height < 1000); // an un-initialized state. + + if (font->buffer) + geFont_DestroyBitmapBuffer( font ); + + font->buffer = geBitmap_Create(width, height, 1, GE_PIXELFORMAT_8BIT); + assert(font->buffer); + + // and a pallette for it. + palette = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_XRGB, 256); + assert(palette); + + for (i = 0; i < 256; i++) + { + success = geBitmap_Palette_SetEntryColor(palette, i, i, i, i, i); + assert(success); + + } + + success = geBitmap_SetPalette(font->buffer, palette); + assert(success); + + success = geBitmap_SetColorKey(font->buffer, TRUE, 0 ,FALSE ); + + success = geEngine_AddBitmap((geEngine *)font->Engine, font->buffer); + assert(success); + + return GE_TRUE; + +} + +//******************************************************************************* +GENESISAPI geBoolean GENESISCC geFont_DrawTextToBitmap(geFont *font, const char *textString, + const GE_Rect *Rect, const GE_RGBA *Color, + uint32 flags, const GE_Rect *clipRect, + geBitmap *targetBitmap) +{ + + int32 x,y,i; + int32 tempX;//, tempY; + int32 lineLen; + + uint32 colorArray[256]; + geFloat fcolorX, fcolorR, fcolorG, fcolorB; + + int32 stringLen; + int32 currentCharIndex; + int32 lineEndIndex=0; + geFontCharacterRecord *charRec; + + geBoolean success; + geBoolean longEnough, endOfText; + + GE_Rect artRect; + RECT box; + int32 resultX, resultY; + + geFontBitmap *lastBitmap; + geBitmap_Palette * palette; + + + // unimplemented flags which we don't want you to use yet. + assert(!(flags & GE_FONT_WRAP )); + assert(!(flags & GE_FONT_JUST_RETURN_FIT)); + assert(!(flags & GE_FONT_JUSTIFY_RIGHT )); + assert(!(flags & GE_FONT_JUSTIFY_CENTER )); + + assert(targetBitmap); + + lastBitmap = NULL; + x = 0; + y = 0; + stringLen = strlen(textString); + currentCharIndex = 0; + + if (font->bitmapList) // if this font has character bitmaps... + { + + while (currentCharIndex < stringLen) + { + // skip leading white space for this line. + while (isspace(textString[currentCharIndex]) && currentCharIndex < stringLen) + currentCharIndex++; + + // if, because of the whitespace skip, we're out of text, exit the loop. + if (currentCharIndex >= stringLen) + break; + + lineLen = 0; + lineEndIndex = currentCharIndex; + longEnough = FALSE; + endOfText = FALSE; + while (!longEnough) + { + charRec = &(font->characterArray[textString[lineEndIndex]]); + + // if the character has art... + if (charRec->bitmapUsed) + { + + if (Rect->Left + lineLen + (charRec->fullWidth) > + Rect->Right) + longEnough = TRUE; + else + { + lineLen = lineLen + (charRec->fullWidth); + lineEndIndex++; + if (lineEndIndex >= stringLen) + { + longEnough = TRUE; + endOfText = TRUE; + } + } + } + else + { + lineEndIndex++; + if (lineEndIndex >= stringLen) + { + longEnough = TRUE; + endOfText = TRUE; + } + } + } + + // if we're word-wrapping, back up to BEFORE the last hunk of whitespace. + if (flags & GE_FONT_WORDWRAP && !endOfText) + { + tempX = lineEndIndex; + while (tempX > currentCharIndex && !isspace(textString[tempX])) + tempX--; + + if (isspace(textString[tempX])) + { + while (tempX > currentCharIndex && isspace(textString[tempX])) + tempX--; + + lineEndIndex = tempX; + } + } + + // aaannnddd, DRAW! + for (; currentCharIndex <= lineEndIndex && currentCharIndex < stringLen; currentCharIndex++) + { + charRec = &(font->characterArray[textString[currentCharIndex]]); + + if (charRec->bitmapUsed) + { + + if (charRec->bitmapUsed != lastBitmap) + { + + lastBitmap = charRec->bitmapUsed; + + palette = geBitmap_GetPalette(lastBitmap->map); + assert(palette); + + for (i = 0; i < 256; i++) + { + + fcolorR = Color->r * i / 255; + fcolorG = Color->g * i / 255; + fcolorB = Color->b * i / 255; + fcolorX = Color->a * i / 255; + + colorArray[i] = gePixelFormat_ComposePixel( GE_PIXELFORMAT_32BIT_XRGB, (int)fcolorR, (int)fcolorG, (int)fcolorB, (int)fcolorX); + } + + success = geBitmap_Palette_SetData( palette ,colorArray,GE_PIXELFORMAT_32BIT_XRGB, 256); + + success = geBitmap_SetPalette(lastBitmap->map, palette); + assert(success); + + } + + + if (clipRect) + { + artRect = charRec->bitmapRect; + + if ( CalculateClipping( &artRect, &resultX, &resultY, + Rect->Left + x + charRec->offsetX, + Rect->Top + y + (font->fontSize - charRec->offsetY), + *clipRect, GE_CLIP_CORNER) + ) + { + success = geBitmap_Blit(charRec->bitmapUsed->map, artRect.Left, artRect.Top, + targetBitmap, resultX, resultY, + artRect.Right - artRect.Left, artRect.Bottom - artRect.Top ); + } + + } + else + { + success = geBitmap_Blit(charRec->bitmapUsed->map, charRec->bitmapRect.Left, + charRec->bitmapRect.Top, targetBitmap, + Rect->Left + x + charRec->offsetX, Rect->Top + y + (font->fontSize - charRec->offsetY), + charRec->bitmapRect.Right - charRec->bitmapRect.Left, + charRec->bitmapRect.Bottom - charRec->bitmapRect.Top ); + } + x += charRec->fullWidth; + } + else + { + // we reached this point because we're trying to draw a character that + // hasn't been added to the font yet using geFont_AddCharacters(). + assert(0); + } + + } + y += font->fontSize; + x = 0; + } + } + else // this font has no attached bitmaps, sooo, we do it another way! + { + box.left = Rect->Left; + box.right = Rect->Right; + box.top = Rect->Top; + box.bottom = Rect->Bottom; + success = geFont_DrawUsingDIB(font, textString, box, targetBitmap, Color, flags); + } + + return lineEndIndex; +} + + +//******************************************************************************* +GENESISAPI geBoolean GENESISCC geFont_TestDraw(geFont *font, int16 x, int16 y, int16 index) +{ + geRect Source; + geFontBitmap *fontBitmap; + geBoolean success; + + fontBitmap = font->bitmapList; + for (; index > 0 && fontBitmap->next; index--) + fontBitmap = fontBitmap->next; + + assert(fontBitmap); + + Source.Top = 0; + Source.Left = 0; + Source.Right = 255; + Source.Bottom = 255; + + success = geEngine_DrawBitmap(font->Engine, fontBitmap->map, + &Source, x, y); + + return success; +} + + + + +//******************************************************************************* +GENESISAPI geBoolean GENESISCC geFont_DrawUsingDIB(geFont *font, const char *textString, + RECT box, geBitmap *targetBitmap, + const GE_RGBA *Color, uint32 flags) +{ + + geBoolean success; + + HDC hdc, drawDC; + + geFloat fcolorR, fcolorG, fcolorB; + + int32 x,y; + + uint8 *lpDIBBuffer, tempChar; // DIB image buffer + HBITMAP hDIB, oldMap; // Handle returned from CreateDIBSection + HPALETTE hPalette; // Handle to palette if 8-bit mode in use + HFONT oldFont, winFont; + LOGPALETTE *pLogPal; // LOGPALETTE structure + BITMAPINFO *pbmi; // BITMAPINFO structure + BITMAPINFOHEADER *pbmih; // Pointer to pbmi header + + int locX, locY; + + geBitmap *lock; + geBitmap_Info Info; + geBitmap_Info SecondaryInfo; + + unsigned char *destBits; + int16 mapWidth; + + + int i; + + int desktop_bpp, display_bpp; + + int targetSizeX, targetSizeY; + + // + // Init DIB stuff + // + + desktop_bpp = 8; + display_bpp = 8; + + targetSizeX = geBitmap_Width (targetBitmap) + ( 4 - ( geBitmap_Width (targetBitmap) % 4 ) ); + targetSizeY = geBitmap_Height(targetBitmap); + + hDIB = NULL; + lpDIBBuffer = NULL; + hPalette = NULL; + + pLogPal = (LOGPALETTE *) + GE_RAM_ALLOCATE_ARRAY (char, sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256)); + + assert(pLogPal); + + memset(pLogPal,0, sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256)); + + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = 256; + + pbmi = (BITMAPINFO *) + GE_RAM_ALLOCATE_ARRAY(char,sizeof (BITMAPINFOHEADER) + (sizeof (RGBQUAD) * 256)); + + if (pbmi == NULL) + { + geRam_Free(pLogPal); + assert(0); + } + + memset(pbmi, 0, sizeof (BITMAPINFOHEADER) + (sizeof (RGBQUAD) * 256)); + + pbmih = &(pbmi->bmiHeader); + + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biWidth = (targetSizeX); + pbmih->biHeight = -(targetSizeY); + pbmih->biPlanes = 1; + pbmih->biBitCount = (uint16) 8; + pbmih->biSizeImage = 0; + pbmih->biXPelsPerMeter = 0; + pbmih->biYPelsPerMeter = 0; + pbmih->biClrUsed = 0; + pbmih->biClrImportant = 0; + + pbmih->biCompression = BI_RGB; + + + // set palette entries + for (i = 0; i < 256; i++) + { + fcolorR = Color->r * i / 255; + fcolorG = Color->g * i / 255; + fcolorB = Color->b * i / 255; + + pbmi->bmiColors[i].rgbRed = (unsigned char) fcolorR; + pbmi->bmiColors[i].rgbGreen = (unsigned char) fcolorG; + pbmi->bmiColors[i].rgbBlue = (unsigned char) fcolorB; + + } + + hPalette = CreatePalette(pLogPal); + + // + // Allocate the DIB section ("back buffer") + // + + hdc = GetDC(GetDesktopWindow()); + + hDIB = CreateDIBSection(hdc, // Device context + pbmi, // BITMAPINFO structure + DIB_RGB_COLORS, // Color data type + (void **) &lpDIBBuffer, // Address of image map pointer + NULL, // File + 0); // Bitmap file offset + + ReleaseDC(GetDesktopWindow(), hdc); + + assert(hDIB); + + // now we DrawText to the DIB + + drawDC = CreateCompatibleDC(NULL); + + winFont = CreateFont( -1 * font->fontSize, + 0,0,0, font->fontWeight, + 0,0,0,0,OUT_TT_ONLY_PRECIS ,0,0,0, font->fontNameString); + assert(winFont); + + oldFont = SelectObject( drawDC, winFont); + oldMap = SelectObject( drawDC, hDIB); + + SetTextColor(drawDC, RGB(Color->r,Color->g,Color->b)); + SetBkColor (drawDC, RGB(0,0,0)); + + SetBkMode( drawDC, OPAQUE ); + + // we are accounting for the fact that Windows GDI stuff doesn't seem to draw on the end of a rect + box.bottom++; + box.right++; + + if (flags & GE_FONT_WORDWRAP) + DrawText(drawDC, textString, strlen(textString), &box, DT_WORDBREAK); + else + DrawText(drawDC, textString, strlen(textString), &box, 0); + + // undoing the for-windows hack + box.bottom--; + box.right--; + + SelectObject(drawDC,oldMap); + SelectObject(drawDC,oldFont); + + DeleteDC(drawDC); + + DeleteObject(winFont); + + + // now we copy the bits in the DIB to the targetBitmap + success = geBitmap_LockForWrite( targetBitmap, &lock, + 0,0); + + success = geBitmap_GetInfo(lock, &Info, &SecondaryInfo); + + if (!gePixelFormat_IsRaw(Info.Format)) + { + success = geBitmap_UnLock(lock); + + if (gePixelFormat_IsRaw(SecondaryInfo.Format)) + { + success = geBitmap_LockForWriteFormat( targetBitmap, &lock,0,0, SecondaryInfo.Format); + assert(success); + Info = SecondaryInfo; + } + else + { + success = geBitmap_SetFormat(targetBitmap, GE_PIXELFORMAT_24BIT_RGB, GE_TRUE, 0, NULL); + assert(success); + success = geBitmap_SetColorKey(targetBitmap, GE_TRUE, 0, GE_FALSE); + assert(success); + success = geBitmap_LockForWrite( targetBitmap, &lock,0,0); + assert(success); + success = geBitmap_GetInfo(lock, &Info, &SecondaryInfo); + assert(success); + } + + } + + mapWidth = Info.Stride; + + destBits = geBitmap_GetBits(lock); + + if (GE_PIXELFORMAT_8BIT == Info.Format) + { + locX = 0; + locY = 0; + + for ( y = box.top; + y <= box.bottom; + y++) + { + for (x = box.left; + x <= box.right; + x++) + { + tempChar = lpDIBBuffer[y * targetSizeX + x]; + destBits[(y+locY)*mapWidth + (x+locX)] = tempChar; + } + } + } + else + { + uint8 * bptr; + + // oh well, do our best + // bitmaps must have had a good reason to not give us the format we preferred, + + for(y=box.top; y <= box.bottom; y++) + { + for(x=box.left; x <= box.right; x++) + { + uint32 R,G,B; + + // put a color in any format + tempChar = lpDIBBuffer[y * targetSizeX + x]; + + R = (uint32)(Color->r * tempChar / 255); + G = (uint32)(Color->g * tempChar / 255); + B = (uint32)(Color->b * tempChar / 255); + + // we use alpha of 255 for opaque + + bptr = destBits + (Info.Stride * y * gePixelFormat_BytesPerPel(Info.Format)) + + gePixelFormat_BytesPerPel(Info.Format) * x; + gePixelFormat_PutColor(Info.Format,&bptr,R,G,B,255); + } + + } + } + + success = geBitmap_UnLock(lock); + + + // finally, clean up! + DeleteObject(hDIB); + DeleteObject(hPalette); + + + geRam_Free(pbmi); + geRam_Free(pLogPal); + + return TRUE; +} + + +//******************************************************************************* +GENESISAPI int32 GENESISCC geFont_GetStringPixelWidth (geFont *font, const char *textString) +{ + + if (font->bitmapList) + { + int32 i, width; + + width = 0; + for (i = 0; i < (int32)strlen(textString); i++) + { + assert (font->characterArray[textString[i]].bitmapUsed); + + width += font->characterArray[textString[i]].fullWidth; + } + + return width; + } + else + { + SIZE sizeInfo; + HDC hdc; + HFONT oldFont, winFont; + + hdc = GetDC(GetDesktopWindow()); + winFont = CreateFont( -1 * font->fontSize, + 0,0,0, font->fontWeight, + 0,0,0,0,OUT_TT_ONLY_PRECIS ,0,0,0, font->fontNameString); + assert(winFont); + + oldFont = SelectObject( hdc, winFont); + + GetTextExtentPoint32( hdc, textString, strlen(textString), &sizeInfo); + + SelectObject(hdc,oldFont); + DeleteObject(winFont); + + ReleaseDC(GetDesktopWindow(), hdc); + + return sizeInfo.cx; + } +} + +//******************************************************************************* +GENESISAPI int32 GENESISCC geFont_GetStringPixelHeight(geFont *font, const char *textString) +{ + + SIZE sizeInfo; + HDC hdc; + HFONT oldFont, winFont; + + hdc = GetDC(GetDesktopWindow()); + winFont = CreateFont( -1 * font->fontSize, + 0,0,0, font->fontWeight, + 0,0,0,0,OUT_TT_ONLY_PRECIS ,0,0,0, font->fontNameString); + assert(winFont); + + oldFont = SelectObject( hdc, winFont); + + GetTextExtentPoint32( hdc, textString, strlen(textString), &sizeInfo); + + SelectObject(hdc,oldFont); + DeleteObject(winFont); + + ReleaseDC(GetDesktopWindow(), hdc); + + return sizeInfo.cy; +} + +//******************************************************************************* +GENESISAPI geBitmap* GENESISCC geFont_GetBuffer(geFont *font) +{ + + return font->buffer; +} + + +//******************************************************************************* +GENESISAPI geBoolean GENESISCC geFont_GetCharMap(geFont *font, uint8 character, GE_Rect *Rect, + geBitmap **targetBitmap, int32 *fullWidth, int32 *fullHeight, + int32 *offsetX, int32 *offsetY) +{ + + + assert(font); + assert(font->characterArray[character].bitmapUsed); + + *targetBitmap = font->characterArray[character].bitmapUsed->map; + + *Rect = font->characterArray[character].bitmapRect; + + *fullWidth = font->characterArray[character].fullWidth; + *fullHeight = font->fontSize; + *offsetX = font->characterArray[character].offsetX; + *offsetY = font->characterArray[character].offsetY; + + return GE_TRUE; +} + + +//******************************************************************************* +GENESISAPI void GENESISCC geFont_EnableAntialiasing(geFont *font, const geBoolean anti) +{ + font->antialiased = anti; +} + +//******************************************************************************* +GENESISAPI geBoolean GENESISCC geFont_IsAntialiased(geFont *font) +{ + return font->antialiased; +} + diff --git a/G3D/Font/wgClip.H b/G3D/Font/wgClip.H new file mode 100644 index 0000000..44160c7 --- /dev/null +++ b/G3D/Font/wgClip.H @@ -0,0 +1,47 @@ +/****************************************************************************************/ +/* WGCLIP.H */ +/* */ +/* Author: Thom Robertson */ +/* Description: 2D rectangular clip testing support */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_CLIP_H +#define GE_CLIP_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#define GE_CLIP_CENTER 1 +#define GE_CLIP_CORNER 0 +#include "basetype.h" +#include "getypes.h" + +//*************************************************************** +// returns true if you need to draw at all. +GENESISAPI geBoolean GENESISCC CalculateClipping( + GE_Rect *artRect, int32 *resultX, int32 *resultY, + int32 x, int32 y, + const GE_Rect bounds, int32 type); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Font/wgClip.c b/G3D/Font/wgClip.c new file mode 100644 index 0000000..08209a3 --- /dev/null +++ b/G3D/Font/wgClip.c @@ -0,0 +1,118 @@ +/****************************************************************************************/ +/* WGCLIP.C */ +/* */ +/* Author: Thom Robertson */ +/* Description: 2D rectangular clip testing support */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define WIN32_LEAN_AND_MEAN +#pragma warning(disable : 4201 4214 4115) +#include +#include +#pragma warning(default : 4201 4214 4115) + +#include +#include + +#include "genesis.h" +#include "basetype.h" +#include "extbox.h" + +#include "wgClip.h" + +#pragma warning (disable:4514) // unreferenced inline function (caused by Windows) + +//*************************************************************** +// returns true if you need to draw at all. +GENESISAPI geBoolean GENESISCC CalculateClipping( + GE_Rect *artRect, int32 *resultX, int32 *resultY, + int32 x, int32 y, + const GE_Rect bounds, int32 type) +{ + + int32 localX, localY; + int32 shiftX, shiftY; + int32 baseX, baseY; + + assert(artRect); + assert(resultX); + assert(resultY); + + baseX = artRect->Left; + baseY = artRect->Top; + + // normalize the rect passed in. + artRect->Left = artRect->Left - baseX; + artRect->Right = artRect->Right - baseX; + artRect->Top = artRect->Top - baseY; + artRect->Bottom = artRect->Bottom - baseY; + + + localX = x; + localY = y; + + if (GE_CLIP_CENTER == type) + { + shiftX = artRect->Right / 2; + shiftY = artRect->Bottom / 2; + } + else + { + shiftX = 0; + shiftY = 0; + } + + if (artRect->Right + localX - shiftX > bounds.Right) + { + artRect->Right -= (artRect->Right + localX - shiftX) - bounds.Right; // push Right edge Leftward + } + + if (artRect->Bottom + localY - shiftY > bounds.Bottom) + { + artRect->Bottom -= (artRect->Bottom + localY - shiftY) - bounds.Bottom; // push Bottom edge Leftward + } + + if (artRect->Left + localX - shiftX < bounds.Left) + { + localX += bounds.Left - (artRect->Left + localX - shiftX); + artRect->Left += localX - x; // push Left edge Rightward + } + + if (artRect->Top + localY - shiftY < bounds.Top) + { + localY += bounds.Top - (artRect->Top + localY - shiftY); + artRect->Top += localY - y; + } + + if (artRect->Left >= artRect->Right) + return GE_FALSE; + if (artRect->Top >= artRect->Bottom) + return GE_FALSE; + + *resultX = localX - shiftX; + *resultY = localY - shiftY; + + // un-normalize the rect passed in. + artRect->Left = artRect->Left + baseX; + artRect->Right = artRect->Right + baseX; + artRect->Top = artRect->Top + baseY; + artRect->Bottom = artRect->Bottom + baseY; + + + return GE_TRUE; +} + diff --git a/G3D/Ge.c b/G3D/Ge.c new file mode 100644 index 0000000..d3f2ae4 --- /dev/null +++ b/G3D/Ge.c @@ -0,0 +1,368 @@ +/****************************************************************************************/ +/* GE.c */ +/* */ +/* Author: John Pollard */ +/* Description: Old interface to engine (REMOVE???) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include +#include +#include + +#include "Genesis.H" +#include "System.h" +#include "Ram.h" + +//#include "Sound.h" +//#include "Sound3d.h" + +#include "World.h" +#include "Surface.h" +//#include "Camera.h" +#include "Light.h" +#include "Plane.h" +#include "Entities.h" +#include "Trace.h" +#include "User.h" +//#include "Host.h" +#include "Motion.h" +#include "Vis.h" + +//===================================================================================== +// local static globals +//===================================================================================== +static geEngine *CEngine; // The current engine object +static char *geTag="Eclipse!"; + +//===================================================================================== +// local static function prototypes +//===================================================================================== +geBoolean geEngine_SetWorld(geEngine *Engine, geWorld *World); + +//===================================================================================== +// Engine +//===================================================================================== + +//===================================================================================== +// geEngine_CreateWithVersion +//===================================================================================== +GENESISAPI geEngine *geEngine_CreateWithVersion(HWND hWnd, const char *AppName, const char *DriverDirectory, uint32 Version) +{ + assert(AppName != NULL); + + // + // Initialize the engine level resources + // + return Sys_EngineCreate(hWnd, AppName, DriverDirectory, Version); +} + +//===================================================================================== +// geEngine_Free +//===================================================================================== +GENESISAPI void geEngine_Free(geEngine *Engine) +{ + Sys_EngineFree(Engine); +} + +//===================================================================================== +// geEngine_FillRect +//===================================================================================== +GENESISAPI void geEngine_FillRect(geEngine *Engine, const GE_Rect *Rect, const GE_RGBA *Color) +{ + User_EngineFillRect(Engine, Rect, Color); +} + +//===================================================================================== +// GE_ScreenShot +//===================================================================================== +GENESISAPI geBoolean geEngine_ScreenShot(geEngine *Engine, const char *FileName) +{ + assert(Engine); + + return Engine->DriverInfo.RDriver->ScreenShot(FileName); +} + +//===================================================================================== +// geEngine_EnabledFrameRateCounter +//===================================================================================== +GENESISAPI void geEngine_EnableFrameRateCounter(geEngine *Engine, geBoolean Enabled) +{ + assert(Engine); + Engine->DisplayFrameRateCounter = Enabled; +} + +//===================================================================================== +// Sound +//===================================================================================== +//======================================================================================== +// Camera +//======================================================================================== + +#ifdef MESHES +//======================================================================================== +// geWorld_CreateMesh +// Create a mesh definition object +//======================================================================================== +GENESISAPI geMesh_Def *geWorld_CreateMesh(geWorld *World, const char *BitmapPath, const char *FileName) +{ + assert(World != NULL); + assert(FileName != NULL); + + return (geMesh_Def*)Sys_WorldCreateMesh(World, BitmapPath, FileName); +} + +//======================================================================================== +// geWorld_FreeMesh +//======================================================================================== +GENESISAPI void geWorld_FreeMesh(geWorld *World, geMesh_Def *MeshDef) +{ + assert(World != NULL); + assert(MeshDef != NULL); + + Sys_WorldFreeMesh(World,(Mesh_MeshDef*)MeshDef); +} + +//======================================================================================== +// geWorld_AddMesh +//======================================================================================== +GENESISAPI geMesh *geWorld_AddMesh(geWorld *World, geMesh_Def *MeshDef, uint32 Flags, uint32 UserFlags) +{ + return (geMesh*)Mesh_WorldAddMesh(World,(Mesh_MeshDef*)MeshDef, Flags, UserFlags); +} + +//======================================================================================== +// geWorld_RemoveMesh +//======================================================================================== +GENESISAPI void geWorld_RemoveMesh(geWorld *World, geMesh *Mesh) +{ + assert(World != NULL); + assert(Mesh!= NULL); + + Mesh_WorldRemoveMesh(World, (Mesh_RenderQ*)Mesh); +} + +//======================================================================================== +// geWorld_SetMeshXForm +//======================================================================================== +GENESISAPI geBoolean geWorld_SetMeshXForm(geWorld *World, geMesh *Mesh, const geXForm3d *XForm) +{ + assert(World != NULL); + assert(Mesh!= NULL); + assert(XForm != NULL); + + return Mesh_SetMeshXForm((Mesh_RenderQ*)Mesh, XForm); +} + +//======================================================================================== +// geWorld_SetMeshFrame +//======================================================================================== +GENESISAPI geBoolean geWorld_SetMeshFrame(geWorld *World, geMesh *Mesh, int32 Frame) +{ + assert(World != NULL); + assert(Mesh!= NULL); + + return Mesh_SetMeshFrame((Mesh_RenderQ*)Mesh, Frame); +} + +//======================================================================================== +// geWorld_GetMeshBox +//======================================================================================== +GENESISAPI geBoolean geWorld_GetMeshBox(geWorld *World, geMesh_Def *MeshDef, geVec3d *Mins, geVec3d *Maxs) +{ + assert (World != NULL); + assert (MeshDef != NULL); + assert (Mins != NULL); + assert (Maxs != NULL); + return Mesh_MeshGetBox(World,(Mesh_MeshDef*)MeshDef, Mins, Maxs); +} + +//======================================================================================== +// geWorld_GetMeshFrameCount +//======================================================================================== +GENESISAPI int geWorld_GetMeshFrameCount(const geWorld *World, const geMesh *Mesh) +{ + Mesh_RenderQ * mesh; + + mesh = (Mesh_RenderQ *)Mesh; + assert(mesh); + assert(mesh->MeshDef); + return (int)mesh->MeshDef->NumFrames; +} +#endif + +#if 0 +//======================================================================================== +// geWorld_SetModelXForm +//======================================================================================== +GENESISAPI geBoolean geWorld_SetModelXForm(geWorld *World, geWorld_Model *Model, const geXForm3d *XForm) +{ + return World_SetModelXForm(World, Model, XForm); +} + +GENESISAPI geBoolean geWorld_ModelMotionGetTimeExtents( + const GE_ModelMotion * M, + GE_TimeType * StartTime, + GE_TimeType * EndTime) +{ + return geMotion_GetTimeExtents((const geMotion *)M, StartTime, EndTime); +} + +GENESISAPI GE_ModelMotion *geWorld_ModelGetMotion(geWorld_Model *Model) +{ + return (GE_ModelMotion *)World_ModelGetMotion(Model); +} + +GENESISAPI void geWorld_ModelMotionSample( + GE_ModelMotion * M, + GE_TimeType Time, + geXForm3d * XForm) +{ + gePath * P; + + P = geMotion_GetPath((const geMotion *)M, 0); + assert(P); + gePath_Sample(P, Time, XForm); +} + +GENESISAPI void * geWorld_ModelGetUserData(const geWorld_Model *Model) +{ + return World_ModelGetUserData(Model); +} + +GENESISAPI void geWorld_ModelSetUserData(geWorld_Model *Model, void *UserData) +{ + World_ModelSetUserData(Model, UserData); +} +#endif + +//======================================================================================== +// geWorld_AddLight +//======================================================================================== +GENESISAPI geLight *geWorld_AddLight(geWorld *World) +{ + assert(World != NULL); + + return (geLight*)Light_WorldAddLight(World); +} + +//======================================================================================== +// geWorld_RemoveLight +//======================================================================================== +GENESISAPI void geWorld_RemoveLight(geWorld *World, geLight *Light) +{ + assert(World != NULL); + assert(Light != NULL); + + Light_WorldRemoveLight(World, (Light_DLight*)Light); +} + +//======================================================================================== +// geWorld_SetLightAttributes +//======================================================================================== +GENESISAPI geBoolean geWorld_SetLightAttributes( geWorld *World, + geLight *Light, + const geVec3d *Pos, + const GE_RGBA *RGBA, + geFloat Radius, + geBoolean CastShadow) +{ + assert(World != NULL); + assert(Light != NULL); + assert(Pos != NULL); + assert(RGBA != NULL); + + return Light_SetAttributes((Light_DLight*)Light, Pos, RGBA, Radius, CastShadow); +} + +//======================================================================================== +// geWorld_SetLTypeTable +//======================================================================================== +GENESISAPI geBoolean geWorld_SetLTypeTable(geWorld *World, int32 LType, const char *Table) +{ + assert(World != NULL); + assert(Table != NULL); + + return Light_WorldSetLTypeTable(World, LType, Table); +} + +//======================================================================================== +// geWorld_TestModelMove +//======================================================================================== +GENESISAPI geBoolean geWorld_TestModelMove( geWorld *World, + geWorld_Model *Model, + const geXForm3d *DXForm, + const geVec3d *Mins, const geVec3d *Maxs, + const geVec3d *In, geVec3d *Out) +{ + return Trace_TestModelMove( World, Model, DXForm, + Mins, Maxs, + In, Out); +} + +//======================================================================================== +// geWorld_ModelCollision +//======================================================================================== +GENESISAPI geBoolean geWorld_ModelCollision(geWorld *World, + geWorld_Model *Model, + const geXForm3d *DXForm, + GE_Collision *Collision) +{ + Collision->Mesh = NULL; + Collision->Actor = NULL; + Collision->Model = NULL; + return Trace_ModelCollision(World, + Model, + DXForm, + Collision, + //&(Mesh_RenderQ *)Collision->Mesh, + &Collision->Impact); +} + +//======================================================================================== +// geWorld_Collision +//======================================================================================== + +GENESISAPI geBoolean geWorld_Collision(geWorld *World, const geVec3d *Mins, const geVec3d *Maxs, const geVec3d *Front, const geVec3d *Back, uint32 Contents, uint32 CollideFlags, uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, GE_Collision *Col) +{ + return Trace_GEWorldCollision(World, Mins, Maxs, Front, Back, Contents, CollideFlags, UserFlags, CollisionCB, Context, Col); +} + +//======================================================================================== +// geWorld_GetContents +//======================================================================================== +GENESISAPI geBoolean geWorld_GetContents(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, uint32 Flags, uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, GE_Contents *Contents) +{ + return Trace_GetContents(World, Pos, Mins, Maxs, Flags, UserFlags, CollisionCB, Context, Contents); +} + +// changed texture name + +//======================================================================================== +// geWorld_GetContents +//======================================================================================== +GENESISAPI geBoolean geWorld_GetTextureName(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, char *TexName) +{ + return Trace_GetTexureName(World, Pos, Mins, Maxs, TexName); +} +// end change texture name + +//======================================================================================== +// NetPlay +//======================================================================================== + + diff --git a/G3D/Genesis.aps b/G3D/Genesis.aps new file mode 100644 index 0000000000000000000000000000000000000000..830c2c7a482e6f5d30f8c825e7ef20222241ee37 GIT binary patch literal 17656 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 TIcDuO93K1Mgf_>FeZ%=5I1*u4 literal 0 HcmV?d00001 diff --git a/G3D/Genesis.dsp b/G3D/Genesis.dsp new file mode 100644 index 0000000..25b0ac6 --- /dev/null +++ b/G3D/Genesis.dsp @@ -0,0 +1,790 @@ +# Microsoft Developer Studio Project File - Name="Genesis" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=Genesis - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Genesis.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Genesis.mak" CFG="Genesis - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Genesis - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "Genesis - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Source", MPPBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Genesis - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W3 /GX /Ot /Ow /Og /Oi /Op /Ob2 /I "..\G3D" /I "World" /I "Engine" /I "Engine\Drivers" /I "Actor" /I "BSP" /I "Math" /I "Entities" /I "Support" /I "Physics" /I "VFile" /I "Bitmap" /I "Bitmap\Compression" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Fd"Release/genesis.pdb" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +# SUBTRACT RSC /x +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "Genesis - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /I "..\G3D" /I "World" /I "Engine" /I "Engine\Drivers" /I "Actor" /I "BSP" /I "Math" /I "Entities" /I "Support" /I "Physics" /I "VFile" /I "Bitmap" /I "Bitmap\Compression" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /Fd"Debug/genesis.pdb" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +# SUBTRACT RSC /x +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# SUBTRACT BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug\GenesisD.lib" + +!ENDIF + +# Begin Target + +# Name "Genesis - Win32 Release" +# Name "Genesis - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "World" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\World\Fog.c +# End Source File +# Begin Source File + +SOURCE=.\World\Fog.h +# End Source File +# Begin Source File + +SOURCE=.\World\Frustum.c +# End Source File +# Begin Source File + +SOURCE=.\World\Frustum.h +# End Source File +# Begin Source File + +SOURCE=.\World\Gbspfile.c +# End Source File +# Begin Source File + +SOURCE=.\World\Gbspfile.h +# End Source File +# Begin Source File + +SOURCE=.\World\Light.c +# End Source File +# Begin Source File + +SOURCE=.\World\Light.h +# End Source File +# Begin Source File + +SOURCE=.\World\Plane.c +# End Source File +# Begin Source File + +SOURCE=.\World\Plane.h +# End Source File +# Begin Source File + +SOURCE=.\World\Surface.c +# End Source File +# Begin Source File + +SOURCE=.\World\Surface.h +# End Source File +# Begin Source File + +SOURCE=.\World\Trace.c +# End Source File +# Begin Source File + +SOURCE=.\World\Trace.h +# End Source File +# Begin Source File + +SOURCE=.\World\User.c +# End Source File +# Begin Source File + +SOURCE=.\World\User.h +# End Source File +# Begin Source File + +SOURCE=.\World\Vis.c +# End Source File +# Begin Source File + +SOURCE=.\World\Vis.h +# End Source File +# Begin Source File + +SOURCE=.\World\WBitmap.c +# End Source File +# Begin Source File + +SOURCE=.\World\WBitmap.h +# End Source File +# Begin Source File + +SOURCE=.\World\World.c +# End Source File +# Begin Source File + +SOURCE=.\World\World.h +# End Source File +# End Group +# Begin Group "Engine" + +# PROP Default_Filter "" +# Begin Group "Logo" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Engine\Logo\A_CORONA.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\A_STREAK.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\CORONA.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\electric.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\electric.h +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\logo.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\LogoActor.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\streak.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\WebUrl.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Engine\BitmapList.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\BitmapList.h +# End Source File +# Begin Source File + +SOURCE=.\Engine\engine.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\engine.h +# End Source File +# Begin Source File + +SOURCE=.\Engine\fontbmp.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\System.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\System.h +# End Source File +# End Group +# Begin Group "Actor" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Actor\actor.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\actor.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\body.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\body.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\bodyinst.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\bodyinst.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\motion.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\motion.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\path.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\path.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\pose.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\pose.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\puppet.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\puppet.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\QKFrame.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\QKFrame.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\strblock.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\strblock.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\tkarray.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\tkarray.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\tkevents.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\tkevents.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\vkframe.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\vkframe.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\XFArray.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\xfarray.h +# End Source File +# End Group +# Begin Group "BSP" + +# PROP Default_Filter "" +# End Group +# Begin Group "Math" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Math\Box.c +# End Source File +# Begin Source File + +SOURCE=.\Math\Box.h +# End Source File +# Begin Source File + +SOURCE=.\Math\crc32.c +# End Source File +# Begin Source File + +SOURCE=.\Math\crc32.h +# End Source File +# Begin Source File + +SOURCE=.\Math\ExtBox.c +# End Source File +# Begin Source File + +SOURCE=.\Math\ExtBox.h +# End Source File +# Begin Source File + +SOURCE=.\Math\quatern.c +# End Source File +# Begin Source File + +SOURCE=.\Math\quatern.h +# End Source File +# Begin Source File + +SOURCE=.\Math\Vec3d.c +# End Source File +# Begin Source File + +SOURCE=.\Math\Vec3d.h +# End Source File +# Begin Source File + +SOURCE=.\Math\Xform3d.c +# End Source File +# Begin Source File + +SOURCE=.\Math\Xform3d.h +# End Source File +# End Group +# Begin Group "Entities" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Entities\Entities.c +# End Source File +# Begin Source File + +SOURCE=.\Entities\Entities.h +# End Source File +# End Group +# Begin Group "Support" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Support\Basetype.h +# End Source File +# Begin Source File + +SOURCE=.\Support\Errorlog.c +# End Source File +# Begin Source File + +SOURCE=.\Support\Errorlog.h +# End Source File +# Begin Source File + +SOURCE=.\Support\geAssert.c +# End Source File +# Begin Source File + +SOURCE=.\Support\geAssert.h +# End Source File +# Begin Source File + +SOURCE=.\Support\log.c +# End Source File +# Begin Source File + +SOURCE=.\Support\log.h +# End Source File +# Begin Source File + +SOURCE=.\Support\mempool.c +# End Source File +# Begin Source File + +SOURCE=.\Support\mempool.h +# End Source File +# Begin Source File + +SOURCE=.\Support\Ram.c +# End Source File +# Begin Source File + +SOURCE=.\Support\Ram.h +# End Source File +# Begin Source File + +SOURCE=.\Support\ramdll.c +# End Source File +# End Group +# Begin Group "Physics" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Physics\matrix33.c +# End Source File +# Begin Source File + +SOURCE=.\Physics\matrix33.h +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsJoint.c +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsJoint.h +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsObject.c +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsObject.h +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsSystem.c +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsSystem.h +# End Source File +# End Group +# Begin Group "VFile" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=".\VFile\dirtree-common.c" +# End Source File +# Begin Source File + +SOURCE=".\VFile\dirtree-common.h" +# End Source File +# Begin Source File + +SOURCE=.\VFile\dirtree.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\dirtree.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\fsdos.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\fsdos.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\Fsmemory.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\Fsmemory.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\fsvfs.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\fsvfs.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\vfile._h +# End Source File +# Begin Source File + +SOURCE=.\VFile\vfile.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\vfile.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\vfile_structs.h +# End Source File +# End Group +# Begin Group "Bitmap" + +# PROP Default_Filter "" +# Begin Group "Compression" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Bitmap\Compression\palcreate.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\palcreate.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\palettize.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\palettize.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\paloptimize.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\paloptimize.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\utility.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\yuv.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\yuv.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Bitmap\bitmap.__h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap._h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap_blitdata.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap_blitdata.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap_gamma.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap_gamma.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\pixelformat.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\pixelformat.h +# End Source File +# End Group +# Begin Group "Font" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Font\font.c +# End Source File +# Begin Source File + +SOURCE=.\Font\font.H +# End Source File +# Begin Source File + +SOURCE=.\Font\wgClip.c +# End Source File +# Begin Source File + +SOURCE=.\Font\wgClip.H +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Camera.c +# End Source File +# Begin Source File + +SOURCE=.\Camera.h +# End Source File +# Begin Source File + +SOURCE=.\CSNetMgr.c +# End Source File +# Begin Source File + +SOURCE=.\Ge.c +# End Source File +# Begin Source File + +SOURCE=.\Genesis.h +# End Source File +# Begin Source File + +SOURCE=.\genesis.rc +# End Source File +# Begin Source File + +SOURCE=.\getypes.h +# End Source File +# Begin Source File + +SOURCE=.\list.c +# End Source File +# Begin Source File + +SOURCE=.\list.h +# End Source File +# Begin Source File + +SOURCE=.\Netplay.c +# End Source File +# Begin Source File + +SOURCE=.\Ptrtypes.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\Sound.c +# End Source File +# Begin Source File + +SOURCE=.\Sound.h +# End Source File +# Begin Source File + +SOURCE=.\Sound3d.c +# End Source File +# Begin Source File + +SOURCE=.\Sound3d.h +# End Source File +# Begin Source File + +SOURCE=.\sprite.c +# End Source File +# Begin Source File + +SOURCE=.\sprite.h +# End Source File +# Begin Source File + +SOURCE=.\Tclip.c +# End Source File +# Begin Source File + +SOURCE=.\tclip.h +# End Source File +# Begin Source File + +SOURCE=.\timer.c +# End Source File +# Begin Source File + +SOURCE=.\timer.h +# End Source File +# Begin Source File + +SOURCE=.\tsc.c +# End Source File +# Begin Source File + +SOURCE=.\tsc.h +# End Source File +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# End Group +# Begin Source File + +SOURCE=.\CSNetMgr.h +# End Source File +# Begin Source File + +SOURCE=.\Netplay.h +# End Source File +# End Target +# End Project diff --git a/G3D/Genesis.dsw b/G3D/Genesis.dsw new file mode 100644 index 0000000..ff276bd --- /dev/null +++ b/G3D/Genesis.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Genesis"=.\Genesis.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/G3D/Genesis.h b/G3D/Genesis.h new file mode 100644 index 0000000..da645a9 --- /dev/null +++ b/G3D/Genesis.h @@ -0,0 +1,664 @@ +/****************************************************************************************/ +/* Genesis.h */ +/* */ +/* Description: The master header for Genesis */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GENESIS_H +#define GENESIS_H + +#include "BaseType.h" +#include "Vec3d.h" +#include "XForm3d.h" +#include "GETypes.h" +#include "ExtBox.h" +#include "vfile.h" +#include "Bitmap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//================================================================================ +// Constants / Defines / TypDefs +//================================================================================ + +typedef struct geEngine geEngine; + +typedef struct geDriver_System geDriver_System; +typedef struct geDriver geDriver; +typedef struct geDriver_Mode geDriver_Mode; + +typedef struct geSound_System geSound_System; +typedef struct geSound_Cfg geSound_Cfg; +typedef struct geSound_Def geSound_Def; +typedef struct geSound geSound; + +typedef struct geActor geActor; +typedef struct geActor_Def geActor_Def; // the definition of an actor's geometry/bone structure + +typedef struct geWorld geWorld; + +typedef struct geWorld_Model geWorld_Model; + +typedef struct geEntity geEntity; +typedef struct geEntity_EntitySet geEntity_EntitySet; + +typedef struct geCamera geCamera; + +typedef struct geCSNetMgr geCSNetMgr; + +typedef struct gePoly gePoly; + +typedef struct geLight geLight; + +typedef struct geFog geFog; + +typedef struct geMesh_Def geMesh_Def; // Mesh def +typedef struct geMesh geMesh; + +#define GE_VERSION_MAJOR (1UL) +#define GE_VERSION_MINOR (3UL) +#define GE_VERSION_MINOR_MIN (3UL) + +#define GE_VERSION_MAJOR_SHIFT (16) +#define GE_VERSION_MAJOR_MASK ((uint32)0xFFFF0000) + +#define GE_VERSION ( (GE_VERSION_MAJOR << GE_VERSION_MAJOR_SHIFT) + GE_VERSION_MINOR ) + +// From here down, still needs to be fixed up for July4 +typedef struct GE_ModelMotion GE_ModelMotion; +typedef float GE_TimeType; + +// Polys +typedef enum +{ + GE_TEXTURED_POLY, + GE_GOURAUD_POLY, + GE_TEXTURED_POINT +} gePoly_Type; + +// Poly Fx flags +#define GE_RENDER_DO_NOT_OCCLUDE_OTHERS (1<<0) // Poly will not occlude others +#define GE_RENDER_DO_NOT_OCCLUDE_SELF (1<<1) // Renders under any condition. Useful for halos, etc... +#define GE_RENDER_BACKFACED (1<<2) // Poly should be backfaced from the Camera's Pov +#define GE_RENDER_DEPTH_SORT_BF (1<<3) // Sorts relative to camera position, from back to front +#define GE_RENDER_CLAMP_UV (1<<4) // Clamp UV's in both directions +#define GE_RENDER_NO_FOG (1<<5) +#define GE_RENDER_NO_CLIP (1<<6) + +// World Add flags +#define GE_WORLD_RENDER (1<<0) +#define GE_WORLD_COLLIDE (1<<1) + + + +#ifndef GE_CONTENTS_TYPES +#define GE_CONTENTS_TYPES + +// +// Content types in GE_Contents structure (multiple contents can be mixed...) +// +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= +// IF THESE FLAGS CHANGE, THEY MUST CHANGE IN GBSPFILE.H in Genesis AND GBSPLIB, and Genesis.H!!!!! +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= +#define GE_CONTENTS_SOLID (1<<0) // Solid (Visible) +#define GE_CONTENTS_WINDOW (1<<1) // Window (Visible) +#define GE_CONTENTS_EMPTY (1<<2) // Empty but Visible (water, lava, etc...) + +#define GE_CONTENTS_TRANSLUCENT (1<<3) // Vis will see through it +#define GE_CONTENTS_WAVY (1<<4) // Wavy (Visible) +#define GE_CONTENTS_DETAIL (1<<5) // Won't be included in vis oclusion + +#define GE_CONTENTS_CLIP (1<<6) // Structural but not visible +#define GE_CONTENTS_HINT (1<<7) // Primary splitter (Non-Visible) +#define GE_CONTENTS_AREA (1<<8) // Area seperator leaf (Non-Visible) + +#define GE_CONTENTS_FLOCKING (1<<9) +#define GE_CONTENTS_SHEET (1<<10) +#define GE_CONTENTS_AIR (1<<11) // No brush lives in this leaf +#define GE_RESERVED4 (1<<12) +#define GE_RESERVED5 (1<<13) +#define GE_RESERVED6 (1<<14) +#define GE_RESERVED7 (1<<15) + +// 16-31 reserved for user contents +#define GE_CONTENTS_USER1 (1<<16) +#define GE_CONTENTS_USER2 (1<<17) +#define GE_CONTENTS_USER3 (1<<18) +#define GE_CONTENTS_USER4 (1<<19) +#define GE_CONTENTS_USER5 (1<<20) +#define GE_CONTENTS_USER6 (1<<21) +#define GE_CONTENTS_USER7 (1<<22) +#define GE_CONTENTS_USER8 (1<<23) +#define GE_CONTENTS_USER9 (1<<24) +#define GE_CONTENTS_USER10 (1<<25) +#define GE_CONTENTS_USER11 (1<<26) +#define GE_CONTENTS_USER12 (1<<27) +#define GE_CONTENTS_USER13 (1<<28) +#define GE_CONTENTS_USER14 (1<<29) +#define GE_CONTENTS_USER15 (1<<30) +#define GE_CONTENTS_USER16 (1<<31) +// 16-31 reserved for user contents + + +// These contents are all solid types +#define GE_CONTENTS_SOLID_CLIP (GE_CONTENTS_SOLID | GE_CONTENTS_WINDOW | GE_CONTENTS_CLIP) +#define GE_CONTENTS_CANNOT_OCCUPY GE_CONTENTS_SOLID_CLIP + +// These contents are all visible types +#define GE_VISIBLE_CONTENTS ( GE_CONTENTS_SOLID | \ + GE_CONTENTS_EMPTY | \ + GE_CONTENTS_WINDOW | \ + GE_CONTENTS_WAVY) + +#endif +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + +// NOTES - Fills in first Model/Mesh hit +// Exceptions: +// Returns the last solid model hit... +typedef struct +{ + geMesh *Mesh; + geWorld_Model *Model; + geActor *Actor; + int32 Contents; +} GE_Contents; + +typedef geBoolean GE_CollisionCB(geWorld_Model *Model, geActor *Actor, void *Context); + +// Collision +typedef struct +{ + geVec3d Normal; // Orientation of plane + geFloat Dist; // Distance from origin +} GE_Plane; + +typedef struct +{ + geWorld_Model *Model; // Pointer to what model was hit (if any) + geMesh *Mesh; // Pointer to what mesh was hit (if any) + geActor *Actor; // Pointer to what actor was hit (if any) + geVec3d Impact; // Impact Point + geFloat Ratio; // Percent from 0 to 1.0, how far along the line for the impact point + GE_Plane Plane; // Impact Plane +} GE_Collision; + +// If these render states change, they must change in DCommon.h too!!! +// These are still under construction, and are for debug purposes only. +// They are merely means of overriding ways the engine normally renders primitives, etc... +// +// RenderState States +// +#define GE_RENDERSTATE_ZWRITE 0 // Z Writes +#define GE_RENDERSTATE_ZCMP 1 // Z Compares +#define GE_RENDERSTATE_BILINEAR 2 // Bilinear filtering +#define GE_RENDERSTATE_ANTI_ALIAS 3 // Anti-Aliasing +#define GE_RENDERSTATE_POLYMODE 4 // Normal, Gouraud only, Lines only, etc + +// +// RenderState Flags +// +#define GE_RENDERFLAG_OFF 0 +#define GE_RENDERFLAG_ON 1 + +// +// PolyMode flags (A method to override how polys are drawn for debugging purposes...) +// +#define GE_POLYMODE_NORMAL 1 // Draw as is +#define GE_POLYMODE_GOURAUD 2 // Gouraud only +#define GE_POLYMODE_LINES 3 // Outlines only + +//================================================================================ +// Engine Management functions +//================================================================================ + + +#ifdef _INC_WINDOWS + // Windows.h must be included before genesis.h for this api to be exposed. + + +GENESISAPI geEngine *geEngine_CreateWithVersion(HWND hWnd, const char *AppName, const char *DriverDirectory, uint32 Version); + // use geEngine_Create, rather than calling this directly. + +#define geEngine_Create( hWnd, AppName, DriverDirectory) geEngine_CreateWithVersion(hWnd,AppName,DriverDirectory,GE_VERSION) + +#endif + +GENESISAPI void geEngine_Free(geEngine *Engine); + +GENESISAPI geBoolean geEngine_AddWorld(geEngine *Engine, geWorld *World); +GENESISAPI geBoolean geEngine_RemoveWorld(geEngine *Engine, geWorld *World); + +GENESISAPI geBoolean geEngine_AddBitmap(geEngine *Engine, geBitmap *Bitmap); +GENESISAPI geBoolean geEngine_RemoveBitmap(geEngine *Engine, geBitmap *Bitmap); + +GENESISAPI geDriver_System *geEngine_GetDriverSystem(geEngine *Engine); + +GENESISAPI geBoolean geEngine_SetDriverAndMode( geEngine *Engine, + geDriver *Driver, + geDriver_Mode *DriverMode); + +GENESISAPI geBoolean geEngine_ShutdownDriver(geEngine *Engine); + +GENESISAPI geBoolean geEngine_BeginFrame(geEngine *Engine, geCamera *Camera, geBoolean ClearScreen); +GENESISAPI geBoolean geEngine_EndFrame(geEngine *Engine); + +GENESISAPI geBoolean geEngine_RenderWorld(geEngine *Engine, geWorld *World, geCamera *Camera, geFloat Time); +GENESISAPI geBoolean geEngine_Printf(geEngine *Engine, int32 x, int32 y, const char *String, ...); + +GENESISAPI void GENESISCC geEngine_RenderPoly(const geEngine *Engine, const GE_TLVertex *Points, int NumPoints, const geBitmap *Texture, uint32 Flags); + //RenderPoly : if Texture is null, we Gouraud shade + +GENESISAPI void GENESISCC geEngine_RenderPolyArray(const geEngine *Engine, const GE_TLVertex ** pPoints, int * pNumPoints, int NumPolys, + const geBitmap *Texture, uint32 Flags); + +GENESISAPI geBoolean GENESISCC geEngine_DrawAlphaBitmap( + geEngine * Engine, + geBitmap * pBitmap, + geVec3d * VertUVArray, + geCamera * ClipCamera, // if null, uses full screen + GE_Rect * PixelRect, // pixels in the "camera" view + GE_Rect * PercentRect, // percent of the "camera" view + geFloat Alpha, + GE_RGBA * RGBA_Array + ); + +GENESISAPI geBoolean GENESISCC geEngine_DrawBitmap(const geEngine *Engine,const geBitmap *Bitmap, + const geRect * Source, uint32 x, uint32 y); + //DrawBitmap & RenderPoly : must Engine_AddBitmap first! + + +GENESISAPI void geEngine_FillRect(geEngine *Engine, const GE_Rect *Rect, const GE_RGBA *Color); + +GENESISAPI geBoolean geEngine_SetGamma(geEngine *Engine, geFloat Gamma); +GENESISAPI geBoolean geEngine_GetGamma(geEngine *Engine, geFloat *Gamma); + +GENESISAPI geBoolean geEngine_SetFogEnable(geEngine *Engine, geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End); + // enables/disables distance fogging. (based on Enable) + // r,g,b is the color of the fog + // Start is how far out from the camera is not fogged - this is where the fog begins + // End is how far out from the camera where the fog fully obscures things + + +GENESISAPI geBoolean geEngine_ScreenShot(geEngine *Engine, const char *FileName); + +GENESISAPI void geEngine_EnableFrameRateCounter(geEngine *Engine, geBoolean Enabled); + +GENESISAPI geBoolean geEngine_Activate(geEngine *Engine, geBoolean bActive); + +#ifdef _INC_WINDOWS + // Windows.h must be included before genesis.h for this api to be exposed. +GENESISAPI geBoolean geEngine_UpdateWindow(geEngine *Engine); +#endif + +// geDriver +GENESISAPI geDriver *geDriver_SystemGetNextDriver(geDriver_System *DriverSystem, geDriver *Start); +GENESISAPI geDriver_Mode *geDriver_GetNextMode(geDriver *Driver, geDriver_Mode *Start); +GENESISAPI geBoolean geDriver_GetName(geDriver *Driver, const char **Name); +GENESISAPI geBoolean geDriver_ModeGetName(geDriver_Mode *Mode, const char **Name); +GENESISAPI geBoolean geDriver_ModeGetWidthHeight(geDriver_Mode *Mode, int32 *Width, int32 *Height); + +//================================================================================ +// Sound Management functions +//================================================================================ +#ifdef _INC_WINDOWS + // Windows.h must be included before genesis.h for this api to be exposed. +GENESISAPI geSound_System *geSound_CreateSoundSystem(HWND hWnd); +#endif + + +GENESISAPI void geSound_DestroySoundSystem(geSound_System *Sound); + + +GENESISAPI geSound_Def *geSound_LoadSoundDef(geSound_System *SoundS, geVFile *File); +GENESISAPI void geSound_FreeSoundDef(geSound_System *SoundS, geSound_Def *SoundDef); + +GENESISAPI geSound *geSound_PlaySoundDef(geSound_System *SoundS, + geSound_Def *SoundDef, + geFloat Volume, + geFloat Pan, + geFloat Frequency, + geBoolean Loop); +GENESISAPI geBoolean geSound_StopSound(geSound_System *SoundS, geSound *Sound); +GENESISAPI geBoolean geSound_ModifySound(geSound_System *SoundS, + geSound *Sound, + geFloat Volume, + geFloat Pan, + geFloat Frequency); +GENESISAPI geBoolean geSound_SoundIsPlaying(geSound_System *SoundS, geSound *Sound); +GENESISAPI geBoolean geSound_SetMasterVolume( geSound_System *SoundS, geFloat Volume ); + +GENESISAPI void geSound3D_GetConfig( + const geWorld *World, + const geXForm3d *CameraTransform, + const geVec3d *SoundPos, + geFloat Min, + geFloat Ds, + geFloat *Volume, + geFloat *Pan, + geFloat *Frequency); + +GENESISAPI void geSound3D_GetConfigIgnoreObstructions( + const geWorld *World, + const geXForm3d *MXForm, + const geVec3d *SndPos, + geFloat Min, + geFloat Ds, + geFloat *Volume, + geFloat *Pan, + geFloat *Frequency); + +// Added 11/08/1999 Ed Averill API call to return DSOUND object +GENESISAPI void *geSound_GetDSound(void); +// End 11/08/1999 modification + +//================================================================================ +// Path Support +//================================================================================ +#include "Path.h" +//================================================================================ +// Motion Support +//================================================================================ +#include "Motion.h" +//================================================================================ +// Actor Support +//================================================================================ +#include "Actor.h" + +//MRB BEGIN +//geSprite +//================================================================================ +// Sprite Support +//================================================================================ +#include "Sprite.h" +//MRB END + + +//================================================================================ +// World Management functions +//================================================================================ +GENESISAPI geWorld *geWorld_Create(geVFile *File); +GENESISAPI void geWorld_Free(geWorld *World); + +// World Actors +GENESISAPI geBoolean geWorld_RemoveActor (geWorld *World, geActor *Actor); +GENESISAPI geBoolean geWorld_AddActor (geWorld *World, geActor *Actor, uint32 Flags, uint32 UserFlags); +GENESISAPI geBoolean geWorld_SetActorFlags (geWorld *World, geActor *Actor, uint32 Flags); + +//MRB BEGIN +//geSprite +GENESISAPI geBoolean geWorld_RemoveSprite (geWorld *World, geSprite *Sprite); +GENESISAPI geBoolean geWorld_AddSprite (geWorld *World, geSprite *Sprite, uint32 Flags, uint32 UserFlags); +GENESISAPI geBoolean geWorld_SetSpriteFlags (geWorld *World, geSprite *Sprite, uint32 Flags); +//MRB END + +// World Bitmaps +GENESISAPI geBoolean geWorld_AddBitmap( geWorld *World, geBitmap *Bitmap); +GENESISAPI geBoolean geWorld_RemoveBitmap( geWorld *World, geBitmap *Bitmap); +GENESISAPI geBoolean geWorld_HasBitmap(const geWorld *World, const geBitmap *Bitmap); +GENESISAPI geBitmap *geWorld_GetBitmapByName(geWorld *World, const char *BitmapName); +GENESISAPI geBoolean geWorld_BitmapIsVisible(geWorld *World, const geBitmap *Bitmap); + +// World BModels +GENESISAPI geWorld_Model *geWorld_GetNextModel(geWorld *World, geWorld_Model *Start); +GENESISAPI geBoolean geWorld_SetModelXForm(geWorld *World, geWorld_Model *Model, const geXForm3d *XForm); +GENESISAPI geBoolean geWorld_GetModelXForm(const geWorld *World, const geWorld_Model *Model, geXForm3d *XForm); +GENESISAPI geBoolean geWorld_OpenModel(geWorld *World, geWorld_Model *Model, geBoolean Open); +GENESISAPI geBoolean geWorld_GetModelRotationalCenter(const geWorld *World, const geWorld_Model *Model, geVec3d *Center); +GENESISAPI geBoolean geWorld_ModelGetBBox(const geWorld *World, const geWorld_Model *Model, geVec3d *Mins, geVec3d *Maxs); +GENESISAPI geMotion * geWorld_ModelGetMotion(geWorld_Model *Model); +// eaa3 07/28/2000 + +GENESISAPI void geWorld_ModelGetCenter(geWorld_Model *Model, geVec3d *Center); + +GENESISAPI void *geWorld_ModelGetUserData(const geWorld_Model *Model); +GENESISAPI void geWorld_ModelSetUserData(geWorld_Model *Model, void *UserData); +GENESISAPI void geWorld_ModelSetFlags(geWorld_Model *Model, uint32 ModelFlags); +GENESISAPI uint32 geWorld_ModelGetFlags(geWorld_Model *Model); + +// World Lights +GENESISAPI geLight *geWorld_AddLight(geWorld *World); +GENESISAPI void geWorld_RemoveLight(geWorld *World, geLight *Light); +GENESISAPI geBoolean geWorld_SetLightAttributes( geWorld *World, + geLight *Light, + const geVec3d *Pos, + const GE_RGBA *RGBA, + geFloat Radius, + geBoolean CastShadow); +GENESISAPI geBoolean geWorld_SetLTypeTable(geWorld *World, int32 LType, const char *Table); + +// World fog +GENESISAPI geFog *geWorld_AddFog(geWorld *World); +GENESISAPI geBoolean geWorld_RemoveFog(geWorld *World, geFog *Fog); + +GENESISAPI geBoolean geFog_SetAttributes( geFog *Fog, + const geVec3d *Pos, + GE_RGBA *Color, + geFloat LightBrightness, + geFloat VolumeBrightness, + geFloat VolumeRadius); + +// World Classes/Entities +GENESISAPI geEntity_EntitySet *geWorld_GetEntitySet(geWorld *World, const char *ClassName); +GENESISAPI geEntity *geEntity_EntitySetGetNextEntity(geEntity_EntitySet *EntitySet, geEntity *Entity); +GENESISAPI void *geEntity_GetUserData(geEntity *Entity); +GENESISAPI void geEntity_GetName(const geEntity *Entity, char *Buff, int MaxLen); + +// World collision +GENESISAPI geBoolean geWorld_ModelCollision( geWorld *World, + geWorld_Model *Model, + const geXForm3d *DXForm, + GE_Collision *Collision); +GENESISAPI geBoolean geWorld_TestModelMove( geWorld *World, + geWorld_Model *Model, + const geXForm3d *DXForm, + const geVec3d *Mins, const geVec3d *Maxs, + const geVec3d *In, geVec3d *Out); + +GENESISAPI geBoolean geWorld_Collision( geWorld *World, // World to collide with + const geVec3d *Mins, // Mins of object (in object-space). This CAN be NULL + const geVec3d *Maxs, // Maxs of object (in object-space). This CAN be NULL + const geVec3d *Front, // Front of line (in world-space) + const geVec3d *Back, // Back of line (in world-space) + uint32 Contents, // Contents to collide with (use GE_CONTENTS_SOLID_CLIP for default) + uint32 CollideFlags, // To mask out certain object types (GE_COLLIDE_ALL, etc...) + uint32 UserFlags, // To mask out actors (refer to geActor_SetUserFlags) + GE_CollisionCB *CollisionCB, // A callback to allow user to reject collisions with certain objects) + void *Context, // User data passed through above callback + GE_Collision *Col); // Structure filled with info about what was collided with + // NOTE - Mins/Maxs CAN be NULL. If you are just testing a point, then use NULL (it's faster!!!). + +GENESISAPI geBoolean geWorld_GetContents(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, uint32 Flags, uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, GE_Contents *Contents); +// changed texture name +GENESISAPI geBoolean geWorld_GetTextureName(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, char *TexName); +// end change texture name + +// World Polys +GENESISAPI gePoly *geWorld_AddPolyOnce(geWorld *World, + GE_LVertex *Verts, + int32 NumVerts, + geBitmap *Bitmap, + gePoly_Type Type, + uint32 RenderFlags, + geFloat Scale); +GENESISAPI gePoly *geWorld_AddPoly(geWorld *World, + GE_LVertex *Verts, + int32 NumVerts, + geBitmap *Bitmap, + gePoly_Type Type, + uint32 RenderFlags, + geFloat Scale); + +GENESISAPI void geWorld_RemovePoly(geWorld *World, gePoly *Poly); +GENESISAPI geBoolean gePoly_GetLVertex(gePoly *Poly, int32 Index, GE_LVertex *LVert); +GENESISAPI geBoolean gePoly_SetLVertex(gePoly *Poly, int32 Index, const GE_LVertex *LVert); + +// World visibility +GENESISAPI geBoolean geWorld_GetLeaf(const geWorld *World, const geVec3d *Pos, int32 *Leaf); +GENESISAPI geBoolean geWorld_MightSeeLeaf(const geWorld *World, int32 Leaf); + +GENESISAPI geBoolean geWorld_LeafMightSeeLeaf(const geWorld *World, int32 Leaf1, int32 Leaf2, uint32 VisFlags); + // Checks to see if Leaf1 can see Leaf2 + // Currently VisFlags is not used yet. It could be used for checking against areas, etc... + // Eventually you could also pass in a VisObject, that is manipulated with a camera... + +GENESISAPI geBoolean GENESISCC geWorld_IsActorPotentiallyVisible(const geWorld *World, const geActor *Actor, const geCamera *Camera); + +//MRB BEGIN +//geSprite +GENESISAPI geBoolean GENESISCC geWorld_IsSpritePotentiallyVisible(const geWorld *World, const geSprite *Sprite, const geCamera *Camera); + +//================================================================================ +// Camera Management functions +//================================================================================ + +GENESISAPI geCamera *GENESISCC geCamera_Create(geFloat Fov, const geRect *Rect); +GENESISAPI void GENESISCC geCamera_Destroy(geCamera **pCamera); +GENESISAPI void GENESISCC geCamera_SetZScale(geCamera *Camera, geFloat ZScale); +GENESISAPI geFloat GENESISCC geCamera_GetZScale(const geCamera *Camera); +GENESISAPI void GENESISCC geCamera_SetFarClipPlane(geCamera *Camera, geBoolean Enable, geFloat ZFar); + // sets a far clipping plane. The world and objects aren't drawn if they lie beyond ZFar. + // Zfar is the distance out from the camera. + // Polygons crossing the line are not nesessarily clipped exactly to the line. +GENESISAPI void GENESISCC geCamera_GetFarClipPlane(const geCamera *Camera, geBoolean *Enable, geFloat *ZFar); +GENESISAPI void GENESISCC geCamera_SetAttributes(geCamera *Camera,geFloat Fov, const geRect *Rect); +GENESISAPI void GENESISCC geCamera_GetClippingRect(const geCamera *Camera, geRect *Rect); + +GENESISAPI void GENESISCC geCamera_ScreenPointToWorld(const geCamera *Camera, + int32 ScreenX, + int32 ScreenY, + geVec3d *Vector ); +GENESISAPI void GENESISCC geCamera_Project(const geCamera *Camera, + const geVec3d *PointInCameraSpace, + geVec3d *ProjectedPoint); +GENESISAPI void GENESISCC geCamera_Transform(const geCamera *Camera, + const geVec3d *WorldSpacePoint, + geVec3d *CameraSpacePoint); + +GENESISAPI void GENESISCC geCamera_TransformArray(const geCamera *Camera, + const geVec3d *WorldSpacePointPtr, + geVec3d *CameraSpacePointPtr, + int count); + +GENESISAPI void GENESISCC geCamera_TransformAndProject(const geCamera *Camera, + const geVec3d *Point, + geVec3d *ProjectedPoint); + +GENESISAPI void GENESISCC geCamera_TransformAndProjectArray(const geCamera *Camera, + const geVec3d *WorldSpacePointPtr, + geVec3d *ProjectedSpacePointPtr, + int count); + +GENESISAPI void GENESISCC geCamera_TransformAndProjectL(const geCamera *Camera, + const GE_LVertex *Point, + GE_TLVertex *ProjectedPoint); + +GENESISAPI void GENESISCC geCamera_TransformAndProjectLArray(const geCamera *Camera, + const GE_LVertex *WorldSpacePointPtr, + GE_TLVertex *ProjectedSpacePointPtr, + int count); + + +GENESISAPI geBoolean GENESISCC geCamera_SetWorldSpaceXForm(geCamera *Camera, const geXForm3d *XForm); +GENESISAPI geBoolean GENESISCC geCamera_SetWorldSpaceVisXForm(geCamera *Camera, const geXForm3d *XForm); +GENESISAPI const geXForm3d *GENESISCC geCamera_GetWorldSpaceXForm( const geCamera *Camera); +GENESISAPI const geXForm3d * GENESISCC geCamera_GetCameraSpaceXForm( const geCamera *Camera); +GENESISAPI const geXForm3d * GENESISCC geCamera_GetWorldSpaceVisXForm( const geCamera *Camera); +GENESISAPI geBoolean GENESISCC geCamera_ConvertWorldSpaceToCameraSpace(const geXForm3d *WXForm, geXForm3d *CXForm); +GENESISAPI const geVec3d *GENESISCC geCamera_GetPov(const geCamera *Camera); + + + +GENESISAPI void GENESISCC geTClip_SetupEdges(geEngine *Engine, + geFloat LeftEdge, + geFloat RightEdge, + geFloat TopEdge , + geFloat BottomEdge, + geFloat BackEdge); + +GENESISAPI geBoolean GENESISCC geTClip_Push(void); +GENESISAPI geBoolean GENESISCC geTClip_Pop(void); + +GENESISAPI geBoolean GENESISCC geTClip_SetTexture(const geBitmap * Bitmap); +GENESISAPI void GENESISCC geTClip_Triangle(const GE_LVertex TriVertex[3]); + +GENESISAPI void GENESISCC geTClip_SetRenderFlags(uint32 newflags); // LA +GENESISAPI void GENESISCC geTClip_UnclippedTriangle(const GE_LVertex TriVertex[3]); // LA + + +//================================================================================ +// NetPlay Management functions +//================================================================================ + +typedef uint32 geCSNetMgr_NetID; +#define MAX_CLIENT_NAME 256 + +// Types for messages received from GE_ReceiveSystemMessage +typedef enum +{ + NET_MSG_NONE, // No msg + NET_MSG_USER, // User message + NET_MSG_CREATE_CLIENT, // A new client has joined in + NET_MSG_DESTROY_CLIENT, // An existing client has left + NET_MSG_HOST, // We are the server now + NET_MSG_SESSIONLOST, // Connection was lost + NET_MSG_SERVER_ID, // Internal, for hand shaking process +} geCSNetMgr_NetMsgType; + + +typedef struct +{ + char Name[MAX_CLIENT_NAME]; + geCSNetMgr_NetID Id; +} geCSNetMgr_NetClient; + +#ifdef _INC_WINDOWS + // Windows.h must be included before genesis.h for this api to be exposed. + typedef struct geCSNetMgr_NetSession + { + char SessionName[200]; // Description of Service provider + GUID Guid; // Service Provider GUID + } geCSNetMgr_NetSession; +GENESISAPI geBoolean GENESISCC geCSNetMgr_FindSession(geCSNetMgr *M, const char *IPAdress, geCSNetMgr_NetSession **SessionList, int32 *SessionNum ); +GENESISAPI geBoolean GENESISCC geCSNetMgr_JoinSession(geCSNetMgr *M, const char *Name, const geCSNetMgr_NetSession* Session); +#endif + + +GENESISAPI geCSNetMgr * GENESISCC geCSNetMgr_Create(void); +GENESISAPI void GENESISCC geCSNetMgr_Destroy(geCSNetMgr **ppM); +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveFromServer(geCSNetMgr *M, geCSNetMgr_NetMsgType *Type, int32 *Size, uint8 **Data); +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveFromClient(geCSNetMgr *M, geCSNetMgr_NetMsgType *Type, geCSNetMgr_NetID *IdClient, int32 *Size, uint8 **Data); +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveSystemMessage(geCSNetMgr *M, geCSNetMgr_NetID IdFor, geCSNetMgr_NetMsgType *Type, geCSNetMgr_NetClient *Client); +GENESISAPI geBoolean GENESISCC geCSNetMgr_ReceiveAllMessages(geCSNetMgr *M, geCSNetMgr_NetID *IdFrom, geCSNetMgr_NetID *IdTo, geCSNetMgr_NetMsgType *Type, int32 *Size, uint8 **Data); +GENESISAPI geCSNetMgr_NetID GENESISCC geCSNetMgr_GetServerID(geCSNetMgr *M); +GENESISAPI geCSNetMgr_NetID GENESISCC geCSNetMgr_GetOurID(geCSNetMgr *M); +GENESISAPI geCSNetMgr_NetID GENESISCC geCSNetMgr_GetAllPlayerID(geCSNetMgr *M); +GENESISAPI geBoolean GENESISCC geCSNetMgr_WeAreTheServer(geCSNetMgr *M); +GENESISAPI geBoolean GENESISCC geCSNetMgr_StartSession(geCSNetMgr *M, const char *SessionName, const char *PlayerName ); +GENESISAPI geBoolean GENESISCC geCSNetMgr_StopSession(geCSNetMgr *M); +GENESISAPI geBoolean GENESISCC geCSNetMgr_SendToServer(geCSNetMgr *M, geBoolean Guaranteed, uint8 *Data, int32 DataSize); +GENESISAPI geBoolean GENESISCC geCSNetMgr_SendToClient(geCSNetMgr *M, geCSNetMgr_NetID To, geBoolean Guaranteed, uint8 *Data, int32 DataSize); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Genesis.mak b/G3D/Genesis.mak new file mode 100644 index 0000000..958c750 --- /dev/null +++ b/G3D/Genesis.mak @@ -0,0 +1,925 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on Genesis.dsp +!IF "$(CFG)" == "" +CFG=Genesis - Win32 Debug +!MESSAGE No configuration specified. Defaulting to Genesis - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Genesis - Win32 Release" && "$(CFG)" != "Genesis - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Genesis.mak" CFG="Genesis - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Genesis - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "Genesis - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Genesis - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +ALL : "$(OUTDIR)\Genesis.lib" + + +CLEAN : + -@erase "$(INTDIR)\A_CORONA.obj" + -@erase "$(INTDIR)\A_STREAK.obj" + -@erase "$(INTDIR)\actor.obj" + -@erase "$(INTDIR)\bitmap.obj" + -@erase "$(INTDIR)\bitmap_blitdata.obj" + -@erase "$(INTDIR)\bitmap_gamma.obj" + -@erase "$(INTDIR)\BitmapList.obj" + -@erase "$(INTDIR)\body.obj" + -@erase "$(INTDIR)\bodyinst.obj" + -@erase "$(INTDIR)\Box.obj" + -@erase "$(INTDIR)\Camera.obj" + -@erase "$(INTDIR)\CORONA.obj" + -@erase "$(INTDIR)\crc32.obj" + -@erase "$(INTDIR)\CSNetMgr.obj" + -@erase "$(INTDIR)\dirtree.obj" + -@erase "$(INTDIR)\electric.obj" + -@erase "$(INTDIR)\engine.obj" + -@erase "$(INTDIR)\Entities.obj" + -@erase "$(INTDIR)\Errorlog.obj" + -@erase "$(INTDIR)\ExtBox.obj" + -@erase "$(INTDIR)\Fog.obj" + -@erase "$(INTDIR)\font.obj" + -@erase "$(INTDIR)\fontbmp.obj" + -@erase "$(INTDIR)\Frustum.obj" + -@erase "$(INTDIR)\fsdos.obj" + -@erase "$(INTDIR)\Fsmemory.obj" + -@erase "$(INTDIR)\fsvfs.obj" + -@erase "$(INTDIR)\Gbspfile.obj" + -@erase "$(INTDIR)\Ge.obj" + -@erase "$(INTDIR)\geAssert.obj" + -@erase "$(INTDIR)\genesis.idb" + -@erase "$(INTDIR)\genesis.res" + -@erase "$(INTDIR)\Light.obj" + -@erase "$(INTDIR)\list.obj" + -@erase "$(INTDIR)\log.obj" + -@erase "$(INTDIR)\logo.obj" + -@erase "$(INTDIR)\LogoActor.obj" + -@erase "$(INTDIR)\matrix33.obj" + -@erase "$(INTDIR)\mempool.obj" + -@erase "$(INTDIR)\motion.obj" + -@erase "$(INTDIR)\Netplay.obj" + -@erase "$(INTDIR)\palcreate.obj" + -@erase "$(INTDIR)\palettize.obj" + -@erase "$(INTDIR)\paloptimize.obj" + -@erase "$(INTDIR)\path.obj" + -@erase "$(INTDIR)\PhysicsJoint.obj" + -@erase "$(INTDIR)\PhysicsObject.obj" + -@erase "$(INTDIR)\PhysicsSystem.obj" + -@erase "$(INTDIR)\pixelformat.obj" + -@erase "$(INTDIR)\Plane.obj" + -@erase "$(INTDIR)\pose.obj" + -@erase "$(INTDIR)\puppet.obj" + -@erase "$(INTDIR)\QKFrame.obj" + -@erase "$(INTDIR)\quatern.obj" + -@erase "$(INTDIR)\Ram.obj" + -@erase "$(INTDIR)\ramdll.obj" + -@erase "$(INTDIR)\Sound.obj" + -@erase "$(INTDIR)\Sound3d.obj" + -@erase "$(INTDIR)\strblock.obj" + -@erase "$(INTDIR)\streak.obj" + -@erase "$(INTDIR)\Surface.obj" + -@erase "$(INTDIR)\System.obj" + -@erase "$(INTDIR)\Tclip.obj" + -@erase "$(INTDIR)\timer.obj" + -@erase "$(INTDIR)\tkarray.obj" + -@erase "$(INTDIR)\tkevents.obj" + -@erase "$(INTDIR)\Trace.obj" + -@erase "$(INTDIR)\tsc.obj" + -@erase "$(INTDIR)\User.obj" + -@erase "$(INTDIR)\Vec3d.obj" + -@erase "$(INTDIR)\vfile.obj" + -@erase "$(INTDIR)\Vis.obj" + -@erase "$(INTDIR)\vkframe.obj" + -@erase "$(INTDIR)\WBitmap.obj" + -@erase "$(INTDIR)\WebUrl.obj" + -@erase "$(INTDIR)\wgClip.obj" + -@erase "$(INTDIR)\World.obj" + -@erase "$(INTDIR)\XFArray.obj" + -@erase "$(INTDIR)\Xform3d.obj" + -@erase "$(INTDIR)\yuv.obj" + -@erase "$(OUTDIR)\Genesis.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MT /W3 /GX /O2 /X /I "..\SDK\DXSDK\Include" /I "..\Source" /I "World" /I "Engine" /I "Engine\Drivers" /I "Actor" /I "BSP" /I "Math" /I "Entities" /I "Support" /I "Physics" /I "VFile" /I "Bitmap" /I "Bitmap\Compression" /I "..\MSDev60\Include" /I "..\MSDev60\MFC\Include" /I "..\SDK\DX6SDK\Include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\genesis.pdb" /FD /c +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\genesis.res" /i "..\MSDev60\Include" /i "..\MSDev60\MFC\Include" /d "NDEBUG" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\Genesis.bsc" +BSC32_SBRS= \ + +LIB32=link.exe -lib +LIB32_FLAGS=/nologo /out:"$(OUTDIR)\Genesis.lib" +LIB32_OBJS= \ + "$(INTDIR)\Fog.obj" \ + "$(INTDIR)\Frustum.obj" \ + "$(INTDIR)\Gbspfile.obj" \ + "$(INTDIR)\Light.obj" \ + "$(INTDIR)\Plane.obj" \ + "$(INTDIR)\Surface.obj" \ + "$(INTDIR)\Trace.obj" \ + "$(INTDIR)\User.obj" \ + "$(INTDIR)\Vis.obj" \ + "$(INTDIR)\WBitmap.obj" \ + "$(INTDIR)\World.obj" \ + "$(INTDIR)\A_CORONA.obj" \ + "$(INTDIR)\A_STREAK.obj" \ + "$(INTDIR)\CORONA.obj" \ + "$(INTDIR)\electric.obj" \ + "$(INTDIR)\logo.obj" \ + "$(INTDIR)\LogoActor.obj" \ + "$(INTDIR)\streak.obj" \ + "$(INTDIR)\WebUrl.obj" \ + "$(INTDIR)\BitmapList.obj" \ + "$(INTDIR)\engine.obj" \ + "$(INTDIR)\fontbmp.obj" \ + "$(INTDIR)\System.obj" \ + "$(INTDIR)\actor.obj" \ + "$(INTDIR)\body.obj" \ + "$(INTDIR)\bodyinst.obj" \ + "$(INTDIR)\motion.obj" \ + "$(INTDIR)\path.obj" \ + "$(INTDIR)\pose.obj" \ + "$(INTDIR)\puppet.obj" \ + "$(INTDIR)\QKFrame.obj" \ + "$(INTDIR)\strblock.obj" \ + "$(INTDIR)\tkarray.obj" \ + "$(INTDIR)\tkevents.obj" \ + "$(INTDIR)\vkframe.obj" \ + "$(INTDIR)\XFArray.obj" \ + "$(INTDIR)\Box.obj" \ + "$(INTDIR)\crc32.obj" \ + "$(INTDIR)\ExtBox.obj" \ + "$(INTDIR)\quatern.obj" \ + "$(INTDIR)\Vec3d.obj" \ + "$(INTDIR)\Xform3d.obj" \ + "$(INTDIR)\Entities.obj" \ + "$(INTDIR)\Errorlog.obj" \ + "$(INTDIR)\geAssert.obj" \ + "$(INTDIR)\log.obj" \ + "$(INTDIR)\mempool.obj" \ + "$(INTDIR)\Ram.obj" \ + "$(INTDIR)\ramdll.obj" \ + "$(INTDIR)\matrix33.obj" \ + "$(INTDIR)\PhysicsJoint.obj" \ + "$(INTDIR)\PhysicsObject.obj" \ + "$(INTDIR)\PhysicsSystem.obj" \ + "$(INTDIR)\dirtree.obj" \ + "$(INTDIR)\fsdos.obj" \ + "$(INTDIR)\Fsmemory.obj" \ + "$(INTDIR)\fsvfs.obj" \ + "$(INTDIR)\vfile.obj" \ + "$(INTDIR)\palcreate.obj" \ + "$(INTDIR)\palettize.obj" \ + "$(INTDIR)\paloptimize.obj" \ + "$(INTDIR)\yuv.obj" \ + "$(INTDIR)\bitmap.obj" \ + "$(INTDIR)\bitmap_blitdata.obj" \ + "$(INTDIR)\bitmap_gamma.obj" \ + "$(INTDIR)\pixelformat.obj" \ + "$(INTDIR)\font.obj" \ + "$(INTDIR)\wgClip.obj" \ + "$(INTDIR)\Camera.obj" \ + "$(INTDIR)\CSNetMgr.obj" \ + "$(INTDIR)\Ge.obj" \ + "$(INTDIR)\list.obj" \ + "$(INTDIR)\Netplay.obj" \ + "$(INTDIR)\Sound.obj" \ + "$(INTDIR)\Sound3d.obj" \ + "$(INTDIR)\Tclip.obj" \ + "$(INTDIR)\timer.obj" \ + "$(INTDIR)\tsc.obj" \ + "$(INTDIR)\genesis.res" \ + "..\Sdk\Dx6sdk\Lib\dxguid.lib" + +"$(OUTDIR)\Genesis.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS) + $(LIB32) @<< + $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Genesis - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\Genesis.lib" + + +CLEAN : + -@erase "$(INTDIR)\A_CORONA.obj" + -@erase "$(INTDIR)\A_STREAK.obj" + -@erase "$(INTDIR)\actor.obj" + -@erase "$(INTDIR)\bitmap.obj" + -@erase "$(INTDIR)\bitmap_blitdata.obj" + -@erase "$(INTDIR)\bitmap_gamma.obj" + -@erase "$(INTDIR)\BitmapList.obj" + -@erase "$(INTDIR)\body.obj" + -@erase "$(INTDIR)\bodyinst.obj" + -@erase "$(INTDIR)\Box.obj" + -@erase "$(INTDIR)\Camera.obj" + -@erase "$(INTDIR)\CORONA.obj" + -@erase "$(INTDIR)\crc32.obj" + -@erase "$(INTDIR)\CSNetMgr.obj" + -@erase "$(INTDIR)\dirtree.obj" + -@erase "$(INTDIR)\electric.obj" + -@erase "$(INTDIR)\engine.obj" + -@erase "$(INTDIR)\Entities.obj" + -@erase "$(INTDIR)\Errorlog.obj" + -@erase "$(INTDIR)\ExtBox.obj" + -@erase "$(INTDIR)\Fog.obj" + -@erase "$(INTDIR)\font.obj" + -@erase "$(INTDIR)\fontbmp.obj" + -@erase "$(INTDIR)\Frustum.obj" + -@erase "$(INTDIR)\fsdos.obj" + -@erase "$(INTDIR)\Fsmemory.obj" + -@erase "$(INTDIR)\fsvfs.obj" + -@erase "$(INTDIR)\Gbspfile.obj" + -@erase "$(INTDIR)\Ge.obj" + -@erase "$(INTDIR)\geAssert.obj" + -@erase "$(INTDIR)\genesis.idb" + -@erase "$(INTDIR)\genesis.pdb" + -@erase "$(INTDIR)\genesis.res" + -@erase "$(INTDIR)\Light.obj" + -@erase "$(INTDIR)\list.obj" + -@erase "$(INTDIR)\log.obj" + -@erase "$(INTDIR)\logo.obj" + -@erase "$(INTDIR)\LogoActor.obj" + -@erase "$(INTDIR)\matrix33.obj" + -@erase "$(INTDIR)\mempool.obj" + -@erase "$(INTDIR)\motion.obj" + -@erase "$(INTDIR)\Netplay.obj" + -@erase "$(INTDIR)\palcreate.obj" + -@erase "$(INTDIR)\palettize.obj" + -@erase "$(INTDIR)\paloptimize.obj" + -@erase "$(INTDIR)\path.obj" + -@erase "$(INTDIR)\PhysicsJoint.obj" + -@erase "$(INTDIR)\PhysicsObject.obj" + -@erase "$(INTDIR)\PhysicsSystem.obj" + -@erase "$(INTDIR)\pixelformat.obj" + -@erase "$(INTDIR)\Plane.obj" + -@erase "$(INTDIR)\pose.obj" + -@erase "$(INTDIR)\puppet.obj" + -@erase "$(INTDIR)\QKFrame.obj" + -@erase "$(INTDIR)\quatern.obj" + -@erase "$(INTDIR)\Ram.obj" + -@erase "$(INTDIR)\ramdll.obj" + -@erase "$(INTDIR)\Sound.obj" + -@erase "$(INTDIR)\Sound3d.obj" + -@erase "$(INTDIR)\strblock.obj" + -@erase "$(INTDIR)\streak.obj" + -@erase "$(INTDIR)\Surface.obj" + -@erase "$(INTDIR)\System.obj" + -@erase "$(INTDIR)\Tclip.obj" + -@erase "$(INTDIR)\timer.obj" + -@erase "$(INTDIR)\tkarray.obj" + -@erase "$(INTDIR)\tkevents.obj" + -@erase "$(INTDIR)\Trace.obj" + -@erase "$(INTDIR)\tsc.obj" + -@erase "$(INTDIR)\User.obj" + -@erase "$(INTDIR)\Vec3d.obj" + -@erase "$(INTDIR)\vfile.obj" + -@erase "$(INTDIR)\Vis.obj" + -@erase "$(INTDIR)\vkframe.obj" + -@erase "$(INTDIR)\WBitmap.obj" + -@erase "$(INTDIR)\WebUrl.obj" + -@erase "$(INTDIR)\wgClip.obj" + -@erase "$(INTDIR)\World.obj" + -@erase "$(INTDIR)\XFArray.obj" + -@erase "$(INTDIR)\Xform3d.obj" + -@erase "$(INTDIR)\yuv.obj" + -@erase "$(OUTDIR)\Genesis.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /X /I "..\SDK\DX6SDK\Include" /I "..\Source" /I "World" /I "Engine" /I "Engine\Drivers" /I "Actor" /I "BSP" /I "Math" /I "Entities" /I "Support" /I "Physics" /I "VFile" /I "Bitmap" /I "Bitmap\Compression" /I "..\MSDev60\Include" /I "..\MSDev60\MFC\Include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\genesis.pdb" /FD /GZ /c +RSC_PROJ=/l 0x409 /x /fo"$(INTDIR)\genesis.res" /i "..\MSDev60\Include" /i "..\MSDev60\MFC\Include" /d "_DEBUG" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\Genesis.bsc" +BSC32_SBRS= \ + +LIB32=link.exe -lib +LIB32_FLAGS=/nologo /out:"$(OUTDIR)\Genesis.lib" +LIB32_OBJS= \ + "$(INTDIR)\Fog.obj" \ + "$(INTDIR)\Frustum.obj" \ + "$(INTDIR)\Gbspfile.obj" \ + "$(INTDIR)\Light.obj" \ + "$(INTDIR)\Plane.obj" \ + "$(INTDIR)\Surface.obj" \ + "$(INTDIR)\Trace.obj" \ + "$(INTDIR)\User.obj" \ + "$(INTDIR)\Vis.obj" \ + "$(INTDIR)\WBitmap.obj" \ + "$(INTDIR)\World.obj" \ + "$(INTDIR)\A_CORONA.obj" \ + "$(INTDIR)\A_STREAK.obj" \ + "$(INTDIR)\CORONA.obj" \ + "$(INTDIR)\electric.obj" \ + "$(INTDIR)\logo.obj" \ + "$(INTDIR)\LogoActor.obj" \ + "$(INTDIR)\streak.obj" \ + "$(INTDIR)\WebUrl.obj" \ + "$(INTDIR)\BitmapList.obj" \ + "$(INTDIR)\engine.obj" \ + "$(INTDIR)\fontbmp.obj" \ + "$(INTDIR)\System.obj" \ + "$(INTDIR)\actor.obj" \ + "$(INTDIR)\body.obj" \ + "$(INTDIR)\bodyinst.obj" \ + "$(INTDIR)\motion.obj" \ + "$(INTDIR)\path.obj" \ + "$(INTDIR)\pose.obj" \ + "$(INTDIR)\puppet.obj" \ + "$(INTDIR)\QKFrame.obj" \ + "$(INTDIR)\strblock.obj" \ + "$(INTDIR)\tkarray.obj" \ + "$(INTDIR)\tkevents.obj" \ + "$(INTDIR)\vkframe.obj" \ + "$(INTDIR)\XFArray.obj" \ + "$(INTDIR)\Box.obj" \ + "$(INTDIR)\crc32.obj" \ + "$(INTDIR)\ExtBox.obj" \ + "$(INTDIR)\quatern.obj" \ + "$(INTDIR)\Vec3d.obj" \ + "$(INTDIR)\Xform3d.obj" \ + "$(INTDIR)\Entities.obj" \ + "$(INTDIR)\Errorlog.obj" \ + "$(INTDIR)\geAssert.obj" \ + "$(INTDIR)\log.obj" \ + "$(INTDIR)\mempool.obj" \ + "$(INTDIR)\Ram.obj" \ + "$(INTDIR)\ramdll.obj" \ + "$(INTDIR)\matrix33.obj" \ + "$(INTDIR)\PhysicsJoint.obj" \ + "$(INTDIR)\PhysicsObject.obj" \ + "$(INTDIR)\PhysicsSystem.obj" \ + "$(INTDIR)\dirtree.obj" \ + "$(INTDIR)\fsdos.obj" \ + "$(INTDIR)\Fsmemory.obj" \ + "$(INTDIR)\fsvfs.obj" \ + "$(INTDIR)\vfile.obj" \ + "$(INTDIR)\palcreate.obj" \ + "$(INTDIR)\palettize.obj" \ + "$(INTDIR)\paloptimize.obj" \ + "$(INTDIR)\yuv.obj" \ + "$(INTDIR)\bitmap.obj" \ + "$(INTDIR)\bitmap_blitdata.obj" \ + "$(INTDIR)\bitmap_gamma.obj" \ + "$(INTDIR)\pixelformat.obj" \ + "$(INTDIR)\font.obj" \ + "$(INTDIR)\wgClip.obj" \ + "$(INTDIR)\Camera.obj" \ + "$(INTDIR)\CSNetMgr.obj" \ + "$(INTDIR)\Ge.obj" \ + "$(INTDIR)\list.obj" \ + "$(INTDIR)\Netplay.obj" \ + "$(INTDIR)\Sound.obj" \ + "$(INTDIR)\Sound3d.obj" \ + "$(INTDIR)\Tclip.obj" \ + "$(INTDIR)\timer.obj" \ + "$(INTDIR)\tsc.obj" \ + "$(INTDIR)\genesis.res" \ + "..\Sdk\Dx6sdk\Lib\dxguid.lib" + +"$(OUTDIR)\Genesis.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS) + $(LIB32) @<< + $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("Genesis.dep") +!INCLUDE "Genesis.dep" +!ELSE +!MESSAGE Warning: cannot find "Genesis.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "Genesis - Win32 Release" || "$(CFG)" == "Genesis - Win32 Debug" +SOURCE=.\World\Fog.c + +"$(INTDIR)\Fog.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\Frustum.c + +"$(INTDIR)\Frustum.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\Gbspfile.c + +"$(INTDIR)\Gbspfile.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\Light.c + +"$(INTDIR)\Light.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\Plane.c + +"$(INTDIR)\Plane.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\Surface.c + +"$(INTDIR)\Surface.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\Trace.c + +"$(INTDIR)\Trace.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\User.c + +"$(INTDIR)\User.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\Vis.c + +"$(INTDIR)\Vis.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\WBitmap.c + +"$(INTDIR)\WBitmap.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\World\World.c + +"$(INTDIR)\World.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\Logo\A_CORONA.c + +"$(INTDIR)\A_CORONA.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\Logo\A_STREAK.c + +"$(INTDIR)\A_STREAK.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\Logo\CORONA.c + +"$(INTDIR)\CORONA.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\Logo\electric.c + +"$(INTDIR)\electric.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\Logo\logo.c + +"$(INTDIR)\logo.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\Logo\LogoActor.c + +"$(INTDIR)\LogoActor.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\Logo\streak.c + +"$(INTDIR)\streak.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\Logo\WebUrl.c + +"$(INTDIR)\WebUrl.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\BitmapList.c + +"$(INTDIR)\BitmapList.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\engine.c + +"$(INTDIR)\engine.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\fontbmp.c + +"$(INTDIR)\fontbmp.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Engine\System.c + +"$(INTDIR)\System.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\actor.c + +"$(INTDIR)\actor.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\body.c + +"$(INTDIR)\body.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\bodyinst.c + +"$(INTDIR)\bodyinst.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\motion.c + +"$(INTDIR)\motion.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\path.c + +"$(INTDIR)\path.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\pose.c + +"$(INTDIR)\pose.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\puppet.c + +"$(INTDIR)\puppet.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\QKFrame.c + +"$(INTDIR)\QKFrame.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\strblock.c + +"$(INTDIR)\strblock.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\tkarray.c + +"$(INTDIR)\tkarray.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\tkevents.c + +"$(INTDIR)\tkevents.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\vkframe.c + +"$(INTDIR)\vkframe.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Actor\XFArray.c + +"$(INTDIR)\XFArray.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Math\Box.c + +"$(INTDIR)\Box.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Math\crc32.c + +"$(INTDIR)\crc32.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Math\ExtBox.c + +"$(INTDIR)\ExtBox.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Math\quatern.c + +"$(INTDIR)\quatern.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Math\Vec3d.c + +"$(INTDIR)\Vec3d.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Math\Xform3d.c + +"$(INTDIR)\Xform3d.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Entities\Entities.c + +"$(INTDIR)\Entities.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Support\Errorlog.c + +"$(INTDIR)\Errorlog.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Support\geAssert.c + +"$(INTDIR)\geAssert.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Support\log.c + +"$(INTDIR)\log.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Support\mempool.c + +"$(INTDIR)\mempool.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Support\Ram.c + +"$(INTDIR)\Ram.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Support\ramdll.c + +"$(INTDIR)\ramdll.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Physics\matrix33.c + +"$(INTDIR)\matrix33.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Physics\PhysicsJoint.c + +"$(INTDIR)\PhysicsJoint.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Physics\PhysicsObject.c + +"$(INTDIR)\PhysicsObject.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Physics\PhysicsSystem.c + +"$(INTDIR)\PhysicsSystem.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\VFile\dirtree.c + +"$(INTDIR)\dirtree.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\VFile\fsdos.c + +"$(INTDIR)\fsdos.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\VFile\Fsmemory.c + +"$(INTDIR)\Fsmemory.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\VFile\fsvfs.c + +"$(INTDIR)\fsvfs.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\VFile\vfile.c + +"$(INTDIR)\vfile.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Bitmap\Compression\palcreate.c + +"$(INTDIR)\palcreate.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Bitmap\Compression\palettize.c + +"$(INTDIR)\palettize.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Bitmap\Compression\paloptimize.c + +"$(INTDIR)\paloptimize.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Bitmap\Compression\yuv.c + +"$(INTDIR)\yuv.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Bitmap\bitmap.c + +"$(INTDIR)\bitmap.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Bitmap\bitmap_blitdata.c + +"$(INTDIR)\bitmap_blitdata.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Bitmap\bitmap_gamma.c + +"$(INTDIR)\bitmap_gamma.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Bitmap\pixelformat.c + +"$(INTDIR)\pixelformat.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Font\font.c + +"$(INTDIR)\font.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Font\wgClip.c + +"$(INTDIR)\wgClip.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\Camera.c + +"$(INTDIR)\Camera.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\CSNetMgr.c + +"$(INTDIR)\CSNetMgr.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Ge.c + +"$(INTDIR)\Ge.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\genesis.rc + +"$(INTDIR)\genesis.res" : $(SOURCE) "$(INTDIR)" + $(RSC) $(RSC_PROJ) $(SOURCE) + + +SOURCE=.\list.c + +"$(INTDIR)\list.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Netplay.c + +"$(INTDIR)\Netplay.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Sound.c + +"$(INTDIR)\Sound.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Sound3d.c + +"$(INTDIR)\Sound3d.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Tclip.c + +"$(INTDIR)\Tclip.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\timer.c + +"$(INTDIR)\timer.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\tsc.c + +"$(INTDIR)\tsc.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/G3D/GenesisDLL.dsp b/G3D/GenesisDLL.dsp new file mode 100644 index 0000000..256abac --- /dev/null +++ b/G3D/GenesisDLL.dsp @@ -0,0 +1,802 @@ +# Microsoft Developer Studio Project File - Name="GenesisDLL" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GenesisDLL - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GenesisDLL.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GenesisDLL.mak" CFG="GenesisDLL - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GenesisDLL - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GenesisDLL - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis20/Source", VBRBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GenesisDLL - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseDLL" +# PROP Intermediate_Dir "ReleaseDLL" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GENESISDLL_EXPORTS" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W3 /GX /O2 /Ob2 /I "..\Source" /I "World" /I "Engine" /I "Engine\Drivers" /I "Actor" /I "BSP" /I "Math" /I "Entities" /I "Support" /I "Physics" /I "VFile" /I "Bitmap" /I "Bitmap\Compression" /I "..\G3D" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BUILDGENESIS" /D "GENESISDLLVERSION" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 libcmt.lib kernel32.lib user32.lib gdi32.lib oldnames.lib ole32.lib urlmon.lib uuid.lib winmm.lib /nologo /dll /machine:I386 /out:"ReleaseDLL/Genesis.dll" +# SUBTRACT LINK32 /nodefaultlib +# Begin Custom Build +IntDir=.\ReleaseDLL +OutDir=.\ReleaseDLL +InputPath=.\ReleaseDLL\Genesis.dll +SOURCE="$(InputPath)" + +"$(OUTDIR)\genesisi.lib" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + lib /OUT:$(OUTDIR)\genesisi.lib $(IntDir)\ramdll.obj $(OUTDIR)\genesis.lib + +# End Custom Build + +!ELSEIF "$(CFG)" == "GenesisDLL - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GenesisDLL___Win32_Debug" +# PROP BASE Intermediate_Dir "GenesisDLL___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugDLL" +# PROP Intermediate_Dir "DebugDLL" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GENESISDLL_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /I "..\Source" /I "World" /I "Engine" /I "Engine\Drivers" /I "Actor" /I "BSP" /I "Math" /I "Entities" /I "Support" /I "Physics" /I "VFile" /I "Bitmap" /I "Bitmap\Compression" /I "guWorld" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BUILDGENESIS" /D "GENESISDLLVERSION" /YX /FD /GZ /c +# SUBTRACT CPP /X +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libcmtd.lib kernel32.lib user32.lib gdi32.lib oldnames.lib ole32.lib urlmon.lib uuid.lib winmm.lib /nologo /dll /debug /machine:I386 /out:"DebugDLL/Genesis.dll" /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib +# Begin Custom Build +IntDir=.\DebugDLL +OutDir=.\DebugDLL +InputPath=.\DebugDLL\Genesis.dll +SOURCE="$(InputPath)" + +"$(OUTDIR)\genesisid.lib" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + lib /OUT:$(OUTDIR)\genesisid.lib $(IntDir)\ramdll.obj $(OUTDIR)\genesis.lib + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "GenesisDLL - Win32 Release" +# Name "GenesisDLL - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Group "Actor" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Actor\actor.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\actor.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\body.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\body.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\bodyinst.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\bodyinst.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\motion.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\motion.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\path.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\path.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\pose.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\pose.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\puppet.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\puppet.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\QKFrame.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\QKFrame.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\strblock.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\strblock.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\tkarray.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\tkarray.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\tkevents.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\tkevents.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\vkframe.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\vkframe.h +# End Source File +# Begin Source File + +SOURCE=.\Actor\XFArray.c +# End Source File +# Begin Source File + +SOURCE=.\Actor\xfarray.h +# End Source File +# End Group +# Begin Group "Bitmap" + +# PROP Default_Filter "" +# Begin Group "Compression" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Bitmap\Compression\image.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\palcreate.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\palcreate.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\palettize.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\palettize.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\paloptimize.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\paloptimize.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\utility.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\yuv.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\Compression\yuv.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Bitmap\bitmap.__h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap._h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap_blitdata.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap_blitdata.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap_gamma.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\bitmap_gamma.h +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\pixelformat.c +# End Source File +# Begin Source File + +SOURCE=.\Bitmap\pixelformat.h +# End Source File +# End Group +# Begin Group "Engine" + +# PROP Default_Filter "" +# Begin Group "Logo" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Engine\Logo\A_CORONA.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\A_STREAK.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\CORONA.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\electric.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\electric.h +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\logo.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\LogoActor.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\streak.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\Logo\WebUrl.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Engine\BitmapList.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\BitmapList.h +# End Source File +# Begin Source File + +SOURCE=.\Engine\engine.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\engine.h +# End Source File +# Begin Source File + +SOURCE=.\Engine\fontbmp.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\System.c +# End Source File +# Begin Source File + +SOURCE=.\Engine\System.h +# End Source File +# End Group +# Begin Group "Entities" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Entities\Entities.c +# End Source File +# Begin Source File + +SOURCE=.\Entities\Entities.h +# End Source File +# End Group +# Begin Group "Math" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Math\Box.c +# End Source File +# Begin Source File + +SOURCE=.\Math\Box.h +# End Source File +# Begin Source File + +SOURCE=.\Math\crc32.c +# End Source File +# Begin Source File + +SOURCE=.\Math\crc32.h +# End Source File +# Begin Source File + +SOURCE=.\Math\ExtBox.c +# End Source File +# Begin Source File + +SOURCE=.\Math\ExtBox.h +# End Source File +# Begin Source File + +SOURCE=.\Math\quatern.c +# End Source File +# Begin Source File + +SOURCE=.\Math\quatern.h +# End Source File +# Begin Source File + +SOURCE=.\Math\Vec3d.c +# End Source File +# Begin Source File + +SOURCE=.\Math\Vec3d.h +# End Source File +# Begin Source File + +SOURCE=.\Math\Xform3d.c +# End Source File +# Begin Source File + +SOURCE=.\Math\Xform3d.h +# End Source File +# End Group +# Begin Group "Support" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Support\Basetype.h +# End Source File +# Begin Source File + +SOURCE=.\Support\Errorlog.c +# End Source File +# Begin Source File + +SOURCE=.\Support\Errorlog.h +# End Source File +# Begin Source File + +SOURCE=.\Support\geAssert.c +# End Source File +# Begin Source File + +SOURCE=.\Support\geAssert.h +# End Source File +# Begin Source File + +SOURCE=.\Support\log.c +# End Source File +# Begin Source File + +SOURCE=.\Support\log.h +# End Source File +# Begin Source File + +SOURCE=.\Support\mempool.c +# End Source File +# Begin Source File + +SOURCE=.\Support\mempool.h +# End Source File +# Begin Source File + +SOURCE=.\Support\Ram.c +# End Source File +# Begin Source File + +SOURCE=.\Support\Ram.h +# End Source File +# Begin Source File + +SOURCE=.\Support\ramdll.c +# End Source File +# End Group +# Begin Group "VFile" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=".\VFile\dirtree-common.c" +# End Source File +# Begin Source File + +SOURCE=".\VFile\dirtree-common.h" +# End Source File +# Begin Source File + +SOURCE=.\VFile\dirtree.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\dirtree.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\fsdos.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\fsdos.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\Fsmemory.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\Fsmemory.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\fsvfs.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\fsvfs.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\vfile._h +# End Source File +# Begin Source File + +SOURCE=.\VFile\vfile.c +# End Source File +# Begin Source File + +SOURCE=.\VFile\vfile.h +# End Source File +# Begin Source File + +SOURCE=.\VFile\vfile_structs.h +# End Source File +# End Group +# Begin Group "World" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\World\Fog.c +# End Source File +# Begin Source File + +SOURCE=.\World\Fog.h +# End Source File +# Begin Source File + +SOURCE=.\World\Frustum.c +# End Source File +# Begin Source File + +SOURCE=.\World\Frustum.h +# End Source File +# Begin Source File + +SOURCE=.\World\Gbspfile.c +# End Source File +# Begin Source File + +SOURCE=.\World\Gbspfile.h +# End Source File +# Begin Source File + +SOURCE=.\World\Light.c +# End Source File +# Begin Source File + +SOURCE=.\World\Light.h +# End Source File +# Begin Source File + +SOURCE=.\World\Plane.c +# End Source File +# Begin Source File + +SOURCE=.\World\Plane.h +# End Source File +# Begin Source File + +SOURCE=.\World\Surface.c +# End Source File +# Begin Source File + +SOURCE=.\World\Surface.h +# End Source File +# Begin Source File + +SOURCE=.\World\Trace.c +# End Source File +# Begin Source File + +SOURCE=.\World\Trace.h +# End Source File +# Begin Source File + +SOURCE=.\World\User.c +# End Source File +# Begin Source File + +SOURCE=.\World\User.h +# End Source File +# Begin Source File + +SOURCE=.\World\Vis.c +# End Source File +# Begin Source File + +SOURCE=.\World\Vis.h +# End Source File +# Begin Source File + +SOURCE=.\World\WBitmap.c +# End Source File +# Begin Source File + +SOURCE=.\World\WBitmap.h +# End Source File +# Begin Source File + +SOURCE=.\World\World.c +# End Source File +# Begin Source File + +SOURCE=.\World\World.h +# End Source File +# End Group +# Begin Group "Font" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Font\font.c +# End Source File +# Begin Source File + +SOURCE=.\Font\font.H +# End Source File +# Begin Source File + +SOURCE=.\Font\wgClip.c +# End Source File +# Begin Source File + +SOURCE=.\Font\wgClip.H +# End Source File +# End Group +# Begin Group "Physics" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Physics\matrix33.c +# End Source File +# Begin Source File + +SOURCE=.\Physics\matrix33.h +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsJoint.c +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsJoint.h +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsObject.c +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsObject.h +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsSystem.c +# End Source File +# Begin Source File + +SOURCE=.\Physics\PhysicsSystem.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Camera.c +# End Source File +# Begin Source File + +SOURCE=.\Camera.h +# End Source File +# Begin Source File + +SOURCE=.\Ge.c +# End Source File +# Begin Source File + +SOURCE=.\Genesis.h +# End Source File +# Begin Source File + +SOURCE=.\genesis.rc +# End Source File +# Begin Source File + +SOURCE=.\getypes.h +# End Source File +# Begin Source File + +SOURCE=.\list.c +# End Source File +# Begin Source File + +SOURCE=.\list.h +# End Source File +# Begin Source File + +SOURCE=.\Ptrtypes.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\Sound.c +# End Source File +# Begin Source File + +SOURCE=.\Sound.h +# End Source File +# Begin Source File + +SOURCE=.\Sound3d.c +# End Source File +# Begin Source File + +SOURCE=.\Sound3d.h +# End Source File +# Begin Source File + +SOURCE=.\sprite.c +# End Source File +# Begin Source File + +SOURCE=.\sprite.h +# End Source File +# Begin Source File + +SOURCE=.\Tclip.c +# End Source File +# Begin Source File + +SOURCE=.\tclip.h +# End Source File +# Begin Source File + +SOURCE=.\timer.c +# End Source File +# Begin Source File + +SOURCE=.\timer.h +# End Source File +# Begin Source File + +SOURCE=.\tsc.c +# End Source File +# Begin Source File + +SOURCE=.\tsc.h +# End Source File +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# End Group +# End Target +# End Project diff --git a/G3D/GenesisDLL.dsw b/G3D/GenesisDLL.dsw new file mode 100644 index 0000000..ed39de5 --- /dev/null +++ b/G3D/GenesisDLL.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "GenesisDLL"=.\GenesisDLL.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/G3D/GenesisDLL.mak b/G3D/GenesisDLL.mak new file mode 100644 index 0000000..92f6495 --- /dev/null +++ b/G3D/GenesisDLL.mak @@ -0,0 +1,960 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on GenesisDLL.dsp +!IF "$(CFG)" == "" +CFG=GenesisDLL - Win32 Debug +!MESSAGE No configuration specified. Defaulting to GenesisDLL - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "GenesisDLL - Win32 Release" && "$(CFG)" != "GenesisDLL - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GenesisDLL.mak" CFG="GenesisDLL - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GenesisDLL - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GenesisDLL - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GenesisDLL - Win32 Release" + +OUTDIR=.\ReleaseDLL +INTDIR=.\ReleaseDLL +# Begin Custom Macros +OutDir=.\ReleaseDLL +# End Custom Macros + +ALL : "$(OUTDIR)\Genesis.dll" ".\ReleaseDLL\genesisi.lib" + + +CLEAN : + -@erase "$(INTDIR)\A_CORONA.obj" + -@erase "$(INTDIR)\A_STREAK.obj" + -@erase "$(INTDIR)\actor.obj" + -@erase "$(INTDIR)\bitmap.obj" + -@erase "$(INTDIR)\bitmap_blitdata.obj" + -@erase "$(INTDIR)\bitmap_gamma.obj" + -@erase "$(INTDIR)\BitmapList.obj" + -@erase "$(INTDIR)\body.obj" + -@erase "$(INTDIR)\bodyinst.obj" + -@erase "$(INTDIR)\Box.obj" + -@erase "$(INTDIR)\Camera.obj" + -@erase "$(INTDIR)\CORONA.obj" + -@erase "$(INTDIR)\crc32.obj" + -@erase "$(INTDIR)\CSNetMgr.obj" + -@erase "$(INTDIR)\dirtree.obj" + -@erase "$(INTDIR)\electric.obj" + -@erase "$(INTDIR)\engine.obj" + -@erase "$(INTDIR)\Entities.obj" + -@erase "$(INTDIR)\Errorlog.obj" + -@erase "$(INTDIR)\ExtBox.obj" + -@erase "$(INTDIR)\Fog.obj" + -@erase "$(INTDIR)\font.obj" + -@erase "$(INTDIR)\fontbmp.obj" + -@erase "$(INTDIR)\Frustum.obj" + -@erase "$(INTDIR)\fsdos.obj" + -@erase "$(INTDIR)\Fsmemory.obj" + -@erase "$(INTDIR)\fsvfs.obj" + -@erase "$(INTDIR)\Gbspfile.obj" + -@erase "$(INTDIR)\Ge.obj" + -@erase "$(INTDIR)\geAssert.obj" + -@erase "$(INTDIR)\genesis.res" + -@erase "$(INTDIR)\Light.obj" + -@erase "$(INTDIR)\list.obj" + -@erase "$(INTDIR)\log.obj" + -@erase "$(INTDIR)\logo.obj" + -@erase "$(INTDIR)\LogoActor.obj" + -@erase "$(INTDIR)\matrix33.obj" + -@erase "$(INTDIR)\mempool.obj" + -@erase "$(INTDIR)\motion.obj" + -@erase "$(INTDIR)\Netplay.obj" + -@erase "$(INTDIR)\palcreate.obj" + -@erase "$(INTDIR)\palettize.obj" + -@erase "$(INTDIR)\paloptimize.obj" + -@erase "$(INTDIR)\path.obj" + -@erase "$(INTDIR)\PhysicsJoint.obj" + -@erase "$(INTDIR)\PhysicsObject.obj" + -@erase "$(INTDIR)\PhysicsSystem.obj" + -@erase "$(INTDIR)\pixelformat.obj" + -@erase "$(INTDIR)\Plane.obj" + -@erase "$(INTDIR)\pose.obj" + -@erase "$(INTDIR)\puppet.obj" + -@erase "$(INTDIR)\QKFrame.obj" + -@erase "$(INTDIR)\quatern.obj" + -@erase "$(INTDIR)\Ram.obj" + -@erase "$(INTDIR)\ramdll.obj" + -@erase "$(INTDIR)\Sound.obj" + -@erase "$(INTDIR)\Sound3d.obj" + -@erase "$(INTDIR)\strblock.obj" + -@erase "$(INTDIR)\streak.obj" + -@erase "$(INTDIR)\Surface.obj" + -@erase "$(INTDIR)\System.obj" + -@erase "$(INTDIR)\Tclip.obj" + -@erase "$(INTDIR)\timer.obj" + -@erase "$(INTDIR)\tkarray.obj" + -@erase "$(INTDIR)\tkevents.obj" + -@erase "$(INTDIR)\Trace.obj" + -@erase "$(INTDIR)\tsc.obj" + -@erase "$(INTDIR)\User.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\Vec3d.obj" + -@erase "$(INTDIR)\vfile.obj" + -@erase "$(INTDIR)\Vis.obj" + -@erase "$(INTDIR)\vkframe.obj" + -@erase "$(INTDIR)\WBitmap.obj" + -@erase "$(INTDIR)\WebUrl.obj" + -@erase "$(INTDIR)\wgClip.obj" + -@erase "$(INTDIR)\World.obj" + -@erase "$(INTDIR)\XFArray.obj" + -@erase "$(INTDIR)\Xform3d.obj" + -@erase "$(INTDIR)\yuv.obj" + -@erase "$(OUTDIR)\Genesis.dll" + -@erase "$(OUTDIR)\Genesis.exp" + -@erase "$(OUTDIR)\Genesis.lib" + -@erase ".\ReleaseDLL\genesisi.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MT /W3 /GX /O2 /X /I "..\SDK\DX6SDK\Include" /I "..\Source" /I "World" /I "Engine" /I "Engine\Drivers" /I "Actor" /I "BSP" /I "Math" /I "Entities" /I "Support" /I "Physics" /I "VFile" /I "Bitmap" /I "Bitmap\Compression" /I "..\MSDev60\Include" /I "..\MSDev60\MFC\Include" /I "guWorld" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BUILDGENESIS" /D "GENESISDLLVERSION" /Fp"$(INTDIR)\GenesisDLL.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\genesis.res" /d "NDEBUG" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\GenesisDLL.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libcmt.lib kernel32.lib user32.lib gdi32.lib oldnames.lib ole32.lib urlmon.lib uuid.lib winmm.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\Genesis.pdb" /machine:I386 /nodefaultlib /out:"$(OUTDIR)\Genesis.dll" /implib:"$(OUTDIR)\Genesis.lib" +LINK32_OBJS= \ + "$(INTDIR)\actor.obj" \ + "$(INTDIR)\body.obj" \ + "$(INTDIR)\bodyinst.obj" \ + "$(INTDIR)\motion.obj" \ + "$(INTDIR)\path.obj" \ + "$(INTDIR)\pose.obj" \ + "$(INTDIR)\puppet.obj" \ + "$(INTDIR)\QKFrame.obj" \ + "$(INTDIR)\strblock.obj" \ + "$(INTDIR)\tkarray.obj" \ + "$(INTDIR)\tkevents.obj" \ + "$(INTDIR)\vkframe.obj" \ + "$(INTDIR)\XFArray.obj" \ + "$(INTDIR)\palcreate.obj" \ + "$(INTDIR)\palettize.obj" \ + "$(INTDIR)\paloptimize.obj" \ + "$(INTDIR)\yuv.obj" \ + "$(INTDIR)\bitmap.obj" \ + "$(INTDIR)\bitmap_blitdata.obj" \ + "$(INTDIR)\bitmap_gamma.obj" \ + "$(INTDIR)\pixelformat.obj" \ + "$(INTDIR)\A_CORONA.obj" \ + "$(INTDIR)\A_STREAK.obj" \ + "$(INTDIR)\CORONA.obj" \ + "$(INTDIR)\electric.obj" \ + "$(INTDIR)\logo.obj" \ + "$(INTDIR)\LogoActor.obj" \ + "$(INTDIR)\streak.obj" \ + "$(INTDIR)\BitmapList.obj" \ + "$(INTDIR)\engine.obj" \ + "$(INTDIR)\fontbmp.obj" \ + "$(INTDIR)\System.obj" \ + "$(INTDIR)\Entities.obj" \ + "$(INTDIR)\Box.obj" \ + "$(INTDIR)\crc32.obj" \ + "$(INTDIR)\ExtBox.obj" \ + "$(INTDIR)\quatern.obj" \ + "$(INTDIR)\Vec3d.obj" \ + "$(INTDIR)\Xform3d.obj" \ + "$(INTDIR)\Errorlog.obj" \ + "$(INTDIR)\geAssert.obj" \ + "$(INTDIR)\log.obj" \ + "$(INTDIR)\mempool.obj" \ + "$(INTDIR)\Ram.obj" \ + "$(INTDIR)\ramdll.obj" \ + "$(INTDIR)\dirtree.obj" \ + "$(INTDIR)\fsdos.obj" \ + "$(INTDIR)\Fsmemory.obj" \ + "$(INTDIR)\fsvfs.obj" \ + "$(INTDIR)\vfile.obj" \ + "$(INTDIR)\Fog.obj" \ + "$(INTDIR)\Frustum.obj" \ + "$(INTDIR)\Gbspfile.obj" \ + "$(INTDIR)\Light.obj" \ + "$(INTDIR)\Plane.obj" \ + "$(INTDIR)\Surface.obj" \ + "$(INTDIR)\Trace.obj" \ + "$(INTDIR)\User.obj" \ + "$(INTDIR)\Vis.obj" \ + "$(INTDIR)\WBitmap.obj" \ + "$(INTDIR)\World.obj" \ + "$(INTDIR)\font.obj" \ + "$(INTDIR)\wgClip.obj" \ + "$(INTDIR)\matrix33.obj" \ + "$(INTDIR)\PhysicsJoint.obj" \ + "$(INTDIR)\PhysicsObject.obj" \ + "$(INTDIR)\PhysicsSystem.obj" \ + "$(INTDIR)\Camera.obj" \ + "$(INTDIR)\CSNetMgr.obj" \ + "$(INTDIR)\Ge.obj" \ + "$(INTDIR)\list.obj" \ + "$(INTDIR)\Netplay.obj" \ + "$(INTDIR)\Sound.obj" \ + "$(INTDIR)\Sound3d.obj" \ + "$(INTDIR)\Tclip.obj" \ + "$(INTDIR)\timer.obj" \ + "$(INTDIR)\tsc.obj" \ + "$(INTDIR)\genesis.res" \ + "..\Sdk\Dx6sdk\Lib\dxguid.lib" \ + "$(INTDIR)\WebUrl.obj" + +"$(OUTDIR)\Genesis.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +IntDir=.\ReleaseDLL +OutDir=.\ReleaseDLL +InputPath=.\ReleaseDLL\Genesis.dll +SOURCE="$(InputPath)" + +"$(OUTDIR)\genesisi.lib" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + < +#include +#include + +#include "Box.h" + + +///////////////////////////////////////////////////////////////////// +// geBox_ functions + + +// Box needs to know what its axes are like in world space +// this involves a simplified rotation of the Box's local +// frame axes into global coord system + +static void geBox_ComputeGlobalFrameAxes(geBox* Box) +{ + geBoolean isOrthonormal; + + assert(Box != NULL); + + isOrthonormal = geXForm3d_IsOrthonormal(&(Box->Transform)); + assert(isOrthonormal); + + Box->GlobalFrameAxes[0].X = Box->Transform.AX * Box->xScale; + Box->GlobalFrameAxes[0].Y = Box->Transform.BX * Box->xScale; + Box->GlobalFrameAxes[0].Z = Box->Transform.CX * Box->xScale; + + Box->GlobalFrameAxes[1].X = Box->Transform.AY * Box->yScale; + Box->GlobalFrameAxes[1].Y = Box->Transform.BY * Box->yScale; + Box->GlobalFrameAxes[1].Z = Box->Transform.CY * Box->yScale; + + Box->GlobalFrameAxes[2].X = Box->Transform.AZ * Box->zScale; + Box->GlobalFrameAxes[2].Y = Box->Transform.BZ * Box->zScale; + Box->GlobalFrameAxes[2].Z = Box->Transform.CZ * Box->zScale; + +} + + +// set up a Box; call when initializing an Box or when +// the Box's scale(s) change + +void geBox_Set(geBox* Box, geFloat xScale, geFloat yScale, geFloat zScale, const geXForm3d* Transform) +{ + geBoolean isOrthonormal; + + assert(Box != NULL); + assert(Transform != NULL); + + isOrthonormal = geXForm3d_IsOrthonormal(&(Box->Transform)); + assert(isOrthonormal); + + Box->xScale = xScale; + Box->yScale = yScale; + Box->zScale = zScale; + + geBox_SetXForm(Box, Transform); +} + +// set a Box's Transform + +void geBox_SetXForm(geBox* Box, const geXForm3d* Transform) +{ + geBoolean isOrthonormal; + + assert(Box != NULL); + assert(Transform != NULL); + + isOrthonormal = geXForm3d_IsOrthonormal(Transform); + assert(isOrthonormal); + + geXForm3d_Copy(Transform, &(Box->Transform)); + + isOrthonormal = geXForm3d_IsOrthonormal(&(Box->Transform)); + assert(isOrthonormal); + + geXForm3d_GetTranspose(Transform, &(Box->TransformInv)); + + isOrthonormal = geXForm3d_IsOrthonormal(&(Box->TransformInv)); + assert(isOrthonormal); + + geBox_ComputeGlobalFrameAxes(Box); +} + + +// test for Box overlap between 2 Boxs +// tests for overlap between B against A and then A against B + +geBoolean geBox_DetectCollisionBetween(const geBox* Box1, const geBox* Box2) +{ + int i, c; + geFloat radius; + const geBox* BoxA; + const geBox* BoxB; + static geVec3d centerToCenterVector, xformedCenterToCenterVector; + static geVec3d inverseXFormedGlobalFrameAxes[3]; + geBoolean isOrthonormal; + + assert(Box1 != NULL); + assert(Box2 != NULL); + + // assert orthonormality + + isOrthonormal = geXForm3d_IsOrthonormal(&(Box1->Transform)); + assert(isOrthonormal); + + isOrthonormal = geXForm3d_IsOrthonormal(&(Box2->Transform)); + assert(isOrthonormal); + + // test B against A and if necessary A against B + + for (c = 0; c < 2; c ++) + { + if (c == 0) + { + BoxA = Box1; + BoxB = Box2; + } + + else + { + BoxA = Box2; + BoxB = Box1; + } + + // rotate B's global frame axes by the amount A was rotated to bring it + // back into its local coord system + + for (i = 0; i < 3; i++) + { + geXForm3d_Rotate(&(BoxA->TransformInv), &(BoxB->GlobalFrameAxes[i]), + &inverseXFormedGlobalFrameAxes[i]); + } + + // get B's translation offset from A in global coord system + + geVec3d_Subtract(&(BoxB->Transform.Translation), &(BoxA->Transform.Translation), + ¢erToCenterVector); + + // rotate offset by the amount A was rotated to bring it + // back into its local coord system + + geXForm3d_Rotate(&(BoxA->TransformInv), ¢erToCenterVector, + &xformedCenterToCenterVector); + + xformedCenterToCenterVector.X = (geFloat)fabs(xformedCenterToCenterVector.X); + xformedCenterToCenterVector.Y = (geFloat)fabs(xformedCenterToCenterVector.Y); + xformedCenterToCenterVector.Z = (geFloat)fabs(xformedCenterToCenterVector.Z); + + // test every radius of BoxB + // for every global frame-axis-aligned axis of BoxA + // to see if overlap occurred + + // test overlap in X axis + + radius = (geFloat)(fabs(inverseXFormedGlobalFrameAxes[0].X) + + fabs(inverseXFormedGlobalFrameAxes[1].X) + + fabs(inverseXFormedGlobalFrameAxes[2].X)); + + if ((radius + BoxA->xScale) < xformedCenterToCenterVector.X) + return GE_FALSE; + + // test overlap in Y axis + + radius = (geFloat)(fabs(inverseXFormedGlobalFrameAxes[0].Y) + + fabs(inverseXFormedGlobalFrameAxes[1].Y) + + fabs(inverseXFormedGlobalFrameAxes[2].Y)); + + if ((radius + BoxA->yScale) < xformedCenterToCenterVector.Y) + return GE_FALSE; + + // test overlap in Z axis + + radius = (geFloat)(fabs(inverseXFormedGlobalFrameAxes[0].Z) + + fabs(inverseXFormedGlobalFrameAxes[1].Z) + + fabs(inverseXFormedGlobalFrameAxes[2].Z)); + + if ((radius + BoxA->zScale) < xformedCenterToCenterVector.Z) + return GE_FALSE; + + } // c + + return GE_TRUE; // all tests checked out, overlap occurred +} + diff --git a/G3D/Math/Box.h b/G3D/Math/Box.h new file mode 100644 index 0000000..a074278 --- /dev/null +++ b/G3D/Math/Box.h @@ -0,0 +1,63 @@ +/****************************************************************************************/ +/* BOX.H */ +/* */ +/* Author: Jason Wood */ +/* Description: Box is a 3D Oriented Bounding Box */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#if !defined (GE_BOX_H) +#define GE_BOX_H + +#include "Vec3d.h" +#include "XForm3d.h" + +typedef struct geBox +{ + // all member variables are **PRIVATE** + // the Box's scales along the Box's local frame axes + + geFloat xScale, yScale, zScale; + + // the Box's local frame origin lies at (0, 0, 0) in local space + // + // these are the scaled Box axes in the global frame + + geVec3d GlobalFrameAxes[3]; + + // the transformation that takes the Box's axes from local space + // to global space, and its inverse + + geXForm3d Transform, TransformInv; + +}geBox; + +///////////////////////////////////////////////////////////////////////////// +// call this to set up a Box for the first time or when the Box's +// local frame axes scale(s) change +void geBox_Set(geBox* Box, geFloat xScale, geFloat yScale, geFloat zScale, const geXForm3d* Transform); + + +// call this to set the Box's transformation matrix (does not change the +// scales of the Box's local frame axes) +void geBox_SetXForm(geBox* Box, const geXForm3d* Transform); + + +// returns GE_TRUE if the boxes overlap, GE_FALSE otherwise +geBoolean geBox_DetectCollisionBetween(const geBox* Box1, const geBox* Box2); + +#endif diff --git a/G3D/Math/ExtBox.c b/G3D/Math/ExtBox.c new file mode 100644 index 0000000..7509329 --- /dev/null +++ b/G3D/Math/ExtBox.c @@ -0,0 +1,496 @@ +/****************************************************************************************/ +/* EXTBOX.C */ +/* */ +/* Author: */ +/* Description: Axial aligned bounding box support */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "ExtBox.h" +#include + +#define MAX(aa,bb) ( ((aa)>(bb))?(aa):(bb) ) +#define MIN(aa,bb) ( ((aa)<(bb))?(aa):(bb) ) + +geBoolean GENESISCC geExtBox_IsValid( const geExtBox *B ) +{ + if (B == NULL) return GE_FALSE; + + if (geVec3d_IsValid(&(B->Min)) == GE_FALSE) + return GE_FALSE; + if (geVec3d_IsValid(&(B->Max)) == GE_FALSE) + return GE_FALSE; + + + if ( (B->Min.X <= B->Max.X) && + (B->Min.Y <= B->Max.Y) && + (B->Min.Z <= B->Max.Z) ) + return GE_TRUE; + else + return GE_FALSE; +} + +void GENESISCC geExtBox_Set( geExtBox *B, + geFloat X1,geFloat Y1,geFloat Z1, + geFloat X2,geFloat Y2,geFloat Z2) +{ + assert (B != NULL); + + //geVec3d_Set (&B->Min, MIN (x1, x2), MIN (y1, y2),MIN (z1, z2)); + //geVec3d_Set (&B->Max, MAX (x1, x2), MAX (y1, y2),MAX (z1, z2)); + + if ( X1 > X2 ) + { B->Max.X = X1; B->Min.X = X2; } + else + { B->Max.X = X2; B->Min.X = X1; } + + if ( Y1 > Y2 ) + { B->Max.Y = Y1; B->Min.Y = Y2; } + else + { B->Max.Y = Y2; B->Min.Y = Y1; } + + if ( Z1 > Z2 ) + { B->Max.Z = Z1; B->Min.Z = Z2; } + else + { B->Max.Z = Z2; B->Min.Z = Z1; } + + assert( geVec3d_IsValid(&(B->Min)) != GE_FALSE ); + assert( geVec3d_IsValid(&(B->Max)) != GE_FALSE ); + +} + +// Set box Min and Max to the passed point +void GENESISCC geExtBox_SetToPoint ( geExtBox *B, const geVec3d *Point ) +{ + assert( B != NULL ); + assert( Point != NULL ); + assert( geVec3d_IsValid(Point) != GE_FALSE ); + + + B->Max = *Point; + B->Min = *Point; +} + +// Extend a box to encompass the passed point +void GENESISCC geExtBox_ExtendToEnclose( geExtBox *B, const geVec3d *Point ) +{ + assert ( geExtBox_IsValid(B) != GE_FALSE ); + assert( Point != NULL ); + assert( geVec3d_IsValid(Point) != GE_FALSE ); + + if (Point->X > B->Max.X ) B->Max.X = Point->X; + if (Point->Y > B->Max.Y ) B->Max.Y = Point->Y; + if (Point->Z > B->Max.Z ) B->Max.Z = Point->Z; + + if (Point->X < B->Min.X ) B->Min.X = Point->X; + if (Point->Y < B->Min.Y ) B->Min.Y = Point->Y; + if (Point->Z < B->Min.Z ) B->Min.Z = Point->Z; + +} + +static geBoolean GENESISCC geExtBox_Intersects( const geExtBox *B1, const geExtBox *B2 ) +{ + assert ( geExtBox_IsValid (B1) != GE_FALSE ); + assert ( geExtBox_IsValid (B2) != GE_FALSE ); + + if ((B1->Min.X > B2->Max.X) || (B1->Max.X < B2->Min.X)) return GE_FALSE; + if ((B1->Min.Y > B2->Max.Y) || (B1->Max.Y < B2->Min.Y)) return GE_FALSE; + if ((B1->Min.Z > B2->Max.Z) || (B1->Max.Z < B2->Min.Z)) return GE_FALSE; + return GE_TRUE; +} + + + +geBoolean GENESISCC geExtBox_Intersection( const geExtBox *B1, const geExtBox *B2, geExtBox *Result ) +{ + geBoolean rslt; + + assert ( geExtBox_IsValid (B1) != GE_FALSE ); + assert ( geExtBox_IsValid (B2) != GE_FALSE ); + + rslt = geExtBox_Intersects (B1, B2); + if ( (rslt != GE_FALSE) && (Result != NULL)) + { + geExtBox_Set ( Result, + MAX (B1->Min.X, B2->Min.X), + MAX (B1->Min.Y, B2->Min.Y), + MAX (B1->Min.Z, B2->Min.Z), + MIN (B1->Max.X, B2->Max.X), + MIN (B1->Max.Y, B2->Max.Y), + MIN (B1->Max.Z, B2->Max.Z) ); + } + return rslt; +} + +void GENESISCC geExtBox_Union( const geExtBox *B1, const geExtBox *B2, geExtBox *Result ) +{ + assert ( geExtBox_IsValid (B1) != GE_FALSE ); + assert ( geExtBox_IsValid (B2) != GE_FALSE ); + assert (Result != NULL); + + geExtBox_Set ( Result, + MIN (B1->Min.X, B2->Min.X), + MIN (B1->Min.Y, B2->Min.Y), + MIN (B1->Min.Z, B2->Min.Z), + MAX (B1->Max.X, B2->Max.X), + MAX (B1->Max.Y, B2->Max.Y), + MAX (B1->Max.Z, B2->Max.Z) ); +} + +geBoolean GENESISCC geExtBox_ContainsPoint( const geExtBox *B, const geVec3d *Point ) +{ + assert (geExtBox_IsValid (B) != GE_FALSE); + assert( geVec3d_IsValid(Point) != GE_FALSE ); + + if ( (Point->X >= B->Min.X) && (Point->X <= B->Max.X) && + (Point->Y >= B->Min.Y) && (Point->Y <= B->Max.Y) && + (Point->Z >= B->Min.Z) && (Point->Z <= B->Max.Z) ) + { + return GE_TRUE; + } + else + { + return GE_FALSE; + } +} + + +void GENESISCC geExtBox_GetTranslation( const geExtBox *B, geVec3d *pCenter ) +{ + assert (geExtBox_IsValid (B) != GE_FALSE); + assert (pCenter != NULL); + + geVec3d_Set( pCenter, + (B->Min.X + B->Max.X)/2.0f, + (B->Min.Y + B->Max.Y)/2.0f, + (B->Min.Z + B->Max.Z)/2.0f ); +} + +void GENESISCC geExtBox_Translate( geExtBox *B, geFloat DX, geFloat DY, geFloat DZ ) +{ + geVec3d VecDelta; + + assert (geExtBox_IsValid (B) != GE_FALSE); + + geVec3d_Set (&VecDelta, DX, DY, DZ); + assert( geVec3d_IsValid(&VecDelta) != GE_FALSE ); + geVec3d_Add (&B->Min, &VecDelta, &B->Min); + geVec3d_Add (&B->Max, &VecDelta, &B->Max); +} + +void GENESISCC geExtBox_SetTranslation( geExtBox *B, const geVec3d *pCenter ) +{ + geVec3d Center,Translation; + + assert (geExtBox_IsValid (B) != GE_FALSE); + assert (pCenter != NULL); + assert( geVec3d_IsValid(pCenter) != GE_FALSE ); + + geExtBox_GetTranslation( B, &Center ); + geVec3d_Subtract( pCenter, &Center, &Translation); + + geExtBox_Translate( B, Translation.X, Translation.Y, Translation.Z ); +} + +void GENESISCC geExtBox_GetScaling( const geExtBox *B, geVec3d *pScale ) +{ + assert (geExtBox_IsValid (B) != GE_FALSE ); + assert (pScale != NULL); + + geVec3d_Subtract( &(B->Max), &(B->Min), pScale ); +} + +void GENESISCC geExtBox_Scale( geExtBox *B, geFloat ScaleX, geFloat ScaleY, geFloat ScaleZ ) +{ + geVec3d Center; + geVec3d Scale; + geFloat DX,DY,DZ; + + assert (geExtBox_IsValid (B) != GE_FALSE ); + assert (ScaleX >= 0.0f ); + assert (ScaleY >= 0.0f ); + assert (ScaleZ >= 0.0f ); + assert (ScaleX * ScaleX >= 0.0f ); // check for NANS + assert (ScaleY * ScaleY >= 0.0f ); + assert (ScaleZ * ScaleZ >= 0.0f ); + + geExtBox_GetTranslation( B, &Center ); + geExtBox_GetScaling ( B, &Scale ); + + DX = ScaleX * Scale.X * 0.5f; + DY = ScaleY * Scale.Y * 0.5f; + DZ = ScaleZ * Scale.Z * 0.5f; + + B->Min.X = Center.X - DX; + B->Min.Y = Center.Y - DY; + B->Min.Z = Center.Z - DZ; + + B->Max.X = Center.X + DX; + B->Max.Y = Center.Y + DY; + B->Max.Z = Center.Z + DZ; + + assert (geExtBox_IsValid (B) != GE_FALSE); +} + +void GENESISCC geExtBox_SetScaling( geExtBox *B, const geVec3d *pScale ) +{ + geVec3d Center; + geFloat DX,DY,DZ; + + assert (geExtBox_IsValid (B) != GE_FALSE ); + assert (pScale != NULL ); + assert (geVec3d_IsValid( pScale )!= GE_FALSE); + assert (pScale->X >= 0.0f ); + assert (pScale->Y >= 0.0f ); + assert (pScale->Z >= 0.0f ); + + geExtBox_GetTranslation( B, &Center ); + + DX = pScale->X / 2.0f; + DY = pScale->Y / 2.0f; + DZ = pScale->Z / 2.0f; + + B->Min.X = Center.X - DX; + B->Min.Y = Center.Y - DY; + B->Min.Z = Center.Z - DZ; + + B->Max.X = Center.X + DX; + B->Max.Y = Center.Y + DY; + B->Max.Z = Center.Z + DZ; +} + +void GENESISCC geExtBox_LinearSweep( const geExtBox *BoxToSweep, + const geVec3d *StartPoint, + const geVec3d *EndPoint, + geExtBox *EnclosingBox ) +{ + + assert (geExtBox_IsValid (BoxToSweep) != GE_FALSE ); + assert (StartPoint != NULL ); + assert (EndPoint != NULL ); + assert (geVec3d_IsValid( StartPoint )!= GE_FALSE); + assert (geVec3d_IsValid( EndPoint )!= GE_FALSE); + assert (EnclosingBox != NULL ); + + *EnclosingBox = *BoxToSweep; + + if (EndPoint->X > StartPoint->X) + { + EnclosingBox->Min.X += StartPoint->X; + EnclosingBox->Max.X += EndPoint->X; + } + else + { + EnclosingBox->Min.X += EndPoint->X; + EnclosingBox->Max.X += StartPoint->X; + } + + if (EndPoint->Y > StartPoint->Y) + { + EnclosingBox->Min.Y += StartPoint->Y; + EnclosingBox->Max.Y += EndPoint->Y; + } + else + { + EnclosingBox->Min.Y += EndPoint->Y; + EnclosingBox->Max.Y += StartPoint->Y; + } + + if (EndPoint->Z > StartPoint->Z) + { + EnclosingBox->Min.Z += StartPoint->Z; + EnclosingBox->Max.Z += EndPoint->Z; + } + else + { + EnclosingBox->Min.Z += EndPoint->Z; + EnclosingBox->Max.Z += StartPoint->Z; + } + assert (geExtBox_IsValid (EnclosingBox) != GE_FALSE ); +} + +static geBoolean GENESISCC geExtBox_XFaceDist( const geVec3d *Start, + const geVec3d *Delta, const geExtBox *B, geFloat *T, geFloat X) +{ + geFloat t; + geFloat Y,Z; + assert( Start != NULL ); + assert( Delta != NULL ); + assert( B != NULL ); + assert( T != NULL ); + + //if ( (Start->X <= X) && (X <= Delta->X + Start->X) ) + { + t = (X - Start->X)/Delta->X; + Y = Start->Y + Delta->Y * t; + if ( ( B->Min.Y <= Y) && (Y <= B->Max.Y) ) + { + Z = Start->Z + Delta->Z * t; + if ( ( B->Min.Z <= Z) && (Z <= B->Max.Z) ) + { + *T = t; + return GE_TRUE; + } + } + } + return GE_FALSE; +} + +static geBoolean GENESISCC geExtBox_YFaceDist( const geVec3d *Start, const geVec3d *Delta, const geExtBox *B, geFloat *T, geFloat Y) +{ + geFloat t; + geFloat X,Z; + assert( Start != NULL ); + assert( Delta != NULL ); + assert( B != NULL ); + assert( T != NULL ); + + //if ( (Start->Y <= Y) && (Y <= Delta->Y + Start->Y) ) + { + t = (Y - Start->Y)/Delta->Y; + Z = Start->Z + Delta->Z * t; + if ( ( B->Min.Z <= Z) && (Z <= B->Max.Z) ) + { + X = Start->X + Delta->X * t; + if ( ( B->Min.X <= X) && (X <= B->Max.X) ) + { + *T = t; + return GE_TRUE; + } + } + } + return GE_FALSE; +} + + +static geBoolean GENESISCC geExtBox_ZFaceDist( const geVec3d *Start, const geVec3d *Delta, const geExtBox *B, geFloat *T, geFloat Z) +{ + geFloat t; + geFloat X,Y; + assert( Start != NULL ); + assert( Delta != NULL ); + assert( B != NULL ); + assert( T != NULL ); + + //if ( (Start->Z <= Z) && (Z <= Delta->Z + Start->Z) ) + { + t = (Z - Start->Z)/Delta->Z; + X = Start->X + Delta->X * t; + if ( ( B->Min.X <= X) && (X <= B->Max.X) ) + { + Y = Start->Y + Delta->Y * t; + if ( ( B->Min.Y <= Y) && (Y <= B->Max.Y) ) + { + *T = t; + return GE_TRUE; + } + } + } + return GE_FALSE; +} + + + +geBoolean GENESISCC geExtBox_RayCollision( const geExtBox *B, const geVec3d *Start, const geVec3d *End, + geFloat *T, geVec3d *Normal ) +{ + // only detects rays going 'in' to the box + geFloat t; + geVec3d Delta; + geVec3d LocalNormal; + geFloat LocalT; + + assert( B != NULL ); + assert( Start != NULL ); + assert( End != NULL ); + assert (geVec3d_IsValid( Start )!= GE_FALSE); + assert (geVec3d_IsValid( End )!= GE_FALSE); + assert (geExtBox_IsValid( B )!= GE_FALSE ); + + geVec3d_Subtract(End,Start,&Delta); + + if (Normal == NULL) + Normal = &LocalNormal; + if (T == NULL) + T = &LocalT; + + // test x end of box, facing away from ray direction. + if (Delta.X > 0.0f) + { + if ( (Start->X <= B->Min.X) && (B->Min.X <= End->X) && + (geExtBox_XFaceDist( Start ,&Delta, B, &t, B->Min.X ) != GE_FALSE) ) + { + geVec3d_Set( Normal, -1.0f, 0.0f, 0.0f ); + *T = t; + return GE_TRUE; + } + } + else if (Delta.X < 0.0f) + { + if ( (End->X <= B->Max.X) && (B->Max.X <= Start->X) && + (geExtBox_XFaceDist( Start ,&Delta, B, &t, B->Max.X ) != GE_FALSE) ) + { + geVec3d_Set( Normal, 1.0f, 0.0f, 0.0f ); + *T = t; + return GE_TRUE; + } + } + + // test y end of box, facing away from ray direction. + if (Delta.Y > 0.0f) + { + if ( (Start->Y <= B->Min.Y) && (B->Min.Y <= End->Y) && + (geExtBox_YFaceDist( Start ,&Delta, B, &t, B->Min.Y ) != GE_FALSE) ) + { + geVec3d_Set( Normal, 0.0f, -1.0f, 0.0f ); + *T = t; + return GE_TRUE; + } + } + else if (Delta.Y < 0.0f) + { + if ( (End->Y <= B->Max.Y) && (B->Max.Y <= Start->Y) && + (geExtBox_YFaceDist( Start ,&Delta, B, &t, B->Max.Y ) != GE_FALSE) ) + { + geVec3d_Set( Normal, 0.0f, 1.0f, 0.0f ); + *T = t; + return GE_TRUE; + } + } + + // test z end of box, facing away from ray direction. + if (Delta.Z > 0.0f) + { + if ( (Start->Z <= B->Min.Z) && (B->Min.Z <= End->Z) && + (geExtBox_ZFaceDist( Start ,&Delta, B, &t, B->Min.Z ) != GE_FALSE) ) + { + geVec3d_Set( Normal, 0.0f, 0.0f, -1.0f ); + *T = t; + return GE_TRUE; + } + } + else if (Delta.Z < 0.0f) + { + if ( (End->Z <= B->Max.Z) && (B->Max.Z <= Start->Z) && + (geExtBox_ZFaceDist( Start ,&Delta, B, &t, B->Max.Z ) != GE_FALSE) ) + { + geVec3d_Set( Normal, 0.0f, 0.0f, 1.0f ); + *T = t; + return GE_TRUE; + } + } + return GE_FALSE; +} diff --git a/G3D/Math/ExtBox.h b/G3D/Math/ExtBox.h new file mode 100644 index 0000000..cceced4 --- /dev/null +++ b/G3D/Math/ExtBox.h @@ -0,0 +1,94 @@ +/****************************************************************************************/ +/* EXTBOX.H */ +/* */ +/* Author: */ +/* Description: Axial aligned bounding box (extent box) support */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_EXTBOX_H +#define GE_EXTBOX_H + +#include "basetype.h" +#include "vec3d.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct geExtBox +{ + geVec3d Min; + geVec3d Max; +} geExtBox; + +// Set the values in a box +void GENESISCC geExtBox_Set ( geExtBox *B, + geFloat X1, geFloat Y1, geFloat Z1, + geFloat X2, geFloat Y2, geFloat Z2 ); + +// Test a box for validity ( non NULL and max >= min ) +geBoolean GENESISCC geExtBox_IsValid( const geExtBox *B ); + +// Set box Min and Max to the passed point +void GENESISCC geExtBox_SetToPoint ( geExtBox *B, const geVec3d *Point ); + +// Extend a box to encompass the passed point +void GENESISCC geExtBox_ExtendToEnclose( geExtBox *B, const geVec3d *Point ); + +// Return result of box intersection. +// If no intersection, returns GE_FALSE and bResult is not modified. +// If intersection, returns GE_TRUE and fills bResult (if not NULL) +// with the intersected box, +// bResult may be one of b1 or b2. +// +geBoolean GENESISCC geExtBox_Intersection ( const geExtBox *B1, const geExtBox *B2, geExtBox *Result ); + +// computes union of b1 and b2 and returns in bResult. +void GENESISCC geExtBox_Union ( const geExtBox *B1, const geExtBox *B2, geExtBox *Result ); + +geBoolean GENESISCC geExtBox_ContainsPoint ( const geExtBox *B, const geVec3d *Point ); + +void GENESISCC geExtBox_GetTranslation ( const geExtBox *B, geVec3d *pCenter ); +void GENESISCC geExtBox_SetTranslation ( geExtBox *B, const geVec3d *pCenter ); +void GENESISCC geExtBox_Translate ( geExtBox *B, geFloat DX, geFloat DY, geFloat DZ ); + +void GENESISCC geExtBox_GetScaling ( const geExtBox *B, geVec3d *pScale ); +void GENESISCC geExtBox_SetScaling ( geExtBox *B, const geVec3d *pScale ); +void GENESISCC geExtBox_Scale ( geExtBox *B, geFloat DX, geFloat DY,geFloat DZ ); + +// Creates a box that encloses the entire area of a box that moves along linear path +void GENESISCC geExtBox_LinearSweep( const geExtBox *BoxToSweep, + const geVec3d *StartPoint, + const geVec3d *EndPoint, + geExtBox *EnclosingBox ); + +// Collides a ray with box B. The ray is directed, from Start to End. +// Only returns a ray hitting the outside of the box. +// on success, GE_TRUE is returned, and +// if T is non-NULL, T is returned as 0..1 where 0 is a collision at Start, and 1 is a collision at End +// if Normal is non-NULL, Normal is the surface normal of the box where the collision occured. +geBoolean GENESISCC geExtBox_RayCollision( const geExtBox *B, const geVec3d *Start, const geVec3d *End, + geFloat *T, geVec3d *Normal ); + +#ifdef __cplusplus + } +#endif + + + +#endif + diff --git a/G3D/Math/VEC3D.C b/G3D/Math/VEC3D.C new file mode 100644 index 0000000..219d5e1 --- /dev/null +++ b/G3D/Math/VEC3D.C @@ -0,0 +1,298 @@ +/****************************************************************************************/ +/* VEC3D.C */ +/* */ +/* Author: */ +/* Description: 3D Vector implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include "Vec3d.h" + +#define VCOMPARE_EPSILON (geFloat)0.0005 + +#ifdef NDEBUG +#ifdef _MSC_VER +#define ASM_NORMALIZE +#endif +#endif + +#ifndef NDEBUG +GENESISAPI geFloat GENESISCC geVec3d_GetElement(geVec3d *V, int Index) +{ + assert( V != NULL ); + assert( Index >= 0 ); + assert( Index < 3 ); + return (* ((&((V)->X)) + (Index) )); +} +#endif + +GENESISAPI geBoolean GENESISCC geVec3d_IsValid(const geVec3d *V) +{ + if (V == NULL) + return GE_FALSE; + if ((V->X * V->X) < 0.0f) + return GE_FALSE; + if ((V->Y * V->Y) < 0.0f) + return GE_FALSE; + if ((V->Z * V->Z) < 0.0f) + return GE_FALSE; + return GE_TRUE; +} + + +GENESISAPI void GENESISCC geVec3d_Set(geVec3d *V, geFloat X, geFloat Y, geFloat Z) +{ + assert ( V != NULL ); + V->X = X; + V->Y = Y; + V->Z = Z; + assert( geVec3d_IsValid(V) != GE_FALSE ); +} + +GENESISAPI void GENESISCC geVec3d_Get(const geVec3d *V, geFloat *X, geFloat *Y, geFloat *Z) +{ + assert ( V != NULL ); + assert ( X != NULL ); + assert ( Y != NULL ); + assert ( Z != NULL ); + assert( geVec3d_IsValid(V) != GE_FALSE ); + + *X = V->X; + *Y = V->Y; + *Z = V->Z; +} + + +GENESISAPI geFloat GENESISCC geVec3d_DotProduct(const geVec3d *V1, const geVec3d *V2) +{ + assert ( V1 != NULL ); + assert ( V2 != NULL ); + assert( geVec3d_IsValid(V1) != GE_FALSE ); + assert( geVec3d_IsValid(V2) != GE_FALSE ); + + return(V1->X*V2->X + V1->Y*V2->Y + V1->Z*V2->Z); +} + +GENESISAPI void GENESISCC geVec3d_CrossProduct(const geVec3d *V1, const geVec3d *V2, geVec3d *VResult) +{ + geVec3d Result; + assert ( V1 != NULL ); + assert ( V2 != NULL ); + assert ( VResult != NULL ); + assert( geVec3d_IsValid(V1) != GE_FALSE ); + assert( geVec3d_IsValid(V2) != GE_FALSE ); + + Result.X = V1->Y*V2->Z - V1->Z*V2->Y; + Result.Y = V1->Z*V2->X - V1->X*V2->Z; + Result.Z = V1->X*V2->Y - V1->Y*V2->X; + + *VResult = Result; +} + +GENESISAPI geBoolean GENESISCC geVec3d_Compare(const geVec3d *V1, const geVec3d *V2, geFloat Tolerance) +{ + assert ( V1 != NULL ); + assert ( V2 != NULL ); + assert ( Tolerance >= 0.0 ); + assert( geVec3d_IsValid(V1) != GE_FALSE ); + assert( geVec3d_IsValid(V2) != GE_FALSE ); + + if (fabs(V2->X - V1->X) > Tolerance) //VCOMPARE_EPSILON) + return GE_FALSE; + if (fabs(V2->Y - V1->Y) > Tolerance) //VCOMPARE_EPSILON) + return GE_FALSE; + if (fabs(V2->Z - V1->Z) > Tolerance) //VCOMPARE_EPSILON) + return GE_FALSE; + + return GE_TRUE; +} + +#ifdef ASM_NORMALIZE + +GENESISAPI geFloat GENESISCC geVec3d_Normalize(geVec3d *V1) +{ +geFloat *fPtr; +geFloat Dist,OneOverDist; + + fPtr = (geFloat *)V1; + Dist = (*fPtr) * (*fPtr); fPtr++; + Dist += (*fPtr) * (*fPtr); fPtr++; + Dist += (*fPtr) * (*fPtr); + + // Vtune shows the geFloat <-> double conversions + // required for the clib sqrt() are taking a lot of time. + // hence we use asm to access the geFloat fsqrt() directly + + __asm + { + FLD Dist + FSQRT + FSTP Dist + } + + if ( Dist == 0.0f ) + return 0.0f; + + OneOverDist = 1.0f/Dist; + + fPtr = (geFloat *)V1; + *fPtr *= OneOverDist; fPtr++; + *fPtr *= OneOverDist; fPtr++; + *fPtr *= OneOverDist; + +return (geFloat)Dist; +} +#else +GENESISAPI geFloat GENESISCC geVec3d_Normalize(geVec3d *V1) +{ + geFloat OneOverDist; + geFloat Dist; + + assert( geVec3d_IsValid(V1) != GE_FALSE ); + + Dist = (geFloat)sqrt(geVec3d_DotProduct(V1, V1)); + + if (Dist == 0.0) + return 0.0f; + OneOverDist = 1.0f/Dist; + + V1->X *= OneOverDist; + V1->Y *= OneOverDist; + V1->Z *= OneOverDist; + + return Dist; +} +#endif // ASM_NORMALIZE + +GENESISAPI geBoolean GENESISCC geVec3d_IsNormalized(const geVec3d *V) +{ + geFloat length; + + assert( geVec3d_IsValid(V) != GE_FALSE ); + + length = geVec3d_Length(V); + if ((length >= 1.0f - VCOMPARE_EPSILON) && (length <= 1.0f + VCOMPARE_EPSILON)) + return GE_TRUE; + + return GE_FALSE; +} + +GENESISAPI void GENESISCC geVec3d_Scale(const geVec3d *VSrc, geFloat Scale, geVec3d *VDst) +{ + assert ( VDst != NULL ); + assert( geVec3d_IsValid(VSrc) != GE_FALSE ); + + VDst->X = VSrc->X * Scale; + VDst->Y = VSrc->Y * Scale; + VDst->Z = VSrc->Z * Scale; + assert( geVec3d_IsValid(VDst) != GE_FALSE ); +} + +GENESISAPI geFloat GENESISCC geVec3d_LengthSquared(const geVec3d *V1) +{ + return geVec3d_DotProduct(V1, V1); +} + +GENESISAPI geFloat GENESISCC geVec3d_Length(const geVec3d *V1) +{ + assert( geVec3d_IsValid(V1) != GE_FALSE ); + + return (geFloat)sqrt(geVec3d_DotProduct(V1, V1)); +} + +GENESISAPI void GENESISCC geVec3d_Subtract(const geVec3d *V1, const geVec3d *V2, geVec3d *V1MinusV2) +{ + assert( geVec3d_IsValid(V1) != GE_FALSE ); + assert( geVec3d_IsValid(V2) != GE_FALSE ); + assert ( V1MinusV2 != NULL ); + + V1MinusV2->X = V1->X - V2->X; + V1MinusV2->Y = V1->Y - V2->Y; + V1MinusV2->Z = V1->Z - V2->Z; +} + +GENESISAPI void GENESISCC geVec3d_Add(const geVec3d *V1, const geVec3d *V2, geVec3d *V1PlusV2) +{ + assert( geVec3d_IsValid(V1) != GE_FALSE ); + assert( geVec3d_IsValid(V2) != GE_FALSE ); + assert ( V1PlusV2 != NULL ); + + V1PlusV2->X = V1->X + V2->X; + V1PlusV2->Y = V1->Y + V2->Y; + V1PlusV2->Z = V1->Z + V2->Z; +} + +GENESISAPI void GENESISCC geVec3d_MA(geVec3d *V1, geFloat Scale, const geVec3d *V2, geVec3d *V1PlusV2Scaled) +{ + assert( geVec3d_IsValid(V1) != GE_FALSE ); + assert( geVec3d_IsValid(V2) != GE_FALSE ); + assert ( V1PlusV2Scaled != NULL ); + + V1PlusV2Scaled->X = V1->X + V2->X*Scale; + V1PlusV2Scaled->Y = V1->Y + V2->Y*Scale; + V1PlusV2Scaled->Z = V1->Z + V2->Z*Scale; +} + +GENESISAPI void GENESISCC geVec3d_AddScaled(const geVec3d *V1, const geVec3d *V2, geFloat Scale, geVec3d *V1PlusV2Scaled) +{ + assert( geVec3d_IsValid(V1) != GE_FALSE ); + assert( geVec3d_IsValid(V2) != GE_FALSE ); + assert ( V1PlusV2Scaled != NULL ); + + V1PlusV2Scaled->X = V1->X + V2->X*Scale; + V1PlusV2Scaled->Y = V1->Y + V2->Y*Scale; + V1PlusV2Scaled->Z = V1->Z + V2->Z*Scale; +} + +GENESISAPI void GENESISCC geVec3d_Copy(const geVec3d *VSrc, geVec3d *VDst) +{ + assert ( VDst != NULL ); + assert( geVec3d_IsValid(VSrc) != GE_FALSE ); + + *VDst = *VSrc; +} + +GENESISAPI void GENESISCC geVec3d_Clear(geVec3d *V) +{ + assert ( V != NULL ); + + V->X = 0.0f; + V->Y = 0.0f; + V->Z = 0.0f; +} + +GENESISAPI void GENESISCC geVec3d_Inverse(geVec3d *V) +{ + assert( geVec3d_IsValid(V) != GE_FALSE ); + + V->X = -V->X; + V->Y = -V->Y; + V->Z = -V->Z; +} + +GENESISAPI geFloat GENESISCC geVec3d_DistanceBetween(const geVec3d *V1, const geVec3d *V2) // returns length of V1-V2 +{ + geVec3d B; + + assert( geVec3d_IsValid(V1) != GE_FALSE ); + assert( geVec3d_IsValid(V2) != GE_FALSE ); + + geVec3d_Subtract(V1,V2,&B); + return geVec3d_Length(&B); +} + diff --git a/G3D/Math/VEC3D.H b/G3D/Math/VEC3D.H new file mode 100644 index 0000000..ed1f240 --- /dev/null +++ b/G3D/Math/VEC3D.H @@ -0,0 +1,70 @@ +/****************************************************************************************/ +/* VEC3D.H */ +/* */ +/* Author: */ +/* Description: 3D Vector interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_VEC3D_H +#define GE_VEC3D_H + +#include "basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + geFloat X, Y, Z; +} geVec3d; + +#ifndef NDEBUG +GENESISAPI geFloat GENESISCC geVec3d_GetElement(geVec3d *V, int Index); +#else + #define geVec3d_GetElement(Vector,Index) (* ((&((Vector)->X)) + (Index) )) +#endif + +GENESISAPI void GENESISCC geVec3d_Set(geVec3d *V, geFloat X, geFloat Y, geFloat Z); +GENESISAPI void GENESISCC geVec3d_Get(const geVec3d *V, geFloat *X, geFloat *Y, geFloat *Z); + +GENESISAPI geFloat GENESISCC geVec3d_DotProduct(const geVec3d *V1, const geVec3d *V2); +GENESISAPI void GENESISCC geVec3d_CrossProduct(const geVec3d *V1, const geVec3d *V2, geVec3d *VResult); +GENESISAPI geBoolean GENESISCC geVec3d_Compare(const geVec3d *V1, const geVec3d *V2,geFloat tolarance); +GENESISAPI geFloat GENESISCC geVec3d_Normalize(geVec3d *V1); +GENESISAPI geBoolean GENESISCC geVec3d_IsNormalized(const geVec3d *V); +GENESISAPI void GENESISCC geVec3d_Scale(const geVec3d *VSrc, geFloat Scale, geVec3d *VDst); +GENESISAPI geFloat GENESISCC geVec3d_Length(const geVec3d *V1); +GENESISAPI geFloat GENESISCC geVec3d_LengthSquared(const geVec3d *V1); +GENESISAPI void GENESISCC geVec3d_Subtract(const geVec3d *V1, const geVec3d *V2, geVec3d *V1MinusV2); +GENESISAPI void GENESISCC geVec3d_Add(const geVec3d *V1, const geVec3d *V2, geVec3d *VSum); +GENESISAPI void GENESISCC geVec3d_Copy(const geVec3d *Vsrc, geVec3d *Vdst); +GENESISAPI void GENESISCC geVec3d_Clear(geVec3d *V); +GENESISAPI void GENESISCC geVec3d_Inverse(geVec3d *V); +GENESISAPI void GENESISCC geVec3d_MA(geVec3d *V1, geFloat Scale, const geVec3d *V2, geVec3d *V1PlusV2Scaled); +GENESISAPI void GENESISCC geVec3d_AddScaled(const geVec3d *V1, const geVec3d *V2, geFloat Scale, geVec3d *V1PlusV2Scaled); + +GENESISAPI geFloat GENESISCC geVec3d_DistanceBetween(const geVec3d *V1, const geVec3d *V2); // returns length of V1-V2 + +GENESISAPI geBoolean GENESISCC geVec3d_IsValid(const geVec3d *V); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Math/Xform3d.c b/G3D/Math/Xform3d.c new file mode 100644 index 0000000..f1adcca --- /dev/null +++ b/G3D/Math/Xform3d.c @@ -0,0 +1,848 @@ +/****************************************************************************************/ +/* XFORM3D.C */ +/* */ +/* Author: */ +/* Description: 3D transform implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "XForm3d.h" + + +#ifndef NDEBUG + static geXForm3d_MaximalAssertionMode = GE_TRUE; + #define geXForm3d_Assert if (geXForm3d_MaximalAssertionMode) assert + +GENESISAPI void GENESISCC geXForm3d_SetMaximalAssertionMode( geBoolean Enable ) + { + assert( (Enable == GE_TRUE) || (Enable == GE_FALSE) ); + geXForm3d_MaximalAssertionMode = Enable; + } +#else + #define geXForm3d_Assert assert +#endif + + +GENESISAPI geBoolean GENESISCC geXForm3d_IsValid(const geXForm3d *M) + // returns GE_TRUE if M is 'valid' + // 'valid' means that M is non NULL, and there are no NAN's in the matrix. +{ + + if (M == NULL) + return GE_FALSE; + if (geVec3d_IsValid(&(M->Translation)) == GE_FALSE) + return GE_FALSE; + + if ((M->AX * M->AX) < 0.0f) + return GE_FALSE; + if ((M->AY * M->AY) < 0.0f) + return GE_FALSE; + if ((M->AZ * M->AZ) < 0.0f) + return GE_FALSE; + + if ((M->BX * M->BX) < 0.0f) + return GE_FALSE; + if ((M->BY * M->BY) < 0.0f) + return GE_FALSE; + if ((M->BZ * M->BZ) < 0.0f) + return GE_FALSE; + + if ((M->CX * M->CX) < 0.0f) + return GE_FALSE; + if ((M->CY * M->CY) < 0.0f) + return GE_FALSE; + if ((M->CZ * M->CZ) < 0.0f) + return GE_FALSE; + return GE_TRUE; +} + + +//MRB BEGIN +GENESISAPI geBoolean GENESISCC geXForm3d_IsIdentity(const geXForm3d *M) + // returns GE_TRUE if M is an identity matrix +{ + assert( M != NULL ); + + return ( M->Translation.X == 0.0f + && M->Translation.Y == 0.0f + && M->Translation.Z == 0.0f + && M->AX == 1.0f + && M->AY == 0.0f + && M->AZ == 0.0f + && M->BX == 0.0f + && M->BY == 1.0f + && M->BZ == 0.0f + && M->CX == 0.0f + && M->CY == 0.0f + && M->CZ == 1.0f ); +} +//MRB END + + + +GENESISAPI void GENESISCC geXForm3d_SetIdentity(geXForm3d *M) + // sets M to an identity matrix (clears it) +{ + assert( M != NULL ); + + M->AX = M->BY = M->CZ = 1.0f; + M->AY = M->AZ = M->BX = M->BZ = M->CX = M->CY = 0.0f; + M->Translation.X = M->Translation.Y = M->Translation.Z = 0.0f; + + geXForm3d_Assert ( geXForm3d_IsOrthonormal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_SetXRotation(geXForm3d *M,geFloat RadianAngle) + // sets up a transform that rotates RadianAngle about X axis +{ + geFloat Cos,Sin; + assert( M != NULL ); + assert( RadianAngle * RadianAngle >= 0.0f ); + + Cos = (geFloat)cos(RadianAngle); + Sin = (geFloat)sin(RadianAngle); + M->BY = Cos; + M->BZ = -Sin; + M->CY = Sin; + M->CZ = Cos; + M->AX = 1.0f; + M->AY = M->AZ = M->BX = M->CX = 0.0f; + M->Translation.X = M->Translation.Y = M->Translation.Z = 0.0f; + + geXForm3d_Assert ( geXForm3d_IsOrthonormal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_SetYRotation(geXForm3d *M,geFloat RadianAngle) + // sets up a transform that rotates RadianAngle about Y axis +{ + geFloat Cos,Sin; + assert( M != NULL ); + assert( RadianAngle * RadianAngle >= 0.0f ); + + Cos = (geFloat)cos(RadianAngle); + Sin = (geFloat)sin(RadianAngle); + + M->AX = Cos; + M->AZ = Sin; + M->CX = -Sin; + M->CZ = Cos; + M->BY = 1.0f; + M->AY = M->BX = M->BZ = M->CY = 0.0f; + M->Translation.X = M->Translation.Y = M->Translation.Z = 0.0f; + + + geXForm3d_Assert ( geXForm3d_IsOrthonormal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_SetZRotation(geXForm3d *M,geFloat RadianAngle) + // sets up a transform that rotates RadianAngle about Z axis +{ + geFloat Cos,Sin; + assert( M != NULL ); + assert( RadianAngle * RadianAngle >= 0.0f ); + + Cos = (geFloat)cos(RadianAngle); + Sin = (geFloat)sin(RadianAngle); + + M->AX = Cos; + M->AY = -Sin; + M->BX = Sin; + M->BY = Cos; + M->CZ = 1.0f; + M->AZ = M->BZ = M->CX = M->CY = 0.0f; + M->Translation.X = M->Translation.Y = M->Translation.Z = 0.0f; + + + geXForm3d_Assert ( geXForm3d_IsOrthonormal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_SetTranslation(geXForm3d *M,geFloat x, geFloat y, geFloat z) + // sets up a transform that translates x,y,z +{ + assert( M != NULL ); + + M->Translation.X = x; + M->Translation.Y = y; + M->Translation.Z = z; + assert( geVec3d_IsValid(&M->Translation)!=GE_FALSE); + + M->AX = M->BY = M->CZ = 1.0f; + M->AY = M->AZ = 0.0f; + M->BX = M->BZ = 0.0f; + M->CX = M->CY = 0.0f; + + + geXForm3d_Assert ( geXForm3d_IsOrthonormal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_SetScaling(geXForm3d *M,geFloat x, geFloat y, geFloat z) + // sets up a transform that scales by x,y,z +{ + assert( M != NULL ); + assert( x * x >= 0.0f); + assert( y * y >= 0.0f); + assert( z * z >= 0.0f); + assert( x > GEXFORM3D_MINIMUM_SCALE ); + assert( y > GEXFORM3D_MINIMUM_SCALE ); + assert( z > GEXFORM3D_MINIMUM_SCALE ); + + M->AX = x; + M->BY = y; + M->CZ = z; + + M->AY = M->AZ = 0.0f; + M->BX = M->BZ = 0.0f; + M->CX = M->CY = 0.0f; + M->Translation.X = M->Translation.Y = M->Translation.Z = 0.0f; + + + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_RotateX(geXForm3d *M,geFloat RadianAngle) + // Rotates M by RadianAngle about X axis +{ + geXForm3d R; + assert( M != NULL ); + assert( RadianAngle * RadianAngle >= 0.0f ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + geXForm3d_SetXRotation(&R,RadianAngle); + geXForm3d_Multiply(&R, M, M); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_RotateY(geXForm3d *M,geFloat RadianAngle) + // Rotates M by RadianAngle about Y axis +{ + geXForm3d R; + assert( M != NULL ); + assert( RadianAngle * RadianAngle >= 0.0f ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + geXForm3d_SetYRotation(&R,RadianAngle); + geXForm3d_Multiply(&R, M, M); + + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_RotateZ(geXForm3d *M,geFloat RadianAngle) + // Rotates M by RadianAngle about Z axis +{ + geXForm3d R; + assert( M != NULL ); + assert( RadianAngle * RadianAngle >= 0.0f ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + geXForm3d_SetZRotation(&R,RadianAngle); + geXForm3d_Multiply(&R, M, M); + + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); +} + + +GENESISAPI void GENESISCC geXForm3d_Translate(geXForm3d *M,geFloat x, geFloat y, geFloat z) + // Translates M by x,y,z +{ + geXForm3d T; + assert( M != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + geXForm3d_SetTranslation(&T,x,y,z); + geXForm3d_Multiply(&T, M, M); + + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_Scale(geXForm3d *M,geFloat x, geFloat y, geFloat z) + // Scales M by x,y,z +{ + geXForm3d S; + assert( M != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + geXForm3d_SetScaling(&S,x,y,z); + geXForm3d_Multiply(&S, M, M); + + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_Multiply( + const geXForm3d *M1, + const geXForm3d *M2, + geXForm3d *MProduct) + // MProduct = matrix multiply of M1*M2 +{ + geXForm3d M1L; + geXForm3d M2L; + + assert( M1 != NULL ); + assert( M2 != NULL ); + assert( MProduct != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M1) == GE_TRUE ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M2) == GE_TRUE ); + + M1L = *M1; + M2L = *M2; + + MProduct->AX = M1L.AX * M2L.AX; + MProduct->AX += M1L.AY * M2L.BX; + MProduct->AX += M1L.AZ * M2L.CX; + + MProduct->AY = M1L.AX * M2L.AY; + MProduct->AY += M1L.AY * M2L.BY; + MProduct->AY += M1L.AZ * M2L.CY; + + MProduct->AZ = M1L.AX * M2L.AZ; + MProduct->AZ += M1L.AY * M2L.BZ; + MProduct->AZ += M1L.AZ * M2L.CZ; + + MProduct->BX = M1L.BX * M2L.AX; + MProduct->BX += M1L.BY * M2L.BX; + MProduct->BX += M1L.BZ * M2L.CX; + + MProduct->BY = M1L.BX * M2L.AY; + MProduct->BY += M1L.BY * M2L.BY; + MProduct->BY += M1L.BZ * M2L.CY; + + MProduct->BZ = M1L.BX * M2L.AZ; + MProduct->BZ += M1L.BY * M2L.BZ; + MProduct->BZ += M1L.BZ * M2L.CZ; + + MProduct->CX = M1L.CX * M2L.AX; + MProduct->CX += M1L.CY * M2L.BX; + MProduct->CX += M1L.CZ * M2L.CX; + + MProduct->CY = M1L.CX * M2L.AY; + MProduct->CY += M1L.CY * M2L.BY; + MProduct->CY += M1L.CZ * M2L.CY; + + MProduct->CZ = M1L.CX * M2L.AZ; + MProduct->CZ += M1L.CY * M2L.BZ; + MProduct->CZ += M1L.CZ * M2L.CZ; + + MProduct->Translation.X = M1L.AX * M2L.Translation.X; + MProduct->Translation.X += M1L.AY * M2L.Translation.Y; + MProduct->Translation.X += M1L.AZ * M2L.Translation.Z; + MProduct->Translation.X += M1L.Translation.X; + + MProduct->Translation.Y = M1L.BX * M2L.Translation.X; + MProduct->Translation.Y += M1L.BY * M2L.Translation.Y; + MProduct->Translation.Y += M1L.BZ * M2L.Translation.Z; + MProduct->Translation.Y += M1L.Translation.Y; + + MProduct->Translation.Z = M1L.CX * M2L.Translation.X; + MProduct->Translation.Z += M1L.CY * M2L.Translation.Y; + MProduct->Translation.Z += M1L.CZ * M2L.Translation.Z; + MProduct->Translation.Z += M1L.Translation.Z; + + geXForm3d_Assert ( geXForm3d_IsOrthogonal(MProduct) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_Transform( + const geXForm3d *M, + const geVec3d *V, + geVec3d *Result) + // Result is Matrix M * Vector V: V Tranformed by M +{ + geVec3d VL; + assert( M != NULL ); + assert( geVec3d_IsValid(V)!=GE_FALSE); + + assert( Result != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + VL = *V; + + Result->X = (VL.X * M->AX) + (VL.Y * M->AY) + (VL.Z * M->AZ) + M->Translation.X; + Result->Y = (VL.X * M->BX) + (VL.Y * M->BY) + (VL.Z * M->BZ) + M->Translation.Y; + Result->Z = (VL.X * M->CX) + (VL.Y * M->CY) + (VL.Z * M->CZ) + M->Translation.Z; + geXForm3d_Assert( geVec3d_IsValid(Result)!=GE_FALSE); + +} + + +//======================================================================================== +// geXForm3d_TransformArray +// Assembly version +//======================================================================================== +GENESISAPI void GENESISCC geXForm3d_TransformArray(const geXForm3d *XForm, const geVec3d *Source, geVec3d *Dest, int32 Count) +{ + #define FSIZE 4 + static int32 Lookup[]={0x696C6345,0x21657370}; + assert( XForm != NULL ); + assert( Source != NULL ); + assert( Dest != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(XForm) == GE_TRUE ); + + + if (Count <= 0) // Early out if possible + return; + + _asm + { + mov ecx,Count // get item count + mov esi,Source // get source array pointer + mov ebx,Dest // get dest array pointer + mov edi,XForm // point to matrix + imul ecx,ecx,3*FSIZE // ecx is size of array + add esi,ecx // esi points to source end + add ebx,ecx // edi pointe to dest end + neg ecx // ecx ready for count-up + +Again: + // Multiply + fld dword ptr [esi+ecx+0*FSIZE] // 1;i1 + fmul dword ptr [edi+(0+0*3)*FSIZE] // 1;m11 + fld dword ptr [esi+ecx+1*FSIZE] // 1;m11 i2 + fmul dword ptr [edi+(1+0*3)*FSIZE] // 1;m11 m12 + fld dword ptr [esi+ecx+2*FSIZE] // 1;m11 m12 i3 + fmul dword ptr [edi+(2+0*3)*FSIZE] // 1;m11 m12 m13 + fxch st(1) // 0;m11 m13 m12 + faddp st(2),st // 1;s1a m13 + fld dword ptr [esi+ecx+0*FSIZE] // 1;s1a m13 i1 + fmul dword ptr [edi+(0+1*3)*FSIZE] // 1;s1a m13 m21 + fxch st(1) // 0;s1a m21 m13 + faddp st(2),st // 1;s1b m21 + fld dword ptr [esi+ecx+1*FSIZE] // 1;s1b m21 i2 + fmul dword ptr [edi+(1+1*3)*FSIZE] // 1;s1b m21 m22 + fld dword ptr [esi+ecx+2*FSIZE] // 1;s1b m21 m22 i3 + fmul dword ptr [edi+(2+1*3)*FSIZE] // 1;s1b m21 m22 m23 + fxch st(1) // 0;s1b m21 m23 m22 + faddp st(2),st // 1;s1b s2a m23 + fld dword ptr [esi+ecx+0*FSIZE] // 1;s1b s2a m23 i1 + fmul dword ptr [edi+(0+2*3)*FSIZE] // 1;s1b s2a m23 m31 + fxch st(1) // 0;s1b s2a m31 m23 + faddp st(2),st // 1;s1b s2b m31 + fld dword ptr [esi+ecx+1*FSIZE] // 1;s1b s2b m31 i2 + fmul dword ptr [edi+(1+2*3)*FSIZE] // 1;s1b s2b m31 m32 + fld dword ptr [esi+ecx+2*FSIZE] // 1;s1b s2b m31 m32 i3 + fmul dword ptr [edi+(2+2*3)*FSIZE] // 1;s1b s2b m31 m32 m33 + // Add translation + fxch st(1) // 0;s1b s2b m31 m33 m32 + faddp st(2),st // 1;s1b s2b s3a m33 + fxch st(3) // 0;m33 s2b s3a s1b + fadd dword ptr [edi+(9+0)*FSIZE] // 1;m33 s2b s3a s1c + fxch st(1) // 0;m33 s2b s1c s3a + faddp st(3),st // 1;s3b s2b s1c + fxch st(1) // 0;s3b s1c s2b + fadd dword ptr [edi+(9+1)*FSIZE] // 1;s3b s1c s2c + fxch st(2) // 0;s2c s1c s3b + fadd dword ptr [edi+(9+2)*FSIZE] // 1;s2c s1c s3c + fxch st(1) // 0;s2c s3c s1c + fstp dword ptr [ebx+ecx+0*FSIZE] // 2;s2c s3c + fxch st(1) // 0;s3c s2c + fstp dword ptr [ebx+ecx+1*FSIZE] // 2;s3c + fstp dword ptr [ebx+ecx+2*FSIZE] // 2; + add ecx,3*FSIZE // 1; + + cmp ecx, 0 + jne Again + } + + // 34 cycles predicted (per loop) + // 39 cycles measured +} + +GENESISAPI void GENESISCC geXForm3d_Rotate( + const geXForm3d *M, + const geVec3d *V, + geVec3d *Result) + // Result is Matrix M * Vector V: V Rotated by M (no translation) +{ + geVec3d VL; + assert( M != NULL ); + assert( Result != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + assert( geVec3d_IsValid(V)!=GE_FALSE); + + VL = *V; + + Result->X = (VL.X * M->AX) + (VL.Y * M->AY) + (VL.Z * M->AZ); + Result->Y = (VL.X * M->BX) + (VL.Y * M->BY) + (VL.Z * M->BZ); + Result->Z = (VL.X * M->CX) + (VL.Y * M->CY) + (VL.Z * M->CZ); + geXForm3d_Assert( geVec3d_IsValid(Result)!=GE_FALSE); +} + + +GENESISAPI void GENESISCC geXForm3d_GetLeft(const geXForm3d *M, geVec3d *Left) + // Gets a vector that is 'left' in the frame of reference of M (facing -Z) +{ + assert( M != NULL ); + assert( Left != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + Left->X = -M->AX; + Left->Y = -M->BX; + Left->Z = -M->CX; + geXForm3d_Assert( geVec3d_IsValid(Left)!=GE_FALSE); +} + +GENESISAPI void GENESISCC geXForm3d_GetUp(const geXForm3d *M, geVec3d *Up) + // Gets a vector that is 'up' in the frame of reference of M (facing -Z) +{ + assert( M != NULL ); + assert( Up != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + Up->X = M->AY; + Up->Y = M->BY; + Up->Z = M->CY; + geXForm3d_Assert( geVec3d_IsValid(Up)!=GE_FALSE); +} + +GENESISAPI void GENESISCC geXForm3d_GetIn(const geXForm3d *M, geVec3d *In) + // Gets a vector that is 'in' in the frame of reference of M (facing -Z) +{ + assert( M != NULL ); + assert( In != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + In->X = -M->AZ; + In->Y = -M->BZ; + In->Z = -M->CZ; + geXForm3d_Assert( geVec3d_IsValid(In)!=GE_FALSE); +} + +GENESISAPI void GENESISCC geXForm3d_GetTranspose(const geXForm3d *M, geXForm3d *MInv) +{ + geXForm3d M1; + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + M1 = *M; + + MInv->AX = M1.AX; + MInv->AY = M1.BX; + MInv->AZ = M1.CX; + + MInv->BX = M1.AY; + MInv->BY = M1.BY; + MInv->BZ = M1.CY; + + MInv->CX = M1.AZ; + MInv->CY = M1.BZ; + MInv->CZ = M1.CZ; + + MInv->Translation.X = 0.0f; + MInv->Translation.Y = 0.0f; + MInv->Translation.Z = 0.0f; + + { + geXForm3d T; + geXForm3d_SetTranslation(&T,-M1.Translation.X,-M1.Translation.Y,-M1.Translation.Z); + geXForm3d_Multiply(MInv,&T,MInv); + } + + geXForm3d_Assert ( geXForm3d_IsOrthogonal(MInv) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_TransposeTransform( + const geXForm3d *M, + const geVec3d *V, + geVec3d *Result) + // applies the Transpose transform of M to V. Result = (M^T) * V +{ + geVec3d V1; + + assert( M != NULL ); + assert( geVec3d_IsValid(V)!=GE_FALSE); + + assert( Result != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(M) == GE_TRUE ); + + V1.X = V->X - M->Translation.X; + V1.Y = V->Y - M->Translation.Y; + V1.Z = V->Z - M->Translation.Z; + + Result->X = (V1.X * M->AX) + (V1.Y * M->BX) + (V1.Z * M->CX); + Result->Y = (V1.X * M->AY) + (V1.Y * M->BY) + (V1.Z * M->CY); + Result->Z = (V1.X * M->AZ) + (V1.Y * M->BZ) + (V1.Z * M->CZ); + geXForm3d_Assert( geVec3d_IsValid(Result)!=GE_FALSE); +} + + +GENESISAPI void GENESISCC geXForm3d_Copy( + const geXForm3d *Src, + geXForm3d *Dst) +{ + assert( Src != NULL ); + assert( Dst != NULL ); + geXForm3d_Assert ( geXForm3d_IsOrthogonal(Src) == GE_TRUE ); + + *Dst = *Src; +} + +GENESISAPI void GENESISCC geXForm3d_GetEulerAngles(const geXForm3d *M, geVec3d *Angles) + // order of angles z,y,x +{ + geFloat AZ; + assert( M != NULL ); + assert( Angles != NULL ); + + geXForm3d_Assert ( geXForm3d_IsOrthonormal(M) == GE_TRUE ); + + //ack. due to floating point error, the value can drift away from 1.0 a bit + // this will clamp it. The _IsOrthonormal test will pass because it allows + // for a tolerance. + + AZ = M->AZ; + if (AZ > 1.0f) + AZ = 1.0f; + if (AZ < -1.0f) + AZ = -1.0f; + + Angles->Y = -(geFloat)asin(-AZ); + + if ( cos(Angles->Y) != 0 ) + { + Angles->X = -(geFloat)atan2(M->BZ, M->CZ); + Angles->Z = -(geFloat)atan2(M->AY, M->AX); + } + else + { + Angles->X = -(geFloat)atan2(M->BX, M->BY); + Angles->Z = 0.0f; + } + assert( geVec3d_IsValid(Angles)!=GE_FALSE); +} + + +GENESISAPI void GENESISCC geXForm3d_SetEulerAngles(geXForm3d *M, const geVec3d *Angles) + // order of angles z,y,x +{ + geXForm3d XM, YM, ZM; + + assert( M != NULL ); + assert( geVec3d_IsValid(Angles)!=GE_FALSE); + + geXForm3d_SetXRotation(&XM,Angles->X); + geXForm3d_SetYRotation(&YM,Angles->Y); + geXForm3d_SetZRotation(&ZM,Angles->Z); + + geXForm3d_Multiply(&XM, &YM, M); + geXForm3d_Multiply(M, &ZM, M); + + + geXForm3d_Assert ( geXForm3d_IsOrthonormal(M) == GE_TRUE ); + +} + +GENESISAPI geBoolean GENESISCC geXForm3d_IsOrthonormal(const geXForm3d *M) + // returns GE_TRUE if M is orthonormal + // (if the rows and columns are all normalized (transform has no scaling or shearing) + // and is orthogonal (row1 cross row2 = row3 & col1 cross col2 = col3) +{ +#define ORTHONORMAL_TOLERANCE ((geFloat)(0.001f)) + geVec3d Col1,Col2,Col3; + geVec3d Col1CrossCol2; + geBoolean IsOrthonormal; + assert( M != NULL ); + + geXForm3d_Assert ( geXForm3d_IsValid(M) == GE_TRUE ); + + Col1.X = M->AX; + Col1.Y = M->BX; + Col1.Z = M->CX; + + Col2.X = M->AY; + Col2.Y = M->BY; + Col2.Z = M->CY; + + Col3.X = M->AZ; + Col3.Y = M->BZ; + Col3.Z = M->CZ; + + geVec3d_CrossProduct(&Col1,&Col2,&Col1CrossCol2); + + IsOrthonormal = geVec3d_Compare(&Col1CrossCol2,&Col3,ORTHONORMAL_TOLERANCE); + if (IsOrthonormal == GE_FALSE) + { + geVec3d_Inverse(&Col3); + IsOrthonormal = geVec3d_Compare(&Col1CrossCol2,&Col3,ORTHONORMAL_TOLERANCE); + } + + if ( geVec3d_IsValid(&(M->Translation)) ==GE_FALSE) + return GE_FALSE; + + return IsOrthonormal; +} + + +GENESISAPI void GENESISCC geXForm3d_Orthonormalize(geXForm3d *M) + // essentially removes scaling (or other distortions) from + // an orthogonal (or nearly orthogonal) matrix +{ + geVec3d Col1,Col2,Col3; + assert( M != NULL ); + geXForm3d_Assert ( geXForm3d_IsValid(M) == GE_TRUE ); + + Col1.X = M->AX; + Col1.Y = M->BX; + Col1.Z = M->CX; + geVec3d_Normalize(&Col1); + M->AX = Col1.X; + M->BX = Col1.Y; + M->CX = Col1.Z; + + Col2.X = M->AY; + Col2.Y = M->BY; + Col2.Z = M->CY; + geVec3d_Normalize(&Col2); + M->AY = Col2.X; + M->BY = Col2.Y; + M->CY = Col2.Z; + + geVec3d_CrossProduct(&Col1,&Col2,&Col3); + + M->AZ = Col3.X; + M->BZ = Col3.Y; + M->CZ = Col3.Z; + + geXForm3d_Assert ( geXForm3d_IsOrthonormal(M) == GE_TRUE ); +} + + + + +GENESISAPI geBoolean GENESISCC geXForm3d_IsOrthogonal(const geXForm3d *M) + // returns GE_TRUE if M is orthogonal + // (row1 cross row2 = row3 & col1 cross col2 = col3) +{ +#define ORTHOGONAL_TOLERANCE ((geFloat)(0.001f)) + geVec3d Col1,Col2,Col3; + geVec3d Col1CrossCol2; + geBoolean IsOrthogonal; + assert( M != NULL ); + geXForm3d_Assert ( geXForm3d_IsValid(M) == GE_TRUE ); + + //return GE_TRUE; + + Col1.X = M->AX; + Col1.Y = M->BX; + Col1.Z = M->CX; + //geVec3d_Normalize(&Col1); + + Col2.X = M->AY; + Col2.Y = M->BY; + Col2.Z = M->CY; + //geVec3d_Normalize(&Col2); + + Col3.X = M->AZ; + Col3.Y = M->BZ; + Col3.Z = M->CZ; + geVec3d_Normalize(&Col3); + + geVec3d_CrossProduct(&Col1,&Col2,&Col1CrossCol2); + + geVec3d_Normalize(&Col1CrossCol2); + + IsOrthogonal = geVec3d_Compare(&Col1CrossCol2,&Col3,ORTHOGONAL_TOLERANCE); + if (IsOrthogonal == GE_FALSE) + { + geVec3d_Inverse(&Col3); + IsOrthogonal = geVec3d_Compare(&Col1CrossCol2,&Col3,ORTHOGONAL_TOLERANCE); + } + + if ( geVec3d_IsValid(&(M->Translation)) ==GE_FALSE) + return GE_FALSE; + + return IsOrthogonal; +} + +GENESISAPI void GENESISCC geXForm3d_SetFromLeftUpIn( + geXForm3d *M, + const geVec3d *Left, + const geVec3d *Up, + const geVec3d *In) +{ + assert(M); + assert(Left); + assert(Up); + assert(In); + geXForm3d_Assert(geVec3d_IsNormalized(Left)); + geXForm3d_Assert(geVec3d_IsNormalized(Up)); + geXForm3d_Assert(geVec3d_IsNormalized(In)); + + M->AX = -Left->X; + M->BX = -Left->Y; + M->CX = -Left->Z; + M->AY = Up->X; + M->BY = Up->Y; + M->CY = Up->Z; + M->AZ = -In->X; + M->BZ = -In->Y; + M->CZ = -In->Z; + + geVec3d_Clear(&M->Translation); + + + geXForm3d_Assert ( geXForm3d_IsOrthonormal(M) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geXForm3d_Mirror( + const geXForm3d *Source, + const geVec3d *PlaneNormal, + geFloat PlaneDist, + geXForm3d *Dest) +{ + geFloat Dist; + geVec3d In, Left, Up; + geXForm3d Original; + geVec3d MirrorTranslation; + + geXForm3d_Assert ( geXForm3d_IsOrthogonal(Source) == GE_TRUE ); + assert( PlaneNormal != NULL ); + assert( Dest != NULL ); + + geXForm3d_Copy(Source, &Original); + + // Mirror the translation portion of the matrix + Dist = geVec3d_DotProduct(&Original.Translation, PlaneNormal) - PlaneDist; + geVec3d_AddScaled(&Original.Translation, PlaneNormal, -Dist*2.0f, &MirrorTranslation); + + // Mirror the Rotational portion of the xform first + geXForm3d_GetIn(&Original, &In); + geVec3d_Add(&Original.Translation, &In, &In); + Dist = geVec3d_DotProduct(&In, PlaneNormal) - PlaneDist; + geVec3d_AddScaled(&In, PlaneNormal, -Dist*2.0f, &In); + geVec3d_Subtract(&In, &MirrorTranslation, &In); + geVec3d_Normalize(&In); + + geXForm3d_GetLeft(&Original, &Left); + geVec3d_Add(&Original.Translation, &Left, &Left); + Dist = geVec3d_DotProduct(&Left, PlaneNormal) - PlaneDist; + geVec3d_AddScaled(&Left, PlaneNormal, -Dist*2.0f, &Left); + geVec3d_Subtract(&Left, &MirrorTranslation, &Left); + geVec3d_Normalize(&Left); + + geXForm3d_GetUp(&Original, &Up); + geVec3d_Add(&Original.Translation, &Up, &Up); + Dist = geVec3d_DotProduct(&Up, PlaneNormal) - PlaneDist; + geVec3d_AddScaled(&Up, PlaneNormal, -Dist*2.0f, &Up); + geVec3d_Subtract(&Up, &MirrorTranslation, &Up); + geVec3d_Normalize(&Up); + + geXForm3d_SetFromLeftUpIn(Dest, &Left, &Up, &In); + + // Must set the mirror translation here since geXForm3d_SetFromLeftUpIn cleared the translation portion + geVec3d_Set(&Dest->Translation, MirrorTranslation.X, MirrorTranslation.Y, MirrorTranslation.Z); + + geXForm3d_Assert ( geXForm3d_IsOrthogonal(Dest) == GE_TRUE ); +} + diff --git a/G3D/Math/Xform3d.h b/G3D/Math/Xform3d.h new file mode 100644 index 0000000..2a59fa5 --- /dev/null +++ b/G3D/Math/Xform3d.h @@ -0,0 +1,225 @@ +/****************************************************************************************/ +/* XFORM3D.H */ +/* */ +/* Author: */ +/* Description: 3D transform interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_XFORM_H +#define GE_XFORM_H + + +#include "Vec3d.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + geFloat AX,AY,AZ; // e[0][0],e[0][1],e[0][2] + geFloat BX,BY,BZ; // e[1][0],e[1][1],e[1][2] + geFloat CX,CY,CZ; // e[2][0],e[2][1],e[2][2] + geVec3d Translation; // e[0][3],e[1][3],e[2][3] + // 0,0,0,1 // e[3][0],e[3][1],e[3][2] +} geXForm3d; + +/* this is essentially a 'standard' 4x4 transform matrix, + with the bottom row always 0,0,0,1 + + | AX, AY, AZ, Translation.X | + | BX, BY, BZ, Translation.Y | + | CX, CY, CZ, Translation.Z | + | 0, 0, 0, 1 | +*/ + +// all geXForm3d_Set* functions return a right-handed transform. + +#define GEXFORM3D_MINIMUM_SCALE (0.00001f) + + +GENESISAPI void GENESISCC geXForm3d_Copy( + const geXForm3d *Src, + geXForm3d *Dst); + // copies Src to Dst. + +GENESISAPI geBoolean GENESISCC geXForm3d_IsValid(const geXForm3d *M); + // returns GE_TRUE if M is 'valid' + // 'valid' means that M is non NULL, and there are no NAN's in the matrix. + +//MRB BEGIN +GENESISAPI geBoolean GENESISCC geXForm3d_IsIdentity(const geXForm3d *M); + // returns GE_TRUE if M is an identity matrix +//MRB END + +GENESISAPI geBoolean GENESISCC geXForm3d_IsOrthonormal(const geXForm3d *M); + // returns GE_TRUE if M is orthonormal + // (if the rows and columns are all normalized (transform has no scaling or shearing) + // and is orthogonal (row1 cross row2 = row3 & col1 cross col2 = col3) + // * does not check for right-handed convention * + +GENESISAPI geBoolean GENESISCC geXForm3d_IsOrthogonal(const geXForm3d *M); + // returns GE_TRUE if M is orthogonal + // (row1 cross row2 = row3 & col1 cross col2 = col3) + // * does not check for right-handed convention * + +GENESISAPI void GENESISCC geXForm3d_Orthonormalize(geXForm3d *M); + // essentially removes scaling (or other distortions) from + // an orthogonal (or nearly orthogonal) matrix + // returns a right-handed matrix + + +GENESISAPI void GENESISCC geXForm3d_SetIdentity(geXForm3d *M); + // sets M to an identity matrix (clears it) + +GENESISAPI void GENESISCC geXForm3d_SetXRotation(geXForm3d *M,geFloat RadianAngle); + // sets up a transform that rotates RadianAngle about X axis + // all existing contents of M are replaced + +GENESISAPI void GENESISCC geXForm3d_SetYRotation(geXForm3d *M,geFloat RadianAngle); + // sets up a transform that rotates RadianAngle about Y axis + // all existing contents of M are replaced + +GENESISAPI void GENESISCC geXForm3d_SetZRotation(geXForm3d *M,geFloat RadianAngle); + // sets up a transform that rotates RadianAngle about Z axis + // all existing contents of M are replaced + +GENESISAPI void GENESISCC geXForm3d_SetTranslation(geXForm3d *M,geFloat x, geFloat y, geFloat z); + // sets up a transform that translates x,y,z + // all existing contents of M are replaced + +GENESISAPI void GENESISCC geXForm3d_SetScaling(geXForm3d *M,geFloat x, geFloat y, geFloat z); + // sets up a transform that scales by x,y,z + // all existing contents of M are replaced + +GENESISAPI void GENESISCC geXForm3d_RotateX(geXForm3d *M,geFloat RadianAngle); + // Rotates M by RadianAngle about X axis + // applies the rotation to the existing contents of M + +GENESISAPI void GENESISCC geXForm3d_RotateY(geXForm3d *M,geFloat RadianAngle); + // Rotates M by RadianAngle about Y axis + // applies the rotation to the existing contents of M + +GENESISAPI void GENESISCC geXForm3d_RotateZ(geXForm3d *M,geFloat RadianAngle); + // Rotates M by RadianAngle about Z axis + // applies the rotation to the existing contents of M + +GENESISAPI void GENESISCC geXForm3d_Translate(geXForm3d *M,geFloat x, geFloat y, geFloat z); + // Translates M by x,y,z + // applies the translation to the existing contents of M + +GENESISAPI void GENESISCC geXForm3d_Scale(geXForm3d *M,geFloat x, geFloat y, geFloat z); + // Scales M by x,y,z + // applies the scale to the existing contents of M + +GENESISAPI void GENESISCC geXForm3d_Multiply( + const geXForm3d *M1, + const geXForm3d *M2, + geXForm3d *MProduct); + // MProduct = matrix multiply of M1*M2 + // Concatenates the transformation in the M2 matrix onto the transformation in M1 + +GENESISAPI void GENESISCC geXForm3d_Transform( + const geXForm3d *M, + const geVec3d *V, + geVec3d *Result); + // Result is Matrix M * Vector V: V Tranformed by M + +GENESISAPI void GENESISCC geXForm3d_TransformArray( const geXForm3d *XForm, + const geVec3d *Source, + geVec3d *Dest, + int32 Count); + +GENESISAPI void GENESISCC geXForm3d_Rotate( + const geXForm3d *M, + const geVec3d *V, + geVec3d *Result); + // Result is Matrix M * Vector V: V Rotated by M (no translation) + + +/*** +* + "Left,Up,In" are just the basis vectors in the new coordinate space. + You can get them by multiplying the unit bases into the transforms. +* +******/ + +GENESISAPI void GENESISCC geXForm3d_GetLeft(const geXForm3d *M, geVec3d *Left); + // Gets a vector that is 'left' in the frame of reference of M (facing -Z) + +GENESISAPI void GENESISCC geXForm3d_GetUp(const geXForm3d *M, geVec3d *Up); + // Gets a vector that is 'up' in the frame of reference of M (facing -Z) + +GENESISAPI void GENESISCC geXForm3d_GetIn(const geXForm3d *M, geVec3d *In); + // Gets a vector that is 'in' in the frame of reference of M (facing -Z) + +GENESISAPI void GENESISCC geXForm3d_GetTranspose(const geXForm3d *M, geXForm3d *MTranspose); + // Gets the Transpose transform of M (M^T) + // Transpose of a matrix is the switch of the rows and columns + // The transpose is usefull because it is rapidly computed and is equal to the inverse + // transform for orthonormal transforms [inverse is (M') where M*M' = Identity ] + +GENESISAPI void GENESISCC geXForm3d_TransposeTransform( + const geXForm3d *M, + const geVec3d *V, + geVec3d *Result); + // applies the transpose transform of M to V. Result = (M^T) * V + +/***** +* + the Euler angles are subsequent rotations : + by Angles->Z around the Z axis + then by Angles->Y around the Y axis, in the newly rotate coordinates + then by Angles->X around the X axis +* +******/ + +GENESISAPI void GENESISCC geXForm3d_GetEulerAngles(const geXForm3d *M, geVec3d *Angles); + // Finds Euler angles from M and puts them into Angles + +GENESISAPI void GENESISCC geXForm3d_SetEulerAngles(geXForm3d *M, const geVec3d *Angles); + // Applies Euler angles to build M + +GENESISAPI void GENESISCC geXForm3d_SetFromLeftUpIn( + geXForm3d *M, + const geVec3d *Left, + const geVec3d *Up, + const geVec3d *In); + // Builds an geXForm3d from orthonormal Left, Up and In vectors + +GENESISAPI void GENESISCC geXForm3d_Mirror( + const geXForm3d *Source, + const geVec3d *PlaneNormal, + geFloat PlaneDist, + geXForm3d *Dest); + // Mirrors a XForm3d about a plane + + +//-------------- + +#ifndef NDEBUG + GENESISAPI void GENESISCC geXForm3d_SetMaximalAssertionMode( geBoolean Enable ); +#else + #define geXForm3d_SetMaximalAssertionMode(Enable) +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Math/crc32.c b/G3D/Math/crc32.c new file mode 100644 index 0000000..a93c074 --- /dev/null +++ b/G3D/Math/crc32.c @@ -0,0 +1,159 @@ +/****************************************************************************************/ +/* CRC32.C */ +/* */ +/* Author: Charles Bloom */ +/* Description: CRC construction module */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "crc32.h" + +static uint32 crc_table[256] = +{ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, + 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, + 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, + 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, + 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, + 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, + 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, + 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, + 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, + 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, + 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, + 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, + 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, + 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, + 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, + 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, + 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, + 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, + 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, + 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, + 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, + 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, + 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, + 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, + 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, + 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, + 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, + 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, + 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, + 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, + 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, + 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, + 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, + 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, + 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, + 0x2D02EF8D +}; + +#define STEPCRC(crc,byte) crc = crc_table[((int)crc ^ (byte)) & 0xff] ^ (crc >> 8) + +uint32 CRC32_Start(void) +{ +return (~((uint32)0)); +} + +uint32 CRC32_Finish(uint32 crc) +{ +return (~crc); +} + +uint32 CRC32_AddByte(uint32 crc,uint8 b) +{ + STEPCRC(crc,b); +return(crc); +} + +uint32 CRC32_AddWord(uint32 crc,uint16 w) +{ +uint8 *ptr; + ptr = (uint8 *)&w; + STEPCRC(crc,ptr[0]); + STEPCRC(crc,ptr[1]); +return(crc); +} + +uint32 CRC32_AddLong(uint32 crc,uint32 l) +{ +uint8 *ptr; + ptr = (uint8 *)&l; + STEPCRC(crc,ptr[0]); + STEPCRC(crc,ptr[1]); + STEPCRC(crc,ptr[2]); + STEPCRC(crc,ptr[3]); +return(crc); +} + +uint32 CRC32_Array(const uint8 * buf,uint32 buflen) +{ +uint32 crc = (~((uint32)0)); + + if (!buf ) return 0; + + while( (buflen&0xF) != 0 ) + { + STEPCRC(crc,*buf); buf++; + buflen--; + } + + buflen>>=4; /* 16 at a time */ + + while(buflen--) + { + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + STEPCRC(crc,*buf); buf++; + } + + crc ^= 0xFFFFFFFF; + +return crc; +} + diff --git a/G3D/Math/crc32.h b/G3D/Math/crc32.h new file mode 100644 index 0000000..110bed8 --- /dev/null +++ b/G3D/Math/crc32.h @@ -0,0 +1,45 @@ +/****************************************************************************************/ +/* CRC32.H */ +/* */ +/* Author: Charles Bloom */ +/* Description: CRC construction module */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_CRC32_H +#define GE_CRC32_H + +#include "basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32 CRC32_Array(const uint8 * buf,uint32 buflen); + +extern uint32 CRC32_Start(void); +extern uint32 CRC32_Finish(uint32 crc); + +extern uint32 CRC32_AddByte(uint32 crc,uint8 b); +extern uint32 CRC32_AddWord(uint32 crc,uint16 w); +extern uint32 CRC32_AddLong(uint32 crc,uint32 w); + +#ifdef __cplusplus +} +#endif + +#endif /* GE_CRC32_H */ + diff --git a/G3D/Math/quatern.c b/G3D/Math/quatern.c new file mode 100644 index 0000000..f0ea616 --- /dev/null +++ b/G3D/Math/quatern.c @@ -0,0 +1,808 @@ +/****************************************************************************************/ +/* QUATERN.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Quaternion mathematical system implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include "basetype.h" +#include "quatern.h" + + +#ifndef NDEBUG + static geQuaternion_MaximalAssertionMode = GE_TRUE; + #define geQuaternion_Assert if (geQuaternion_MaximalAssertionMode) assert + + void GENESISCC geQuaternion_SetMaximalAssertionMode( geBoolean Enable ) + { + assert( (Enable == GE_TRUE) || (Enable == GE_FALSE) ); + geQuaternion_MaximalAssertionMode = Enable; + } +#else + #define geQuaternion_Assert assert +#endif + +#define UNIT_TOLERANCE 0.001 + // Quaternion magnitude must be closer than this tolerance to 1.0 to be + // considered a unit quaternion + +#define QZERO_TOLERANCE 0.00001 + // quaternion magnitude must be farther from this tolerance to 0.0 to be + // normalized + +#define TRACE_QZERO_TOLERANCE 0.1 + // trace of matrix must be greater than this to be used for converting a matrix + // to a quaternion. + +#define AA_QZERO_TOLERANCE 0.0001 + + +geBoolean GENESISCC geQuaternion_IsValid(const geQuaternion *Q) +{ + if (Q == NULL) + return GE_FALSE; + if ((Q->W * Q->W) < 0.0f) + return GE_FALSE; + if ((Q->X * Q->X) < 0.0f) + return GE_FALSE; + if ((Q->Y * Q->Y) < 0.0f) + return GE_FALSE; + if ((Q->Z * Q->Z) < 0.0f) + return GE_FALSE; + return GE_TRUE; +} + +void GENESISCC geQuaternion_Set( + geQuaternion *Q, geFloat W, geFloat X, geFloat Y, geFloat Z) +{ + assert( Q != NULL ); + + Q->W = W; + Q->X = X; + Q->Y = Y; + Q->Z = Z; + assert( geQuaternion_IsValid(Q) != GE_FALSE ); +} + +void GENESISCC geQuaternion_SetVec3d( + geQuaternion *Q, geFloat W, const geVec3d *V) +{ + assert( Q != NULL ); + assert( geVec3d_IsValid(V) != GE_FALSE ); + + Q->W = W; + Q->X = V->X; + Q->Y = V->Y; + Q->Z = V->Z; +} + +void GENESISCC geQuaternion_Get( + const geQuaternion *Q, + geFloat *W, + geFloat *X, + geFloat *Y, + geFloat *Z) + // get quaternion components into W,X,Y,Z +{ + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + assert( W != NULL ); + assert( X != NULL ); + assert( Y != NULL ); + assert( Z != NULL ); + + *W = Q->W; + *X = Q->X; + *Y = Q->Y; + *Z = Q->Z; +} + +GENESISAPI void GENESISCC geQuaternion_SetFromAxisAngle(geQuaternion *Q, const geVec3d *Axis, geFloat Theta) + // set a quaternion from an axis and a rotation around the axis +{ + geFloat sinTheta; + assert( Q != NULL); + assert( geVec3d_IsValid(Axis) != GE_FALSE); + assert( (Theta * Theta) >= 0.0f ); + assert( ( fabs(geVec3d_Length(Axis)-1.0f) < AA_QZERO_TOLERANCE) ); + + Theta = Theta * (geFloat)0.5f; + Q->W = (geFloat) cos(Theta); + sinTheta = (geFloat) sin(Theta); + Q->X = sinTheta * Axis->X; + Q->Y = sinTheta * Axis->Y; + Q->Z = sinTheta * Axis->Z; + + geQuaternion_Assert( geQuaternion_IsUnit(Q) == GE_TRUE ); +} + + +geBoolean GENESISCC geQuaternion_GetAxisAngle(const geQuaternion *Q, geVec3d *Axis, geFloat *Theta) +{ + geFloat OneOverSinTheta; + geFloat HalfTheta; + assert( Q != NULL ); + assert( Axis != NULL ); + assert( Theta != NULL ); + geQuaternion_Assert( geQuaternion_IsUnit(Q) != GE_FALSE ); + + HalfTheta = (geFloat)acos( Q->W ); + if (HalfTheta>QZERO_TOLERANCE) + { + OneOverSinTheta = 1.0f / (geFloat)sin( HalfTheta ); + Axis->X = OneOverSinTheta * Q->X; + Axis->Y = OneOverSinTheta * Q->Y; + Axis->Z = OneOverSinTheta * Q->Z; + *Theta = 2.0f * HalfTheta; + geQuaternion_Assert( geVec3d_IsValid(Axis) != GE_FALSE ); + geQuaternion_Assert( (*Theta * *Theta) >= 0.0f); + return GE_TRUE; + } + else + { + Axis->X = Axis->Y = Axis->Z = 0.0f; + *Theta = 0.0f; + return GE_FALSE; + } +} + + +void GENESISCC geQuaternion_GetVec3d( + const geQuaternion *Q, + geFloat *W, + geVec3d *V) + // get quaternion components into W and V +{ + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + assert( W != NULL ); + assert( V != NULL ); + + *W = Q->W; + V->X = Q->X; + V->Y = Q->Y; + V->Z = Q->Z; +} + + +void GENESISCC geQuaternion_FromMatrix( + const geXForm3d *M, + geQuaternion *Q) + // takes upper 3 by 3 portion of matrix (rotation sub matrix) + // and generates a quaternion +{ + geFloat trace,s; + + assert( M != NULL ); + assert( Q != NULL ); + geQuaternion_Assert( geXForm3d_IsOrthonormal(M)==GE_TRUE ); + + trace = M->AX + M->BY + M->CZ; + if (trace > 0.0f) + { + s = (geFloat)sqrt(trace + 1.0f); + Q->W = s * 0.5f; + s = 0.5f / s; + + Q->X = (M->CY - M->BZ) * s; + Q->Y = (M->AZ - M->CX) * s; + Q->Z = (M->BX - M->AY) * s; + } + else + { + int biggest; + enum {A,E,I}; + if (M->AX > M->BY) + { + if (M->CZ > M->AX) + biggest = I; + else + biggest = A; + } + else + { + if (M->CZ > M->AX) + biggest = I; + else + biggest = E; + } + + // in the unusual case the original trace fails to produce a good sqrt, try others... + switch (biggest) + { + case A: + s = (geFloat)sqrt( M->AX - (M->BY + M->CZ) + 1.0); + if (s > TRACE_QZERO_TOLERANCE) + { + Q->X = s * 0.5f; + s = 0.5f / s; + Q->W = (M->CY - M->BZ) * s; + Q->Y = (M->AY + M->BX) * s; + Q->Z = (M->AZ + M->CX) * s; + break; + } + // I + s = (geFloat)sqrt( M->CZ - (M->AX + M->BY) + 1.0); + if (s > TRACE_QZERO_TOLERANCE) + { + Q->Z = s * 0.5f; + s = 0.5f / s; + Q->W = (M->BX - M->AY) * s; + Q->X = (M->CX + M->AZ) * s; + Q->Y = (M->CY + M->BZ) * s; + break; + } + // E + s = (geFloat)sqrt( M->BY - (M->CZ + M->AX) + 1.0); + if (s > TRACE_QZERO_TOLERANCE) + { + Q->Y = s * 0.5f; + s = 0.5f / s; + Q->W = (M->AZ - M->CX) * s; + Q->Z = (M->BZ + M->CY) * s; + Q->X = (M->BX + M->AY) * s; + break; + } + break; + case E: + s = (geFloat)sqrt( M->BY - (M->CZ + M->AX) + 1.0); + if (s > TRACE_QZERO_TOLERANCE) + { + Q->Y = s * 0.5f; + s = 0.5f / s; + Q->W = (M->AZ - M->CX) * s; + Q->Z = (M->BZ + M->CY) * s; + Q->X = (M->BX + M->AY) * s; + break; + } + // I + s = (geFloat)sqrt( M->CZ - (M->AX + M->BY) + 1.0); + if (s > TRACE_QZERO_TOLERANCE) + { + Q->Z = s * 0.5f; + s = 0.5f / s; + Q->W = (M->BX - M->AY) * s; + Q->X = (M->CX + M->AZ) * s; + Q->Y = (M->CY + M->BZ) * s; + break; + } + // A + s = (geFloat)sqrt( M->AX - (M->BY + M->CZ) + 1.0); + if (s > TRACE_QZERO_TOLERANCE) + { + Q->X = s * 0.5f; + s = 0.5f / s; + Q->W = (M->CY - M->BZ) * s; + Q->Y = (M->AY + M->BX) * s; + Q->Z = (M->AZ + M->CX) * s; + break; + } + break; + case I: + s = (geFloat)sqrt( M->CZ - (M->AX + M->BY) + 1.0); + if (s > TRACE_QZERO_TOLERANCE) + { + Q->Z = s * 0.5f; + s = 0.5f / s; + Q->W = (M->BX - M->AY) * s; + Q->X = (M->CX + M->AZ) * s; + Q->Y = (M->CY + M->BZ) * s; + break; + } + // A + s = (geFloat)sqrt( M->AX - (M->BY + M->CZ) + 1.0); + if (s > TRACE_QZERO_TOLERANCE) + { + Q->X = s * 0.5f; + s = 0.5f / s; + Q->W = (M->CY - M->BZ) * s; + Q->Y = (M->AY + M->BX) * s; + Q->Z = (M->AZ + M->CX) * s; + break; + } + // E + s = (geFloat)sqrt( M->BY - (M->CZ + M->AX) + 1.0); + if (s > TRACE_QZERO_TOLERANCE) + { + Q->Y = s * 0.5f; + s = 0.5f / s; + Q->W = (M->AZ - M->CX) * s; + Q->Z = (M->BZ + M->CY) * s; + Q->X = (M->BX + M->AY) * s; + break; + } + break; + default: + assert(0); + } + } + geQuaternion_Assert( geQuaternion_IsUnit(Q) == GE_TRUE ); +} + +GENESISAPI void GENESISCC geQuaternion_ToMatrix( + const geQuaternion *Q, + geXForm3d *M) + // takes a unit quaternion and fills out an equivelant rotation + // portion of a xform +{ + geFloat X2,Y2,Z2; //2*QX, 2*QY, 2*QZ + geFloat XX2,YY2,ZZ2; //2*QX*QX, 2*QY*QY, 2*QZ*QZ + geFloat XY2,XZ2,XW2; //2*QX*QY, 2*QX*QZ, 2*QX*QW + geFloat YZ2,YW2,ZW2; // ... + + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + assert( M != NULL ); + geQuaternion_Assert( geQuaternion_IsUnit(Q) == GE_TRUE ); + + + X2 = 2.0f * Q->X; + XX2 = X2 * Q->X; + XY2 = X2 * Q->Y; + XZ2 = X2 * Q->Z; + XW2 = X2 * Q->W; + + Y2 = 2.0f * Q->Y; + YY2 = Y2 * Q->Y; + YZ2 = Y2 * Q->Z; + YW2 = Y2 * Q->W; + + Z2 = 2.0f * Q->Z; + ZZ2 = Z2 * Q->Z; + ZW2 = Z2 * Q->W; + + M->AX = 1.0f - YY2 - ZZ2; + M->AY = XY2 - ZW2; + M->AZ = XZ2 + YW2; + + M->BX = XY2 + ZW2; + M->BY = 1.0f - XX2 - ZZ2; + M->BZ = YZ2 - XW2; + + M->CX = XZ2 - YW2; + M->CY = YZ2 + XW2; + M->CZ = 1.0f - XX2 - YY2; + + M->Translation.X = M->Translation.Y = M->Translation.Z = 0.0f; + + geQuaternion_Assert( geXForm3d_IsOrthonormal(M)==GE_TRUE ); + +} + + +#define EPSILON (0.00001) + + +void GENESISCC geQuaternion_Slerp( + const geQuaternion *Q0, + const geQuaternion *Q1, + geFloat T, + geQuaternion *QT) + // spherical interpolation between q0 and q1. 0<=t<=1 + // resulting quaternion is 'between' q0 and q1 + // with t==0 being all q0, and t==1 being all q1. +{ + geFloat omega,cosom,sinom,Scale0,Scale1; + geQuaternion QL; + assert( Q0 != NULL ); + assert( Q1 != NULL ); + assert( QT != NULL ); + assert( ( 0 <= T ) && ( T <= 1.0f ) ); + geQuaternion_Assert( geQuaternion_IsUnit(Q0) == GE_TRUE ); + geQuaternion_Assert( geQuaternion_IsUnit(Q1) == GE_TRUE ); + + cosom = (Q0->W * Q1->W) + (Q0->X * Q1->X) + + (Q0->Y * Q1->Y) + (Q0->Z * Q1->Z); + + if (cosom < 0) + { + cosom = -cosom; + QL.X = -Q1->X; + QL.Y = -Q1->Y; + QL.Z = -Q1->Z; + QL.W = -Q1->W; + } + else + { + QL = *Q1; + } + + + if ( (1.0f - cosom) > EPSILON ) + { + omega = (geFloat) acos( cosom ); + sinom = (geFloat) sin( omega ); + Scale0 = (geFloat) sin( (1.0f-T) * omega) / sinom; + Scale1 = (geFloat) sin( T*omega) / sinom; + } + else + { + // has numerical difficulties around cosom == 0 + // in this case degenerate to linear interpolation + + Scale0 = 1.0f - T; + Scale1 = T; + } + + + QT-> X = Scale0 * Q0->X + Scale1 * QL.X; + QT-> Y = Scale0 * Q0->Y + Scale1 * QL.Y; + QT-> Z = Scale0 * Q0->Z + Scale1 * QL.Z; + QT-> W = Scale0 * Q0->W + Scale1 * QL.W; + geQuaternion_Assert( geQuaternion_IsUnit(QT) == GE_TRUE ); +} + + + + +void GENESISCC geQuaternion_SlerpNotShortest( + const geQuaternion *Q0, + const geQuaternion *Q1, + geFloat T, + geQuaternion *QT) + // spherical interpolation between q0 and q1. 0<=t<=1 + // resulting quaternion is 'between' q0 and q1 + // with t==0 being all q0, and t==1 being all q1. +{ + geFloat omega,cosom,sinom,Scale0,Scale1; + assert( Q0 != NULL ); + assert( Q1 != NULL ); + assert( QT != NULL ); + assert( ( 0 <= T ) && ( T <= 1.0f ) ); + geQuaternion_Assert( geQuaternion_IsUnit(Q0) == GE_TRUE ); + geQuaternion_Assert( geQuaternion_IsUnit(Q1) == GE_TRUE ); + + cosom = (Q0->W * Q1->W) + (Q0->X * Q1->X) + + (Q0->Y * Q1->Y) + (Q0->Z * Q1->Z); + if ( (1.0f + cosom) > EPSILON ) + { + if ( (1.0f - cosom) > EPSILON ) + { + omega = (geFloat) acos( cosom ); + sinom = (geFloat) sin( omega ); + // has numerical difficulties around cosom == nPI/2 + // in this case everything is up for grabs... + // ...degenerate to linear interpolation + if (sinom < EPSILON) + { + Scale0 = 1.0f - T; + Scale1 = T; + } + else + { + Scale0 = (geFloat) sin( (1.0f-T) * omega) / sinom; + Scale1 = (geFloat) sin( T*omega) / sinom; + } + } + else + { + // has numerical difficulties around cosom == 0 + // in this case degenerate to linear interpolation + + Scale0 = 1.0f - T; + Scale1 = T; + } + QT-> X = Scale0 * Q0->X + Scale1 * Q1->X; + QT-> Y = Scale0 * Q0->Y + Scale1 * Q1->Y; + QT-> Z = Scale0 * Q0->Z + Scale1 * Q1->Z; + QT-> W = Scale0 * Q0->W + Scale1 * Q1->W; + //#pragma message (" ack:!!!!!!") + //geQuaternionNormalize(QT); + geQuaternion_Assert( geQuaternion_IsUnit(QT)); + } + else + { + QT->X = -Q0->Y; + QT->Y = Q0->X; + QT->Z = -Q0->W; + QT->W = Q0->Z; + Scale0 = (geFloat) sin( (1.0f - T) * (QUATERNION_PI*0.5) ); + Scale1 = (geFloat) sin( T * (QUATERNION_PI*0.5) ); + QT-> X = Scale0 * Q0->X + Scale1 * QT->X; + QT-> Y = Scale0 * Q0->Y + Scale1 * QT->Y; + QT-> Z = Scale0 * Q0->Z + Scale1 * QT->Z; + QT-> W = Scale0 * Q0->W + Scale1 * QT->W; + geQuaternion_Assert( geQuaternion_IsUnit(QT)); + } +} + +void GENESISCC geQuaternion_Multiply( + const geQuaternion *Q1, + const geQuaternion *Q2, + geQuaternion *Q) + // multiplies q1 * q2, and places the result in q. + // no failure. renormalization not automatic + +{ + geQuaternion Q1L,Q2L; + assert( geQuaternion_IsValid(Q1) != GE_FALSE ); + assert( geQuaternion_IsValid(Q2) != GE_FALSE ); + assert( Q != NULL ); + Q1L = *Q1; + Q2L = *Q2; + + Q->W = ( (Q1L.W*Q2L.W) - (Q1L.X*Q2L.X) + - (Q1L.Y*Q2L.Y) - (Q1L.Z*Q2L.Z) ); + + Q->X = ( (Q1L.W*Q2L.X) + (Q1L.X*Q2L.W) + + (Q1L.Y*Q2L.Z) - (Q1L.Z*Q2L.Y) ); + + Q->Y = ( (Q1L.W*Q2L.Y) - (Q1L.X*Q2L.Z) + + (Q1L.Y*Q2L.W) + (Q1L.Z*Q2L.X) ); + + Q->Z = ( (Q1L.W*Q2L.Z) + (Q1L.X*Q2L.Y) + - (Q1L.Y*Q2L.X) + (Q1L.Z*Q2L.W) ); + geQuaternion_Assert( geQuaternion_IsValid(Q) != GE_FALSE ); + +} + + +void GENESISCC geQuaternion_Rotate( + const geQuaternion *Q, + const geVec3d *V, + geVec3d *VRotated) + // Rotates V by the quaternion Q, places the result in VRotated. +{ + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + assert( geVec3d_IsValid(V) != GE_FALSE ); + assert( VRotated != NULL ); + + geQuaternion_Assert( geQuaternion_IsUnit(Q) == GE_TRUE ); + + { + geQuaternion Qinv,QV,QRotated, QT; + geFloat zero; + geQuaternion_SetVec3d(&QV ,0.0f,V); + geQuaternion_Inverse (Q,&Qinv); + geQuaternion_Multiply(Q,&QV,&QT); + geQuaternion_Multiply(&QT,&Qinv,&QRotated); + geQuaternion_GetVec3d(&QRotated,&zero,VRotated); + } +} + + + +geBoolean GENESISCC geQuaternion_IsUnit(const geQuaternion *Q) + // returns GE_TRUE if Q is a unit geQuaternion. GE_FALSE otherwise. +{ + geFloat magnitude; + assert( Q != NULL ); + + magnitude = (Q->W * Q->W) + (Q->X * Q->X) + + (Q->Y * Q->Y) + (Q->Z * Q->Z); + + if (( magnitude < 1.0+UNIT_TOLERANCE ) && ( magnitude > 1.0-UNIT_TOLERANCE )) + return GE_TRUE; + return GE_FALSE; +} + +geFloat GENESISCC geQuaternion_Magnitude(const geQuaternion *Q) + // returns Magnitude of Q. +{ + + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + return (Q->W * Q->W) + (Q->X * Q->X) + (Q->Y * Q->Y) + (Q->Z * Q->Z); +} + + +GENESISAPI geFloat GENESISCC geQuaternion_Normalize(geQuaternion *Q) + // normalizes Q to be a unit geQuaternion +{ + geFloat magnitude,one_over_magnitude; + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + + magnitude = (geFloat) sqrt ((Q->W * Q->W) + (Q->X * Q->X) + + (Q->Y * Q->Y) + (Q->Z * Q->Z)); + + if (( magnitude < QZERO_TOLERANCE ) && ( magnitude > -QZERO_TOLERANCE )) + { + return 0.0f; + } + + one_over_magnitude = 1.0f / magnitude; + + Q->W *= one_over_magnitude; + Q->X *= one_over_magnitude; + Q->Y *= one_over_magnitude; + Q->Z *= one_over_magnitude; + return magnitude; +} + + +GENESISAPI void GENESISCC geQuaternion_Copy(const geQuaternion *QSrc, geQuaternion *QDst) + // copies quaternion QSrc into QDst +{ + assert( geQuaternion_IsValid(QSrc) != GE_FALSE ); + assert( QDst != NULL ); + *QDst = *QSrc; +} + +void GENESISCC geQuaternion_Inverse(const geQuaternion *Q, geQuaternion *QInv) + // sets QInv to the inverse of Q. +{ + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + assert( QInv != NULL ); + + QInv->W = Q->W; + QInv->X = -Q->X; + QInv->Y = -Q->Y; + QInv->Z = -Q->Z; +} + + +void GENESISCC geQuaternion_Add( + const geQuaternion *Q1, + const geQuaternion *Q2, + geQuaternion *QSum) + // QSum = Q1 + Q2 (result is not generally a unit quaternion!) +{ + assert( geQuaternion_IsValid(Q1) != GE_FALSE ); + assert( geQuaternion_IsValid(Q2) != GE_FALSE ); + assert( QSum != NULL ); + QSum->W = Q1->W + Q2->W; + QSum->X = Q1->X + Q2->X; + QSum->Y = Q1->Y + Q2->Y; + QSum->Z = Q1->Z + Q2->Z; +} + +void GENESISCC geQuaternion_Subtract( + const geQuaternion *Q1, + const geQuaternion *Q2, + geQuaternion *QSum) + // QSum = Q1 - Q2 (result is not generally a unit quaternion!) +{ + assert( geQuaternion_IsValid(Q1) != GE_FALSE ); + assert( geQuaternion_IsValid(Q2) != GE_FALSE ); + assert( QSum != NULL ); + QSum->W = Q1->W - Q2->W; + QSum->X = Q1->X - Q2->X; + QSum->Y = Q1->Y - Q2->Y; + QSum->Z = Q1->Z - Q2->Z; +} + + +#define ZERO_EPSILON (0.0001f) +static int32 geQuaternion_XFormTable[]={1768710981,560296816}; + +void GENESISCC geQuaternion_Ln( + const geQuaternion *Q, + geQuaternion *LnQ) + // ln(Q) for unit quaternion only! +{ + geFloat Theta; + geQuaternion QL; + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + assert( LnQ != NULL ); + geQuaternion_Assert( geQuaternion_IsUnit(Q) == GE_TRUE ); + + if (Q->W < 0.0f) + { + QL.W = -Q->W; + QL.X = -Q->X; + QL.Y = -Q->Y; + QL.Z = -Q->Z; + } + else + { + QL = *Q; + } + Theta = (geFloat) acos( QL.W ); + // 0 < Theta < pi + if (Theta< ZERO_EPSILON) + { + // lim(t->0) of t/sin(t) = 1, so: + LnQ->W = 0.0f; + LnQ->X = QL.X; + LnQ->Y = QL.Y; + LnQ->Z = QL.Z; + } + else + { + geFloat Theta_Over_sin_Theta = Theta / (geFloat) sin ( Theta ); + LnQ->W = 0.0f; + LnQ->X = Theta_Over_sin_Theta * QL.X; + LnQ->Y = Theta_Over_sin_Theta * QL.Y; + LnQ->Z = Theta_Over_sin_Theta * QL.Z; + } +} + +void GENESISCC geQuaternion_Exp( + const geQuaternion *Q, + geQuaternion *ExpQ) + // exp(Q) for pure quaternion only! (zero scalar part (W)) +{ + geFloat Theta; + geFloat sin_Theta_over_Theta; + + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + assert( ExpQ != NULL); + assert( Q->W == 0.0 ); //check a range? + + Theta = (geFloat) sqrt(Q->X*Q->X + Q->Y*Q->Y + Q->Z*Q->Z); + if (Theta > ZERO_EPSILON) + { + sin_Theta_over_Theta = (geFloat) sin(Theta) / Theta; + } + else + { + sin_Theta_over_Theta = (geFloat) 1.0f; + } + + ExpQ->W = (geFloat) cos(Theta); + ExpQ->X = sin_Theta_over_Theta * Q->X; + ExpQ->Y = sin_Theta_over_Theta * Q->Y; + ExpQ->Z = sin_Theta_over_Theta * Q->Z; +} + +void GENESISCC geQuaternion_Scale( + const geQuaternion *Q, + geFloat Scale, + geQuaternion *QScaled) + // Q = Q * Scale (result is not generally a unit quaternion!) +{ + assert( geQuaternion_IsValid(Q) != GE_FALSE ); + assert( (Scale * Scale) >=0.0f ); + assert( QScaled != NULL); + + QScaled->W = Q->W * Scale; + QScaled->X = Q->X * Scale; + QScaled->Y = Q->Y * Scale; + QScaled->Z = Q->Z * Scale; +} + +void GENESISCC geQuaternion_SetNoRotation(geQuaternion *Q) + // sets Q to be a quaternion with no rotation (like an identity matrix) +{ + Q->W = 1.0f; + Q->X = Q->Y = Q->Z = 0.0f; + + /* this is equivelant to: + { + geXForm3d M; + geXForm3d_SetIdentity(&M); + geQuaternionFromMatrix(&M,Q); + } + */ +} + + + +geBoolean GENESISCC geQuaternion_Compare( geQuaternion *Q1, geQuaternion *Q2, geFloat Tolerance ) +{ + assert( geQuaternion_IsValid(Q1) != GE_FALSE ); + assert( geQuaternion_IsValid(Q2) != GE_FALSE ); + assert ( Tolerance >= 0.0 ); + + if ( // they are the same but with opposite signs + ( (fabs(Q1->X + Q2->X) <= Tolerance ) + && (fabs(Q1->Y + Q2->Y) <= Tolerance ) + && (fabs(Q1->Z + Q2->Z) <= Tolerance ) + && (fabs(Q1->W + Q2->W) <= Tolerance ) + ) + || // they are the same with same signs + ( (fabs(Q1->X - Q2->X) <= Tolerance ) + && (fabs(Q1->Y - Q2->Y) <= Tolerance ) + && (fabs(Q1->Z - Q2->Z) <= Tolerance ) + && (fabs(Q1->W - Q2->W) <= Tolerance ) + ) + ) + return GE_TRUE; + else + return GE_FALSE; + + + +} diff --git a/G3D/Math/quatern.h b/G3D/Math/quatern.h new file mode 100644 index 0000000..d11ef61 --- /dev/null +++ b/G3D/Math/quatern.h @@ -0,0 +1,237 @@ +/****************************************************************************************/ +/* QUATERN.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Quaternion mathematical system interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_QUATERNION_H +#define GE_QUATERNION_H + +/*************************************************************************** + + The quatern module contains basic support for a quaternion object. + + quaternions are an extension of complex numbers that allows an + expression for rotation that can be easily interpolated. geQuaternion_s are also + more numericaly stable for repeated rotations than matrices. + + + A quaternion is a 4 element 'vector' [w,x,y,z] where: + + q = w + xi + yj + zk + i*i = -1 + j*j = -1 + k*k = -1 + i*j = -j*i = k + j*k = -k*j = i + k*i = -i*k = j + q' (conjugate) = w - xi - yj - zk + ||q|| (magnitude) = sqrt(q*q') = sqrt(w*w + x*x + y*y + z*z) + unit quaternion ||q|| == 1; this implies q' == qinverse + quaternions are associative (q1*q2)*q3 == q1*(q2*q3) + quaternions are not commutative q1*q2 != q2*q1 + qinverse (inverse (1/q) ) = q'/(q*q') + + q can be expressed by w + xi + yj + zk or [w,x,y,z] + or as in this implementation (s,v) where s=w, and v=[x,y,z] + + quaternions can represent a rotation. The rotation is an angle t, around a + unit vector u. q=(s,v); s= cos(t/2); v= u*sin(t/2). + + quaternions can apply the rotation to a point. let the point be p [px,py,pz], + and let P be a quaternion(0,p). Protated = q*P*qinverse + ( Protated = q*P*q' if q is a unit quaternion) + + concatenation rotations is similar to matrix concatenation. given two rotations + q1 and q2, to rotate by q1, then q2: let qc = (q2*q1), then the combined + rotation is given by qc*P*qcinverse (= qc*P*qc' if q is a unit quaternion) + + multiplication: + q1 = w1 + x1i + y1j + z1k + q2 = w2 + x2i + y2j + z2k + q1*q2 = q3 = + (w1*w2 - x1*x2 - y1*y2 - z1*z2) {w3} + (w1*x2 + x1*w2 + y1*z2 - z1*y2)i {x3} + (w1*y2 - x1*z2 + y1*w2 + z1*x2)j {y3} + (w1*z2 + x1*y2 + y1*x2 + z1*w2)k {z3} + + also, + q1 = (s1,v1) = [s1,(x1,y1,z1)] + q2 = (s2,v2) = [s2,(x2,y2,z2)] + q1*q2 = q3 = (s1*s2 - dot_product(v1,v2), {s3} + (s1*v2 + s2*v1 + cross_product(v1,v2)) {v3} + + + interpolation - it is possible (and sometimes reasonable) to interpolate between + two quaternions by interpolating each component. This does not quarantee a + resulting unit quaternion, and will result in an animation with non-linear + rotational velocity. + + spherical interpolation: (slerp) treat the quaternions as vectors + find the angle between them (w = arccos(q1 dot q2) ). + given 0<=t<=1, q(t) = q1*(sin((1-t)*w)/sin(w) + q2 * sin(t*w)/sin(w). + since q == -q, care must be taken to rotate the proper way. + + this implementation uses the notation quaternion q = (quatS,quatV) + where quatS is a scalar, and quatV is a 3 element vector. + +********************************************/ + +#include "basetype.h" +#include "xform3d.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + geFloat W; + geFloat X,Y,Z; + //geVec3d QuatV; +} geQuaternion; + + +#define QUATERNION_PI (GE_PI) + +geBoolean GENESISCC geQuaternion_IsValid( const geQuaternion *Q ); + // return GE_TRUE if Q is non null and for has no NAN's in its components + +void GENESISCC geQuaternion_Set( geQuaternion *Q, geFloat W, geFloat X, geFloat Y, geFloat Z); + // set quaternion components. Doesn't normalize +void GENESISCC geQuaternion_SetVec3d( geQuaternion *Q, geFloat W, const geVec3d *V); + // set quaternion components. Doesn't normalize +GENESISAPI void GENESISCC geQuaternion_SetFromAxisAngle(geQuaternion *Q, const geVec3d *Axis, geFloat Theta); + // set a quaternion from an axis and a rotation around the axis +geBoolean GENESISCC geQuaternion_GetAxisAngle(const geQuaternion *Q, geVec3d *Axis, geFloat *Theta); + // gets an axis and angle of rotation around the axis from a quaternion + // returns GE_TRUE if there is an axis. + // returns GE_FALSE if there is no axis (and Axis is set to 0,0,0, and Theta is 0) + +void GENESISCC geQuaternion_Get( const geQuaternion *Q, + geFloat *W, geFloat *X, geFloat *Y, geFloat *Z); + // get quaternion components into W,X,Y,Z +void GENESISCC geQuaternion_GetVec3d( const geQuaternion *Q, geFloat *W, geVec3d *V); + // get quaternion components into W and V + +void GENESISCC geQuaternion_FromMatrix( + const geXForm3d *RotationMatrix, + geQuaternion *QDest); + // takes upper 3 by 3 portion of matrix (rotation sub matrix) + // and generates a quaternion + +GENESISAPI void GENESISCC geQuaternion_ToMatrix( + const geQuaternion *Q, + geXForm3d *RotationMatrixDest); + // takes a unit quaternion and makes RotationMatrixDest an equivelant rotation xform. + // (any translation in RotationMatrixDest will be list) + +void GENESISCC geQuaternion_Slerp( + const geQuaternion *Q0, + const geQuaternion *Q1, + geFloat T, + geQuaternion *QT); + // spherical interpolation between q0 and q1. 0<=t<=1 + // resulting quaternion is 'between' q0 and q1 + // with t==0 being all q0, and t==1 being all q1. + // returns a quaternion with a positive W - always takes shortest route + // through the positive W domain. + +void GENESISCC geQuaternion_SlerpNotShortest( + const geQuaternion *Q0, + const geQuaternion *Q1, + geFloat T, + geQuaternion *QT); + // spherical interpolation between q0 and q1. 0<=t<=1 + // resulting quaternion is 'between' q0 and q1 + // with t==0 being all q0, and t==1 being all q1. + + +void GENESISCC geQuaternion_Multiply( + const geQuaternion *Q1, + const geQuaternion *Q2, + geQuaternion *QProduct); + // multiplies q1 * q2, and places the result in q. + // no failure. renormalization not automatic + +void GENESISCC geQuaternion_Rotate( + const geQuaternion *Q, + const geVec3d *V, + geVec3d *VRotated); + // Rotates V by the quaternion Q, places the result in VRotated. + +geBoolean GENESISCC geQuaternion_IsUnit(const geQuaternion *Q); + // returns GE_TRUE if q is a unit quaternion. GE_FALSE otherwise. + +GENESISAPI geFloat GENESISCC geQuaternion_Normalize(geQuaternion *Q); + // normalizes q to be a unit quaternion. returns original magnitude of q + +GENESISAPI void GENESISCC geQuaternion_Copy(const geQuaternion *QSrc, geQuaternion *QDst); + // copies quaternion QSrc into QDst + +void GENESISCC geQuaternion_SetNoRotation(geQuaternion *Q); + // sets Q to be a quaternion with no rotation (like an identity matrix) + +void GENESISCC geQuaternion_Ln( + const geQuaternion *Q, + geQuaternion *LnQ); + // ln(Q) for unit quaternion only! + +void GENESISCC geQuaternion_Exp( + const geQuaternion *Q, + geQuaternion *ExpQ); + // exp(Q) for pure quaternion only! (zero scalar part (W)) + +void GENESISCC geQuaternion_Scale( + const geQuaternion *Q, + geFloat Scale, + geQuaternion *QScaled); + // Q = Q * Scale (result is not generally a unit quaternion!) + +void GENESISCC geQuaternion_Add( + const geQuaternion *Q1, + const geQuaternion *Q2, + geQuaternion *QSum); + // QSum = Q1 + Q2 (result is not generally a unit quaternion!) + +void GENESISCC geQuaternion_Subtract( + const geQuaternion *Q1, + const geQuaternion *Q2, + geQuaternion *QSum); + // QSum = Q1 - Q2 (result is not generally a unit quaternion!) + +void GENESISCC geQuaternion_Inverse(const geQuaternion *Q, geQuaternion *QInv); + // sets QInv to the inverse of Q. + +geFloat GENESISCC geQuaternion_Magnitude(const geQuaternion *Q); + // returns Magnitude of Q. + +geBoolean GENESISCC geQuaternion_Compare( geQuaternion *Q1, geQuaternion *Q2, geFloat Tolerance ); + // return GE_TRUE if quaternions differ elementwise by less than Tolerance. + + +#ifndef NDEBUG +void GENESISCC geQuaternion_SetMaximalAssertionMode( geBoolean Enable ); +#endif + +#ifdef __cplusplus +} +#endif + + +#endif // GE_QUATERNION_H diff --git a/G3D/Netplay.c b/G3D/Netplay.c new file mode 100644 index 0000000..b3a9a35 --- /dev/null +++ b/G3D/Netplay.c @@ -0,0 +1,863 @@ +/****************************************************************************************/ +/* NetPlay.c */ +/* */ +/* Author: John Pollard */ +/* Description: DirectPlay wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define IDIRECTPLAY2_OR_GREATER + +#include +#include + +#include +#include +#include + +#include "netplay.h" +#include "ErrorLog.h" + +//#define INIT_GUID + +//#define UNICODE (do not use, not done yet. Need to fix strings...) + +//************************************************************************************ +// Misc globals all will need... +//************************************************************************************ + + +LPGUID glpGuid; + +SP_DESC GlobalSP; +SESSION_DESC *GlobalSession; // Global sessions availible +DWORD gSessionCnt; +BOOL FoundSP = FALSE; // If the provider was found +BOOL FoundSession = FALSE; + +//LPDIRECTPLAY3A g_lpDP = NULL; +LPDIRECTPLAY4A g_lpDP = NULL; + +BOOL FoundConnection = FALSE; +LPVOID lpConnectionBuffer = NULL; + +// ************************************************************************************ +// Misc global functions +// ************************************************************************************ +HRESULT DPlayCreateSession(LPTSTR lptszSessionName, DWORD MaxPlayers); +HRESULT DPlayOpenSession(LPGUID lpSessionGuid); +BOOL WINAPI EnumSession(LPCDPSESSIONDESC2 lpDPSessionDesc, LPDWORD lpdwTimeOut, DWORD dwFlags, + LPVOID lpContext); +HRESULT DPlayEnumSessions(DWORD dwTimeout, LPDPENUMSESSIONSCALLBACK2 lpEnumCallback, + LPVOID lpContext, DWORD dwFlags); +HRESULT DPlayCreatePlayer(LPDPID lppidID, LPTSTR lptszPlayerName, HANDLE hEvent, + LPVOID lpData, DWORD dwDataSize); +HRESULT DPlayDestroyPlayer(DPID pid); +HRESULT DPlayRelease(void); + +static HRESULT DPlayCreate(void ); + +// New dp3 Connection callback +BOOL FAR PASCAL DPEnumConnectionsCallback( + LPCGUID lpguidSP, + LPVOID lpConnection, + DWORD dwSize, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext); + +static void DoDPError(HRESULT Hr); + +FILE *DebugF; + +//======================================================================================================== +// InitNetPlay +// Enumerate the service providers, and everything else... +//======================================================================================================== +BOOL InitNetPlay(LPGUID lpGuid) +{ + HRESULT Hr; + + glpGuid = lpGuid; + + FoundSP = FALSE; + + Hr = DPlayCreate(); + + if (Hr != DP_OK) + { + DoDPError(Hr); + return FALSE; + } + + IDirectPlayX_EnumConnections( g_lpDP, glpGuid, DPEnumConnectionsCallback, NULL, 0); + + if (!FoundConnection) + { + geErrorLog_AddString(-1, "InitNetPlay: No connections available.\n", NULL); + return FALSE; + } + + return TRUE; +} + +//==================================================================================================== +// NetPlayEnumSession +//==================================================================================================== +BOOL NetPlayEnumSession(LPSTR IPAdress, SESSION_DESC **SessionList, DWORD *SessionNum) +{ + HRESULT hr; + +#if 1 + char tempBuf[1024]; + DWORD tempLng = 1024; + LPDIRECTPLAYLOBBY2A lpDPL = NULL; + + // Free the old connection buffer + if(lpConnectionBuffer ) + { + free( lpConnectionBuffer ); + lpConnectionBuffer = NULL; + } + + hr = CoCreateInstance( &CLSID_DirectPlayLobby, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectPlayLobby3A, (LPVOID *) &lpDPL ); + + if (hr != DP_OK) + { + DoDPError(hr); + return( FALSE ); + } + + hr = IDirectPlayLobby_CreateAddress(lpDPL, &DPSPGUID_TCPIP, &DPAID_INet, (LPVOID)IPAdress, strlen(IPAdress), tempBuf, &tempLng); + + if (hr != DP_OK) + { + DoDPError(hr); + return( FALSE ); + } + + if (lpDPL) + { + hr = IDirectPlayLobby_Release(lpDPL); + + if (hr != DP_OK) + { + DoDPError(hr); + return( FALSE ); + } + lpDPL = NULL; + } + + hr = IDirectPlayX_InitializeConnection( g_lpDP, tempBuf, 0); +#else + hr = IDirectPlayX_InitializeConnection( g_lpDP, lpConnectionBuffer, 0); +#endif + + if (hr != DP_OK) + { + DoDPError(hr); + return( FALSE ); + } + + GlobalSession = NULL; + gSessionCnt = 0; + + hr = DPlayEnumSessions(0, EnumSession, NULL, 0); + + *SessionList = GlobalSession; + *SessionNum = gSessionCnt; + + return( TRUE ); + +} + +//================================================================================================== +// NetPlayCreateSession +//================================================================================================== +BOOL NetPlayCreateSession(LPSTR SessionName, DWORD MaxPlayers) +{ + HRESULT Hr; + + assert(g_lpDP); + assert(lpConnectionBuffer); + + Hr = IDirectPlayX_InitializeConnection(g_lpDP, lpConnectionBuffer, 0); + + if (Hr != DP_OK) + { + DoDPError(Hr); + return FALSE; + } + + Hr = DPlayCreateSession(SessionName, MaxPlayers); + + if (Hr != DP_OK) + { + DoDPError(Hr); + return FALSE; + } + + return TRUE; +} + +//================================================================================================== +// NetPlayJoinSession +//================================================================================================== +BOOL NetPlayJoinSession(SESSION_DESC *Session) +{ + HRESULT Hr; + + Hr = DPlayOpenSession(&Session->Guid); + + if (Hr != DP_OK) + { + DoDPError(Hr); + return FALSE; + } + + return TRUE; +} + +//================================================================================================== +// NetPlayCreatePlayer +// Creates a player for session +//================================================================================================== +BOOL NetPlayCreatePlayer(LPDPID lppidID, LPTSTR lptszPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, geBoolean ServerPlayer) +{ + HRESULT hr = DPERR_GENERIC; + DPNAME name; + DWORD Flags; + + assert(g_lpDP); + + ZeroMemory(&name,sizeof(name)); + name.dwSize = sizeof(DPNAME); + +#ifdef UNICODE + name.lpszShortName = lptszPlayerName; +#else + name.lpszShortNameA = lptszPlayerName; +#endif + + Flags = 0; + + //if (ServerPlayer) + // Flags |= DPPLAYER_SERVERPLAYER; + + hr = IDirectPlayX_CreatePlayer(g_lpDP, lppidID, &name, hEvent, lpData, dwDataSize, Flags); + + if (hr != DP_OK) + { + DoDPError(hr); + return FALSE; + } + + return TRUE; +} + +//========================================================================================================= +// NetPlayDestroyPlayer +//========================================================================================================= +BOOL NetPlayDestroyPlayer(DPID pid) +{ + HRESULT Hr = DPlayDestroyPlayer(pid); + + if (Hr != DP_OK) + { + DoDPError(Hr); + return FALSE; + } + + return TRUE; +} + +//========================================================================================================= +// NetPlayReceive +//========================================================================================================= +HRESULT NetPlayReceive(LPDPID lpidFrom, LPDPID lpidTo, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize) +{ + HRESULT Hr; + assert(g_lpDP); + + Hr = IDirectPlayX_Receive(g_lpDP, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize); + + if (Hr != DP_OK) + { + if (Hr != DPERR_NOMESSAGES) + DoDPError(Hr); + } + + return Hr; +} + +//========================================================================================================= +// NetPlaySend +//========================================================================================================= +HRESULT NetPlaySend(DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize) +{ + HRESULT Hr; + + assert(g_lpDP); + +#if 0 + dwFlags |= DPSEND_ASYNC; + Hr = IDirectPlayX_SendEx(g_lpDP, idFrom, idTo, dwFlags, lpData, dwDataSize, 0, 0, NULL, NULL); +#else + Hr = IDirectPlayX_Send(g_lpDP, idFrom, idTo, dwFlags, lpData, dwDataSize); +#endif + + if (Hr != DP_OK) + { + if (Hr == DPERR_PENDING) + return DP_OK; + + DoDPError(Hr); + } + + return Hr; +} + +//========================================================================================================= +// DeInitNetPlay +//========================================================================================================= +BOOL DeInitNetPlay(void) +{ + HRESULT Hr; + + if (lpConnectionBuffer) + { + free(lpConnectionBuffer); + lpConnectionBuffer = NULL; + } + + FoundConnection = FALSE; + FoundSP = FALSE; + + Hr = DPlayRelease(); + + if (Hr != DP_OK) + { + DoDPError(Hr); + return FALSE; + } + + return TRUE; +} + +//==================================================================================================== +// NetPlayGetNumMessages +//==================================================================================================== +geBoolean NetPlayGetNumMessages(int32 *NumMsgSend, int32 *NumBytesSend, int32 *NumMsgRec, int32 *NumBytesRec) +{ + HRESULT Hr; + DPID IdFrom, IdTo; + + IdFrom = IdTo = 0; + + Hr = IDirectPlayX_GetMessageQueue(g_lpDP, IdFrom, IdTo, DPMESSAGEQUEUE_SEND, NumMsgSend, NumBytesSend); + + if (Hr != DP_OK) + { + geErrorLog_AddString(-1, "NetPlayGetNumMessages: IDirectPlayX_GetMessageQueue failed.\n", NULL); + DoDPError(Hr); + return GE_FALSE; + } + + Hr = IDirectPlayX_GetMessageQueue(g_lpDP, IdFrom, IdTo, DPMESSAGEQUEUE_RECEIVE, NumMsgRec, NumBytesRec); + + if (Hr != DP_OK) + { + geErrorLog_AddString(-1, "NetPlayGetNumMessages: IDirectPlayX_GetMessageQueue failed.\n", NULL); + DoDPError(Hr); + return GE_FALSE; + } + + return GE_TRUE; +} + +// ************************************************************************************ +// WRAPPER Code sarts here... +// ************************************************************************************ +//======================================================================================== +// DPlayCreate +//======================================================================================== +HRESULT DPlayCreate( void ) +{ + HRESULT hr=E_FAIL; + LPDIRECTPLAY lpDP=NULL; + + CoInitialize( NULL ); + + hr = CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectPlay4A, (LPVOID *) &g_lpDP ); + //hr = CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_INPROC_SERVER, + // &IID_IDirectPlay3A, (LPVOID *) &g_lpDP ); + + return hr; +} + +//======================================================================================== +// DPlayCreateSession +//======================================================================================== +HRESULT DPlayCreateSession(LPTSTR lptszSessionName, DWORD MaxPlayers) +{ + HRESULT hr = E_FAIL; + DPSESSIONDESC2 dpDesc; + + assert(g_lpDP); + + ZeroMemory(&dpDesc, sizeof(dpDesc)); + dpDesc.dwSize = sizeof(dpDesc); + + dpDesc.dwFlags = DPSESSION_KEEPALIVE; + +#if 0 // Just keeping these here for reference... + dpDesc.dwFlags |= DPSESSION_CLIENTSERVER; + dpDesc.dwFlags |= DPSESSION_MIGRATEHOST; + dpDesc.dwFlags |= DPSESSION_OPTIMIZELATENCY; + dpDesc.dwFlags |= DPSESSION_DIRECTPLAYPROTOCOL; +#endif + + dpDesc.dwMaxPlayers = MaxPlayers; + +#ifdef UNICODE + dpDesc.lpszSessionName = lptszSessionName; +#else + dpDesc.lpszSessionNameA = lptszSessionName; +#endif + + // set the application guid + if (glpGuid) + dpDesc.guidApplication = *glpGuid; + + hr = IDirectPlayX_Open(g_lpDP, &dpDesc, DPOPEN_CREATE); + + if (hr != DP_OK) + { + DoDPError(hr); + } + + return hr; +} + +//======================================================================================================== +// DPlayOpenSession +//======================================================================================================== +HRESULT DPlayOpenSession(LPGUID lpSessionGuid) +{ + HRESULT hr = E_FAIL; + DPSESSIONDESC2 dpDesc; + + assert(g_lpDP); + + ZeroMemory(&dpDesc, sizeof(dpDesc)); + dpDesc.dwSize = sizeof(dpDesc); + + //dpDesc.dwFlags = DPSESSION_DIRECTPLAYPROTOCOL; + + // set the session guid + if (lpSessionGuid) + dpDesc.guidInstance = *lpSessionGuid; + + // Set the application guid + if (glpGuid) + dpDesc.guidApplication = *glpGuid; + + // open it + hr = IDirectPlayX_Open(g_lpDP, &dpDesc, DPOPEN_JOIN); + + return hr; +} + +//======================================================================================================== +// DPlayEnumSessions +//======================================================================================================== +HRESULT DPlayEnumSessions(DWORD dwTimeout, LPDPENUMSESSIONSCALLBACK2 lpEnumCallback, + LPVOID lpContext, DWORD dwFlags) +{ + HRESULT hr = E_FAIL; + DPSESSIONDESC2 dpDesc; + + ZeroMemory(&dpDesc, sizeof(dpDesc)); + dpDesc.dwSize = sizeof(dpDesc); + + if (glpGuid) + dpDesc.guidApplication = *glpGuid; + + if (g_lpDP) + hr = IDirectPlayX_EnumSessions(g_lpDP, &dpDesc, dwTimeout, lpEnumCallback, + lpContext, dwFlags); + return hr; +} + +//======================================================================================================== +// Callback for enum session +//======================================================================================================== +BOOL WINAPI EnumSession(LPCDPSESSIONDESC2 lpDPSessionDesc, LPDWORD lpdwTimeOut, DWORD dwFlags, + LPVOID lpContext) +{ + HWND hWnd = (HWND) lpContext; + LPSTR Str = NULL; + + if(dwFlags & DPESC_TIMEDOUT) + return FALSE; // don't try again + + gSessionCnt++; + + if( GlobalSession ) + GlobalSession = realloc( GlobalSession, gSessionCnt * sizeof(SESSION_DESC)); + else + GlobalSession = malloc( sizeof( SESSION_DESC ) ); + + GlobalSession[gSessionCnt-1].Guid = lpDPSessionDesc->guidInstance; + +#ifdef UNICODE + strcpy(GlobalSession[gSessionCnt-1].SessionName, lpDPSessionDesc->lpszSessionName); +#else + strcpy(GlobalSession[gSessionCnt-1].SessionName, lpDPSessionDesc->lpszSessionNameA); +#endif + + return(TRUE); +} + +//==================================================================================================== +// DPlayCreatePlayer +//==================================================================================================== +HRESULT DPlayCreatePlayer(LPDPID lppidID, LPTSTR lptszPlayerName, HANDLE hEvent, + LPVOID lpData, DWORD dwDataSize) +{ + HRESULT hr = DPERR_GENERIC; + DPNAME name; + + assert(g_lpDP); + + ZeroMemory(&name,sizeof(name)); + name.dwSize = sizeof(DPNAME); + +#ifdef UNICODE + name.lpszShortName = lptszPlayerName; +#else + name.lpszShortNameA = lptszPlayerName; +#endif + + hr = IDirectPlayX_CreatePlayer(g_lpDP, lppidID, &name, hEvent, lpData, dwDataSize, DPPLAYER_SERVERPLAYER); + + return hr; +} + +//==================================================================================================== +// DPlayDestroyPlayer +//==================================================================================================== +HRESULT DPlayDestroyPlayer(DPID pid) +{ + HRESULT hr=E_FAIL; + + assert(g_lpDP); + + hr = IDirectPlayX_DestroyPlayer(g_lpDP, pid); + + return hr; +} + +//==================================================================================================== +// DPlayRelease +//==================================================================================================== +HRESULT DPlayRelease(void) +{ + HRESULT hr = DP_OK; + + if (g_lpDP) + { + IDirectPlayX_Close(g_lpDP ); + + hr = IDirectPlayX_Release(g_lpDP); + g_lpDP = NULL; + } + + CoUninitialize(); + + return hr; +} + +//==================================================================================================== +// DPEnumConnectionsCallback +//==================================================================================================== +BOOL FAR PASCAL DPEnumConnectionsCallback( + LPCGUID lpguidSP, + LPVOID lpConnection, + DWORD dwSize, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext) +{ + LPSTR Str; + + if (FoundConnection) + return TRUE; + + Str = lpName->lpszShortNameA; + + // Loop through and try to see if this is the service provider we want (TCP/IP for now...) + while (strlen(Str) > 0) + { + if (!strnicmp(Str, "TCP", 3)) + //if (!strnicmp(Str, "Serial", 6)) + { + // Make sure it's deleted + if (lpConnectionBuffer) + { + free(lpConnectionBuffer); + lpConnectionBuffer = NULL; + } + + // make space for Connection Shortcut + lpConnectionBuffer = (char*)malloc(dwSize); + if (lpConnectionBuffer == NULL) + goto FAILURE; + + memcpy(lpConnectionBuffer, lpConnection, dwSize); + FoundConnection = TRUE; + break; + } + Str++; + } + +FAILURE: + return (TRUE); +} + + +//==================================================================================================== +// DoDPError +//==================================================================================================== +static void DoDPError(HRESULT Hr) +{ + switch (Hr) + { + case CLASS_E_NOAGGREGATION: + geErrorLog_AddString(-1, "A non-NULL value was passed for the pUnkOuter parameter in DirectPlayCreate, DirectPlayLobbyCreate, or IDirectPlayLobby2::Connect.\n", NULL); + break; + + case DP_OK: + geErrorLog_AddString(-1, "The request completed successfully.\n", NULL); + break; + + case DPERR_ACCESSDENIED: + geErrorLog_AddString(-1, "The session is full or an incorrect password was supplied.\n", NULL); + break; + + case DPERR_ACTIVEPLAYERS: + geErrorLog_AddString(-1, "The requested operation cannot be performed because there are existing active players.\n", NULL); + break; + + case DPERR_ALREADYINITIALIZED: + geErrorLog_AddString(-1, "This object is already initialized. \n", NULL); + break; + + case DPERR_APPNOTSTARTED: + geErrorLog_AddString(-1, "The application has not been started yet.\n", NULL); + break; + + case DPERR_AUTHENTICATIONFAILED: + geErrorLog_AddString(-1, "The password or credentials supplied could not be authenticated. \n", NULL); + break; + + case DPERR_BUFFERTOOLARGE: + geErrorLog_AddString(-1, "The data buffer is too large to store. \n", NULL); + break; + + case DPERR_BUSY: + geErrorLog_AddString(-1, "A message cannot be sent because the transmission medium is busy. \n", NULL); + break; + + case DPERR_BUFFERTOOSMALL: + geErrorLog_AddString(-1, "The supplied buffer is not large enough to contain the requested data. \n", NULL); + break; + + case DPERR_CANTADDPLAYER: + geErrorLog_AddString(-1, "The player cannot be added to the session. \n", NULL); + break; + + case DPERR_CANTCREATEGROUP: + geErrorLog_AddString(-1, "A new group cannot be created. \n", NULL); + break; + + case DPERR_CANTCREATEPLAYER: + geErrorLog_AddString(-1, "A new player cannot be created. \n", NULL); + break; + + case DPERR_CANTCREATEPROCESS: + geErrorLog_AddString(-1, "Cannot start the application. \n", NULL); + break; + + case DPERR_CANTCREATESESSION: + geErrorLog_AddString(-1, "A new session cannot be created. \n", NULL); + break; + + case DPERR_CANTLOADCAPI: + geErrorLog_AddString(-1, "No credentials were supplied and the CryptoAPI package (CAPI) to use for cryptography services cannot be loaded. \n", NULL); + break; + + case DPERR_CANTLOADSECURITYPACKAGE: + geErrorLog_AddString(-1, "The software security package cannot be loaded. \n", NULL); + break; + + case DPERR_CANTLOADSSPI: + geErrorLog_AddString(-1, "No credentials were supplied and the software security package (SSPI) that will prompt for credentials cannot be loaded. \n", NULL); + break; + + case DPERR_CAPSNOTAVAILABLEYET: + geErrorLog_AddString(-1, "The capabilities of the DirectPlay object have not been determined yet. This error will occur if the DirectPlay object is implemented on a connectivity solution that requires polling to determine available bandwidth and latency. \n", NULL); + break; + + case DPERR_CONNECTING: + geErrorLog_AddString(-1, "The method is in the process of connecting to the network. The application should keep calling the method until it returns DP_OK, indicating successful completion, or it returns a different error. \n", NULL); + break; + + case DPERR_ENCRYPTIONFAILED: + geErrorLog_AddString(-1, "The requested information could not be digitally encrypted. Encryption is used for message privacy. This error is only relevant in a secure session. \n", NULL); + break; + + case DPERR_EXCEPTION: + geErrorLog_AddString(-1, "An exception occurred when processing the request. \n", NULL); + break; + + case DPERR_GENERIC: + geErrorLog_AddString(-1, "An undefined error condition occurred. \n", NULL); + break; + + case DPERR_INVALIDFLAGS: + geErrorLog_AddString(-1, "The flags passed to this method are invalid. \n", NULL); + break; + + case DPERR_INVALIDGROUP: + geErrorLog_AddString(-1, "The group ID is not recognized as a valid group ID for this game session. \n", NULL); + break; + + case DPERR_INVALIDINTERFACE: + geErrorLog_AddString(-1, "The interface parameter is invalid. \n", NULL); + break; + + case DPERR_INVALIDOBJECT: + geErrorLog_AddString(-1, "The DirectPlay object pointer is invalid. \n", NULL); + break; + + case DPERR_INVALIDPARAMS: + geErrorLog_AddString(-1, "One or more of the parameters passed to the method are invalid. \n", NULL); + break; + + case DPERR_INVALIDPASSWORD: + geErrorLog_AddString(-1, "An invalid password was supplied when attempting to join a session that requires a password. \n", NULL); + break; + + case DPERR_INVALIDPLAYER: + geErrorLog_AddString(-1, "The player ID is not recognized as a valid player ID for this game session. \n", NULL); + break; + + case DPERR_LOGONDENIED: + geErrorLog_AddString(-1, "The session could not be opened because credentials are required and either no credentials were supplied or the credentials were invalid. \n", NULL); + break; + + case DPERR_NOCAPS: + geErrorLog_AddString(-1, "The communication link that DirectPlay is attempting to use is not capable of this function. \n", NULL); + break; + + case DPERR_NOCONNECTION: + geErrorLog_AddString(-1, "No communication link was established. \n", NULL); + break; + + case DPERR_NOINTERFACE: + geErrorLog_AddString(-1, "The interface is not supported. \n", NULL); + break; + + case DPERR_NOMESSAGES: + geErrorLog_AddString(-1, "There are no messages in the receive queue. \n", NULL); + break; + + case DPERR_NONAMESERVERFOUND: + geErrorLog_AddString(-1, "No name server (host) could be found or created. A host must exist to create a player. \n", NULL); + break; + + case DPERR_NONEWPLAYERS: + geErrorLog_AddString(-1, "The session is not accepting any new players. \n", NULL); + break; + + case DPERR_NOPLAYERS: + geErrorLog_AddString(-1, "There are no active players in the session. \n", NULL); + break; + + case DPERR_NOSESSIONS: + geErrorLog_AddString(-1, "There are no existing sessions for this game. \n", NULL); + break; + + case DPERR_NOTLOBBIED: + geErrorLog_AddString(-1, "Returned by the IDirectPlayLobby2::Connect method if the application was not started by using the IDirectPlayLobby2::RunApplication method or if there is no DPLCONNECTION structure currently initialized for this DirectPlayLobby object. \n", NULL); + break; + + case DPERR_NOTLOGGEDIN: + geErrorLog_AddString(-1, "An action cannot be performed because a player or client application is not logged in. Returned by the IDirectPlay3::Send method when the client application tries to send a secure message without being logged in. \n", NULL); + break; + + case DPERR_OUTOFMEMORY: + geErrorLog_AddString(-1, "There is insufficient memory to perform the requested operation. \n", NULL); + break; + + case DPERR_PLAYERLOST: + geErrorLog_AddString(-1, "A player has lost the connection to the session. \n", NULL); + break; + + case DPERR_SENDTOOBIG: + geErrorLog_AddString(-1, "The message being sent by the IDirectPlay3::Send method is too large. \n", NULL); + break; + + case DPERR_SESSIONLOST: + geErrorLog_AddString(-1, "The connection to the session has been lost. \n", NULL); + break; + + case DPERR_SIGNFAILED: + geErrorLog_AddString(-1, "The requested information could not be digitally signed. Digital signatures are used to establish the authenticity of messages. \n", NULL); + break; + + case DPERR_TIMEOUT: + geErrorLog_AddString(-1, "The operation could not be completed in the specified time. \n", NULL); + break; + + case DPERR_UNAVAILABLE: + geErrorLog_AddString(-1, "The requested function is not available at this time. \n", NULL); + break; + + case DPERR_UNINITIALIZED: + geErrorLog_AddString(-1, "The requested object has not been initialized. \n", NULL); + break; + + case DPERR_UNKNOWNAPPLICATION: + geErrorLog_AddString(-1, "An unknown application was specified. \n", NULL); + break; + + case DPERR_UNSUPPORTED: + geErrorLog_AddString(-1, "The function is not available in this implementation. Returned from IDirectPlay3::GetGroupConnectionSettings and IDirectPlay3::SetGroupConnectionSettings if they are called from a session that is not a lobby session. \n", NULL); + break; + + case DPERR_USERCANCEL: + geErrorLog_AddString(-1, "Can be returned in two ways. 1) The user canceled the connection process during a call to the IDirectPlay3::Open method. 2) The user clicked Cancel in one of the DirectPlay service provider dialog boxes during a call to IDirectPlay3::EnumSessions. \n", NULL); + break; + + default: + geErrorLog_AddString(-1, "NetPlayError: Don't know this one...\n", NULL); + break; + } +} diff --git a/G3D/Netplay.h b/G3D/Netplay.h new file mode 100644 index 0000000..7c021df --- /dev/null +++ b/G3D/Netplay.h @@ -0,0 +1,76 @@ +/****************************************************************************************/ +/* NetPlay.h */ +/* */ +/* Author: John Pollard */ +/* Description: DirectPlay wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_NETPLAY_H +#define GE_NETPLAY_H + +#include +#include + +#include "BaseType.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ************************************************************************************ +// Defines +// ************************************************************************************ +#define NETPLAY_OPEN_CREATE 1 +#define NETPLAY_OPEN_JOIN 2 + + +typedef struct +{ + char Desc[200]; // Description of Service provider + GUID Guid; // Global Service Provider GUID +} SP_DESC; + +// must match stuct AFX_SESSION in cengine.h +typedef struct +{ + char SessionName[200]; // Description of Service provider + GUID Guid; // Global Service Provider GUID +} SESSION_DESC; + +extern SP_DESC GlobalSP; // Global info about the sp +extern SESSION_DESC* GlobalSession; // Global sessions availible +extern LPGUID glpGuid; + +void DoDPError(HRESULT Hr); +BOOL InitNetPlay(LPGUID lpGuid); +BOOL NetPlayEnumSession(LPSTR IPAdress, SESSION_DESC** SessionList, DWORD* SessionNum); +BOOL NetPlayJoinSession(SESSION_DESC* SessionList); +BOOL NetPlayCreateSession(LPSTR SessionName, DWORD MaxPlayers); +BOOL NetPlayCreatePlayer(LPDPID lppidID, LPTSTR lptszPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, geBoolean ServerPlayer); +BOOL NetPlayDestroyPlayer(DPID pid); +HRESULT NetPlaySend(DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize); +HRESULT NetPlayReceive(LPDPID lpidFrom, LPDPID lpidTo, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize); +BOOL DeInitNetPlay(void); + +// HACK!!!! Function is in Engine.cpp (So NetPlay.C can call it...) +BOOL AFX_CPrintfC(char *String); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Physics/PhysicsJoint.c b/G3D/Physics/PhysicsJoint.c new file mode 100644 index 0000000..a29e6f3 --- /dev/null +++ b/G3D/Physics/PhysicsJoint.c @@ -0,0 +1,268 @@ +/****************************************************************************************/ +/* PHYSICSJOINT.H */ +/* */ +/* Author: Jason Wood */ +/* Description: Rigid body joint implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "vec3d.h" +#include "xform3d.h" +#include "ram.h" +#include "matrix33.h" +#include "quatern.h" + +#include "PhysicsObject.h" +#include "PhysicsJoint.h" + +typedef struct gePhysicsJoint +{ + gePhysicsJoint_Kind Type; + geVec3d locationA; + geVec3d locationB; + geVec3d locationAInWorldSpace; + geVec3d locationBInWorldSpace; + gePhysicsObject * Object1; + gePhysicsObject * Object2; + geFloat assemblyRate; +} gePhysicsJoint; + +#define JOINT_ASSEMBLY_RATE_MULTIPLIER (4.f) + +GENESISAPI gePhysicsJoint * GENESISCC gePhysicsJoint_Create(gePhysicsJoint_Kind Kind, const geVec3d *Location, + geFloat assemblyRate, gePhysicsObject *PS1, gePhysicsObject *PS2, geFloat physicsScale) +{ + gePhysicsJoint* pPhysjnt; + geVec3d POLocation; + geVec3d physicsSpaceLocation; + + pPhysjnt = NULL; + pPhysjnt = GE_RAM_ALLOCATE_STRUCT(gePhysicsJoint); + if (pPhysjnt == NULL) + { + return NULL; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // make sure the joint makes sense + + pPhysjnt->Type = Kind; + pPhysjnt->assemblyRate = assemblyRate * JOINT_ASSEMBLY_RATE_MULTIPLIER; + pPhysjnt->Object1 = PS1; + pPhysjnt->Object2 = PS2; + + geVec3d_Scale(Location, physicsScale, &physicsSpaceLocation); + + switch (Kind) + { + case JT_WORLD: + if (PS1 == NULL) + { + /* + GenVSI_Error(VSI, + GE_FALSE, + "Joint_Spawn: World joint needs non-NULL gePhysicsObject1 field.\n"); + */ + return NULL; + } + #if 0 + if (pJoint->Next == pJoint) + { + /* + GenVSI_Error(VSI, + GE_FALSE, + "Joint_Spawn: Next field points to parent.\n"); + */ + return NULL; + } + #endif + + gePhysicsObject_GetLocation(PS1, &POLocation, 0); + + geVec3d_Subtract(&physicsSpaceLocation, + &POLocation, + &pPhysjnt->locationA); + geVec3d_Copy(&physicsSpaceLocation, &pPhysjnt->locationB); + break; + + case JT_SPHERICAL: + if (PS1 == NULL || PS2 == NULL) + { + /* + GenVSI_Error(VSI, + GE_FALSE, + "Joint_Spawn: Spherical joint needs 2 non-NULL gePhysicsObjects.\n"); + */ + return NULL; + } + #if 0 + if (pJoint->Next == pJoint) + { + /* + GenVSI_Error(VSI, + GE_FALSE, + "Joint_Spawn: Next field points to parent.\n"); + */ + } + #endif + if (PS1 == PS2) + { + /* + GenVSI_Error(VSI, + GE_FALSE, + "Joint_Spawn: Spherical joint: need 2 distinct gePhysicsObjects.\n"); + */ + return NULL; + } + + gePhysicsObject_GetLocation(PS1, &POLocation, 0); + geVec3d_Subtract(&physicsSpaceLocation, + &POLocation, + &pPhysjnt->locationA); + + gePhysicsObject_GetLocation(PS2, &POLocation, 0); + geVec3d_Subtract(&physicsSpaceLocation, + &POLocation, + &pPhysjnt->locationB); + break; + + default: + /* + GenVSI_Error(VSI, + GE_FALSE, + "Joint_Spawn: unsupported joint type %d.\n", ij->jointType); + */ + return NULL; + } + + return pPhysjnt; +} + +GENESISAPI geBoolean GENESISCC gePhysicsJoint_Destroy(gePhysicsJoint** ppPhysjnt) +{ + assert(ppPhysjnt != NULL); + assert(*ppPhysjnt != NULL); + + geRam_Free(*ppPhysjnt); + + *ppPhysjnt = NULL; + + return GE_TRUE; +} + +GENESISAPI gePhysicsJoint_Kind GENESISCC gePhysicsJoint_GetType(const gePhysicsJoint* pPhysjnt) +{ + assert(pPhysjnt != NULL); + + return pPhysjnt->Type; +} + +GENESISAPI void GENESISCC gePhysicsJoint_GetLocationA(const gePhysicsJoint* pPhysjnt, geVec3d* pLoc) +{ + assert(pPhysjnt != NULL); + assert(pLoc != NULL); + + geVec3d_Copy(&pPhysjnt->locationA, pLoc); +} + +GENESISAPI void GENESISCC gePhysicsJoint_GetLocationB(const gePhysicsJoint* pPhysjnt, geVec3d* pLoc) +{ + assert(pPhysjnt != NULL); + assert(pLoc != NULL); + + geVec3d_Copy(&pPhysjnt->locationB, pLoc); +} + +GENESISAPI void GENESISCC gePhysicsJoint_SetLocationA(gePhysicsJoint* pPhysjnt, const geVec3d* pLoc) +{ + assert(pPhysjnt != NULL); + assert(pLoc != NULL); + + geVec3d_Copy(pLoc, &pPhysjnt->locationA); +} + +GENESISAPI void GENESISCC gePhysicsJoint_SetLocationB(gePhysicsJoint* pPhysjnt, const geVec3d* pLoc) +{ + assert(pPhysjnt != NULL); + assert(pLoc != NULL); + + geVec3d_Copy(pLoc, &pPhysjnt->locationB); +} + +GENESISAPI void GENESISCC gePhysicsJoint_GetLocationAInWorldSpace(const gePhysicsJoint* pPhysjnt, geVec3d* pLoc) +{ + assert(pPhysjnt != NULL); + assert(pLoc != NULL); + + geVec3d_Copy(&pPhysjnt->locationAInWorldSpace, pLoc); +} + +GENESISAPI void GENESISCC gePhysicsJoint_GetLocationBInWorldSpace(const gePhysicsJoint* pPhysjnt, geVec3d* pLoc) +{ + assert(pPhysjnt != NULL); + assert(pLoc != NULL); + + geVec3d_Copy(&pPhysjnt->locationBInWorldSpace, pLoc); +} + +GENESISAPI void GENESISCC gePhysicsJoint_SetLocationAInWorldSpace(gePhysicsJoint* pPhysjnt, const geVec3d* pLoc) +{ + assert(pPhysjnt != NULL); + assert(pLoc != NULL); + + geVec3d_Copy(pLoc, &pPhysjnt->locationAInWorldSpace); +} + +GENESISAPI void GENESISCC gePhysicsJoint_SetLocationBInWorldSpace(gePhysicsJoint* pPhysjnt, const geVec3d* pLoc) +{ + assert(pPhysjnt != NULL); + assert(pLoc != NULL); + + geVec3d_Copy(pLoc, &pPhysjnt->locationBInWorldSpace); +} + +GENESISAPI gePhysicsObject* GENESISCC gePhysicsJoint_GetObject1(const gePhysicsJoint* pPhysjnt) +{ + assert(pPhysjnt != NULL); + + return pPhysjnt->Object1; +} + +GENESISAPI gePhysicsObject* GENESISCC gePhysicsJoint_GetObject2(const gePhysicsJoint* pPhysjnt) +{ + assert(pPhysjnt != NULL); + + return pPhysjnt->Object2; +} + +GENESISAPI geFloat GENESISCC gePhysicsJoint_GetAssemblyRate(const gePhysicsJoint* pPhysjnt) +{ + assert(pPhysjnt != NULL); + + return pPhysjnt->assemblyRate; +} + +GENESISAPI void GENESISCC gePhysicsJoint_SetAssemblyRate(gePhysicsJoint* pPhysjnt, geFloat assemblyRate) +{ + assert(pPhysjnt != NULL); + assert(assemblyRate >= (geFloat)(1e-5)); + + pPhysjnt->assemblyRate = assemblyRate; +} + diff --git a/G3D/Physics/PhysicsJoint.h b/G3D/Physics/PhysicsJoint.h new file mode 100644 index 0000000..776c274 --- /dev/null +++ b/G3D/Physics/PhysicsJoint.h @@ -0,0 +1,68 @@ +/****************************************************************************************/ +/* PHYSICSJOINT.H */ +/* */ +/* Author: Jason Wood */ +/* Description: Rigid body joint interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef PHYSICSJOINT_H +#define PHYSICSJOINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + JT_WORLD = 0, + JT_SPHERICAL, + JT_PTTOPATH, + JT_PTTOSURFACE +} gePhysicsJoint_Kind; + +typedef struct gePhysicsJoint gePhysicsJoint; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// ctor / dtor + +//gePhysicsJoint* gePhysicsJoint_Create(ItemJoint* pItemJoint); +GENESISAPI gePhysicsJoint * GENESISCC gePhysicsJoint_Create(gePhysicsJoint_Kind Kind, const geVec3d *Location, + geFloat assemblyRate, gePhysicsObject *PS1, gePhysicsObject *PS2, geFloat physicsScale); +GENESISAPI geBoolean GENESISCC gePhysicsJoint_Destroy(gePhysicsJoint** ppPhysjnt); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// functions + +GENESISAPI gePhysicsJoint_Kind GENESISCC gePhysicsJoint_GetType(const gePhysicsJoint* pPhysjnt); +GENESISAPI void GENESISCC gePhysicsJoint_GetLocationA(const gePhysicsJoint* pPhysjnt, geVec3d* pLoc); +GENESISAPI void GENESISCC gePhysicsJoint_GetLocationB(const gePhysicsJoint* pPhysjnt, geVec3d* pLoc); +GENESISAPI void GENESISCC gePhysicsJoint_SetLocationA(gePhysicsJoint* pPhysjnt, const geVec3d* pLoc); +GENESISAPI void GENESISCC gePhysicsJoint_SetLocationB(gePhysicsJoint* pPhysjnt, const geVec3d* pLoc); +GENESISAPI void GENESISCC gePhysicsJoint_GetLocationAInWorldSpace(const gePhysicsJoint* pPhysjnt, geVec3d* pLoc); +GENESISAPI void GENESISCC gePhysicsJoint_GetLocationBInWorldSpace(const gePhysicsJoint* pPhysjnt, geVec3d* pLoc); +GENESISAPI void GENESISCC gePhysicsJoint_SetLocationAInWorldSpace(gePhysicsJoint* pPhysjnt, const geVec3d* pLoc); +GENESISAPI void GENESISCC gePhysicsJoint_SetLocationBInWorldSpace(gePhysicsJoint* pPhysjnt, const geVec3d* pLoc); +GENESISAPI gePhysicsObject* GENESISCC gePhysicsJoint_GetObject1(const gePhysicsJoint* pPhysjnt); +GENESISAPI gePhysicsObject* GENESISCC gePhysicsJoint_GetObject2(const gePhysicsJoint* pPhysjnt); +GENESISAPI geFloat GENESISCC gePhysicsJoint_GetAssemblyRate(const gePhysicsJoint* pPhysjnt); +GENESISAPI void GENESISCC gePhysicsJoint_SetAssemblyRate(gePhysicsJoint* pPhysjnt, geFloat assemblyRate); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Physics/PhysicsObject.c b/G3D/Physics/PhysicsObject.c new file mode 100644 index 0000000..a2fe0dc --- /dev/null +++ b/G3D/Physics/PhysicsObject.c @@ -0,0 +1,864 @@ +/****************************************************************************************/ +/* PHYSICSOBJECT.C */ +/* */ +/* Author: Jason Wood */ +/* Description: Constrained rigid body implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "genesis.h" +#include "ram.h" +#include "matrix33.h" +#include "quatern.h" + + +#include "PhysicsObject.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// gePhysicsObject structure definition + +typedef struct +{ + geXForm3d xform; // includes location and rotation matrix + geVec3d linearVelocity; + geVec3d angularVelocity; + geVec3d force, appliedForce; + geVec3d torque, appliedTorque; + geQuaternion orientation; + +} gePhysicsObject_Config; + +typedef struct gePhysicsObject +{ + geFloat mass, oneOverMass; + + geVec3d OriginalLocation; + + Matrix33 inertiaTensor, + inertiaTensorInverse; + geBoolean isAffectedByGravity; + geBoolean respondsToForces; + geFloat linearDamping; + geFloat angularDamping; + + int activeConfig; + gePhysicsObject_Config configs[2]; + + geFloat physicsScale; + +} gePhysicsObject; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ctor / dtor + +GENESISAPI gePhysicsObject * GENESISCC gePhysicsObject_Create( + const geVec3d *StartLocation, + geFloat mass, + geBoolean IsAffectedByGravity, + geBoolean RespondsToForces, + geFloat linearDamping, + geFloat angularDamping, + const geVec3d * Mins, + const geVec3d * Maxs, + geFloat physicsScale) +{ + gePhysicsObject* pgePhysicsObject; + geVec3d defaultAxis; + geVec3d bbScale; + int i; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + pgePhysicsObject = NULL; + pgePhysicsObject = GE_RAM_ALLOCATE_STRUCT(gePhysicsObject); + + if (pgePhysicsObject == NULL) + return NULL; + + assert(pgePhysicsObject != NULL); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // fill user data with relevant class data + + pgePhysicsObject->respondsToForces = RespondsToForces; + pgePhysicsObject->isAffectedByGravity = IsAffectedByGravity; + + pgePhysicsObject->linearDamping = linearDamping; + pgePhysicsObject->angularDamping = angularDamping; + + pgePhysicsObject->physicsScale = physicsScale; + geVec3d_Copy(StartLocation, &pgePhysicsObject->OriginalLocation); + geVec3d_Scale(&pgePhysicsObject->OriginalLocation, physicsScale, &pgePhysicsObject->OriginalLocation); + + assert(mass >= 0.1f); + + pgePhysicsObject->mass = mass; + pgePhysicsObject->oneOverMass = 1.f / mass; + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // initialize gePhysicsObject's state + + for (i = 0; i < 2; i ++) + { + geVec3d_Clear(&pgePhysicsObject->configs[i].linearVelocity); + geVec3d_Clear(&pgePhysicsObject->configs[i].angularVelocity); + geVec3d_Clear(&pgePhysicsObject->configs[i].force); + geVec3d_Clear(&pgePhysicsObject->configs[i].torque); + geVec3d_Clear(&pgePhysicsObject->configs[i].appliedForce); + geVec3d_Clear(&pgePhysicsObject->configs[i].appliedTorque); + + geVec3d_Set(&defaultAxis, 1.f, 0.f, 0.f); + geQuaternion_SetFromAxisAngle(&pgePhysicsObject->configs[i].orientation, + &defaultAxis, + 0.f); + + geXForm3d_SetIdentity(&pgePhysicsObject->configs[i].xform); + geVec3d_Clear(&pgePhysicsObject->configs[i].xform.Translation); + } + + Matrix33_SetIdentity(&pgePhysicsObject->inertiaTensor); + Matrix33_SetIdentity(&pgePhysicsObject->inertiaTensorInverse); + + geVec3d_Subtract(Maxs, Mins, &bbScale); + geVec3d_Scale(&bbScale, physicsScale, &bbScale); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute gePhysicsObject's inertia tensor and inverse + // we assume the gePhysicsObject is an axis-aligned box + + pgePhysicsObject->inertiaTensor.x[0][0] = pgePhysicsObject->mass / 12.f * (bbScale.Y * bbScale.Y + bbScale.Z * bbScale.Z); + pgePhysicsObject->inertiaTensor.x[1][1] = pgePhysicsObject->mass / 12.f * (bbScale.X * bbScale.X + bbScale.Z * bbScale.Z); + pgePhysicsObject->inertiaTensor.x[2][2] = pgePhysicsObject->mass / 12.f * (bbScale.X * bbScale.X + bbScale.Y * bbScale.Y); + + assert(pgePhysicsObject->inertiaTensor.x[0][0] > (geFloat)1e-5); + assert(pgePhysicsObject->inertiaTensor.x[1][1] > (geFloat)1e-5); + assert(pgePhysicsObject->inertiaTensor.x[2][2] > (geFloat)1e-5); + + pgePhysicsObject->inertiaTensorInverse.x[0][0] = 1 / pgePhysicsObject->inertiaTensor.x[0][0]; + pgePhysicsObject->inertiaTensorInverse.x[1][1] = 1 / pgePhysicsObject->inertiaTensor.x[1][1]; + pgePhysicsObject->inertiaTensorInverse.x[2][2] = 1 / pgePhysicsObject->inertiaTensor.x[2][2]; + + pgePhysicsObject->activeConfig = 0; + + return pgePhysicsObject; +} + +GENESISAPI geBoolean GENESISCC gePhysicsObject_Destroy(gePhysicsObject** pPhysob) +{ + assert(pPhysob != NULL); + assert(*pPhysob != NULL); + + geRam_Free(*pPhysob); + *pPhysob = NULL; + + return GE_TRUE; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// functions + +// apply force in global frame with changes taking effect on next iteration of gePhysicsObject's owner +GENESISAPI geBoolean GENESISCC gePhysicsObject_ApplyGlobalFrameForce(gePhysicsObject* pod, geVec3d* force, geVec3d* radiusVector, geBoolean isAppliedForce, + int configIndex) +{ + gePhysicsObject_Config* pConfig; + geVec3d torqueToAdd; + + assert(pod != NULL); + assert(force != NULL); + assert(radiusVector != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + pConfig = &pod->configs[configIndex]; + + if (! isAppliedForce) + { + geVec3d_Add(force, &pConfig->force, &pConfig->force); + + geVec3d_CrossProduct(radiusVector, force, &torqueToAdd); + geVec3d_Add(&torqueToAdd, &pConfig->torque, &pConfig->torque); + } + + else + { + geVec3d_Add(force, &pConfig->appliedForce, &pConfig->appliedForce); + + geVec3d_CrossProduct(radiusVector, force, &torqueToAdd); + geVec3d_Add(&torqueToAdd, &pConfig->appliedTorque, &pConfig->appliedTorque); + } + + return GE_TRUE; +} + +// apply impulse in global frame with immediate change in velocities +GENESISAPI geBoolean GENESISCC gePhysicsObject_ApplyGlobalFrameImpulse( + gePhysicsObject* pPhysob, + geVec3d* pImpulse, + geVec3d* pRadVec, + int configIndex) +{ + gePhysicsObject_Config* pConfig; + Matrix33 R, Rt; + geVec3d rCrossRW, rCrossRL, dv, dw; + assert( pPhysob != NULL ); + assert( pImpulse != NULL ); + assert( pRadVec != NULL ); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + pConfig = &pPhysob->configs[configIndex]; + + geVec3d_Scale(pImpulse, pPhysob->oneOverMass, &dv); + geVec3d_Add(&dv, &pConfig->linearVelocity, &pConfig->linearVelocity); + + geVec3d_CrossProduct(pRadVec, pImpulse, &rCrossRW); + + Matrix33_ExtractFromXForm3d(&pConfig->xform, &R); + Matrix33_GetTranspose(&R, &Rt); + + Matrix33_MultiplyVec3d(&Rt, &rCrossRW, &rCrossRL); + Matrix33_MultiplyVec3d(&pPhysob->inertiaTensorInverse, &rCrossRL, &dw); + geVec3d_Add(&dw, &pConfig->angularVelocity, &pConfig->angularVelocity); + + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC gePhysicsObject_ComputeForces(gePhysicsObject* pod, int configIndex) +{ + gePhysicsObject_Config* pConfig = &pod->configs[configIndex]; + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + assert( pod != NULL ); + + // add damping + geVec3d_Scale(&pConfig->linearVelocity, 1.f - pod->linearDamping, &pConfig->linearVelocity); + geVec3d_Scale(&pConfig->angularVelocity, 1.f - pod->angularDamping, &pConfig->angularVelocity); + + // clear force and torque accumulators + geVec3d_Clear(&pConfig->force); + geVec3d_Clear(&pConfig->torque); + + // add gravity + if (pod->isAffectedByGravity) + geVec3d_Set(&pConfig->force, 0.f, PHYSICSOBJECT_GRAVITY * pod->mass, 0.f); + + // add forces + if (! pod->respondsToForces) return GE_TRUE; + + geVec3d_Add(&pConfig->appliedForce, &pConfig->force, &pConfig->force); + geVec3d_Add(&pConfig->appliedTorque, &pConfig->torque, &pConfig->torque); + + return GE_TRUE; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// integrate a gePhysicsObject's equations of motion by time step deltaTime + +GENESISAPI geBoolean GENESISCC gePhysicsObject_Integrate( + gePhysicsObject* pod, + geFloat dt, + int sourceConfigIndex) +{ + gePhysicsObject_Config* pSourceConfig, *pTargetConfig; + geVec3d tau; + geVec3d a, dv; + geVec3d angularMomentum, angularAcceleration; + geVec3d omega_x_L, term1, dtTimesOmega; + Matrix33 R, Rt; + + geFloat qmag; + geQuaternion qdot; + geFloat G[3][4], Gt[4][3]; + int i, j; + static int M[]={0x696C6345,0x21657370}; + geFloat dt2 = 0.5f * (dt * dt); + + assert( sourceConfigIndex >= 0 ); + assert( sourceConfigIndex < 2 ); + assert( pod != NULL ); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + pSourceConfig = &pod->configs[sourceConfigIndex]; + pTargetConfig = &pod->configs[1 - sourceConfigIndex]; + + geVec3d_Scale(&pSourceConfig->force, pod->oneOverMass, &a); + geVec3d_Scale(&a, dt, &dv); + geVec3d_Add(&pSourceConfig->linearVelocity, &dv, &pTargetConfig->linearVelocity); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Matrix33_MultiplyVec3d(&pod->inertiaTensor, &pSourceConfig->angularVelocity, &angularMomentum); + geVec3d_CrossProduct(&pSourceConfig->angularVelocity, &angularMomentum, &omega_x_L); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute torque in body frame (= R ^ T * torque) + + Matrix33_ExtractFromXForm3d(&pSourceConfig->xform, &R); + Matrix33_GetTranspose(&R, &Rt); + Matrix33_MultiplyVec3d(&Rt, &pSourceConfig->torque, &tau); + + geVec3d_Subtract(&tau, &omega_x_L, &term1); + + Matrix33_MultiplyVec3d(&pod->inertiaTensorInverse, &term1, &angularAcceleration); + + geXForm3d_Rotate(&pSourceConfig->xform, &pSourceConfig->angularVelocity, &dtTimesOmega); + geVec3d_Scale(&dtTimesOmega, dt, &dtTimesOmega); + + G[0][0] = -pSourceConfig->orientation.X; + G[0][1] = pSourceConfig->orientation.W; + G[0][2] = -pSourceConfig->orientation.Z; + G[0][3] = pSourceConfig->orientation.Y; + + G[1][0] = -pSourceConfig->orientation.Y; + G[1][1] = pSourceConfig->orientation.Z; + G[1][2] = pSourceConfig->orientation.W; + G[1][3] = -pSourceConfig->orientation.X; + + G[2][0] = -pSourceConfig->orientation.Z; + G[2][1] = -pSourceConfig->orientation.Y; + G[2][2] = pSourceConfig->orientation.X; + G[2][3] = pSourceConfig->orientation.W; + + for (i = 0; i < 3; i++) + for (j = 0; j < 4; j++) + Gt[j][i] = 0.5f * G[i][j]; + + qdot.W = Gt[0][0] * dtTimesOmega.X + Gt[0][1] * dtTimesOmega.Y + Gt[0][2] * dtTimesOmega.Z; + qdot.X = Gt[1][0] * dtTimesOmega.X + Gt[1][1] * dtTimesOmega.Y + Gt[1][2] * dtTimesOmega.Z; + qdot.Y = Gt[2][0] * dtTimesOmega.X + Gt[2][1] * dtTimesOmega.Y + Gt[2][2] * dtTimesOmega.Z; + qdot.Z = Gt[3][0] * dtTimesOmega.X + Gt[3][1] * dtTimesOmega.Y + Gt[3][2] * dtTimesOmega.Z; + + pTargetConfig->orientation.W = pSourceConfig->orientation.W + qdot.W; + pTargetConfig->orientation.X = pSourceConfig->orientation.X + qdot.X; + pTargetConfig->orientation.Y = pSourceConfig->orientation.Y + qdot.Y; + pTargetConfig->orientation.Z = pSourceConfig->orientation.Z + qdot.Z; + + qmag = geQuaternion_Normalize(&pTargetConfig->orientation); + geQuaternion_ToMatrix(&pTargetConfig->orientation, &pTargetConfig->xform); + + pTargetConfig->angularVelocity.X = pSourceConfig->angularVelocity.X + dt * angularAcceleration.X; + pTargetConfig->angularVelocity.Y = pSourceConfig->angularVelocity.Y + dt * angularAcceleration.Y; + pTargetConfig->angularVelocity.Z = pSourceConfig->angularVelocity.Z + dt * angularAcceleration.Z; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + pTargetConfig->xform.Translation.X = + pSourceConfig->xform.Translation.X + dt * pSourceConfig->linearVelocity.X + dt2 * a.X; + pTargetConfig->xform.Translation.Y = + pSourceConfig->xform.Translation.Y + dt * pSourceConfig->linearVelocity.Y + dt2 * a.Y; + pTargetConfig->xform.Translation.Z = + pSourceConfig->xform.Translation.Z + dt * pSourceConfig->linearVelocity.Z + dt2 * a.Z; + + return GE_TRUE; +} + +GENESISAPI geFloat GENESISCC gePhysicsObject_GetMass(const gePhysicsObject* po) +{ + assert(po != NULL); + + return po->mass; +} + +GENESISAPI void GENESISCC gePhysicsObject_SetMass(gePhysicsObject* po, geFloat mass) +{ + assert(po != NULL); + + po->mass = mass; + + #pragma message("TODO: set i tensor") +} + +GENESISAPI geFloat GENESISCC gePhysicsObject_GetOneOverMass(const gePhysicsObject* po) +{ + assert(po != NULL); + + return po->oneOverMass; +} + +GENESISAPI void GENESISCC gePhysicsObject_GetXForm( const gePhysicsObject* po, + geXForm3d* xform, + int configIndex) +{ + assert(po != NULL); + assert(xform != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geXForm3d_Copy(&po->configs[configIndex].xform, xform); +} + +GENESISAPI void GENESISCC gePhysicsObject_SetXForm( gePhysicsObject* po, + const geXForm3d* xform, + int configIndex) +{ + assert(po != NULL); + assert(xform != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geXForm3d_Copy(xform, &po->configs[configIndex].xform); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetXFormInEditorSpace(const gePhysicsObject* po, + geXForm3d* xform, + int configIndex) +{ + assert(po != NULL); + assert(xform != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geXForm3d_Copy(&po->configs[configIndex].xform, xform); + geVec3d_Scale(&xform->Translation, 1 / po->physicsScale, &xform->Translation); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetOriginalLocation(const gePhysicsObject* po, geVec3d* loc) +{ + assert(po != NULL); + assert(loc != NULL); + + geVec3d_Copy(&po->OriginalLocation, loc); +} + +GENESISAPI void GENESISCC gePhysicsObject_SetOriginalLocation(gePhysicsObject* po, const geVec3d* loc) +{ + assert(po != NULL); + assert(loc != NULL); + + geVec3d_Copy(loc, &po->OriginalLocation); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// get gePhysicsObject's location in Physics space (xlation and olocation are in Physics space units) +GENESISAPI void GENESISCC gePhysicsObject_GetLocation( const gePhysicsObject *po, + geVec3d *Location, + int configIndex) +{ + assert(po != NULL); + assert(Location != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Add(&po->configs[configIndex].xform.Translation, &po->OriginalLocation, Location); +} + +// get gePhysicsObject's location in editor(world) space +GENESISAPI void GENESISCC gePhysicsObject_GetLocationInEditorSpace(const gePhysicsObject* po, + geVec3d* loc, + int configIndex) +{ + assert(po != NULL); + assert(loc != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Add(&po->OriginalLocation, &po->configs[configIndex].xform.Translation, loc); + geVec3d_Scale(loc, 1 / po->physicsScale, loc); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetLinearVelocity(const gePhysicsObject* po, + geVec3d* vel, + int configIndex) +{ + assert(po != NULL); + assert(vel != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(&po->configs[configIndex].linearVelocity, vel); +} + +GENESISAPI void GENESISCC gePhysicsObject_SetLinearVelocity(gePhysicsObject* po, + const geVec3d* vel, + int configIndex) +{ + assert(po != NULL); + assert(vel != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(vel, &po->configs[configIndex].linearVelocity); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetAngularVelocity(const gePhysicsObject* po, + geVec3d* vel, + int configIndex) +{ + assert(po != NULL); + assert(vel != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(&po->configs[configIndex].angularVelocity, vel); +} + +GENESISAPI void GENESISCC gePhysicsObject_SetAngularVelocity(gePhysicsObject* po, + const geVec3d* vel, + int configIndex) +{ + assert(po != NULL); + assert(vel != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(vel, &po->configs[configIndex].angularVelocity); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetForce( const gePhysicsObject* po, + geVec3d* force, + int configIndex) +{ + assert(po != NULL); + assert(force != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(&po->configs[configIndex].force, force); +} + +GENESISAPI void GENESISCC gePhysicsObject_SetForce( gePhysicsObject* po, + const geVec3d* force, + int configIndex) +{ + assert(po != NULL); + assert(force != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(force, &po->configs[configIndex].force); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetTorque(const gePhysicsObject* po, + geVec3d* torque, + int configIndex) +{ + assert(po != NULL); + assert(torque != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(&po->configs[configIndex].torque, torque); +} + +GENESISAPI void GENESISCC gePhysicsObject_SetTorque(gePhysicsObject* po, + const geVec3d* torque, + int configIndex) +{ + assert(po != NULL); + assert(torque != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(torque, &po->configs[configIndex].torque); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetAppliedForce( const gePhysicsObject* po, + geVec3d* force, + int configIndex) +{ + assert(po != NULL); + assert(force != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(&po->configs[configIndex].appliedForce, force); +} + +GENESISAPI void GENESISCC gePhysicsObject_SetAppliedForce( gePhysicsObject* po, + const geVec3d* force, + int configIndex) +{ + assert(po != NULL); + assert(force != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(force, &po->configs[configIndex].appliedForce); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetAppliedTorque( const gePhysicsObject* po, + geVec3d* torque, + int configIndex) +{ + assert(po != NULL); + assert(torque != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(&po->configs[configIndex].appliedTorque, torque); +} + +GENESISAPI void GENESISCC gePhysicsObject_SetAppliedTorque( gePhysicsObject* po, + const geVec3d* torque, + int configIndex) +{ + assert(po != NULL); + assert(torque != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Copy(torque, &po->configs[configIndex].appliedTorque); +} + +GENESISAPI void GENESISCC gePhysicsObject_ClearForce(gePhysicsObject* po, int configIndex) +{ + assert(po != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Clear(&po->configs[configIndex].force); +} + +GENESISAPI void GENESISCC gePhysicsObject_ClearTorque(gePhysicsObject* po, int configIndex) +{ + assert(po != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Clear(&po->configs[configIndex].torque); +} + +GENESISAPI void GENESISCC gePhysicsObject_ClearAppliedForce(gePhysicsObject* po, int configIndex) +{ + assert(po != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Clear(&po->configs[configIndex].appliedForce); +} + +GENESISAPI void GENESISCC gePhysicsObject_ClearAppliedTorque(gePhysicsObject* po, int configIndex) +{ + assert(po != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Clear(&po->configs[configIndex].appliedTorque); +} + +GENESISAPI void GENESISCC gePhysicsObject_IncForce( gePhysicsObject* po, + const geVec3d* forceInc, + int configIndex) +{ + assert(po != NULL); + assert(forceInc != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Add(&po->configs[configIndex].force, forceInc, &po->configs[configIndex].force); +} + +GENESISAPI void GENESISCC gePhysicsObject_IncTorque(gePhysicsObject* po, + const geVec3d* torqueInc, + int configIndex) +{ + assert(po != NULL); + assert(torqueInc != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Add(&po->configs[configIndex].torque, torqueInc, &po->configs[configIndex].torque); +} + +GENESISAPI void GENESISCC gePhysicsObject_IncAppliedForce( gePhysicsObject* po, + const geVec3d* forceInc, + int configIndex) +{ + assert(po != NULL); + assert(forceInc != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Add(&po->configs[configIndex].appliedForce, forceInc, &po->configs[configIndex].appliedForce); +} + +GENESISAPI void GENESISCC gePhysicsObject_IncAppliedTorque(gePhysicsObject* po, + const geVec3d* torqueInc, int configIndex) +{ + assert(po != NULL); + assert(torqueInc != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geVec3d_Add(&po->configs[configIndex].appliedTorque, torqueInc, &po->configs[configIndex].appliedTorque); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetOrientation( const gePhysicsObject* po, + geQuaternion* orient, int configIndex) +{ + assert(po != NULL); + assert(orient != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geQuaternion_Copy(&po->configs[configIndex].orientation, orient); +} + +GENESISAPI void GENESISCC gePhysicsObject_SetOrientation(gePhysicsObject* po, + const geQuaternion* orient, + int configIndex) +{ + assert(po != NULL); + assert(orient != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + geQuaternion_Copy(orient, &po->configs[configIndex].orientation); +} + +// get inertia tensor and inverse in body (local unrotated) space +GENESISAPI void GENESISCC gePhysicsObject_GetInertiaTensor(const gePhysicsObject* po, Matrix33* iTensor) +{ + assert(po != NULL); + assert(iTensor != NULL); + + Matrix33_Copy(&po->inertiaTensor, iTensor); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetInertiaTensorInverse(const gePhysicsObject* po, Matrix33* iTensorInv) +{ + assert(po != NULL); + assert(iTensorInv != NULL); + + Matrix33_Copy(&po->inertiaTensorInverse, iTensorInv); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetInertiaTensorInPhysicsSpace( + const gePhysicsObject* pPhysob, + Matrix33* pITensor, + int configIndex) +{ + Matrix33 R, Rt, RJ; + + assert(pPhysob != NULL); + assert(pITensor != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + Matrix33_ExtractFromXForm3d(&pPhysob->configs[configIndex].xform, &R); + Matrix33_GetTranspose(&R, &Rt); + + Matrix33_Multiply(&R, &pPhysob->inertiaTensor, &RJ); + Matrix33_Multiply(&RJ, &Rt, pITensor); +} + +GENESISAPI void GENESISCC gePhysicsObject_GetInertiaTensorInverseInPhysicsSpace( + const gePhysicsObject* pPhysob, + Matrix33* pITensorInv, + int configIndex) +{ + Matrix33 R, Rt, RJi; + + assert(pPhysob != NULL); + assert(pITensorInv != NULL); + assert( configIndex >= 0 ); + assert( configIndex < 2 ); + + Matrix33_ExtractFromXForm3d(&pPhysob->configs[configIndex].xform, &R); + Matrix33_GetTranspose(&R, &Rt); + + Matrix33_Multiply(&R, &pPhysob->inertiaTensorInverse, &RJi); + Matrix33_Multiply(&RJi, &Rt, pITensorInv); +} + +GENESISAPI geBoolean GENESISCC gePhysicsObject_IsAffectedByGravity(const gePhysicsObject* po) +{ + assert(po != NULL); + + return po->isAffectedByGravity; +} + +GENESISAPI void GENESISCC gePhysicsObject_SetIsAffectedByGravity(gePhysicsObject* po, geBoolean flag) +{ + assert(po != NULL); + + po->isAffectedByGravity = flag; +} + +GENESISAPI geBoolean GENESISCC gePhysicsObject_RespondsToForces(const gePhysicsObject* po) +{ + assert(po != NULL); + + return po->respondsToForces; +} + +GENESISAPI void GENESISCC gePhysicsObject_SetRespondsToForces(gePhysicsObject* po, geBoolean flag) +{ + assert(po != NULL); + + po->respondsToForces = flag; +} + +GENESISAPI geFloat GENESISCC gePhysicsObject_GetLinearDamping(const gePhysicsObject* po) +{ + assert(po != NULL); + + return po->linearDamping; +} + +GENESISAPI void GENESISCC gePhysicsObject_SetLinearDamping(gePhysicsObject* po, geFloat linearDamping) +{ + assert(po != NULL); + assert(linearDamping >= 0.f && linearDamping <= 1.f); + + po->linearDamping = linearDamping; +} + +GENESISAPI geFloat GENESISCC gePhysicsObject_GetAngularDamping(const gePhysicsObject* po) +{ + assert(po != NULL); + + return po->angularDamping; +} + +GENESISAPI void GENESISCC gePhysicsObject_SetAngularDamping(gePhysicsObject* po, geFloat angularDamping) +{ + assert(po != NULL); + assert(angularDamping >= 0.f && angularDamping <= 1.f); + + po->angularDamping = angularDamping; +} + +GENESISAPI void GENESISCC gePhysicsObject_SetActiveConfig(gePhysicsObject* pPhysob, int configIndex) +{ + assert(pPhysob != NULL); + pPhysob->activeConfig = configIndex; +} + +GENESISAPI int GENESISCC gePhysicsObject_GetActiveConfig(gePhysicsObject* pPhysob) +{ + assert(pPhysob != NULL); + return pPhysob->activeConfig; +} + +GENESISAPI void GENESISCC gePhysicsObject_SetPhysicsScale(gePhysicsObject* pPhysob, geFloat scale) +{ + assert(pPhysob != NULL); + pPhysob->physicsScale = scale; +} + +GENESISAPI geFloat GENESISCC gePhysicsObject_GetPhysicsScale(gePhysicsObject* pPhysob) +{ + assert(pPhysob != NULL); + return pPhysob->physicsScale; +} + diff --git a/G3D/Physics/PhysicsObject.h b/G3D/Physics/PhysicsObject.h new file mode 100644 index 0000000..691bb76 --- /dev/null +++ b/G3D/Physics/PhysicsObject.h @@ -0,0 +1,137 @@ +/****************************************************************************************/ +/* PHYSICSOBJECT.H */ +/* */ +/* Author: Jason Wood */ +/* Description: Constrained rigid body interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef PHYSICSOBJECT_H +#define PHYSICSOBJECT_H + +#include "matrix33.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PHYSICSOBJECT_GRAVITY (-3.9f) + +typedef struct gePhysicsObject gePhysicsObject; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ctor/dtor + +GENESISAPI gePhysicsObject * GENESISCC gePhysicsObject_Create( + const geVec3d *StartLocation, + geFloat mass, + geBoolean IsAffectedByGravity, + geBoolean RespondsToForces, + geFloat linearDamping, + geFloat angularDamping, + const geVec3d * Mins, + const geVec3d * Maxs, + geFloat physicsScale); +GENESISAPI geBoolean GENESISCC gePhysicsObject_Destroy(gePhysicsObject** pPhysob); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// functions + +GENESISAPI geBoolean GENESISCC gePhysicsObject_ApplyGlobalFrameForce(gePhysicsObject* pod, geVec3d* force, geVec3d* radiusVector, geBoolean isAppliedForce, + int configIndex); +GENESISAPI geBoolean GENESISCC gePhysicsObject_ApplyGlobalFrameImpulse(gePhysicsObject* pPhysob, geVec3d* pImpulse, geVec3d* pRadVec, int configIndex); +GENESISAPI geBoolean GENESISCC gePhysicsObject_ComputeForces(gePhysicsObject* pod, int configIndex); +GENESISAPI geBoolean GENESISCC gePhysicsObject_Integrate(gePhysicsObject* pod, geFloat deltaTime, int SourceConfigIndex); + +GENESISAPI geFloat GENESISCC gePhysicsObject_GetMass(const gePhysicsObject* po); +GENESISAPI void GENESISCC gePhysicsObject_SetMass(gePhysicsObject* po, geFloat mass); + +GENESISAPI geFloat GENESISCC gePhysicsObject_GetOneOverMass(const gePhysicsObject* po); + +GENESISAPI void GENESISCC gePhysicsObject_GetXForm(const gePhysicsObject* po, geXForm3d* xform, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_SetXForm(gePhysicsObject* po, const geXForm3d* xform, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetXFormInEditorSpace(const gePhysicsObject* po, geXForm3d* xform, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetOriginalLocation(const gePhysicsObject* po, geVec3d* loc); +GENESISAPI void GENESISCC gePhysicsObject_SetOriginalLocation(gePhysicsObject* po, const geVec3d* loc); + +GENESISAPI void GENESISCC gePhysicsObject_GetLocation(const gePhysicsObject *po, geVec3d *Location, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_GetLocationInEditorSpace(const gePhysicsObject* po, geVec3d* loc, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetLinearVelocity(const gePhysicsObject* po, geVec3d* vel, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_SetLinearVelocity(gePhysicsObject* po, const geVec3d* vel, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetAngularVelocity(const gePhysicsObject* po, geVec3d* vel, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_SetAngularVelocity(gePhysicsObject* po, const geVec3d* vel, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetForce(const gePhysicsObject* po, geVec3d* force, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_SetForce(gePhysicsObject* po, const geVec3d* force, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetTorque(const gePhysicsObject* po, geVec3d* torque, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_SetTorque(gePhysicsObject* po, const geVec3d* torque, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetAppliedForce(const gePhysicsObject* po, geVec3d* force, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_SetAppliedForce(gePhysicsObject* po, const geVec3d* force, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetAppliedTorque(const gePhysicsObject* po, geVec3d* torque, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_SetAppliedTorque(gePhysicsObject* po, const geVec3d* torque, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_ClearForce(gePhysicsObject* po, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_ClearTorque(gePhysicsObject* po, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_ClearAppliedForce(gePhysicsObject* po, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_ClearAppliedTorque(gePhysicsObject* po, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_IncForce(gePhysicsObject* po, const geVec3d* forceInc, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_IncTorque(gePhysicsObject* po, const geVec3d* torqueInc, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_IncAppliedForce(gePhysicsObject* po, const geVec3d* forceInc, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_IncAppliedTorque(gePhysicsObject* po, const geVec3d* torqueInc, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetOrientation(const gePhysicsObject* po, geQuaternion* orient, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_SetOrientation(gePhysicsObject* po, const geQuaternion* orient, int configIndex); + +GENESISAPI void GENESISCC gePhysicsObject_GetInertiaTensor(const gePhysicsObject* po, Matrix33* iTensor); +GENESISAPI void GENESISCC gePhysicsObject_GetInertiaTensorInverse(const gePhysicsObject* po, Matrix33* iTensorInv); + +GENESISAPI void GENESISCC gePhysicsObject_GetInertiaTensorInPhysicsSpace(const gePhysicsObject* pPhysob, Matrix33* pITensor, int configIndex); +GENESISAPI void GENESISCC gePhysicsObject_GetInertiaTensorInverseInPhysicsSpace(const gePhysicsObject* pPhysob, Matrix33* pITensorInv, int configIndex); + +GENESISAPI geBoolean GENESISCC gePhysicsObject_IsAffectedByGravity(const gePhysicsObject* po); +GENESISAPI void GENESISCC gePhysicsObject_SetIsAffectedByGravity(gePhysicsObject* po, geBoolean flag); + +GENESISAPI geBoolean GENESISCC gePhysicsObject_RespondsToForces(const gePhysicsObject* po); +GENESISAPI void GENESISCC gePhysicsObject_SetRespondsToForces(gePhysicsObject* po, geBoolean flag); + +GENESISAPI geFloat GENESISCC gePhysicsObject_GetLinearDamping(const gePhysicsObject* po); +GENESISAPI void GENESISCC gePhysicsObject_SetLinearDamping(gePhysicsObject* po, geFloat linearDamping); + +GENESISAPI geFloat GENESISCC gePhysicsObject_GetAngularDamping(const gePhysicsObject* po); +GENESISAPI void GENESISCC gePhysicsObject_SetAngularDamping(gePhysicsObject* po, geFloat angularDamping); + +GENESISAPI void GENESISCC gePhysicsObject_SetActiveConfig(gePhysicsObject* pPhysob, int configIndex); +GENESISAPI int GENESISCC gePhysicsObject_GetActiveConfig(gePhysicsObject* pPhysob); + +GENESISAPI void GENESISCC gePhysicsObject_SetPhysicsScale(gePhysicsObject* pPhysob, geFloat scale); +GENESISAPI geFloat GENESISCC gePhysicsObject_GetPhysicsScale(gePhysicsObject* pPhysob); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Physics/PhysicsSystem.c b/G3D/Physics/PhysicsSystem.c new file mode 100644 index 0000000..460ea81 --- /dev/null +++ b/G3D/Physics/PhysicsSystem.c @@ -0,0 +1,841 @@ +/****************************************************************************************/ +/* PHYSICSSYSTEM.C */ +/* */ +/* Author: Jason Wood */ +/* Description: Rigid body, constraint based physics system implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include +#include + +#include "vec3d.h" +#include "xform3d.h" +#include "ram.h" +#include "matrix33.h" +#include "quatern.h" + +#include "PhysicsObject.h" +#include "PhysicsJoint.h" +#include "PhysicsSystem.h" + +typedef struct LinearSystemStruct +{ + geFloat ** M; + geFloat * X; + geFloat * KVector; +} LinearSystemStruct; + +typedef struct gePhysicsSystem +{ + int sumOfConstraintDimensions; + LinearSystemStruct *linsys; + int PhysicsObjectCount; + int PhysicsJointCount; + gePhysicsObject **Objects; + gePhysicsJoint **Joints; + geFloat physicsScale; + + int sourceConfigIndex, targetConfigIndex; + +} gePhysicsSystem; + + +static geBoolean gePhysicsSystem_EnforceConstraints(gePhysicsSystem* physsysPtr, geFloat subStepSize); +static geBoolean gePhysicsSystem_SolveForConstraintForces(gePhysicsSystem* physsysPtr); + +static Matrix33 gePhysicsSystemIdentityMatrix; + +GENESISAPI gePhysicsSystem* GENESISCC gePhysicsSystem_Create(void) +{ + gePhysicsSystem* pPhyssys; + + pPhyssys = NULL; + pPhyssys = GE_RAM_ALLOCATE_STRUCT(gePhysicsSystem); + if (pPhyssys == NULL) + { + return NULL; + } + + memset(pPhyssys, 0, sizeof(*pPhyssys)); + + Matrix33_SetIdentity(&gePhysicsSystemIdentityMatrix); + + pPhyssys->sourceConfigIndex = 0; + pPhyssys->targetConfigIndex = 1; + + return pPhyssys; +} + +GENESISAPI geBoolean GENESISCC gePhysicsSystem_AddObject(gePhysicsSystem *PS, gePhysicsObject *Object) +{ + gePhysicsObject ** NewList; + assert( PS != NULL ); + + NewList = geRam_Realloc(PS->Objects, sizeof(*NewList) * (PS->PhysicsObjectCount + 1)); + if (!NewList) + return GE_FALSE; + + NewList[PS->PhysicsObjectCount] = Object; + PS->PhysicsObjectCount++; + PS->Objects = NewList; + + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC gePhysicsSystem_AddJoint(gePhysicsSystem *PS, gePhysicsJoint *Joint) +{ + gePhysicsJoint ** NewList; + int i; + gePhysicsJoint_Kind type; + assert( PS != NULL ); + assert( Joint != NULL ); + + NewList = geRam_Realloc(PS->Joints, sizeof(*NewList) * (PS->PhysicsJointCount + 1)); + if (!NewList) + return GE_FALSE; + + NewList[PS->PhysicsJointCount] = Joint; + PS->PhysicsJointCount++; + PS->Joints = NewList; + + // Free any old data + if (PS->linsys) + { + assert(PS->linsys->M); + assert(PS->linsys->X); + assert(PS->linsys->KVector); + + for (i = 0; i < PS->sumOfConstraintDimensions; i++) + { + assert(PS->linsys->M[i]); + geRam_Free(PS->linsys->M[i]); + } + + geRam_Free(PS->linsys->M); + geRam_Free(PS->linsys->X); + geRam_Free(PS->linsys->KVector); + geRam_Free(PS->linsys); + } + + PS->linsys = GE_RAM_ALLOCATE_STRUCT(LinearSystemStruct); + if (PS->linsys == NULL) + { + return GE_FALSE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute size of linear system + + PS->sumOfConstraintDimensions = 0; + for ( i = 0; i < PS->PhysicsJointCount; i++) + { + type = gePhysicsJoint_GetType(NewList[i]); + switch (type) + { + case JT_WORLD: + case JT_SPHERICAL: + PS->sumOfConstraintDimensions += 3; + break; + + default: + // shouldn't happen ! + assert(!"Illegal joint kind"); + return GE_FALSE; + } + } + + if (PS->sumOfConstraintDimensions == 0) + return GE_FALSE; + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // alloc mem for the linear system and handle exceptions + + PS->linsys->M = (geFloat**)geRam_Allocate(PS->sumOfConstraintDimensions * sizeof(geFloat*)); + + if (PS->linsys->M == NULL) + { + return GE_FALSE; + } + + for (i = 0; i < PS->sumOfConstraintDimensions; i++) + { + PS->linsys->M[i] = (geFloat*)geRam_Allocate(PS->sumOfConstraintDimensions * sizeof(geFloat)); + + if (PS->linsys->M[i] == NULL) + { + return GE_FALSE; + } + } + + PS->linsys->X = (geFloat*)geRam_Allocate(PS->sumOfConstraintDimensions * sizeof(geFloat)); + + if (PS->linsys->X == NULL) + { + return GE_FALSE; + } + + PS->linsys->KVector = (geFloat*)geRam_Allocate(PS->sumOfConstraintDimensions * sizeof(geFloat)); + + if (PS->linsys->KVector == NULL) + { + return GE_FALSE; + } + + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC gePhysicsSystem_Destroy(gePhysicsSystem** ppPhyssys) +{ + gePhysicsSystem *pPhyssys; + int i; + + pPhyssys = *ppPhyssys; + + geRam_Free(pPhyssys->Objects); + geRam_Free(pPhyssys->Joints); + + // Free any old data + if (pPhyssys->linsys) + { + assert(pPhyssys->linsys->M); + assert(pPhyssys->linsys->X); + assert(pPhyssys->linsys->KVector); + + for (i = 0; i < pPhyssys->sumOfConstraintDimensions; i++) + { + assert(pPhyssys->linsys->M[i]); + geRam_Free(pPhyssys->linsys->M[i]); + } + + geRam_Free(pPhyssys->linsys->M); + geRam_Free(pPhyssys->linsys->X); + geRam_Free(pPhyssys->linsys->KVector); + } + + geRam_Free(pPhyssys->linsys); + geRam_Free(*ppPhyssys); + *ppPhyssys = NULL; + + return GE_TRUE; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// physics stuff follows + +static geFloat fmin(geFloat a, geFloat b) +{ + return a < b ? a : b; +} + +GENESISAPI geBoolean GENESISCC gePhysicsSystem_Iterate(gePhysicsSystem* psPtr, geFloat Time) +{ + int i; + + int numIntegrationSteps; + geFloat minAssemblyRate, subStepSize; + geFloat amountIntegrated = 0.f; + + assert( psPtr != NULL ); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // integrate numIntegrationSteps times during the frame + // this is done to ensure smoother motion and enforce constraint stability + + minAssemblyRate = FLT_MAX; + + if (psPtr->PhysicsJointCount == 0) + { + numIntegrationSteps = 1; + } + + else + numIntegrationSteps = 5; + + if (Time > 0.03f) Time = 0.03f; + + subStepSize = Time / numIntegrationSteps; + + for ( amountIntegrated = 0.f; + amountIntegrated < Time; + amountIntegrated += subStepSize) + { + for (i = 0; i < psPtr->PhysicsObjectCount; i++) + { + if (!gePhysicsObject_ComputeForces(psPtr->Objects[i], psPtr->sourceConfigIndex)) + return GE_FALSE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // enforce constraints + + if (psPtr->sumOfConstraintDimensions > 0) + { + if (!gePhysicsSystem_EnforceConstraints(psPtr, subStepSize)) + return GE_FALSE; + } + + for (i = 0; i < psPtr->PhysicsObjectCount; i++) + { + if (!gePhysicsObject_Integrate(psPtr->Objects[i], subStepSize, psPtr->sourceConfigIndex)) + return GE_FALSE; + } + + psPtr->sourceConfigIndex = (psPtr->sourceConfigIndex == 0 ? 1 : 0); + psPtr->targetConfigIndex = (psPtr->targetConfigIndex == 0 ? 1 : 0); + + // let physical object's control fns update themselves + } + + for (i = 0; i < psPtr->PhysicsObjectCount; i++) + { + gePhysicsObject* pod; + + pod = psPtr->Objects[i]; + + gePhysicsObject_ClearAppliedForce(pod, psPtr->sourceConfigIndex); + gePhysicsObject_ClearAppliedTorque(pod, psPtr->sourceConfigIndex); + gePhysicsObject_SetActiveConfig(psPtr->Objects[i], psPtr->sourceConfigIndex); + } + + return GE_TRUE; +} + +static geBoolean gePhysicsSystem_EnforceConstraints(gePhysicsSystem* PS, geFloat subStepSize) +{ + geFloat h, hSquared; + geVec3d beta, D0, D1; + geVec3d K; + geVec3d rA, rB; + geVec3d accA, accB; + geVec3d velA, velB; + + Matrix33 tmpMat; + Matrix33 term11, term12, term21, term22; + Matrix33 rStarA, itA, itiA, rStarB, itB, itiB; + Matrix33 rotA, rotB, rotAt, rotBt; + + geVec3d tmpVec; + geVec3d jntLocA, jntLocB; + geVec3d jntLocAWS, jntLocBWS; + geVec3d offsetVecA, offsetVecB; + geVec3d omegaA, LA, omegaB, LB; + geVec3d zeroForceAccelerationA, zeroForceAccelerationB; + geVec3d ptVelocityA, ptVelocityB; + geVec3d alphaA, alphaB; + geVec3d ptAccelerationA, ptAccelerationB; + + geVec3d linearVelocityA, linearVelocityB; + geVec3d angularVelocityA, angularVelocityB; + + geXForm3d xformA, xformB; + + Matrix33 iTensorA, iTensorB; + Matrix33 iTensorInvA, iTensorInvB; + + geVec3d constraintForce; + Matrix33 Mblock; + + int i, j, k, iOffset; + int size; + + int si; + + gePhysicsJoint* jntData; + gePhysicsObject *podA, *podB; + + gePhysicsJoint_Kind type; + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // BEGIN + assert( PS != NULL ); + + si = PS->sourceConfigIndex; + + assert(PS != NULL); + + size = PS->sumOfConstraintDimensions; + + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + PS->linsys->M[i][j] = 0.f; + + + for (i = 0, iOffset = 0; i < PS->PhysicsJointCount; i++) + { + jntData = PS->Joints[i]; + h = gePhysicsJoint_GetAssemblyRate(jntData); + hSquared = h * h; + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute joints' actual locations in the world + + type = gePhysicsJoint_GetType(jntData); + + switch(type) + { + case JT_WORLD: + + podA = gePhysicsJoint_GetObject1(jntData); + + assert(podA != NULL); + + gePhysicsObject_GetLocation(podA, &offsetVecA, si); + gePhysicsObject_GetXForm(podA, &xformA, si); + gePhysicsJoint_GetLocationA(jntData, &jntLocA); + + geXForm3d_Rotate(&xformA, &jntLocA, &rA); + geVec3d_Add(&offsetVecA, &rA, &tmpVec); + gePhysicsJoint_SetLocationAInWorldSpace(jntData, &tmpVec); + + Matrix33_MakeCrossProductMatrix33(&rA, &rStarA); + + Matrix33_ExtractFromXForm3d(&xformA, &rotA); + Matrix33_GetTranspose(&rotA, &rotAt); + + gePhysicsObject_GetInertiaTensor(podA, &iTensorA); + gePhysicsObject_GetInertiaTensorInverse(podA, &iTensorInvA); + + Matrix33_Multiply(&rotA, &iTensorA, &tmpMat); + Matrix33_Multiply(&tmpMat, &rotAt, &itA); + + Matrix33_Multiply(&rotA, &iTensorInvA, &tmpMat); + Matrix33_Multiply(&tmpMat, &rotAt, &itiA); + + gePhysicsObject_GetAngularVelocity(podA, &angularVelocityA, si); + + Matrix33_MultiplyVec3d(&rotA, &angularVelocityA, &omegaA); + Matrix33_MultiplyVec3d(&itA, &omegaA, &LA); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // create M submatrix + + Matrix33_MultiplyScalar(gePhysicsObject_GetOneOverMass(podA), &gePhysicsSystemIdentityMatrix, &term11); + Matrix33_Multiply(&rStarA, &itiA, &tmpMat); + Matrix33_Multiply(&tmpMat, &rStarA, &term12); + Matrix33_Subtract(&term11, &term12, &Mblock); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute deviation + + geVec3d_CrossProduct(&omegaA, &LA, &zeroForceAccelerationA); + geVec3d_CrossProduct(&omegaA, &rA, &ptVelocityA); + geVec3d_CrossProduct(&omegaA, &ptVelocityA, &alphaA); + geVec3d_Add(&zeroForceAccelerationA, &alphaA, &ptAccelerationA); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // tmpMat holds rStarA * itiA + + Matrix33_MultiplyVec3d(&tmpMat, &ptAccelerationA, &beta); + + gePhysicsObject_GetLinearVelocity(podA, &linearVelocityA, si); + geVec3d_Add(&linearVelocityA, &ptVelocityA, &D1); + + gePhysicsJoint_GetLocationAInWorldSpace(jntData, &jntLocAWS); + gePhysicsJoint_GetLocationB(jntData, &jntLocB); + geVec3d_Subtract(&jntLocAWS, &jntLocB, &D0); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute K subvector + + geVec3d_Scale(&D1, 2.f / h, &D1); + geVec3d_Scale(&D0, 1.f / hSquared, &D0); + geVec3d_Add(&beta, &D1, &K); + geVec3d_Add(&D0, &K, &K); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // fill linear system appropriately + + PS->linsys->KVector[iOffset] = -K.X; + PS->linsys->KVector[iOffset + 1] = -K.Y; + PS->linsys->KVector[iOffset + 2] = -K.Z; + + for (j = 0; j < 3; j++) + { + for (k = 0; k < 3; k++) + { + PS->linsys->M[iOffset + j][iOffset + k] = Mblock.x[j][k]; + } + } + + iOffset += 3; + break; + + case JT_SPHERICAL: + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute joint locations in world space + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // for gePhysicsObject A + + podA = gePhysicsJoint_GetObject1(jntData); + + assert(podA != NULL); + + gePhysicsObject_GetLocation(podA, &offsetVecA, si); + gePhysicsObject_GetXForm(podA, &xformA, si); + gePhysicsJoint_GetLocationA(jntData, &jntLocA); + + geXForm3d_Rotate(&xformA, &jntLocA, &rA); + geVec3d_Add(&offsetVecA, &rA, &tmpVec); + gePhysicsJoint_SetLocationAInWorldSpace(jntData, &tmpVec); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // for gePhysicsObject B + + podB = gePhysicsJoint_GetObject2(jntData); + + assert(podB != NULL); + + gePhysicsObject_GetLocation(podB, &offsetVecB, si); + gePhysicsObject_GetXForm(podB, &xformB, si); + gePhysicsJoint_GetLocationB(jntData, &jntLocB); + + geXForm3d_Rotate(&xformB, &jntLocB, &rB); + geVec3d_Add(&offsetVecB, &rB, &tmpVec); + gePhysicsJoint_SetLocationBInWorldSpace(jntData, &tmpVec); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // do physics setup + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // for gePhysicsObject A + + Matrix33_MakeCrossProductMatrix33(&rA, &rStarA); + + Matrix33_ExtractFromXForm3d(&xformA, &rotA); + Matrix33_GetTranspose(&rotA, &rotAt); + + gePhysicsObject_GetInertiaTensor(podA, &iTensorA); + gePhysicsObject_GetInertiaTensorInverse(podA, &iTensorInvA); + + Matrix33_Multiply(&rotA, &iTensorA, &tmpMat); + Matrix33_Multiply(&tmpMat, &rotAt, &itA); + + Matrix33_Multiply(&rotA, &iTensorInvA, &tmpMat); + Matrix33_Multiply(&tmpMat, &rotAt, &itiA); + + gePhysicsObject_GetAngularVelocity(podA, &angularVelocityA, si); + + Matrix33_MultiplyVec3d(&rotA, &angularVelocityA, &omegaA); + Matrix33_MultiplyVec3d(&itA, &omegaA, &LA); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // for gePhysicsObject B + + Matrix33_MakeCrossProductMatrix33(&rB, &rStarB); + + Matrix33_ExtractFromXForm3d(&xformB, &rotB); + Matrix33_GetTranspose(&rotB, &rotBt); + + gePhysicsObject_GetInertiaTensor(podB, &iTensorB); + gePhysicsObject_GetInertiaTensorInverse(podB, &iTensorInvB); + + Matrix33_Multiply(&rotB, &iTensorB, &tmpMat); + Matrix33_Multiply(&tmpMat, &rotBt, &itB); + + Matrix33_Multiply(&rotB, &iTensorInvB, &tmpMat); + Matrix33_Multiply(&tmpMat, &rotBt, &itiB); + + gePhysicsObject_GetAngularVelocity(podB, &angularVelocityB, si); + + Matrix33_MultiplyVec3d(&rotB, &angularVelocityB, &omegaB); + Matrix33_MultiplyVec3d(&itB, &omegaB, &LB); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // create M submatrix + + Matrix33_MultiplyScalar(gePhysicsObject_GetOneOverMass(podA) + + gePhysicsObject_GetOneOverMass(podB), &gePhysicsSystemIdentityMatrix, &term11); + + Matrix33_Multiply(&rStarA, &itiA, &tmpMat); + Matrix33_Multiply(&tmpMat, &rStarA, &term12); + + Matrix33_Multiply(&rStarB, &itiB, &tmpMat); + Matrix33_Multiply(&tmpMat, &rStarB, &term22); + + Matrix33_Add(&term12, &term22, &term21); + + Matrix33_Subtract(&term11, &term21, &Mblock); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute deviation + + geVec3d_CrossProduct(&omegaA, &LA, &zeroForceAccelerationA); + geVec3d_CrossProduct(&omegaA, &rA, &ptVelocityA); + geVec3d_CrossProduct(&omegaA, &ptVelocityA, &alphaA); + geVec3d_Add(&zeroForceAccelerationA, &alphaA, &ptAccelerationA); + + geVec3d_CrossProduct(&omegaB, &LB, &zeroForceAccelerationB); + geVec3d_CrossProduct(&omegaB, &rB, &ptVelocityB); + geVec3d_CrossProduct(&omegaB, &ptVelocityB, &alphaB); + geVec3d_Add(&zeroForceAccelerationB, &alphaB, &ptAccelerationB); + + Matrix33_MultiplyVec3d(&itiA, &ptAccelerationA, &tmpVec); + Matrix33_MultiplyVec3d(&rStarA, &tmpVec, &accA); + + Matrix33_MultiplyVec3d(&itiB, &ptAccelerationB, &tmpVec); + Matrix33_MultiplyVec3d(&rStarB, &tmpVec, &accB); + + geVec3d_Subtract(&accA, &accB, &beta); + + gePhysicsObject_GetLinearVelocity(podA, &linearVelocityA, si); + geVec3d_Add(&linearVelocityA, &ptVelocityA, &velA); + gePhysicsObject_GetLinearVelocity(podB, &linearVelocityB, si); + geVec3d_Add(&linearVelocityB, &ptVelocityB, &velB); + + geVec3d_Subtract(&velA, &velB, &D1); + + gePhysicsJoint_GetLocationAInWorldSpace(jntData, &jntLocAWS); + gePhysicsJoint_GetLocationBInWorldSpace(jntData, &jntLocBWS); + + geVec3d_Subtract(&jntLocAWS, &jntLocBWS, &D0); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute K subvector + + geVec3d_Scale(&D1, 2.f / h, &D1); + geVec3d_Scale(&D0, 1.f / hSquared, &D0); + geVec3d_Add(&beta, &D1, &K); + geVec3d_Add(&D0, &K, &K); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // fill linear system appropriately + + PS->linsys->KVector[iOffset] = -K.X; + PS->linsys->KVector[iOffset + 1] = -K.Y; + PS->linsys->KVector[iOffset + 2] = -K.Z; + + for (j = 0; j < 3; j++) + { + for (k = 0; k < 3; k++) + { + PS->linsys->M[iOffset + j][iOffset + k] = Mblock.x[j][k]; + } + } + + iOffset += 3; + break; + + default: + assert(!"Illegal joint type"); + break; + } // switch + } // for + + if (!gePhysicsSystem_SolveForConstraintForces(PS)) + { + return GE_FALSE; + } + + for (i = 0, iOffset = 0; i < PS->PhysicsJointCount; i++) + { + jntData = PS->Joints[i]; + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // compute joints' actual locations in the world + + type = gePhysicsJoint_GetType(jntData); + + switch(type) + { + case JT_WORLD: + + podA = gePhysicsJoint_GetObject1(jntData); + assert(podA != NULL); + + gePhysicsObject_GetXForm(podA, &xformA, si); + gePhysicsJoint_GetLocationA(jntData, &jntLocA); + geXForm3d_Rotate(&xformA, &jntLocA, &rA); + + constraintForce.X = PS->linsys->X[iOffset]; + constraintForce.Y = PS->linsys->X[iOffset + 1]; + constraintForce.Z = PS->linsys->X[iOffset + 2]; + + gePhysicsObject_ApplyGlobalFrameForce(podA, &constraintForce, &rA, GE_FALSE, si); + + iOffset += 3; + + break; + + case JT_SPHERICAL: + + podA = gePhysicsJoint_GetObject1(jntData); + assert(podA != NULL); + + gePhysicsObject_GetXForm(podA, &xformA, si); + gePhysicsJoint_GetLocationA(jntData, &jntLocA); + geXForm3d_Rotate(&xformA, &jntLocA, &rA); + + constraintForce.X = PS->linsys->X[iOffset]; + constraintForce.Y = PS->linsys->X[iOffset + 1]; + constraintForce.Z = PS->linsys->X[iOffset + 2]; + + gePhysicsObject_ApplyGlobalFrameForce(podA, &constraintForce, &rA, GE_FALSE, si); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // apply -ve force to gePhysicsObject B + + podB = gePhysicsJoint_GetObject2(jntData); + assert(podB != NULL); + + gePhysicsObject_GetXForm(podB, &xformB, si); + gePhysicsJoint_GetLocationB(jntData, &jntLocB); + geXForm3d_Rotate(&xformB, &jntLocB, &rB); + + constraintForce.X = -constraintForce.X; + constraintForce.Y = -constraintForce.Y; + constraintForce.Z = -constraintForce.Z; + + gePhysicsObject_ApplyGlobalFrameForce(podB, &constraintForce, &rB, GE_FALSE, si); + + iOffset += 3; + + break; + + default: + break; + } // switch + } // for + + return GE_TRUE; +} + +static int imin(int a, int b) +{ + return a < b ? a : b; +} + +static geBoolean gePhysicsSystem_SolveForConstraintForces(gePhysicsSystem* PS) +{ + int i, j, k, n; + int ixend1, ixend2; + geFloat num; + geFloat** M; + geFloat* b; + geFloat* x; + + assert(PS != NULL); + + b = PS->linsys->KVector; + x = PS->linsys->X; + M = PS->linsys->M; + + assert(b != NULL); + assert(x != NULL); + assert(M != NULL); + + n = PS->sumOfConstraintDimensions; + + for (i = 0; i < n; i++) + { + assert(M[i] != NULL); + + if ((geFloat)fabs(M[i][i]) < (geFloat)(1e-5)) + { + return GE_FALSE; + } + + num = 1 / M[i][i]; + + for (j = i; j < n; j++) + M[i][j] *= num; + + b[i] *= num; + + + + ixend1 = imin(n, i + 3); + + for (j = i + 1; j < ixend1; j++) + { + num = M[j][i]; + + ixend2 = imin(n, i + 2); + + for (k = i; k < ixend2; k++) + { + M[i][k] -= num * M[i][k]; + } + + b[j] -= num * b[i]; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // backsubstitute + + for (i = n - 1; i >= 0; i--) + { + x[i] = b[i]; + + ixend1 = imin(n, i + 2); + + for (j = i + 1; j < ixend1; j++) + { + x[i] -= M[i][j] * x[j]; + } + } + + return GE_TRUE; +} + +GENESISAPI int GENESISCC gePhysicsSystem_GetSourceConfigIndex(const gePhysicsSystem* pSys) +{ + assert(pSys != NULL); + + return pSys->sourceConfigIndex; +} + +GENESISAPI gePhysicsObject** GENESISCC gePhysicsSystem_GetPhysicsObjects(const gePhysicsSystem* pSys) +{ + assert(pSys != NULL); + + return pSys->Objects; +} + +GENESISAPI gePhysicsJoint** GENESISCC gePhysicsSystem_GetPhysicsJoints(const gePhysicsSystem* pSys) +{ + assert(pSys != NULL); + + return pSys->Joints; +} + +GENESISAPI int GENESISCC gePhysicsSystem_GetNumPhysicsObjects(const gePhysicsSystem* pSys) +{ + assert(pSys != NULL); + + return pSys->PhysicsObjectCount; +} + +GENESISAPI int GENESISCC gePhysicsSystem_GetNumPhysicsJoints(const gePhysicsSystem* pSys) +{ + assert(pSys != NULL); + + return pSys->PhysicsJointCount; +} + +GENESISAPI int GENESISCC gePhysicsSystem_GetSumOfConstraintDimensions(const gePhysicsSystem* pSys) +{ + assert(pSys != NULL); + + return pSys->sumOfConstraintDimensions; +} + diff --git a/G3D/Physics/PhysicsSystem.h b/G3D/Physics/PhysicsSystem.h new file mode 100644 index 0000000..176fb81 --- /dev/null +++ b/G3D/Physics/PhysicsSystem.h @@ -0,0 +1,54 @@ +/****************************************************************************************/ +/* PHYSICSSYSTEM.H */ +/* */ +/* Author: Jason Wood */ +/* Description: Rigid body, constraint based physics system interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#if !defined (PHYSICSSYSTEM_H) +#define PHYSICSSYSTEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct gePhysicsSystem gePhysicsSystem; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// ctor / dtor + +GENESISAPI gePhysicsSystem *GENESISCC gePhysicsSystem_Create(void); +GENESISAPI geBoolean GENESISCC gePhysicsSystem_Destroy(gePhysicsSystem** ppSys); + +GENESISAPI geBoolean GENESISCC gePhysicsSystem_Iterate(gePhysicsSystem* psPtr, geFloat Time); + +GENESISAPI geBoolean GENESISCC gePhysicsSystem_AddJoint(gePhysicsSystem *psPtr, gePhysicsJoint *Joint); +GENESISAPI geBoolean GENESISCC gePhysicsSystem_AddObject(gePhysicsSystem *psPtr, gePhysicsObject *Object); + +GENESISAPI int GENESISCC gePhysicsSystem_GetSourceConfigIndex(const gePhysicsSystem* pSys); +GENESISAPI gePhysicsObject** GENESISCC gePhysicsSystem_GetPhysobs(const gePhysicsSystem* pSys); +GENESISAPI gePhysicsJoint** GENESISCC gePhysicsSystem_GetPhysjnts(const gePhysicsSystem* pSys); +GENESISAPI int GENESISCC gePhysicsSystem_GetNumPhysobs(const gePhysicsSystem* pSys); +GENESISAPI int GENESISCC gePhysicsSystem_GetNumPhysjnts(const gePhysicsSystem* pSys); +GENESISAPI int GENESISCC gePhysicsSystem_GetSumOfConstraintDimensions(const gePhysicsSystem* pSys); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Physics/matrix33.c b/G3D/Physics/matrix33.c new file mode 100644 index 0000000..5e04d28 --- /dev/null +++ b/G3D/Physics/matrix33.c @@ -0,0 +1,201 @@ +/****************************************************************************************/ +/* MATRIX33.H */ +/* */ +/* Author: Jason Wood */ +/* Description: Pure 3x3 matrix */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "vec3d.h" +#include "xform3d.h" +#include "matrix33.h" + +void Matrix33_MakeCrossProductMatrix33(const geVec3d* v, + Matrix33* m) +{ + assert(v != NULL); + assert(m != NULL); + + m->x[0][0] = m->x[1][1] = m->x[2][2] = 0.0f; + m->x[0][1] = -v->Z; m->x[0][2] = v->Y; + m->x[1][0] = v->Z; m->x[1][2] = -v->X; + m->x[2][0] = -v->Y; m->x[2][1] = v->X; +} + +void Matrix33_ExtractFromXForm3d(const geXForm3d* xform, Matrix33* m) +{ + assert(xform != NULL); + assert(m != NULL); + + m->x[0][0] = xform->AX; m->x[0][1] = xform->AY; m->x[0][2] = xform->AZ; + m->x[1][0] = xform->BX; m->x[1][1] = xform->BY; m->x[1][2] = xform->BZ; + m->x[2][0] = xform->CX; m->x[2][1] = xform->CY; m->x[2][2] = xform->CZ; +} + +void Matrix33_MultiplyVec3d(const Matrix33* m, const geVec3d* v, geVec3d* res) +{ + assert(m != NULL); + assert(v != NULL); + assert(res != NULL); + + res->X = m->x[0][0] * v->X + m->x[0][1] * v->Y + m->x[0][2] * v->Z; + res->Y = m->x[1][0] * v->X + m->x[1][1] * v->Y + m->x[1][2] * v->Z; + res->Z = m->x[2][0] * v->X + m->x[2][1] * v->Y + m->x[2][2] * v->Z; +} + +void Matrix33_Multiply(const Matrix33* m1, const Matrix33* m2, Matrix33* res) +{ + int i, j, k; + + assert(m1 != NULL); + assert(m2 != NULL); + assert(res != NULL); + + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + res->x[i][j] = 0.0f; + + for (k = 0; k < 3; k++) + res->x[i][j] += m1->x[i][k] * m2->x[k][j]; + } + } +} + +void Matrix33_GetTranspose(const Matrix33* m, Matrix33* t) +{ + int i, j; + + assert(m != NULL); + assert(t != NULL); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + t->x[j][i] = m->x[i][j]; +} + +void Matrix33_Copy(const Matrix33* m, Matrix33* c) +{ + int i, j; + + assert(m != NULL); + assert(c != NULL); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + c->x[i][j] = m->x[i][j]; +} + +void Matrix33_SetIdentity(Matrix33* m) +{ + int i, j; + + assert(m != NULL); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + { + if (i == j) + m->x[i][j] = 1.f; + else m->x[i][j] = 0.f; + } +} + +void Matrix33_Add(const Matrix33* m1, const Matrix33* m2, Matrix33* res) +{ + int i, j; + + assert(m1 != NULL); + assert(m2 != NULL); + assert(res != NULL); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + res->x[i][j] = m1->x[i][j] + m2->x[i][j]; +} + +void Matrix33_Subtract(const Matrix33* m1, const Matrix33* m2, Matrix33* res) +{ + int i, j; + + assert(m1 != NULL); + assert(m2 != NULL); + assert(res != NULL); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + res->x[i][j] = m1->x[i][j] - m2->x[i][j]; +} + +void Matrix33_MultiplyScalar(geFloat s, const Matrix33* m, Matrix33* res) +{ + int i, j; + + assert(m != NULL); + assert(res != NULL); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + res->x[i][j] = s * m->x[i][j]; +} + +void Matrix33_GetInverse(const Matrix33* m, Matrix33* inv) +{ + int i, j, k; + Matrix33 copy; + + assert(m != NULL); + assert(inv != NULL); + + Matrix33_Copy(m, ©); + Matrix33_SetIdentity(inv); + + for (i = 0; i < 3; i++) + { + if (copy.x[i][i] != 1.0f) + { + geFloat divby = copy.x[i][i]; + + assert(fabs(divby) >= 1e-5); + + for (j = 0; j < 3; j++) + { + inv->x[i][j] /= divby; + copy.x[i][j] /= divby; + } + } + for (j = 0; j < 3; j++) + { + if (j != i) + { + if (copy.x[j][i] != 0.0f) + { + geFloat mulby = copy.x[j][i]; + for (k = 0; k < 3; k++) + { + copy.x[j][k] -= mulby * copy.x[i][k]; + inv->x[j][k] -= mulby * inv->x[i][k]; + } + } + } + } + } +} + diff --git a/G3D/Physics/matrix33.h b/G3D/Physics/matrix33.h new file mode 100644 index 0000000..e73cd0d --- /dev/null +++ b/G3D/Physics/matrix33.h @@ -0,0 +1,51 @@ +/****************************************************************************************/ +/* MATRIX33.H */ +/* */ +/* Author: Jason Wood */ +/* Description: Pure 3x3 matrix */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef MATRIX33_H +#define MATRIX33_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + geFloat x[3][3]; +} Matrix33; + +void Matrix33_Copy(const Matrix33* m, Matrix33* c); +void Matrix33_SetIdentity(Matrix33* m); +void Matrix33_Add(const Matrix33* m1, const Matrix33* m2, Matrix33* res); +void Matrix33_Subtract(const Matrix33* m1, const Matrix33* m2, Matrix33* res); +void Matrix33_MultiplyVec3d(const Matrix33* m, const geVec3d* v, geVec3d* res); +void Matrix33_Multiply(const Matrix33* m1, const Matrix33* m2, Matrix33* res); +void Matrix33_MultiplyScalar(geFloat s, const Matrix33* m, Matrix33* res); +void Matrix33_GetTranspose(const Matrix33* m, Matrix33* t); +void Matrix33_GetInverse(const Matrix33* m, Matrix33* inv); +void Matrix33_MakeCrossProductMatrix33(const geVec3d* v, Matrix33* m); +void Matrix33_ExtractFromXForm3d(const geXForm3d* xform, Matrix33* m); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Ptrtypes.h b/G3D/Ptrtypes.h new file mode 100644 index 0000000..bbf79c8 --- /dev/null +++ b/G3D/Ptrtypes.h @@ -0,0 +1,67 @@ +/****************************************************************************************/ +/* PtrTypes.c */ +/* */ +/* Description: File to resolve interdependency problems */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#ifndef GE_PTRTYPES_H +#define GE_PTRTYPES_H + +#include "BaseType.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// System.h +typedef struct geEngine geEngine; + +// Light.h +typedef struct Light_LightInfo Light_LightInfo; + +// Surface.h +typedef struct Surf_SurfInfo Surf_SurfInfo; +typedef struct Surf_TexVert Surf_TexVert; + +// World.h +typedef struct geWorld geWorld; + +// Frustum.h +typedef struct Frustum_Info Frustum_Info; + +// World.h +typedef struct World_BSP World_BSP; +typedef struct geWorld_Leaf geWorld_Leaf; + + +// Mesh.h +typedef struct Mesh_MeshInfo Mesh_MeshInfo; +typedef struct Mesh_MeshDef Mesh_MeshDef; +typedef struct Mesh_RenderQ Mesh_RenderQ; + +// Entities.h +typedef struct geEntity_EntitySet geEntity_EntitySet; + +// User.h +typedef struct User_Info User_Info; +typedef struct gePoly gePoly; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/G3D/RCa24739 b/G3D/RCa24739 new file mode 100644 index 0000000000000000000000000000000000000000..a19403d3552bbe6bfac401b91bf0840760dcd33b GIT binary patch literal 5060 zcmd6r+ioI95QghIQr=+#H(ALd#(2H!+<_0oTGm(wlSGPyhz|sX9j^edHd0Xf%rtJ#C2w(X;%ckJ0- zY-0C3Y4zfBk-Oqnmh4;m#>xeKqWr+|9xeB*dPdi?J=qLv&XN6za|}gVC(t^)dBK(u zw8Vx`W#hyK&>x{E+{@jy6&jGGxYYsUW-F|{^m&5a(0n%3&Q(wUBmw>(&+0v;oZ*;)wK+9 zEqJcsx#QY&7!MRLrHSS%{QSud(A;5N1B&NaT+!#P?+9gjl`3pVRSn>~r@mxCAG)ZI z_$$o6<_uP<6RIyNI*R$Cr7?1j>^Sl*$7G+*R3~ctUrR-F^@zv>WN9j-bL)N0}Wdue#(uS$GrZl6J|e7JNls&CLU3A8@U?JFUGzdK>KB5zp>g z4sm&_g6vC&k0zEW7aeNUUS%0+f)>lGtP0-nZtLgF~jjES6F;pB%Xq}O1 zRsE1`jPT@lWMa(bkzan3*gww3Q!;yk zy;ZI{*4dhC=^}sNI;;BZ#QxkN!|lu_VNjlijOa<(3-K#@TtUm2W1USmPUk<;mf0^-fSTr$^U&M;G$3(Y)KwLp{1UjaTpf<8{TDoVa*aiQj5YeFb&## uu8{A>cZuYF`x*Sz_5c2NAjEI`?;zjnE2_Ry_B%rB>nLRhq<_J7LBYRUBYpJ% literal 0 HcmV?d00001 diff --git a/G3D/RCb24739 b/G3D/RCb24739 new file mode 100644 index 0000000000000000000000000000000000000000..2d14941b03c8634da6a3a7daa8b0b2c34778731e GIT binary patch literal 5060 zcmd6r+ioI95QghIQr=+#H(ALd#(2H!+<_0oTGm(wlSGPyhz|sX9j^edHd0Xf%rtJ#C2w(X;%ckJ0- zY-0C3Y4zgsu)tk$D@*pRePiWH!~*0)=`usTm|ySA473Z=vEduu>xaUcAbMf-OI>%ujeqau#@6EScc^w@WbRE3QLz-BEjI=>}e9g!kdPhW}Nh(bsvxyPqAZYZ>BN z@La=l$F=D&9w=T)6U|rn`I8->xx=~!6wkA`qR(635z6!`RoIZK8o+l?eaV78bWtDi zSD1gz8LU*dR$o+f6!S$(W8@s!apYT$$v&N_PSp0lmWt@=5s?YV(o{(2*87^vF;ufd z_pV2j`_>~{x7?{uU-PV9b;*6Q@FvhD?UGe3_=>!mn+M1~;97HcT6=@^HrTr(p53(^ z;__An*_RFmLpQVwSk_dd%G;h^H=BGny6DE7JHOy^{Wq~ z)d5%W`ZkvNmB(18<2d68`n$}z8&?ss{%GN?uY}^7ptAv2)8#`NRWEH~s5q3+IwRAn z`XSjE;mIQ_Q)2U+P3cYCvhvVQowdL7>*sorqes*=u{5tr=+$KVfR+@^Qz)wA5<8y2 zy=uLxG_}7#)WGout_!!<&`w10_gzu@mI<;4&a0qlo&4bQIb89+#v?!IDem32$tqS) zkRePf!}|5O*3&v!%7OPJ#gp-p=et?d!mFXo28uPx% zbd-t9lf&KWouFn;kFNKQF63jQdAFa3dUSCbuipK~>xwZsaq+AYztx=j64V~*jLv+^ zecjCj^=CgH;%Tw^`z=TP>YTo%XGoU5Pril?%J1TLWeE%}e#dBzOgK~OT>9g=vd&VE zzS>u^^h@=hvJa7^WvV;u3q1A%`j@|JmeCyN|CC+qW{DSQ`qFQQ{j8NxC$az4dFSz6 uA>WPf63PAcGx)3P|NZYkh~M_#LB7{lRDGrFcZAm0QOXWT|AOs;f`0+Y0e%$# literal 0 HcmV?d00001 diff --git a/G3D/RCc24739 b/G3D/RCc24739 new file mode 100644 index 0000000000000000000000000000000000000000..2d14941b03c8634da6a3a7daa8b0b2c34778731e GIT binary patch literal 5060 zcmd6r+ioI95QghIQr=+#H(ALd#(2H!+<_0oTGm(wlSGPyhz|sX9j^edHd0Xf%rtJ#C2w(X;%ckJ0- zY-0C3Y4zgsu)tk$D@*pRePiWH!~*0)=`usTm|ySA473Z=vEduu>xaUcAbMf-OI>%ujeqau#@6EScc^w@WbRE3QLz-BEjI=>}e9g!kdPhW}Nh(bsvxyPqAZYZ>BN z@La=l$F=D&9w=T)6U|rn`I8->xx=~!6wkA`qR(635z6!`RoIZK8o+l?eaV78bWtDi zSD1gz8LU*dR$o+f6!S$(W8@s!apYT$$v&N_PSp0lmWt@=5s?YV(o{(2*87^vF;ufd z_pV2j`_>~{x7?{uU-PV9b;*6Q@FvhD?UGe3_=>!mn+M1~;97HcT6=@^HrTr(p53(^ z;__An*_RFmLpQVwSk_dd%G;h^H=BGny6DE7JHOy^{Wq~ z)d5%W`ZkvNmB(18<2d68`n$}z8&?ss{%GN?uY}^7ptAv2)8#`NRWEH~s5q3+IwRAn z`XSjE;mIQ_Q)2U+P3cYCvhvVQowdL7>*sorqes*=u{5tr=+$KVfR+@^Qz)wA5<8y2 zy=uLxG_}7#)WGout_!!<&`w10_gzu@mI<;4&a0qlo&4bQIb89+#v?!IDem32$tqS) zkRePf!}|5O*3&v!%7OPJ#gp-p=et?d!mFXo28uPx% zbd-t9lf&KWouFn;kFNKQF63jQdAFa3dUSCbuipK~>xwZsaq+AYztx=j64V~*jLv+^ zecjCj^=CgH;%Tw^`z=TP>YTo%XGoU5Pril?%J1TLWeE%}e#dBzOgK~OT>9g=vd&VE zzS>u^^h@=hvJa7^WvV;u3q1A%`j@|JmeCyN|CC+qW{DSQ`qFQQ{j8NxC$az4dFSz6 uA>WPf63PAcGx)3P|NZYkh~M_#LB7{lRDGrFcZAm0QOXWT|AOs;f`0+Y0e%$# literal 0 HcmV?d00001 diff --git a/G3D/RCd24739 b/G3D/RCd24739 new file mode 100644 index 0000000000000000000000000000000000000000..527c1250d5c3139385730cf885f1017e317864b7 GIT binary patch literal 5060 zcmd6r+in_H6o%JzrM|-yZW_s=#yCz~Rh7U8YK0ifVA@KN5Ve7#k|6>dwNhRvZ`tqP zdp0w}Ic+Y`h&im;>-?{^_E5C3jV!jlMOLl9jxH_zBI zf)-iOGPNG`KJ32`xEN2G{Tt^SyuQFs#p4S43BTq1?8?YbJo(z*TmA6U+R{Q>@c*ns5aDZRXsas|ZzhLViuqS%a(Y@*$0?mnJb(913Wi zlWA4`kZg?bq|eHj*i4csy^UK|9^1LI_7Bc}uID*AL|qe0^QwSeO}6)FiP1cRqB<_H z;|bjB)~iZm`v*kz9B<&da(fN!L==DD6}4}fBD?3j3Ys>_4?bVQmEG5PHJu=)(Y!U|LX~>A4l)VtYyvHT9j5#*hbmydgM24bR zW2Yc&KP{wf%E~1`PgXQ9p<4Pou9_*cmLUS`Iwx!c$SIZdQN=_Y7ccm zXTImY>Sluav!4&yX|ewMEk*tMoW7=KNS3}&zJ?9T@A7wL0SxB9V+wALOsUD3JL%8P zl}(m<^i{r+rSGV$FVTO_K17xlsqU~Z@YoONU;VCGMRPX)=j>v)OT0qUmwr1OX03!e z$@*VjbRORo(%twzkvwcagTK1|-~SGT_+9@Uq +#include +#include +#include + +#include "BaseType.h" +#include "ErrorLog.h" +#include "VFile.h" +#include "Sound.h" +#include "Ram.h" + +typedef struct SoundManager SoundManager; +typedef struct Channel Channel; + + +typedef struct geSound_System +{ + geBoolean Active; + SoundManager *SoundM; + geFloat GlobalVolume; +} geSound_System; + +typedef struct geSound_Cfg +{ + geFloat Volume; + geFloat Pan; + geFloat Frequency; +} geSound_Cfg; + + +/* + The interfaces here allow an application to write sound data to + abstract channels which are then to be mixed. The interfaces here + require two things. First, that the application create only one + sound manager per instance, and second that the type of sound data + being passed into the sound channels remains constant. That is, + the format of the binary information is all one format from + one sound to another; the application cannot combine RIFF and WAV + formats in a single channel. +*/ +/* + Call these ones only once per application: +*/ + +static SoundManager * CreateSoundManager(HWND hWnd); +static void DestroySoundManager(SoundManager *sm); + +//static BOOL FillSoundChannel(SoundManager *sm, char* Dir, char *Name, unsigned int* Handle ); +static BOOL FillSoundChannel(SoundManager *sm, geVFile *File, unsigned int* Handle ); +//static BOOL FillSoundChannelMemory(SoundManager *sm, const void *Buffer, unsigned int* Handle ); +static BOOL StartSoundChannel( SoundManager *sm, unsigned int Handle, geSound_Cfg *cfg, int loop, unsigned int* sfx); +static BOOL StopSoundChannel(Channel *channel); +static BOOL FreeAllChannels(SoundManager *sm); +static BOOL FreeChannel(SoundManager *sm, Channel *channel); +static BOOL ModifyChannel( Channel *channel, geSound_Cfg *cfg ); +static int ChannelPlaying( Channel *channel ); +static Channel* GetChannel( SoundManager *sm, unsigned int ID ); + + +typedef struct Channel +{ +// char* name; + LPDIRECTSOUNDBUFFER buffer; + unsigned int ID; + int BaseFreq; + geSound_Cfg cfg; + void * Data; + struct Channel *next; + struct Channel *nextDup; +} Channel; + +typedef struct SoundManager +{ + int smChannelCount; + unsigned int smNextChannelID; + + LPDIRECTSOUNDBUFFER smPrimaryChannel; + Channel* smChannels; + //LPDIRECTSOUNDNOTIFY * smNotify; +} SoundManager; + +static LPDIRECTSOUND lpDirectSound; +// This isn't really safe as a global. But it's consistent with the global lpDirectSound. +static HMODULE hmodDirectSound = NULL; + +// Added 11/08/1999 Ed Averill to expose DSound object for external code +GENESISAPI void *geSound_GetDSound() +{ + return (void *)lpDirectSound; +} +// End 11/08/1999 addition + +//===================================================================================== +// geSound_SystemCreate +//===================================================================================== +GENESISAPI geSound_System *geSound_CreateSoundSystem(HWND hWnd) +{ + geSound_System *SoundSystem; + + SoundSystem = GE_RAM_ALLOCATE_STRUCT(geSound_System); + + if (!SoundSystem) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return NULL; + } + + memset(SoundSystem, 0, sizeof(geSound_System)); + + // Initialize the sound system + SoundSystem->SoundM = CreateSoundManager(hWnd); + + if (!SoundSystem->SoundM) + { + geRam_Free(SoundSystem); + geErrorLog_Add(GE_ERR_CREATE_SOUND_MANAGER_FAILED, NULL); + return NULL; + } + SoundSystem->GlobalVolume = 1.0f; + + return SoundSystem; +} + +//===================================================================================== +// geSound_SystemFree +//===================================================================================== +GENESISAPI void geSound_DestroySoundSystem(geSound_System *Sound) +{ + assert(Sound != NULL); + + // Shutdown the sound system + DestroySoundManager(Sound->SoundM); + + Sound->SoundM = NULL; + + geRam_Free(Sound); +} + +//===================================================================================== +// Sound_LoadSound +//===================================================================================== +//GENESISAPI geSound_Def *geSound_LoadSoundDef(geSound_System *SoundS, const char *Path, const char *FileName) +GENESISAPI geSound_Def *geSound_LoadSoundDef(geSound_System *SoundS, geVFile *File) +{ + unsigned int SoundDef = 0; + + assert(SoundS != NULL); + +// if (!FillSoundChannel(SoundS->SoundM, (char*)Path, (char*)FileName, &SoundDef)) + if (!FillSoundChannel(SoundS->SoundM, File, &SoundDef)) + return 0; + + return (geSound_Def *)SoundDef; +} + +#if 0 +//===================================================================================== +// Sound_LoadSound +//===================================================================================== +GENESISAPI geSound_Def *geSound_LoadSoundDefFromMemory( + geSound_System *SoundS, + const void *Buffer) +{ + unsigned int SoundDef = 0; + + assert(SoundS != NULL); + assert(Buffer != NULL); + + if (!FillSoundChannelMemory(SoundS->SoundM, Buffer, &SoundDef)) + return 0; + + return (geSound_Def *)SoundDef; +} +#endif + +//===================================================================================== +// Sound_FreeSound +//===================================================================================== +GENESISAPI void geSound_FreeSoundDef(geSound_System *SoundS, geSound_Def *SoundDef) +{ + Channel* Channel; + + assert(SoundS != NULL); + assert(SoundDef != 0); + + Channel = GetChannel(SoundS->SoundM, (unsigned int)SoundDef); + + if (!Channel) + return; + + FreeChannel(SoundS->SoundM, Channel); +} + +//===================================================================================== +// Sound_FreeAllChannels +//===================================================================================== +GENESISAPI void geSound_FreeAllChannels(geSound_System *SoundS) +{ + if (!SoundS) return; + + FreeAllChannels( SoundS->SoundM ); +} + +//===================================================================================== +// Sound_SetGlobalVolume +//===================================================================================== +GENESISAPI geBoolean geSound_SetMasterVolume( geSound_System *SoundS, geFloat Volume ) +{ + if( !SoundS ) + return( GE_FALSE ); + SoundS->GlobalVolume = Volume; + return( GE_TRUE ); +} + +//===================================================================================== +// Sound_PlaySound +//===================================================================================== +GENESISAPI geSound *geSound_PlaySoundDef(geSound_System *SoundS, + geSound_Def *SoundDef, + geFloat Volume, + geFloat Pan, + geFloat Frequency, + geBoolean Loop) +{ + unsigned int Sound; + geSound_Cfg LocalCfg; + + LocalCfg.Volume = Volume; + LocalCfg.Pan = Pan; + LocalCfg.Frequency = Frequency; + + LocalCfg.Volume *= SoundS->GlobalVolume; + if (!StartSoundChannel(SoundS->SoundM, (unsigned int)SoundDef, &LocalCfg, (BOOL)Loop, &Sound)) + { + return 0; + } + + return (geSound *)Sound; +} + +//===================================================================================== +// Sound_StopSound +//===================================================================================== +GENESISAPI geBoolean geSound_StopSound(geSound_System *SoundS, geSound *Sound) +{ + Channel* Channel; + + assert(SoundS != NULL); + assert(Sound != NULL); + + Channel = GetChannel(SoundS->SoundM, (unsigned int)Sound); + + if (!Channel) + return GE_FALSE; + + return StopSoundChannel(Channel); +} + +//===================================================================================== +// Sound_ModifySound +//===================================================================================== +GENESISAPI geBoolean geSound_ModifySound(geSound_System *SoundS, + geSound *Sound,geFloat Volume, + geFloat Pan, + geFloat Frequency) +{ + Channel* Channel; + geSound_Cfg LocalCfg; + + assert(SoundS != NULL); + assert(Sound != NULL); + + Channel = GetChannel(SoundS->SoundM, (unsigned int)Sound); + + if (!Channel) + return GE_FALSE; + LocalCfg.Volume = Volume; + LocalCfg.Pan = Pan; + LocalCfg.Frequency = Frequency; + LocalCfg.Volume *= SoundS->GlobalVolume; + return ModifyChannel(Channel, &LocalCfg); +} + +//===================================================================================== +// Sound_SoundIsPlaying +//===================================================================================== +GENESISAPI geBoolean geSound_SoundIsPlaying(geSound_System *SoundS, geSound *Sound) +{ + Channel* Channel; + + assert(SoundS != NULL); + if(Sound == NULL) + return GE_FALSE; // eaa3 05/29/2000 don't assert if NULL handle! + + Channel = GetChannel(SoundS->SoundM, (unsigned int)Sound); + + if (!Channel) + return GE_FALSE; + + return ChannelPlaying(Channel); +} + + +//===================================================================================== +//===================================================================================== + +static BOOL DSParseWaveResource(const void *pvRes, WAVEFORMATEX **ppWaveHeader, + BYTE **ppbWaveData,DWORD *pcbWaveSize) +{ + DWORD *pdw; + DWORD *pdwEnd; + DWORD dwRiff; + DWORD dwType; + DWORD dwLength; + + if (ppWaveHeader) + *ppWaveHeader = NULL; + + if (ppbWaveData) + *ppbWaveData = NULL; + + if (pcbWaveSize) + *pcbWaveSize = 0; + + pdw = (DWORD *)pvRes; + dwRiff = *pdw++; + dwLength = *pdw++; + dwType = *pdw++; + + if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F')) + goto exit; // not even RIFF + + if (dwType != mmioFOURCC('W', 'A', 'V', 'E')) + goto exit; // not a WAV + + pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4); + + while (pdw < pdwEnd) + { + dwType = *pdw++; + dwLength = *pdw++; + + switch (dwType) + { + case mmioFOURCC('f', 'm', 't', ' '): + if (ppWaveHeader && !*ppWaveHeader) + { + if (dwLength < sizeof(WAVEFORMAT)) + goto exit; // not a WAV + + *ppWaveHeader = (WAVEFORMATEX *)pdw; + + if ((!ppbWaveData || *ppbWaveData) && + (!pcbWaveSize || *pcbWaveSize)) + { + return TRUE; + } + } + break; + + case mmioFOURCC('d', 'a', 't', 'a'): + if ((ppbWaveData && !*ppbWaveData) || + (pcbWaveSize && !*pcbWaveSize)) + { + if (ppbWaveData) + *ppbWaveData = (LPBYTE)pdw; + + if (pcbWaveSize) + *pcbWaveSize = dwLength; + + if (!ppWaveHeader || *ppWaveHeader) + return TRUE; + } + break; + } + + pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1)); + } + +exit: + return FALSE; +} + +static BOOL DSFillSoundBuffer(IDirectSoundBuffer *pDSB, BYTE *pbWaveData, DWORD cbWaveSize) +{ + + if (pDSB && pbWaveData && cbWaveSize) + { + LPVOID pMem1, pMem2; + DWORD dwSize1, dwSize2; + + if (SUCCEEDED(IDirectSoundBuffer_Lock(pDSB, 0, cbWaveSize, + &pMem1, &dwSize1, &pMem2, &dwSize2, 0))) + { + ZeroMemory(pMem1, dwSize1); + CopyMemory(pMem1, pbWaveData, dwSize1); + + if ( 0 != dwSize2 ) + CopyMemory(pMem2, pbWaveData+dwSize1, dwSize2); + + IDirectSoundBuffer_Unlock(pDSB, pMem1, dwSize1, pMem2, dwSize2); + return TRUE; + } + } + return FALSE; +} + + +DSCAPS dsCaps; +static SoundManager * CreateSoundManager(HWND hWnd ) +{ + typedef HRESULT (WINAPI *DS_CREATE_FUNC)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); + PCMWAVEFORMAT pcmwf; + DSBUFFERDESC dsbdesc; + HRESULT hres; + SoundManager * sm; + DS_CREATE_FUNC pDirectSoundCreate; + + // load the DirectSound DLL + hmodDirectSound = LoadLibrary ("DSOUND.DLL"); + if (hmodDirectSound == NULL) + { + // Couldn't load DSOUND.DLL + return NULL; + } + + pDirectSoundCreate = (DS_CREATE_FUNC)GetProcAddress (hmodDirectSound, "DirectSoundCreate"); + if (pDirectSoundCreate == NULL) + { + // couldn't find the DirectSoundCreate function + FreeLibrary (hmodDirectSound); + return NULL; + } + + hres = pDirectSoundCreate(NULL, &lpDirectSound, NULL); + if (hres != DS_OK) + { + // failed somehow + FreeLibrary (hmodDirectSound); + return NULL; + } + +// sm = malloc(sizeof(*sm)); + sm = geRam_Allocate(sizeof(*sm)); + if (!sm) + { + IDirectSound_Release(lpDirectSound); + FreeLibrary (hmodDirectSound); + return NULL; + } + sm->smChannelCount = 0; + sm->smNextChannelID = 1; + sm->smChannels = NULL; + + memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT)); + pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM; + + //pcmwf.wf.nChannels = 1; + //pcmwf.wf.nSamplesPerSec = 44050; + //pcmwf.wf.nBlockAlign = 2; +#if 1 + pcmwf.wf.nChannels = 2; + pcmwf.wf.nSamplesPerSec = 44100; + pcmwf.wf.nBlockAlign = 4; + pcmwf.wBitsPerSample = 16; + pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign; +#else + pcmwf.wf.nChannels = 1; + pcmwf.wf.nSamplesPerSec = 22050; + pcmwf.wf.nBlockAlign = 1; + pcmwf.wBitsPerSample = 8; + pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * 2; +#endif + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;// | DSBCAPS_CTRLDEFAULT;// | DSBCAPS_CTRL3D; + dsbdesc.dwBufferBytes = 0; //dwBufferBytes and lpwfxFormat must be set this way. + dsbdesc.lpwfxFormat = NULL; + +#if 1 + if (DS_OK== IDirectSound_SetCooperativeLevel(lpDirectSound, hWnd,DSSCL_NORMAL)) +#else + if (DS_OK== IDirectSound_SetCooperativeLevel(lpDirectSound, hWnd,DSSCL_EXCLUSIVE)) +#endif + { + if (DS_OK== IDirectSound_CreateSoundBuffer(lpDirectSound, &dsbdesc, &sm->smPrimaryChannel, NULL)) + { + return sm; + } + IDirectSound_Release(lpDirectSound); + FreeLibrary (hmodDirectSound); + } +// free( sm ); + geRam_Free(sm); + return NULL; +} + +//static BOOL CreateChannel( char* Name, DSBUFFERDESC* dsBD, Channel** chanelPtr) +static BOOL CreateChannel(DSBUFFERDESC* dsBD, Channel** chanelPtr) +{ + Channel* channel; + +// channel = malloc( sizeof( Channel ) ); + channel = geRam_Allocate( sizeof( Channel ) ); + if ( channel == NULL ) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return( FALSE ); + } + if(DS_OK != IDirectSound_CreateSoundBuffer(lpDirectSound, dsBD, &channel->buffer, NULL)) + { + geErrorLog_Add(GE_ERR_CREATE_SOUND_BUFFER_FAILED, NULL); + return FALSE; + } + if(DS_OK != IDirectSoundBuffer_GetFrequency(channel->buffer, &channel->BaseFreq) ) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + channel->next = NULL; + channel->nextDup = NULL; + channel->ID = 0; + channel->cfg.Volume = 1.0f; + channel->cfg.Pan = 0.0f; + channel->cfg.Frequency = 0.0f; +// channel->name = Name; + + *chanelPtr = channel; + return( TRUE ); +} + +//static BOOL GetSoundData( char* Name, unsigned char** dataPtr) +static BOOL GetSoundData( geVFile *File, unsigned char** dataPtr) +{ +// FILE * f; + int32 Size; + uint8 *data; +// int32 CurPos; + +#if 0 + f = fopen(Name, "rb"); + + if (!f) + { + geErrorLog_Add(GE_ERR_FILE_OPEN_ERROR, NULL); + return FALSE; + } +#endif + +#if 0 + CurPos = ftell (f); // Save the startinf pos into this function + fseek (f, 0, SEEK_END); // Seek to end + Size = ftell (f); // Get End (this will be the size) + fseek (f, CurPos, SEEK_SET); // Restore file position +#endif + + if (geVFile_Size(File, &Size) == GE_FALSE) + return FALSE; + + data = geRam_Allocate(Size); + + if (!data) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return FALSE; + } + + if (geVFile_Read(File, data, Size) == GE_FALSE) + { + geRam_Free(data); + return FALSE; + } + +// fread(data, Size, 1, f); + +// fclose(f); + *dataPtr = data; + return( TRUE ); +} + +static BOOL ParseData( const uint8* data, DSBUFFERDESC* dsBD, BYTE ** pbWaveData ) +{ + + //Parse the Data + memset(dsBD, 0, sizeof(DSBUFFERDESC)); + + dsBD->dwSize = sizeof(DSBUFFERDESC); + dsBD->dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + if (!DSParseWaveResource(data, &dsBD->lpwfxFormat, pbWaveData, &dsBD->dwBufferBytes)) + { + geErrorLog_Add(GE_ERR_INVALID_WAV, NULL); + return FALSE; + } + return( TRUE ); + +} + +//static BOOL FillSoundChannel(SoundManager *sm, char* Dir, char *Name, unsigned int* Handle ) +static BOOL FillSoundChannel(SoundManager *sm, geVFile *File, unsigned int* Handle ) +{ + DSBUFFERDESC dsBD; + INT NumBytes; + uint8 *data = NULL; + BYTE * pbWaveData; +// char* Name2; + Channel* channel; + + *Handle = 0; + if (!sm) + return TRUE; + +#if 0 + //Open the file + if (Dir) + { + Name2 = malloc( strlen( Name ) + strlen( Dir ) + 3); // 2 for the "//" and 1 for terminator + if( !Name2 ) + return( 0 ); + sprintf(Name2, "%s\\%s", Dir, Name); + } + else + { + Name2 = malloc( strlen( Name ) + 3); // 2 for the "//" and 1 for terminator + if( !Name2 ) + return( 0 ); + + sprintf(Name2, "%s", Name); + } +#endif + if(!GetSoundData( File, &data )) + return( FALSE ); + + if( !ParseData( data, &dsBD, &pbWaveData ) ) + { + geRam_Free(data); + return( FALSE ); + } + + NumBytes = dsBD.dwBufferBytes; + + //Create the channel +// if( !CreateChannel( Name2, &dsBD, &channel ) ) + if (!CreateChannel(&dsBD, &channel)) + { + geRam_Free(data); + return FALSE; + } + channel->next = sm->smChannels; + channel->ID = sm->smNextChannelID++; + channel->Data = data; + + sm->smChannels = channel; + sm->smChannelCount++; + + //Fill the channel + if (!DSFillSoundBuffer(channel->buffer, pbWaveData, NumBytes)) + return FALSE; + +// free( data ); +// geRam_Free(data); + + *Handle = channel->ID; + return TRUE; +} + +#if 0 +static BOOL FillSoundChannelMemory(SoundManager *sm, const void *Buffer, unsigned int* Handle ) +{ + DSBUFFERDESC dsBD; + INT NumBytes; + BYTE * pbWaveData; + char * Name; + Channel * channel; + + *Handle = 0; + if (!sm) + return TRUE; + + if (!ParseData(Buffer, &dsBD, &pbWaveData)) + return FALSE; + + NumBytes = dsBD.dwBufferBytes; + + Name = malloc(11); + if (Name == NULL) + return FALSE; + sprintf(Name, "0x%8x", Buffer); + + //Create the channel +// if (!CreateChannel(Name, &dsBD, &channel)) + if (!CreateChannel(&dsBD, &channel)) + return FALSE; + + channel->next = sm->smChannels; + channel->ID = sm->smNextChannelID++; + + sm->smChannels = channel; + sm->smChannelCount++; + + //Fill the channel + if (!DSFillSoundBuffer(channel->buffer, pbWaveData, NumBytes)) + return FALSE; + + *Handle = channel->ID; + return TRUE; +} +#endif + +static void StopDupBuffers( Channel* channel ) +{ + Channel* dupChannel, *prevChannel; + + assert( channel ); + + dupChannel = channel->nextDup; + prevChannel = channel; + while( dupChannel ) + { + IDirectSoundBuffer_Stop(dupChannel->buffer); + dupChannel = dupChannel->nextDup; + } +} + +static void ClearDupBuffers( Channel* channel ) +{ + Channel* dupChannel, *prevChannel; + + if( channel == NULL) + return; + + dupChannel = channel->nextDup; + prevChannel = channel; + while( dupChannel ) + { + if( !ChannelPlaying( dupChannel ) ) + { + prevChannel->nextDup = dupChannel->nextDup; + IDirectSound_Release(dupChannel->buffer); +// free( dupChannel ); + geRam_Free(dupChannel); + dupChannel = prevChannel->nextDup; + } + else + { + prevChannel = dupChannel; + dupChannel = dupChannel->nextDup; + } + } +} + +static BOOL FreeAllChannels(SoundManager *sm) +{ + int Error; + + Channel* channel, *nextChannel; + + channel = sm->smChannels; + while( channel ) + { + nextChannel = channel->next; + StopDupBuffers( channel ); + ClearDupBuffers( channel ); + Error = IDirectSoundBuffer_Stop(channel->buffer); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + Error = IDirectSound_Release(channel->buffer); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + +// if( channel->name ) +// geRam_Free(channel->name); +// free( channel->name ); + if (channel->Data) + geRam_Free(channel->Data); + geRam_Free(channel); +// free( channel ); + channel = nextChannel; + } + sm->smChannels = NULL; + sm->smChannelCount = 0; + + return TRUE; +} + + +static BOOL FreeChannel(SoundManager *sm, Channel* channel) +{ + int Error; + Channel*prevChannel = NULL, *curChannel; + if ( channel ) + { + StopDupBuffers( channel ); + ClearDupBuffers( channel ); + Error = IDirectSoundBuffer_Stop(channel->buffer); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + Error = IDirectSound_Release(channel->buffer); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } +// if( channel->name ) +// geRam_Free(channel->name); +// free( channel->name ); + + if( channel->Data ) + geRam_Free(channel->Data); + + curChannel = sm->smChannels; + while( curChannel && curChannel != channel ) + { + prevChannel = curChannel; + curChannel = curChannel->next; + } + if( curChannel ) + { + if( prevChannel ) + prevChannel->next = curChannel->next; + else + sm->smChannels = curChannel->next; + geRam_Free(curChannel); +// free( curChannel ); + } + } + + return TRUE; +} + +static Channel* ReloadData(void *Data) +{ + DSBUFFERDESC dsBD; + BYTE * pbWaveData; + INT NumBytes; +// uint8 *data = NULL; + Channel* channel; + +// if( !Name ) +// return( NULL ); +// if( !GetSoundData( Data, &data ) ) +// return( NULL ); + + if( !ParseData( Data, &dsBD, &pbWaveData ) ) + return( NULL ); + + NumBytes = dsBD.dwBufferBytes; + + //Create the channel +// if( !CreateChannel( Name, &dsBD, &channel ) ) + if( !CreateChannel(&dsBD, &channel ) ) + return NULL; + + //Fill the channel + if ( !DSFillSoundBuffer(channel->buffer, pbWaveData, NumBytes)) + return NULL; + +// geRam_Free(data); +// free( data ); + return( channel ); +} + +static BOOL DupChannel( SoundManager *sm, Channel* channel, Channel** dupChannelPtr ) +{ + Channel* dupChannel; + HRESULT Error; + + *dupChannelPtr = NULL; +// dupChannel = malloc( sizeof(Channel ) ); + dupChannel = geRam_Allocate( sizeof(Channel ) ); + if( dupChannel == NULL ) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL ); + return FALSE; + } + Error = IDirectSound_DuplicateSoundBuffer( lpDirectSound, channel->buffer, &dupChannel->buffer ); + if( Error != DS_OK ) + { + geRam_Free(dupChannel); +// free( dupChannel ); + dupChannel = ReloadData( channel->Data ); + if( dupChannel == NULL ) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + } + dupChannel->ID = sm->smNextChannelID++; + dupChannel->next = NULL; + dupChannel->nextDup = channel->nextDup; + dupChannel->cfg = channel->cfg; +// dupChannel->name = NULL; + dupChannel->Data = channel->Data; + channel->nextDup = dupChannel; + *dupChannelPtr = dupChannel; + return( TRUE ); +} + +static BOOL StartSoundChannel( SoundManager *sm, unsigned int Handle, geSound_Cfg *cfg, int loop, unsigned int* sfx) +{ + HRESULT hres; + Channel* channel, *dupChannel; + + if( Handle == 0 ) + return( FALSE ); + channel = GetChannel( sm, Handle ); + //Clear all non-playing duplicate buffers. + ClearDupBuffers(channel); + //If the main buffer is playing and all non-playing dups have been cleared + //we need a new duplicate. + if( ChannelPlaying( channel ) ) + { + if(!DupChannel( sm,channel, &dupChannel ) ) + return( FALSE ); + channel = dupChannel; + } + if( !ModifyChannel( channel, cfg ) ) + return( FALSE ); + IDirectSoundBuffer_SetCurrentPosition(channel->buffer, 0); + hres = IDirectSoundBuffer_Play( channel->buffer, + 0, + 0, + loop ? DSBPLAY_LOOPING : 0); + + if (hres == DS_OK) + { + if( sfx ) + *sfx = channel->ID; + return TRUE; + } + + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; +} + +static BOOL StopSoundChannel(Channel* channel) +{ + HRESULT hres; + + assert(channel); + + hres = IDirectSoundBuffer_Stop(channel->buffer); + + if (hres == DS_OK) + return TRUE; + + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; +} + +static void DestroySoundManager(SoundManager *sm) +{ + if (!sm) return; + + FreeAllChannels( sm ); + if (sm->smPrimaryChannel != NULL) + sm->smPrimaryChannel->lpVtbl->Release(sm->smPrimaryChannel); + if (lpDirectSound != NULL) + IDirectSound_Release(lpDirectSound); + if (hmodDirectSound != NULL) + FreeLibrary (hmodDirectSound); + geRam_Free(sm); +// free(sm); +} + +static BOOL ModifyChannel( Channel *channel, geSound_Cfg *cfg ) +{ + int Error, Vol, Pan, Freq; + assert(channel); + + if( !cfg ) + return( TRUE ); + ClearDupBuffers(channel); + if( cfg->Volume != channel->cfg.Volume ) + { + Vol = (DWORD)((1.0 - cfg->Volume ) * DSBVOLUME_MIN); + Error = IDirectSoundBuffer_SetVolume(channel->buffer, Vol); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + channel->cfg.Volume = cfg->Volume; + } + + if( cfg->Pan != channel->cfg.Pan ) + { + Pan = (int)(cfg->Pan * DSBPAN_RIGHT); + Error = IDirectSoundBuffer_SetPan(channel->buffer, Pan); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + channel->cfg.Pan = cfg->Pan; + } + + + if( cfg->Frequency != channel->cfg.Frequency ) + { + + Freq = (DWORD)(channel->BaseFreq * cfg->Frequency); + + if(Freq < 0) + Freq = 0; + + Error = IDirectSoundBuffer_SetFrequency(channel->buffer, Freq); + if (Error != DS_OK) + { + geErrorLog_Add(GE_ERR_DS_ERROR, NULL); + return FALSE; + } + channel->cfg.Frequency = cfg->Frequency; + } + + return TRUE; +} + +static int ChannelPlaying( Channel *channel ) +{ + DWORD status, Error; + + if(!channel) + return( 0 ); + + Error = IDirectSoundBuffer_GetStatus( channel->buffer, &status); + if( Error != DS_OK) + return 0; + return( status & DSBSTATUS_PLAYING ); +} + +static Channel* GetChannel( SoundManager *sm, unsigned int ID ) +{ + Channel* dupChannel; + Channel* channel = sm->smChannels; + + while( channel ) + { + if( channel->ID == ID ) + break; + dupChannel = channel->nextDup; + while( dupChannel ) + { + if( dupChannel->ID == ID ) + break; + dupChannel = dupChannel->nextDup; + } + if( dupChannel ) + return( dupChannel ); + channel = channel->next; + } + return( channel ); +} diff --git a/G3D/Sound.h b/G3D/Sound.h new file mode 100644 index 0000000..e415191 --- /dev/null +++ b/G3D/Sound.h @@ -0,0 +1,76 @@ +/****************************************************************************************/ +/* Sound.h */ +/* */ +/* Author: Brian Adelberg */ +/* Description: DirectSound wrapper */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_SOUND_H +#define GE_SOUND_H + +#ifdef __cplusplus +extern "C" { +#endif + + +// GENESIS_PUBLIC_APIS + +typedef struct geSound_System geSound_System; +typedef struct geSound_Def geSound_Def; +typedef struct geSound geSound; + + +#ifdef _INC_WINDOWS + // Windows.h must be previously included for this api to be exposed. +GENESISAPI geSound_System *geSound_CreateSoundSystem(HWND hWnd); +#endif + +GENESISAPI void geSound_DestroySoundSystem(geSound_System *Sound); + + +GENESISAPI geSound_Def *geSound_LoadSoundDef(geSound_System *SoundS, geVFile *File); +GENESISAPI void geSound_FreeSoundDef(geSound_System *SoundS, + geSound_Def *SoundDef); + +GENESISAPI void geSound_FreeAllChannels(geSound_System *SoundS); + +GENESISAPI geSound *geSound_PlaySoundDef(geSound_System *SoundS, + geSound_Def *SoundDef, + geFloat Volume, + geFloat Pan, + geFloat Frequency, + geBoolean Loop); +GENESISAPI geBoolean geSound_StopSound(geSound_System *SoundS, geSound *Sound); +GENESISAPI geBoolean geSound_ModifySound(geSound_System *SoundS, + geSound *Sound, + geFloat Volume, + geFloat Pan, + geFloat Frequency); +GENESISAPI geBoolean geSound_SoundIsPlaying(geSound_System *SoundS, geSound *Sound); +GENESISAPI geBoolean geSound_SetMasterVolume( geSound_System *SoundS, geFloat Volume ); +// Added 11/08/1999 Ed Averill API call to return DSOUND object +GENESISAPI void *geSound_GetDSound(void); +// End 11/08/1999 modification + +// GENESIS_PRIVATE_APIS + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Sound3d.c b/G3D/Sound3d.c new file mode 100644 index 0000000..61e16e7 --- /dev/null +++ b/G3D/Sound3d.c @@ -0,0 +1,214 @@ +/****************************************************************************************/ +/* Sound3D.c */ +/* */ +/* Author: Brian Adelberg */ +/* Description: 3D Sound code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "Trace.h" +#include "Vec3d.h" +#include "XForm3d.h" +#include "Camera.h" +#include "Sound3d.h" + +// Sound +typedef struct geSound3d_Cfg +{ + geFloat Volume; + geFloat Pan; + geFloat Frequency; +} geSound3d_Cfg; + + +//===================================================================================== +// Snd3D_RoolOut +// Snd will drop off so that it is half intensity when twice min distance +// A 10 db reduction means half the intensity. +// In our volume routine 0.01 represents a decible +//===================================================================================== +static void geSound3D_RollOut(geSound3d_Cfg *Cfg, geFloat Dist, geFloat Min, geFloat Max) +{ + geFloat Volume; + assert( Cfg != NULL ); + + if( Dist > Max ) + { + Volume = 0.0f; + } + else if( Dist < Min ) + { + Volume = 1.0f; + } + else + Volume = 1.0f - (Dist/Min - 1)*0.1f; + Cfg->Volume = Volume; +} + +//===================================================================================== +// Snd3D_Pan +//===================================================================================== +static void geSound3D_Pan(geSound3d_Cfg *Cfg, geFloat FaceOffset ) +{ + assert(Cfg != NULL); + Cfg->Pan = (geFloat)sin((double)FaceOffset )*0.1f; +} + +//===================================================================================== +// Mps is the reletive velocity in meters per second +//===================================================================================== +static void geSound3D_Doppler(geSound3d_Cfg *Cfg, geFloat Mps ) +{ + //331 mps is the velocity of sound through air in standard conditions. + assert(Cfg != NULL); + Cfg->Frequency = 1.0f + (Mps/ 331.0f ); +} + +//===================================================================================== +// Snd3D_3DSound +// This is the position of the sound translated to your view +// coordinate system +//===================================================================================== +GENESISAPI void geSound3D_GetConfig( + const geWorld *World, + const geXForm3d *MXForm, + const geVec3d *SndPos, + geFloat Min, + geFloat Ds, + geFloat *Volume, + geFloat *Pan, + geFloat *Frequency) +{ + geVec3d ViewPos, LocalPos, Dist; + geSound3d_Cfg Cfg; + geFloat Magnitude; + geVec3d Origin = {0.0f, 0.0f, 0.0f}; + geXForm3d CXForm; + int32 Leaf1, Leaf2; + + assert( World != NULL ); + assert( MXForm != NULL ); + assert( SndPos != NULL ); + assert( Volume != NULL ); + assert( Pan != NULL ); + assert( Frequency != NULL ); + + + LocalPos = MXForm->Translation; + // Transform the sound to view space + geCamera_ConvertWorldSpaceToCameraSpace(MXForm, &CXForm); + geXForm3d_Transform( &CXForm, SndPos, &ViewPos); + // FIXME: Need to check these and return TRUE or FALSE + if( !geWorld_GetLeaf((geWorld*)World, &LocalPos, &Leaf1) ) + return; + if( !geWorld_GetLeaf((geWorld*)World, SndPos, &Leaf2) ) + return; + + if (!geWorld_LeafMightSeeLeaf((geWorld*)World, Leaf1, Leaf2, 0)) + { + Magnitude = 0.0f; + Dist.X = 0.0f; // Shut up compiler warning + Cfg.Volume = 0.0f; + } + else + { + GE_Collision Col; + + // Find the distance from the camera to the original light pos + geVec3d_Subtract(&LocalPos, SndPos, &Dist); + + Magnitude = geVec3d_Length(&Dist); + + if (Trace_GEWorldCollision((geWorld*)World, NULL, NULL, &LocalPos, SndPos, GE_CONTENTS_SOLID_CLIP, GE_COLLIDE_MODELS, 0, NULL, NULL, &Col)) + Magnitude *= 1.5f; + + geSound3D_RollOut(&Cfg, Magnitude, Min, Min*10); + } + + geSound3D_Pan(&Cfg, (geFloat)atan2( (double)ViewPos.X, (double)ViewPos.Z ) ); + //Cfg->Frequency = 1.0f; + geSound3D_Doppler(&Cfg, Ds); + + *Volume = Cfg.Volume; + *Pan = Cfg.Pan; + *Frequency = Cfg.Frequency; +} + + +//===================================================================================== +// geSound3D_GetConfigIgnoreObstructions() +//===================================================================================== +GENESISAPI void geSound3D_GetConfigIgnoreObstructions( + const geWorld *World, + const geXForm3d *MXForm, + const geVec3d *SndPos, + geFloat Min, + geFloat Ds, + geFloat *Volume, + geFloat *Pan, + geFloat *Frequency) +{ + geVec3d ViewPos, LocalPos, Dist; + geSound3d_Cfg Cfg; + geFloat Magnitude; + geVec3d Origin = {0.0f, 0.0f, 0.0f}; + geXForm3d CXForm; + int32 Leaf1, Leaf2; + + assert( World != NULL ); + assert( MXForm != NULL ); + assert( SndPos != NULL ); + assert( Volume != NULL ); + assert( Pan != NULL ); + assert( Frequency != NULL ); + + + LocalPos = MXForm->Translation; + // Transform the sound to view space + geCamera_ConvertWorldSpaceToCameraSpace(MXForm, &CXForm); + geXForm3d_Transform( &CXForm, SndPos, &ViewPos); + // FIXME: Need to check these and return TRUE or FALSE + if( !geWorld_GetLeaf((geWorld*)World, &LocalPos, &Leaf1) ) + return; + if( !geWorld_GetLeaf((geWorld*)World, SndPos, &Leaf2) ) + return; + + if (!geWorld_LeafMightSeeLeaf((geWorld*)World, Leaf1, Leaf2, 0)) + { + Magnitude = 0.0f; + Dist.X = 0.0f; // Shut up compiler warning + Cfg.Volume = 0.0f; + } + else + { + // Find the distance from the camera to the original light pos + geVec3d_Subtract(&LocalPos, SndPos, &Dist); + + Magnitude = geVec3d_Length(&Dist); + + geSound3D_RollOut(&Cfg, Magnitude, Min, Min*10); + } + + geSound3D_Pan(&Cfg, (geFloat)atan2( (double)ViewPos.X, (double)ViewPos.Z ) ); + //Cfg->Frequency = 1.0f; + geSound3D_Doppler(&Cfg, Ds); + + *Volume = Cfg.Volume; + *Pan = Cfg.Pan; + *Frequency = Cfg.Frequency; +} diff --git a/G3D/Sound3d.h b/G3D/Sound3d.h new file mode 100644 index 0000000..69c311c --- /dev/null +++ b/G3D/Sound3d.h @@ -0,0 +1,60 @@ +/****************************************************************************************/ +/* Sound3D.h */ +/* */ +/* Author: Brian Adelberg */ +/* Description: 3D Sound code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_SOUND3D_H +#define GE_SOUND3D_H + +#include "BaseType.h" +#include "Sound.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// GENESIS_PUBLIC_APIS + +GENESISAPI void geSound3D_GetConfig( + const geWorld *World, + const geXForm3d *CameraTransform, + const geVec3d *SoundPos, + geFloat Min, + geFloat Ds, + geFloat *Volume, + geFloat *Pan, + geFloat *Frequency); + +GENESISAPI void geSound3D_GetConfigIgnoreObstructions( + const geWorld *World, + const geXForm3d *MXForm, + const geVec3d *SndPos, + geFloat Min, + geFloat Ds, + geFloat *Volume, + geFloat *Pan, + geFloat *Frequency); + +// GENESIS_PRIVATE_APIS + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Support/ERRORLOG.C b/G3D/Support/ERRORLOG.C new file mode 100644 index 0000000..042b887 --- /dev/null +++ b/G3D/Support/ERRORLOG.C @@ -0,0 +1,189 @@ +/****************************************************************************************/ +/* ERRORLOG.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Generic error logging system implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include // assert() +#include +#include // memmove(), strncpy() strncat() + +#include "ErrorLog.h" + +#define MAX_ERRORS 30 // ... + +#define MAX_USER_NAME_LEN 128 // Needed just 10 more chars! (was 100) JP +#define MAX_CONTEXT_LEN 128 // How big should this be? Must be big enough to allow full paths to files, etc... + +typedef struct +{ + geErrorLog_ErrorIDEnumType ErrorID; + char String[MAX_USER_NAME_LEN+1]; + char Context[MAX_CONTEXT_LEN+1]; +} geErrorType; + +typedef struct +{ + int ErrorCount; + int MaxErrors; + geErrorType ErrorList[MAX_ERRORS]; +} geErrorLogType; + +geErrorLogType geErrorLog_Locals = {0,MAX_ERRORS}; + +GENESISAPI void geErrorLog_Clear(void) + // clears error history +{ + geErrorLog_Locals.ErrorCount = 0; +} + +GENESISAPI int geErrorLog_Count(void) + // reports size of current error log +{ + return geErrorLog_Locals.ErrorCount; +} + + +GENESISAPI void geErrorLog_AddExplicit(geErrorLog_ErrorClassType Error, + const char *ErrorIDString, + const char *ErrorFileString, + int LineNumber, + const char *UserString, + const char *Context) +{ + char *SDst; + char *CDst; + + assert( geErrorLog_Locals.ErrorCount >= 0 ); + + if (geErrorLog_Locals.ErrorCount>=MAX_ERRORS) + { // scoot list down by one (lose oldest error) + memmove( + (char *)(&( geErrorLog_Locals.ErrorList[0] )), + (char *)(&( geErrorLog_Locals.ErrorList[1] )), + sizeof(geErrorType) * (geErrorLog_Locals.MaxErrors-1) ); + geErrorLog_Locals.ErrorCount = geErrorLog_Locals.MaxErrors-1; + } + + assert( geErrorLog_Locals.ErrorCount < geErrorLog_Locals.MaxErrors ); + + SDst = geErrorLog_Locals.ErrorList[geErrorLog_Locals.ErrorCount].String; + + // Copy new error info + if (ErrorIDString != NULL) + { + strncpy(SDst,ErrorIDString,MAX_USER_NAME_LEN); + } + + strncat(SDst," ",MAX_USER_NAME_LEN); + + if (ErrorFileString!=NULL) + { + const char* pModule = strrchr(ErrorFileString, '\\'); + if(!pModule) + pModule = ErrorFileString; + else + pModule++; // skip that backslash + strncat(SDst,pModule,MAX_USER_NAME_LEN); + strncat(SDst," ",MAX_USER_NAME_LEN); + } + + { + char Number[20]; + itoa(LineNumber,Number,10); + strncat(SDst,Number,MAX_USER_NAME_LEN); + } + + if (UserString != NULL) + { + if (UserString[0]!=0) + { + strncat(SDst," ",MAX_USER_NAME_LEN); + strncat(SDst,UserString,MAX_USER_NAME_LEN); + } + } + + CDst = geErrorLog_Locals.ErrorList[geErrorLog_Locals.ErrorCount].Context; + + // Clear the context string in the errorlog to prepare for a new one + memset(CDst, 0, sizeof(char)*MAX_CONTEXT_LEN); + + if (Context != NULL) + { + if (Context[0]!=0) + { + //strncat(SDst," ",MAX_USER_NAME_LEN); + strncat(SDst,Context,MAX_USER_NAME_LEN); + } + } + + geErrorLog_Locals.ErrorCount++; + +#ifndef NDEBUG +#pragma message ("Clean up the OutputDebugStrings in geErrorLog_AddExplicit") +{ + char buff[100]; + sprintf(buff, "ErrorLog: %d -", Error); + OutputDebugString(buff); + OutputDebugString(SDst); + OutputDebugString("\r\n"); +} +#endif +} + + + +GENESISAPI geBoolean geErrorLog_AppendStringToLastError(const char *String) +{ + char *SDst; + if (String == NULL) + { + return GE_FALSE; + } + + if (geErrorLog_Locals.ErrorCount>0) + { + SDst = geErrorLog_Locals.ErrorList[geErrorLog_Locals.ErrorCount-1].String; + + strncat(SDst,String,MAX_USER_NAME_LEN); + return GE_TRUE; + } + else + { + return GE_FALSE; + } +} + +GENESISAPI geBoolean geErrorLog_Report(int history, geErrorLog_ErrorClassType *error, const char **UserString) +{ + assert( error != NULL ); + + if ( (history > geErrorLog_Locals.ErrorCount) || (history < 0)) + { + return GE_FALSE; + } + + + *error = geErrorLog_Locals.ErrorList[history].ErrorID; + *UserString = geErrorLog_Locals.ErrorList[history].String; + return GE_TRUE; +} + diff --git a/G3D/Support/Errorlog.h b/G3D/Support/Errorlog.h new file mode 100644 index 0000000..1bdcff1 --- /dev/null +++ b/G3D/Support/Errorlog.h @@ -0,0 +1,238 @@ +/****************************************************************************************/ +/* ERRORLOG.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Generic error logging system interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_ERRORLOG_H +#define GE_ERRORLOG_H + +#include "basetype.h" + +#ifndef NDEBUG + #define ERRORLOG_FULL_REPORTING +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + GE_ERR_INVALID_DRIVER_HANDLE, // Driver not supported + GE_ERR_INVALID_MODE_HANDLE, // Mode not supported + GE_ERR_DRIVER_INIT_FAILED, // Could not init Driver + GE_ERR_DRIVER_ALLREADY_INITIALIZED, // Driver init failure + GE_ERR_DRIVER_NOT_FOUND, // File open error for driver + GE_ERR_DRIVER_NOT_INITIALIZED, // Driver shutdown failure + GE_ERR_INVALID_DRIVER, // Wrong driver version, or bad driver + GE_ERR_DRIVER_BEGIN_SCENE_FAILED, + GE_ERR_DRIVER_END_SCENE_FAILED, + GE_ERR_CREATE_SOUND_MANAGER_FAILED, + GE_ERR_CREATE_SOUND_BUFFER_FAILED, + GE_ERR_DS_ERROR, + GE_ERR_INVALID_WAV, + GE_ERR_NO_PERF_FREQ, + GE_ERR_FILE_OPEN_ERROR, + GE_ERR_FILE_READ_ERROR, + GE_ERR_FILE_WRITE_ERROR, + GE_ERR_PALETTE_LOAD_FAILURE, + GE_ERR_GBSP_LOAD_FAILURE, + GE_ERR_INVALID_PARMS, + GE_ERR_INVALID_CAMERA, + GE_ERR_RENDER_WORLD_FAILED, + GE_ERR_BEGIN_WORLD_FAILED, + GE_ERR_END_WORLD_FAILED, + GE_ERR_BEGIN_MODELS_FAILED, + GE_ERR_END_MODELS_FAILED, + GE_ERR_BEGIN_MESHES_FAILED, + GE_ERR_END_MESHES_FAILED, + GE_ERR_RENDER_MESH_FAILED, + GE_ERR_BAD_LMAP_EXTENTS, + GE_ERR_INVALID_TEXTURE, + GE_ERR_REGISTER_WORLD_TEXTURE_FAILED, + GE_ERR_REGISTER_LIGHTMAPS_FAILED, + GE_ERR_REGISTER_WORLD_PALETTE_FAILED, + GE_ERR_REGISTER_MISC_TEXTURE_FAILED, + GE_ERR_INVALID_MESH_FILE, + GE_ERR_LOAD_BITMAP_FAILED, + GE_ERR_MAX_MESH_DEFS, + GE_ERR_MESH_MAX_NODES, + GE_ERR_INVALID_MESH_MATERIAL, + GE_ERR_MAX_MESH_MATERIALS, + GE_ERR_MAX_MESH_CLIP_PLANES, + GE_ERR_RENDERQ_OVERFLOW, + GE_ERR_INVALID_LTYPE, + GE_ERR_MAX_ENTITIES, + GE_ERR_GET_ENTITY_DATA_ERROR, + GE_ERR_INVALID_ENTITY_FIELD_TYPE, + GE_ERR_MODEL_NOT_FOUND, + GE_ERR_MODEL_NOT_IN_ENTITY, + GE_ERR_MAX_TEXTURES, + GE_ERR_MAX_DECALS, + GE_ERR_MAX_VERTS, + GE_ERR_OUT_OF_MEMORY, + GE_ERR_INVALID_BSP_TAG, + GE_ERR_INVALID_BSP_VERSION, + GE_ERR_ERROR_READING_BSP_CHUNK, + ERR_PATH_CREATE_ENOMEM, // failure to create a path (memory allocation failed) + ERR_PATH_INSERT_R_KEYFRAME, // failure to insert a rotation keyframe + ERR_PATH_INSERT_T_KEYFRAME, // failure to insert a translation keyframe + ERR_PATH_DELETE_R_KEYFRAME, // failure to delete a rotation keyframe + ERR_PATH_DELETE_T_KEYFRAME, // failure to delete a translation keyframe + ERR_PATH_FILE_READ, // failure to read from file + ERR_PATH_FILE_VERSION, // tried to create path from file with wrong/bad version + ERR_PATH_FILE_PARSE, // failure to parse file (unexpected format problem) + ERR_PATH_FILE_WRITE, // failure to read from file + ERR_MOTION_CREATE_ENOMEM, // failure to create (memory allocation failed) + ERR_MOTION_ADDPATH_ENOMEM, // failure to add path into motion (memory allocation failed) + ERR_MOTION_ADDPATH_PATH, // failure to add path into motion (path creation failed) + ERR_MOTION_ADDPATH_BAD_NAME, // failure to add path into motion due to name conflict + ERR_MOTION_INSERT_EVENT, // failure to insert event (memory allocation failed or duplicate key) + ERR_MOTION_DELETE_EVENT, // failure to insert event + ERR_MOTION_FILE_READ, // failure to read from file + ERR_MOTION_FILE_WRITE, // failure to write to file + ERR_MOTION_FILE_PARSE, // failure to parse file (unexpected format problem) + ERR_TKARRAY_INSERT_IDENTICAL, // failure to insert into list because of existing identical key + ERR_TKARRAY_INSERT_ENOMEM, // failure to insert into list because of memory allocation failure + ERR_TKARRAY_DELETE_NOT_FOUND, // failure to delete from list because key was not found + ERR_TKARRAY_CREATE, // failure to create TKArray object (out of memroy) + ERR_TKARRAY_TOO_BIG, // TKArray object can't be added to - it's list is as big as it can get + ERR_VKARRAY_INSERT, // insertion to VKArray failed + ERR_QKARRAY_INSERT, // insertion to QKArray failed + ERR_POSE_CREATE_ENOMEM, // Motion object failed to create (memory allocation failed) + ERR_POSE_ADDJOINT_ENOMEM, // Motion_AddJoint failed to allocate/reallocate memory for new joint + ERR_TKEVENTS_CREATE_ENOMEM, // failure to create TKEvents object (memory allocation failed) + ERR_TKEVENTS_DELETE_NOT_FOUND, // failure to delete from list because key was not found + ERR_TKEVENTS_INSERT_ENOMEM, // failure to insert into list because of memory allocation failure + ERR_TKEVENTS_INSERT, // failure to insert into list + ERR_TKEVENTS_FILE_READ, // failure to read from data file + ERR_TKEVENTS_FILE_WRITE, // failure to write to data file + ERR_TKEVENTS_FILE_VERSION, // failure to read tkevents object: file has wrong version + ERR_TKEVENTS_FILE_PARSE, // failure to parse file (unexpected format problem) + ERR_STRBLOCK_ENOMEM, // failure to create, insert, or append (memory allocation failed) + ERR_STRBLOCK_STRLEN, // string too long to insert or append + ERR_STRBLOCK_FILE_READ, // failure to read from data file + ERR_STRBLOCK_FILE_WRITE, // failure to write to data file + ERR_STRBLOCK_FILE_PARSE, // failure to parse reading from input file (unexpected format problem) + ERR_BODY_ENOMEM, // failure to create, or add (memory allocation failed) + ERR_BODY_FILE_PARSE, // failure to parse reading from input file (unexpected format problem) + ERR_BODY_FILE_READ, // failure to read from data file + ERR_BODY_FILE_WRITE, // failure to write to data file + ERR_BODY_BONEXFARRAY, // XFArray object failed to return array, or array size doesn't match bone count + ERR_XFARRAY_ENOMEM, // failure to create. (memory allocation failure) + ERR_PUPPET_ENOMEM, // failure to create. (memory allocation failure) + ERR_PUPPET_RENDER, // failure to render. + ERR_PUPPET_NO_MATERIALS, // failure to create: associated body has no materials. + ERR_PUPPET_LOAD_TEXTURE, // failure to load texture + ERR_TEXPOOL_ENOMEM, // failure to create or add to. (memory allocation/reallocation failure) + ERR_TEXPOOL_TOO_BIG, // failure to add to pool, pool is too large. + ERR_TEXPOOL_LOAD_TEXTURE, // failure to load texture into pool + ERR_TEXPOOL_TEXTURE_NOT_FREE, // texture pool destroyed without first freeing all it's shared textures + ERR_ACTOR_ENOMEM, // failure to create. (memory allocation failure) + ERR_ACTOR_RENDER_PREP, // failure to prepare actor for rendering (bad Body or allocation failure) + ERR_ACTOR_RENDER_FAILED, // failure to render. failure to get geometry from Body + ERR_ACTOR_TOO_MANY_MOTIONS, // failure to add motion. too many. + ERR_ACTOR_FILE_READ, // failure to read from data file. + ERR_ACTOR_FILE_PARSE, // failure to parse reading from input file(unexpected format problem) + ERR_ACTOR_FILE_WRITE, // failure to write to data file. + GE_ERR_INVALID_MODEL_MOTION_FILE, // Bad model motion file (for bsp files) + GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, // Chunk size does not match structure size of kind +//MRB BEGIN +//geSprite + ERR_SPRITE_ENOMEM, // failure to create. (memory allocation failure) + ERR_SPRITE_INVALIDBITMAP, // failure to use bitmap because bitmap was invalid +//MRB END +} geErrorLog_ErrorIDEnumType; + + +typedef enum +{ + GE_ERR_MEMORY_RESOURCE, + GE_ERR_DISPLAY_RESOURCE, + GE_ERR_SOUND_RESOURCE, + GE_ERR_SYSTEM_RESOURCE, + GE_ERR_INTERNAL_RESOURCE, + + GE_ERR_FILEIO_OPEN, + GE_ERR_FILEIO_CLOSE, + GE_ERR_FILEIO_READ, + GE_ERR_FILEIO_WRITE, + GE_ERR_FILEIO_FORMAT, + GE_ERR_FILEIO_VERSION, + + GE_ERR_LIST_FULL, + GE_ERR_DATA_FORMAT, + GE_ERR_SEARCH_FAILURE, +} geErrorLog_ErrorClassType; + +GENESISAPI void geErrorLog_Clear(void); + // clears error history + +GENESISAPI int geErrorLog_Count(void); + // reports size of current error log + +GENESISAPI void geErrorLog_AddExplicit(geErrorLog_ErrorClassType, + const char *ErrorIDString, + const char *ErrorFileString, + int LineNumber, + const char *UserString, + const char *Context); + // not intended to be used directly: use ErrorLog_Add or ErrorLog_AddString + + +#ifdef ERRORLOG_FULL_REPORTING + // 'Debug' version includes a textual error id, and the user string + + #define geErrorLog_Add(Error, Context) geErrorLog_AddExplicit(Error, #Error, __FILE__, __LINE__,"", Context) + // logs an error. + + #define geErrorLog_AddString(Error,String, Context) geErrorLog_AddExplicit(Error, #Error, __FILE__,__LINE__, String, Context) + // logs an error with additional identifing string. + +GENESISAPI geBoolean geErrorLog_AppendStringToLastError(const char *String);// use geErrorLog_AppendString + + #define geErrorLog_AppendString(XXX) geErrorLog_AppendStringToLastError(XXX) + // adds text to the previous logged error + +#else + // 'Release' version does not include the textual error id, or the user string + + #define geErrorLog_Add(Error, Context) geErrorLog_AddExplicit(Error, "", __FILE__, __LINE__,"", Context) + // logs an error. + + #define geErrorLog_AddString(Error,String, Context) geErrorLog_AddExplicit(Error, "", __FILE__,__LINE__, "", Context) + // logs an error with additional identifing string. + + #define geErrorLog_AppendString(XXX) + // adds text to the previous logged error + +#endif + +GENESISAPI geBoolean geErrorLog_Report(int History, geErrorLog_ErrorClassType *Error, const char **UserString); + // reports from the error log. + // history is 0 for most recent, 1.. for second most recent etc. + // returns GE_TRUE if report succeeded. GE_FALSE if it failed. + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Support/RAM.H b/G3D/Support/RAM.H new file mode 100644 index 0000000..0fe751f --- /dev/null +++ b/G3D/Support/RAM.H @@ -0,0 +1,140 @@ +/****************************************************************************************/ +/* RAM.H */ +/* */ +/* Author: */ +/* Description: Replacement for malloc, realloc and free */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_RAM_H +#define GE_RAM_H + +#include "basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (* geRam_CriticalCallbackFunction)(void); + +/* + Set the critical callback function. ram_allocate will call the critical + callback function if it's unable to allocate memory. +*/ +GENESISAPI geRam_CriticalCallbackFunction geRam_SetCriticalCallback + ( + geRam_CriticalCallbackFunction callback + ); + +/* + increments or decrements a counter . if the counter is >0 + the critical callback function (if set) is called for a failed memory allocation. + add is added to the current counter value. the new counter value is returned. +*/ +GENESISAPI int geRam_EnableCriticalCallback(int add); + + +/* + Allocate memory of the given size. In debug mode, the memory is filled + with 0xA5, and we keep track of the amount of memory allocated. Also, in debug + mode, we track where the memory was allocated and can optionally provide a + report of allocated blocks. See geRam_ReportAllocations. +*/ +#ifndef NDEBUG + +#define geRam_Allocate(size) _geRam_DebugAllocate(size, __FILE__, __LINE__) + +// Do not call _geRam_DebugAllocate directly. +GENESISAPI void* _geRam_DebugAllocate(uint32 size, const char* pFile, int line); + +#else + +GENESISAPI void *geRam_Allocate(uint32 size); + +#endif + +/* + Free an allocated memory block. +*/ +GENESISAPI void geRam_Free_(void *ptr); + + extern void *StupidUnusedPointer; // never used, except to mask the + // possible warning you get if you use the geRam_Free macro below, without + // using the xxx pointer again in the same block. This is ugly. + +#define geRam_Free(xxx) geRam_Free_(xxx) ,(xxx)=NULL, StupidUnusedPointer=(xxx) + +/* + Reallocate memory. This function supports shrinking and expanding blocks, + and will also act like ram_allocate if the pointer passed to it is NULL. + It won't, however, free the memory if you pass it a 0 size. +*/ +#ifndef NDEBUG + +#define geRam_Realloc(ptr, newsize) _geRam_DebugRealloc(ptr, newsize, __FILE__, __LINE__) + +// Do not call _geRam_DebugRealloc directly. +GENESISAPI void* _geRam_DebugRealloc(void* ptr, uint32 size, const char* pFile, int line); + +#else + +GENESISAPI void *geRam_Realloc(void *ptr,uint32 newsize); + +#endif + +#ifndef NDEBUG + +GENESISAPI void geRam_ReportAllocations(void); + +#else + +#define geRam_ReportAllocations() + +#endif + +#ifndef NDEBUG + extern int32 geRam_CurrentlyUsed; + extern int32 geRam_NumberOfAllocations; + extern int32 geRam_MaximumUsed; + extern int32 geRam_MaximumNumberOfAllocations; + +GENESISAPI void geRam_AddAllocation(int n,uint32 size); +#else + #define geRam_AddAllocation(n,s) +#endif + +// allocate the ram & clear it. (calloc) +GENESISAPI void * geRam_AllocateClear(uint32 size); + +#define GE_RAM_ALLOCATE_STRUCT(type) (type *)geRam_Allocate (sizeof (type)) +#define GE_RAM_ALLOCATE_ARRAY(type,count) (type *)geRam_Allocate (sizeof (type) * (count)) + +#ifndef NDEBUG +#define GE_RAM_REALLOC_ARRAY(ptr,type,count) (type *)geRam_Realloc( (ptr), sizeof(type) * (count) );{type *XX=(ptr);} +#else +#define GE_RAM_REALLOC_ARRAY(ptr,type,count) (type *)geRam_Realloc( (ptr), sizeof(type) * (count) ) +#endif + +#ifndef NDEBUG +geBoolean geRam_IsValidPtr(void *ptr); +#endif + +#ifdef __cplusplus + } +#endif + +#endif + diff --git a/G3D/Support/Ram.c b/G3D/Support/Ram.c new file mode 100644 index 0000000..43e41c3 --- /dev/null +++ b/G3D/Support/Ram.c @@ -0,0 +1,550 @@ +/****************************************************************************************/ +/* RAM.C */ +/* */ +/* Author: */ +/* Description: Replacement for malloc, realloc and free */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#ifndef NDEBUG +#define _CRTDBG_MAP_ALLOC +#include +#endif + +#include "ram.h" + +/* + This controls the MINIMAL_CONFIG flag. Basically, all overflow, underflow, + and size checking code is always enabled except when NDEBUG is defined... +*/ +#ifdef NDEBUG + // debugging's turned off, so make it minimal config + #ifndef MINIMAL_CONFIG + #define MINIMAL_CONFIG + #endif +#else + // debugging on, so do full checking + #ifdef MINIMAL_CONFIG + #undef MINIMAL_CONFIG + #endif +#endif + +// stupid stuff... +#ifndef GENESISDLLVERSION +void *StupidUnusedPointer; +#endif + +// critical allocation stuff... +static int geRam_CriticalAllocationCount = 0; + +static geRam_CriticalCallbackFunction geRam_CriticalCallback = NULL; + +/* + increments or decrements a counter. if the counter is >0 + the critical callback function (if set) is called for a failed memory allocation. + add is added to the current counter value. the new counter value is returned. +*/ +GENESISAPI int geRam_EnableCriticalCallback(int add) +{ + geRam_CriticalAllocationCount += add; + return geRam_CriticalAllocationCount; +} + + +/* + Set the critical callback function. geRam_Allocate will call this function + if it's unable to allocate memory. Returns the previous critical callback fcn. +*/ +GENESISAPI geRam_CriticalCallbackFunction geRam_SetCriticalCallback + ( + geRam_CriticalCallbackFunction critical_callback + ) +{ + geRam_CriticalCallbackFunction OldCallback; + + OldCallback = geRam_CriticalCallback; + geRam_CriticalCallback = critical_callback; + return OldCallback; +} + +/* + If an allocation fails, this function will be called. If the critical callback + function is not NULL, then that function will be called. +*/ +static int geRam_DoCriticalCallback + ( + void + ) +{ + if ((geRam_CriticalAllocationCount != 0) && (geRam_CriticalCallback != NULL)) + { + return geRam_CriticalCallback (); + } + else + { + return 0; + } +} + + +GENESISAPI void * geRam_AllocateClear(uint32 size) +{ +void * mem; + size = (size + 3)&(~(uint32)3); + mem = geRam_Allocate(size); + if ( mem ) + { + memset(mem,0,size); + } +return mem; +} + +#ifdef MINIMAL_CONFIG + + /* + Minimal configuration acts almost exactly like standard malloc, free, + and realloc. The only difference is the critical allocation stuff. + */ + + + /* + Allocate memory of the given size. In debug mode, the memory is filled + with 0xA5, and we keep track of the amount of memory allocated. + */ + void *geRam_Allocate + ( + uint32 size + ) + { + void *p; + + do + { + p = malloc(size); + } while ((p == NULL) && (geRam_DoCriticalCallback ())); + + return p; + } + + // free an allocated block + void geRam_Free_ + ( + void *ptr + ) + { + free (ptr); + } + + // reallocate a block... + // This acts like the standard realloc +GENESISAPI void *geRam_Realloc + ( + void *ptr, + uint32 newsize + ) + { + char *p; + char * NewPtr; + + if (ptr == NULL) + { + return geRam_Allocate (newsize); + } + + // if newsize is NULL, then it's a free and return NULL + if (newsize == 0) + { + geRam_Free (ptr); + return NULL; + } + + p = ptr; + do + { + NewPtr = (char *)realloc (p, newsize); + } while ((NewPtr == NULL) && (geRam_DoCriticalCallback ())); + + return NewPtr; + } + +#else // MINIMAL_CONFIG + /* + For debugging implementations, we add a header and trailer to the + allocated memory blocks so that we compute memory usage, and catch + simple over- and under-run errors. + */ + + // yes, this will break if we use more than 2 gigabytes of RAM... + int32 geRam_CurrentlyUsed = 0; // total ram currently in use + int32 geRam_MaximumUsed = 0; // max total ram allocated at any time + int32 geRam_NumberOfAllocations = 0; // current number of blocks allocated + int32 geRam_MaximumNumberOfAllocations = 0; // max number of allocations at any time + + // header and trailer stuff... + static char MemStamp[] = {"!CHECKME!"}; + static const int MemStampSize = sizeof (MemStamp); + static const int SizeSize = sizeof (uint32); + // <> CB : pad sized to multiples of 8 !!! + #define HEADER_SIZE (((SizeSize + MemStampSize)+7)&(~(uint32)7)) + #define EXTRA_SIZE (((HEADER_SIZE + MemStampSize)+7)&(~(uint32)7)) + static const unsigned char AllocFillerByte = (unsigned char)0xA5; + static const unsigned char FreeFillerByte = (unsigned char)0xB6; + /* + A memory block is allocated that's size + (2*MemStampSize)+SizeSize bytes. + It's then filled with 0xA5. The size stamp is placed at the head of the block, + with the MemStamp being placed directly after the size at the front, and + also at the end of the block. The layout is: + + <> + */ + typedef enum + { + DONT_INITIALIZE = 0, + INITIALIZE_MEMORY = 1 + } geRam_MemoryInitialization; + + static void geRam_SetupBlock + ( + char * p, + uint32 size, + geRam_MemoryInitialization InitMem + ) + { + if (InitMem == INITIALIZE_MEMORY) + { + // fill the memory block + memset (p+HEADER_SIZE, AllocFillerByte, size); + } + + // add the size at the front + *((uint32 *)p) = size; + + // copy the memstamp to the front of the block + memcpy (p+SizeSize, MemStamp, MemStampSize); + + // and to the end of the block + memcpy (p+HEADER_SIZE+size, MemStamp, MemStampSize); + } + +#ifndef NDEBUG +GENESISAPI void* _geRam_DebugAllocate(uint32 size, const char* pFile, int line) + { + char *p; + + do + { + p = (char*)_malloc_dbg (size + EXTRA_SIZE, _NORMAL_BLOCK, pFile, line); + } while ((p == NULL) && geRam_DoCriticalCallback ()); + + if (p == NULL) + { + return NULL; + } + + // setup size stamps and memory overwrite checks + geRam_SetupBlock (p, size, INITIALIZE_MEMORY); + + // and update the allocations stuff + geRam_NumberOfAllocations++; + geRam_CurrentlyUsed += size; + + if (geRam_NumberOfAllocations > geRam_MaximumNumberOfAllocations) + { + geRam_MaximumNumberOfAllocations = geRam_NumberOfAllocations; + } + if (geRam_CurrentlyUsed > geRam_MaximumUsed) + { + geRam_MaximumUsed = geRam_CurrentlyUsed; + } + + return p+HEADER_SIZE; + } + +#else // NDEBUG + +GENESISAPI void * geRam_Allocate (uint32 size) + { + char *p; + + do + { + p = (char*)malloc (size + EXTRA_SIZE); + } while ((p == NULL) && geRam_DoCriticalCallback ()); + + if (p == NULL) + { + return NULL; + } + + // setup size stamps and memory overwrite checks + geRam_SetupBlock (p, size, INITIALIZE_MEMORY); + + // and update the allocations stuff + geRam_NumberOfAllocations++; + geRam_CurrentlyUsed += size; + + if (geRam_NumberOfAllocations > geRam_MaximumNumberOfAllocations) + { + geRam_MaximumNumberOfAllocations = geRam_NumberOfAllocations; + } + if (geRam_CurrentlyUsed > geRam_MaximumUsed) + { + geRam_MaximumUsed = geRam_CurrentlyUsed; + } + + return p+HEADER_SIZE; + } +#endif // NDEBUG + + static char * ram_verify_block + ( + void * ptr + ) + { + char * p = ptr; + uint32 size; + + if (p == NULL) + { + assert (0 && "freeing NULL"); + return NULL; + } + + // make p point to the beginning of the block + p -= HEADER_SIZE; + + // get size from block + size = *((uint32 *)p); + + // check stamp at front + if (memcmp (p+SizeSize, MemStamp, MemStampSize) != 0) + { + assert (0 && "ram_verify_block: Memory block corrupted at front"); + return NULL; + } + + // and at back + if (memcmp (p+HEADER_SIZE+size, MemStamp, MemStampSize) != 0) + { + assert (0 && "ram_verify_block: Memory block corrupted at tail"); + return NULL; + } + + return p; + } + +GENESISAPI void geRam_Free_ (void *ptr) + { + char *p; + uint32 size; + + // make sure it's a valid block... + p = ram_verify_block (ptr); + if (p == NULL) + { + return; + } + + // gotta get the size before you free it + size = *((uint32 *)p); + + // fill it with trash... + memset (p, FreeFillerByte, size+EXTRA_SIZE); + + // free the memory + free (p); + + // update allocations + geRam_NumberOfAllocations--; + assert ((geRam_NumberOfAllocations >= 0) && "free()d more ram than you allocated!"); + + geRam_CurrentlyUsed -= size; + assert ((geRam_CurrentlyUsed >= 0) && "free()d more ram than you allocated!"); + } + +#ifndef NDEBUG + +GENESISAPI void * _geRam_DebugRealloc (void *ptr, uint32 newsize, const char* pFile, int line) + { + char *p; + char * NewPtr; + uint32 size; + + // if realloc is called with NULL, just treat it like an alloc + if (ptr == NULL) + { + return _geRam_DebugAllocate(newsize, pFile, line); + } + + // verify the block + p = ram_verify_block (ptr); + if (p == NULL) + { + return NULL; + } + + // if newsize is NULL, then it's a free and return NULL + if (newsize == 0) + { + geRam_Free (ptr); + return NULL; + } + + // gotta get the size before I realloc it... + size = *((uint32 *)p); + + do + { + NewPtr = (char *)_realloc_dbg(p, newsize+EXTRA_SIZE, _NORMAL_BLOCK, pFile, line); + } while ((NewPtr == NULL) && geRam_DoCriticalCallback ()); + + // if allocation failed, return NULL... + if (NewPtr == NULL) + { + return NULL; + } + + geRam_SetupBlock (NewPtr, newsize, DONT_INITIALIZE); + + geRam_CurrentlyUsed += (newsize - size); + if (geRam_CurrentlyUsed > geRam_MaximumUsed) + { + geRam_MaximumUsed = geRam_CurrentlyUsed; + } + assert ((geRam_CurrentlyUsed >= 0) && "free()d more ram than you allocated!"); + + return NewPtr + HEADER_SIZE; + } + +#else // NDEBUG + +GENESISAPI void * geRam_Realloc (void *ptr, uint32 newsize) + { + char *p; + char * NewPtr; + uint32 size; + + // if realloc is called with NULL, just treat it like an alloc + if (ptr == NULL) + { + return geRam_Allocate (newsize); + } + + // verify the block + p = ram_verify_block (ptr); + if (p == NULL) + { + return NULL; + } + + // if newsize is NULL, then it's a free and return NULL + if (newsize == 0) + { + geRam_Free (ptr); + return NULL; + } + + // gotta get the size before I realloc it... + size = *((uint32 *)p); + + do + { + NewPtr = (char *)realloc (p, newsize+EXTRA_SIZE); + } while ((NewPtr == NULL) && geRam_DoCriticalCallback ()); + + // if allocation failed, return NULL... + if (NewPtr == NULL) + { + return NULL; + } + + geRam_SetupBlock (NewPtr, newsize, DONT_INITIALIZE); + + geRam_CurrentlyUsed += (newsize - size); + if (geRam_CurrentlyUsed > geRam_MaximumUsed) + { + geRam_MaximumUsed = geRam_CurrentlyUsed; + } + assert ((geRam_CurrentlyUsed >= 0) && "free()d more ram than you allocated!"); + + return NewPtr + HEADER_SIZE; + } + +#endif // NDEBUG + +#ifndef NDEBUG + +GENESISAPI void geRam_ReportAllocations(void) +{ + _CrtDumpMemoryLeaks(); +} + +#endif + + // for external programs that allocate memory some other way. + // Here they can use ram to keep track of the memory. +GENESISAPI void geRam_AddAllocation (int n, uint32 size) + { + // and update the allocations stuff + geRam_NumberOfAllocations += n; + geRam_CurrentlyUsed += size; + + if (geRam_NumberOfAllocations > geRam_MaximumNumberOfAllocations) + { + geRam_MaximumNumberOfAllocations = geRam_NumberOfAllocations; + } + if (geRam_CurrentlyUsed > geRam_MaximumUsed) + { + geRam_MaximumUsed = geRam_CurrentlyUsed; + } + } + +#endif // MINIMAL_CONFIG + + +#ifndef NDEBUG +geBoolean geRam_IsValidPtr(void *ptr) +{ +char * p = ptr; +uint32 size; + + if (p == NULL) return GE_FALSE; + + // make p point to the beginning of the block + p -= HEADER_SIZE; + + // get size from block + size = *((uint32 *)p); + + // check stamp at front + if (memcmp (p+SizeSize, MemStamp, MemStampSize) != 0) + { + return GE_FALSE; + } + + // and at back + if (memcmp (p+HEADER_SIZE+size, MemStamp, MemStampSize) != 0) + { + return GE_FALSE; + } + +return GE_TRUE; +} +#endif diff --git a/G3D/Support/geAssert.c b/G3D/Support/geAssert.c new file mode 100644 index 0000000..8ea7508 --- /dev/null +++ b/G3D/Support/geAssert.c @@ -0,0 +1,134 @@ +/****************************************************************************************/ +/* GEASSERT.C */ +/* */ +/* Author: */ +/* Description: Replacement for assert implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "geAssert.h" +#include +#include +#include +#include + +// See geAssert.h for details. + +//void __cdecl _assertge (void *expr,void *filename,unsigned lineno); +void geAssertDefault(void *, void *, unsigned); +geAssertCallbackFn *geAssertCallback = &geAssertDefault; + +geAssertCallbackFn *geSetAssertCallback( geAssertCallbackFn *newAssertCallback ) +{ + geAssertCallbackFn *oldCallback = geAssertCallback; + geAssertCallback = newAssertCallback; + return oldCallback; +} + +void geAssertDefault( void *exp, void *file, unsigned line ) +{ +#ifdef _DEBUG + _assert( exp, file, line ); +#endif +} + + +// This might seem a little redundant, but I needed a unique name +// for the place that all geAsserts would begin. From here, I +// call the geAssertCallback routine, whatever it has been +// assigned to be. -Ken +void geAssertEntryPoint( void *exp, void *file, unsigned line ) +{ + geAssertCallback( exp, file, line ); +} + +//------------------------------------------- + +static geAssert_CriticalShutdownCallback CriticalCallBack = NULL; +static void * CriticalCallBackContext = NULL; + +void geAssert_SetCriticalShutdownCallback( geAssert_CriticalShutdownCallback CB ,void *Context) +{ + CriticalCallBack = CB; + CriticalCallBackContext = Context; +} + +#ifndef NDEBUG + +#include +#include + +#define MAX_ASSERT_STRING_LENGTH 4096 +/* +void __cdecl _assertge (void *expr,void *filename,unsigned lineno) +{ +int nCode; +char assertbuf[MAX_ASSERT_STRING_LENGTH]; +static int in_assert_cnt = 0; // a semaphore + + if ( in_assert_cnt ) + return; + in_assert_cnt++; + + if ( (strlen(expr) + strlen(filename) + 100) < MAX_ASSERT_STRING_LENGTH ) + sprintf(assertbuf,"assert(%s) \n FILE %s : LINE : %d\n",expr,filename,lineno); + else + sprintf(assertbuf," assert string longer than %d characters!\n",MAX_ASSERT_STRING_LENGTH); + + nCode = MessageBox(NULL,assertbuf, + "Genesis3D Exception", + MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL); + + if (nCode == IDIGNORE) + { + in_assert_cnt --; + return; + } + + // Abort: abort the program + if (nCode == IDABORT) + { + // CriticalCallBack does things like shut down the driver + // if we retry or ignore, don't do it, so.. + if ( CriticalCallBack ) + { + CriticalCallBack(CriticalCallBackContext); + } + + // raise abort signal + raise(SIGABRT); + + // We usually won't get here, but it's possible that + // SIGABRT was ignored. So exit the program anyway. + + _exit(3); + } + + // Retry: call the debugger + // minimal code from here out so that the debugger can easily step back + // to the asserting line of code : + + if (nCode == IDRETRY) + __asm { int 3 }; + + in_assert_cnt --; +} +*/ +#endif // NDEBUG + + + + diff --git a/G3D/Support/geAssert.h b/G3D/Support/geAssert.h new file mode 100644 index 0000000..6bacd34 --- /dev/null +++ b/G3D/Support/geAssert.h @@ -0,0 +1,67 @@ +/****************************************************************************************/ +/* GEASSERT.H */ +/* */ +/* Author: */ +/* Description: Replacement for assert interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_ASSERT_H +#define GE_ASSERT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// You should use geAssert() anywhere in the Genesis engine that +// you would normally use assert(). +// +// If you wish to be called back when asserts happen, use the +// routine geAssertSetCallback(). It returns the address of +// the callback routine that you're replacing. + + +#ifdef NDEBUG + + #define geAssert(exp) + +#else + + extern void geAssertEntryPoint( void *, void *, unsigned ); + + #define geAssert(exp) (void)( (exp) || (geAssertEntryPoint(#exp, __FILE__, __LINE__), 0) ) + +#endif + +/************************************************************/ + +typedef void geAssertCallbackFn( void *exp, void *file, unsigned line ); + +geAssertCallbackFn *geAssertSetCallback( geAssertCallbackFn *newAssertCallback ); + +typedef void (*geAssert_CriticalShutdownCallback) (void *Context); + +extern void geAssert_SetCriticalShutdownCallback( geAssert_CriticalShutdownCallback CB , void *Context); + +/************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Support/log.c b/G3D/Support/log.c new file mode 100644 index 0000000..c00ea0b --- /dev/null +++ b/G3D/Support/log.c @@ -0,0 +1,56 @@ +/****************************************************************************************/ +/* LOG.C */ +/* */ +/* Author: */ +/* Description: Debugging logger implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include + +void Log_Out(const char * string) +{ +#ifdef _DEBUG + OutputDebugString(string); +#endif + printf(string); +} + + +void Log_Puts(const char * string) +{ + Log_Out(string); + Log_Out("\n"); +} + +void Log_Printf(const char * String, ...) +{ + va_list ArgPtr; + char TempStr[1024]; + + va_start(ArgPtr, String); + vsprintf(TempStr, String, ArgPtr); + va_end(ArgPtr); + + Log_Out(TempStr); +} + +#ifdef _LOG +#pragma message("LOG on") +#endif \ No newline at end of file diff --git a/G3D/Support/log.h b/G3D/Support/log.h new file mode 100644 index 0000000..b112ce2 --- /dev/null +++ b/G3D/Support/log.h @@ -0,0 +1,48 @@ +/****************************************************************************************/ +/* LOG.H */ +/* */ +/* Author: */ +/* Description: Debugging logger interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_LOG_H +#define GE_LOG_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _LOG + +void Log_Puts( const char * string); +void Log_Printf(const char * string, ...); + +#else // _LOG + +static _inline void Log_Printf(const char * str, ...) { } +#define Log_Puts(string) + +#endif // _LOG + +#ifdef __cplusplus +} +#endif + +#endif // LOG_H + diff --git a/G3D/Support/mempool.c b/G3D/Support/mempool.c new file mode 100644 index 0000000..568e247 --- /dev/null +++ b/G3D/Support/mempool.c @@ -0,0 +1,331 @@ +/****************************************************************************************/ +/* MEMPOOL.C */ +/* */ +/* Author: Charles Bloom */ +/* Description: Fixed size block memory allocator implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "mempool.h" +#include "ram.h" + +/* + * MemPool is a 'root' level object (eg. 'list' uses us). We sit only above 'Ram' + * in the heirarchy + * + * MemPool + * system for fast Resetting & Freeing of nodes; for use in tree structures + * requires no traversing for freeing + * does auto-extending of memory space in case you use more space than + * expected or if you don't know how much you will need + * HunkLength is forced to be a multiple of 4 + * + */ + +#define RamCalloc(size) geRam_AllocateClear(size) +#define RamFree(mem) geRam_Free(mem) +#define RamRealloc(mem,size) geRam_Realloc(mem,size) + +#ifndef memclear +#define memclear(mem,size) memset(mem,0,size); +#endif + +/**********************/ + +/*structs:*/ +typedef struct MemBlock MemBlock; +struct MemBlock +{ + MemBlock * Next; + char * MemBase; + char * MemPtr; + int MemLength; + int MemFree; // MemPtr + MemFree == MemBase + MemLength +}; + + +struct MemPool +{ + int HunkLength; + MemBlock * CurMemBlock; // jump into the list + MemBlock * MemList; // list of memblocks + int AutoExtendNumItems; + int NumFreedHunks; + int MaxNumFreedHunks; + void ** FreedHunks; + int NumItemsActive; +}; + +int MemBlock_IsValid(MemBlock *mb) +{ + if ( ! mb ) return 0; + if ( mb->Next ) + { + if ( ! MemBlock_IsValid(mb->Next) ) + return 0; + } + + assert( geRam_IsValidPtr(mb->MemBase) ); + + if ( mb->MemFree < 0 || mb->MemFree > mb->MemLength ) + return 0; + if ( mb->MemPtr != mb->MemBase + (mb->MemLength - mb->MemFree) ) + return 0; +return 1; +} + +int MemPool_IsValid(MemPool * Pool) +{ + if ( ! Pool ) return 0; + if ( Pool->NumFreedHunks < 0 || Pool->AutoExtendNumItems < 0 + || Pool->MaxNumFreedHunks < 0 || Pool->NumItemsActive || Pool->HunkLength ) + return 0; + if ( Pool->NumFreedHunks >= Pool->MaxNumFreedHunks ) return 0; + + // make sure curmemblock is in the memblock list + // <> make sure the freedhunks are in the memblocks (this is the most likely error) + + return MemBlock_IsValid(Pool->MemList); +} + +MemPool * MemPool_Create (int HunkLength,int NumHunks,int AutoExtendNumItems) +{ +MemPool * Ret; + +if ( (Ret = RamCalloc(sizeof(MemPool))) == NULL ) + return(NULL); + +Ret->HunkLength = (HunkLength+3)&(~3); +Ret->CurMemBlock = NULL; +Ret->MemList = NULL; +Ret->NumFreedHunks = 0; +Ret->MaxNumFreedHunks = 16; +Ret->AutoExtendNumItems = AutoExtendNumItems; +Ret->NumItemsActive = 0; + +if ( (Ret->FreedHunks = RamCalloc(Ret->MaxNumFreedHunks*sizeof(void *))) == NULL ) +{ + RamFree(Ret); + return(NULL); +} + +if ( ! MemPool_Extend(Ret,NumHunks) ) +{ + RamFree(Ret->FreedHunks); + RamFree(Ret); + return(NULL); +} + +return(Ret); +} + +void MemPool_Destroy(MemPool ** pPool) +{ +MemBlock * CurMemBlock; +MemBlock * NextMemBlock; +MemPool * Pool; + + assert(pPool); + + Pool = *pPool; + + if ( Pool == NULL ) return; + + CurMemBlock = Pool->MemList; + while(CurMemBlock) + { + RamFree(CurMemBlock->MemBase); + NextMemBlock = CurMemBlock->Next; + RamFree(CurMemBlock); + CurMemBlock = NextMemBlock; + } + + RamFree(Pool->FreedHunks); + RamFree(Pool); + + *pPool = NULL; +} + +void * MemPool_GetHunk (MemPool * Pool) +{ +void * Ret; +MemBlock * CurMemBlock; + + if ( Pool->NumFreedHunks > 0 ) + { + Pool->NumFreedHunks--; + Ret = Pool->FreedHunks[Pool->NumFreedHunks]; + + goto GotHunk; + } + + if ( (CurMemBlock = Pool->CurMemBlock) == NULL ) + return(NULL); + + if ( CurMemBlock->MemFree < Pool->HunkLength ) + { + if ( ! MemPool_Extend(Pool,Pool->AutoExtendNumItems) ) + return(NULL); + CurMemBlock = Pool->CurMemBlock; + } + + Ret = (void *) CurMemBlock->MemPtr; + + CurMemBlock->MemFree -= Pool->HunkLength; + CurMemBlock->MemPtr += Pool->HunkLength; + +GotHunk: + +// clear at alloc & reset & Free, not in Get +// memclear(Ret,Pool->HunkLength); + + Pool->NumItemsActive++; + +return(Ret); +} + +void MemPool_Reset(MemPool * Pool) +{ +MemBlock * CurMemBlock; + + Pool->NumFreedHunks = 0; + Pool->NumItemsActive = 0; + Pool->CurMemBlock = Pool->MemList; + + for( CurMemBlock = Pool->MemList; CurMemBlock ; CurMemBlock = CurMemBlock->Next) + { + CurMemBlock->MemFree = CurMemBlock->MemLength; + CurMemBlock->MemPtr = CurMemBlock->MemBase; + + memclear(CurMemBlock->MemBase,CurMemBlock->MemLength); + } +} + +int MemPool_Extend(MemPool * Pool, int NumHunks) +{ +MemBlock * NewMemBlock; + + NewMemBlock = Pool->MemList; + while ( NewMemBlock ) + { + if ( NewMemBlock->MemFree > Pool->HunkLength ) + { + Pool->CurMemBlock = NewMemBlock; + return(1); + } + NewMemBlock = NewMemBlock->Next; + } + + if ( (NewMemBlock = RamCalloc(sizeof(MemBlock))) == NULL ) + return(0); + + NewMemBlock->MemLength = NumHunks * Pool->HunkLength; + NewMemBlock->MemFree = NewMemBlock->MemLength; + + if ( (NewMemBlock->MemBase = RamCalloc(NewMemBlock->MemLength)) == NULL ) + { + RamFree(NewMemBlock); + return(0); + } + + NewMemBlock->MemPtr = NewMemBlock->MemBase; + + NewMemBlock->Next = Pool->MemList; + Pool->MemList = NewMemBlock; + + Pool->CurMemBlock = NewMemBlock; + +return(1); +} + +int MemPool_FreeHunk(MemPool * Pool,void * Hunk) +{ + assert( Pool ); + // <> assert Hunk is in Pool ! + + // we must use this growing array for Freed Hunks, because + // to use a linked list of freed hunks, we'd need to use MemPool !!! + + if ( Pool->NumFreedHunks >= Pool->MaxNumFreedHunks ) + { + Pool->MaxNumFreedHunks <<= 1; + + Pool->FreedHunks = RamRealloc(Pool->FreedHunks,Pool->MaxNumFreedHunks*sizeof(void *)); + assert(Pool->FreedHunks); + if ( ! Pool->FreedHunks ) + return(0); + } + + Pool->FreedHunks[Pool->NumFreedHunks] = Hunk; + Pool->NumFreedHunks++; + + Pool->NumItemsActive--; + + memclear(Hunk,Pool->HunkLength); + +return(1); +} + +/*************************/ +static MemBlock * WalkMemBlock; +static char *WalkPtr,*WalkPtrEnd; +static MemPool * LastPool; + +void * MemPool_WalkNext(MemPool *Pool,void *Hunk) +{ + if ( ! Pool ) return NULL; + if ( ! Hunk ) + { + LastPool = Pool; + WalkMemBlock = Pool->MemList; + if ( ! WalkMemBlock ) return NULL; + WalkPtr = WalkMemBlock->MemBase; + WalkPtrEnd = WalkPtr + (WalkMemBlock->MemLength - WalkMemBlock->MemFree); + } + else + { + assert( Pool == LastPool ); + assert( WalkPtr == Hunk ); + rewalk: + WalkPtr += Pool->HunkLength; + if ( WalkPtr >= WalkPtrEnd ) + { + WalkMemBlock = WalkMemBlock->Next; + if ( ! WalkMemBlock ) return NULL; + WalkPtr = WalkMemBlock->MemBase; + WalkPtrEnd = WalkPtr + (WalkMemBlock->MemLength - WalkMemBlock->MemFree); + } + } + + // must check to see if WalkPtr is in the FreedHunks ! + // this is so slow it makes this function worthless! + { + int i; + for(i=0;iNumFreedHunks;i++) + { + if ( WalkPtr == Pool->FreedHunks[i] ) + { + Hunk = WalkPtr; + goto rewalk; + } + } + } + +return WalkPtr; +} diff --git a/G3D/Support/mempool.h b/G3D/Support/mempool.h new file mode 100644 index 0000000..2206683 --- /dev/null +++ b/G3D/Support/mempool.h @@ -0,0 +1,48 @@ +/****************************************************************************************/ +/* MEMPOOL.H */ +/* */ +/* Author: Charles Bloom */ +/* Description: Fixed size block memory allocator interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef MEMPOOL_H +#define MEMPOOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MemPool MemPool; + +extern MemPool * MemPool_Create(int HunkLength,int NumHunks,int AutoExtendNumItems); +extern int MemPool_Extend(MemPool * Pool,int NumHunks); +extern void MemPool_Destroy(MemPool ** pPool); +extern void MemPool_Reset(MemPool * Pool); +extern void * MemPool_GetHunk(MemPool * Pool); +extern int MemPool_FreeHunk(MemPool * Pool,void *Hunk); + + /* NOTEZ: MemPool_Get clears the memory block to zeros*/ + +#ifdef _DEBUG +extern int MemPool_IsValid(MemPool * Pool); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*CRB_MEMPOOL_H*/ diff --git a/G3D/Support/ramdll.c b/G3D/Support/ramdll.c new file mode 100644 index 0000000..bb8f5c1 --- /dev/null +++ b/G3D/Support/ramdll.c @@ -0,0 +1,25 @@ +/****************************************************************************************/ +/* RAMDLL.C */ +/* */ +/* Author: */ +/* Description: A tragic waste of real estate to make the DLL version of G3D work. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifdef GENESISDLLVERSION +void *StupidUnusedPointer; +#endif + diff --git a/G3D/Tclip.c b/G3D/Tclip.c new file mode 100644 index 0000000..1dc7816 --- /dev/null +++ b/G3D/Tclip.c @@ -0,0 +1,571 @@ +/****************************************************************************************/ +/* TClip */ +/* */ +/* Author: Mike Sandige & Charles Bloom */ +/* Description: Triangle Clipping to the screen rectangle */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +//#define DO_TIMER + +/********* + +Cbloom Jan 18 +TClip gained 2-3 fps +(not counting the gains already from _SetTexture) + +I reorganized the TClip_Triangle function flow to early-out +for triangles all-in or all-out. The old code considered this +case, but was not as lean as possible for these most-common cases. + +To solve these problems, flow was changed to : + 1. do all compares and accumulated the 3 out bits for each of the five faces + (so we have 15 bit-flags) + 2. then do clips while more clips remain. + 3. as a free benefit, the new structure means that Rasterize is only called once + in TClip_Triangle, so it was inlined. + +Step two results in very fast exiting when no clipping remains. + + +If/When we get the Intel compiler that can optimize ?: to CMOV, speed will improve +even more! + +----------------------------------- + +Timer profiling shows: +(with D3DDrv, in ActView, viewing dema.act) +times are seconds per frame + +default pose : 58.6 fps +TClip_New : 0.006749 +TClip_Rasterize : 0.006149 + +default pose : 52.9 fps +TClip_Old : 0.007230 : 1.$ % +TClip_Rasterize : 0.006183 : 1.$ % + +***********/ + +// TClip.c +// Fast Triangle Clipping +/*}{***********************/ + +#include +#include + +#include "TClip.h" +#include "engine.h" +#include "bitmap._h" + +#include "list.h" +#include "ram.h" + +#include "timer.h" + +TIMER_VARS(TClip_Triangle); + +//#define ONE_OVER_Z_PIPELINE // this has more accuracy, but the slowness of doing 1/ divides + +typedef enum +{ + BACK_CLIPPING_PLANE = 0, + LEFT_CLIPPING_PLANE, + RIGHT_CLIPPING_PLANE, + TOP_CLIPPING_PLANE, + BOTTOM_CLIPPING_PLANE, + NUM_CLIPPING_PLANES +} geTClip_ClippingPlane; + +// 3 bits for V_IN/OUT flags +#define V_ALL_IN (0) +#define V0_OUT (1) +#define V1_OUT (2) +#define V2_OUT (4) + + // at a=0, result is l; at a=1, result is h +#define LINEAR_INTERPOLATE(a,l,h) ((l)+(((h)-(l))*(a))) + +#define RASTERIZECC +typedef void (RASTERIZECC *geTClip_Rasterize_FuncPtr) (const GE_LVertex * TriVtx); + +typedef struct geTClip_StaticsType +{ + geFloat LeftEdge; + geFloat RightEdge; + geFloat TopEdge; + geFloat BottomEdge; + geFloat BackEdge; + + DRV_Driver * Driver; + geEngine *Engine; + const geBitmap *Bitmap; + geRDriver_THandle * THandle; + + geTClip_Rasterize_FuncPtr RasterizeFunc; + + uint32 RenderFlags; // LA + +} geTClip_StaticsType; + +/*}{************ Protos ***********/ + +static void RASTERIZECC geTClip_Rasterize_Tex(const GE_LVertex * TriVtx); +static void RASTERIZECC geTClip_Rasterize_Gou(const GE_LVertex * TriVtx); +static void GENESISCC geTClip_Split(GE_LVertex *NewVertex,const GE_LVertex *V1,const GE_LVertex *V2,int ClippingPlane); +static void GENESISCC geTClip_TrianglePlane(const GE_LVertex * zTriVertex,geTClip_ClippingPlane ClippingPlane); +static void GENESISCC geTClip_TrianglePlane_Old(const GE_LVertex * zTriVertex,geTClip_ClippingPlane ClippingPlane); + +/*}{************ The State Statics ***********/ + +static Link * geTClip_Link = NULL; +static geTClip_StaticsType geTClip_Statics; +static uint32 ActiveRenderFlags = 0; // LA + +/*}{************ Functions ***********/ + +// LA +void GENESISCC geTClip_SetRenderFlags(uint32 newflags) +{ + geTClip_Statics.RenderFlags = newflags; + ActiveRenderFlags = newflags; + return; +} + +geBoolean GENESISCC geTClip_Push(void) +{ +geTClip_StaticsType * TCI; + + geTClip_Statics.RenderFlags = ActiveRenderFlags; // LA + + if ( ! geTClip_Link ) + { + List_Start(); + geTClip_Link = Link_Create(); + if ( ! geTClip_Link ) + return GE_FALSE; + } + + TCI = geRam_Allocate(sizeof(geTClip_StaticsType)); + if ( ! TCI ) + return GE_FALSE; + memcpy(TCI,&geTClip_Statics,sizeof(geTClip_StaticsType)); + + Link_Push( geTClip_Link , TCI ); + + geTClip_Statics.RenderFlags = 0; // LA, this is needed to set RF = 0 for default after any _Push + + return GE_TRUE; +} + +geBoolean GENESISCC geTClip_Pop(void) +{ +geTClip_StaticsType * TCI; + if ( ! geTClip_Link ) + return GE_FALSE; + TCI = Link_Pop( geTClip_Link ); + if ( ! TCI ) + return GE_FALSE; + memcpy(&geTClip_Statics,TCI,sizeof(geTClip_StaticsType)); + geRam_Free(TCI); + + if ( ! Link_Peek(geTClip_Link) ) + { + Link_Destroy(geTClip_Link); + geTClip_Link = NULL; + List_Stop(); + } + + ActiveRenderFlags = geTClip_Statics.RenderFlags; // LA, set ARF from newly pop'd statics + + return GE_TRUE; +} + +geBoolean GENESISCC geTClip_SetTexture(const geBitmap * Bitmap) +{ + geTClip_Statics.Bitmap = Bitmap; + if ( Bitmap ) + { + geTClip_Statics.THandle = geBitmap_GetTHandle(Bitmap); + assert(geTClip_Statics.THandle); + geTClip_Statics.RasterizeFunc = geTClip_Rasterize_Tex; + } + else + { + geTClip_Statics.THandle = NULL; + geTClip_Statics.RasterizeFunc = geTClip_Rasterize_Gou; + } +return GE_TRUE; +} + +void GENESISCC geTClip_SetupEdges( + geEngine *Engine, + geFloat LeftEdge, + geFloat RightEdge, + geFloat TopEdge , + geFloat BottomEdge, + geFloat BackEdge) +{ + assert(Engine); + memset(&geTClip_Statics,0,sizeof(geTClip_Statics)); + geTClip_Statics.Engine = Engine; + geTClip_Statics.Driver = Engine->DriverInfo.RDriver; //Engine_GetRDriver(Engine); + geTClip_Statics.LeftEdge = LeftEdge; + geTClip_Statics.RightEdge = RightEdge; + geTClip_Statics.TopEdge = TopEdge; + geTClip_Statics.BottomEdge = BottomEdge; + geTClip_Statics.BackEdge = BackEdge; +} + +void geTClip_Done(void) +{ + TIMER_REPORT(TClip_Triangle); +} + +void GENESISCC geTClip_Triangle(const GE_LVertex TriVertex[3]) +{ + + TIMER_P(TClip_Triangle); + +#if 1 + geTClip_TrianglePlane(TriVertex,BACK_CLIPPING_PLANE); + //geTClip_TrianglePlane(TriVertex,LEFT_CLIPPING_PLANE); +#else + geTClip_TrianglePlane_Old(TriVertex,BACK_CLIPPING_PLANE); +#endif + + TIMER_Q(TClip_Triangle); +} + +/*}{************ TClip_Rasterize ***********/ + +static void RASTERIZECC geTClip_Rasterize_Tex(const GE_LVertex * TriVtx) +{ + geTClip_Statics.Driver->RenderMiscTexturePoly((DRV_TLVertex *)TriVtx, + 3,geTClip_Statics.THandle, ActiveRenderFlags); // LA +} + +static void RASTERIZECC geTClip_Rasterize_Gou(const GE_LVertex * TriVtx) +{ + geTClip_Statics.Driver->RenderGouraudPoly((DRV_TLVertex *)TriVtx,3,ActiveRenderFlags); // LA +} + +static void GENESISCC geTClip_Rasterize(const GE_LVertex * TriVtx) +{ + +// we require GE_LVertex == DRV_TLVertex == GE_TLVertex +// this is a silly point because the TClip inputs should really be GE_TLVertex anyway !!!! + + if ( geTClip_Statics.THandle ) + { + geTClip_Statics.Driver->RenderMiscTexturePoly((DRV_TLVertex *)TriVtx, + 3,geTClip_Statics.THandle,ActiveRenderFlags); // LA + } + else + { + geTClip_Statics.Driver->RenderGouraudPoly((DRV_TLVertex *)TriVtx, + 3,ActiveRenderFlags); // LA + } +} + +/*}{************ TClip_Split ***********/ + +static void GENESISCC geTClip_Split(GE_LVertex *NewVertex,const GE_LVertex *V1,const GE_LVertex *V2,int ClippingPlane) +{ + geFloat Ratio=0.0f; + geFloat OneOverZ1,OneOverZ2; + + #ifdef ONE_OVER_Z_PIPELINE + // in here ->Z is really (one over z) + OneOverZ1 = V1->Z; + OneOverZ2 = V2->Z; + #else + OneOverZ1 = 1.0f/V1->Z; + OneOverZ2 = 1.0f/V2->Z; + #endif + + switch (ClippingPlane) + { + case (BACK_CLIPPING_PLANE): + assert((V2->Z - V1->Z)!=0.0f); + Ratio = ((1.0f/geTClip_Statics.BackEdge) - OneOverZ2)/( OneOverZ1 - OneOverZ2 ); + + NewVertex->X = LINEAR_INTERPOLATE(Ratio,(V2->X),(V1->X)); + NewVertex->Y = LINEAR_INTERPOLATE(Ratio,(V2->Y),(V1->Y)); + #ifdef ONE_OVER_Z_PIPELINE + NewVertex->Z = 1.0f/ geTClip_Statics.BackEdge; + #else + NewVertex->Z = geTClip_Statics.BackEdge; + #endif + + break; + case (LEFT_CLIPPING_PLANE): + assert((V2->X - V1->X)!=0.0f); + Ratio = (geTClip_Statics.LeftEdge - V2->X)/( V1->X - V2->X); + + NewVertex->X = geTClip_Statics.LeftEdge; + NewVertex->Y = LINEAR_INTERPOLATE(Ratio,(V2->Y),(V1->Y)); + #ifdef ONE_OVER_Z_PIPELINE + NewVertex->Z = LINEAR_INTERPOLATE(Ratio,OneOverZ2,OneOverZ1); + #else + NewVertex->Z = 1.0f/LINEAR_INTERPOLATE(Ratio,OneOverZ2,OneOverZ1); + #endif + + break; + case (RIGHT_CLIPPING_PLANE): + assert((V2->X - V1->X)!=0.0f); + Ratio = (geTClip_Statics.RightEdge - V2->X)/( V1->X - V2->X); + + NewVertex->X = geTClip_Statics.RightEdge; + NewVertex->Y = LINEAR_INTERPOLATE(Ratio,(V2->Y),(V1->Y)); + #ifdef ONE_OVER_Z_PIPELINE + NewVertex->Z = LINEAR_INTERPOLATE(Ratio,OneOverZ2,OneOverZ1); + #else + NewVertex->Z = 1.0f/LINEAR_INTERPOLATE(Ratio,OneOverZ2,OneOverZ1); + #endif + + break; + case (TOP_CLIPPING_PLANE): + assert((V2->Y - V1->Y)!=0.0f); + Ratio = (geTClip_Statics.TopEdge - V2->Y)/( V1->Y - V2->Y); + + NewVertex->X = LINEAR_INTERPOLATE(Ratio,(V2->X),(V1->X)); + NewVertex->Y = geTClip_Statics.TopEdge; + #ifdef ONE_OVER_Z_PIPELINE + NewVertex->Z = LINEAR_INTERPOLATE(Ratio,OneOverZ2,OneOverZ1); + #else + NewVertex->Z = 1.0f/LINEAR_INTERPOLATE(Ratio,OneOverZ2,OneOverZ1); + #endif + + break; + case (BOTTOM_CLIPPING_PLANE): + assert((V2->Y - V1->Y)!=0.0f); + Ratio = (geTClip_Statics.BottomEdge - V2->Y)/( V1->Y - V2->Y); + + NewVertex->X = LINEAR_INTERPOLATE(Ratio,(V2->X),(V1->X)); + NewVertex->Y = geTClip_Statics.BottomEdge; + #ifdef ONE_OVER_Z_PIPELINE + NewVertex->Z = LINEAR_INTERPOLATE(Ratio,OneOverZ2,OneOverZ1); + #else + NewVertex->Z = 1.0f/LINEAR_INTERPOLATE(Ratio,OneOverZ2,OneOverZ1); + #endif + + break; + } + + + { + geFloat OneOverZ1_Ratio; + geFloat OneOverZ2_Ratio; + #ifdef ONE_OVER_Z_PIPELINE + OneOverZ1 *= 1.0f / NewVertex->Z; + OneOverZ2 *= 1.0f / NewVertex->Z; + #else + OneOverZ1 *= NewVertex->Z; + OneOverZ2 *= NewVertex->Z; + #endif + OneOverZ1_Ratio = OneOverZ1 * Ratio; + OneOverZ2_Ratio = OneOverZ2 * Ratio; + + // the following is optimized to get rid of a handfull of multiplies. Read: + // NewVertex->r = LINEAR_INTERPOLATE(Ratio,(V2->r * OneOverZ2),(V1->r * OneOverZ1)); + + NewVertex->r =(V2->r * OneOverZ2) + (V1->r * OneOverZ1_Ratio) - (V2->r * OneOverZ2_Ratio); + NewVertex->g =(V2->g * OneOverZ2) + (V1->g * OneOverZ1_Ratio) - (V2->g * OneOverZ2_Ratio); + NewVertex->b =(V2->b * OneOverZ2) + (V1->b * OneOverZ1_Ratio) - (V2->b * OneOverZ2_Ratio); + NewVertex->a =(V2->a * OneOverZ2) + (V1->a * OneOverZ1_Ratio) - (V2->a * OneOverZ2_Ratio); + NewVertex->u =(V2->u * OneOverZ2) + (V1->u * OneOverZ1_Ratio) - (V2->u * OneOverZ2_Ratio); + NewVertex->v =(V2->v * OneOverZ2) + (V1->v * OneOverZ1_Ratio) - (V2->v * OneOverZ2_Ratio); + } + +} + + +/*}{************ TClip_TrianglePlane ***********/ + +static void GENESISCC geTClip_TrianglePlane(const GE_LVertex * TriVertex, + geTClip_ClippingPlane ClippingPlane) +{ +uint32 OutBits = 0; + + switch(ClippingPlane) + { + case BACK_CLIPPING_PLANE: + + OutBits |= (TriVertex[0].Z < geTClip_Statics.BackEdge) ? V0_OUT : 0; + OutBits |= (TriVertex[1].Z < geTClip_Statics.BackEdge) ? V1_OUT : 0; + OutBits |= (TriVertex[2].Z < geTClip_Statics.BackEdge) ? V2_OUT : 0; + + case LEFT_CLIPPING_PLANE: + + OutBits |= (TriVertex[0].X < geTClip_Statics.LeftEdge) ? (V0_OUT<<3) : 0; + OutBits |= (TriVertex[1].X < geTClip_Statics.LeftEdge) ? (V1_OUT<<3) : 0; + OutBits |= (TriVertex[2].X < geTClip_Statics.LeftEdge) ? (V2_OUT<<3) : 0; + + case RIGHT_CLIPPING_PLANE: + + OutBits |= (TriVertex[0].X > geTClip_Statics.RightEdge) ? (V0_OUT<<6) : 0; + OutBits |= (TriVertex[1].X > geTClip_Statics.RightEdge) ? (V1_OUT<<6) : 0; + OutBits |= (TriVertex[2].X > geTClip_Statics.RightEdge) ? (V2_OUT<<6) : 0; + + case TOP_CLIPPING_PLANE: + + OutBits |= (TriVertex[0].Y < geTClip_Statics.TopEdge) ? (V0_OUT<<9) : 0; + OutBits |= (TriVertex[1].Y < geTClip_Statics.TopEdge) ? (V1_OUT<<9) : 0; + OutBits |= (TriVertex[2].Y < geTClip_Statics.TopEdge) ? (V2_OUT<<9) : 0; + + case BOTTOM_CLIPPING_PLANE: + + OutBits |= (TriVertex[0].Y > geTClip_Statics.BottomEdge) ? (V0_OUT<<12) : 0; + OutBits |= (TriVertex[1].Y > geTClip_Statics.BottomEdge) ? (V1_OUT<<12) : 0; + OutBits |= (TriVertex[2].Y > geTClip_Statics.BottomEdge) ? (V2_OUT<<12) : 0; + + case NUM_CLIPPING_PLANES: + break; + } + + if ( OutBits ) + { + GE_LVertex NewTriVertex[3]; + + memset(NewTriVertex, '\0',sizeof(GE_LVertex)*(3)); + + ClippingPlane = 0; + for(;;) + { + assert(ClippingPlane < NUM_CLIPPING_PLANES); + + switch ( OutBits & 7 ) + { + case (V_ALL_IN): //NOT CLIPPED + OutBits >>= 3; + ClippingPlane ++; + continue; + + // these all return: + + case (V0_OUT): + NewTriVertex[0] = TriVertex[2]; + geTClip_Split(&(NewTriVertex[1]),TriVertex+0,TriVertex+2,ClippingPlane); + NewTriVertex[2] = TriVertex[1]; + + geTClip_TrianglePlane(NewTriVertex,ClippingPlane+1); + + NewTriVertex[0] = NewTriVertex[1]; + geTClip_Split(&(NewTriVertex[1]),TriVertex+0,TriVertex+1,ClippingPlane); + + //<> could gain a little speed like this, but who cares? + // if ( ! (OutBits>>3) ) + // goto Rasterize + // else + geTClip_TrianglePlane(NewTriVertex,ClippingPlane+1); + return; + + case (V1_OUT): + NewTriVertex[0] = TriVertex[0]; + geTClip_Split(&(NewTriVertex[1]),TriVertex+0,TriVertex+1,ClippingPlane); + NewTriVertex[2] = TriVertex[2]; + + geTClip_TrianglePlane(NewTriVertex,ClippingPlane+1); + + NewTriVertex[0] = NewTriVertex[1]; + geTClip_Split(&(NewTriVertex[1]),TriVertex+1,TriVertex+2,ClippingPlane); + + geTClip_TrianglePlane(NewTriVertex,ClippingPlane+1); + return; + + case (V0_OUT + V1_OUT): + NewTriVertex[0] = TriVertex[2]; + geTClip_Split(&(NewTriVertex[1]),TriVertex+0,TriVertex+2,ClippingPlane); + geTClip_Split(&(NewTriVertex[2]),TriVertex+1,TriVertex+2,ClippingPlane); + + geTClip_TrianglePlane(NewTriVertex,ClippingPlane+1); + return; + + case (V2_OUT): + NewTriVertex[0] = TriVertex[1]; + geTClip_Split(&(NewTriVertex[1]),TriVertex+1,TriVertex+2,ClippingPlane); + NewTriVertex[2] = TriVertex[0]; + + geTClip_TrianglePlane(NewTriVertex,ClippingPlane+1); + + NewTriVertex[0] = NewTriVertex[1]; + geTClip_Split(&(NewTriVertex[1]),TriVertex+0,TriVertex+2,ClippingPlane); + + geTClip_TrianglePlane(NewTriVertex,ClippingPlane+1); + return; + + case (V2_OUT + V0_OUT): + NewTriVertex[0] = TriVertex[1]; + geTClip_Split(&(NewTriVertex[1]),TriVertex+1,TriVertex+2,ClippingPlane); + geTClip_Split(&(NewTriVertex[2]),TriVertex+0,TriVertex+1,ClippingPlane); + + geTClip_TrianglePlane(NewTriVertex,ClippingPlane+1); + return; + + case (V2_OUT + V1_OUT): + NewTriVertex[0] = TriVertex[0]; + geTClip_Split(&(NewTriVertex[1]),TriVertex+0,TriVertex+1,ClippingPlane); + geTClip_Split(&(NewTriVertex[2]),TriVertex+0,TriVertex+2,ClippingPlane); + + geTClip_TrianglePlane(NewTriVertex,ClippingPlane+1); + return; + + case (V2_OUT + V1_OUT + V0_OUT): + /* TOTALLY CLIPPED */ + return; + } + } + } + +#if 0 // { + + // this eliminates an 'if' , but doesn't seem to help :^( + // presumably because it's a predictable branch + geTClip_Statics.RasterizeFunc(TriVertex); + +#else //}{ + + if ( geTClip_Statics.THandle ) + { + geTClip_Statics.Driver->RenderMiscTexturePoly((DRV_TLVertex *)TriVertex, + 3,geTClip_Statics.THandle,ActiveRenderFlags); // LA + } + else + { + geTClip_Statics.Driver->RenderGouraudPoly((DRV_TLVertex *)TriVertex,3,ActiveRenderFlags); // LA + } + +#endif //} + +} + +// LA - this is for completely onscreen-only triangles +void GENESISCC geTClip_UnclippedTriangle(const GE_LVertex TriVertex[3]) +{ + if ( geTClip_Statics.THandle ) + { + geTClip_Statics.Driver->RenderMiscTexturePoly((DRV_TLVertex *)TriVertex, + 3,geTClip_Statics.THandle,ActiveRenderFlags); + } + else + { + geTClip_Statics.Driver->RenderGouraudPoly((DRV_TLVertex *)TriVertex,3,ActiveRenderFlags); + } + return; +} + +/*}{*********** EOF ************/ diff --git a/G3D/VFile/FSMEMORY.C b/G3D/VFile/FSMEMORY.C new file mode 100644 index 0000000..ce5ac4e --- /dev/null +++ b/G3D/VFile/FSMEMORY.C @@ -0,0 +1,505 @@ +/****************************************************************************************/ +/* FSMEMORY.C */ +/* */ +/* Author: Eli Boling */ +/* Description: Memory file system implementation */ +/* Bug repair for 1.1 release - thanks to Tim Brengle */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include +#include + +#include "basetype.h" +#include "ram.h" + +#include "vfile.h" +#include "vfile._h" + +#include "fsmemory.h" + +// "MF01" +#define MEMORYFILE_SIGNATURE 0x3130464D + +// "MF02" +#define MEMORYFINDER_SIGNATURE 0x3230464D + +#define CHECK_HANDLE(H) assert(H);assert(H->Signature == MEMORYFILE_SIGNATURE); +#define CHECK_FINDER(F) assert(F);assert(F->Signature == MEMORYFINDER_SIGNATURE); + +#define MEMORY_FILE_GROW 0x2000 + +typedef struct MemoryFile +{ + unsigned int Signature; + char * Memory; + int Size; + int AllocatedSize; + int Position; + geBoolean WeOwnMemory; + geBoolean ReadOnly; +} MemoryFile; + +static void * GENESISCC FSMemory_FinderCreate( + geVFile * FS, + void * Handle, + const char * FileSpec) +{ + return NULL; +} + +static geBoolean GENESISCC FSMemory_FinderGetNextFile(void *Handle) +{ + assert(!Handle); + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_FinderGetProperties(void *Handle, geVFile_Properties *Props) +{ + assert(!Handle); + return GE_FALSE; +} + +static void GENESISCC FSMemory_FinderDestroy(void *Handle) +{ + assert(!Handle); +} + +static void * GENESISCC FSMemory_Open( + geVFile * FS, + void * Handle, + const char * Name, + void * Context, + unsigned int OpenModeFlags) +{ + return NULL; +} + +static void * GENESISCC FSMemory_OpenNewSystem( + geVFile * FS, + const char * Name, + void * Context, + unsigned int OpenModeFlags) +{ + MemoryFile * NewFS; + geVFile_MemoryContext * MemContext; + + if (FS || Name || !Context) + return NULL; + + MemContext = Context; + + // Don't allow the user to pass in memory pointer if we're updating or creating, because + // we don't know what allocation functions we should use to resize their block if + // necessary. If you want to create a new file, you have to pass in NULL and let + // us manage the allocations. + if (MemContext->Data && (OpenModeFlags & (GE_VFILE_OPEN_UPDATE | GE_VFILE_OPEN_CREATE))) + return NULL; + + if (OpenModeFlags & GE_VFILE_OPEN_DIRECTORY) + return NULL; + + NewFS = geRam_Allocate(sizeof(*NewFS)); + if (!NewFS) + return NewFS; + memset(NewFS, 0, sizeof(*NewFS)); + + NewFS->Memory = MemContext->Data; + NewFS->Size = MemContext->DataLength; + NewFS->AllocatedSize = NewFS->Size; + + if (NewFS->Memory) + { + NewFS->ReadOnly = GE_TRUE; + NewFS->WeOwnMemory = GE_FALSE; + } + else + { + NewFS->ReadOnly = GE_FALSE; + NewFS->WeOwnMemory = GE_TRUE; + } + + NewFS->Signature = MEMORYFILE_SIGNATURE; + + return NewFS; +} + +static geBoolean GENESISCC FSMemory_UpdateContext( + geVFile * FS, + void * Handle, + void * Context, + int ContextSize) +{ + MemoryFile * File; + geVFile_MemoryContext * MemoryContext; + + assert(FS); + assert(Context); + + File = Handle; + + CHECK_HANDLE(File); + + if (ContextSize != sizeof(geVFile_MemoryContext)) + return GE_FALSE; + + MemoryContext = Context; + + MemoryContext->Data = File->Memory; + MemoryContext->DataLength = File->Size; + + return GE_TRUE; +} + +static void GENESISCC FSMemory_Close(void *Handle) +{ + MemoryFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->WeOwnMemory == GE_TRUE && File->Memory) + geRam_Free(File->Memory); + geRam_Free(File); +} + +static int GENESISCC ClampOperationSize(const MemoryFile *File, int Size) +{ + return min(File->Size - File->Position, Size); +} + +static char * GENESISCC DataPtr(const MemoryFile *File) +{ + return File->Memory + File->Position; +} + +static geBoolean GENESISCC FSMemory_GetS(void *Handle, void *Buff, int MaxLen) +{ + MemoryFile * File; + char * p; + char * Start; + char * pBuff; + + assert(Buff); + assert(MaxLen != 0); + + File = Handle; + + CHECK_HANDLE(File); + + MaxLen = ClampOperationSize(File, MaxLen); + if (MaxLen == 0) + return GE_FALSE; + + p = DataPtr(File); + pBuff = Buff; + Start = p; + +//--------- +// Bug fix thanks to Tim Brengle +//--------- + + //while (*p != '\n' && MaxLen > 0) + while (*p != '\n' && MaxLen > 1) + { + *pBuff++ = *p++; + MaxLen--; + } + + File->Position += p - Start + 1; + assert(File->Position <= File->Size); + assert(File->Size <= File->AllocatedSize); + + #if 0 + if (MaxLen != 0) + { + *pBuff = *p; + return GE_TRUE; + } + return GE_FALSE; + #endif + + *(pBuff + 1) = 0; + return GE_TRUE; + +} + +static geBoolean GENESISCC FSMemory_Read(void *Handle, void *Buff, int Count) +{ + MemoryFile * File; + + assert(Buff); + assert(Count != 0); + + File = Handle; + + CHECK_HANDLE(File); + + if (ClampOperationSize(File, Count) != Count) + return GE_FALSE; + + memcpy(Buff, DataPtr(File), Count); + + File->Position += Count; + assert(File->Position <= File->Size); + assert(File->Size <= File->AllocatedSize); + + return GE_TRUE; +} + +static geBoolean GENESISCC TestForExpansion(MemoryFile *File, int Size) +{ + assert(File); + assert(File->ReadOnly == GE_FALSE); + assert(File->WeOwnMemory == GE_TRUE); + + assert(File->AllocatedSize >= File->Size); + assert(File->AllocatedSize >= File->Position); + + if (File->AllocatedSize - File->Position < Size) + { + int NewSize; + char * NewBlock; + + NewSize = ((File->AllocatedSize + Size + (MEMORY_FILE_GROW - 1)) / MEMORY_FILE_GROW) * MEMORY_FILE_GROW; + NewBlock = geRam_Realloc(File->Memory, NewSize); + if (!NewBlock) + return GE_FALSE; + File->Memory = NewBlock; + File->AllocatedSize = NewSize; +//printf("FSMemory: Expanded file to %d bytes\n", NewSize); + } + + return GE_TRUE; +} + +static geBoolean GENESISCC FSMemory_Write(void *Handle, const void *Buff, int Count) +{ + MemoryFile * File; + + assert(Buff); + assert(Count != 0); + + File = Handle; + + CHECK_HANDLE(File); + + if (File->ReadOnly == GE_TRUE) + return GE_FALSE; + + if (TestForExpansion(File, Count) == GE_FALSE) + return GE_FALSE; + + memcpy(DataPtr(File), Buff, Count); + + File->Position += Count; + if (File->Size < File->Position) + File->Size = File->Position; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSMemory_Seek(void *Handle, int Where, geVFile_Whence Whence) +{ + MemoryFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + switch (Whence) + { + int NewPos; + + case GE_VFILE_SEEKCUR: + NewPos = File->Position + Where; + if (NewPos > File->AllocatedSize) + { + if (File->ReadOnly == GE_TRUE) + return GE_FALSE; + if (TestForExpansion(File, Where) == GE_FALSE) + return GE_FALSE; + } + File->Position = NewPos; + break; + + case GE_VFILE_SEEKEND: + if (File->Size < Where) + return GE_FALSE; + File->Position = File->Size - Where; + break; + + case GE_VFILE_SEEKSET: + if (Where > File->AllocatedSize) + { + if (File->ReadOnly == GE_TRUE) + return GE_FALSE; + if (TestForExpansion(File, Where - File->Position) == GE_FALSE) + return GE_FALSE; + } + File->Position = Where; + break; + + default: + assert(!"Unknown seek kind"); + } + + if (File->Position > File->Size) + File->Size = File->Position; + + assert(File->Size <= File->AllocatedSize); + assert(File->Position <= File->AllocatedSize); + + return GE_TRUE; +} + +static geBoolean GENESISCC FSMemory_EOF(const void *Handle) +{ + const MemoryFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->Position == File->Size) + return GE_TRUE; + + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_Tell(const void *Handle, long *Position) +{ + const MemoryFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + *Position = File->Position; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSMemory_Size(const void *Handle, long *Size) +{ + const MemoryFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + *Size = File->Size; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSMemory_GetProperties(const void *Handle, geVFile_Properties *Properties) +{ + assert(!"Not implemented"); + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_SetSize(void *Handle, long Size) +{ + assert(!"Not implemented"); + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_SetAttributes(void *Handle, geVFile_Attributes Attributes) +{ + assert(!"Not implemented"); + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_SetTime(void *Handle, const geVFile_Time *Time) +{ + assert(!"Not implemented"); + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_SetHints(void *Handle, const geVFile_Hints *Hints) +{ + assert(!"Not implemented"); + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_FileExists(geVFile *FS, void *Handle, const char *Name) +{ + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_Disperse( + geVFile * FS, + void * Handle, + const char *Directory, + geBoolean Recursive) +{ + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_DeleteFile(geVFile *FS, void *Handle, const char *Name) +{ + return GE_FALSE; +} + +static geBoolean GENESISCC FSMemory_RenameFile(geVFile *FS, void *Handle, const char *Name, const char *NewName) +{ + return GE_FALSE; +} + +static geVFile_SystemAPIs FSMemory_APIs = +{ + FSMemory_FinderCreate, + FSMemory_FinderGetNextFile, + FSMemory_FinderGetProperties, + FSMemory_FinderDestroy, + + FSMemory_OpenNewSystem, + FSMemory_UpdateContext, + FSMemory_Open, + FSMemory_DeleteFile, + FSMemory_RenameFile, + FSMemory_FileExists, + FSMemory_Disperse, + FSMemory_Close, + + FSMemory_GetS, + FSMemory_Read, + FSMemory_Write, + FSMemory_Seek, + FSMemory_EOF, + FSMemory_Tell, + FSMemory_Size, + + FSMemory_GetProperties, + + FSMemory_SetSize, + FSMemory_SetAttributes, + FSMemory_SetTime, + FSMemory_SetHints, +}; + +const geVFile_SystemAPIs * GENESISCC FSMemory_GetAPIs(void) +{ + return &FSMemory_APIs; +} + diff --git a/G3D/VFile/FSMEMORY.H b/G3D/VFile/FSMEMORY.H new file mode 100644 index 0000000..28a7410 --- /dev/null +++ b/G3D/VFile/FSMEMORY.H @@ -0,0 +1,28 @@ +/****************************************************************************************/ +/* FSMEMORY.H */ +/* */ +/* Author: Eli Boling */ +/* Description: Memory file system interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef FSMEMORY_H +#define FSMEMORY_H + +const geVFile_SystemAPIs * GENESISCC FSMemory_GetAPIs(void); + +#endif + diff --git a/G3D/VFile/dirtree-common.c b/G3D/VFile/dirtree-common.c new file mode 100644 index 0000000..8137354 --- /dev/null +++ b/G3D/VFile/dirtree-common.c @@ -0,0 +1,106 @@ +/****************************************************************************************/ +/* DIRTREE-COMMON.C */ +/* */ +/* Author: Samuel Seay */ +/* Description: Common functions between Dirtree files */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include +#include + +#include "ram.h" +#include "dirtree-common.h" + +char * DuplicateString(const char *String) +{ + int Length; + char * NewString; + + Length = strlen(String) + 1; + NewString = geRam_Allocate(Length); + if (NewString) + memcpy(NewString, String, Length); + return NewString; +} + +const char *GetNextDir(const char *Path, char *Buff) +{ + while (*Path && *Path != '\\') + *Buff++ = *Path++; + *Buff = '\0'; + + if (*Path == '\\') + Path++; + + return Path; +} + +geBoolean MatchPattern(const char *Source, const char *Pattern) +{ + assert(Source); + assert(Pattern); + + switch (*Pattern) + { + case '\0': + if (*Source) + return GE_FALSE; + break; + + case '*': + if (*(Pattern + 1) != '\0') + { + Pattern++; + while (*Source) + { + if (MatchPattern(Source, Pattern) == GE_TRUE) + return GE_TRUE; + Source++; + } + return GE_FALSE; + } + break; + + case '?': + return MatchPattern(Source + 1, Pattern + 1); + + default: + if (*Source == *Pattern) + return MatchPattern(Source + 1, Pattern + 1); + else + return GE_FALSE; + } + + return GE_TRUE; +} + +geBoolean PathHasDir(const char *Path) +{ + if (strchr(Path, '\\')) + return GE_TRUE; + + return GE_FALSE; +} + +#ifdef DEBUG +void indent(int i) +{ + while (i--) + printf(" "); +} +#endif \ No newline at end of file diff --git a/G3D/VFile/dirtree-common.h b/G3D/VFile/dirtree-common.h new file mode 100644 index 0000000..46da5ae --- /dev/null +++ b/G3D/VFile/dirtree-common.h @@ -0,0 +1,53 @@ +/****************************************************************************************/ +/* DIRTREE-COMMON.H */ +/* */ +/* Author: Samuel Seay */ +/* Description: Common functions between Dirtree files */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DIRTREE_COMMON_H +#define DIRTREE_COMMON_H + + +#include "vfile.h" + +typedef struct DirTree_Header +{ + unsigned long Signature; + int Size; + +} DirTree_Header; + +#define DIRTREE_LIST_TERMINATED 0xffffffff +#define DIRTREE_LIST_NOTTERMINATED 0 + +#ifndef MAKEFOURCC +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((unsigned long)(unsigned char)(ch0) | ((unsigned long)(unsigned char)(ch1) << 8) | \ + ((unsigned long)(unsigned char)(ch2) << 16) | ((unsigned long)(unsigned char)(ch3) << 24 )) +#endif + +char * DuplicateString(const char *String); +const char *GetNextDir(const char *Path, char *Buff); +geBoolean MatchPattern(const char *Source, const char *Pattern); +geBoolean PathHasDir(const char *Path); + +#ifdef DEBUG +static void indent(int i); +#endif + +#endif \ No newline at end of file diff --git a/G3D/VFile/dirtree.c b/G3D/VFile/dirtree.c new file mode 100644 index 0000000..6d7764a --- /dev/null +++ b/G3D/VFile/dirtree.c @@ -0,0 +1,732 @@ +/****************************************************************************************/ +/* DIRTREE.C */ +/* */ +/* Author: Eli Boling */ +/* Description: Directory tree implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include +#include +#include +#include + +#include "basetype.h" +#include "ram.h" + +#include "dirtree.h" +#include "dirtree-common.h" + +#define DIRTREE_FILE_SIGNATURE MAKEFOURCC('D', 'T', '0', '1') +static int DirTree_SignatureBase=0x696C6345; +static int DirTree_SignatureOffset=0x21657370; + +typedef struct DirTree +{ + char * Name; + geVFile_Time Time; + geVFile_Attributes AttributeFlags; + long Size; + geVFile_Hints Hints; + long Offset; + struct DirTree * Parent; + struct DirTree * Children; + struct DirTree * Siblings; +} DirTree; + +typedef struct DirTree_Finder +{ + char * MatchName; + char * MatchExt; + DirTree * Current; +} DirTree_Finder; + +DirTree *DirTree_Create(void) +{ + DirTree * Tree; + + Tree = geRam_Allocate(sizeof(*Tree)); + if (!Tree) + return Tree; + + memset(Tree, 0, sizeof(*Tree)); + Tree->Name = DuplicateString(""); + if (!Tree->Name) + { + geRam_Free(Tree); + return NULL; + } + + Tree->AttributeFlags |= GE_VFILE_ATTRIB_DIRECTORY; + + return Tree; +} + +void DirTree_Destroy(DirTree *Tree) +{ + assert(Tree); + assert(Tree->Name); + + if (Tree->Children) + DirTree_Destroy(Tree->Children); + + if (Tree->Siblings) + DirTree_Destroy(Tree->Siblings); + + geRam_Free(Tree->Name); + geRam_Free(Tree); +} + +static geBoolean WriteTree(const DirTree *Tree, geVFile *File) +{ + int Length; + int Terminator; + + assert(Tree); + assert(Tree->Name); + + Terminator = DIRTREE_LIST_NOTTERMINATED; + if (geVFile_Write(File, &Terminator, sizeof(Terminator)) == GE_FALSE) + return GE_FALSE; + + // Write out the name + Length = strlen(Tree->Name) + 1; + if (geVFile_Write(File, &Length, sizeof(Length)) == GE_FALSE) + return GE_FALSE; + if (Length > 0) + { + if (geVFile_Write(File, Tree->Name, Length) == GE_FALSE) + return GE_FALSE; + } + + // Write out the attribute information + if (geVFile_Write(File, &Tree->Time, sizeof(Tree->Time)) == GE_FALSE) + return GE_FALSE; + + if (geVFile_Write(File, &Tree->AttributeFlags, sizeof(Tree->AttributeFlags)) == GE_FALSE) + return GE_FALSE; + + if (geVFile_Write(File, &Tree->Size, sizeof(Tree->Size)) == GE_FALSE) + return GE_FALSE; + + if (geVFile_Write(File, &Tree->Offset, sizeof(Tree->Offset)) == GE_FALSE) + return GE_FALSE; + + if (geVFile_Write(File, &Tree->Hints.HintDataLength, sizeof(Tree->Hints.HintDataLength)) == GE_FALSE) + return GE_FALSE; + + if (Tree->Hints.HintDataLength != 0) + //bug fix. someone got copy happy and forgot to remove the & from Tree->Hints.HintData + if (geVFile_Write(File, Tree->Hints.HintData, Tree->Hints.HintDataLength) == GE_FALSE) + return GE_FALSE; + + // Write out the Children + if (Tree->Children) + { + WriteTree(Tree->Children, File); + } + else + { + Terminator = DIRTREE_LIST_TERMINATED; + if (geVFile_Write(File, &Terminator, sizeof(Terminator)) == GE_FALSE) + return GE_FALSE; + } + + // Write out the Siblings + if (Tree->Siblings) + { + WriteTree(Tree->Siblings, File); + } + else + { + Terminator = DIRTREE_LIST_TERMINATED; + if (geVFile_Write(File, &Terminator, sizeof(Terminator)) == GE_FALSE) + return GE_FALSE; + } + + return GE_TRUE; +} + +static geBoolean DirTree_WriteToFile1(const DirTree *Tree, geVFile *File, long *Size) +{ + DirTree_Header Header; + long StartPosition; + long EndPosition; + + if (geVFile_Tell(File, &StartPosition) == GE_FALSE) + return GE_FALSE; + + Header.Signature = DIRTREE_FILE_SIGNATURE; + if (geVFile_Seek(File, sizeof(Header), GE_VFILE_SEEKCUR) == GE_FALSE) + return GE_FALSE; + + if (WriteTree(Tree, File) == GE_FALSE) + return GE_FALSE; + + geVFile_Tell(File, &EndPosition); + Header.Size = EndPosition - StartPosition; + geVFile_Seek(File, StartPosition, GE_VFILE_SEEKSET); + if (geVFile_Write(File, &Header, sizeof(Header)) == GE_FALSE) + return GE_FALSE; + + // Make sure that we end up at the end of the directory. + geVFile_Seek(File, EndPosition, GE_VFILE_SEEKSET); + + *Size = Header.Size; + + return GE_TRUE; +} + +void DirTree_SetFileSize(DirTree *Tree, long Size) +{ + assert(Tree); + Tree->Size = Size; +} + +void DirTree_GetFileSize(DirTree *Tree, long *Size) +{ + assert(Tree); + *Size = Tree->Size; +} + +geBoolean DirTree_WriteToFile(const DirTree *Tree, geVFile *File) +{ + geBoolean Res; + long Size; + + Res = DirTree_WriteToFile1(Tree, File, &Size); + if (Res == GE_FALSE) + return Res; + + return GE_TRUE; +} + +geBoolean DirTree_GetSize(const DirTree *Tree, long *Size) +{ + geVFile * FS; + geVFile_MemoryContext Context; + + /* + This function is implemented via a write to a memory file for + a few reasons. First, it makes it easier to maintain this code. We + don't have to track format information in Write, Read and Size functions, + just in Write and Read. Second, it gets us testing of the memory + file system for free. Third, it was cute. The last one doesn't count, + of course, but the other two are compelling. This API ends up being + inefficient, but the assumption is that it will be called rarely. + */ + + Context.Data = NULL; + Context.DataLength = 0; + + FS = geVFile_OpenNewSystem(NULL, + GE_VFILE_TYPE_MEMORY, + NULL, + &Context, + GE_VFILE_OPEN_CREATE); + if (!FS) + return GE_FALSE; + + if (DirTree_WriteToFile1(Tree, FS, Size) == GE_FALSE) + return GE_FALSE; + + if (geVFile_Size(FS, Size) == GE_FALSE) + return GE_FALSE; + + geVFile_Close(FS); + + return GE_TRUE; +} + +static geBoolean ReadTree(geVFile *File, DirTree **TreePtr) +{ + int Terminator; + int Length; + DirTree * Tree; + + if (geVFile_Read(File, &Terminator, sizeof(Terminator)) == GE_FALSE) + return GE_FALSE; + + if (Terminator == DIRTREE_LIST_TERMINATED) + { + *TreePtr = NULL; + return GE_TRUE; + } + + Tree = geRam_Allocate(sizeof(*Tree)); + if (!Tree) + return GE_FALSE; + memset(Tree, 0, sizeof(*Tree)); + + // Read the name + if (geVFile_Read(File, &Length, sizeof(Length)) == GE_FALSE) + goto fail; + + assert(Length > 0); + Tree->Name = geRam_Allocate(Length); + if (!Tree->Name) + { + geRam_Free(Tree); + return GE_FALSE; + } + + if (geVFile_Read(File, Tree->Name, Length) == GE_FALSE) + goto fail; + +//printf("Reading '%s'\n", Tree->Name); + + // Read out the attribute information + if (geVFile_Read(File, &Tree->Time, sizeof(Tree->Time)) == GE_FALSE) + goto fail; + + if (geVFile_Read(File, &Tree->AttributeFlags, sizeof(Tree->AttributeFlags)) == GE_FALSE) + goto fail; + + if (geVFile_Read(File, &Tree->Size, sizeof(Tree->Size)) == GE_FALSE) + goto fail; + + if (geVFile_Read(File, &Tree->Offset, sizeof(Tree->Offset)) == GE_FALSE) + goto fail; + + if (geVFile_Read(File, &Tree->Hints.HintDataLength, sizeof(Tree->Hints.HintDataLength)) == GE_FALSE) + goto fail; + + if (Tree->Hints.HintDataLength != 0) + { + Tree->Hints.HintData = geRam_Allocate(Tree->Hints.HintDataLength); + if (!Tree->Hints.HintData) + goto fail; + //bug fix. someone got copy happy and forgot to remove the & from Tree->Hints.HintData + if (geVFile_Read(File, Tree->Hints.HintData, Tree->Hints.HintDataLength) == GE_FALSE) + goto fail; + } + +//printf("Reading children of '%s'\n", Tree->Name); + // Read the children + if (ReadTree(File, &Tree->Children) == GE_FALSE) + goto fail; + +//printf("Reading siblings of '%s'\n", Tree->Name); + // Read the Siblings + if (ReadTree(File, &Tree->Siblings) == GE_FALSE) + goto fail; + +//DirTree_Dump(Tree); + + *TreePtr = Tree; + + return GE_TRUE; + +fail: + DirTree_Destroy(Tree); + return GE_FALSE; +} + +DirTree *DirTree_CreateFromFile(geVFile *File) +{ + DirTree * Res; + DirTree_Header Header; + long StartPosition; + long EndPosition; + + if (geVFile_Tell(File, &StartPosition) == GE_FALSE) + return GE_FALSE; + + if (geVFile_Read(File, &Header, sizeof(Header)) == GE_FALSE) + return NULL; + + if (Header.Signature != DIRTREE_FILE_SIGNATURE) + return GE_FALSE; + + if (ReadTree(File, &Res) == GE_FALSE) + return NULL; + + geVFile_Tell(File, &EndPosition); + if (Header.Size != EndPosition - StartPosition) + { + DirTree_Destroy(Res); + return NULL; + } + + return Res; +} + +DirTree *DirTree_FindExact(const DirTree *Tree, const char *Path) +{ + static char Buff[_MAX_PATH]; + DirTree * Siblings; + + assert(Tree); + assert(Path); + + if (*Path == '\\') + return NULL; + + if (*Path == '\0') + return (DirTree *)Tree; + + Path = GetNextDir(Path, Buff); + + Siblings = Tree->Children; + while (Siblings) + { + if (!stricmp(Siblings->Name, Buff)) + { + if (!*Path) + return Siblings; + return DirTree_FindExact(Siblings, Path); + } + Siblings = Siblings->Siblings; + } + + return NULL; +} + +DirTree *DirTree_FindPartial( + const DirTree * Tree, + const char * Path, + const char ** LeftOvers) +{ + static char Buff[_MAX_PATH]; + DirTree * Siblings; + + assert(Tree); + assert(Path); + + if (*Path == '\\') + return NULL; + + *LeftOvers = Path; + + if (*Path == '\0') + return (DirTree *)Tree; + + Path = GetNextDir(Path, Buff); + + Siblings = Tree->Children; + while (Siblings) + { + if (!stricmp(Siblings->Name, Buff)) + { + *LeftOvers = Path; + if (!*Path) + return Siblings; + return DirTree_FindPartial(Siblings, Path, LeftOvers); + } + Siblings = Siblings->Siblings; + } + + return (DirTree *)Tree; +} + +DirTree * DirTree_AddFile(DirTree *Tree, const char *Path, geBoolean IsDirectory) +{ + DirTree * NewEntry; + const char * LeftOvers; + + assert(Tree); + assert(Path); + assert(IsDirectory == GE_TRUE || IsDirectory == GE_FALSE); + + assert(strlen(Path) > 0); + + if (PathHasDir(Path)) + { + Tree = DirTree_FindPartial(Tree, Path, &LeftOvers); + if (!Tree) + return NULL; + + if (PathHasDir(LeftOvers)) + return NULL; + + Path = LeftOvers; + } + + NewEntry = geRam_Allocate(sizeof(*NewEntry)); + if (!NewEntry) + return NULL; + + memset(NewEntry, 0, sizeof(*NewEntry)); + NewEntry->Name = DuplicateString(Path); + if (!NewEntry->Name) + { + geRam_Free(NewEntry->Name); + geRam_Free(NewEntry); + return NULL; + } + + NewEntry->Siblings = Tree->Children; + Tree->Children = NewEntry; + + if (IsDirectory == GE_TRUE) + NewEntry->AttributeFlags |= GE_VFILE_ATTRIB_DIRECTORY; + + return NewEntry; +} + +geBoolean DirTree_Remove(DirTree *Tree, DirTree *SubTree) +{ + DirTree Siblings; + DirTree * pSiblings; + DirTree * Parent; + DirTree * ParanoiaCheck; + + assert(Tree); + assert(SubTree); + + Parent = SubTree->Parent; + assert(Parent); + + ParanoiaCheck = Parent; + while (ParanoiaCheck && ParanoiaCheck != Tree) + ParanoiaCheck = ParanoiaCheck->Parent; + if (!ParanoiaCheck) + return GE_FALSE; + + Siblings.Siblings = Parent->Children; + assert(Siblings.Siblings); + pSiblings = &Siblings; + while (pSiblings->Siblings) + { + if (pSiblings->Siblings == SubTree) + { + pSiblings->Siblings = SubTree->Siblings; + if (SubTree == Parent->Children) + Parent->Children = SubTree->Siblings; + SubTree->Siblings = NULL; + DirTree_Destroy(SubTree); + return GE_TRUE; + } + pSiblings = pSiblings->Siblings; + } + + assert(!"Shouldn't be a way to get here"); + return GE_FALSE; +} + +void DirTree_SetFileAttributes(DirTree *Tree, geVFile_Attributes Attributes) +{ + assert(Tree); + assert(Attributes); + + // Only support the read only flag + assert(!(Attributes & ~GE_VFILE_ATTRIB_READONLY)); + assert(!(Tree->AttributeFlags & GE_VFILE_ATTRIB_DIRECTORY)); + + Tree->AttributeFlags = (Tree->AttributeFlags & ~GE_VFILE_ATTRIB_READONLY) | Attributes; +} + +void DirTree_GetFileAttributes(DirTree *Tree, geVFile_Attributes *Attributes) +{ + assert(Tree); + assert(Attributes); + + *Attributes = Tree->AttributeFlags; +} + +void DirTree_SetFileOffset(DirTree *Leaf, long Offset) +{ + assert(Leaf); + assert(!(Leaf->AttributeFlags & GE_VFILE_ATTRIB_DIRECTORY)); + + Leaf->Offset = Offset; +} + +void DirTree_GetFileOffset(DirTree *Leaf, long *Offset) +{ + assert(Leaf); + assert(!(Leaf->AttributeFlags & GE_VFILE_ATTRIB_DIRECTORY)); + + *Offset = Leaf->Offset; +} + +void DirTree_SetFileTime(DirTree *Tree, const geVFile_Time *Time) +{ + assert(Tree); + + Tree->Time = *Time; +} + +void DirTree_GetFileTime(DirTree *Tree, geVFile_Time *Time) +{ + assert(Tree); + + *Time = Tree->Time; +} + +geBoolean DirTree_SetFileHints(DirTree *Tree, const geVFile_Hints *Hints) +{ + if (Tree->Hints.HintData) + geRam_Free(Tree->Hints.HintData); + + if (Hints->HintData) + { + Tree->Hints.HintData = geRam_Allocate(Hints->HintDataLength); + if (!Tree->Hints.HintData) + return GE_FALSE; + memcpy(Tree->Hints.HintData, Hints->HintData, Hints->HintDataLength); + } + Tree->Hints.HintDataLength = Hints->HintDataLength; + return GE_TRUE; +} + +void DirTree_GetFileHints(DirTree *Tree, geVFile_Hints *Hints) +{ + *Hints = Tree->Hints; +} + +geBoolean DirTree_GetName(DirTree *Tree, char *Buff, int MaxLen) +{ + int Length; + + assert(Tree); + assert(Buff); + assert(MaxLen > 0); + + Length = strlen(Tree->Name); + if (Length > MaxLen) + return GE_FALSE; + + memcpy(Buff, Tree->Name, Length + 1); + + return GE_TRUE; +} + +geBoolean DirTree_FileExists(const DirTree *Tree, const char *Path) +{ + if (DirTree_FindExact(Tree, Path) == NULL) + return GE_FALSE; + + return GE_TRUE; +} + +DirTree_Finder * DirTree_CreateFinder(DirTree *Tree, const char *Path) +{ + DirTree_Finder * Finder; + DirTree * SubTree; + char Directory[_MAX_PATH]; + char Name[_MAX_FNAME]; + char Ext[_MAX_EXT]; + + assert(Tree); + assert(Path); + + _splitpath(Path, NULL, Directory, Name, Ext); + + SubTree = DirTree_FindExact(Tree, Directory); + if (!SubTree) + return NULL; + + Finder = geRam_Allocate(sizeof(*Finder)); + if (!Finder) + return Finder; + + Finder->MatchName = DuplicateString(Name); + if (!Finder->MatchName) + { + geRam_Free(Finder); + return NULL; + } + + // The RTL leaves the '.' on there. That won't do. + if (*Ext == '.') + Finder->MatchExt = DuplicateString(&Ext[1]); + else + Finder->MatchExt = DuplicateString(&Ext[0]); + + if (!Finder->MatchExt) + { + geRam_Free(Finder->MatchName); + geRam_Free(Finder); + return NULL; + } + + Finder->Current = SubTree->Children; + + return Finder; +} + +void DirTree_DestroyFinder(DirTree_Finder *Finder) +{ + assert(Finder); + assert(Finder->MatchName); + assert(Finder->MatchExt); + + geRam_Free(Finder->MatchName); + geRam_Free(Finder->MatchExt); + geRam_Free(Finder); +} + +DirTree * DirTree_FinderGetNextFile(DirTree_Finder *Finder) +{ + DirTree * Res; + char Name[_MAX_FNAME]; + char Ext[_MAX_EXT]; + + assert(Finder); + + Res = Finder->Current; + + if (!Res) + return Res; + + do + { + _splitpath(Res->Name, NULL, NULL, Name, Ext); + if (MatchPattern(Name, Finder->MatchName) == GE_TRUE && + MatchPattern(Ext, Finder->MatchExt) == GE_TRUE) + { + break; + } + + Res = Res->Siblings; + + } while (Res); + + if (Res) + Finder->Current = Res->Siblings; + + return Res; +} + +#ifdef DEBUG + +static void DirTree_Dump1(const DirTree *Tree, int i) +{ + DirTree * Temp; + + indent(i); + if (Tree->AttributeFlags & GE_VFILE_ATTRIB_DIRECTORY) + printf("\\%s\n", Tree->Name); + else + printf("%-*s %08x %08x\n", 40 - i, Tree->Name, Tree->Offset, Tree->Size); + Temp = Tree->Children; + while (Temp) + { + DirTree_Dump1(Temp, i + 2); + Temp = Temp->Siblings; + } +} + +void DirTree_Dump(const DirTree *Tree) +{ + printf("%-*s %-8s %-8s\n", 40, "Name", "Offset", "Size"); + printf("------------------------------------------------------------\n"); + DirTree_Dump1(Tree, 0); +} + +#endif diff --git a/G3D/VFile/dirtree.h b/G3D/VFile/dirtree.h new file mode 100644 index 0000000..2610be5 --- /dev/null +++ b/G3D/VFile/dirtree.h @@ -0,0 +1,90 @@ +/****************************************************************************************/ +/* DIRTREE.H */ +/* */ +/* Author: Eli Boling */ +/* Description: Directory tree interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DIRTREE_H +#define DIRTREE_H + +#include "vfile.h" + +typedef struct DirTree DirTree; +typedef struct DirTree_Finder DirTree_Finder; + +DirTree *DirTree_Create(void); + +DirTree *DirTree_CreateFromFile(geVFile *File); + +geBoolean DirTree_WriteToFile(const DirTree *Tree, geVFile *File); + +geBoolean DirTree_GetSize(const DirTree *Tree, long *Size); + // Gets the size of data that will be written to disk to persist + // the tree. This API is NOT efficient. + +void DirTree_Destroy(DirTree *Tree); + + +DirTree *DirTree_FindExact(const DirTree *Tree, const char *Path); +DirTree *DirTree_FindPartial( + const DirTree * Tree, + const char * Path, + const char ** LeftOvers); + +DirTree * DirTree_AddFile(DirTree *Tree, const char *Path, geBoolean IsDirectory); + +geBoolean DirTree_Remove(DirTree *Tree, DirTree *SubTree); + +void DirTree_SetFileAttributes(DirTree *Tree, geVFile_Attributes Attributes); + +void DirTree_GetFileAttributes(DirTree *Tree, geVFile_Attributes *Attributes); + +void DirTree_SetFileOffset(DirTree *Tree, long Offset); + +void DirTree_GetFileOffset(DirTree *Tree, long *Offset); + +void DirTree_SetFileTime(DirTree *Tree, const geVFile_Time *Time); + +void DirTree_GetFileTime(DirTree *Tree, geVFile_Time *Time); + +void DirTree_SetFileSize(DirTree *Tree, long Size); + +void DirTree_GetFileSize(DirTree *Tree, long *Size); + +geBoolean DirTree_SetFileHints(DirTree *Tree, const geVFile_Hints *Hints); + +void DirTree_GetFileHints(DirTree *Tree, geVFile_Hints *Hints); + +geBoolean DirTree_GetName(DirTree *Tree, char *Buff, int MaxLen); + +geBoolean DirTree_FileExists(const DirTree *Tree, const char *Path); + + +DirTree_Finder * DirTree_CreateFinder(DirTree *Tree, const char *Path); + +void DirTree_DestroyFinder(DirTree_Finder *Finder); + +DirTree * DirTree_FinderGetNextFile(DirTree_Finder *Finder); + + +#ifdef DEBUG +void DirTree_Dump(const DirTree *Tree); +#endif + +#endif + diff --git a/G3D/VFile/fsdos.c b/G3D/VFile/fsdos.c new file mode 100644 index 0000000..6157e8a --- /dev/null +++ b/G3D/VFile/fsdos.c @@ -0,0 +1,922 @@ +/****************************************************************************************/ +/* FSDOS.C */ +/* */ +/* Author: Eli Boling */ +/* Description: DOS file system implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include +#include + +#include "basetype.h" +#include "ram.h" + +#include "vfile.h" +#include "vfile._h" + +#include "fsdos.h" + +// "DF01" +#define DOSFILE_SIGNATURE 0x31304644 + +// "DF02" +#define DOSFINDER_SIGNATURE 0x32304644 + +#define CHECK_HANDLE(H) assert(H);assert(H->Signature == DOSFILE_SIGNATURE); +#define CHECK_FINDER(F) assert(F);assert(F->Signature == DOSFINDER_SIGNATURE); + +typedef struct DosFile +{ + unsigned int Signature; + HANDLE FileHandle; + char * FullPath; + const char * Name; + geBoolean IsDirectory; +} DosFile; + +typedef struct DosFinder +{ + unsigned int Signature; + HANDLE FindHandle; + WIN32_FIND_DATA FindData; + geBoolean FirstStillCached; + int OffsetToName; +} DosFinder; + +static geBoolean BuildFileName( + const DosFile * File, + const char * Name, + char * Buff, + char ** NamePtr, + int MaxLen) +{ + int DirLength; + int NameLength; + + if ( ! Name ) + return GE_FALSE; + + if (File) + { + if (File->IsDirectory == GE_FALSE) + return GE_FALSE; + + assert(File->FullPath); + DirLength = strlen(File->FullPath); + + if (DirLength > MaxLen) + return GE_FALSE; + + memcpy(Buff, File->FullPath, DirLength); + } + else + { + DirLength = 0; + } + + NameLength = strlen(Name); + if (DirLength + NameLength + 2 > MaxLen || ! Buff ) + return GE_FALSE; + + if (DirLength != 0) + { + Buff[DirLength] = '\\'; + memcpy(Buff + DirLength + 1, Name, NameLength + 1); + if (NamePtr) + *NamePtr = Buff + DirLength + 1; + } + else + { + memcpy(Buff, Name, NameLength + 1); + if (NamePtr) + *NamePtr = Buff; + + // Special case: no directory, no file name. We meant something like ".\" + if (!*Buff) + { + strcpy (Buff, ".\\"); + } + } + + return GE_TRUE; +} + +static void * GENESISCC FSDos_FinderCreate( + geVFile * FS, + void * Handle, + const char * FileSpec) +{ + DosFinder * Finder; + DosFile * File; + char * NamePtr; + char Buff[_MAX_PATH]; + + assert(FileSpec != NULL); + + File = Handle; + + CHECK_HANDLE(File); + + Finder = geRam_Allocate(sizeof(*Finder)); + if (!Finder) + return NULL; + + memset(Finder, 0, sizeof(*Finder)); + + if (BuildFileName(File, FileSpec, Buff, &NamePtr, sizeof(Buff)) == GE_FALSE) + { + geRam_Free(Finder); + return NULL; + } + + Finder->OffsetToName = NamePtr - Buff; + + Finder->FindHandle = FindFirstFile(Buff, &Finder->FindData); + + Finder->FirstStillCached = GE_TRUE; + + Finder->Signature = DOSFINDER_SIGNATURE; + return (void *)Finder; +} + +static geBoolean GENESISCC FSDos_FinderGetNextFile(void *Handle) +{ + DosFinder * Finder; + + Finder = Handle; + + CHECK_FINDER(Finder); + + if (Finder->FindHandle == INVALID_HANDLE_VALUE) + return GE_FALSE; + + if (Finder->FirstStillCached == GE_TRUE) + { + Finder->FirstStillCached = GE_FALSE; + + if (Finder->FindData.cFileName[0] != '.') + return GE_TRUE; + } + + while (FindNextFile(Finder->FindHandle, &Finder->FindData) == TRUE) + { + if (Finder->FindData.cFileName[0] != '.') + return GE_TRUE; + } + + return GE_FALSE; +} + +static geBoolean GENESISCC FSDos_FinderGetProperties(void *Handle, geVFile_Properties *Props) +{ + DosFinder * Finder; + geVFile_Attributes Attribs; + int Length; + + assert(Props); + + Finder = Handle; + + CHECK_FINDER(Finder); + + if (Finder->FindHandle == INVALID_HANDLE_VALUE) + return GE_FALSE; + + Attribs = 0; + if (Finder->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + Attribs |= GE_VFILE_ATTRIB_DIRECTORY; + if (Finder->FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + Attribs |= GE_VFILE_ATTRIB_READONLY; + + Props->Time.Time1 = Finder->FindData.ftLastWriteTime.dwLowDateTime; + Props->Time.Time2 = Finder->FindData.ftLastWriteTime.dwHighDateTime; + + Props->AttributeFlags = Attribs; + Props->Size = Finder->FindData.nFileSizeLow; + Props->Hints.HintData = NULL; + Props->Hints.HintDataLength = 0; + + Length = strlen(Finder->FindData.cFileName); + if (Length > sizeof(Props->Name) - 1) + return GE_FALSE; + memcpy(Props->Name, Finder->FindData.cFileName, Length + 1); + + return GE_TRUE; +} + +static void GENESISCC FSDos_FinderDestroy(void *Handle) +{ + DosFinder * Finder; + + Finder = Handle; + + CHECK_FINDER(Finder); + + if (Finder->FindHandle != INVALID_HANDLE_VALUE) + FindClose(Finder->FindHandle); + + Finder->Signature = 0; + geRam_Free(Finder); +} + +// Terrible function. It mutated, and now it modifies its argument. +static geBoolean IsRootDirectory(char *Path) +{ + int SlashCount; + + // Drive letter test + if (Path[1] == ':' && Path[2] == '\\' && Path[3] == '\0') + { + Path[2] = '\0'; + return GE_TRUE; + } + + // Now UNC path test + SlashCount = 0; + if (Path[0] == '\\' && Path[1] == '\\') + { + Path += 2; + while (*Path) + { + if (*Path++ == '\\') + SlashCount++; + } + } + + if (SlashCount == 1) + return GE_TRUE; + + return GE_FALSE; +} + +static void * GENESISCC FSDos_Open( + geVFile * FS, + void * Handle, + const char * Name, + void * Context, + unsigned int OpenModeFlags) +{ + DosFile * DosFS; + DosFile * NewFile; + char Buff[_MAX_PATH]; + int Length; + char * NamePtr; + + DosFS = Handle; + + if (DosFS && DosFS->IsDirectory != GE_TRUE) + return NULL; + + NewFile = geRam_Allocate(sizeof(*NewFile)); + if (!NewFile) + return NewFile; + + memset(NewFile, 0, sizeof(*NewFile)); + + if (BuildFileName(DosFS, Name, Buff, &NamePtr, sizeof(Buff)) == GE_FALSE) + goto fail; + + Length = strlen(Buff); + NewFile->FullPath = geRam_Allocate(Length + 1); + if (!NewFile->FullPath) + goto fail; + + NewFile->Name = NewFile->FullPath + (NamePtr - &Buff[0]); + + memcpy(NewFile->FullPath, Buff, Length + 1); + + if (OpenModeFlags & GE_VFILE_OPEN_DIRECTORY) + { + WIN32_FIND_DATA FileInfo; + HANDLE FindHandle; + geBoolean IsDirectory; + + assert(!DosFS || DosFS->IsDirectory == GE_TRUE); + + memset(&FileInfo, 0, sizeof(FileInfo)); + FindHandle = FindFirstFile(NewFile->FullPath, &FileInfo); + if (FindHandle != INVALID_HANDLE_VALUE && + FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + IsDirectory = GE_TRUE; + } + else + { + IsDirectory = IsRootDirectory(NewFile->FullPath); + } + + FindClose (FindHandle); + + if (OpenModeFlags & GE_VFILE_OPEN_CREATE) + { + if (IsDirectory == GE_TRUE) + goto fail; + + if (CreateDirectory(NewFile->FullPath, NULL) == FALSE) + goto fail; + } + else + { + if (IsDirectory != GE_TRUE) + goto fail; + } + + NewFile->IsDirectory = GE_TRUE; + NewFile->FileHandle = INVALID_HANDLE_VALUE; + } + else + { + DWORD ShareMode=0; + DWORD CreationMode; + DWORD Access=0; + DWORD LastError; + + CreationMode = OPEN_EXISTING; + + switch (OpenModeFlags & (GE_VFILE_OPEN_READONLY | + GE_VFILE_OPEN_UPDATE | + GE_VFILE_OPEN_CREATE)) + { + case GE_VFILE_OPEN_READONLY: + Access = GENERIC_READ; + ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + break; + + case GE_VFILE_OPEN_CREATE: + CreationMode = CREATE_ALWAYS; + // Fall through + + case GE_VFILE_OPEN_UPDATE: + Access = GENERIC_READ | GENERIC_WRITE; + ShareMode = FILE_SHARE_READ; + break; + + default: + assert(!"Illegal open mode flags"); + break; + } + + NewFile->FileHandle = CreateFile(NewFile->FullPath, + Access, + ShareMode, + NULL, + CreationMode, + 0, + NULL); + if (NewFile->FileHandle == INVALID_HANDLE_VALUE) + { + LastError = GetLastError(); + goto fail; + } + } + + NewFile->Signature = DOSFILE_SIGNATURE; + + return (void *)NewFile; + +fail: + if (NewFile->FullPath) + geRam_Free(NewFile->FullPath); + geRam_Free(NewFile); + return NULL; +} + +static void * GENESISCC FSDos_OpenNewSystem( + geVFile * FS, + const char * Name, + void * Context, + unsigned int OpenModeFlags) +{ + return FSDos_Open(FS, NULL, Name, Context, OpenModeFlags); +} + +static geBoolean GENESISCC FSDos_UpdateContext( + geVFile * FS, + void * Handle, + void * Context, + int ContextSize) +{ + return GE_FALSE; +} + +static void GENESISCC FSDos_Close(void *Handle) +{ + DosFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->IsDirectory == GE_FALSE) + { + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + CloseHandle(File->FileHandle); + } + + assert(File->FullPath); + File->Signature = 0; + geRam_Free(File->FullPath); + geRam_Free(File); +} + +static geBoolean GENESISCC FSDos_GetS(void *Handle, void *Buff, int MaxLen) +{ + DosFile * File; + DWORD BytesRead; + BOOL Result; + char * p; + char * End; + + assert(Buff); + assert(MaxLen != 0); + + File = Handle; + + CHECK_HANDLE(File); + + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + if (File->IsDirectory == GE_TRUE) + return GE_FALSE; + + Result = ReadFile(File->FileHandle, Buff, MaxLen - 1, &BytesRead, NULL); + if (BytesRead == 0) + { +#if 0 + if (Result == FALSE) + return GE_FALSE; + + // The Win32 API is vague about this, so we're being weird with the asserts + assert(Result != TRUE); +#endif + return GE_FALSE; + } + + End = (char *)Buff + BytesRead; + p = Buff; + while (p < End) + { + /* + This code will terminate a line on one of three conditions: + \r Character changed to \n, next char set to 0 + \n Next char set to 0 + \r\n First \r changed to \n. \n changed to 0. + */ + if (*p == '\r') + { + int Skip = 0; + + *p = '\n'; // set end of line + p++; // and skip to next char + // If the next char is a newline, then skip it too (\r\n case) + if (*p == '\n') + { + Skip = 1; + } + *p = '\0'; + // Set the file pointer back a bit since we probably overran + SetFilePointer(File->FileHandle, -(int)(BytesRead - ((p + Skip) - (char *)Buff)), NULL, FILE_CURRENT); + assert(p - (char *)Buff <= MaxLen); + return GE_TRUE; + } + else if (*p == '\n') + { + // Set the file pointer back a bit since we probably overran + p++; + SetFilePointer(File->FileHandle, -(int)(BytesRead - (p - (char *)Buff)), NULL, FILE_CURRENT); + *p = '\0'; + assert(p - (char *)Buff <= MaxLen); + return GE_TRUE; + } + p++; + } + + return GE_FALSE; +} + + +static geBoolean GENESISCC FSDos_Read(void *Handle, void *Buff, int Count) +{ + DosFile * File; + DWORD BytesRead; + + assert(Buff); + assert(Count != 0); + + File = Handle; + + CHECK_HANDLE(File); + + if (File->IsDirectory == GE_TRUE) + return GE_FALSE; + +#ifdef ELIDEBUG +{ + FILE * fp; + long Position; + + Position = SetFilePointer(File->FileHandle, 0, NULL, FILE_CURRENT); + fp = fopen("c:\\vfs.eli", "ab+"); + fprintf(fp, "FSDos_Read: %-8d bytes @ %-8d\r\n", Count, Position); + fclose(fp); +} +#endif + + if (ReadFile(File->FileHandle, Buff, Count, &BytesRead, NULL) == FALSE) + return GE_FALSE; + + if (BytesRead == 0) + return GE_FALSE; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSDos_Write(void *Handle, const void *Buff, int Count) +{ + DosFile * File; + DWORD BytesWritten; + + assert(Buff); + assert(Count != 0); + + File = Handle; + + CHECK_HANDLE(File); + + if (File->IsDirectory == GE_TRUE) + return GE_FALSE; + +#ifdef ELIDEBUG +{ + FILE * fp; + long Position; + + Position = SetFilePointer(File->FileHandle, 0, NULL, FILE_CURRENT); + fp = fopen("c:\\vfs.eli", "ab+"); + fprintf(fp, "FSDos_Write: %-8d bytes @ %-8d\r\n", Count, Position); + fclose(fp); +} +#endif + + if (WriteFile(File->FileHandle, Buff, Count, &BytesWritten, NULL) == FALSE) + return GE_FALSE; + + if ((int)BytesWritten != Count) + return GE_FALSE; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSDos_Seek(void *Handle, int Where, geVFile_Whence Whence) +{ + int RTLWhence=0; + DosFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->IsDirectory == GE_TRUE) + return GE_FALSE; + + switch (Whence) + { + case GE_VFILE_SEEKCUR: + RTLWhence = FILE_CURRENT; + break; + + case GE_VFILE_SEEKEND: + RTLWhence = FILE_END; + break; + + case GE_VFILE_SEEKSET: + RTLWhence = FILE_BEGIN; + break; + default: + assert(!"Unknown seek kind"); + } + + if (SetFilePointer(File->FileHandle, Where, NULL, RTLWhence) == 0xffffffff) + return GE_FALSE; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSDos_EOF(const void *Handle) +{ + const DosFile * File; + DWORD CurPos; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->IsDirectory == GE_TRUE) + return GE_FALSE; + + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + CurPos = SetFilePointer(File->FileHandle, 0, NULL, FILE_CURRENT); + assert(CurPos != 0xffffffff); + + if (CurPos == GetFileSize(File->FileHandle, NULL)) + return GE_TRUE; + + return GE_FALSE; +} + +static geBoolean GENESISCC FSDos_Tell(const void *Handle, long *Position) +{ + const DosFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->IsDirectory == GE_TRUE) + return GE_FALSE; + + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + *Position = SetFilePointer(File->FileHandle, 0, NULL, FILE_CURRENT); + if (*Position == -1L) + return GE_FALSE; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSDos_Size(const void *Handle, long *Size) +{ + const DosFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->IsDirectory == GE_TRUE) + return GE_FALSE; + + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + *Size = GetFileSize(File->FileHandle, NULL); + if (*Size != (long)0xffffffff) + return GE_TRUE; + + return GE_FALSE; +} + +static geBoolean GENESISCC FSDos_GetProperties(const void *Handle, geVFile_Properties *Properties) +{ + const DosFile * File; + geVFile_Attributes Attribs; + BY_HANDLE_FILE_INFORMATION Info; + int Length; + + assert(Properties); + + File = Handle; + + CHECK_HANDLE(File); + + if (File->IsDirectory == GE_TRUE) + { + memset(Properties, 0, sizeof(*Properties)); + Properties->AttributeFlags = FILE_ATTRIBUTE_DIRECTORY; +#pragma message ("FSDos_GetProperties: Time support is not there for directories") + } + else + { + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + if (GetFileInformationByHandle(File->FileHandle, &Info) == FALSE) + return GE_FALSE; + + Attribs = 0; + if (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + Attribs |= GE_VFILE_ATTRIB_DIRECTORY; + if (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + Attribs |= GE_VFILE_ATTRIB_READONLY; + + Properties->Time.Time1 = Info.ftLastWriteTime.dwLowDateTime; + Properties->Time.Time2 = Info.ftLastWriteTime.dwHighDateTime; + + Properties->AttributeFlags = Attribs; + Properties->Size = Info.nFileSizeLow; + Properties->Hints.HintData = NULL; + Properties->Hints.HintDataLength = 0; + } + + Length = strlen(File->Name) + 1; + if (Length > sizeof(Properties->Name)) + return GE_FALSE; + memcpy(Properties->Name, File->Name, Length); + + return GE_TRUE; +} + +static geBoolean GENESISCC FSDos_SetSize(void *Handle, long size) +{ + DosFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->IsDirectory == GE_FALSE) + { + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + if (SetFilePointer(File->FileHandle, 0, NULL, FILE_END) == 0xffffffff) + return GE_FALSE; + + if (SetEndOfFile(File->FileHandle) == FALSE) + return GE_FALSE; + } + + return GE_FALSE; +} + +static geBoolean GENESISCC FSDos_SetAttributes(void *Handle, geVFile_Attributes Attributes) +{ + DosFile * File; + DWORD Win32Attributes; + + File = Handle; + + CHECK_HANDLE(File); + + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + if (File->IsDirectory == GE_TRUE) + return GE_FALSE; + + if (Attributes & GE_VFILE_ATTRIB_READONLY) + Win32Attributes = FILE_ATTRIBUTE_READONLY; + else + Win32Attributes = FILE_ATTRIBUTE_NORMAL; + + if (SetFileAttributes(File->FullPath, Win32Attributes) == FALSE) + return GE_FALSE; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSDos_SetTime(void *Handle, const geVFile_Time *Time) +{ + DosFile * File; + FILETIME Win32Time; + + File = Handle; + + CHECK_HANDLE(File); + + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + Win32Time.dwLowDateTime = Time->Time1; + Win32Time.dwHighDateTime = Time->Time2; + if (SetFileTime(File->FileHandle, &Win32Time, &Win32Time, &Win32Time) == FALSE) + return GE_FALSE; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSDos_SetHints(void *Handle, const geVFile_Hints *Hints) +{ + DosFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + assert(File->FileHandle != INVALID_HANDLE_VALUE); + + return GE_FALSE; +} + +static geBoolean GENESISCC FSDos_FileExists(geVFile *FS, void *Handle, const char *Name) +{ + DosFile * File; + char Buff[_MAX_PATH]; + + File = Handle; + + if (File && File->IsDirectory == GE_FALSE) + return GE_FALSE; + + if (BuildFileName(File, Name, Buff, NULL, sizeof(Buff)) == GE_FALSE) + return GE_FALSE; + + if (GetFileAttributes(Buff) == 0xffffffff) + return GE_FALSE; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSDos_Disperse( + geVFile * FS, + void * Handle, + const char *Directory, + geBoolean Recursive) +{ + return GE_FALSE; +} + +static geBoolean GENESISCC FSDos_DeleteFile(geVFile *FS, void *Handle, const char *Name) +{ + DosFile * File; + char Buff[_MAX_PATH]; + + File = Handle; + + if (File && File->IsDirectory == GE_FALSE) + return GE_FALSE; + + if (BuildFileName(File, Name, Buff, NULL, sizeof(Buff)) == GE_FALSE) + return GE_FALSE; + + if (DeleteFile(Buff) == FALSE) + return GE_FALSE; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSDos_RenameFile(geVFile *FS, void *Handle, const char *Name, const char *NewName) +{ + DosFile * File; + char Old[_MAX_PATH]; + char New[_MAX_PATH]; + + File = Handle; + + if (File && File->IsDirectory == GE_FALSE) + return GE_FALSE; + + if (BuildFileName(File, Name, Old, NULL, sizeof(Old)) == GE_FALSE) + return GE_FALSE; + + if (BuildFileName(File, NewName, New, NULL, sizeof(New)) == GE_FALSE) + return GE_FALSE; + + if (MoveFile(Old, New) == FALSE) + return GE_FALSE; + + return GE_TRUE; +} + +static geVFile_SystemAPIs FSDos_APIs = +{ + FSDos_FinderCreate, + FSDos_FinderGetNextFile, + FSDos_FinderGetProperties, + FSDos_FinderDestroy, + + FSDos_OpenNewSystem, + FSDos_UpdateContext, + FSDos_Open, + FSDos_DeleteFile, + FSDos_RenameFile, + FSDos_FileExists, + FSDos_Disperse, + FSDos_Close, + + FSDos_GetS, + FSDos_Read, + FSDos_Write, + FSDos_Seek, + FSDos_EOF, + FSDos_Tell, + FSDos_Size, + + FSDos_GetProperties, + + FSDos_SetSize, + FSDos_SetAttributes, + FSDos_SetTime, + FSDos_SetHints, +}; + +const geVFile_SystemAPIs *GENESISCC FSDos_GetAPIs(void) +{ + return &FSDos_APIs; +} + diff --git a/G3D/VFile/fsdos.h b/G3D/VFile/fsdos.h new file mode 100644 index 0000000..6e719dd --- /dev/null +++ b/G3D/VFile/fsdos.h @@ -0,0 +1,28 @@ +/****************************************************************************************/ +/* FSDOS.H */ +/* */ +/* Author: Eli Boling */ +/* Description: DOS file system interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef FSDOS_H +#define FSDOS_H + +const geVFile_SystemAPIs *GENESISCC FSDos_GetAPIs(void); + +#endif + diff --git a/G3D/VFile/fsvfs.c b/G3D/VFile/fsvfs.c new file mode 100644 index 0000000..ed7a368 --- /dev/null +++ b/G3D/VFile/fsvfs.c @@ -0,0 +1,899 @@ +/****************************************************************************************/ +/* FSVFS.C */ +/* */ +/* Author: Eli Boling */ +/* Description: Collection file system implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include + +#include "ram.h" + +#include "fsvfs.h" +#include "dirtree.h" + +// "VF00" +#define VFSFILEHEADER_SIGNATURE 0x30304656 +// "CF00" +#define VCFSFILEHEADER_SIGNATURE 0x30304643 + +// "VF01" +#define VFSFILE_SIGNATURE 0x31304656 + +// "VF02" +#define VFSFINDER_SIGNATURE 0x32304656 + +#define HEADER_VERSION 0 + +typedef struct VFSFileHeader +{ + unsigned int Signature; + unsigned short Version; // Version number + geBoolean Dispersed; // Is this VFS dispersed? + long DirectoryOffset; // File offset to directory + long DataLength; // Length of all file data, including VFS header + long EndPosition; // End Position in the RWOps file we were written to +} VFSFileHeader; + +// In the above structure, EndPosition should be the same as DataLength. We use this for +// asserts. + +typedef struct VFSFile +{ + unsigned int Signature; + + geVFile * RWOps; // Parent file for read/write ops + struct VFSFile *System; // If we're a child, we need a back pointer + + DirTree * DirEntry; // Directory entry for this file + DirTree * Directory; // Directory information for the VFS + + long RWOpsStartPos; // Starting position in the RWOps file + long CurrentRelPos; // Current file pointer (relative to our start) + long Length; // Current file size + char Mask; + + unsigned int OpenModeFlags; + + // Things that are specific to the Root node + long EndPosition; // End position in the RWOps file if we're a system + geBoolean IsSystem; // Am I the owner of the Directory? + long DataLength; // Current size of the aggregate including VFS header + geBoolean Dispersed; // Is this VFS dispersed? + +} VFSFile; + +typedef struct VFSFinder +{ + unsigned int Signature; + VFSFile * File; + DirTree_Finder * Finder; + DirTree * LastFind; +} VFSFinder; + +#define CHECK_HANDLE(H) assert(H);assert(H->Signature == VFSFILE_SIGNATURE); +#define CHECK_FINDER(F) assert(F);assert(F->Signature == VFSFINDER_SIGNATURE); + +static void * GENESISCC FSVFS_FinderCreate( + geVFile * FS, + void * Handle, + const char * FileSpec) +{ + VFSFinder * Finder; + VFSFile * File; + + assert(FileSpec != NULL); + + File = Handle; + + CHECK_HANDLE(File); + + if (!File->Directory) + return NULL; + + Finder = geRam_Allocate(sizeof(*Finder)); + if (!Finder) + return NULL; + + memset(Finder, 0, sizeof(*Finder)); + + Finder->Signature = VFSFINDER_SIGNATURE; + Finder->File = File; + Finder->Finder = DirTree_CreateFinder(File->Directory, FileSpec); + if (!Finder->Finder) + { + geRam_Free(Finder); + return NULL; + } + + return (void *)Finder; +} + +static geBoolean GENESISCC FSVFS_FinderGetNextFile(void *Handle) +{ + VFSFinder * Finder; + + Finder = Handle; + + CHECK_FINDER(Finder); + + Finder->LastFind = DirTree_FinderGetNextFile(Finder->Finder); + if (Finder->LastFind) + return GE_TRUE; + + return GE_FALSE; +} + +static geBoolean GENESISCC FSVFS_FinderGetProperties(void *Handle, geVFile_Properties *Properties) +{ + VFSFinder * Finder; + + assert(Properties); + + Finder = Handle; + + CHECK_FINDER(Finder); + + if (!Finder->LastFind) + return GE_FALSE; + + DirTree_GetFileTime(Finder->LastFind, &Properties->Time); + DirTree_GetFileAttributes(Finder->LastFind, &Properties->AttributeFlags); + DirTree_GetFileSize(Finder->LastFind, &Properties->Size); + DirTree_GetFileHints(Finder->LastFind, &Properties->Hints); + return DirTree_GetName(Finder->LastFind, &Properties->Name[0], sizeof(Properties->Name)); +} + +static void GENESISCC FSVFS_FinderDestroy(void *Handle) +{ + VFSFinder * Finder; + + Finder = Handle; + + CHECK_FINDER(Finder); + + assert(Finder->Finder); + + Finder->Signature = 0; + DirTree_DestroyFinder(Finder->Finder); + geRam_Free(Finder); +} + +static void * GENESISCC FSVFS_Open( + geVFile * FS, + void * Handle, + const char * Name, + void * Dummy, + unsigned int OpenModeFlags) +{ + VFSFile * Context; + VFSFile * NewFile; + DirTree * FileEntry; + + Context = Handle; + + CHECK_HANDLE(Context); + + assert(Name); + + if (!Context->Directory) + return NULL; + + /* + Right now, we only support update operations to a VFS which is being + created. We can do create operations to a VFS which is being created, + or which already exists. We can also support directory open operations + at anytime. + */ + if ((OpenModeFlags & GE_VFILE_OPEN_UPDATE) && + !(OpenModeFlags & GE_VFILE_OPEN_DIRECTORY) && + !(OpenModeFlags & GE_VFILE_OPEN_CREATE) && + !(Context->System->OpenModeFlags & GE_VFILE_OPEN_CREATE)) + return NULL; + + FileEntry = DirTree_FindExact(Context->Directory, Name); + if (OpenModeFlags & GE_VFILE_OPEN_CREATE) + { + if (FileEntry) + return NULL; + + FileEntry = DirTree_AddFile(Context->Directory, + Name, + (OpenModeFlags & GE_VFILE_OPEN_DIRECTORY) ? GE_TRUE : GE_FALSE); + if (!FileEntry) + return NULL; + } + else + { + if (!FileEntry) + return NULL; + } + + NewFile = geRam_Allocate(sizeof(*NewFile)); + if (!NewFile) + return NewFile; + + memset(NewFile, 0, sizeof(*NewFile)); + + NewFile->Signature = VFSFILE_SIGNATURE; + NewFile->DirEntry = FileEntry; + NewFile->RWOps = Context->RWOps; + NewFile->Dispersed = GE_FALSE; + NewFile->System = Context->System; + NewFile->Mask = Context->Mask; + + // If we're a directory, make us a first class operator with the child + if (OpenModeFlags & GE_VFILE_OPEN_DIRECTORY) + { + NewFile->Directory = FileEntry; + } + else + { + if (OpenModeFlags & GE_VFILE_OPEN_CREATE) + { + NewFile->RWOpsStartPos = Context->System->DataLength + + Context->System->RWOpsStartPos; + } + else + { + DirTree_GetFileOffset(FileEntry, &NewFile->RWOpsStartPos); + } + } + + NewFile->OpenModeFlags = OpenModeFlags; + + if (!(OpenModeFlags & GE_VFILE_OPEN_DIRECTORY)) + { + if (OpenModeFlags & GE_VFILE_OPEN_CREATE) + { + DirTree_SetFileOffset(FileEntry, NewFile->RWOpsStartPos); + } + else + { + assert(!(OpenModeFlags & GE_VFILE_OPEN_UPDATE)); + DirTree_GetFileSize(FileEntry, &NewFile->Length); + } + } + + // Only a VFS opened with OpenNewSystem gets to be the owner + NewFile->IsSystem = GE_FALSE; + + return (void *)NewFile; +} + +static void * GENESISCC FSVFS_OpenNewSystem( + geVFile * RWOps, + const char * Name, + void * Context, + unsigned int OpenModeFlags) +{ + VFSFile * NewFS; + long RWOpsStartPos; + char *TStr; + char EString[256]; + char Mask; + + assert(RWOps != NULL); + assert(Name == NULL); + if(Context == NULL) + Mask = 0; + else + { + TStr = (char *)Context; + strncpy(EString, TStr, 8); + Mask = EString[0] & 0x01; + Mask |= EString[7] & 0x02; + Mask |= EString[1] & 0x04; + Mask |= EString[6] & 0x08; + Mask |= EString[2] & 0x10; + Mask |= EString[5] & 0x20; + Mask |= EString[3] & 0x40; + Mask |= EString[4] & 0x80; + + //Mask = (EString[0]<<2) & 0xc0; + //Mask |= EString[1] & 0x30; + //Mask |= EString[2] & 0x0c; + //Mask |= EString[3] & 0x03; + } + + // All VFS are directories + if (!(OpenModeFlags & GE_VFILE_OPEN_DIRECTORY)) + return NULL; + + if (geVFile_Tell(RWOps, &RWOpsStartPos) == GE_FALSE) + return NULL; + + if (!(OpenModeFlags & GE_VFILE_OPEN_CREATE)) + { + VFSFileHeader Header; + long DirectoryStartPos; + long DirectoryEndPos; + +//#pragma message ("FSVFS_OpenNewSystem: READ/WRITE opens not supported") + + if (geVFile_Read(RWOps, &Header, sizeof(Header)) == GE_FALSE) + return NULL; + + if (!((Header.Signature == VFSFILEHEADER_SIGNATURE) || (Header.Signature == VCFSFILEHEADER_SIGNATURE))) + return NULL; + + if (Header.Version != HEADER_VERSION) + return NULL; + + if (Header.Dispersed == GE_TRUE) + { + assert(!"Not implemented"); + return NULL; + } + + // Go to the directory + if (geVFile_Seek(RWOps, Header.DirectoryOffset, GE_VFILE_SEEKSET) == GE_FALSE) + return NULL; + + // Remember where we started reading the directory + if (geVFile_Tell(RWOps, &DirectoryStartPos) == GE_FALSE) + return NULL; + + NewFS = geRam_Allocate(sizeof(*NewFS)); + if (!NewFS) + return NewFS; + memset(NewFS, 0, sizeof(*NewFS)); + + NewFS->RWOps = RWOps; + NewFS->RWOpsStartPos = RWOpsStartPos; + NewFS->DataLength = Header.DataLength; + NewFS->EndPosition = Header.EndPosition; + NewFS->Mask = Mask; + + // Read the directory + NewFS->Directory = DirTree_CreateFromFile(RWOps); + if (!NewFS->Directory) + { + geRam_Free(NewFS); + return NULL; + } + + // Get the end position for paranoia checking + if (geVFile_Tell(RWOps, &DirectoryEndPos) == GE_FALSE) + { + DirTree_Destroy(NewFS->Directory); + geRam_Free(NewFS); + return NULL; + } + } + else + { + NewFS = geRam_Allocate(sizeof(*NewFS)); + if (!NewFS) + return NewFS; + memset(NewFS, 0, sizeof(*NewFS)); + + NewFS->RWOps = RWOps; + NewFS->RWOpsStartPos = RWOpsStartPos; + NewFS->Directory = DirTree_Create(); + NewFS->DataLength = sizeof(VFSFileHeader); + NewFS->Mask = Mask; + } + + NewFS->Signature = VFSFILE_SIGNATURE; + NewFS->IsSystem = GE_TRUE; + NewFS->System = NewFS; + NewFS->OpenModeFlags = OpenModeFlags; + + return NewFS; +} + +static geBoolean GENESISCC FSVFS_UpdateContext( + geVFile * FS, + void * Handle, + void * Context, + int ContextSize) +{ + return GE_FALSE; +} + +static void GENESISCC FSVFS_Close(void *Handle) +{ + VFSFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->Directory) + { + if (File->IsSystem == GE_TRUE) + { + // Hmmm. We're the top level + assert(File == File->System); + + if (File->OpenModeFlags & (GE_VFILE_OPEN_CREATE | GE_VFILE_OPEN_UPDATE)) + { + VFSFileHeader Header; + long EndPosition; + + // Have to update the directory + if (geVFile_Seek(File->RWOps, File->RWOpsStartPos + File->DataLength, GE_VFILE_SEEKSET) == GE_FALSE) + { + // What to do on failure? + assert(!"Can't fail"); + } + if (DirTree_WriteToFile(File->Directory, File->RWOps) == GE_FALSE) + { + // What to do on failure? + assert(!"Can't fail"); + } + geVFile_Tell(File->RWOps, &EndPosition); + if (geVFile_Seek(File->RWOps, File->RWOpsStartPos, GE_VFILE_SEEKSET) == GE_FALSE) + { + // What to do on failure? + assert(!"Can't fail"); + } + if(File->Mask==0) + Header.Signature = VFSFILEHEADER_SIGNATURE; + else + Header.Signature = VCFSFILEHEADER_SIGNATURE; + Header.Version = HEADER_VERSION; + Header.Dispersed = GE_FALSE; + Header.EndPosition = EndPosition; + + Header.DirectoryOffset = File->RWOpsStartPos + File->DataLength; + Header.DataLength = File->DataLength; + if (geVFile_Write(File->RWOps, &Header, sizeof(Header)) == GE_FALSE) + { + // What to do on failure? + assert(!"Can't fail"); + } + + // Make sure that we end up at the end of the RWOps file + geVFile_Seek(File->RWOps, EndPosition, GE_VFILE_SEEKSET); + } + else + { + // Have to make sure that we leave the file pointer at the end + // of our data in the RWOps file that we come from. + + geVFile_Seek(File->RWOps, File->EndPosition, GE_VFILE_SEEKSET); + } + + DirTree_Destroy(File->Directory); + } + } + else + { + // Update the system with the length of this file. Subsequent + // file operations will follow this file. + assert(File->System); + File->System->DataLength += File->Length; + DirTree_SetFileSize(File->DirEntry, File->Length); + } + + geRam_Free(File); +} + +static geBoolean GENESISCC ForceFilePos(VFSFile *File) +{ + assert(File); + assert(File->RWOps); + assert(!File->Directory); + + assert(File->CurrentRelPos >= 0); + assert(File->CurrentRelPos <= File->Length); + + return geVFile_Seek(File->RWOps, + File->RWOpsStartPos + File->CurrentRelPos, + GE_VFILE_SEEKSET); +} + +static int ClampOperationSize(const VFSFile *File, int Size) +{ + assert(!File->Directory); + assert(File->CurrentRelPos >= 0); + return min(File->Length - File->CurrentRelPos, Size); +} + +static void GENESISCC UpdateFilePos(VFSFile *File) +{ + long RWOpsPos; + + assert(!File->Directory); + assert(File->CurrentRelPos >= 0); + + geVFile_Tell(File->RWOps, &RWOpsPos); + + File->CurrentRelPos = RWOpsPos - File->RWOpsStartPos; + if (File->CurrentRelPos > File->Length) + File->Length = File->CurrentRelPos; + + assert(File->CurrentRelPos >= 0); +} + +static geBoolean GENESISCC FSVFS_GetS(void *Handle, void *Buff, int MaxLen) +{ + VFSFile * File; + geBoolean Res; + + assert(Buff); + assert(MaxLen != 0); + + File = Handle; + + CHECK_HANDLE(File); + + if (File->Directory) + return GE_FALSE; + + assert(File->CurrentRelPos >= 0); + assert(File->CurrentRelPos <= File->Length); + + if (!ForceFilePos(File)) + return GE_FALSE; + + MaxLen = ClampOperationSize(File, MaxLen); + + Res = geVFile_GetS(File->RWOps, Buff, MaxLen); + + UpdateFilePos(File); + + return Res; +} + +static geBoolean GENESISCC FSVFS_Read(void *Handle, void *Buff, int Count) +{ + VFSFile * File; + geBoolean Res; + int i; + char Bbyte; + char *TBuffer; + +#ifndef NDEBUG + int CurRelPos; +#endif + + assert(Buff); + assert(Count != 0); + + File = Handle; + + CHECK_HANDLE(File); + + if (File->Directory) + return GE_FALSE; + + assert(File->CurrentRelPos >= 0); + assert(File->CurrentRelPos <= File->Length); + + if (!ForceFilePos(File)) + return GE_FALSE; + + if (ClampOperationSize(File, Count) != Count) + return GE_FALSE; + +#ifndef NDEBUG + CurRelPos = File->CurrentRelPos; +#endif + Res = geVFile_Read(File->RWOps, Buff, Count); + TBuffer = Buff; + for(i=0;iMask; + memcpy((TBuffer+i),&Bbyte,1); + } + + UpdateFilePos(File); + assert(File->CurrentRelPos - CurRelPos == Count); + + return Res; +} + +static geBoolean GENESISCC FSVFS_Write(void *Handle, const void *Buff, int Count) +{ + VFSFile * File; + geBoolean Res; + int i; + char Bbyte; + char *TBuffer; + +#ifndef NDEBUG + int CurRelPos; +#endif + + assert(Buff); + assert(Count != 0); + + File = Handle; + + CHECK_HANDLE(File); + + if (File->Directory) + return GE_FALSE; + + if (File->OpenModeFlags & GE_VFILE_OPEN_READONLY) + return GE_FALSE; + + assert(File->CurrentRelPos >= 0); + assert(File->CurrentRelPos <= File->Length); + + if (!ForceFilePos(File)) + return GE_FALSE; + +#ifndef NDEBUG + CurRelPos = File->CurrentRelPos; +#endif + TBuffer = (char *)Buff; + for(i=0;iMask; + memcpy((TBuffer+i),&Bbyte,1); + } + Res = geVFile_Write(File->RWOps, Buff, Count); + + UpdateFilePos(File); + assert(File->CurrentRelPos - CurRelPos == Count); + + return Res; +} + +static geBoolean GENESISCC FSVFS_Seek(void *Handle, int Where, geVFile_Whence Whence) +{ + VFSFile * File; + geBoolean Res; + long AbsolutePos=0; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->Directory) + return GE_FALSE; + + assert(File->CurrentRelPos >= 0); + assert(File->CurrentRelPos <= File->Length); + + switch (Whence) + { + case GE_VFILE_SEEKSET: + AbsolutePos = File->RWOpsStartPos + Where; + break; + + case GE_VFILE_SEEKEND: + AbsolutePos = File->RWOpsStartPos + File->Length - Where; + break; + + case GE_VFILE_SEEKCUR: + AbsolutePos = File->RWOpsStartPos + File->CurrentRelPos + Where; + break; + + default: + assert(!"Illegal seek case"); + } + + if (AbsolutePos < File->RWOpsStartPos) + return GE_FALSE; + + Res = geVFile_Seek(File->RWOps, AbsolutePos, GE_VFILE_SEEKSET); + + UpdateFilePos(File); + + return Res; +} + +static geBoolean GENESISCC FSVFS_EOF(const void *Handle) +{ + const VFSFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->Directory) + return GE_FALSE; + + assert(File->CurrentRelPos >= 0); + assert(File->CurrentRelPos <= File->Length); + + if (File->CurrentRelPos == File->Length) + return GE_TRUE; + + return GE_FALSE; +} + +static geBoolean GENESISCC FSVFS_Tell(const void *Handle, long *Position) +{ + const VFSFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->Directory) + return GE_FALSE; + + assert(File->CurrentRelPos >= 0); + assert(File->CurrentRelPos <= File->Length); + + *Position = File->CurrentRelPos; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSVFS_Size(const void *Handle, long *Size) +{ + const VFSFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (File->Directory != NULL) + return GE_FALSE; + + assert(File->CurrentRelPos >= 0); + assert(File->CurrentRelPos <= File->Length); + + *Size = File->Length; + + return GE_TRUE; +} + +static geBoolean GENESISCC FSVFS_GetProperties(const void *Handle, geVFile_Properties *Properties) +{ + const VFSFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + assert(File->DirEntry); + + DirTree_GetFileTime(File->DirEntry, &Properties->Time); + DirTree_GetFileAttributes(File->DirEntry, &Properties->AttributeFlags); + DirTree_GetFileSize(File->DirEntry, &Properties->Size); + DirTree_GetFileHints(File->DirEntry, &Properties->Hints); + return DirTree_GetName(File->DirEntry, &Properties->Name[0], sizeof(Properties->Name)); +} + +static geBoolean GENESISCC FSVFS_SetSize(void *Handle, long Size) +{ + assert(!"Not implemented"); + return GE_FALSE; +} + +static geBoolean GENESISCC FSVFS_SetAttributes(void *Handle, geVFile_Attributes Attributes) +{ + const VFSFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + assert(File->DirEntry); + + if (Attributes & ~GE_VFILE_ATTRIB_READONLY) + return GE_FALSE; + + DirTree_SetFileAttributes(File->DirEntry, Attributes); + + return GE_TRUE; +} + +static geBoolean GENESISCC FSVFS_SetTime(void *Handle, const geVFile_Time *Time) +{ + const VFSFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + assert(File->DirEntry); + + DirTree_SetFileTime(File->DirEntry, Time); + + return GE_FALSE; +} + +static geBoolean GENESISCC FSVFS_SetHints(void *Handle, const geVFile_Hints *Hints) +{ + const VFSFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + assert(File->DirEntry); + + return DirTree_SetFileHints(File->DirEntry, Hints); +} + +static geBoolean GENESISCC FSVFS_FileExists(geVFile *FS, void *Handle, const char *Name) +{ + VFSFile * File; + + File = Handle; + + CHECK_HANDLE(File); + + if (!File->Directory) + return GE_FALSE; + + return DirTree_FileExists(File->Directory, Name); +} + +static geBoolean GENESISCC FSVFS_Disperse( + geVFile * FS, + void * Handle, + const char *Directory, + geBoolean Recursive) +{ +assert(!"Not implemented"); + return GE_FALSE; +} + +static geBoolean GENESISCC FSVFS_DeleteFile(geVFile *FS, void *Handle, const char *Name) +{ +assert(!"Not implemented"); + return GE_FALSE; +} + +static geBoolean GENESISCC FSVFS_RenameFile(geVFile *FS, void *Handle, const char *Name, const char *NewName) +{ +assert(!"Not implemented"); + return GE_FALSE; +} + +static geVFile_SystemAPIs FSVFS_APIs = +{ + FSVFS_FinderCreate, + FSVFS_FinderGetNextFile, + FSVFS_FinderGetProperties, + FSVFS_FinderDestroy, + + FSVFS_OpenNewSystem, + FSVFS_UpdateContext, + FSVFS_Open, + FSVFS_DeleteFile, + FSVFS_RenameFile, + FSVFS_FileExists, + FSVFS_Disperse, + FSVFS_Close, + + FSVFS_GetS, + FSVFS_Read, + FSVFS_Write, + FSVFS_Seek, + FSVFS_EOF, + FSVFS_Tell, + FSVFS_Size, + + FSVFS_GetProperties, + + FSVFS_SetSize, + FSVFS_SetAttributes, + FSVFS_SetTime, + FSVFS_SetHints, +}; + +const geVFile_SystemAPIs * GENESISCC FSVFS_GetAPIs(void) +{ + return &FSVFS_APIs; +} + diff --git a/G3D/VFile/fsvfs.h b/G3D/VFile/fsvfs.h new file mode 100644 index 0000000..ed70d2f --- /dev/null +++ b/G3D/VFile/fsvfs.h @@ -0,0 +1,30 @@ +/****************************************************************************************/ +/* FSVFS.H */ +/* */ +/* Author: Eli Boling */ +/* Description: Collection file system interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef FSVFS_H +#define FSVFS_H + +#include "vfile._h" + +const geVFile_SystemAPIs * GENESISCC FSVFS_GetAPIs(void); + +#endif + diff --git a/G3D/VFile/vfile._h b/G3D/VFile/vfile._h new file mode 100644 index 0000000..04f1771 --- /dev/null +++ b/G3D/VFile/vfile._h @@ -0,0 +1,103 @@ +/****************************************************************************************/ +/* VFILE._H */ +/* */ +/* Author: Eli Boling */ +/* Description: Systems internal interfaces for vfiles */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef VFILE__H +#define VFILE__H + +#include "basetype.h" +#include "vfile.h" + +typedef void * (GENESISCC *geVFile_FinderCreateFN)(geVFile *FileSystem, void *Handle, const char *FileSpec); +typedef geBoolean (GENESISCC *geVFile_FinderGetNextFileFN)(void *Handle); +typedef geBoolean (GENESISCC *geVFile_FinderGetPropertiesFN)(void *Handle, geVFile_Properties *Properties); +typedef void (GENESISCC *geVFile_FinderDestroyFN)(void *Handle); + +typedef void * (GENESISCC *geVFile_OpenNewSystemFN)(geVFile *FS, + const char *Name, + void * Context, + unsigned int OpenModeFlags); + +typedef geBoolean (GENESISCC *geVFile_UpdateContextFN)(geVFile *FS, void *Handle, void *Context, int ContextSize); + +typedef void * (GENESISCC *geVFile_OpenFN)(geVFile *FS, + void *Handle, + const char *Name, + void * Context, + unsigned int OpenModeFlags); + +typedef geBoolean (GENESISCC *geVFile_DeleteFileFN)(geVFile *FS, void *Handle, const char *FileName); +typedef geBoolean (GENESISCC *geVFile_RenameFileFN)(geVFile *FS, void *Handle, const char *FileName, const char *NewFileName); +typedef geBoolean (GENESISCC *geVFile_FileExistsFN)(geVFile *FS, void *Handle, const char *FileName); +typedef geBoolean (GENESISCC *geVFile_DisperseFN)(geVFile *FS, void *Handle, const char *Directory, geBoolean Recursive); +typedef void (GENESISCC *geVFile_CloseFN)(void *Handle); + +typedef geBoolean (GENESISCC *geVFile_GetSFN)(void *Handle, void *Buff, int MaxSize); +typedef geBoolean (GENESISCC *geVFile_ReadFN)(void *Handle, void *Buff, int Count); +typedef geBoolean (GENESISCC *geVFile_WriteFN)(void *Handle, const void *Buff, int Count); +typedef geBoolean (GENESISCC *geVFile_SeekFN)(void *Handle, int Where, geVFile_Whence Whence); +typedef geBoolean (GENESISCC *geVFile_EOFFN)(const void *Handle); +typedef geBoolean (GENESISCC *geVFile_TellFN)(const void *Handle, long *Position); +typedef geBoolean (GENESISCC *geVFile_GetPropertiesFN)(const void *Handle, geVFile_Properties *Properties); + +typedef geBoolean (GENESISCC *geVFile_SizeFN)(const void *Handle, long *Size); +typedef geBoolean (GENESISCC *geVFile_SetSizeFN)(void *Handle, long Size); +typedef geBoolean (GENESISCC *geVFile_SetAttributesFN)(void *Handle, geVFile_Attributes Attributes); +typedef geBoolean (GENESISCC *geVFile_SetTimeFN)(void *Handle, const geVFile_Time *Time); +typedef geBoolean (GENESISCC *geVFile_SetHintsFN)(void *Handle, const geVFile_Hints *Hints); + +typedef struct geVFile_SystemAPIs +{ + geVFile_FinderCreateFN FinderCreate; + geVFile_FinderGetNextFileFN FinderGetNextFile; + geVFile_FinderGetPropertiesFN FinderGetProperties; + geVFile_FinderDestroyFN FinderDestroy; + + geVFile_OpenNewSystemFN OpenNewSystem; + geVFile_UpdateContextFN UpdateContext; + geVFile_OpenFN Open; + geVFile_DeleteFileFN DeleteFile; + geVFile_RenameFileFN RenameFile; + geVFile_FileExistsFN FileExists; + geVFile_DisperseFN Disperse; + geVFile_CloseFN Close; + + geVFile_GetSFN GetS; + geVFile_ReadFN Read; + geVFile_WriteFN Write; + geVFile_SeekFN Seek; + geVFile_EOFFN Eof; + geVFile_TellFN Tell; + geVFile_SizeFN Size; + + geVFile_GetPropertiesFN GetProperties; + + geVFile_SetSizeFN SetSize; + geVFile_SetAttributesFN SetAttributes; + geVFile_SetTimeFN SetTime; + geVFile_SetHintsFN SetHints; +} geVFile_SystemAPIs; + +geBoolean GENESISCC VFile_RegisterFileSystem( + const geVFile_SystemAPIs * APIs, + geVFile_TypeIdentifier * Type); + +#endif + diff --git a/G3D/VFile/vfile.c b/G3D/VFile/vfile.c new file mode 100644 index 0000000..78b685c --- /dev/null +++ b/G3D/VFile/vfile.c @@ -0,0 +1,618 @@ +/****************************************************************************************/ +/* VFILE.C */ +/* */ +/* Author: Eli Boling */ +/* Description: Virtual file implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include +#include + +#include "basetype.h" +#include "ram.h" + +#include "vfile.h" +#include "vfile._h" + +#include "fsdos.h" +#include "fsmemory.h" +#include "fsvfs.h" +// +// add include files for file types here + +typedef struct FSSearchList +{ + geVFile * FS; + struct FSSearchList * Next; +} FSSearchList; + + +typedef struct geVFile +{ + geVFile_TypeIdentifier SystemType; + const geVFile_SystemAPIs * APIs; + void * FSData; + geVFile * Context; + FSSearchList * SearchList; + CRITICAL_SECTION CriticalSection; + geVFile * BaseFile; +} geVFile; + +typedef struct geVFile_Finder +{ + const geVFile_SystemAPIs * APIs; + void * Data; +} geVFile_Finder; + +static geVFile_SystemAPIs ** RegisteredAPIs; +static int SystemCount; +static geBoolean BuiltInAPIsRegistered = GE_FALSE; + +#ifndef NDEBUG +static geBoolean SystemInitialized = GE_FALSE; +#endif + +static CRITICAL_SECTION MainCriticalSection; + +static geBoolean GENESISCC geVFile_RegisterFileSystemInternal(const geVFile_SystemAPIs *APIs, geVFile_TypeIdentifier *Type) +{ + geVFile_SystemAPIs ** NewList; + + NewList = geRam_Realloc(RegisteredAPIs, sizeof(*RegisteredAPIs) * (SystemCount + 1)); + if (!NewList) + return GE_FALSE; + + RegisteredAPIs = NewList; +#pragma message ("Casting away const in geVFile_RegisterFileSystem") + RegisteredAPIs[SystemCount++] = (geVFile_SystemAPIs *)APIs; + *Type = SystemCount; + + return GE_TRUE; +} + +void GENESISCC geVFile_CloseAPI (void) +{ + geRam_Free(RegisteredAPIs); +} + +static geBoolean RegisterBuiltInAPIs(void) +{ + geVFile_TypeIdentifier Type; + + if (BuiltInAPIsRegistered == GE_TRUE) + return GE_TRUE; + + if (geVFile_RegisterFileSystemInternal(FSDos_GetAPIs(), &Type) == GE_FALSE) + return GE_FALSE; + if (Type != GE_VFILE_TYPE_DOS) + return GE_FALSE; + + if (geVFile_RegisterFileSystemInternal(FSMemory_GetAPIs(), &Type) == GE_FALSE) + return GE_FALSE; + if (Type != GE_VFILE_TYPE_MEMORY) + return GE_FALSE; + + if (geVFile_RegisterFileSystemInternal(FSVFS_GetAPIs(), &Type) == GE_FALSE) + return GE_FALSE; + if (Type != GE_VFILE_TYPE_VIRTUAL) + return GE_FALSE; + +// Register New APIs here +/* if (geVFile_RegisterFileSystemInternal(FSVCFS_GetAPIs(), &Type) == GE_FALSE) + return GE_FALSE; + if (Type != GE_VFILE_TYPE_CVIRTUAL) + return GE_FALSE; +*/ + BuiltInAPIsRegistered = GE_TRUE; + + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geVFile_RegisterFileSystem(const geVFile_SystemAPIs *APIs, geVFile_TypeIdentifier *Type) +{ + geBoolean Result; + + assert(APIs); + assert(Type); + + if (RegisterBuiltInAPIs() == GE_FALSE) + return GE_FALSE; + + Result = geVFile_RegisterFileSystemInternal(APIs, Type); + + return Result; +} + +static geBoolean GENESISCC CheckOpenFlags(unsigned int OpenModeFlags) +{ + int FlagCount; + unsigned int AccessFlags; + + // Test to see that the open mode for this thing is mutually exclusive in + // the proper flags. + FlagCount = 0; + AccessFlags = OpenModeFlags & (GE_VFILE_OPEN_READONLY | GE_VFILE_OPEN_UPDATE | GE_VFILE_OPEN_CREATE); + if (AccessFlags & GE_VFILE_OPEN_READONLY) + FlagCount++; + if (AccessFlags & GE_VFILE_OPEN_UPDATE) + FlagCount++; + if (AccessFlags & GE_VFILE_OPEN_CREATE) + FlagCount++; + + if (FlagCount != 1 && !(OpenModeFlags & GE_VFILE_OPEN_DIRECTORY)) + return GE_FALSE; + + return GE_TRUE; +} + +GENESISAPI geVFile * GENESISCC geVFile_OpenNewSystem( + geVFile * FS, + geVFile_TypeIdentifier FileSystemType, + const char * Name, + void * Context, + unsigned int OpenModeFlags) +{ + const geVFile_SystemAPIs * APIs; + geVFile * File; + void * FSData; + geVFile * BaseFile; + + + if (RegisterBuiltInAPIs() == GE_FALSE) + return GE_FALSE; + + if ((FileSystemType == 0) || (FileSystemType > SystemCount)) + return NULL; + + if (CheckOpenFlags(OpenModeFlags) == GE_FALSE) + return NULL; + + // Sugarcoating support for a taste test + if (FS == NULL && (FileSystemType == GE_VFILE_TYPE_VIRTUAL +// +// add tests for file types here + +// || FileSystemType == GE_VFILE_TYPE_CVIRTUAL + + )) + { + assert(Name); + BaseFile = geVFile_OpenNewSystem(NULL, + GE_VFILE_TYPE_DOS, + Name, + NULL, + OpenModeFlags & ~GE_VFILE_OPEN_DIRECTORY); + if (!BaseFile) + return NULL; + FS = BaseFile; + Name = NULL; + } + else + BaseFile = NULL; + + APIs = RegisteredAPIs[FileSystemType - 1]; + assert(APIs); + FSData = APIs->OpenNewSystem(FS, Name, Context, OpenModeFlags); + + if (!FSData) + { + if (BaseFile) + geVFile_Close(BaseFile); + return NULL; + } + + File = geRam_Allocate(sizeof(*File)); + if (!File) + { + if (BaseFile) + geVFile_Close(BaseFile); + APIs->Close(FSData); + return NULL; + } + + File->SystemType = FileSystemType; + File->APIs = APIs; + File->FSData = FSData; + File->SearchList = geRam_Allocate(sizeof(*File->SearchList)); + File->BaseFile = BaseFile; + + if (!File->SearchList) + { + if (BaseFile) + geVFile_Close(BaseFile); + geRam_Free(File); + APIs->Close(FSData); + return NULL; + } + + File->SearchList->FS = File; + File->SearchList->Next = NULL; + + return File; +} + +GENESISAPI geBoolean GENESISCC geVFile_UpdateContext(geVFile *FS, void *Context, int ContextSize) +{ + assert(FS); + assert(Context); + + return FS->APIs->UpdateContext(FS, FS->FSData, Context, ContextSize); +} + +GENESISAPI geVFile * GENESISCC geVFile_Open( + geVFile * FS, + const char * Name, + unsigned int OpenModeFlags) +{ + FSSearchList * SearchList; + geVFile * StartContext; + geVFile * File; + void * FSData; + + assert(Name); + + if (!FS) + return NULL; + + if (CheckOpenFlags(OpenModeFlags) == GE_FALSE) + return NULL; + + StartContext = FS; + + SearchList = FS->SearchList; + assert(SearchList); + assert(SearchList->FS == FS); + if (!(OpenModeFlags & GE_VFILE_OPEN_CREATE)) + { + while (SearchList) + { + FS = SearchList->FS; + if (FS->APIs->FileExists(FS, FS->FSData, Name)) + break; + SearchList = SearchList->Next; + } + } + + if (!SearchList) + return NULL; + + FSData = FS->APIs->Open(FS, FS->FSData, Name, NULL, OpenModeFlags); + if (!FSData) + return NULL; + + File = geRam_Allocate(sizeof(*File)); + if (!File) + { + FS->APIs->Close(FSData); + return NULL; + } + + memset(File, 0, sizeof(*File)); + + File->SystemType = 0; + File->APIs = FS->APIs; + File->FSData = FSData; + File->SearchList = geRam_Allocate(sizeof(*File->SearchList)); + File->Context = FS; + + if (!File->SearchList) + { + geRam_Free(File); + FS->APIs->Close(FSData); + return NULL; + } + + File->SearchList->FS = File; + File->SearchList->Next = StartContext->SearchList; + + return File; +} + +GENESISAPI geVFile * GENESISCC geVFile_GetContext(const geVFile *File) +{ + assert(File); + + return File->Context; +} + +static void DestroySearchList(FSSearchList *SearchList) +{ + while (SearchList) + { + FSSearchList * Temp; + + Temp = SearchList; + SearchList = SearchList->Next; + geRam_Free(Temp); + } +} + +static FSSearchList * CopySearchList(const FSSearchList *SearchList) +{ + FSSearchList * NewList; + FSSearchList * Tail; + + NewList = Tail = NULL; + while (SearchList) + { + FSSearchList * Temp; + + Temp = geRam_Allocate(sizeof(*Tail)); + if (!Temp) + { + DestroySearchList(NewList); + return NULL; + } + if (Tail) + Tail->Next = Temp; + else + { + assert(!NewList); + NewList = Temp; + } + Tail = Temp; + Tail->FS = SearchList->FS; + Tail->Next = NULL; + SearchList = SearchList->Next; + } + return NewList; +} + +GENESISAPI geBoolean GENESISCC geVFile_AddPath(geVFile *FS1, const geVFile *FS2, geBoolean Append) +{ + FSSearchList * SearchList; + + assert(FS1); + assert(FS2); + + SearchList = CopySearchList(FS2->SearchList); + if (!SearchList) + return GE_FALSE; + + if (Append == GE_FALSE) + { + SearchList->Next = FS1->SearchList; + FS1->SearchList = SearchList; + } + else + { + FSSearchList Temp; + FSSearchList * pTemp; + + Temp.Next = FS1->SearchList; + pTemp = &Temp; + while (pTemp->Next) + { + pTemp = pTemp->Next; + } + + pTemp->Next = SearchList; + } + + return GE_TRUE; +} + +GENESISAPI geBoolean GENESISCC geVFile_DeleteFile(geVFile *FS, const char *FileName) +{ + assert(FS); + assert(FileName); + + return FS->APIs->DeleteFile(FS, FS->FSData, FileName); +} + +GENESISAPI geBoolean GENESISCC geVFile_RenameFile(geVFile *FS, const char *FileName, const char *NewName) +{ + assert(FS); + assert(FileName); + assert(NewName); + + return FS->APIs->RenameFile(FS, FS->FSData, FileName, NewName); +} + +GENESISAPI geBoolean GENESISCC geVFile_FileExists(geVFile *FS, const char *FileName) +{ + return FS->APIs->FileExists(FS, FS->FSData, FileName); +} + +GENESISAPI geBoolean GENESISCC geVFile_Close(geVFile *File) +{ + assert(File); + + File->APIs->Close(File->FSData); + + if (File->BaseFile) + geVFile_Close(File->BaseFile); + + geRam_Free(File->SearchList); + geRam_Free(File); +#pragma message ("Need to propagate returns through VFile_Close") + return GE_TRUE; +} + + +GENESISAPI geBoolean GENESISCC geVFile_GetS(geVFile *File, void *Buff, int MaxLen) +{ + assert(File); + assert(Buff); + + if (MaxLen == 0) + return GE_FALSE; + + return File->APIs->GetS(File->FSData, Buff, MaxLen); +} + +GENESISAPI geBoolean GENESISCC geVFile_Read(geVFile *File, void *Buff, int Count) +{ + assert(File); + assert(Buff); + + if (Count == 0) + return GE_TRUE; + + return File->APIs->Read(File->FSData, Buff, Count); +} + +GENESISAPI geBoolean GENESISCC geVFile_Write(geVFile *File, const void *Buff, int Count) +{ + assert(File); + assert(Buff); + + if (Count == 0) + return GE_TRUE; + + return File->APIs->Write(File->FSData, Buff, Count); +} + +GENESISAPI geBoolean GENESISCC geVFile_Seek(geVFile *File, int Where, geVFile_Whence Whence) +{ + assert(File); + + return File->APIs->Seek(File->FSData, Where, Whence); +} + +GENESISAPI geBoolean GENESISCC geVFile_Printf(geVFile *File, const char *Format, ...) +{ + char Temp[8096]; + va_list ArgPtr; + + assert(File); + assert(Format); + + va_start(ArgPtr, Format); + vsprintf(Temp, Format, ArgPtr); + va_end(ArgPtr); + + return File->APIs->Write(File->FSData, &Temp[0], strlen(Temp)); +} + +GENESISAPI geBoolean GENESISCC geVFile_EOF (const geVFile *File) +{ + assert(File); + + return File->APIs->Eof(File->FSData); +} + +GENESISAPI geBoolean GENESISCC geVFile_Tell (const geVFile *File, long *Position) +{ + assert(File); + + return File->APIs->Tell(File->FSData, Position); +} + +GENESISAPI geBoolean GENESISCC geVFile_Size (const geVFile *File, long *Size) +{ + assert(File); + + return File->APIs->Size(File->FSData, Size); +} + +GENESISAPI geBoolean GENESISCC geVFile_GetProperties(const geVFile *File, geVFile_Properties *Properties) +{ + assert(File); + + return File->APIs->GetProperties(File->FSData, Properties); +} + +GENESISAPI geBoolean GENESISCC geVFile_SetSize(geVFile *File, long Size) +{ + assert(File); + + return File->APIs->SetSize(File->FSData, Size); +} + +GENESISAPI geBoolean GENESISCC geVFile_SetAttributes(geVFile *File, geVFile_Attributes Attributes) +{ + assert(File); + + return File->APIs->SetAttributes(File->FSData, Attributes); +} + +GENESISAPI geBoolean GENESISCC geVFile_SetTime(geVFile *File, const geVFile_Time *Time) +{ + assert(File); + + return File->APIs->SetTime(File->FSData, Time); +} + +GENESISAPI geBoolean GENESISCC geVFile_SetHints(geVFile *File, const geVFile_Hints *Hints) +{ + assert(File); + + return File->APIs->SetHints(File->FSData, Hints); +} + +GENESISAPI geVFile_Finder * GENESISCC geVFile_CreateFinder( + geVFile *FileSystem, + const char *FileSpec) +{ + geVFile_Finder * Finder; + + assert(FileSystem); + assert(FileSpec); + + Finder = geRam_Allocate(sizeof(*Finder)); + if (!Finder) + return Finder; + + Finder->Data = FileSystem->APIs->FinderCreate(FileSystem, FileSystem->FSData, FileSpec); + if (!Finder->Data) + { + geRam_Free(Finder); + return NULL; + } + + Finder->APIs = FileSystem->APIs; + + return Finder; +} + +GENESISAPI void GENESISCC geVFile_DestroyFinder(geVFile_Finder *Finder) +{ + assert(Finder); + assert(Finder->APIs); + + Finder->APIs->FinderDestroy(Finder->Data); + geRam_Free(Finder); +} + +GENESISAPI geBoolean GENESISCC geVFile_FinderGetNextFile(geVFile_Finder *Finder) +{ + assert(Finder); + assert(Finder->APIs); + assert(Finder->Data); + return Finder->APIs->FinderGetNextFile(Finder->Data); +} + +GENESISAPI geBoolean GENESISCC geVFile_FinderGetProperties(const geVFile_Finder *Finder, geVFile_Properties *Properties) +{ + assert(Finder); + assert(Finder->APIs); + assert(Finder->Data); + + return Finder->APIs->FinderGetProperties(Finder->Data, Properties); +} + + +GENESISAPI void GENESISCC geVFile_TimeToWin32FileTime(const geVFile_Time *Time, LPFILETIME Win32FileTime) +{ + *Win32FileTime = *(LPFILETIME)Time; +} diff --git a/G3D/VFile/vfile.h b/G3D/VFile/vfile.h new file mode 100644 index 0000000..bf06be9 --- /dev/null +++ b/G3D/VFile/vfile.h @@ -0,0 +1,192 @@ +/****************************************************************************************/ +/* VFILE.H */ +/* */ +/* Author: Eli Boling */ +/* Description: Virtual file interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef VFILE_H +#define VFILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "basetype.h" + +typedef struct geVFile geVFile; + +//--------- Finder (Directory) -------------- +typedef struct geVFile_Finder geVFile_Finder; + +typedef int geVFile_TypeIdentifier; +typedef unsigned int geVFile_Attributes; + +typedef struct geVFile_Hints +{ + void * HintData; + int HintDataLength; +} geVFile_Hints; + +typedef struct geVFile_Time +{ + unsigned long Time1; + unsigned long Time2; +} geVFile_Time; + +#define GE_VFILE_ATTRIB_READONLY 0x00000001 +#define GE_VFILE_ATTRIB_DIRECTORY 0x00000002 + +typedef struct geVFile_Properties +{ + geVFile_Time Time; + geVFile_Attributes AttributeFlags; + long Size; + geVFile_Hints Hints; + char Name[1024]; +} geVFile_Properties; + +#ifdef _INC_WINDOWS +GENESISAPI void GENESISCC geVFile_TimeToWin32FileTime(const geVFile_Time *, LPFILETIME Win32FileTime); + // Converts a geVFile time to a Win32 FILETIME structure. This API is the + // way to get the file time into a format to do standardized date/time + // operations on. We do not provide date/time operations natively. +#endif + +GENESISAPI geVFile_Finder * GENESISCC geVFile_CreateFinder( + geVFile * FileSystem, + const char * FileSpec); + // Creates a finder object from which you can get iterated file names. + // This is findfirst/findnext functionality. + +GENESISAPI void GENESISCC geVFile_DestroyFinder(geVFile_Finder *Finder); + // Destroys a Finder object + +GENESISAPI geBoolean GENESISCC geVFile_FinderGetNextFile(geVFile_Finder *Finder); + // Tracks to the next file in the finder directory + +GENESISAPI geBoolean GENESISCC geVFile_FinderGetProperties(const geVFile_Finder *Finder, geVFile_Properties *Properties); + // Gets the file properties from a geVFile_Finder. You cannot set properties for + // a file through a finder. You have to set the properties through a geVFile. + +//--------- File System Operations ---- + +typedef struct geVFile_MemoryContext +{ + void * Data; + int DataLength; +} geVFile_MemoryContext; + +#define GE_VFILE_TYPE_DOS ( (geVFile_TypeIdentifier) 1L ) +#define GE_VFILE_TYPE_MEMORY ( (geVFile_TypeIdentifier) 2L ) +#define GE_VFILE_TYPE_VIRTUAL ( (geVFile_TypeIdentifier) 3L ) +//#define GE_VFILE_TYPE_CVIRTUAL ( (geVFile_TypeIdentifier) 4L ) + +// First three flags are mutually exclusive. Combining them will result in failure +// returns for both geVFile_OpenNewSystem and geVFile_Open. +#define GE_VFILE_OPEN_READONLY 0x00000001 +#define GE_VFILE_OPEN_UPDATE 0x00000002 +#define GE_VFILE_OPEN_CREATE 0x00000004 + +#define GE_VFILE_OPEN_DIRECTORY 0x00000008 + + +GENESISAPI geVFile * GENESISCC geVFile_OpenNewSystem( + geVFile * FS, + geVFile_TypeIdentifier FileSystemType, // { DOS, MEMORY, ETC ... }, + const char * Name, + void * Context, + unsigned int OpenModeFlags); + // Opens a file / file system. + +GENESISAPI geBoolean GENESISCC geVFile_UpdateContext(geVFile *FS, void *Context, int ContextSize); + +GENESISAPI geVFile * GENESISCC geVFile_GetContext(const geVFile *File); + // Returns the outer context in which File was opened. + +GENESISAPI geVFile * GENESISCC geVFile_Open( + geVFile * FS, + const char * Name, + unsigned int OpenModeFlags); + +/* +typedef enum +{ + geVFile_AppendPath, + geVFile_PrependPath, +} geVFile_SearchOrder; +*/ + +GENESISAPI geBoolean GENESISCC geVFile_AddPath(geVFile *FS1, const geVFile *FS2, geBoolean Append); + // Appends (or prepends) the path associated with FS2 into FS1. + // Append==GE_TRUE causes the FS2 to be searched AFTER FS1 + // Append==GE_FALSE causes the FS2 to be searched BEFORE FS1 + +/* perhaps geVFile_AppendPath and geVFile_PrependPath */ + + +GENESISAPI geBoolean GENESISCC geVFile_DeleteFile(geVFile *FS, const char *FileName); + // Deletes a file within a file system. Returns GE_TRUE on success, GE_FALSE + // on failure. + +GENESISAPI geBoolean GENESISCC geVFile_RenameFile(geVFile *FS, const char *FileName, const char *NewName); + // Renames a file within a file system. Returns GE_TRUE on success, GE_FALSE + // on failure. + +GENESISAPI geBoolean GENESISCC geVFile_FileExists(geVFile *FS, const char *FileName); + // Returns GE_TRUE if the file FileName exists in FS, GE_FALSE otherwise. + // Does not do any searching (?) + +//geVFile_VFileType geVFile_Register( all kinds of stuff ); + +GENESISAPI geBoolean GENESISCC geVFile_Close (geVFile *File); + // closes and destroys the File + +GENESISAPI void GENESISCC geVFile_CloseAPI (void); + +//---------- File Specific Operations ----------- + +typedef enum +{ + GE_VFILE_SEEKCUR = 0, + GE_VFILE_SEEKEND = 1, + GE_VFILE_SEEKSET = 2 +} geVFile_Whence; + +GENESISAPI geBoolean GENESISCC geVFile_GetS ( geVFile *File, void *Buff, int MaxLen); +GENESISAPI geBoolean GENESISCC geVFile_Read ( geVFile *File, void *Buff, int Count); +GENESISAPI geBoolean GENESISCC geVFile_Write ( geVFile *File, const void *Buff, int Count); +GENESISAPI geBoolean GENESISCC geVFile_Seek ( geVFile *File, int where, geVFile_Whence Whence); +GENESISAPI geBoolean GENESISCC geVFile_Printf ( geVFile *File, const char *Format, ...); +GENESISAPI geBoolean GENESISCC geVFile_EOF (const geVFile *File); +GENESISAPI geBoolean GENESISCC geVFile_Tell (const geVFile *File, long *Position); +GENESISAPI geBoolean GENESISCC geVFile_GetProperties(const geVFile *File, geVFile_Properties *Properties); +//geBoolean geVFile_GetName(geVFile *File, char *Buff, int MaxBuffLen); + // Gets the name of the file + +GENESISAPI geBoolean GENESISCC geVFile_Size (const geVFile *File, long *Size); +GENESISAPI geBoolean GENESISCC geVFile_SetSize ( geVFile *File, long Size); +GENESISAPI geBoolean GENESISCC geVFile_SetAttributes( geVFile *File, geVFile_Attributes Attributes); +GENESISAPI geBoolean GENESISCC geVFile_SetTime ( geVFile *File, const geVFile_Time *Time); +GENESISAPI geBoolean GENESISCC geVFile_SetHints ( geVFile *File, const geVFile_Hints *Hints); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/VFile/vfile_structs.h b/G3D/VFile/vfile_structs.h new file mode 100644 index 0000000..a5fe6a2 --- /dev/null +++ b/G3D/VFile/vfile_structs.h @@ -0,0 +1,52 @@ +#ifndef VFILESTRUCT_H +#define VFILESTRUCT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include +#include + +#include "basetype.h" +#include "ram.h" +#include "vfile.h" +#include "vfile._h" +#include "fsdos.h" +#include "fsmemory.h" +#include "fsvfs.h" + +typedef struct FSSearchList +{ + geVFile * FS; + struct FSSearchList * Next; +} FSSearchList; + + +typedef struct geVFile +{ + geVFile_TypeIdentifier SystemType; + const geVFile_SystemAPIs * APIs; + void * FSData; + geVFile * Context; + FSSearchList * SearchList; + CRITICAL_SECTION CriticalSection; + geVFile * BaseFile; +} geVFile; + +typedef struct geVFile_Finder +{ + const geVFile_SystemAPIs * APIs; + void * Data; +} geVFile_Finder; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Winres.h b/G3D/Winres.h new file mode 100644 index 0000000..7185eaa --- /dev/null +++ b/G3D/Winres.h @@ -0,0 +1,45 @@ +// This is a part of the Microsoft Foundation Classes C++ library. +// Copyright (C) 1992-1998 Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Microsoft Foundation Classes Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Microsoft Foundation Classes product. + +// winres.h - Windows resource definitions +// extracted from WINUSER.H and COMMCTRL.H + +#ifdef _AFX_MINREBUILD +#pragma component(minrebuild, off) +#endif + +#define VS_VERSION_INFO 1 + +#ifdef APSTUDIO_INVOKED +#define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols +#endif + +#ifndef WINVER +#define WINVER 0x0400 // default to Windows Version 4.0 +#endif + +#include + +// operation messages sent to DLGINIT +#define LB_ADDSTRING (WM_USER+1) +#define CB_ADDSTRING (WM_USER+3) + +#ifdef APSTUDIO_INVOKED +#undef APSTUDIO_HIDDEN_SYMBOLS +#endif + +#ifdef IDC_STATIC +#undef IDC_STATIC +#endif +#define IDC_STATIC (-1) + +#ifdef _AFX_MINREBUILD +#pragma component(minrebuild, on) +#endif diff --git a/G3D/Winresrc.h b/G3D/Winresrc.h new file mode 100644 index 0000000..37cb0d9 --- /dev/null +++ b/G3D/Winresrc.h @@ -0,0 +1,27 @@ +/*++ BUILD Version: ???? Increment this if a change has global effects + +Copyright 1990 - 1998 Microsoft Corporation + +Module Name: + + winresrc.h + +Abstract: + + This module defines the 32-Bit Windows resource codes. + +Revision History: + +--*/ + +#ifndef _WINRESRC_ +#define _WINRESRC_ + +#include +#include +#include +#include +#include +#include + +#endif /* _WINRESRC_ */ diff --git a/G3D/World/FRUSTUM.H b/G3D/World/FRUSTUM.H new file mode 100644 index 0000000..5c15629 --- /dev/null +++ b/G3D/World/FRUSTUM.H @@ -0,0 +1,111 @@ +/****************************************************************************************/ +/* Frustum.h */ +/* */ +/* Author: John Pollard */ +/* Description: Frustum creation/clipping */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_FRUSTUM_H +#define GE_FRUSTUM_H + +#include +//#include + +#include "BaseType.h" +#include "GBSPFile.h" +#include "Vec3d.h" +#include "Camera.h" +#include "XForm3d.h" +#include "Surface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_FCP 32 // Max ClipPlanes for frustum... + +#define CLIP_PLANE_EPSILON 0.001f + +//================================================================================ +// Structure defines +//================================================================================ +typedef struct Frustum_Info +{ + int32 NumPlanes; // Number of frustum planes to clip against + GFX_Plane Planes[MAX_FCP]; // Planes to clip against + + // Quick LUTS For BBox testing against frustum + int32 FrustumBBoxIndexes[MAX_FCP*6]; + int32 *pFrustumBBoxIndexes[MAX_FCP]; +} Frustum_Info; + +//================================================================================ +// Function ProtoTypes +//================================================================================ +void Frustum_SetFromCamera(Frustum_Info *Info, geCamera *Camera); +geBoolean Frustum_SetFromPoly(Frustum_Info *Info, geVec3d *Verts, int32 NumVerts, geBoolean Flip); +void Frustum_RotateToWorldSpace(Frustum_Info *In, geCamera *Camera, Frustum_Info *Out); +void Frustum_TransformToWorldSpace(const Frustum_Info *In, const geCamera *Camera, Frustum_Info *Out); + +geBoolean gePlane_ClipVertsFannedUVRGB( const geVec3d *In, const Surf_TexVert *TIn, int32 NumIn, + const GFX_Plane *Plane, + geVec3d *Out, Surf_TexVert *TOut, int32 *NumOut); + +geBoolean Frustum_ClipToPlane( GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + int32 NumVerts, int32 *OutVerts); +geBoolean Frustum_ClipToPlaneUV( GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + Surf_TexVert *pTIn, Surf_TexVert *pTOut, + int32 NumVerts, int32 *OutVerts); + +geBoolean Frustum_ClipToPlaneUVRGB(GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + Surf_TexVert *pTIn, Surf_TexVert *pTOut, + int32 NumVerts, int32 *OutVerts); + +geBoolean Frustum_ClipToPlaneUVRGBA(GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + Surf_TexVert *pTIn, Surf_TexVert *pTOut, + int32 NumVerts, int32 *OutVerts); + +geBoolean Frustum_ClipToPlaneRGB( GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + Surf_TexVert *pTIn, Surf_TexVert *pTOut, + int32 NumVerts, int32 *OutVerts); + +geBoolean Frustum_ClipToPlaneL( GFX_Plane *pPlane, + GE_LVertex *pIn, GE_LVertex *pOut, + int32 NumVerts, int32 *OutVerts); // CB added + +void Frustum_Project(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera); +void Frustum_ProjectRGB(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera); +void Frustum_ProjectRGBA(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera); +void Frustum_ProjectRGBNoClamp(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera); + +geBoolean Frustum_PointsInFrustum(const geVec3d *Pin, const GFX_Plane *Plane, int32 NumVerts, int32 *c); + +geBoolean Frustum_PointInFrustum(const Frustum_Info *Fi, const geVec3d *Point, geFloat Radius); + +geBoolean Frustum_ClipAllPlanesL(const Frustum_Info * Fi,uint32 ClipFlags,GE_LVertex *Verts, int32 *pNumVerts); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/World/Fog.c b/G3D/World/Fog.c new file mode 100644 index 0000000..84bd28a --- /dev/null +++ b/G3D/World/Fog.c @@ -0,0 +1,111 @@ +/****************************************************************************************/ +/* Fog.c */ +/* */ +/* Author: John Pollard */ +/* Description: Fog module */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "Fog.h" + +//================================================================================ +// geFog_Create +//================================================================================ +GENESISAPI geFog *geFog_Create(SET_ATTR_CB *SetAttrCB) +{ + geFog *Fog; + + Fog = GE_RAM_ALLOCATE_STRUCT(geFog); + + if (!Fog) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return NULL; + } + + memset(Fog, 0, sizeof(geFog)); + + if (SetAttrCB) + Fog->SetAttrCB = SetAttrCB; + + return Fog; +} + +//================================================================================ +// geFog_Destroy +//================================================================================ +GENESISAPI void geFog_Destroy(geFog *Fog) +{ + assert(Fog); + + geRam_Free(Fog); +} + +//================================================================================ +// geFog_SetAttributes +//================================================================================ +GENESISAPI geBoolean geFog_SetAttributes( geFog *Fog, + const geVec3d *Pos, + GE_RGBA *Color, + geFloat LightBrightness, + geFloat VolumeBrightness, + geFloat VolumeRadius) +{ + Fog->Pos = *Pos; + Fog->Color.r = Color->r*(1.0f/255.0f)*(1<<8); + Fog->Color.g = Color->g*(1.0f/255.0f)*(1<<8); + Fog->Color.b = Color->b*(1.0f/255.0f)*(1<<8); + Fog->LightBrightness = LightBrightness; + Fog->VolumeBrightness = VolumeBrightness; + Fog->VolumeRadius = VolumeRadius; + Fog->VolumeRadiusSquared = VolumeRadius*VolumeRadius; + Fog->VolumeRadius2 = VolumeRadius*2; + + // Now that all is set, call the CB if it exist... + if (Fog->SetAttrCB) + { + if (!Fog->SetAttrCB(Fog)) + return GE_FALSE; + } + + return GE_TRUE; +} + +//================================================================================ +// geFog_SetUserData +//================================================================================ +GENESISAPI geBoolean geFog_SetUserData(geFog *Fog, void *UserData) +{ + assert(Fog); + + Fog->UserData = UserData; + + return GE_TRUE; +} + +//================================================================================ +// geFog_GetUserData +//================================================================================ +GENESISAPI void *geFog_GetUserData(geFog *Fog) +{ + assert(Fog); + + return Fog->UserData; +} + diff --git a/G3D/World/Fog.h b/G3D/World/Fog.h new file mode 100644 index 0000000..b76c1fc --- /dev/null +++ b/G3D/World/Fog.h @@ -0,0 +1,83 @@ +/****************************************************************************************/ +/* Fog.h */ +/* */ +/* Author: John Pollard */ +/* Description: Fog module */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_FOG_H +#define GE_FOG_H + +#include + +#include "Vec3d.h" +#include "BaseType.h" +#include "GeTypes.h" +#include "Ram.h" +#include "Errorlog.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//===================================================================================== +// Defines / Structure defines +//===================================================================================== +typedef struct geFog geFog; + +typedef geBoolean SET_ATTR_CB(geFog *Fog); + +typedef struct geFog +{ + geVec3d Pos; + GE_RGBA Color; + geFloat LightBrightness; + geFloat VolumeBrightness; + geFloat VolumeRadius; + geFloat VolumeRadius2; // *2 + geFloat VolumeRadiusSquared; // Radius squared + + void *UserData; + + SET_ATTR_CB *SetAttrCB; // CB for when geFog_SetAttributes is called + + struct geFog *Next; + struct geFog *Prev; +} geFog; + +//===================================================================================== +// Function ProtoTypes +//===================================================================================== +GENESISAPI geFog *geFog_Create(SET_ATTR_CB *SetAttrCB); + +GENESISAPI void geFog_Destroy(geFog *Fog); + +GENESISAPI geBoolean geFog_SetAttributes( geFog *Fog, + const geVec3d *Pos, + GE_RGBA *Color, + geFloat LightBrightness, + geFloat VolumeBrightness, + geFloat VolumeRadius); + +GENESISAPI geBoolean geFog_SetUserData(geFog *Fog, void *UserData); +GENESISAPI void *geFog_GetUserData(geFog *Fog); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/World/Frustum.c b/G3D/World/Frustum.c new file mode 100644 index 0000000..8a83251 --- /dev/null +++ b/G3D/World/Frustum.c @@ -0,0 +1,1223 @@ +/****************************************************************************************/ +/* Frustum.c */ +/* */ +/* Author: John Pollard */ +/* Description: Frustum creation/clipping */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "Camera.h" +#include "Frustum.h" +#include "Surface.h" + +#include "Vec3d.h" + +//#define RIGHT_HANDED + +//===================================================================================== +// Local Static Function prototypes +//===================================================================================== +static void SetWorldspaceClipPlane(const GFX_Plane *In, const geCamera *Camera, GFX_Plane *Out); +static void BackRotateVector(const geVec3d *In, geVec3d *Out, const geXForm3d *XForm); +static void SetUpFrustumBBox(Frustum_Info *Info); +int Frustum_Seed1=1768710981; +int Frustum_Seed2=560296816; +//================================================================================ +// Frustum_SetFromCamera +//================================================================================ +void Frustum_SetFromCamera(Frustum_Info *Info, geCamera *Camera) +{ + geFloat s, c, ZFar; + geBoolean ZFarEnable; + geVec3d Normal; + int32 i; + + geCamera_GetViewAngleXSinCos(Camera,&s,&c); + + // Left clip plane + Normal.X = s; + Normal.Y = 0.0f; + Normal.Z = -c; + geVec3d_Normalize(&Normal); + Info->Planes[0].Normal = Normal; + + // Right clip plane + Normal.X = -s; + geVec3d_Normalize(&Normal); + Info->Planes[1].Normal = Normal; + + geCamera_GetViewAngleYSinCos(Camera,&s,&c); + + // Bottom clip plane + Normal.X = 0.0f; + Normal.Y = s; + Normal.Z = -c; + geVec3d_Normalize(&Normal); + Info->Planes[2].Normal = Normal; + + // Top clip plane + Normal.Y = -s; + geVec3d_Normalize(&Normal); + Info->Planes[3].Normal = Normal; + + Info->NumPlanes = 4; + + // Clear all distances + for (i=0; iNumPlanes; i++) + { + Info->Planes[i].Dist = 0.0f; + Info->Planes[i].Type = PLANE_ANY; + } + + // Check to see if we need to use a far clip plane + geCamera_GetFarClipPlane(Camera, &ZFarEnable, &ZFar); + + if (ZFarEnable) + { + geFloat ZScale; + + ZScale = geCamera_GetZScale(Camera); + + // Far clip plane + Normal.X = 0.0f; + Normal.Y = 0.0f; + Normal.Z = 1.0f; + geVec3d_Normalize(&Normal); + Info->Planes[4].Normal = Normal; + + Info->Planes[4].Dist = -(ZFar/ZScale); + Info->Planes[4].Type = PLANE_ANY; + + Info->NumPlanes = 5; + } + + // Get BBox info for fast BBox rejection against frustum... + SetUpFrustumBBox(Info); +} + +//================================================================================ +// Frustum_SetFromPoly +// Create a frustum looking through a poly (from the origin) +//================================================================================ +geBoolean Frustum_SetFromPoly(Frustum_Info *Info, geVec3d *Verts, int32 NumVerts, geBoolean Flip) +{ + int32 NextVert; + geVec3d *pVert1, *pVert2, Vect; + GFX_Plane *Planes; + int32 i; + + if (NumVerts >= MAX_FCP) + return GE_FALSE; // Too many planes!!! + + Planes = Info->Planes; + + Info->NumPlanes = 0; + + for (i=0; i< NumVerts; i++) + { + NextVert = ((i+1) < NumVerts) ? (i+1) : 0; + + pVert1 = &Verts[i]; + pVert2 = &Verts[NextVert]; + + if (geVec3d_Compare(pVert1, pVert2, 0.1f)) // Coplanar edge... + continue; // Coplanar edges will cause a plane to be duplicated, skip it or it will screw up + // the clipping stage of the frustum created from this poly... + + geVec3d_Subtract(pVert1, pVert2, &Vect); + + if (Flip) + geVec3d_CrossProduct(pVert2, &Vect, &Planes->Normal); + else + geVec3d_CrossProduct(&Vect, pVert2, &Planes->Normal); + + geVec3d_Normalize(&Planes->Normal); + + Planes->Dist = 0.0f; + Planes->Type = PLANE_ANY; + + Planes++; + Info->NumPlanes++; + } + + // Get BBox info for fast BBox rejection against frustum... + SetUpFrustumBBox(Info); +return GE_TRUE; +} + +//================================================================================ +// Frustum_RotateToWorldSpace +//================================================================================ +void Frustum_RotateToWorldSpace(Frustum_Info *In, geCamera *Camera, Frustum_Info *Out) +{ + int32 i; + GFX_Plane *pPlane1, *pPlane2; + + assert(In != Out); + + pPlane1 = In->Planes; + pPlane2 = Out->Planes; + + // Rotate all the planes + for (i=0; iNumPlanes; i++, pPlane1++, pPlane2++) + { + pPlane2->Type = pPlane1->Type; + + SetWorldspaceClipPlane(pPlane1, Camera, pPlane2); + pPlane2->Dist = 0.0f; // We are just rotating, so set dist to 0 + + if (pPlane1->Dist) // Add the original dist back in + { + geVec3d Vect; + + geVec3d_Clear(&Vect); + geVec3d_AddScaled(&Vect, &pPlane1->Normal, pPlane1->Dist, &Vect); + + BackRotateVector(&Vect, &Vect, geCamera_GetCameraSpaceXForm(Camera)); + + pPlane2->Dist += geVec3d_DotProduct(&pPlane2->Normal, &Vect); + } + } + + Out->NumPlanes = In->NumPlanes; + + // Get BBox info for fast BBox rejection against frustum... + SetUpFrustumBBox(Out); +} + +//================================================================================ +// Frustum_TransformToWorldSpace +//================================================================================ +void Frustum_TransformToWorldSpace(const Frustum_Info *In, const geCamera *Camera, Frustum_Info *Out) +{ + int32 i; + GFX_Plane *pPlane1, *pPlane2; + + assert(In != Out); + + pPlane1 = (GFX_Plane*)In->Planes; + pPlane2 = Out->Planes; + + // Rotate all the planes + for (i=0; iNumPlanes; i++, pPlane1++, pPlane2++) + { + pPlane2->Type = pPlane1->Type; + + SetWorldspaceClipPlane(pPlane1, Camera, pPlane2); + pPlane2->Dist = geVec3d_DotProduct(geCamera_GetPov(Camera), &pPlane2->Normal) - CLIP_PLANE_EPSILON; + + if (pPlane1->Dist) // Add the original dist back in + { + geVec3d Vect; + + geVec3d_Clear(&Vect); + geVec3d_AddScaled(&Vect, &pPlane1->Normal, pPlane1->Dist, &Vect); + + BackRotateVector(&Vect, &Vect, geCamera_GetCameraSpaceXForm(Camera)); + + pPlane2->Dist += geVec3d_DotProduct(&pPlane2->Normal, &Vect); + } + } + Out->NumPlanes = In->NumPlanes; + + // Get BBox info for fast BBox rejection against frustum... + SetUpFrustumBBox(Out); +} + +//================================================================================ +// SetWorldSpaceClipPlane +//================================================================================ +static void SetWorldspaceClipPlane(const GFX_Plane *In, const geCamera *Camera, GFX_Plane *Out) +{ + // Rotate the plane normal into worldspace + BackRotateVector(&In->Normal, &Out->Normal, geCamera_GetCameraSpaceXForm(Camera)); +} + +//================================================================================ +// BackRotateVector +// Rotate a vector from viewspace to worldspace. +//================================================================================ +static void BackRotateVector(const geVec3d *In, geVec3d *Out, const geXForm3d *XForm) +{ + geVec3d VRight, VUp, VIn, InCopy; + + InCopy = *In; + + // Get the 3 vectors that make up the Xform axis + VRight.X = XForm->AX; VRight.Y = XForm->AY; VRight.Z = XForm->AZ; + VUp.X = XForm->BX; VUp.Y = XForm->BY; VUp.Z = XForm->BZ; + VIn.X = XForm->CX; VIn.Y = XForm->CY; VIn.Z = XForm->CZ; + + Out->X = (InCopy.X * VRight.X) + (InCopy.Y * VUp.X) + (InCopy.Z * VIn.X); + Out->Y = (InCopy.X * VRight.Y) + (InCopy.Y * VUp.Y) + (InCopy.Z * VIn.Y); + Out->Z = (InCopy.X * VRight.Z) + (InCopy.Y * VUp.Z) + (InCopy.Z * VIn.Z); +} + +//================================================================================ +// SetUpFrustumBBox +// Setup bbox min/max test for the quadrant the frustum planes are in... +//================================================================================ +static void SetUpFrustumBBox(Frustum_Info *Info) +{ + int32 i, *Index; + + Index = Info->FrustumBBoxIndexes; + + for (i=0 ; iNumPlanes ; i++) + { + if (Info->Planes[i].Normal.X < 0) + { + Index[0] = 0; + Index[3] = 3; + } + else + { + Index[0] = 3; + Index[3] = 0; + } + if (Info->Planes[i].Normal.Y < 0) + { + Index[1] = 1; + Index[4] = 4; + } + else + { + Index[1] = 4; + Index[4] = 1; + } + if (Info->Planes[i].Normal.Z < 0) + { + Index[2] = 2; + Index[5] = 5; + } + else + { + Index[2] = 5; + Index[5] = 2; + } + + Info->pFrustumBBoxIndexes[i] = Index; + Index += 6; + } +} + +//================================================================================ +// gePlane_ClipVertsFanned +// Clips and adds fanned verts (does not fan though the poly out though...) +//================================================================================ +geBoolean gePlane_ClipVertsFanned( const geVec3d *In, int32 NumIn, + const GFX_Plane *Plane, + geVec3d *Out, int32 *NumOut) +{ + #define MAX_VERT 128 + + geVec3d *pIn, *pOut, *pFirst; + int32 i, Count[2], NextVert; + geFloat Dist[MAX_VERT]; + int32 CurIn, NextIn, FirstIn; + geFloat CurDist, FirstDist, PlaneDist, NextDist; + + assert(NumIn < MAX_VERT); + + PlaneDist = Plane->Dist; + + pIn = (geVec3d*)In; + + Count[0] = Count[1] = 0; // Clear front back list + + // First, get all the dist of the verts from the plane + for (i=0; i< NumIn; i++, pIn++) + { + Dist[i] = geVec3d_DotProduct(&Plane->Normal, pIn) - PlaneDist; + + if (Dist[i] >= 0.0f) + Count[0]++; // Front side + else + Count[1]++; // Back side + } + + if (!Count[0]) + return GE_FALSE; // Poly totally clipped away + else if (!Count[1]) + { + // Poly was totally in the ViewFrustum so... + // Copy the poly to the out list + memcpy((void*)In, Out, sizeof(geVec3d)*NumIn); + *NumOut = NumIn; + return GE_TRUE; + } + + FirstDist = Dist[0]; + FirstIn = (FirstDist >= 0.0f); // Save the first one off for when we are fanning... + + CurDist = FirstDist; // Save first as current + CurIn = FirstIn; + + pFirst = pIn = (geVec3d*)In; + pOut = Out; + + // The poly needs to be clipped... + for (i=0; i< NumIn; i++, pIn++) + { + geVec3d *pNext; + + NextVert = ((i+1)= 0.0f); + + // First clip the edges on the poly + if (CurIn != NextIn) + { + geFloat Scale; + + Scale = (PlaneDist - CurDist) / (NextDist - CurDist); + + pOut->X = pIn->X + (pNext->X - pIn->X) * Scale; + pOut->Y = pIn->Y + (pNext->Y - pIn->Y) * Scale; + pOut->Z = pIn->Z + (pNext->Z - pIn->Z) * Scale; + + pOut++; + } + + // Start clipping the fanned edges after we get past the first edge + if (NextVert >= 2) + { + if (FirstIn != NextIn) // The fanned edge crosses the plane, clip it, and store it in the out list + { + geFloat Scale; + + Scale = (Plane->Dist - FirstDist) / (NextDist - FirstDist); + + pOut->X = pFirst->X + (pNext->X - pFirst->X) * Scale; + pOut->Y = pFirst->Y + (pNext->Y - pFirst->Y) * Scale; + pOut->Z = pFirst->Z + (pNext->Z - pFirst->Z) * Scale; + + pOut++; + } + } + + CurIn = NextIn; + CurDist = NextDist; + } + + *NumOut = (pOut - Out); + + return (*NumOut >= 3); +} + +//================================================================================ +// gePlane_ClipVertsFanned +// Clips and adds fanned verts (does not fan though the poly out though...) +//================================================================================ +geBoolean gePlane_ClipVertsFannedUVRGB( const geVec3d *In, const Surf_TexVert *TIn, int32 NumIn, + const GFX_Plane *Plane, + geVec3d *Out, Surf_TexVert *TOut, int32 *NumOut) +{ + #define MAX_VERT 128 + + geVec3d *pIn, *pOut, *pFirst; + Surf_TexVert *pTIn, *pTOut, *pTFirst; + int32 i=0, Count[2], FirstVert=0, NextVert=0; + geFloat Dist[MAX_VERT]; + int32 CurIn, NextIn, FirstIn; + geFloat CurDist, FirstDist, PlaneDist, NextDist; + int32 Temp; + + assert(NumIn < MAX_VERT); + + PlaneDist = Plane->Dist; + + pIn = (geVec3d*)In; + + Count[0] = Count[1] = 0; // Clear front back list + + // First, get all the dist of the verts from the plane + for (i=0; i< NumIn; i++, pIn++) + { + Dist[i] = geVec3d_DotProduct(&Plane->Normal, pIn); + + if (Dist[i] >= PlaneDist) + { + Count[0]++; // Front side + FirstVert = i; // The first vert MUST be inside the frustum + } + else + Count[1]++; // Back side + + } + + if (!Count[0]) // Nothing on the front + return GE_FALSE; + else if (!Count[1]) // Nothing on the back + { + // Poly was totally in the ViewFrustum so... + // Copy the poly to the out list + memcpy(Out, In, sizeof(geVec3d)*NumIn); + memcpy(TOut, TIn, sizeof(Surf_TexVert)*NumIn); + *NumOut = NumIn; + return GE_TRUE; + } + + FirstDist = Dist[FirstVert]; + FirstIn = (FirstDist >= PlaneDist); // Save the first one off for when we are fanning... + + CurDist = FirstDist; // Save first as current + CurIn = FirstIn; + + pFirst = pIn = (geVec3d*)&In[FirstVert]; + pTFirst = pTIn = (Surf_TexVert*)&TIn[FirstVert]; + + pOut = Out; + pTOut = TOut; + + Temp = 0; + + // The poly needs to be clipped... + for (i=FirstVert; i< FirstVert+NumIn; i++, Temp++) + { + geVec3d *pNext; + Surf_TexVert *pTNext; + int32 ThisVert; + + ThisVert = i%NumIn; + NextVert = (i+1)%NumIn; + + pIn = (geVec3d*)&In[ThisVert]; + pTIn = (Surf_TexVert*)&TIn[ThisVert]; + + if (CurIn) + { + *pOut++ = *pIn; + *pTOut++ = *pTIn; + } + + pNext = (geVec3d*)&In[NextVert]; + pTNext = (Surf_TexVert*)&TIn[NextVert]; + + NextDist = Dist[NextVert]; + NextIn = (NextDist >= PlaneDist); + + // First clip the edges on the poly + if (CurIn != NextIn) + { + geFloat Scale; + + Scale = (PlaneDist - CurDist) / (NextDist - CurDist); + + pOut->X = pIn->X + (pNext->X - pIn->X) * Scale; + pOut->Y = pIn->Y + (pNext->Y - pIn->Y) * Scale; + pOut->Z = pIn->Z + (pNext->Z - pIn->Z) * Scale; + + pTOut->u = pTIn->u + (pTNext->u - pTIn->u) * Scale; + pTOut->v = pTIn->v + (pTNext->v - pTIn->v) * Scale; + + pTOut->r = pTIn->r + (pTNext->r - pTIn->r) * Scale; + pTOut->g = pTIn->g + (pTNext->g - pTIn->g) * Scale; + pTOut->b = pTIn->b + (pTNext->b - pTIn->b) * Scale; + + pOut++; + pTOut++; + } + + // Start clipping the fanned edges after we get past the first edge + if (Temp >= 1 && Temp+2 < NumIn) + { + if (FirstIn != NextIn) // The fanned edge crosses the plane, clip it, and store it in the out list + { + geFloat Scale; + + Scale = (PlaneDist - FirstDist) / (NextDist - FirstDist); + + pOut->X = pFirst->X + (pNext->X - pFirst->X) * Scale; + pOut->Y = pFirst->Y + (pNext->Y - pFirst->Y) * Scale; + pOut->Z = pFirst->Z + (pNext->Z - pFirst->Z) * Scale; + + pTOut->u = pTFirst->u + (pTNext->u - pTFirst->u) * Scale; + pTOut->v = pTFirst->v + (pTNext->v - pTFirst->v) * Scale; + + pTOut->r = pTFirst->r + (pTNext->r - pTFirst->r) * Scale; + pTOut->g = pTFirst->g + (pTNext->g - pTFirst->g) * Scale; + pTOut->b = pTFirst->b + (pTNext->b - pTFirst->b) * Scale; + + pOut++; + pTOut++; + } + } + + CurIn = NextIn; + CurDist = NextDist; + } + + *NumOut = (pOut - Out); + + return (*NumOut >= 3); +} + +//================================================================================ +// Frustum_ClipToPlane +// Clips X, Y only +//================================================================================ +geBoolean Frustum_ClipToPlane( GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + int32 NumVerts, int32 *OutVerts) +{ + int32 i, NextVert, CurIn, NextIn; + geFloat CurDot, NextDot, Scale; + geVec3d *pInVert, *pOutVert, *pNext; + geVec3d *pNormal; + + pNormal = &pPlane->Normal; + pInVert = pIn; + pOutVert = pOut; + + CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z); + CurIn = (CurDot >= pPlane->Dist); + + for (i=0 ; iX * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z); + NextIn = (NextDot >= pPlane->Dist); + + // Add a clipped vertex if one end of the current edge is + // inside the plane and the other is outside + if (CurIn != NextIn) + { + Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot); + + pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale; + pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale; + pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale; + + pOutVert++; + } + + CurDot = NextDot; + CurIn = NextIn; + pInVert++; + } + + *OutVerts = pOutVert - pOut; + + if (*OutVerts < 3) + return GE_FALSE; + + return GE_TRUE; +} + +//================================================================================ +// Frustum_ClipToPlaneUV +// Clips X, Y, u, v +//================================================================================ +geBoolean Frustum_ClipToPlaneUV( GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + Surf_TexVert *pTIn, Surf_TexVert *pTOut, + int32 NumVerts, int32 *OutVerts) +{ + int32 i, NextVert, CurIn, NextIn; + geFloat CurDot, NextDot, Scale; + geVec3d *pInVert, *pOutVert, *pNext; + Surf_TexVert *pTInVert, *pTOutVert, *pTNext; + geVec3d *pNormal; + + pNormal = &pPlane->Normal; + pInVert = pIn; + pOutVert = pOut; + pTInVert = pTIn; + pTOutVert = pTOut; + + CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z); + CurIn = (CurDot >= pPlane->Dist); + + for (i=0 ; iu = pTInVert->u; + pTOutVert->v = pTInVert->v; + pTOutVert++; + } + + pNext = &pIn[NextVert]; + pTNext = &pTIn[NextVert]; + + NextDot = (pNext->X * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z); + NextIn = (NextDot >= pPlane->Dist); + + // Add a clipped vertex if one end of the current edge is + // inside the plane and the other is outside + if (CurIn != NextIn) + { + Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot); + + pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale; + pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale; + pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale; + + pTOutVert->u = pTInVert->u + (pTNext->u - pTInVert->u) * Scale; + pTOutVert->v = pTInVert->v + (pTNext->v - pTInVert->v) * Scale; + + pOutVert++; + pTOutVert++; + } + + CurDot = NextDot; + CurIn = NextIn; + pInVert++; + pTInVert++; + } + + *OutVerts = pOutVert - pOut; + + if (*OutVerts < 3) + return GE_FALSE; + + return GE_TRUE; +} + +//================================================================================ +// Frustum_ClipToPlaneUVTGB +// Clips X, Y, u, v, r, g, b +//================================================================================ +geBoolean Frustum_ClipToPlaneUVRGB(GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + Surf_TexVert *pTIn, Surf_TexVert *pTOut, + int32 NumVerts, int32 *OutVerts) +{ + int32 i, NextVert, CurIn, NextIn; + geFloat CurDot, NextDot, Scale; + geVec3d *pInVert, *pOutVert, *pNext; + Surf_TexVert *pTInVert, *pTOutVert, *pTNext; + geVec3d *pNormal; + + pNormal = &pPlane->Normal; + pInVert = pIn; + pOutVert = pOut; + pTInVert = pTIn; + pTOutVert = pTOut; + + CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z); + CurIn = (CurDot >= pPlane->Dist); + + for (i=0 ; iX * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z); + NextIn = (NextDot >= pPlane->Dist); + + // Add a clipped vertex if one end of the current edge is + // inside the plane and the other is outside + if (CurIn != NextIn) + { + Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot); + + pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale; + pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale; + pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale; + + pTOutVert->u = pTInVert->u + (pTNext->u - pTInVert->u) * Scale; + pTOutVert->v = pTInVert->v + (pTNext->v - pTInVert->v) * Scale; + + pTOutVert->r = pTInVert->r + (pTNext->r - pTInVert->r) * Scale; + pTOutVert->g = pTInVert->g + (pTNext->g - pTInVert->g) * Scale; + pTOutVert->b = pTInVert->b + (pTNext->b - pTInVert->b) * Scale; + + pOutVert++; + pTOutVert++; + } + + CurDot = NextDot; + CurIn = NextIn; + pInVert++; + pTInVert++; + } + + *OutVerts = pOutVert - pOut; + + if (*OutVerts < 3) + return GE_FALSE; + + return GE_TRUE; +} + +//================================================================================ +// Frustum_ClipToPlaneUVTGB +// Clips X, Y, u, v, r, g, b, a +//================================================================================ +geBoolean Frustum_ClipToPlaneUVRGBA(GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + Surf_TexVert *pTIn, Surf_TexVert *pTOut, + int32 NumVerts, int32 *OutVerts) +{ + int32 i, NextVert, CurIn, NextIn; + geFloat CurDot, NextDot, Scale; + geVec3d *pInVert, *pOutVert, *pNext; + Surf_TexVert *pTInVert, *pTOutVert, *pTNext; + geVec3d *pNormal; + + pNormal = &pPlane->Normal; + pInVert = pIn; + pOutVert = pOut; + pTInVert = pTIn; + pTOutVert = pTOut; + + CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z); + CurIn = (CurDot >= pPlane->Dist); + + for (i=0 ; iX * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z); + NextIn = (NextDot >= pPlane->Dist); + + // Add a clipped vertex if one end of the current edge is + // inside the plane and the other is outside + if (CurIn != NextIn) + { + Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot); + + pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale; + pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale; + pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale; + + pTOutVert->u = pTInVert->u + (pTNext->u - pTInVert->u) * Scale; + pTOutVert->v = pTInVert->v + (pTNext->v - pTInVert->v) * Scale; + + pTOutVert->r = pTInVert->r + (pTNext->r - pTInVert->r) * Scale; + pTOutVert->g = pTInVert->g + (pTNext->g - pTInVert->g) * Scale; + pTOutVert->b = pTInVert->b + (pTNext->b - pTInVert->b) * Scale; + pTOutVert->a = pTInVert->a + (pTNext->a - pTInVert->a) * Scale; + + pOutVert++; + pTOutVert++; + } + + CurDot = NextDot; + CurIn = NextIn; + pInVert++; + pTInVert++; + } + + *OutVerts = pOutVert - pOut; + + if (*OutVerts < 3) + return GE_FALSE; + + return GE_TRUE; +} + +//================================================================================ +// Frustum_ClipToPlaneRGB +// Clips X, Y, r, g, b +//================================================================================ +geBoolean Frustum_ClipToPlaneRGB( GFX_Plane *pPlane, + geVec3d *pIn, geVec3d *pOut, + Surf_TexVert *pTIn, Surf_TexVert *pTOut, + int32 NumVerts, int32 *OutVerts) +{ + int32 i, NextVert, CurIn, NextIn; + geFloat CurDot, NextDot, Scale; + geVec3d *pInVert, *pOutVert, *pNext; + Surf_TexVert *pTInVert, *pTOutVert, *pTNext; + geVec3d *pNormal; + + pNormal = &pPlane->Normal; + pInVert = pIn; + pOutVert = pOut; + pTInVert = pTIn; + pTOutVert = pTOut; + + CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z); + CurIn = (CurDot >= pPlane->Dist); + + for (i=0 ; iX * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z); + NextIn = (NextDot >= pPlane->Dist); + + // Add a clipped vertex if one end of the current edge is + // inside the plane and the other is outside + if (CurIn != NextIn) + { + Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot); + + pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale; + pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale; + pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale; + + pTOutVert->r = pTInVert->r + (pTNext->r - pTInVert->r) * Scale; + pTOutVert->g = pTInVert->g + (pTNext->g - pTInVert->g) * Scale; + pTOutVert->b = pTInVert->b + (pTNext->b - pTInVert->b) * Scale; + + pOutVert++; + pTOutVert++; + } + + CurDot = NextDot; + CurIn = NextIn; + pInVert++; + pTInVert++; + } + + *OutVerts = pOutVert - pOut; + + if (*OutVerts < 3) + return GE_FALSE; + + return GE_TRUE; +} + +//================================================================================ +// Frustum_Project +//================================================================================ +void Frustum_Project(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera) +{ + int32 i; + geVec3d Out; + + assert( pIn != NULL); + assert( pTIn != NULL); + assert( pOut != NULL); + assert( Camera != NULL); + + for (i=0; ix = Out.X; + pOut->y = Out.Y; + pOut->z = Out.Z; + pOut->u = pTIn->u; + pOut->v = pTIn->v; + + pOut++; + pTIn++; + } +} + +//================================================================================ +// Frustum_Project +//================================================================================ +void Frustum_ProjectRGB(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera) +{ + int32 i; + geVec3d Out; + + assert( pIn != NULL); + assert( pTIn != NULL); + assert( pOut != NULL); + assert( Camera != NULL); + + for (i=0; ix = Out.X; + pOut->y = Out.Y; + pOut->z = Out.Z; + + pOut->u = pTIn->u; + pOut->v = pTIn->v; + pOut->r = pTIn->r; + pOut->g = pTIn->g; + pOut->b = pTIn->b; + + pOut++; + pTIn++; + } +} + +//================================================================================ +// Frustum_Project +//================================================================================ +void Frustum_ProjectRGBA(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera) +{ + int32 i; + geVec3d Out; + assert( pIn != NULL); + assert( pTIn != NULL); + assert( pOut != NULL); + assert( Camera != NULL); + + for (i=0; ix = Out.X; + pOut->y = Out.Y; + pOut->z = Out.Z; + pOut->u = pTIn->u; + pOut->v = pTIn->v; + pOut->r = pTIn->r; + pOut->g = pTIn->g; + pOut->b = pTIn->b; + pOut->a = pTIn->a; + + pOut++; + pTIn++; + } +} + +//================================================================================ +// Frustum_Project +//================================================================================ +void Frustum_ProjectRGBNoClamp(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera) +{ + int32 i; + geVec3d Out; + assert( pIn != NULL); + assert( pTIn != NULL); + assert( pOut != NULL); + assert( Camera != NULL); + + for (i=0; ix = Out.X; + pOut->y = Out.Y; + pOut->z = Out.Z; + + pOut->u = pTIn->u; + pOut->v = pTIn->v; + pOut->r = pTIn->r; + pOut->g = pTIn->g; + pOut->b = pTIn->b; + + pOut++; + pTIn++; + } +} + +//================================================================================ +// Frustum_PointsInFrustum +//================================================================================ +geBoolean Frustum_PointsInFrustum(const geVec3d *Pin, const GFX_Plane *Plane, int32 NumVerts, int32 *c) +{ + int32 Count, i; + + Count = 0; + + for (i=0; i< NumVerts; i++) + { + if (geVec3d_DotProduct(Pin, &Plane->Normal) >= Plane->Dist) + Count++; + + Pin++; + } + + *c += Count; + + return Count; +} + +//================================================================================ +// Frustum_PointInFrustum +//================================================================================ +geBoolean Frustum_PointInFrustum(const Frustum_Info *Fi, const geVec3d *Point, geFloat Radius) +{ + int32 i; + const GFX_Plane *Plane; + geFloat Dist; + + Plane = Fi->Planes; + + for (i=0; i< Fi->NumPlanes; i++, Plane++) + { + Dist = geVec3d_DotProduct(Point, &Plane->Normal) - Plane->Dist; + + Dist += Radius; + + if (Dist < 0) // Behind plane + return GE_FALSE; + + } + + return GE_TRUE; +} + +//================================================================================ +// Frustum_ClipAllPlanesL (CB added) +//================================================================================ +geBoolean Frustum_ClipAllPlanesL(const Frustum_Info * Fi,uint32 ClipFlags,GE_LVertex *Verts, int32 *pNumVerts) +{ +uint32 mask; +GE_LVertex WorkVerts[32]; +GE_LVertex *p1,*p2,*p3; +GFX_Plane * FPlane; + + p1 = Verts; + p2 = WorkVerts; + + FPlane = (GFX_Plane *)Fi->Planes; + + for(mask=1; mask <= ClipFlags; mask += mask, FPlane++) + { + if ( ! (ClipFlags & mask) ) + continue; + + if (!Frustum_ClipToPlaneL(FPlane, p1,p2, *pNumVerts,pNumVerts) ) + return GE_FALSE; + + if ( (*pNumVerts) < 3 || (*pNumVerts) > 30 ) + return GE_FALSE; + + p3 = p1; + p1 = p2; + p2 = p3; + } + + if ( p1 != Verts ) + { + memcpy(Verts,p1,sizeof(GE_LVertex)*(*pNumVerts)); + } + +return GE_TRUE; +} + +//================================================================================ +// Frustum_ClipToPlaneL (CB added) +//================================================================================ +geBoolean Frustum_ClipToPlaneL(GFX_Plane *pPlane, + GE_LVertex *pIn, GE_LVertex *pOut, + int32 NumVerts, int32 *NumOutVerts) +{ + int32 i, NextVert, CurIn, NextIn; + geFloat CurDot, NextDot, Scale; + GE_LVertex *pInVert, *pOutVert, *pNext; + geVec3d *pNormal; + + pNormal = &pPlane->Normal; + pInVert = pIn; + pOutVert = pOut; + + CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z); + CurIn = (CurDot >= pPlane->Dist); + + for (i=0 ; iX * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z); + NextIn = (NextDot >= pPlane->Dist); + + // Add a clipped vertex if one end of the current edge is + // inside the plane and the other is outside + if (CurIn != NextIn) + { + Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot); + + pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale; + pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale; + pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale; + + pOutVert->u = pInVert->u + (pNext->u - pInVert->u) * Scale; + pOutVert->v = pInVert->v + (pNext->v - pInVert->v) * Scale; + + pOutVert->r = pInVert->r + (pNext->r - pInVert->r) * Scale; + pOutVert->g = pInVert->g + (pNext->g - pInVert->g) * Scale; + pOutVert->b = pInVert->b + (pNext->b - pInVert->b) * Scale; + pOutVert->a = pInVert->a + (pNext->a - pInVert->a) * Scale; + + pOutVert++; + } + + CurDot = NextDot; + CurIn = NextIn; + pInVert++; + } + + *NumOutVerts = ((uint32)pOutVert - (uint32)pOut)/sizeof(*pOut); + + if ( *NumOutVerts < 3) + return GE_FALSE; + +return GE_TRUE; +} + diff --git a/G3D/World/Gbspfile.c b/G3D/World/Gbspfile.c new file mode 100644 index 0000000..78e20b0 --- /dev/null +++ b/G3D/World/Gbspfile.c @@ -0,0 +1,617 @@ +/****************************************************************************************/ +/* GBSPFile.c */ +/* */ +/* Author: John Pollard */ +/* Description: BSP loader */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "GBSPFile.h" +#include "Vec3d.h" +#include "Ram.h" +#include "System.h" + +#include "ErrorLog.h" +#include "VFile.h" + +static geBoolean LoadMotions(GBSP_BSPData *BSP, geVFile *f) +{ + char KeyS[100], ValueS[100]; + char line[200]; + int32 NumMotions, ModelNum, i; + GFX_Model *Models; + + if (geVFile_GetS(f, line, sizeof(line)) == GE_FALSE) + goto fail; + + if (sscanf(line, "%s %s\n", KeyS, ValueS) != 2) + goto fail; + + if (strcmp(KeyS, "Genesis_Motion_File")) + goto fail; + + if (geVFile_GetS(f, line, sizeof(line)) == GE_FALSE) + goto fail; + + if (sscanf(line, "%s %i\n", KeyS, &NumMotions) != 2) + goto fail; + + if (strcmp(KeyS, "NumMotions")) + goto fail; + + Models = BSP->GFXModels; + + for (i=0; i< NumMotions; i++) + { + if (geVFile_GetS(f, line, sizeof(line)) == GE_FALSE) + goto fail; + + if (sscanf(line, "%s %i\n", KeyS, &ModelNum) != 2) + goto fail; + + if (strcmp(KeyS, "ModelNum")) + goto fail; + + Models[ModelNum].Motion = geMotion_CreateFromFile(f); + + if (!Models[ModelNum].Motion) + goto fail; + } + + return GE_TRUE; + +fail: + geErrorLog_Add(GE_ERR_INVALID_MODEL_MOTION_FILE, NULL); + return GE_FALSE; +} + +//======================================================================================== +// ReadChunkData +//======================================================================================== +static geBoolean ReadChunkData(GBSP_Chunk *Chunk, void *Data, geVFile *f) +{ + return geVFile_Read(f, Data, Chunk->Size * Chunk->Elements); +} + +//======================================================================================== +// ReadChunk +//======================================================================================== +static geBoolean ReadChunk(GBSP_BSPData *BSP, GBSP_Chunk *Chunk, geVFile *f) +{ + int i; + + if (geVFile_Read(f, Chunk, sizeof(GBSP_Chunk)) == GE_FALSE) + { + return GE_FALSE; + } + + switch(Chunk->Type) + { + case GBSP_CHUNK_HEADER: + { +// printf("GBSP_CHUNK_HEADER\n"); + if (sizeof(GBSP_Header) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + if (!ReadChunkData(Chunk, (void*)&BSP->GBSPHeader, f)) + return GE_FALSE; + if (strcmp(BSP->GBSPHeader.TAG, "GBSP")) + { + geErrorLog_Add(GE_ERR_INVALID_BSP_TAG, NULL); + return GE_FALSE; + } + if (BSP->GBSPHeader.Version != GBSP_VERSION) + { + geErrorLog_Add(GE_ERR_INVALID_BSP_VERSION, NULL); + return GE_FALSE; + } + break; + } + case GBSP_CHUNK_MODELS: + { +// printf("GBSP_CHUNK_MODELS\n"); + if (sizeof(GFX_Model) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXModels = Chunk->Elements; + BSP->GFXModels = GE_RAM_ALLOCATE_ARRAY(GFX_Model, BSP->NumGFXModels); + if (!ReadChunkData(Chunk, (void*)BSP->GFXModels, f)) + return GE_FALSE; + // Walk the models and zero out the motion pointers + for (i = 0; i < BSP->NumGFXModels; i++) + BSP->GFXModels[i].Motion = NULL; + break; + } + case GBSP_CHUNK_NODES: + { +// printf("GBSP_CHUNK_NODES\n"); + if (sizeof(GFX_Node) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXNodes = Chunk->Elements; + BSP->GFXNodes = (GFX_Node*)geRam_Allocate(sizeof(GFX_Node)*BSP->NumGFXNodes); + if (!ReadChunkData(Chunk, (void*)BSP->GFXNodes, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_BNODES: + { +// printf("GBSP_CHUNK_BNODES\n"); + if (sizeof(GFX_BNode) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXBNodes = Chunk->Elements; + if (BSP->NumGFXBNodes) + { + BSP->GFXBNodes = (GFX_BNode*)geRam_Allocate(sizeof(GFX_BNode)*BSP->NumGFXBNodes); + if (!ReadChunkData(Chunk, (void*)BSP->GFXBNodes, f)) + return GE_FALSE; + } + break; + } + case GBSP_CHUNK_LEAFS: + { +// printf("GBSP_CHUNK_LEAFS\n"); + if (sizeof(GFX_Leaf) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXLeafs = Chunk->Elements; + BSP->GFXLeafs = (GFX_Leaf*)geRam_Allocate(sizeof(GFX_Leaf)*BSP->NumGFXLeafs); + if (!ReadChunkData(Chunk, (void*)BSP->GFXLeafs, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_CLUSTERS: + { +// printf("GBSP_CHUNK_CLUSTERS\n"); + if (sizeof(GFX_Cluster) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXClusters = Chunk->Elements; + //BSP->GFXClusters = GE_RAM_ALLOCATE_ARRAY(GFX_Cluster, BSP->NumGFXClusters); + BSP->GFXClusters = (GFX_Cluster*)geRam_Allocate(sizeof(GFX_Cluster)*BSP->NumGFXClusters); + if (!ReadChunkData(Chunk, (void*)BSP->GFXClusters, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_AREAS: + { +// printf("GBSP_CHUNK_AREAS\n"); + if (sizeof(GFX_Area) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXAreas = Chunk->Elements; + BSP->GFXAreas = GE_RAM_ALLOCATE_ARRAY(GFX_Area, BSP->NumGFXAreas); + if (!ReadChunkData(Chunk, BSP->GFXAreas, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_AREA_PORTALS: + { +// printf("GBSP_CHUNK_AREA_PORTALS\n"); + if (sizeof(GFX_AreaPortal) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXAreaPortals = Chunk->Elements; + BSP->GFXAreaPortals = GE_RAM_ALLOCATE_ARRAY(GFX_AreaPortal, BSP->NumGFXAreaPortals); + if (!ReadChunkData(Chunk, BSP->GFXAreaPortals, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_PORTALS: + { +// printf("GBSP_CHUNK_PORTALS\n"); + if (sizeof(GFX_Portal) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXPortals = Chunk->Elements; + BSP->GFXPortals = (GFX_Portal*)geRam_Allocate(sizeof(GFX_Portal)*BSP->NumGFXPortals); + if (!ReadChunkData(Chunk, (void*)BSP->GFXPortals, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_PLANES: + { +// printf("GBSP_CHUNK_PLANES\n"); + if (sizeof(GFX_Plane) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXPlanes = Chunk->Elements; + BSP->GFXPlanes = (GFX_Plane*)geRam_Allocate(sizeof(GFX_Plane)*BSP->NumGFXPlanes); + if (!ReadChunkData(Chunk, (void*)BSP->GFXPlanes, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_FACES: + { +// printf("GBSP_CHUNK_FACES\n"); + if (sizeof(GFX_Face) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXFaces = Chunk->Elements; + BSP->GFXFaces = (GFX_Face*)geRam_Allocate(sizeof(GFX_Face)*BSP->NumGFXFaces); + if (!ReadChunkData(Chunk, (void*)BSP->GFXFaces, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_LEAF_FACES: + { +// printf("GBSP_CHUNK_LEAF_FACES\n"); + if (sizeof(int32) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXLeafFaces = Chunk->Elements; + BSP->GFXLeafFaces = (int32*)geRam_Allocate(sizeof(int32)*BSP->NumGFXLeafFaces); + if (!ReadChunkData(Chunk, (void*)BSP->GFXLeafFaces, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_LEAF_SIDES: + { +// printf("GBSP_CHUNK_LEAF_SIDES\n"); + if (sizeof(GFX_LeafSide) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXLeafSides = Chunk->Elements; + BSP->GFXLeafSides = (GFX_LeafSide*)geRam_Allocate(sizeof(GFX_LeafSide)*BSP->NumGFXLeafSides); + if (!ReadChunkData(Chunk, (void*)BSP->GFXLeafSides, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_VERTS: + { +// printf("GBSP_CHUNK_VERTS\n"); + if (sizeof(geVec3d) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXVerts = Chunk->Elements; + BSP->GFXVerts = (geVec3d*)geRam_Allocate(sizeof(geVec3d)*BSP->NumGFXVerts); + if (!ReadChunkData(Chunk, (void*)BSP->GFXVerts, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_VERT_INDEX: + { +// printf("GBSP_CHUNK_VERT_INDEX\n"); + if (sizeof(int32) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + + BSP->NumGFXVertIndexList = Chunk->Elements; + BSP->GFXVertIndexList = (int32*)geRam_Allocate(sizeof(int32)*BSP->NumGFXVertIndexList); + if (!ReadChunkData(Chunk, (void*)BSP->GFXVertIndexList, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_RGB_VERTS: + { +// printf("GBSP_CHUNK_RGB_VERTS\n"); + if (sizeof(geVec3d) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXRGBVerts = Chunk->Elements; + BSP->GFXRGBVerts = (geVec3d*)geRam_Allocate(sizeof(geVec3d)*BSP->NumGFXRGBVerts); + if (!ReadChunkData(Chunk, (void*)BSP->GFXRGBVerts, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_TEXINFO: + { +// printf("GBSP_CHUNK_TEXINFO\n"); + if (sizeof(GFX_TexInfo) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXTexInfo = Chunk->Elements; + BSP->GFXTexInfo = (GFX_TexInfo*)geRam_Allocate(sizeof(GFX_TexInfo)*BSP->NumGFXTexInfo); + if (!ReadChunkData(Chunk, (void*)BSP->GFXTexInfo, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_TEXTURES: + { +// printf("GBSP_CHUNK_TEXTURES\n"); + if (sizeof(GFX_Texture) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXTextures = Chunk->Elements; + BSP->GFXTextures = (GFX_Texture*)geRam_Allocate(sizeof(GFX_Texture)*BSP->NumGFXTextures); + if (!ReadChunkData(Chunk, (void*)BSP->GFXTextures, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_TEXDATA: + { +// printf("GBSP_CHUNK_TEXDATA\n"); + if (sizeof(uint8) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXTexData = Chunk->Elements; + BSP->GFXTexData = (uint8*)geRam_Allocate(sizeof(uint8)*BSP->NumGFXTexData); + if (!ReadChunkData(Chunk, (void*)BSP->GFXTexData, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_ENTDATA: + { +// printf("GBSP_CHUNK_ENTDATA\n"); + if (sizeof(uint8) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXEntData = Chunk->Elements; + BSP->GFXEntData = (uint8*)geRam_Allocate(sizeof(uint8)*BSP->NumGFXEntData); + if (!ReadChunkData(Chunk, (void*)BSP->GFXEntData, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_LIGHTDATA: + { +// printf("GBSP_CHUNK_LIGHTDATA\n"); + if (sizeof(uint8) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXLightData = Chunk->Elements; + BSP->GFXLightData = (uint8*)geRam_Allocate(sizeof(uint8)*BSP->NumGFXLightData); + if (!ReadChunkData(Chunk, (void*)BSP->GFXLightData, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_VISDATA: + { +// printf("GBSP_CHUNK_VISDATA\n"); + if (sizeof(uint8) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXVisData = Chunk->Elements; + BSP->GFXVisData = (uint8*)geRam_Allocate(sizeof(uint8)*BSP->NumGFXVisData); + if (!ReadChunkData(Chunk, (void*)BSP->GFXVisData, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_SKYDATA: + { +// printf("GBSP_CHUNK_SKYDATA\n"); + if (sizeof(GFX_SkyData) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + if (!ReadChunkData(Chunk, (void*)&BSP->GFXSkyData, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_PALETTES: + { +// printf("GBSP_CHUNK_PALETTES\n"); + if (sizeof(DRV_Palette) != Chunk->Size) + { + geErrorLog_Add(GE_ERR_BAD_BSP_FILE_CHUNK_SIZE, NULL); + return GE_FALSE; + } + BSP->NumGFXPalettes = Chunk->Elements; + BSP->GFXPalettes = (DRV_Palette*)geRam_Allocate(sizeof(DRV_Palette)*BSP->NumGFXPalettes); + if (BSP->GFXPalettes == NULL) + return GE_FALSE; + if (!ReadChunkData(Chunk, (void*)BSP->GFXPalettes, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_MOTIONS: + { +// printf("GBSP_CHUNK_MOTIONS\n"); + return LoadMotions(BSP, f); + } + + case GBSP_CHUNK_END: + { +// printf("GBSP_CHUNK_END\n"); + break; + } + default: +// printf("Don't know what this chunk is\n"); + return GE_FALSE; + } + + return TRUE; +} + +//======================================================================================== +// GBSP_LoadGBSPFile +//======================================================================================== +BOOL GBSP_LoadGBSPFile(geVFile *File, GBSP_BSPData *BSP) +{ + GBSP_Chunk Chunk; + + assert(File); + assert(BSP); + + while (1) + { + if (!ReadChunk(BSP, &Chunk, File)) + { + geErrorLog_Add(GE_ERR_ERROR_READING_BSP_CHUNK, NULL); + return GE_FALSE; + } + + if (Chunk.Type == GBSP_CHUNK_END) + break; + } + + return TRUE; +} + +//======================================================================================== +// GBSP_FreeGBSPFile +//======================================================================================== +BOOL GBSP_FreeGBSPFile(GBSP_BSPData *BSP) +{ + if (BSP->GFXModels) + { + int i; + for (i = 0; i < BSP->NumGFXModels; i++) + if (BSP->GFXModels[i].Motion != NULL) + geMotion_Destroy(&(BSP->GFXModels[i].Motion)); + geRam_Free(BSP->GFXModels); + } + + if (BSP->GFXNodes) + geRam_Free(BSP->GFXNodes); + if (BSP->GFXBNodes) + geRam_Free(BSP->GFXBNodes); + if (BSP->GFXLeafs) + geRam_Free(BSP->GFXLeafs); + if (BSP->GFXClusters) + geRam_Free(BSP->GFXClusters); + if (BSP->GFXAreas) + geRam_Free(BSP->GFXAreas); + if (BSP->GFXAreaPortals) + geRam_Free(BSP->GFXAreaPortals); + if (BSP->GFXPortals) + geRam_Free(BSP->GFXPortals); + if (BSP->GFXPlanes) + geRam_Free(BSP->GFXPlanes); + if (BSP->GFXFaces) + geRam_Free(BSP->GFXFaces); + if (BSP->GFXLeafFaces) + geRam_Free(BSP->GFXLeafFaces); + if (BSP->GFXLeafSides) + geRam_Free(BSP->GFXLeafSides); + if (BSP->GFXVerts) + geRam_Free(BSP->GFXVerts); + if (BSP->GFXVertIndexList) + geRam_Free(BSP->GFXVertIndexList); + if (BSP->GFXRGBVerts) + geRam_Free(BSP->GFXRGBVerts); + if (BSP->GFXTextures) + geRam_Free(BSP->GFXTextures); + if (BSP->GFXTexInfo) + geRam_Free(BSP->GFXTexInfo); + if (BSP->GFXTexData) + geRam_Free(BSP->GFXTexData); + if (BSP->GFXPalettes) + geRam_Free(BSP->GFXPalettes); + if (BSP->GFXEntData) + geRam_Free(BSP->GFXEntData); + if (BSP->GFXLightData) + geRam_Free(BSP->GFXLightData); + if (BSP->GFXVisData) + geRam_Free(BSP->GFXVisData); + + BSP->GFXModels = NULL; + BSP->GFXNodes = NULL; + BSP->GFXBNodes = NULL; + BSP->GFXLeafs = NULL; + BSP->GFXClusters = NULL; + BSP->GFXAreas = NULL; + BSP->GFXAreaPortals = NULL; + BSP->GFXPlanes = NULL; + BSP->GFXFaces = NULL; + BSP->GFXLeafFaces = NULL; + BSP->GFXLeafSides = NULL; + BSP->GFXVerts = NULL; + BSP->GFXVertIndexList = NULL; + BSP->GFXRGBVerts = NULL; + BSP->GFXEntData = NULL; + + BSP->GFXTextures = NULL; + BSP->GFXTexInfo = NULL; + BSP->GFXTexData = NULL; + BSP->GFXPalettes = NULL; + + BSP->GFXLightData = NULL; + BSP->GFXVisData = NULL; + BSP->GFXPortals = NULL; + + BSP->NumGFXModels = 0; + BSP->NumGFXNodes = 0; + BSP->NumGFXBNodes = 0; + BSP->NumGFXLeafs = 0; + BSP->NumGFXClusters = 0; + BSP->NumGFXAreas = 0; + BSP->NumGFXAreaPortals = 0; + BSP->NumGFXPlanes = 0; + BSP->NumGFXFaces = 0; + BSP->NumGFXLeafFaces = 0; + BSP->NumGFXLeafSides = 0; + BSP->NumGFXVerts = 0; + BSP->NumGFXVertIndexList = 0; + BSP->NumGFXRGBVerts = 0; + + BSP->NumGFXEntData = 0; + BSP->NumGFXTexInfo = 0; + BSP->NumGFXTextures = 0; + BSP->NumGFXTexData = 0; + + BSP->NumGFXLightData = 0; + BSP->NumGFXVisData = 0; + BSP->NumGFXPortals = 0; + + return TRUE; +} + diff --git a/G3D/World/Gbspfile.h b/G3D/World/Gbspfile.h new file mode 100644 index 0000000..ae4f407 --- /dev/null +++ b/G3D/World/Gbspfile.h @@ -0,0 +1,355 @@ +/****************************************************************************************/ +/* GBSPFile.h */ +/* */ +/* Author: John Pollard */ +/* Description: BSP loader */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_GBSPFILE_H +#define GE_GBSPFILE_H + +#include + +#include "BaseType.h" +#include "Vec3d.h" +#include +#include "DCommon.h" +#include "VFile.h" +#include "Motion.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GBSP_VERSION 15 + +#define GBSP_CHUNK_HEADER 0 + +#define GBSP_CHUNK_MODELS 1 +#define GBSP_CHUNK_NODES 2 +#define GBSP_CHUNK_BNODES 3 +#define GBSP_CHUNK_LEAFS 4 +#define GBSP_CHUNK_CLUSTERS 5 +#define GBSP_CHUNK_AREAS 6 +#define GBSP_CHUNK_AREA_PORTALS 7 +#define GBSP_CHUNK_LEAF_SIDES 8 +#define GBSP_CHUNK_PORTALS 9 +#define GBSP_CHUNK_PLANES 10 +#define GBSP_CHUNK_FACES 11 +#define GBSP_CHUNK_LEAF_FACES 12 +#define GBSP_CHUNK_VERT_INDEX 13 +#define GBSP_CHUNK_VERTS 14 +#define GBSP_CHUNK_RGB_VERTS 15 +#define GBSP_CHUNK_ENTDATA 16 + +#define GBSP_CHUNK_TEXINFO 17 +#define GBSP_CHUNK_TEXTURES 18 +#define GBSP_CHUNK_TEXDATA 19 + +#define GBSP_CHUNK_LIGHTDATA 20 +#define GBSP_CHUNK_VISDATA 21 +#define GBSP_CHUNK_SKYDATA 22 +#define GBSP_CHUNK_PALETTES 23 +#define GBSP_CHUNK_MOTIONS 24 + +#define GBSP_CHUNK_END 0xffff + +#ifndef GE_CONTENTS_TYPES +#define GE_CONTENTS_TYPES + +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= +// IF THESE FLAGS CHANGE, THEY MUST CHANGE IN GBSPFILE.H in Genesis AND GBSPLIB, and Genesis.H!!!!! +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= +#define GE_CONTENTS_SOLID (1<<0) // Solid (Visible) +#define GE_CONTENTS_WINDOW (1<<1) // Window (Visible) +#define GE_CONTENTS_EMPTY (1<<2) // Empty but Visible (water, lava, etc...) + +#define GE_CONTENTS_TRANSLUCENT (1<<3) // Vis will see through it +#define GE_CONTENTS_WAVY (1<<4) // Wavy (Visible) +#define GE_CONTENTS_DETAIL (1<<5) // Won't be included in vis oclusion + +#define GE_CONTENTS_CLIP (1<<6) // Structural but not visible +#define GE_CONTENTS_HINT (1<<7) // Primary splitter (Non-Visible) +#define GE_CONTENTS_AREA (1<<8) // Area seperator leaf (Non-Visible) + +#define GE_CONTENTS_FLOCKING (1<<9) +#define GE_CONTENTS_SHEET (1<<10) +#define GE_RESERVED3 (1<<11) +#define GE_RESERVED4 (1<<12) +#define GE_RESERVED5 (1<<13) +#define GE_RESERVED6 (1<<14) +#define GE_RESERVED7 (1<<15) + +// 16-31 reserved for user contents +#define GE_CONTENTS_USER1 (1<<16) +#define GE_CONTENTS_USER2 (1<<17) +#define GE_CONTENTS_USER3 (1<<18) +#define GE_CONTENTS_USER4 (1<<19) +#define GE_CONTENTS_USER5 (1<<20) +#define GE_CONTENTS_USER6 (1<<21) +#define GE_CONTENTS_USER7 (1<<22) +#define GE_CONTENTS_USER8 (1<<23) +#define GE_CONTENTS_USER9 (1<<24) +#define GE_CONTENTS_USER10 (1<<25) +#define GE_CONTENTS_USER11 (1<<26) +#define GE_CONTENTS_USER12 (1<<27) +#define GE_CONTENTS_USER13 (1<<28) +#define GE_CONTENTS_USER14 (1<<29) +#define GE_CONTENTS_USER15 (1<<30) +#define GE_CONTENTS_USER16 (1<<31) +// 16-31 reserved for user contents + + +// These contents are all solid types +#define GE_CONTENTS_SOLID_CLIP (GE_CONTENTS_SOLID | GE_CONTENTS_WINDOW | GE_CONTENTS_CLIP) +#define GE_CONTENTS_CANNOT_OCCUPY GE_CONTENTS_SOLID_CLIP + +// These contents are all visible types +#define GE_VISIBLE_CONTENTS ( GE_CONTENTS_SOLID | \ + GE_CONTENTS_EMPTY | \ + GE_CONTENTS_WINDOW | \ + GE_CONTENTS_WAVY) + +#endif + +#define BSP_CONTENTS_SOLID -1 +#define BSP_CONTENTS_EMPTY -2 + +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 +#define PLANE_ANY 6 + +typedef struct +{ + int32 Type; // Type of chunk + int32 Size; // Size of each element + int32 Elements; // Number of elements +} GBSP_Chunk; + +typedef struct +{ + int32 Type; + int32 Size; + int32 Elements; + void *Data; +} GBSP_ChunkData; + +typedef struct +{ + char TAG[5]; // 'G','B','S','P','0' + int32 Version; + SYSTEMTIME BSPTime; +} GBSP_Header; + +typedef struct +{ + geVec3d Axis; // Axis of rotation + geFloat Dpm; // Degres per minute + int32 Textures[6]; // Texture indexes for all six sides... + geFloat DrawScale; +} GFX_SkyData; + +typedef struct +{ + geVec3d Normal; + geFloat Dist; + int32 Type; // Defined in MathLib.h (PLANE_X, PLANE_Y, etc...) +} GFX_Plane; + +typedef struct +{ + int32 Children[2]; // Children, indexed into GFXNodes, < 0 = Leaf + int32 NumFaces; // Num faces + int32 FirstFace; // First face + int32 PlaneNum; // + geVec3d Mins; // For BBox frustum culling + geVec3d Maxs; +} GFX_Node; + +typedef struct +{ + int32 Children[2]; // Children, indexed into GFXBNodes, < 0 = Contents + int32 PlaneNum; // + //int32 PlaneSide; +} GFX_BNode; + +typedef struct +{ + int32 ModelNum; + int32 Area; +} GFX_AreaPortal; + +typedef struct +{ + int32 NumAreaPortals; + int32 FirstAreaPortal; +} GFX_Area; + +typedef struct +{ + int32 Contents; // Contents of leaf + geVec3d Mins; // For BBox vis testing + geVec3d Maxs; + int32 FirstFace; // First face in GFXLeafFaces + int32 NumFaces; + int32 FirstPortal; // Number of portals + int32 NumPortals; // First portal + + int32 Cluster; // Cluster area for this leaf + int32 Area; // -1 = Area, 0 = Solid > 0 = Area number + + int32 FirstSide; // Beveled sides for BBox collisions + int32 NumSides; +} GFX_Leaf; + +typedef struct +{ + int32 VisOfs; +} GFX_Cluster; + +typedef struct +{ + int32 PlaneNum; + int32 PlaneSide; +} GFX_LeafSide; + +typedef struct +{ + int32 FirstVert; // First vertex indexed in GFXVertices + int32 NumVerts; // Number of vertices in face + int32 PlaneNum; // PlaneNum + int32 PlaneSide; // 0 = Same direction of plane normal + int32 TexInfo; + int32 LightOfs; // Offset info GFXLightData, -1 = No light + int32 LWidth; // Lightmap width + int32 LHeight; // Lightmap height + uint8 LTypes[4]; +} GFX_Face; + +typedef struct +{ + int32 RootNode[2]; // Top level Node in GFXNodes/GFXBNodes + geVec3d Mins; + geVec3d Maxs; + geVec3d Origin; + int32 FirstFace; // First face in GFXFaces + int32 NumFaces; // Number of faces + int32 FirstLeaf; // First leaf in GFXLeafs; + int32 NumLeafs; // Number of leafs (including solid leafs) + int32 FirstCluster; // First leaf cluster ijn GFXCLusters + int32 NumClusters; // Number of clusters in this model + int32 Areas[2]; + geMotion * Motion; +} GFX_Model; + +typedef struct +{ + char Name[32]; + uint32 Flags; + int32 Width; + int32 Height; + int32 Offset; + int32 PaletteIndex; +} GFX_Texture; + +typedef struct +{ + geVec3d Vecs[2]; + geFloat Shift[2]; + geFloat DrawScale[2]; + int32 Flags; + geFloat FaceLight; // Used in radiosity satge only (remove?) + geFloat ReflectiveScale; + geFloat Alpha; + geFloat MipMapBias; + int32 Texture; +} GFX_TexInfo; + +typedef struct +{ + geVec3d Origin; // Center of portal + int32 LeafTo; // Leaf looking into +} GFX_Portal; + +typedef struct +{ + GBSP_Header GBSPHeader; // Header + GFX_SkyData GFXSkyData; // Sky data + GFX_Model *GFXModels; // Model data + GFX_Node *GFXNodes; // Nodes + GFX_BNode *GFXBNodes; // Bevel Clip Nodes + GFX_Leaf *GFXLeafs; // Leafs + GFX_Cluster *GFXClusters; + GFX_Area *GFXAreas; + GFX_AreaPortal *GFXAreaPortals; + GFX_Plane *GFXPlanes; // Planes + GFX_Face *GFXFaces; // Faces + int32 *GFXLeafFaces; + GFX_LeafSide *GFXLeafSides; + geVec3d *GFXVerts; // Verts + int32 *GFXVertIndexList; // Index list + geVec3d *GFXRGBVerts; // RGBVerts + + uint8 *GFXEntData; + GFX_Texture *GFXTextures; // Textures + GFX_TexInfo *GFXTexInfo; // TexInfo + uint8 *GFXTexData; // TexData + DRV_Palette *GFXPalettes; // Texture palettes + + uint8 *GFXLightData; // Lightmap data + uint8 *GFXVisData; // Vis data + GFX_Portal *GFXPortals; // Portal data + + int32 NumGFXModels; + int32 NumGFXNodes; + int32 NumGFXBNodes; + int32 NumGFXLeafs; + int32 NumGFXClusters; + int32 NumGFXAreas; + int32 NumGFXAreaPortals; + int32 NumGFXPlanes; + int32 NumGFXFaces; + int32 NumGFXLeafFaces; + int32 NumGFXLeafSides; + int32 NumGFXVerts; + int32 NumGFXVertIndexList; + int32 NumGFXRGBVerts; + + int32 NumGFXEntData; + int32 NumGFXTextures; + int32 NumGFXTexInfo; + int32 NumGFXTexData; + int32 NumGFXPalettes; + + int32 NumGFXLightData; + int32 NumGFXVisData; + int32 NumGFXPortals; + +} GBSP_BSPData; + +geBoolean GBSP_LoadGBSPFile(geVFile *File, GBSP_BSPData *BSP); +geBoolean GBSP_FreeGBSPFile(GBSP_BSPData *BSP); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/World/Light.c b/G3D/World/Light.c new file mode 100644 index 0000000..905ba13 --- /dev/null +++ b/G3D/World/Light.c @@ -0,0 +1,2020 @@ +/****************************************************************************************/ +/* Light.c */ +/* */ +/* Author: John Pollard */ +/* Description: Handles lightmaps, dynamic light, fog, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "BaseType.h" +#include "Ram.h" +#include "System.h" +#include "Vec3d.h" +#include "Light.h" +#include "Surface.h" +#include "GBSPFile.h" +#include "Plane.h" +#include "World.h" + +#include "Trace.h" + +#define LIGHT_FRACT 8 +//===================================================================================== +// Local Globals +//===================================================================================== +static geEngine *CEngine = NULL; +static geWorld *CWorld = NULL; +static World_BSP *CBSP; +static GBSP_BSPData *BSPData; // This is in globals, but is also kept here for speed +static Light_LightInfo *LightInfo; +static Surf_SurfInfo *GSurfInfo; + +// Temporary light arrays, used for animating lights, and overlaying maps. +static DRV_RGB BlankRGB[MAX_LMAP_SIZE*MAX_LMAP_SIZE]; +static DRV_RGB TempRGB[MAX_LMAP_SIZE*MAX_LMAP_SIZE]; +static int32 TempRGB32[MAX_LMAP_SIZE*MAX_LMAP_SIZE*3]; +static DRV_RGB TempRGBFog[MAX_LMAP_SIZE*MAX_LMAP_SIZE]; +static int32 TempRGB32Fog[MAX_LMAP_SIZE*MAX_LMAP_SIZE*3]; + +// Fast sqrt stuff +// MOST_SIG_OFFSET gives the (int *) offset from the address of the double +// to the part of the number containing the sign and exponent. +// You will need to find the relevant offset for your architecture. + +#define MOST_SIG_OFFSET 1 + +// SQRT_TAB_SIZE - the size of the lookup table - must be a power of four. + +#define SQRT_TAB_SIZE 16384 + +// MANT_SHIFTS is the number of shifts to move mantissa into position. +// If you quadruple the table size subtract two from this constant, +// if you quarter the table size then add two. +// Valid values are: (16384, 7) (4096, 9) (1024, 11) (256, 13) + +#define MANT_SHIFTS 7 + +#define FastSqrtFloat double +#define EXP_BIAS 1023 // Exponents are always positive +#define EXP_SHIFTS 20 // Shifs exponent to least sig. bits +#define EXP_LSB (1<LightInfo = GE_RAM_ALLOCATE_STRUCT(Light_LightInfo); + + if (!World->LightInfo) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return GE_FALSE; + } + + memset(World->LightInfo, 0, sizeof(Light_LightInfo)); + + UpdateLTypeTables(World); // Update ltype tables for first frame + + return GE_TRUE; +} + +//===================================================================================== +// Light_WorldShutdown +//===================================================================================== +void Light_WorldShutdown(geWorld *World) +{ + assert(World != NULL); + + if (!World->LightInfo) + return; + + geRam_Free(World->LightInfo); + + World->LightInfo = NULL; +} + +//===================================================================================== +// Light_SetEngine +// Lets this module know that the engine has changed +//===================================================================================== +geBoolean Light_SetEngine(geEngine *Engine) +{ + assert (Engine != NULL); + + CEngine = Engine; + + return GE_TRUE; +} + +//===================================================================================== +// Light_SetWorld +// Lets this module know that the world has changed +//===================================================================================== +geBoolean Light_SetWorld(geWorld *World) +{ + assert(World != NULL); + + CWorld = World; + + LightInfo = World->LightInfo; + GSurfInfo = World->CurrentBSP->SurfInfo; + + return GE_TRUE; +} + +//===================================================================================== +// Light_SetGBSP +//===================================================================================== +geBoolean Light_SetGBSP(World_BSP *BSP) +{ + assert(BSP != NULL); + + // Make quick pointer to the world bsp data + CBSP = BSP; + BSPData = &BSP->BSPData; + + return GE_TRUE; +} + +//===================================================================================== +// Light_FogVerts +//===================================================================================== +void Light_FogVerts(const geFog *Fog, const geVec3d *POV, const geVec3d *Verts, Surf_TexVert *TexVerts, int32 NumVerts) +{ + geVec3d FogRay; + geFloat Radius, RadiusSq, FogRayDot, OneOverRadiusDotBright; + geFloat EyeDist; + int32 i; + + Radius = Fog->VolumeRadius; + RadiusSq = Fog->VolumeRadiusSquared; + OneOverRadiusDotBright = (1.0f/Radius)*Fog->VolumeBrightness; + + geVec3d_Subtract(&Fog->Pos, POV, &FogRay); + FogRayDot = geVec3d_DotProduct(&FogRay,&FogRay); + EyeDist = (geFloat)sqrt(FogRayDot); + + for (i=0; i< NumVerts; i++, Verts++, TexVerts++) + { + geVec3d Ray, Ray2, Impact1, Impact2; + geFloat DistSq, Dist, Disc, v; + geFloat t0, t1, t, VertDist, d, d2; + + geVec3d_Subtract(Verts, POV, &Ray); + geVec3d_Normalize(&Ray); + + v = geVec3d_DotProduct(&FogRay, &Ray); + + Disc = (RadiusSq) - (FogRayDot - (v*v)); + + if (Disc <= 0) + continue; + + d = (geFloat)sqrt(Disc); + + t0 = v - d; + t1 = v + d; + + if (t0 > 0) + t = t0; + else if (t1 > 0) + t = t1; + else + continue; + + geVec3d_Subtract(Verts, &Fog->Pos, &Ray2); + DistSq = geVec3d_DotProduct(&Ray2, &Ray2); + VertDist = (geFloat)sqrt(DistSq); + + if (EyeDist < Radius && VertDist < Radius) // Both inside sphere + { + Impact1 = *Verts; + Impact2 = *POV; + } + else if (EyeDist < Radius) // Eye inside + { + Impact1 = *POV; + geVec3d_AddScaled(POV, &Ray, t, &Impact2); + } + else if (VertDist < Radius) // Vert is inside + { + Impact1 = *Verts; + geVec3d_AddScaled(POV, &Ray, t, &Impact2); + } + else // Both lie outside sphere + { + geVec3d_AddScaled(POV, &Ray, t0, &Impact1); + geVec3d_AddScaled(POV, &Ray, t1, &Impact2); + geVec3d_Subtract(&Impact1, POV, &Ray); + + d2 = geVec3d_DotProduct(&Ray, &Ray); + + if (d2 > DistSq) + continue; + } + geVec3d_Subtract(&Impact1, &Impact2, &Ray); + + Dist = geVec3d_Length(&Ray)*OneOverRadiusDotBright; + + #if 1 + // Fog the Specular RGB + TexVerts->r += Dist*Fog->Color.r; + TexVerts->g += Dist*Fog->Color.g; + TexVerts->b += Dist*Fog->Color.b; + #else + TexVerts->r = 255.0f; + TexVerts->g = 255.0f; + TexVerts->b = 255.0f; + #endif + } +} + +extern int32 MirrorRecursion; // GLOBAL!!! (defined in World.c) +geVec3d GlobalEyePos = {100.0f, 0.0f, 0.0f}; + +//===================================================================================== +// FogLightmap +// This is slow, nothing has been pre-computed, but it works, and is being tested!!! +//===================================================================================== +static geBoolean FogLightmap1(geFog *Fog, int32 *LightData, GFX_Face *Face, Surf_SurfInfo *SInfo) +{ + int32 w, h; + geBoolean Hit; + geVec3d Start, UV, Ray; + int32 Light1, Light2, Light3; + geFloat Dist, d2, UVDist, DistSq; + geVec3d FogRay, Ray2; + geFloat v,disc, d; + geVec3d Impact1, Impact2; + geFloat Radius, Red, Grn, Blu, EyeDist; + geFloat RadiusSq, FogRayDot, Radius2; + geVec3d UAdd, VAdd, FogPos; + int32 Width, Height; + + Hit = GE_FALSE; + + Start = UV = SInfo->TexOrg; + + FogPos = Fog->Pos; + + geVec3d_Subtract(&FogPos, &GlobalEyePos, &FogRay); + + Ray2 = FogRay; + EyeDist = geVec3d_Normalize(&Ray2); + + Radius = Fog->VolumeRadius; + RadiusSq = Fog->VolumeRadiusSquared; + Radius2 = Fog->VolumeRadius2; + + FogRayDot = geVec3d_DotProduct(&FogRay,&FogRay); + + Red = Fog->Color.r; + Grn = Fog->Color.g; + Blu = Fog->Color.b; + + //if (EyeDist < Radius) + // return GE_FALSE; + + UAdd = SInfo->T2WVecs[0]; + VAdd = SInfo->T2WVecs[1]; + + Width = SInfo->LInfo.Width; + Height = SInfo->LInfo.Height; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + geFloat OneOver; + + Ray.X = UV.X - GlobalEyePos.X; + Ray.Y = UV.Y - GlobalEyePos.Y; + Ray.Z = UV.Z - GlobalEyePos.Z; + + DistSq = Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z; + Dist = (geFloat)FastSqrt(DistSq); + + OneOver = 1.0f / Dist; + Ray.X *= OneOver; + Ray.Y *= OneOver; + Ray.Z *= OneOver; + + v = FogRay.X*Ray.X + FogRay.Y*Ray.Y + FogRay.Z*Ray.Z; + + disc = (RadiusSq) - (FogRayDot - (v*v)); + + if (disc > 0) + { + geFloat t0, t1, t; + + d = (geFloat)FastSqrt(disc); + + t0 = v - d; + t1 = v + d; + + if (t0 > 0) + t = t0; + else if (t1 > 0) + t = t1; + else + { + *LightData++ = 0; + *LightData++ = 0; + *LightData++ = 0; + + UV.X += UAdd.X; + UV.Y += UAdd.Y; + UV.Z += UAdd.Z; + continue; + } + + #if 1 + Ray2.X = UV.X - FogPos.X; + Ray2.Y = UV.Y - FogPos.Y; + Ray2.Z = UV.Z - FogPos.Z; + + //UVDist = sqrt(Ray2.X*Ray2.X + Ray2.Y*Ray2.Y + Ray2.Z*Ray2.Z); + UVDist = (geFloat)FastSqrt(Ray2.X*Ray2.X + Ray2.Y*Ray2.Y + Ray2.Z*Ray2.Z); + + if (EyeDist < Radius && UVDist < Radius) + { + Impact1 = UV; + Impact2 = GlobalEyePos; + } + else if (EyeDist < Radius) + { + Impact1 = GlobalEyePos; + + Impact2.X = GlobalEyePos.X + t*Ray.X; + Impact2.Y = GlobalEyePos.Y + t*Ray.Y; + Impact2.Z = GlobalEyePos.Z + t*Ray.Z; + } + else if (UVDist < Radius) // UV is inside + { + Impact1 = UV; + + Impact2.X = GlobalEyePos.X + t*Ray.X; + Impact2.Y = GlobalEyePos.Y + t*Ray.Y; + Impact2.Z = GlobalEyePos.Z + t*Ray.Z; + + } + else // Both lie outside sphere + { + Impact1.X = GlobalEyePos.X + t0*Ray.X; + Impact1.Y = GlobalEyePos.Y + t0*Ray.Y; + Impact1.Z = GlobalEyePos.Z + t0*Ray.Z; + + Impact2.X = GlobalEyePos.X + t1*Ray.X; + Impact2.Y = GlobalEyePos.Y + t1*Ray.Y; + Impact2.Z = GlobalEyePos.Z + t1*Ray.Z; + + Ray.X = Impact1.X - GlobalEyePos.X; + Ray.Y = Impact1.Y - GlobalEyePos.Y; + Ray.Z = Impact1.Z - GlobalEyePos.Z; + + //d2 = sqrt(Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z); + //d2 = (geFloat)FastSqrt(Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z); + d2 = Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z; + + if (d2 > DistSq) + { + /* + Ray.X = Impact2.X - GlobalEyePos.X; + Ray.Y = Impact2.Y - GlobalEyePos.Y; + Ray.Z = Impact2.Z - GlobalEyePos.Z; + d3 = sqrt(Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z); + + if (d3 > Dist) + */ + { + *LightData++ = 0; + *LightData++ = 0; + *LightData++ = 0; + + UV.X += UAdd.X; + UV.Y += UAdd.Y; + UV.Z += UAdd.Z; + continue; + } + } + + } + #endif + // Get the distance of the part of the ray that is in the fog + //geVec3d_Subtract(&Impact1, &Impact2, &Ray); + //d = geVec3d_Length(&Ray); + Ray.X = Impact1.X - Impact2.X; + Ray.Y = Impact1.Y - Impact2.Y; + Ray.Z = Impact1.Z - Impact2.Z; + + //d = (geFloat)FastSqrt(Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z); + //d = ((Radius / d)*18); + //Dist = (Fog->VolumeBrightness) / (d*d); + d = Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z; + d = ((RadiusSq / d)*18); + Dist = (Fog->VolumeBrightness) / (d); + //Dist = 255.0f; + + Hit = GE_TRUE; + + Light1 = (int32)(Dist*Red); + Light2 = (int32)(Dist*Grn); + Light3 = (int32)(Dist*Blu); + + *LightData++ = Light1; + *LightData++ = Light2; + *LightData++ = Light3; + } + else + { + *LightData++ = 0; + *LightData++ = 0; + *LightData++ = 0; + } + + UV.X += UAdd.X; + UV.Y += UAdd.Y; + UV.Z += UAdd.Z; + + } + + Start.X += VAdd.X; + Start.Y += VAdd.Y; + Start.Z += VAdd.Z; + UV = Start; + } + + return Hit; +} + +//===================================================================================== +// FogLightmap +// This is slow, nothing has been pre-computed, but it works, and is being tested!!! +//===================================================================================== +static geBoolean FogLightmap2(geFog *Fog, int32 *LightData, GFX_Face *Face, Surf_SurfInfo *SInfo) +{ + int32 w, h; + geBoolean Hit; + geVec3d Start, UV, Ray; + int32 Light1, Light2, Light3; + geFloat Dist, d2, UVDist, DistSq; + geVec3d FogRay, Ray2; + geFloat v,disc, d; + geVec3d Impact1, Impact2; + geFloat Radius, Red, Grn, Blu, EyeDist; + geFloat RadiusSq, FogRayDot, Radius2; + geVec3d UAdd, VAdd, FogPos; + int32 LightAdd, Width, Height; + + Hit = GE_FALSE; + + Start = UV = SInfo->TexOrg; + + FogPos = Fog->Pos; + + geVec3d_Subtract(&FogPos, &GlobalEyePos, &FogRay); + + Ray2 = FogRay; + EyeDist = geVec3d_Normalize(&Ray2); + + Radius = Fog->VolumeRadius; + RadiusSq = Fog->VolumeRadiusSquared; + Radius2 = Fog->VolumeRadius2; + + FogRayDot = geVec3d_DotProduct(&FogRay,&FogRay); + + Red = Fog->Color.r; + Grn = Fog->Color.g; + Blu = Fog->Color.b; + + //if (EyeDist < Radius) + // return GE_FALSE; + + UAdd = SInfo->T2WVecs[0]; + VAdd = SInfo->T2WVecs[1]; + + Width = SInfo->LInfo.Width; + Height = SInfo->LInfo.Height; + + LightAdd = (SInfo->LInfo.Width - Width)*3; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + geFloat OneOver; + + Ray.X = UV.X - GlobalEyePos.X; + Ray.Y = UV.Y - GlobalEyePos.Y; + Ray.Z = UV.Z - GlobalEyePos.Z; + + //Dist = (geFloat)sqrt(Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z); + DistSq = Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z; + Dist = (geFloat)FastSqrt(DistSq); + + OneOver = 1.0f / Dist; + Ray.X *= OneOver; + Ray.Y *= OneOver; + Ray.Z *= OneOver; + + v = FogRay.X*Ray.X + FogRay.Y*Ray.Y + FogRay.Z*Ray.Z; + + disc = (RadiusSq) - (FogRayDot - (v*v)); + + if (disc > 0) + { + geFloat t0, t1, t; + + d = (geFloat)FastSqrt(disc); + //d = (geFloat)sqrt(disc); + + t0 = v - d; + t1 = v + d; + + if (t0 > 0) + t = t0; + else if (t1 > 0) + t = t1; + else + { + LightData+=3; + + UV.X += UAdd.X; + UV.Y += UAdd.Y; + UV.Z += UAdd.Z; + continue; + } + + #if 1 + Ray2.X = UV.X - FogPos.X; + Ray2.Y = UV.Y - FogPos.Y; + Ray2.Z = UV.Z - FogPos.Z; + + //UVDist = sqrt(Ray2.X*Ray2.X + Ray2.Y*Ray2.Y + Ray2.Z*Ray2.Z); + UVDist = (geFloat)FastSqrt(Ray2.X*Ray2.X + Ray2.Y*Ray2.Y + Ray2.Z*Ray2.Z); + + if (EyeDist < Radius && UVDist < Radius) + { + Impact1 = UV; + Impact2 = GlobalEyePos; + } + else if (EyeDist < Radius) + { + Impact1 = GlobalEyePos; + + Impact2.X = GlobalEyePos.X + t*Ray.X; + Impact2.Y = GlobalEyePos.Y + t*Ray.Y; + Impact2.Z = GlobalEyePos.Z + t*Ray.Z; + } + else if (UVDist < Radius) // UV is inside + { + Impact1 = UV; + + Impact2.X = GlobalEyePos.X + t*Ray.X; + Impact2.Y = GlobalEyePos.Y + t*Ray.Y; + Impact2.Z = GlobalEyePos.Z + t*Ray.Z; + + } + else // Both lie outside sphere + { + Impact1.X = GlobalEyePos.X + t0*Ray.X; + Impact1.Y = GlobalEyePos.Y + t0*Ray.Y; + Impact1.Z = GlobalEyePos.Z + t0*Ray.Z; + + Impact2.X = GlobalEyePos.X + t1*Ray.X; + Impact2.Y = GlobalEyePos.Y + t1*Ray.Y; + Impact2.Z = GlobalEyePos.Z + t1*Ray.Z; + + Ray.X = Impact1.X - GlobalEyePos.X; + Ray.Y = Impact1.Y - GlobalEyePos.Y; + Ray.Z = Impact1.Z - GlobalEyePos.Z; + + //d2 = sqrt(Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z); + //d2 = (geFloat)FastSqrt(Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z); + d2 = Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z; + + if (d2 > DistSq) + { + /* + Ray.X = Impact2.X - GlobalEyePos.X; + Ray.Y = Impact2.Y - GlobalEyePos.Y; + Ray.Z = Impact2.Z - GlobalEyePos.Z; + d3 = sqrt(Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z); + + if (d3 > Dist) + */ + { + LightData+=3; + + UV.X += UAdd.X; + UV.Y += UAdd.Y; + UV.Z += UAdd.Z; + continue; + } + } + + } + #endif + // Get the distance of the part of the ray that is in the fog + //geVec3d_Subtract(&Impact1, &Impact2, &Ray); + //d = geVec3d_Length(&Ray); + Ray.X = Impact1.X - Impact2.X; + Ray.Y = Impact1.Y - Impact2.Y; + Ray.Z = Impact1.Z - Impact2.Z; + + //d = (geFloat)FastSqrt(Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z); + //d = ((Radius / d)*18); + //Dist = (Fog->VolumeBrightness) / (d*d); + d = Ray.X*Ray.X + Ray.Y*Ray.Y + Ray.Z*Ray.Z; + d = ((RadiusSq / d)*18); + Dist = (Fog->VolumeBrightness) / (d); + //Dist = 255.0f; + + Hit = GE_TRUE; + + Light1 = (int32)(Dist*Red); + Light2 = (int32)(Dist*Grn); + Light3 = (int32)(Dist*Blu); + + *LightData += Light1; + LightData++; + *LightData += Light2; + LightData++; + *LightData += Light3; + LightData++; + } + else + { + LightData+=3; + } + + UV.X += UAdd.X; + UV.Y += UAdd.Y; + UV.Z += UAdd.Z; + + } + + Start.X += VAdd.X; + Start.Y += VAdd.Y; + Start.Z += VAdd.Z; + UV = Start; + + LightData += LightAdd; + + } + + return Hit; +} + +//===================================================================================== +// Light_SetupLightmap +//===================================================================================== +void Light_SetupLightmap(DRV_LInfo *LInfo, BOOL *Dynamic) +{ + int32 LightOffset; + geBoolean IsDyn, HasDLight; + int32 NumLTypes; + int32 i, Ln; + Surf_SurfInfo *SInfo; + GFX_Face *Face; + int32 Intensity; + uint8 *LightData; + int32 lWidth, lHeight, LMapSize, MapNum, SIndex; + int32 *pRGB1; + DRV_RGB *pRGB2; + + assert (CBSP != NULL); + assert(BSPData != NULL); + assert(BSPData->GFXFaces != NULL); + assert(BSPData->GFXLightData != NULL); + assert(BSPData->GFXTexInfo != NULL); + assert(CWorld->LightInfo != NULL); + + SInfo = &CBSP->SurfInfo[LInfo->Face]; + Face = &BSPData->GFXFaces[LInfo->Face]; + + NumLTypes = SInfo->NumLTypes; + + LightOffset = Face->LightOfs; + + lWidth = LInfo->Width; + lHeight = LInfo->Height; + LMapSize = lHeight * lWidth; + + IsDyn = HasDLight = GE_FALSE; + + if (SInfo->DLightFrame == CWorld->CurFrameDynamic) + if (LightInfo->NumDynamicLights > 0 && !(BSPData->GFXTexInfo[Face->TexInfo].Flags & TEXINFO_FULLBRIGHT)) + HasDLight = GE_TRUE; + + // We can early out if no dlights on this surface, and no styled lighting... + if (!HasDLight && !(SInfo->Flags & SURFINFO_LTYPED)) + { + if (LightOffset >=0) + LInfo->RGBLight[0] = (DRV_RGB*)&BSPData->GFXLightData[LightOffset+1]; + else + LInfo->RGBLight[0] = BlankRGB; + goto FogOnly; + } + + CEngine->DebugInfo.LMap1++; + + // If there is light data + if (LightOffset >=0) + { + // FIXME: Take out one byte RGB check... + // Lightmaps are allways RGB now... + LightData = &BSPData->GFXLightData[LightOffset+1]; + + // layer all styles on first map, using its intensity table + for (MapNum = 0; MapNum < 4; MapNum++) + { + SIndex = Face->LTypes[MapNum]; + + if (SIndex == 255) + break; + + if (LightInfo->LTypeDynamic[SIndex]) + IsDyn = GE_TRUE; + + Intensity = LightInfo->LTypeIntensities[SIndex]; + + if (SIndex == 11) + { + if (MapNum == 0) + AddLightTypeWavy1(TempRGB32, LightData, lWidth, lHeight); + else + AddLightTypeWavy(TempRGB32, LightData, lWidth, lHeight); + + IsDyn = GE_TRUE; // Need to force to true + } + else + { + if (SIndex == 0) // LType 0 is always in first light slot + AddLightType0(TempRGB32, LightData, lWidth, lHeight); + else + { + if (MapNum == 0) + AddLightType1(TempRGB32, LightData, lWidth, lHeight, Intensity); + else + AddLightType(TempRGB32, LightData, lWidth, lHeight, Intensity); + } + } + + LightData += LMapSize*3; + } + } + else + memset(TempRGB32, 0, LMapSize*3*sizeof(TempRGB32[0])); + + // Tack on dynamic lights + if (HasDLight) + { + Light_DLight *DLights = LightInfo->DynamicLights; + + for (Ln = 0; Ln Active) + continue; + + if (!(SInfo->DLights & (1<DebugInfo.NumDLights++; + + if (DLights->CastShadow) + { + if (CombineDLightWithRGBMapWithShadow(TempRGB32, DLights, Face, SInfo)) + IsDyn = GE_TRUE; + } + else + { + if (CombineDLightWithRGBMap(TempRGB32, DLights, Face, SInfo)) + IsDyn = GE_TRUE; + } + } + } + + // Put the light into a driver compatible pointer, and clamp it + pRGB1 = TempRGB32; + pRGB2 = TempRGB; + for (i=0; i< LMapSize; i++) + { + Intensity = (*pRGB1++) >> LIGHT_FRACT; + if (Intensity > 255) + Intensity = 255; + else if (Intensity < 0 ) + Intensity = 0; + pRGB2->r = (uint8)Intensity; + + Intensity = (*pRGB1++) >> LIGHT_FRACT; + if (Intensity > 255) + Intensity = 255; + else if (Intensity < 0 ) + Intensity = 0; + pRGB2->g = (uint8)Intensity; + + Intensity = (*pRGB1++) >> LIGHT_FRACT; + if (Intensity > 255) + Intensity = 255; + else if (Intensity < 0 ) + Intensity = 0; + pRGB2->b = (uint8)Intensity; + + pRGB2++; + } + + // Point the lightmap to the data + LInfo->RGBLight[0] = TempRGB; + + FogOnly: // Jump to here, for fog lightmap only... + + // + // Fog the lightmap (setup lightmap 1) + // + LInfo->RGBLight[1] = NULL; + +#if 1 + if (!MirrorRecursion) // Only do fog on first pass, not in mirrors... + { + geFog *Fog; + geBoolean WasFog; + + WasFog = GE_FALSE; + + if (CWorld->NumVisibleFog) + { + for (i=0; i< CWorld->NumVisibleFog; i++) + { + Fog = CWorld->VisibleFog[i]; + + if (i == 0) // Use FogLightmap1 for first one ONLY + { + if (FogLightmap1(Fog, TempRGB32Fog, Face, SInfo)) + WasFog = GE_TRUE; + } + else // All other fog lights use FogLightmap2 + { + if (FogLightmap2(Fog, TempRGB32Fog, Face, SInfo)) + WasFog = GE_TRUE; + } + } + } + + if (WasFog) + { + CEngine->DebugInfo.LMap2++; + + // Put the light into a driver compatible pointer, and clamp it + pRGB1 = TempRGB32Fog; + pRGB2 = TempRGBFog; + for (i=0; i< LMapSize; i++) + { + Intensity = (*pRGB1++) >> LIGHT_FRACT; + if (Intensity > 255) + Intensity = 255; + pRGB2->r = (uint8)Intensity; + + Intensity = (*pRGB1++) >> LIGHT_FRACT; + if (Intensity > 255) + Intensity = 255; + pRGB2->g = (uint8)Intensity; + + Intensity = (*pRGB1++) >> LIGHT_FRACT; + if (Intensity > 255) + Intensity = 255; + pRGB2->b = (uint8)Intensity; + + pRGB2++; + } + IsDyn = TRUE; // Force this face to be dynamic + LInfo->RGBLight[1] = TempRGBFog; + } + } +#endif + + if (Dynamic) + { + *Dynamic = IsDyn; + } +} + +//===================================================================================== +// AddLightType +//===================================================================================== +static void AddLightType(int32 *LightDest, uint8 *LightData, int32 lw, int32 lh, int32 Intensity) +{ + int32 h; + + assert(LightDest != NULL); + assert(LightData != NULL); + + for (h = 0; h < lw*lh; h++) + { + *LightDest++ += *LightData++ * Intensity; + *LightDest++ += *LightData++ * Intensity; + *LightDest++ += *LightData++ * Intensity; + } +} + +//===================================================================================== +// AddLightType0 +//===================================================================================== +static void AddLightType0(int32 *LightDest, uint8 *LightData, int32 lw, int32 lh) +{ + int32 h; + + assert(LightDest != NULL); + assert(LightData != NULL); + + for (h = 0; h < lw*lh; h++) + { + *LightDest++ = (*LightData++) << LIGHT_FRACT; + *LightDest++ = (*LightData++) << LIGHT_FRACT; + *LightDest++ = (*LightData++) << LIGHT_FRACT; + } +} + +//===================================================================================== +// AddLightType1 +//===================================================================================== +static void AddLightType1(int32 *LightDest, uint8 *LightData, int32 lw, int32 lh, int32 Intensity) +{ + int32 h; + + assert(LightDest != NULL); + assert(LightData != NULL); + + for (h = 0; h < lw*lh; h++) + { + *LightDest++ = *LightData++ * Intensity; + *LightDest++ = *LightData++ * Intensity; + *LightDest++ = *LightData++ * Intensity; + } +} + +//===================================================================================== +// CombineDLightWithRGBMap +//===================================================================================== +static BOOL CombineDLightWithRGBMap(int32 *LightData, Light_DLight *Light, GFX_Face *Face, Surf_SurfInfo *SInfo) +{ + BOOL Hit; + geFloat Radius, Dist; + GFX_Plane *Plane; + GFX_TexInfo *TexInfo; + geVec3d LPos; + int32 Sx, Sy, x, y, u, v, Val; + int32 ColorR, ColorG, ColorB, Radius2, Dist2; + int32 FixedX, FixedY, XStep, YStep; + + assert(BSPData != NULL); + assert(BSPData->GFXTexInfo != NULL); + assert(BSPData->GFXPlanes != NULL); + + TexInfo = &BSPData->GFXTexInfo[Face->TexInfo]; + + Radius = Light->Radius; + Plane = &BSPData->GFXPlanes[Face->PlaneNum]; + + geVec3d_Copy(&Light->Pos, &LPos); + + Dist = geVec3d_DotProduct(&LPos, &Plane->Normal) - Plane->Dist; + + // Shrink the radius by the dist so we can avoid using z in the fast sqrt routine... + Radius -= (geFloat)fabs(Dist); + + if (Radius <= 0) // We can leave now if the dist is > radius + return FALSE; + + // Calculate where light is projected onto the 2d-plane + Sx = (int32)(geVec3d_DotProduct(&LPos, &TexInfo->Vecs[0])); + Sy = (int32)(geVec3d_DotProduct(&LPos, &TexInfo->Vecs[1])); + + // Align the light with the upper left corner of the ligtmap + Sx -= SInfo->LInfo.MinU; + Sy -= SInfo->LInfo.MinV; + + // Scale by the texture scaling (1:21:10 fixed) + Sx *= SInfo->XScale; + Sy *= SInfo->YScale; + + Hit = FALSE; + + ColorR = Light->FColorR; + ColorG = Light->FColorG; + ColorB = Light->FColorB; + + Radius2 = (int32)Radius; + + XStep = SInfo->XStep; + YStep = SInfo->YStep; + + FixedY = Sy; + + for (v=0; v< SInfo->LInfo.Height; v++) + { + y = FixedY >> 10; + + if (y < 0) + y = -y; + + FixedX = Sx; + + for (u=0; u< SInfo->LInfo.Width; u++) + { + x = FixedX >> 10; + + if (x<0) + x = -x; + + if (x > y) + Dist2 = (x + (y>>1)); + else + Dist2 = (y + (x>>1)); + + if (Dist2 < Radius2) + { + Hit = TRUE; + + Val = (Radius2 - Dist2); + + *LightData++ += (int32)(Val * ColorR); + *LightData++ += (int32)(Val * ColorG); + *LightData++ += (int32)(Val * ColorB); + } + else + LightData+=3; + + FixedX -= XStep; + } + + FixedY -= YStep; + } + + return Hit; +} + +//===================================================================================== +// CombineDLightWithRGBMap +//===================================================================================== +static BOOL CombineDLightWithRGBMapWithShadow(int32 *LightData, Light_DLight *Light, GFX_Face *Face, Surf_SurfInfo *SInfo) +{ + BOOL Hit; + geFloat Radius, Dist; + GFX_Plane *Plane; + GFX_TexInfo *TexInfo; + geVec3d LPos, LMapPos, Right, Down, Start; + int32 Sx, Sy, x, y, u, v, Val; + int32 ColorR, ColorG, ColorB, Radius2, Dist2; + int32 FixedX, FixedY, XStep, YStep; + + assert(BSPData != NULL); + assert(BSPData->GFXTexInfo != NULL); + assert(BSPData->GFXPlanes != NULL); + + TexInfo = &BSPData->GFXTexInfo[Face->TexInfo]; + + Radius = Light->Radius; + Plane = &BSPData->GFXPlanes[Face->PlaneNum]; + + geVec3d_Copy(&Light->Pos, &LPos); + + Dist = geVec3d_DotProduct(&LPos, &Plane->Normal) - Plane->Dist; + + // Shrink the radius by the dist so we can avoid using z in the fast sqrt routine... + Radius -= (geFloat)fabs(Dist); + + if (Radius <= 0) // We can leave now if the dist is > radius + return FALSE; + + // Calculate where light is projected onto the 2d-plane + Sx = (int32)(geVec3d_DotProduct(&LPos, &TexInfo->Vecs[0]));// + TexInfo->Shift[0]); + Sy = (int32)(geVec3d_DotProduct(&LPos, &TexInfo->Vecs[1]));// + TexInfo->Shift[1]); + + // Shift into lightmap + Sx -= SInfo->LInfo.MinU; + Sy -= SInfo->LInfo.MinV; + + // Scale by the texture scaling (1:21:10 fixed) + Sx *= SInfo->XScale; + Sy *= SInfo->YScale; + + Hit = FALSE; + + ColorR = Light->FColorR; + ColorG = Light->FColorG; + ColorB = Light->FColorB; + + Radius2 = (int32)Radius; + + XStep = SInfo->XStep; + YStep = SInfo->YStep; + + FixedY = Sy; + + LMapPos = Start = SInfo->TexOrg; + Right = SInfo->T2WVecs[0]; + Down = SInfo->T2WVecs[1]; + + Trace_SetupIntersect(CWorld); // Setup intersection test with current world... + + for (v=0; v< SInfo->LInfo.Height; v++) + { + y = FixedY >> 10; + + if (y < 0) + y = -y; + + FixedX = Sx; + + for (u=0; u< SInfo->LInfo.Width; u++) + { + x = FixedX >> 10; + + if (x<0) + x = -x; + + if (x > y) + Dist2 = (x + (y>>1)); + else + Dist2 = (y + (x>>1)); + + if (Dist2 < Radius2) + { + if (Trace_IntersectWorldBSP(&LPos, &LMapPos, 0)) + { + LightData += 3; + FixedX -= XStep; + geVec3d_Add(&LMapPos, &Right, &LMapPos); + continue; + } + + Hit = TRUE; + + Val = (Radius2 - Dist2); + + *LightData++ += (int32)(Val * ColorR); + *LightData++ += (int32)(Val * ColorG); + *LightData++ += (int32)(Val * ColorB); + } + else + LightData+=3; + + geVec3d_Add(&LMapPos, &Right, &LMapPos); + + FixedX -= XStep; + } + + geVec3d_Add(&Start, &Down, &Start); + LMapPos = Start; + + FixedY -= YStep; + } + + return Hit; +} + +//===================================================================================== +// Light_SetupLights +// Post processes the lights render q so the world can use them while rendering +//===================================================================================== +geBoolean Light_SetupLights(geWorld *World) +{ + int32 i, Node; + Light_DLight *DLights; + + assert(World != NULL); + + assert(BSPData != NULL); + assert(BSPData->GFXModels != NULL); + assert(LightInfo != NULL); + + // Update the intensity tables for dynamic ltyped lighting + UpdateLTypeTables(World); + + DLights = LightInfo->DynamicLights; + +#if 0 + Node = BSPData->GFXModels[0].RootNode[0]; + + for (i=0; i< MAX_DYNAMIC_LIGHTS; i++, DLights++) + { + if (!DLights->Active) + continue; + + SetupDynamicLight_r(DLights, &DLights->Pos, i, Node); + } +#else + for (i=0; i< MAX_DYNAMIC_LIGHTS; i++, DLights++) + { + int32 m; + geVec3d NewPos; + geWorld_Model *Model; + + if (!DLights->Active) + continue; + + Model = CBSP->Models; + + for (m=0; m< BSPData->NumGFXModels; m++, Model++) + { + if (Model->VisFrame != World->CurFrameDynamic) + continue; + + Node = BSPData->GFXModels[m].RootNode[0]; + + geVec3d_Subtract(&DLights->Pos, &Model->Pivot, &NewPos); + // InverseTransform the light about models center of rotation + geXForm3d_TransposeTransform(&Model->XForm, &NewPos, &NewPos); + + geVec3d_Add(&NewPos , &Model->Pivot, &NewPos); + + SetupDynamicLight_r(DLights, &NewPos, i, Node); + } + } +#endif + + return GE_TRUE; +} +//===================================================================================== +// Light_WorldGetLTypeCurent +//===================================================================================== +char Light_WorldGetLTypeCurrent(geWorld *World, int32 LType) +{ + Light_LightInfo *LInfo; + assert( World != NULL ); + assert( LType >= 0 ); + assert( LType < MAX_LTYPES ); + + LInfo = World->LightInfo; + assert( LInfo != NULL ); + + return (LInfo->LTypeTable[LType][LInfo->IPos[LType]]) ; +} + + +//===================================================================================== +// UpdateLTypeTables +//===================================================================================== +static void UpdateLTypeTables(geWorld *World) +{ + int32 s; + geFloat i; + Light_LightInfo *LInfo; + + LInfo = World->LightInfo; + + for (s =0; s IPos[s]++; + + if (LInfo->LTypeTable[s][LInfo->IPos[s]] == 0) + LInfo->IPos[s] = 0; + + i = (geFloat)(LInfo->LTypeTable[s][LInfo->IPos[s]]-96) / 27.0f; + + LInfo->LTypeIntensities[s] = (int32)(i * (1<LTypeIntensities2[s] != LInfo->LTypeTable[s][LInfo->IPos[s]]-96) + LInfo->LTypeDynamic[s] = TRUE; + else + LInfo->LTypeDynamic[s] = FALSE; + + LInfo->LTypeIntensities2[s] = LInfo->LTypeTable[s][LInfo->IPos[s]]-96; + } +} + +//===================================================================================== +// Light_WorldAddLight +//===================================================================================== +Light_DLight *Light_WorldAddLight(geWorld *World) +{ + Light_LightInfo *LInfo; + Light_DLight *DLights; + int32 i; + + assert(World != NULL); + + LInfo = World->LightInfo; + + assert(LInfo); + + DLights = LInfo->DynamicLights; + + for (i=0; i< MAX_DYNAMIC_LIGHTS; i++, DLights++) + { + if (!DLights->Active) + break; + } + + if (i >= MAX_DYNAMIC_LIGHTS) + { + geErrorLog_Add(GE_ERR_RENDERQ_OVERFLOW, NULL); + return NULL; + } + + // Set it's attributes to some default... + memset(DLights, 0, sizeof(Light_DLight)); + + DLights->Active = GE_TRUE; + LInfo->NumDynamicLights++; + + + return DLights; +} + +//===================================================================================== +// Light_WorldRemoveLight +//===================================================================================== +void Light_WorldRemoveLight(geWorld *World, Light_DLight *DLight) +{ + assert(World); + assert(World->LightInfo); + assert(DLight); + assert(DLight->Active); + + if (!DLight->Active) + return; + + DLight->Active = GE_FALSE; + World->LightInfo->NumDynamicLights--; +} + +//===================================================================================== +// Light_SetAttributes +//===================================================================================== +geBoolean Light_SetAttributes( Light_DLight *Light, + const geVec3d *Pos, + const GE_RGBA *RGBA, + geFloat Radius, + geBoolean CastShadow) +{ + assert(Light != NULL); + + Light->Pos = *Pos; + Light->Color = *RGBA; + Light->Radius = Radius; + + // Pre-compute fixed point light colors + Light->FColorR = (int32)((Light->Color.r/195.0f) * (1<FColorG = (int32)((Light->Color.g/195.0f) * (1<FColorB = (int32)((Light->Color.b/195.0f) * (1<CastShadow = CastShadow; + + return GE_TRUE; +} + +//===================================================================================== +// Light_SetLTypeTable +//===================================================================================== +geBoolean Light_WorldSetLTypeTable(geWorld *World, int32 LType, const char *Table) +{ + assert(World != NULL); + assert(World->LightInfo != NULL); + + if (LType < 0 || LType >= MAX_LTYPES) + { + geErrorLog_Add(GE_ERR_INVALID_LTYPE, NULL); + return GE_FALSE; + } + + assert(strlen(Table) < 70); + + strcpy(World->LightInfo->LTypeTable[LType], Table); + + return GE_TRUE; +} + +//===================================================================================== +// Local static support functions +//===================================================================================== + +//===================================================================================== +// FastDist +// Quick sqrt routine +//===================================================================================== +static int32 FastDist(int32 dx, int32 dy, int32 dz) +{ + int32 Max, Med, Min; // biggest, smallest, and middle values + int32 Tmp; + + Max = (dx < 0) ? -dx : dx; + Med = (dz < 0) ? -dz : dz; + Min = (dy < 0) ? -dy : dy; + + if (Max < Med) + { + Tmp = Max; Max = Med; Med = Tmp; + } + if (Max < Min) + { + Tmp = Max; Max = Min; Min = Tmp; + } + Max <<= 2; + Max += Med + Min; + return Max>>2; +} + +#define A_MOD 7 // How much to modulus the anim too + +//===================================================================================== +// SetupWavyColorLight1 +//===================================================================================== +static void SetupWavyColorLight1(DRV_RGB *light1, DRV_RGB *RGBM, int32 lw, int32 lh) +{ + int32 h; + DRV_RGB *rgb; + U16 r,g,b, II; + DRV_RGB *lm; + uint16 Index; + uint8 *SLUT; + int16 *WaveTable; + + assert(light1 != NULL); + assert(RGBM != NULL); + + assert(CEngine != NULL); + + WaveTable = CEngine->WaveTable; + + lm = light1; + rgb = RGBM; + Index = 0; + + SLUT = CEngine->StyleLUT1[0]; + + for (h = 0; h < lh*lw; h++) + { + // We know that WaterColor table is from 0-255... + II = WaveTable[Index++]; + if (Index > A_MOD) + Index -= A_MOD; + + II >>= 2; + if (II > 63) II = 63; + II <<= 8; + r = SLUT[II + lm->r]; + g = SLUT[II + lm->g]; + b = SLUT[II + lm->b]; + + rgb->r = (uint8)r; + rgb->g = (uint8)g; + rgb->b = (uint8)b; + + lm++; + rgb++; + } +} + +//===================================================================================== +// SetupWavyColorLight2 +//===================================================================================== +static void SetupWavyColorLight2(DRV_RGB *light1, DRV_RGB *RGBM, int32 lw, int32 lh) +{ + int32 h; + DRV_RGB *rgb; + U16 r,g,b, II; + DRV_RGB *lm; + uint16 Index; + uint8 *SLUT; + int16 *WaveTable; + + assert(light1 != NULL); + assert(RGBM != NULL); + + assert(CEngine != NULL); + + WaveTable = CEngine->WaveTable; + + lm = light1; + rgb = RGBM; + Index = 0; + + SLUT = CEngine->StyleLUT1[0]; + + for (h = 0; h < lh*lw; h++) + { + // We know that WaterColor table is from 0-255... + II = WaveTable[Index++]; + if (Index > A_MOD) + Index -= A_MOD; + + II >>= 2; + if (II > 63) + II = 63; + II <<= 8; + + r = rgb->r + SLUT[II + lm->r]; + g = rgb->g + SLUT[II + lm->g]; + b = rgb->b + SLUT[II + lm->b]; + + if (r > 255) r = 255; + if (g > 255) g = 255; + if (b > 255) b = 255; + + rgb->r = (uint8)r; + rgb->g = (uint8)g; + rgb->b = (uint8)b; + + lm++; + rgb++; + } +} + +//===================================================================================== +// SetupColorLight1 +//===================================================================================== +static void SetupColorLight1(DRV_RGB *light1, DRV_RGB *RGBM, int32 lw, int32 lh, geFloat intensity) +{ + int32 h; + DRV_RGB *rgb; + uint16 r,g,b; + DRV_RGB *lm; + uint16 II; + uint8 *SLUT; + + assert(light1 != NULL); + assert(RGBM != NULL); + assert(CEngine != NULL); + + lm = light1; + rgb = RGBM; + II = (uint16)(intensity * 63); + + if (II > 63) II = 63; + + SLUT = &CEngine->StyleLUT1[II][0]; + + for (h = 0; h < lh*lw; h++) + { + r = SLUT[lm->r]; + g = SLUT[lm->g]; + b = SLUT[lm->b]; + + rgb->r = (uint8)r; + rgb->g = (uint8)g; + rgb->b = (uint8)b; + + lm++; + rgb++; + } +} + +//===================================================================================== +// SetupColorLight2 +//===================================================================================== +static void SetupColorLight2(DRV_RGB *light1, DRV_RGB *RGBM, int32 lw, int32 lh, geFloat intensity) +{ + int32 h; + DRV_RGB *rgb; + uint16 r,g,b; + DRV_RGB *lm; + uint16 II; + uint8 *SLUT; + + assert(light1 != NULL); + assert(RGBM != NULL); + assert(CEngine != NULL); + + lm = light1; + rgb = RGBM; + II = (uint16)(intensity * 63); + + if (II > 63) + II = 63; + + SLUT = &CEngine->StyleLUT1[II][0]; + + for (h = 0; h < lh*lw; h++) + { + + r = rgb->r + SLUT[lm->r]; + g = rgb->g + SLUT[lm->g]; + b = rgb->b + SLUT[lm->b]; + + if (r > 255) r = 255; + if (g > 255) g = 255; + if (b > 255) b = 255; + + rgb->r = (uint8)r; + rgb->g = (uint8)g; + rgb->b = (uint8)b; + + lm++; + rgb++; + } +} + +//===================================================================================== +// AddLightTypeWavy1 +//===================================================================================== +static void AddLightTypeWavy1(int32 *LightDest, uint8 *LightData, int32 lw, int32 lh) +{ + uint16 *WaveTable, II; + int32 Index, h; + uint8 *SLUT; + + assert(LightDest != NULL); + assert(LightData != NULL); + assert(CEngine != NULL); + + WaveTable = CEngine->WaveTable; + + Index = 0; + + SLUT = CEngine->StyleLUT1[0]; + + for (h = 0; h < lh*lw; h++) + { + // We know that WaterColor table is from 0-255... + II = WaveTable[Index++]; + + if (Index > A_MOD) + Index -= A_MOD; + + II >>= 2; + if (II > 30) II = 30; + II <<= 8; + + *LightDest++ = SLUT[II + *LightData++] << (LIGHT_FRACT); + *LightDest++ = SLUT[II + *LightData++] << (LIGHT_FRACT); + *LightDest++ = SLUT[II + *LightData++] << (LIGHT_FRACT); + } +} + +//===================================================================================== +// AddLightTypeWavy +//===================================================================================== +static void AddLightTypeWavy(int32 *LightDest, uint8 *LightData, int32 lw, int32 lh) +{ + uint16 *WaveTable, II; + int32 Index, h; + uint8 *SLUT; + + assert(LightDest != NULL); + assert(LightData != NULL); + assert(CEngine != NULL); + + WaveTable = CEngine->WaveTable; + + Index = 0; + + SLUT = CEngine->StyleLUT1[0]; + + for (h = 0; h < lh*lw; h++) + { + // We know that WaterColor table is from 0-255... + II = WaveTable[Index++]; + + if (Index > A_MOD) + Index -= A_MOD; + + II >>= 2; + if (II > 30) II = 30; + II <<= 8; + + *LightDest++ += SLUT[II + *LightData++] << (LIGHT_FRACT); + *LightDest++ += SLUT[II + *LightData++] << (LIGHT_FRACT); + *LightDest++ += SLUT[II + *LightData++] << (LIGHT_FRACT); + } +} + +//===================================================================================== +// BuildStyleTables +//===================================================================================== +static void BuildLightLUTS(geEngine *Engine) +{ + S32 i, k; + + for (i=0; i< 256; i++) + { + for (k=0; k< 64; k++) + { + geFloat ii = (geFloat)i; + geFloat kk = (geFloat)k; + geFloat Intensity = (ii * (kk / 62.0f));// * 5.0f; + if (Intensity > 255) + Intensity = 255.0f; + Engine->StyleLUT1[k][i] = (U8)Intensity; + } + } +} + +//===================================================================================== +// SetupDynamicLight_r +//===================================================================================== +static void SetupDynamicLight_r(Light_DLight *pLight, geVec3d *Pos, int32 LNum, int32 Node) +{ + geFloat Dist; + GFX_Plane *pPlane; + GFX_Node *pNode; + Surf_SurfInfo *pSInfo; + int32 i; + + if (Node < 0) // Hit a leaf no more searching + return; + + pNode = &BSPData->GFXNodes[Node]; + pPlane = &BSPData->GFXPlanes[pNode->PlaneNum]; + + Dist = Plane_PlaneDistanceFast(pPlane, Pos); + + if (Dist > pLight->Radius) + { + SetupDynamicLight_r(pLight, Pos, LNum, BSPData->GFXNodes[Node].Children[0]); + return; + } + if (Dist <-pLight->Radius) + { + SetupDynamicLight_r(pLight, Pos, LNum, BSPData->GFXNodes[Node].Children[1]); + return; + } + + // The light is within range of this plane, mark it and go down both sides + pSInfo = &CBSP->SurfInfo[pNode->FirstFace]; + for (i=0; i< pNode->NumFaces; i++, pSInfo++) + { + if (!Surf_InSurfBoundingBox(pSInfo, Pos, pLight->Radius) ) + continue; + + if (pSInfo->DLightFrame != CWorld->CurFrameDynamic) + { + pSInfo->DLightFrame = CWorld->CurFrameDynamic; + pSInfo->DLights = 0; + } + + // We might need to go to a linked list, if more than 32 lights are needed + pSInfo->DLights |= 1<GFXNodes[Node].Children[0]); + SetupDynamicLight_r(pLight, Pos, LNum, BSPData->GFXNodes[Node].Children[1]); +} + +//===================================================================================== +// Light_GetLightmapRGB +// Takes a point, and a face , and gets the light map value it was projected on... +// NOTE: AFX_SetupLightmap should be called first... or Light, RGBLight will be NULL... +// (or invalid) +//===================================================================================== +geBoolean Light_GetLightmapRGB(Surf_SurfInfo *Surf, geVec3d *Pos, GE_RGBA *RGBA) +{ + + DRV_RGB *RGBLight; + geFloat fr = 0.0f, fg = 0.0f, fb = 0.0f; + geVec3d VecU, VecV; + geFloat TexU, TexV; + int32 Index, Width, Height; + + // Make sure this is a lightmaped face + if (!(Surf->Flags & SURFINFO_LIGHTMAP)) + return GE_FALSE; + + RGBLight = Surf->LInfo.RGBLight[0]; + + if (!RGBLight) // Make sure we are not null!!! + return GE_FALSE; + + VecU = BSPData->GFXTexInfo[Surf->TexInfo].Vecs[0]; + VecV = BSPData->GFXTexInfo[Surf->TexInfo].Vecs[1]; + + // Project the Point into the texture space + TexU = geVec3d_DotProduct(Pos, &VecU) + BSPData->GFXTexInfo[Surf->TexInfo].Shift[0]; + TexV = geVec3d_DotProduct(Pos, &VecV) + BSPData->GFXTexInfo[Surf->TexInfo].Shift[1]; + + // Align into lightmap space + TexU -= Surf->LInfo.MinU; + TexV -= Surf->LInfo.MinV; + + if (TexU < 0 || TexV < 0) + return GE_FALSE; + + if (TexU > Surf->LInfo.Width<<4 || TexV > Surf->LInfo.Height<<4) + return GE_FALSE; + + // Scale into lightmap space + TexU /= (16); + TexV /= (16); + + Width = Surf->LInfo.Width; + Height = Surf->LInfo.Height; + + // Cap it off if invalid (for some funky reason) + if (TexU > Width) TexU = (geFloat)Width; + if (TexV > Height) TexV = (geFloat)Height; + if (TexU < 0) TexU = 0.0f; + if (TexV < 0) TexV = 0.0f; + + Index = (int32)TexV * Width + (int32)TexU; + + // Return the color dude... + RGBA->r = (geFloat)RGBLight[Index].r; + RGBA->g = (geFloat)RGBLight[Index].g; + RGBA->b = (geFloat)RGBLight[Index].b; + + return GE_TRUE; +} + +//===================================================================================== +// Light_GetLightmapRGBBlended +//===================================================================================== +geBoolean Light_GetLightmapRGBBlended(Surf_SurfInfo *Surf, geVec3d *Pos, GE_RGBA *RGBA) +{ + + DRV_RGB *RGBLight; + geFloat fr = 0.0f, fg = 0.0f, fb = 0.0f; + geVec3d VecU, VecV; + geFloat TexU, TexV; + int32 Index, Width, Height; + + // Make sure this is a lightmaped face + if (!(Surf->Flags & SURFINFO_LIGHTMAP)) + return GE_FALSE; + + RGBLight = Surf->LInfo.RGBLight[0]; + + if (!RGBLight) // Make sure we are not null!!! + return GE_FALSE; + + TexU = geVec3d_DotProduct(Pos, &VecU) + BSPData->GFXTexInfo[Surf->TexInfo].Shift[0]; + TexV = geVec3d_DotProduct(Pos, &VecV) + BSPData->GFXTexInfo[Surf->TexInfo].Shift[1]; + + // Align into lightmap space + TexU -= Surf->LInfo.MinU; + TexV -= Surf->LInfo.MinV; + + if (TexU < 0 || TexV < 0) + return GE_FALSE; + + if (TexU > Surf->LInfo.Width<<4 || TexV > Surf->LInfo.Height<<4) + return GE_FALSE; + + // Scale into lightmap space + TexU /= (16); + TexV /= (16); + + Width = Surf->LInfo.Width; + Height = Surf->LInfo.Height; + + // Cap it off if invalid (for some funky reason) + if (TexU > Width) TexU = (geFloat)Width; + if (TexV > Height) TexV = (geFloat)Height; + if (TexU < 0) TexU = 0.0f; + if (TexV < 0) TexV = 0.0f; + + Index = (int32)TexV * Width + (int32)TexU; + + // Return the color dude... + RGBA->r = (geFloat)RGBLight[Index].r; + RGBA->g = (geFloat)RGBLight[Index].g; + RGBA->b = (geFloat)RGBLight[Index].b; + + return GE_TRUE; +} + +//===================================================================================== +//===================================================================================== +static void InitSqrtTab(void) +{ + int32 i; + double f; + int32 *fi = (int32*) &f + MOST_SIG_OFFSET; + + for (i = 0; i < SQRT_TAB_SIZE/2; i++) + { + f = 0; /* Clears least sig part */ + *fi = (i << MANT_SHIFTS) | (EXP_BIAS << EXP_SHIFTS); + f = sqrt(f); + SqrtTab[i] = *fi & MANT_MASK; + + f = 0; /* Clears least sig part */ + *fi = (i << MANT_SHIFTS) | ((EXP_BIAS + 1) << EXP_SHIFTS); + f = sqrt(f); + SqrtTab[i + SQRT_TAB_SIZE/2] = *fi & MANT_MASK; + } +} + +//===================================================================================== +//===================================================================================== +static FastSqrtFloat FastSqrt(FastSqrtFloat f) +{ + int32 e; + int32 *fi = (int32*) &f + MOST_SIG_OFFSET; + + //return sqrt(f); + + if (f == (FastSqrtFloat)0.0) + return((FastSqrtFloat)0.0); + + e = (*fi >> EXP_SHIFTS) - EXP_BIAS; + *fi &= MANT_MASK; + + if (e & 1) + *fi |= EXP_LSB; + + e >>= 1; + *fi = (SqrtTab[*fi >> MANT_SHIFTS]) | ((e + EXP_BIAS) << EXP_SHIFTS); + + return(f); +} +#if 0 +//===================================================================================== +//===================================================================================== +void DumpSqrtTab() +{ + int32 i, nl = 0; + + printf("unsigned int SqrtTab[] = {\n"); + + for (i = 0; i < SQRT_TAB_SIZE-1; i++) + { + printf("0x%x,", sqrt_tab[i]); + nl++; + if (nl > 8) + { + nl = 0; + putchar('\n'); + } + } + printf("0x%x\n", SqrtTab[SQRT_TAB_SIZE-1]); + printf("};\n"); +} +#endif diff --git a/G3D/World/Light.h b/G3D/World/Light.h new file mode 100644 index 0000000..87a8abc --- /dev/null +++ b/G3D/World/Light.h @@ -0,0 +1,114 @@ +/****************************************************************************************/ +/* Light.h */ +/* */ +/* Author: John Pollard */ +/* Description: Handles lightmaps, dynamic light, fog, etc */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_LIGHT_H +#define GE_LIGHT_H + +#include +//#include + +#include "Genesis.h" +#include "BaseType.h" +#include "System.h" +#include "DCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//===================================================================================== +// Defines / Structure defines +//===================================================================================== +#define MAX_DYNAMIC_LIGHTS 64 // Maximum number of moving lights in map +#define MAX_LTYPES 24 // Max number of ltypes +//#define MAX_LMAP_SIZE 128 +//#define MAX_LMAP_SIZE 18 +#define MAX_LMAP_SIZE 36 + +typedef struct +{ + geBoolean Active; // Is this light in use? + GE_RGBA Color; // Color of light (0...255.0f) + geVec3d Pos; // Position of this light + geFloat Radius; // Intensity of this light (Radius) + + // Fixed point color + uint32 FColorR; + uint32 FColorG; + uint32 FColorB; + + geBoolean CastShadow; +} Light_DLight; + +typedef struct Light_LightInfo +{ + // Intensity tables, for animated styles + BOOL LTypeDynamic[MAX_LTYPES]; + int32 LTypeIntensities[MAX_LTYPES]; + uint8 LTypeIntensities2[MAX_LTYPES]; + + char LTypeTable[MAX_LTYPES][70]; + int32 IPos[MAX_LTYPES]; // Ref position in ltype table + + Light_DLight DynamicLights[MAX_DYNAMIC_LIGHTS]; + int32 NumDynamicLights; +} Light_LightInfo; + +typedef struct tag_light +{ + int light; + GE_RGBA color; + int style; + geVec3d origin; +} light; + +//===================================================================================== +// Function ProtoTypes +//===================================================================================== +geBoolean Light_EngineInit(geEngine *Engine); +void Light_EngineShutdown(geEngine *Engine); +geBoolean Light_WorldInit(geWorld *World); +void Light_WorldShutdown(geWorld *World); +geBoolean Light_SetEngine(geEngine *Engine); +geBoolean Light_SetWorld(geWorld *World); +geBoolean Light_SetGBSP(World_BSP *BSP); + +Light_DLight *Light_WorldAddLight(geWorld *World); +void Light_WorldRemoveLight(geWorld *World, Light_DLight *DLight); +geBoolean Light_SetupLights(geWorld *World); +geBoolean Light_SetAttributes( Light_DLight *Light, + const geVec3d *Pos, + const GE_RGBA *RGBA, + geFloat Radius, + geBoolean CastShadow); +geBoolean Light_WorldSetLTypeTable(geWorld *World, int32 LType, const char *Table); + +char Light_WorldGetLTypeCurrent(geWorld *World, int32 LType); +void Light_SetupLightmap(DRV_LInfo *LInfo, BOOL *Dynamic); +geBoolean Light_GetLightmapRGB(Surf_SurfInfo *Surf, geVec3d *Pos, GE_RGBA *RGBA); +geBoolean Light_GetLightmapRGBBlended(Surf_SurfInfo *Surf, geVec3d *Pos, GE_RGBA *RGBA); +void Light_FogVerts(const geFog *Fog, const geVec3d *POV, const geVec3d *Verts, Surf_TexVert *TexVerts, int32 NumVerts); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/World/PLANE.H b/G3D/World/PLANE.H new file mode 100644 index 0000000..1511f9a --- /dev/null +++ b/G3D/World/PLANE.H @@ -0,0 +1,57 @@ +/****************************************************************************************/ +/* Plane.h */ +/* */ +/* Author: John Pollard */ +/* Description: Handy functions that deal with GFX_Plane's */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_PLANE_H +#define GE_PLANE_H + +#include +#include + +#include "GBSPFile.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//===================================================================================== +// Defines / Structure defines +//===================================================================================== + +//===================================================================================== +// Function ProtoTypes +//===================================================================================== +geBoolean GENESISCC Plane_SetEngine(geEngine *Engine); +geBoolean GENESISCC Plane_SetWorld(geWorld *World); +geBoolean GENESISCC Plane_SetGBSP(World_BSP *BSP); + +int32 GENESISCC Plane_FindLeaf(const geWorld *World, int32 Node, const geVec3d *POV); + +geFloat GENESISCC Plane_PlaneDistanceFast(const GFX_Plane *Plane, const geVec3d *Point); +geFloat GENESISCC Plane_FaceDistanceFast(const GFX_Face *Face, const geVec3d *Point); +geFloat GENESISCC Plane_PlaneDistance(const GFX_Plane *Plane, const geVec3d *Point); +void gePlane_SetFromVerts(GFX_Plane *Plane, const geVec3d *V1, const geVec3d *V2, const geVec3d *V3); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/World/Plane.c b/G3D/World/Plane.c new file mode 100644 index 0000000..2f1bf92 --- /dev/null +++ b/G3D/World/Plane.c @@ -0,0 +1,226 @@ +/****************************************************************************************/ +/* Plane.c */ +/* */ +/* Author: John Pollard */ +/* Description: Handy functions that deal with GFX_Plane's */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "BaseType.h" +#include "System.h" +#include "World.h" +#include "GBSPFile.h" +#include "Vec3d.h" +#include "XForm3d.h" +#include "Plane.h" + +//===================================================================================== +// static local globals +//===================================================================================== +static geEngine *CEngine; +static geWorld *CWorld; +static GBSP_BSPData *BSPData; // This is in globals, but is also kept here for speed + + +//===================================================================================== +// Plane_SetEngine +// Lets this module know that the engine has changed +//===================================================================================== +geBoolean GENESISCC Plane_SetEngine(geEngine *Engine) +{ + assert (Engine != NULL); + + CEngine = Engine; + + return GE_TRUE; +} + +//===================================================================================== +// Plane_SetWorld +// Lets this module know that the world has changed +//===================================================================================== +geBoolean GENESISCC Plane_SetWorld(geWorld *World) +{ + assert(World != NULL); + + CWorld = World; + + return GE_TRUE; +} + +//===================================================================================== +// Plane_SetGBSP +//===================================================================================== +geBoolean GENESISCC Plane_SetGBSP(World_BSP *BSP) +{ + assert(BSP != NULL); + + // Make quick pointer to the world bsp data + BSPData = &BSP->BSPData; + + return GE_TRUE; +} + +//===================================================================================== +// Plane_FindLeaf +//===================================================================================== +int32 GENESISCC Plane_FindLeaf(const geWorld *World, int32 Node, const geVec3d *POV) +{ + geFloat Dist; + GFX_Node *GFXNodes; + GFX_Plane *GFXPlanes; + int32 Leaf; + + GFXNodes = World->CurrentBSP->BSPData.GFXNodes; + GFXPlanes = World->CurrentBSP->BSPData.GFXPlanes; + + while (Node >= 0) + { + assert(Node >= 0 && Node < World->CurrentBSP->BSPData.NumGFXNodes); + + Dist = Plane_PlaneDistanceFast(&GFXPlanes[GFXNodes[Node].PlaneNum], POV); + + if (Dist < 0) + Node = GFXNodes[Node].Children[1]; + else + Node = GFXNodes[Node].Children[0]; + } + + // We are now in a leaf + Leaf = -(Node+1); + + assert(Leaf >=0 && Leaf < World->CurrentBSP->BSPData.NumGFXLeafs); + + return Leaf; +} + +//===================================================================================== +// Plane_PlaneDistanceFast +// Fast axial aligned plane distance +//===================================================================================== +geFloat GENESISCC Plane_PlaneDistanceFast(const GFX_Plane *Plane, const geVec3d *Point) +{ + geFloat Dist, PDist; + + assert(Plane != NULL); + assert(Point != NULL); + + PDist = Plane->Dist; + + switch (Plane->Type) + { + case PLANE_X: + Dist = (Point->X - PDist); + break; + case PLANE_Y: + Dist = (Point->Y - PDist); + break; + case PLANE_Z: + Dist = (Point->Z - PDist); + break; + + default: + Dist = geVec3d_DotProduct(Point, &Plane->Normal) - PDist; + break; + } + + return Dist; +} + +//===================================================================================== +// Plane_PlaneDistance +// Normal (slow) plane distance +//===================================================================================== +geFloat GENESISCC Plane_PlaneDistance(const GFX_Plane *Plane, const geVec3d *Point) +{ + geFloat Dist; + + assert(Plane != NULL); + assert(Point != NULL); + + Dist = geVec3d_DotProduct(Point, &Plane->Normal) - Plane->Dist; + + return Dist; +} + +//===================================================================================== +// Plane_PlaneDistanceFast +// Fast axial aligned face distance +//===================================================================================== +geFloat GENESISCC Plane_FaceDistanceFast(const GFX_Face *Face, const geVec3d *Point) +{ + geFloat Dist, PDist; + GFX_Plane *Plane; + + assert(Face != NULL); + assert(Point != NULL); + + assert(BSPData != NULL); + assert(BSPData->GFXPlanes != NULL); + + Plane = &BSPData->GFXPlanes[Face->PlaneNum]; + PDist = Plane->Dist; + + switch (Plane->Type) + { + case PLANE_X: + Dist = (Point->X - PDist); + break; + case PLANE_Y: + Dist = (Point->Y - PDist); + break; + case PLANE_Z: + Dist = (Point->Z - PDist); + break; + + default: + Dist = geVec3d_DotProduct(Point, &Plane->Normal) - PDist; + break; + } + + if (Face->PlaneSide) + Dist = -Dist; + + return Dist; +} + +//==================================================================================== +// gePlane_SetFromVerts +//==================================================================================== +void gePlane_SetFromVerts(GFX_Plane *Plane, const geVec3d *V1, const geVec3d *V2, const geVec3d *V3) +{ + geVec3d Vect1, Vect2; + + // Get the 2 vectors to derive the normal + geVec3d_Subtract(V1, V2, &Vect1); + geVec3d_Subtract(V3, V2, &Vect2); + + // The normal is the cross between these 2 vectors + geVec3d_CrossProduct(&Vect1, &Vect2, &Plane->Normal); + geVec3d_Normalize(&Plane->Normal); + + // Get the planes distance from the origin, by projecting a vert on the plane + // along the plane normal, to the origin... + Plane->Dist = geVec3d_DotProduct(V1, &Plane->Normal); + + // Finally, get the plane type + Plane->Type = PLANE_ANY; +} + diff --git a/G3D/World/SURFACE.H b/G3D/World/SURFACE.H new file mode 100644 index 0000000..c395941 --- /dev/null +++ b/G3D/World/SURFACE.H @@ -0,0 +1,116 @@ +/****************************************************************************************/ +/* Surface.h */ +/* */ +/* Author: John Pollard */ +/* Description: Creates the surfaces for a BSP from the GFX data */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_SURFACE_H +#define GE_SURFACE_H + +#include +#include + +#include "BaseType.h" +#include "PtrTypes.h" +#include "Vec3d.h" +#include "DCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//================================================================================ +// Structure defines +//================================================================================ + +// Surface info carries extra info about a face thats not in GFX_Face (File format face) +typedef struct Surf_SurfInfo +{ + DRV_LInfo LInfo; // For RDriver use only... + + geVec3d T2WVecs[2]; + geVec3d TexOrg; + + geVec3d VMins; + geVec3d VMaxs; + + int32 VisFrame; + + int32 TexInfo; + + int32 XStep; // Lightmap step values (1:21:10 fixed) + int32 YStep; + int32 XScale; + int32 YScale; + + geFloat ShiftU; + geFloat ShiftV; + + int32 NumLTypes; // Number of lightmap types this face has... + int32 DLightFrame; // == Globals->CurFrame if dlighted + uint32 DLights; // Bit set for each DLight + uint32 Flags; // Surface Flags (NOTE - This is not the flags from the utilities) + +} Surf_SurfInfo; + +typedef struct Surf_TexVert +{ + geFloat u, v; + geFloat r, g, b, a; +} Surf_TexVert; + +// Lit vertex +typedef struct +{ + geFloat X, Y, Z; // 3d vertex + geFloat u, v; // Uv's + geFloat r, g, b, a; // color +} Surf_LVertex; + +// Transformed Lit vertex +typedef struct +{ + geFloat x, y, z; // screen points + geFloat u, v; // Uv's + geFloat r, g, b, a; // color +} Surf_TLVertex; + +// Surface Flags +#define SURFINFO_TRANS (1<<0) // Surface is transparent +#define SURFINFO_LTYPED (1<<1) // This surface has more than one ltype +#define SURFINFO_LIGHTMAP (1<<2) // This surface has a lightmap +#define SURFINFO_WAVY (1<<3) // This surface is a wavy surface + +//================================================================================ +// Function defines +//================================================================================ +geBoolean Surf_EngineInit(geEngine *Engine); +void Surf_EngineShutdown(geEngine *Engine); +geBoolean Surf_SetEngine(geEngine *Engine); +geBoolean Surf_SetWorld(geWorld *World); +geBoolean Surf_SetGBSP(World_BSP *BSP); +geBoolean Surf_WorldInit(geWorld *World); +void Surf_WorldShutdown(geWorld *World); + +BOOL Surf_InSurfBoundingBox(Surf_SurfInfo *Surf, geVec3d *Pos, geFloat Box); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/World/Surface.c b/G3D/World/Surface.c new file mode 100644 index 0000000..1f9f7c5 --- /dev/null +++ b/G3D/World/Surface.c @@ -0,0 +1,646 @@ +/****************************************************************************************/ +/* Surface.c */ +/* */ +/* Author: John Pollard */ +/* Description: Creates the surfaces for a BSP from the GFX data */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + + +#include "BaseType.h" +#include "System.h" +#include "World.h" +#include "Ram.h" +#include "Surface.h" +#include "WBitmap.h" +#include "Vec3d.h" +#include "Vis.h" + +#include "Light.h" + +//================================================================================ +// local static globals +//================================================================================ +static geEngine *CEngine; +static geWorld *CWorld; +static GBSP_BSPData *BSPData; // This is in globals, but is also kept here for speed + + +//================================================================================ +// local static functions +//================================================================================ +static geBoolean GetTexVerts(World_BSP *BSP); +static geBoolean GetSurfInfo(World_BSP *BSP); +static geBoolean GetRGBVerts(World_BSP *BSP); + + +//===================================================================================== +// Surf_EngineInit +//===================================================================================== +geBoolean Surf_EngineInit(geEngine *Engine) +{ + return GE_TRUE; +} + +//===================================================================================== +// Surf_EngineShutdown +//===================================================================================== +void Surf_EngineShutdown(geEngine *Engine) +{ + CEngine = NULL; + CWorld = NULL; + BSPData = NULL; +} + +//===================================================================================== +// Surf_SetEngine +// Lets this module know that the engine has changed +//===================================================================================== +geBoolean Surf_SetEngine(geEngine *Engine) +{ + assert (Engine != NULL); + + CEngine = Engine; + + return GE_TRUE; +} + +//===================================================================================== +// Surf_SetWorld +// Lets this module know that the world has changed +//===================================================================================== +geBoolean Surf_SetWorld(geWorld *World) +{ + assert(World != NULL); + + CWorld = World; + + return GE_TRUE; +} + +//===================================================================================== +// Surf_SetGBSP +//===================================================================================== +geBoolean Surf_SetGBSP(World_BSP *BSP) +{ + assert(BSP != NULL); + + // Make quick pointer to the world bsp data + BSPData = &BSP->BSPData; + + return GE_TRUE; +} + +void CalcSurfVectors (World_BSP *BSP); + +//================================================================================ +// Surf_WorldInit +//================================================================================ +geBoolean Surf_WorldInit(geWorld *World) +{ + World_BSP *BSP; + + assert(World != NULL); + + BSP = World->CurrentBSP; + + assert(BSP != NULL); + + // Make sure we free the old ones... + if (BSP->TexVerts) + geRam_Free(BSP->TexVerts); + + if (BSP->SurfInfo) + geRam_Free(BSP->SurfInfo); + + // Create new TexVerts and FaceInfo structure for this bsp + BSP->TexVerts = GE_RAM_ALLOCATE_ARRAY(Surf_TexVert, BSP->BSPData.NumGFXVertIndexList); + BSP->SurfInfo = GE_RAM_ALLOCATE_ARRAY(Surf_SurfInfo, BSP->BSPData.NumGFXFaces); + + // Fill in info needed to render this tree + if (!GetTexVerts(BSP)) // Calc texture uv's at vertices... + return GE_FALSE; + + if (!GetSurfInfo(BSP)) // Get surface info + return GE_FALSE; + + Light_SetWorld(World); + Light_SetGBSP(BSP); + + if (!GetRGBVerts(BSP)) // Calc RGB values at vertices + return GE_FALSE; + + CalcSurfVectors (BSP); + + return GE_TRUE; +} + +//================================================================================ +// Surf_WorldShutdown +//================================================================================ +void Surf_WorldShutdown(geWorld *World) +{ + World_BSP *BSP; + + assert(World != NULL); + + BSP = World->CurrentBSP; + + if (!BSP) + return; + + if (BSP->TexVerts) + geRam_Free(BSP->TexVerts); + if (BSP->SurfInfo) + geRam_Free(BSP->SurfInfo); + + BSP->TexVerts = NULL; + BSP->SurfInfo = NULL; +} + + +//================================================================================ +// Surf_InSurfBoundingBox +//================================================================================ +BOOL Surf_InSurfBoundingBox(Surf_SurfInfo *Surf, geVec3d *Pos, geFloat Box) +{ + assert(Surf != NULL); + assert(Pos != NULL); + +/* eaa3 05/31/2000 charlie_x's optimization added */ + + if(Pos->Z+Box >= Surf->VMins.Z && Pos->Z-Box <= Surf->VMaxs.Z) + { + if(Pos->Y+Box >= Surf->VMins.Y && Pos->Y-Box <= Surf->VMaxs.Y) + { + if(Pos->X+Box >= Surf->VMins.X && Pos->X-Box <= Surf->VMaxs.X) + { + return TRUE; + } + } + } +/* + if (Pos->X+Box >= Surf->VMins.X && Pos->X-Box <= Surf->VMaxs.X) + if (Pos->Y+Box >= Surf->VMins.Y && Pos->Y-Box <= Surf->VMaxs.Y) + if (Pos->Z+Box >= Surf->VMins.Z && Pos->Z-Box <= Surf->VMaxs.Z) + return TRUE; +*/ + + return FALSE; +} + +//================================================================================ +// GetTexVerts +//================================================================================ +static geBoolean GetTexVerts(World_BSP *BSP) +{ + int32 i, v, vn; + int32 *pIndex, TexInfo; + geVec3d *pVert, *pVecU, *pVecV; + geFloat U, V; + Surf_TexVert *TexVerts; + GFX_TexInfo *pTexInfo; + GFX_Face *pFace; + + TexVerts = BSP->TexVerts; + + for (i=0; i< BSP->BSPData.NumGFXFaces; i++) + { + pFace = &BSP->BSPData.GFXFaces[i]; + TexInfo = BSP->BSPData.GFXFaces[i].TexInfo; + pTexInfo = &BSP->BSPData.GFXTexInfo[TexInfo]; + + pVecU = &pTexInfo->Vecs[0]; + pVecV = &pTexInfo->Vecs[1]; + + pIndex = &BSP->BSPData.GFXVertIndexList[pFace->FirstVert]; + vn = pFace->FirstVert; + + for (v= 0; v< pFace->NumVerts; v++, pIndex++, vn++) + { + pVert = &BSP->BSPData.GFXVerts[*pIndex]; + + U = geVec3d_DotProduct(pVert, pVecU); + V = geVec3d_DotProduct(pVert, pVecV); + + TexVerts[vn].u = U; + TexVerts[vn].v = V; + } + } + + return GE_TRUE; +} + + +//================================================================================ +// GetSurfInfo +//================================================================================ +static geBoolean GetSurfInfo(World_BSP *BSP) +{ + int32 NumLTypes; + int32 i, k, v; + int32 vn, Index; + geFloat U, V; + geFloat Mins[2], Maxs[2]; + geVec3d VMins, VMaxs; + int32 Size[2]; + Surf_SurfInfo *SurfInfo; + Surf_TexVert *TexVerts; + GFX_Texture *pTexture; + GFX_TexInfo *pTexInfo; + + SurfInfo = BSP->SurfInfo; + TexVerts = BSP->TexVerts; + + assert(SurfInfo != NULL); + assert(TexVerts != NULL); + + geVec3d_Clear(&VMins); + geVec3d_Clear(&VMaxs); + + memset(SurfInfo, 0, sizeof(Surf_SurfInfo)*(BSP->BSPData.NumGFXFaces)); + + for (i=0; i< BSP->BSPData.NumGFXFaces; i++) + { + geFloat XScale, YScale; + + // Find number of styles + NumLTypes = 0; + for (NumLTypes = 0; NumLTypes < 4; NumLTypes++) + { + if (BSP->BSPData.GFXFaces[i].LTypes[NumLTypes]==255) + break; + + if (BSP->BSPData.GFXFaces[i].LTypes[NumLTypes] != 0) + SurfInfo[i].Flags |= SURFINFO_LTYPED; + } + + SurfInfo[i].NumLTypes = NumLTypes; + + SurfInfo[i].TexInfo = BSP->BSPData.GFXFaces[i].TexInfo; + + pTexInfo = &BSP->BSPData.GFXTexInfo[BSP->BSPData.GFXFaces[i].TexInfo]; + pTexture = &BSP->BSPData.GFXTextures[BSP->BSPData.GFXTexInfo[SurfInfo[i].TexInfo].Texture]; + + if (pTexInfo->Flags & TEXINFO_TRANS) + SurfInfo[i].Flags |= SURFINFO_TRANS; + + // Set up lightmap scaling values for dlights + k = BSP->BSPData.GFXFaces[i].TexInfo; + + XScale = geVec3d_Length(&BSP->BSPData.GFXTexInfo[k].Vecs[0]); + YScale = geVec3d_Length(&BSP->BSPData.GFXTexInfo[k].Vecs[1]); + + SurfInfo[i].XStep = (int32)((16.0f / XScale) * (1<<10)); + SurfInfo[i].YStep = (int32)((16.0f / YScale) * (1<<10)); + SurfInfo[i].XScale = (int32)((1.0f/XScale) * (1<<10)); + SurfInfo[i].YScale = (int32)((1.0f/YScale) * (1<<10)); + } + + // + // Find face/texvert min/max + // + for (i=0; i< BSP->BSPData.NumGFXFaces; i++) + { + pTexInfo = &BSP->BSPData.GFXTexInfo[BSP->BSPData.GFXFaces[i].TexInfo]; + pTexture = &BSP->BSPData.GFXTextures[BSP->BSPData.GFXTexInfo[SurfInfo[i].TexInfo].Texture]; + + for (k=0; k<2; k++) + { + Mins[k] = 99999.0f; + Maxs[k] =-99999.0f; + } + for (k=0; k<3; k++) + { + VectorToSUB(VMins, k) = 99999.0f; + VectorToSUB(VMaxs, k) =-99999.0f; + } + + for (v= 0; v< BSP->BSPData.GFXFaces[i].NumVerts; v++) + { + vn = v + BSP->BSPData.GFXFaces[i].FirstVert; + U = TexVerts[vn].u; + V = TexVerts[vn].v; + + if (U < Mins[0]) + Mins[0] = U; + if (U > Maxs[0]) + Maxs[0] = U; + if (V < Mins[1]) + Mins[1] = V; + if (V > Maxs[1]) + Maxs[1] = V; + + Index = BSP->BSPData.GFXVertIndexList[vn]; + + for (k=0; k<3; k++) + { + if (VectorToSUB(BSP->BSPData.GFXVerts[Index], k) < VectorToSUB(VMins, k)) + VectorToSUB(VMins, k) = VectorToSUB(BSP->BSPData.GFXVerts[Index], k); + if (VectorToSUB(BSP->BSPData.GFXVerts[Index], k) > VectorToSUB(VMaxs, k)) + VectorToSUB(VMaxs, k) = VectorToSUB(BSP->BSPData.GFXVerts[Index], k); + } + } + + // Calculate Shift values + #if 1 + { + int32 Width, Height; + geFloat au, av, ScaleU, ScaleV; + + #if 0 + pTexInfo->DrawScale[0] = 1.0f; // For testing + pTexInfo->DrawScale[1] = 1.0f; + #endif + + ScaleU = 1.0f/pTexInfo->DrawScale[0]; + ScaleV = 1.0f/pTexInfo->DrawScale[1]; + + Width = pTexture->Width; + Height = pTexture->Height; + + // Interpret the uv's the same way the drivers will + au = (geFloat)(((int32)((Mins[0]*ScaleU+pTexInfo->Shift[0])/Width ))*Width); + av = (geFloat)(((int32)((Mins[1]*ScaleV+pTexInfo->Shift[1])/Height))*Height); + //au = (geFloat)(((int32)((Mins[0]*ScaleU)/Width ))*Width); + //av = (geFloat)(((int32)((Mins[1]*ScaleV)/Height))*Height); + + SurfInfo[i].ShiftU = pTexInfo->Shift[0] - au; + SurfInfo[i].ShiftV = pTexInfo->Shift[1] - av; + } + #else + { + SurfInfo[i].ShiftU = pTexInfo->Shift[0]; + SurfInfo[i].ShiftV = pTexInfo->Shift[1]; + } + #endif + + SurfInfo[i].VMins = VMins; + SurfInfo[i].VMaxs = VMaxs; + + if (BSP->BSPData.GFXTexInfo[BSP->BSPData.GFXFaces[i].TexInfo].Flags & TEXINFO_NO_LIGHTMAP) + continue; + + for (k=0; k< 2; k++) + { + Mins[k] = (geFloat)floor(Mins[k]/16); + Maxs[k] = (geFloat)ceil(Maxs[k]/16); + + Size[k] = (S32)(Maxs[k] - Mins[k]) + 1; + + if (Size[k] > MAX_LMAP_SIZE) + { + geErrorLog_Add(GE_ERR_BAD_LMAP_EXTENTS, NULL); + return GE_FALSE; + } + } + + //if (Size[0] != BSP->BSPData.GFXFaces[i].LWidth) + // return FALSE; + + //if (Size[1] != BSP->BSPData.GFXFaces[i].LHeight) + // return FALSE; + + Size[0] = BSP->BSPData.GFXFaces[i].LWidth; + Size[1] = BSP->BSPData.GFXFaces[i].LHeight; + + SurfInfo[i].LInfo.Width = (int16)Size[0]; + SurfInfo[i].LInfo.Height = (int16)Size[1]; + + SurfInfo[i].LInfo.MinU = (S32)(Mins[0] * 16); + SurfInfo[i].LInfo.MinV = (S32)(Mins[1] * 16); + SurfInfo[i].LInfo.Face = i; + + #if 0 + { + int32 LightOffset, p; + uint8 *LightData; + + LightOffset = BSP->BSPData.GFXFaces[i].LightOfs; + + if (LightOffset >= 0) + { + LightData = &BSP->BSPData.GFXLightData[LightOffset+1]; + + for (p=0; p< SurfInfo[i].LInfo.lWidth*SurfInfo[i].LInfo.lHeight; p++) + { + LightData++; + if (*LightData) + return GE_FALSE; + //*LightData = 0; + LightData++; + LightData++; + } + } + } + #endif + + #if 0 + // + // Make sure the lightmap u,v's are legit... + // + for (v= 0; v< BSP->BSPData.GFXFaces[i].NumVerts; v++) + { + vn = v + BSP->BSPData.GFXFaces[i].FirstVert; + + U = TexVerts[vn].u - SurfInfo[i].LInfo.MinU; + V = TexVerts[vn].v - SurfInfo[i].LInfo.MinV; + + if (U < 0 || V > 16*128) + { + SurfInfo[i].LInfo.Face = -1; + //geErrorLog_Add(GE_ERR_BAD_LMAP_EXTENTS, NULL); + //return GE_FALSE; + } + if (V < 0 || V > 16*128) + { + SurfInfo[i].LInfo.Face = -1; + //geErrorLog_Add(GE_ERR_BAD_LMAP_EXTENTS, NULL); + //return GE_FALSE; + } + + } + #endif + + SurfInfo[i].Flags |= SURFINFO_LIGHTMAP; + //CalcGFXFaceVectors(i); + } + + if (!Vis_MarkWaterFaces(BSP)) + return GE_FALSE; + + return GE_TRUE; +} + +//================================================================================ +// GetRGBVerts +//================================================================================ +static geBoolean GetRGBVerts(World_BSP *BSP) +{ + Surf_TexVert *pTexVerts; + GFX_Face *pGFXFace; + int32 i; + geVec3d *pGFXRGBVerts; + + pTexVerts = BSP->TexVerts; + pGFXFace = BSP->BSPData.GFXFaces; + pGFXRGBVerts = BSP->BSPData.GFXRGBVerts; + + for (i=0; i< BSP->BSPData.NumGFXFaces; i++, pGFXFace++) + { + GFX_TexInfo *pTexInfo; + int32 v; + + pTexInfo = &BSP->BSPData.GFXTexInfo[pGFXFace->TexInfo]; + + if (!(pTexInfo->Flags & TEXINFO_GOURAUD) && !(pTexInfo->Flags & TEXINFO_FLAT)) + { + for (v= 0; v< pGFXFace->NumVerts; v++) + { + int32 vn; + + vn = pGFXFace->FirstVert + v; + + pTexVerts[vn].r = 255.0f; + pTexVerts[vn].g = 255.0f; + pTexVerts[vn].b = 255.0f; + } + continue; + } + + for (v= 0; v< pGFXFace->NumVerts; v++) + { + int32 vn; + + vn = pGFXFace->FirstVert + v; + + pTexVerts[vn].r = pGFXRGBVerts[vn].X; + pTexVerts[vn].g = pGFXRGBVerts[vn].Y; + pTexVerts[vn].b = pGFXRGBVerts[vn].Z; + } + } + + return GE_TRUE; +} + +//*************************************************************************************** +// Get Texture to WorldSpace vectors +//*************************************************************************************** +void CalcSurfVectors (World_BSP *BSP) +{ + Surf_SurfInfo *pSurfInfo, *Si; + GFX_TexInfo *Tex; + geVec3d TexNormal; + geVec3d FaceNormal; + geFloat DistScale, PlaneDist; + geFloat Dist, Len; + geVec3d Ws[3]; + int32 i, k; + GBSP_BSPData *BSPData; + GFX_Plane *GFXPlanes; + GFX_Face *pFace; + int32 Startx, Starty; + geFloat UU, VV; + + BSPData = &BSP->BSPData; + + pSurfInfo = BSP->SurfInfo; + + GFXPlanes = BSPData->GFXPlanes; + + for (i=0; i< BSP->BSPData.NumGFXFaces; i++) + { + Si = &pSurfInfo[i]; + + pFace = &BSPData->GFXFaces[i]; + + Tex = &BSPData->GFXTexInfo[pFace->TexInfo]; + + geVec3d_CrossProduct(&Tex->Vecs[0], &Tex->Vecs[1], &TexNormal); + geVec3d_Normalize(&TexNormal); + + // flip it towards plane normal + FaceNormal = GFXPlanes[pFace->PlaneNum].Normal; + PlaneDist = GFXPlanes[pFace->PlaneNum].Dist; + + if (pFace->PlaneSide) + { + geVec3d_Inverse(&FaceNormal); + PlaneDist = -PlaneDist; + } + + DistScale = geVec3d_DotProduct(&TexNormal, &FaceNormal); + + if (DistScale < 0) + { + geVec3d_Inverse(&TexNormal); + DistScale = -DistScale; + } + + // distscale is the ratio of the distance along the texture normal to + // the distance along the plane normal + DistScale = 1/DistScale; + + // Get the tex to world vectors + for (k=0 ; k<2 ; k++) + { + Len = geVec3d_Length(&Tex->Vecs[k]); + Dist = geVec3d_DotProduct(&Tex->Vecs[k], &FaceNormal); + Dist *= DistScale; + geVec3d_MA(&Tex->Vecs[k], -Dist, &TexNormal, &Si->T2WVecs[k]); + geVec3d_Scale(&Si->T2WVecs[k], (1/Len)*(1/Len), &Si->T2WVecs[k]); + } + + + for (k=0 ; k<3 ; k++) + VectorToSUB(Si->TexOrg,k) = + - Tex->Vecs[0].Z * VectorToSUB(Si->T2WVecs[0], k) + - Tex->Vecs[1].Z * VectorToSUB(Si->T2WVecs[1], k); + + Dist = geVec3d_DotProduct(&Si->TexOrg, &FaceNormal) - PlaneDist - 1; + Dist *= DistScale; + geVec3d_MA (&Si->TexOrg, -Dist, &TexNormal, &Si->TexOrg); + + Startx = Si->LInfo.MinU; + Starty = Si->LInfo.MinV; + + UU = (geFloat)Startx; + VV = (geFloat)Starty; + + Ws[0].X = Si->TexOrg.X + Si->T2WVecs[0].X*UU + Si->T2WVecs[1].X*VV; + Ws[0].Y = Si->TexOrg.Y + Si->T2WVecs[0].Y*UU + Si->T2WVecs[1].Y*VV; + Ws[0].Z = Si->TexOrg.Z + Si->T2WVecs[0].Z*UU + Si->T2WVecs[1].Z*VV; + UU = (geFloat)Startx+16.0f; + VV = (geFloat)Starty; + Ws[1].X = Si->TexOrg.X + Si->T2WVecs[0].X*UU + Si->T2WVecs[1].X*VV; + Ws[1].Y = Si->TexOrg.Y + Si->T2WVecs[0].Y*UU + Si->T2WVecs[1].Y*VV; + Ws[1].Z = Si->TexOrg.Z + Si->T2WVecs[0].Z*UU + Si->T2WVecs[1].Z*VV; + UU = (geFloat)Startx; + VV = (geFloat)Starty+16.0f; + Ws[2].X = Si->TexOrg.X + Si->T2WVecs[0].X*UU + Si->T2WVecs[1].X*VV; + Ws[2].Y = Si->TexOrg.Y + Si->T2WVecs[0].Y*UU + Si->T2WVecs[1].Y*VV; + Ws[2].Z = Si->TexOrg.Z + Si->T2WVecs[0].Z*UU + Si->T2WVecs[1].Z*VV; + + geVec3d_Subtract(&Ws[1], &Ws[0], &Si->T2WVecs[0]); + geVec3d_Subtract(&Ws[2], &Ws[0], &Si->T2WVecs[1]); + Si->TexOrg = Ws[0]; + } + +} diff --git a/G3D/World/TRACE.H b/G3D/World/TRACE.H new file mode 100644 index 0000000..3acf577 --- /dev/null +++ b/G3D/World/TRACE.H @@ -0,0 +1,141 @@ +/****************************************************************************************/ +/* Trace.h */ +/* */ +/* Author: John Pollard */ +/* Description: BSP collision detection code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_TRACE_H +#define GE_TRACE_H + +#include +#include + +#include "Genesis.h" +#include "BaseType.h" +#include "Vec3d.h" +#include "World.h" +//#include "System.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//===================================================================================== +// Defines / Structure defines +//===================================================================================== +#define PSIDE_FRONT 1 +#define PSIDE_BACK 2 +#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK) +#define PSIDE_FACING 4 + +int32 Trace_BoxOnPlaneSide(const geVec3d *Mins, const geVec3d *Maxs, GFX_Plane *Plane); +geBoolean Trace_BBoxInVisibleLeaf(geWorld *World, geVec3d *Mins, geVec3d *Maxs); + +//===================================================================================== +// Function ProtoTypes +//===================================================================================== + + +geBoolean Trace_GEWorldCollision( geWorld *World, + const geVec3d *Mins, + const geVec3d *Maxs, + const geVec3d *Front, + const geVec3d *Back, + uint32 Contents, // Contents to collide with + uint32 CollideFlags, // GE_COLLIDE_ALL, etc... + uint32 UserFlags, // Flags to mask against actors + GE_CollisionCB *CollisionCB, + void *Context, + GE_Collision *Col); + +geBoolean Trace_WorldCollisionBNode(geWorld *World, + geVec3d *Front, + geVec3d *Back, + int32 *ModelNum, + geVec3d *Impact, + int32 *Node, + int32 *Plane, + int32 *Side); + +geBoolean Trace_WorldCollisionExact(geWorld *World, + const geVec3d *Front, + const geVec3d *Back, + uint32 Flags, + geVec3d *Impact, + GFX_Plane *Plane, + geWorld_Model **Model, + Mesh_RenderQ **Mesh, + geActor **Actor, + uint32 UserFlags, + GE_CollisionCB *CollisionCB, + void *Context); + +// Internal only/ does not chek meshes/ returns index numbers into bsp structures for models +geBoolean Trace_WorldCollisionExact2(geWorld *World, + const geVec3d *Front, + const geVec3d *Back, + geVec3d *Impact, + int32 *Node, + int32 *Plane, + int32 *Side); + +geBoolean Trace_MiscCollision(GFX_BNode *BNodes, GFX_Plane *Planes, const geVec3d *Mins, const geVec3d *Maxs, const geVec3d *Front, const geVec3d *Back, geXForm3d *XForm, geVec3d *I, GFX_Plane *P); +geBoolean Trace_MiscCollision2(GFX_BNode *BNodes, GFX_Plane *Planes, const geVec3d *Front, const geVec3d *Back, geVec3d *I, int32 *P); + +geBoolean Trace_WorldCollisionBBox( geWorld *World, + const geVec3d *Mins, const geVec3d *Maxs, + const geVec3d *Front, const geVec3d *Back, + uint32 Flags, + geVec3d *I, GFX_Plane *P, + geWorld_Model **Model, + Mesh_RenderQ **Mesh, + geActor **Actor, + uint32 UserFlags, + GE_CollisionCB *CollisionCB, + void *Context); + +geBoolean Trace_TestModelMove( geWorld *World, + geWorld_Model *Model, + const geXForm3d *DXForm, + const geVec3d *Mins, const geVec3d *Maxs, + const geVec3d *In, geVec3d *Out); + +geBoolean Trace_ModelCollision(geWorld *World, + geWorld_Model *Model, + const geXForm3d *DXForm, + GE_Collision *Collision, + //Mesh_RenderQ **ImpactedMesh, + geVec3d *ImpactPoint); + +geBoolean Trace_InverseTreeFromBox(geVec3d *Mins, geVec3d *Maxs, GFX_BNode *BNodes, GFX_Plane *Planes); + +geBoolean Trace_GetContents(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, uint32 Flags, uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, GE_Contents *Contents); +// changed texture name +geBoolean Trace_GetTexureName(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, char *TexName); +// end change texture name + +void Trace_GetMoveBox(const geVec3d *Mins, const geVec3d *Maxs, const geVec3d *Front, const geVec3d *Back, geVec3d *OMins, geVec3d *OMaxs); + +void Trace_SetupIntersect(geWorld *World); +geBoolean Trace_IntersectWorldBSP(geVec3d *Front, geVec3d *Back, int32 Node); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/World/Trace.c b/G3D/World/Trace.c new file mode 100644 index 0000000..4271aa2 --- /dev/null +++ b/G3D/World/Trace.c @@ -0,0 +1,2359 @@ +/****************************************************************************************/ +/* Trace.c */ +/* */ +/* Author: John Pollard */ +/* Description: BSP collision detection code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "XForm3d.h" +#include "BaseType.h" +#include "GBSPFile.h" +#include "World.h" +#include "System.h" +#include "Plane.h" +#include "Trace.h" +#include "ExtBox.h" +#include "Actor.h" + +#define ON_EPSILON (0.1f) + +//===================================================================================== +// Local Static Globals +//===================================================================================== + +// Globals returned in the bsp subdivision code +static int32 GPlaneNum; +static GFX_Plane GlobalPlane; +static int32 GlobalNode; +static int32 GlobalSide; +static geVec3d GlobalI; +static geFloat GRatio; +static int32 GlobalLeaf; +static int32 GlobalLeaf; + +static GBSP_BSPData *BSPData; + +// Globals passed to the bsp subdivision code +static uint32 gContents; // Contents that we should collide with for the current collision tests... + +static BOOL UseMinsMaxs; // If MiscCollision should use mins maxs... + +static BOOL HitSet; +static int32 GlobalNNode[2]={0x696C6345,0x21657370}; + +int32 NumExactCast; +int32 NumBBoxCast; +int32 NumGetContents; + +//===================================================================================== +// Local Static Function Prototypes +//===================================================================================== +static geBoolean BSPIntersect(geVec3d *Front, geVec3d *Back, int32 Node); + + + +static geActor *Trace_ActorCollide(geWorld *World, + const geVec3d *Mins, const geVec3d *Maxs, + const geVec3d *Front,const geVec3d *Back, + geVec3d *CollisionPoint,GFX_Plane *BestPlane, + uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, geFloat *BestD ) +{ + int i,Count; + World_Actor *WA; + geVec3d RayDirection; + geFloat RayLength; + geFloat Dist; + geActor *BestActor = NULL; + geVec3d FakeMins = {-1.0f, -1.0f, -1.0f}; + geVec3d FakeMaxs = { 1.0f, 1.0f, 1.0f}; + int32 k; + geVec3d OMins, OMaxs; + + if (!Mins) + Mins = &FakeMins; + + if (!Maxs) + Maxs = &FakeMaxs; + + geVec3d_Subtract(Back,Front,&RayDirection); + RayLength = geVec3d_Normalize(&RayDirection); + + Count = World->ActorCount; + WA = &(World->ActorArray[0]); + + Trace_GetMoveBox(Mins, Maxs, Front, Back, &OMins, &OMaxs); + + for (i=0; iFlags & GE_ACTOR_COLLIDE) || !(WA->UserFlags & UserFlags) ) + continue; + + if (CollisionCB && !CollisionCB(NULL, WA->Actor, Context)) + continue; + + if (!geActor_GetExtBox(WA->Actor, &B)) + continue; + + for (k=0; k<3; k++) + { + if (geVec3d_GetElement(&OMaxs, k) < geVec3d_GetElement(&B.Min, k)) + break; + + if (geVec3d_GetElement(&OMins, k) > geVec3d_GetElement(&B.Max, k)) + break; + } + + if (k != 3) + continue; + + geVec3d_Subtract(&B.Min, Maxs, &B.Min); + geVec3d_Subtract(&B.Max, Mins, &B.Max); + + if (!geExtBox_RayCollision( &B, Front, Back, &Dist, &Normal )) + continue; + + //Dist -= 0.01f; + if (Dist < 0.0f) + Dist = 0.0f; + if (Dist > 1.0f) + Dist = 1.0f; + + Dist *= RayLength; + + if (Dist < *BestD) + { + BestActor = WA->Actor; + *BestD = Dist; + BestPlane->Normal = Normal; + + geVec3d_AddScaled(Front,&RayDirection,Dist,CollisionPoint); + BestPlane->Dist = geVec3d_DotProduct(CollisionPoint,&Normal); + + BestPlane->Type = PLANE_ANY; + } + } + + return BestActor; +} + + + +//===================================================================================== +// Trace_GEWorldCollision +// Function specially designed for GE UI... +//===================================================================================== +geBoolean Trace_GEWorldCollision(geWorld *World, const geVec3d *Mins, const geVec3d *Maxs, const geVec3d *Front, const geVec3d *Back, uint32 Contents, uint32 CollideFlags, uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, GE_Collision *Col) +{ + geVec3d I; + GFX_Plane Plane; + geWorld_Model *Model; + Mesh_RenderQ *Mesh; + geActor *Actor; + + assert(World != NULL); + assert(World->CurrentBSP != NULL); + assert(Front != NULL); + assert(Back!= NULL); + assert(Contents); // It does not make sense to collide with nothing!!! + + // Set the global contents to collide with + gContents = Contents; + + BSPData = &World->CurrentBSP->BSPData; + + // Reset all the collision feedback pointers + Model = NULL; + Mesh = NULL; + Actor = NULL; + + Col->Model = NULL; + Col->Mesh = NULL; + Col->Actor = NULL; + + if (Mins && Maxs) + { + NumBBoxCast++; + if (Trace_WorldCollisionBBox(World, Mins, Maxs, Front, Back, CollideFlags, &I, &Plane, &Model, &Mesh, &Actor, UserFlags, CollisionCB, Context)) + { + + Col->Impact = I; + Col->Plane.Normal = Plane.Normal; + Col->Plane.Dist = Plane.Dist; + + Col->Model = Model; + Col->Mesh = (geMesh*)Mesh; + Col->Actor = Actor; + + Col->Ratio = GRatio; + return GE_TRUE; + } + } + else + { + NumExactCast++; + + if (Trace_WorldCollisionExact(World, Front, Back, CollideFlags, &I, &Plane, &Model, &Mesh, &Actor, UserFlags, CollisionCB, Context)) + { + Col->Impact = I; + Col->Plane.Normal = Plane.Normal; + Col->Plane.Dist = Plane.Dist; + + Col->Model = Model; + Col->Mesh = (geMesh*)Mesh; + Col->Actor = Actor; + + Col->Ratio = GRatio; + + return GE_TRUE; + } + } + return GE_FALSE; +} + +//===================================================================================== +// Trace_WorldCollisionExact +//===================================================================================== +geBoolean Trace_WorldCollisionExact(geWorld *World, + const geVec3d *Front, + const geVec3d *Back, + uint32 Flags, + geVec3d *Impact, + GFX_Plane *Plane, + geWorld_Model **Model, + Mesh_RenderQ **Mesh, + geActor **Actor, + uint32 UserFlags, + GE_CollisionCB *CollisionCB, + void *Context) +{ + int32 i, b; + geVec3d NewFront1, NewBack1; + geVec3d NewFront2, NewBack2; + geWorld_Model *Models, *BestModel; + GFX_Plane BestPlane, Plane2; + Mesh_RenderQ *BestMesh=NULL; + geActor *BestActor=NULL; + geVec3d OMins, OMaxs, Vect, Impact2, BestI; + static geVec3d MMins = {-1.0f, -1.0f, -1.0f}; + static geVec3d MMaxs = { 1.0f, 1.0f, 1.0f}; + geBoolean Hit; + geFloat Dist, BestD; + + assert(World != NULL); + assert(World->CurrentBSP != NULL); + assert(Front != NULL); + assert(Back!= NULL); + + BSPData = &World->CurrentBSP->BSPData; + Models = World->CurrentBSP->Models; + + // Clear mesh/model collision pointers + if (Model) + *Model = NULL; + if (Mesh) + *Mesh = NULL; + if (Actor) + *Actor = NULL; + + BestD = 99999.0f; + BestModel = NULL; + BestMesh = NULL; + Hit = GE_FALSE; + + if (Flags & GE_COLLIDE_ACTORS) + { + BestActor = Trace_ActorCollide(World,NULL, NULL, Front,Back,&Impact2, &Plane2, UserFlags, CollisionCB, Context, &BestD); + if (BestActor != NULL) + { + BestI = Impact2; + BestPlane = Plane2; + Hit = GE_TRUE; + } + } + + if (!(Flags & GE_COLLIDE_MODELS)) + goto NoModels; + + Trace_GetMoveBox(&MMins, &MMaxs, Front, Back, &OMins, &OMaxs); + + for (i = 0; i < BSPData->NumGFXModels; i++, Models++) + { + // First, give the caller a chance to reject the model + if (CollisionCB && !CollisionCB(Models, NULL, Context)) + continue; + + for (b=0; b<3; b++) + { + if (VectorToSUB(OMaxs, b) < VectorToSUB(Models->TMins, b)) + break; + if (VectorToSUB(OMins, b) > VectorToSUB(Models->TMaxs, b)) + break; + } + + if (b != 3) + continue; + + // Move to models center of rotation + geVec3d_Subtract(Front, &Models->Pivot, &NewFront1); + geVec3d_Subtract(Back , &Models->Pivot, &NewBack1); + + // InverseTransform the point about models center of rotation + geXForm3d_TransposeTransform(&Models->XForm, &NewFront1, &NewFront2); + geXForm3d_TransposeTransform(&Models->XForm, &NewBack1 , &NewBack2); + + // push back into world + geVec3d_Add(&NewFront2, &Models->Pivot, &NewFront1); + geVec3d_Add(&NewBack2 , &Models->Pivot, &NewBack1); + + HitSet = FALSE; + + if (BSPIntersect(&NewFront1, &NewBack1, BSPData->GFXModels[i].RootNode[0])) + { + // Rotate the impact plane + geXForm3d_Rotate(&Models->XForm, &GlobalPlane.Normal, &GlobalPlane.Normal); + + // Rotate the impact point + geVec3d_Subtract(&GlobalI, &Models->Pivot, &GlobalI); + geXForm3d_Transform(&Models->XForm, &GlobalI, &GlobalI); + geVec3d_Add(&GlobalI, &Models->Pivot, &GlobalI); + + // Find the new plane distance based on the new impact point with the new plane + GlobalPlane.Dist = geVec3d_DotProduct(&GlobalPlane.Normal, &GlobalI); + + geVec3d_Subtract(&GlobalI, Front, &Vect); + Dist = geVec3d_Length(&Vect); + + if (Dist < BestD) + { + BestD = Dist; + BestI = GlobalI; + + BestPlane = GlobalPlane; + if (GlobalSide) + { + geVec3d_Inverse(&BestPlane.Normal); + BestPlane.Dist = -BestPlane.Dist; + BestPlane.Type = PLANE_ANY; + } + + BestMesh = NULL; // Clear hit mesh + BestActor = NULL; + BestModel = Models; + Hit = GE_TRUE; + } + } + + if ((Flags & GE_COLLIDE_NO_SUB_MODELS)) + goto NoModels; + } + + NoModels: + + if (Hit) + { + if (Impact) + *Impact = BestI; + if (Plane) + *Plane = BestPlane; + if (Model) + *Model = BestModel; + if (Mesh) + *Mesh = BestMesh; + if (Actor) + *Actor = BestActor; + return GE_TRUE; + } + + return GE_FALSE; +} + +//===================================================================================== +// Trace_WorldCollisionExact2 +// Internal only/ does not chek meshes/ returns index numbers into bsp structures for models +// FIXME: This can be replaced by callinf Trace_WorldCollisionExact with the GE_COLLIDE_MODELS +// flag only... +//===================================================================================== +geBoolean Trace_WorldCollisionExact2( geWorld *World, + const geVec3d *Front, + const geVec3d *Back, + geVec3d *Impact, + int32 *Node, + int32 *Plane, + int32 *Side) +{ + int32 i; + geVec3d NewFront1, NewBack1; + geVec3d NewFront2, NewBack2; + geWorld_Model *Models; + + assert(World != NULL); + assert(World->CurrentBSP != NULL); + assert(Front != NULL); + assert(Back!= NULL); + + BSPData = &World->CurrentBSP->BSPData; + Models = World->CurrentBSP->Models; + + GPlaneNum = -1; + + gContents = GE_CONTENTS_SOLID_CLIP; + + for (i = 0; i < BSPData->NumGFXModels; i++) + { + + // Move to models center of rotation + geVec3d_Subtract(Front, &Models[i].Pivot, &NewFront1); + geVec3d_Subtract(Back , &Models[i].Pivot, &NewBack1); + + // InverseTransform the point about models center of rotation + geXForm3d_TransposeTransform(&Models[i].XForm, &NewFront1, &NewFront2); + geXForm3d_TransposeTransform(&Models[i].XForm, &NewBack1 , &NewBack2); + + // push back into world + geVec3d_Add(&NewFront2, &Models[i].Pivot, &NewFront1); + geVec3d_Add(&NewBack2 , &Models[i].Pivot, &NewBack1); + + HitSet = FALSE; + + if (BSPIntersect(&NewFront1, &NewBack1, BSPData->GFXModels[i].RootNode[0])) + { + if (GPlaneNum == -1) + return FALSE; + + if (Impact) *Impact = GlobalI; + if (Node) *Node = GlobalNode; + if (Plane) *Plane = GPlaneNum; + if (Side) *Side = GlobalSide; + + return GE_TRUE; + } + } + + return GE_FALSE; +} + +//===================================================================================== +// Local static support functions +//===================================================================================== + +//===================================================================================== +// BSPIntersect +// Shoot a ray through the tree finding out what solid leafs it passed through +//===================================================================================== +static geBoolean BSPIntersect(geVec3d *Front, geVec3d *Back, int32 Node) +{ + geFloat Fd, Bd, Dist; + int32 Side; + geVec3d I; + GFX_Plane *Plane; + int32 Contents; + + if (Node < 0) + { + Contents = BSPData->GFXLeafs[-(Node+1)].Contents; + + if (Contents & gContents) + return GE_TRUE; // Ray collided with solid space + + return GE_FALSE; + } + + Plane = &BSPData->GFXPlanes[BSPData->GFXNodes[Node].PlaneNum]; + + Fd = Plane_PlaneDistanceFast(Plane, Front); + Bd = Plane_PlaneDistanceFast(Plane, Back); + + if (Fd >= 0 && Bd >= 0) + return(BSPIntersect(Front, Back, BSPData->GFXNodes[Node].Children[0])); + if (Fd < 0 && Bd < 0) + return(BSPIntersect(Front, Back, BSPData->GFXNodes[Node].Children[1])); + + Side = Fd < 0; + Dist = Fd / (Fd - Bd); + + I.X = Front->X + Dist * (Back->X - Front->X); + I.Y = Front->Y + Dist * (Back->Y - Front->Y); + I.Z = Front->Z + Dist * (Back->Z - Front->Z); + + // Work our way to the front, from the back side. As soon as there + // is no more collisions, we can assume that we have the front portion of the + // ray that is in empty space. Once we find this, and see that the back half is in + // solid space, then we found the front intersection point... + if (BSPIntersect(Front, &I, BSPData->GFXNodes[Node].Children[Side])) + return GE_TRUE; + else if (BSPIntersect(&I, Back, BSPData->GFXNodes[Node].Children[!Side])) + { + if (!HitSet) + { + GPlaneNum = BSPData->GFXNodes[Node].PlaneNum; + GlobalPlane = BSPData->GFXPlanes[GPlaneNum]; + GlobalSide = Side; + GlobalI = I; + GlobalNode = Node; + GRatio = Dist; + HitSet = TRUE; + } + return GE_TRUE; + } + + return GE_FALSE; +} + +//===================================================================================== +// BSPIntersectMesh +//===================================================================================== +static GFX_BNode *MiscBNodes; +static GFX_Node *MiscNodes; +static GFX_Plane *MiscPlanes; +static GFX_Leaf *MiscLeafs; +static GFX_LeafSide *MiscSides; + +static geVec3d GMins1, GMaxs1; +static geVec3d GMins2, GMaxs2; +static geVec3d GFront, GBack; +static BOOL LeafHit; +static geFloat BestDist; + +static geBoolean BSPIntersectMisc(geVec3d *Front, geVec3d *Back, int32 Node) +{ + geFloat Fd, Bd, Dist; + uint8 Side; + GFX_Plane Plane; + geVec3d I; + + if (Node == BSP_CONTENTS_SOLID) + return GE_TRUE; // Ray collided with solid space + if (Node < 0) + return GE_FALSE; // Ray collided with empty space + + Plane = MiscPlanes[MiscBNodes[Node].PlaneNum]; + Plane.Type = PLANE_ANY; + + if (UseMinsMaxs) + { + if (Plane.Normal.X > 0) + Plane.Dist -= Plane.Normal.X * GMins1.X; + else + Plane.Dist -= Plane.Normal.X * GMaxs1.X; + + if (Plane.Normal.Y > 0) + Plane.Dist -= Plane.Normal.Y * GMins1.Y; + else + Plane.Dist -= Plane.Normal.Y * GMaxs1.Y; + + if (Plane.Normal.Z > 0) + Plane.Dist -= Plane.Normal.Z * GMins1.Z; + else + Plane.Dist -= Plane.Normal.Z * GMaxs1.Z; + } + + Fd = Plane_PlaneDistanceFast(&Plane, Front); + Bd = Plane_PlaneDistanceFast(&Plane, Back); + + if (Fd >= 0 && Bd >= 0) + return(BSPIntersectMisc(Front, Back, MiscBNodes[Node].Children[0])); + if (Fd < 0 && Bd < 0) + return(BSPIntersectMisc(Front, Back, MiscBNodes[Node].Children[1])); + + Side = Fd < 0; + Dist = Fd / (Fd - Bd); + + I.X = Front->X + Dist * (Back->X - Front->X); + I.Y = Front->Y + Dist * (Back->Y - Front->Y); + I.Z = Front->Z + Dist * (Back->Z - Front->Z); + + // Work our way to the front, from the back side. As soon as there + // is no more collisions, we can assume that we have the front portion of the + // ray that is in empty space. Once we find this, and see that the back half is in + // solid space, then we found the front intersection point... + if (BSPIntersectMisc(Front, &I, MiscBNodes[Node].Children[Side])) + return TRUE; + else if (BSPIntersectMisc(&I, Back, MiscBNodes[Node].Children[!Side])) + { + if (!HitSet) + { + GPlaneNum = MiscBNodes[Node].PlaneNum; + GlobalPlane = Plane; + GlobalSide = Side; + GlobalI = I; + GRatio = Dist; + HitSet = TRUE; + } + return GE_TRUE; + } + + return GE_FALSE; +} + +//===================================================================================== +// Trace_MiscCollision +// Does a collision with a given tree, ray and transform +// (The tree will be rotated by the transform, well actually the +// ray will be inverse rotated) +//===================================================================================== +geBoolean Trace_MiscCollision(GFX_BNode *BNodes, GFX_Plane *Planes, const geVec3d *Mins, const geVec3d *Maxs, const geVec3d *Front, const geVec3d *Back, geXForm3d *XForm, geVec3d *I, GFX_Plane *P) +{ + geVec3d NewFront, NewBack; + geVec3d Trans; + + GPlaneNum = -1; //Safeguard to prevent a bad index + + // Set Global misc vars + MiscBNodes = BNodes; + MiscPlanes = Planes; + + if (Mins && Maxs) + { + GMins1 = *Mins; + GMaxs1 = *Maxs; + UseMinsMaxs = TRUE; + } + else + UseMinsMaxs = FALSE; + + // Move ray into tree space + Trans.X = XForm->Translation.X; + Trans.Y = XForm->Translation.Y; + Trans.Z = XForm->Translation.Z; + + geVec3d_Subtract(Front, &Trans, &NewFront); + geVec3d_Subtract(Back, &Trans, &NewBack); + + HitSet = FALSE; + + if (BSPIntersectMisc(&NewFront, &NewBack, 0)) + { + if (!HitSet) // Was in solid, but did not cross any planes... + return GE_FALSE; // So just return false... + + geVec3d_Add(&GlobalI, &Trans, &GlobalI); + + if (I) *I = GlobalI; // Set the intersection point + if (P) + { + *P = GlobalPlane; + // Adjust so plane is at impact point + P->Dist += geVec3d_DotProduct(&Trans, &P->Normal); + } + + return GE_TRUE; + } + + return GE_FALSE; +} + +//===================================================================================== +// BSPIntersectMisc2 +//===================================================================================== +static geBoolean BSPIntersectMisc2(const geVec3d *Front, const geVec3d *Back, int32 Node) +{ + geFloat Fd, Bd, Dist; + uint8 Side; + GFX_Plane Plane; + geVec3d I; + + if (Node == BSP_CONTENTS_SOLID) + return GE_TRUE; // Ray collided with solid space + if (Node < 0) + return GE_FALSE; // Ray collided with empty space + + Plane = MiscPlanes[MiscBNodes[Node].PlaneNum]; + Plane.Type = PLANE_ANY; + + Fd = Plane_PlaneDistanceFast(&Plane, Front); + Bd = Plane_PlaneDistanceFast(&Plane, Back); + + if (Fd >= 0 && Bd >= 0) + return(BSPIntersectMisc2(Front, Back, MiscBNodes[Node].Children[0])); + if (Fd < 0 && Bd < 0) + return(BSPIntersectMisc2(Front, Back, MiscBNodes[Node].Children[1])); + + Side = Fd < 0; + Dist = Fd / (Fd - Bd); + + I.X = Front->X + Dist * (Back->X - Front->X); + I.Y = Front->Y + Dist * (Back->Y - Front->Y); + I.Z = Front->Z + Dist * (Back->Z - Front->Z); + + // Work our way to the front, from the back side. As soon as there + // is no more collisions, we can assume that we have the front portion of the + // ray that is in empty space. Once we find this, and see that the back half is in + // solid space, then we found the front intersection point... + if (BSPIntersectMisc2(Front, &I, MiscBNodes[Node].Children[Side])) + return TRUE; + else if (BSPIntersectMisc2(&I, Back, MiscBNodes[Node].Children[!Side])) + { + if (!HitSet) + { + GPlaneNum = MiscBNodes[Node].PlaneNum; + GlobalPlane = Plane; + GlobalSide = Side; + GlobalI = I; + GRatio = Dist; + HitSet = TRUE; + } + return GE_TRUE; + } + + return GE_FALSE; +} + +//===================================================================================== +// Trace_MiscCollision2 +//===================================================================================== +geBoolean Trace_MiscCollision2(GFX_BNode *BNodes, GFX_Plane *Planes, const geVec3d *Front, const geVec3d *Back, geVec3d *I, int32 *P) +{ + GPlaneNum = -1; //Safeguard to prevent a bad index + + // Set Global misc vars + MiscBNodes = BNodes; + MiscPlanes = Planes; + + HitSet = FALSE; + + if (BSPIntersectMisc2(Front, Back, 0)) + { + if (!HitSet || GPlaneNum == -1) // Was in solid, but did not cross any planes... + return GE_FALSE; // So just return false... + + if (I) + *I = GlobalI; // Set the intersection point + if (P) + *P = GPlaneNum; + + return GE_TRUE; + } + + return GE_FALSE; +} + +//===================================================================================== +// Trace_BoxOnPlaneSide +// +// Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH +//===================================================================================== +int32 Trace_BoxOnPlaneSide(const geVec3d *Mins, const geVec3d *Maxs, GFX_Plane *Plane) +{ + int32 Side; + int32 i; + geVec3d Corners[2]; + geFloat Dist1, Dist2; + + // Axial planes are easy + if (Plane->Type < PLANE_ANYX) + { + Side = 0; + if (VectorToSUB(*Maxs, Plane->Type) >= Plane->Dist) + Side |= PSIDE_FRONT; + if (VectorToSUB(*Mins, Plane->Type) < Plane->Dist) + Side |= PSIDE_BACK; + return Side; + } + + // Create the proper leading and trailing verts for the box + for (i=0 ; i<3 ; i++) + { + if (VectorToSUB(Plane->Normal, i) < 0) + { + VectorToSUB(Corners[0], i) = VectorToSUB(*Mins, i); + VectorToSUB(Corners[1], i) = VectorToSUB(*Maxs, i); + } + else + { + VectorToSUB(Corners[1], i) = VectorToSUB(*Mins, i); + VectorToSUB(Corners[0], i) = VectorToSUB(*Maxs, i); + } + } + + Dist1 = geVec3d_DotProduct(&Plane->Normal, &Corners[0]) - Plane->Dist; + Dist2 = geVec3d_DotProduct(&Plane->Normal, &Corners[1]) - Plane->Dist; + + Side = 0; + if (Dist1 >= 0) + Side = PSIDE_FRONT; + if (Dist2 < 0) + Side |= PSIDE_BACK; + + return Side; +} + +//===================================================================================== +// Trace_ExpandPlaneForBox +// Pushes a plan out by the side of the box it is looking at +//===================================================================================== +void Trace_ExpandPlaneForBox(GFX_Plane *Plane, geVec3d *Mins, geVec3d *Maxs) +{ + geVec3d *Normal; + + Normal = &Plane->Normal; + + if (Normal->X > 0) + Plane->Dist -= Normal->X * Mins->X; + else + Plane->Dist -= Normal->X * Maxs->X; + + if (Normal->Y > 0) + Plane->Dist -= Normal->Y * Mins->Y; + else + Plane->Dist -= Normal->Y * Maxs->Y; + + if (Normal->Z > 0) + Plane->Dist -= Normal->Z * Mins->Z; + else + Plane->Dist -= Normal->Z * Maxs->Z; +} + +//===================================================================================== +// IntersectLeafSides +//===================================================================================== +static geBoolean PointInLeafSides(const geVec3d *Pos, const GFX_Leaf *Leaf) +{ + int32 i, f; + GFX_Plane Plane; + geFloat Dist; + + f = Leaf->FirstSide; + + for (i=0; i< Leaf->NumSides; i++) + { + Plane = MiscPlanes[MiscSides[i+f].PlaneNum]; + Plane.Type = PLANE_ANY; + + if (MiscSides[i+f].PlaneSide) + { + geVec3d_Inverse(&Plane.Normal); + Plane.Dist = -Plane.Dist; + } + + // Simulate the point having a box, by pushing the plane out by the box size + Trace_ExpandPlaneForBox(&Plane, &GMins1, &GMaxs1); + + Dist = Plane_PlaneDistanceFast(&Plane, Pos); + + if (Dist >= 0.0f) + return GE_FALSE; // Since leafs are convex, it must be outside... + } + + return GE_TRUE; +} + +//===================================================================================== +// IntersectLeafSides +//===================================================================================== +BOOL IntersectLeafSides_r(geVec3d *Front, geVec3d *Back, int32 Leaf, int32 Side, int32 PSide) +{ + geFloat Fd, Bd, Dist; + GFX_Plane Plane; + int32 RSide, Side2; + geVec3d I, Vec; + + if (!PSide) + return FALSE; + + if (Side >= MiscLeafs[Leaf].NumSides) + return TRUE; // if it lands behind all planes, it is inside + + RSide = MiscLeafs[Leaf].FirstSide + Side; + + Plane = MiscPlanes[MiscSides[RSide].PlaneNum]; + Plane.Type = PLANE_ANY; + + if (MiscSides[RSide].PlaneSide) + { + geVec3d_Inverse(&Plane.Normal); + Plane.Dist = -Plane.Dist; + } + + // Simulate the point having a box, by pushing the plane out by the box size + Trace_ExpandPlaneForBox(&Plane, &GMins1, &GMaxs1); + + Fd = Plane_PlaneDistanceFast(&Plane, Front); + Bd = Plane_PlaneDistanceFast(&Plane, Back); + +#if 1 + if (Fd >= 0 && Bd >= 0) // Leaf sides are convex hulls, so front side is totally outside + return IntersectLeafSides_r(Front, Back, Leaf, Side+1, 0); + + if (Fd < 0 && Bd < 0) + return IntersectLeafSides_r(Front, Back, Leaf, Side+1, 1); +#else + if ((Fd >= ON_EPSILON && Bd >= ON_EPSILON) || (Bd > Fd && Fd >= 0) ) + return IntersectLeafSides_r(Front, Back, Leaf, Side+1, 0); + + if ((Fd < -ON_EPSILON && Bd < -ON_EPSILON) || (Bd < Fd && Fd <= 0)) + return IntersectLeafSides_r(Front, Back, Leaf, Side+1, 1); +#endif + + // We have an intersection + + //Dist = Fd / (Fd - Bd); + + Side2 = Fd < 0; + + if (Fd < 0) + Dist = (Fd + ON_EPSILON)/(Fd-Bd); + else + Dist = (Fd - ON_EPSILON)/(Fd-Bd); + + if (Dist < 0.0f) + Dist = 0.0f; + + if (Dist > 1.0f) + Dist = 1.0f; + + I.X = Front->X + Dist * (Back->X - Front->X); + I.Y = Front->Y + Dist * (Back->Y - Front->Y); + I.Z = Front->Z + Dist * (Back->Z - Front->Z); + + // Only go down the back side, since the front side is empty in a convex tree + if (IntersectLeafSides_r(Front, &I, Leaf, Side+1, Side2)) + { + LeafHit = TRUE; + return TRUE; + } + else if (IntersectLeafSides_r(&I, Back, Leaf, Side+1, !Side2)) + { + geVec3d_Subtract(&I, &GFront, &Vec); + Dist = geVec3d_Length(&Vec); + + // Record the intersection closest to the start of ray + if (Dist < BestDist && !HitSet) + { + GlobalI = I; + GlobalLeaf = Leaf; + BestDist = Dist; + GlobalPlane = Plane; + GRatio = Dist; + HitSet = TRUE; + } + LeafHit = TRUE; + return TRUE; + } + + return FALSE; +} + +//===================================================================================== +// IntersectLeafSides2 +//===================================================================================== +BOOL IntersectLeafSides2(geVec3d *Pos, int32 Leaf) +{ + GFX_Plane Plane; + int32 i; + geFloat Dist; + + for (i=0; i< MiscLeafs[Leaf].NumSides; i++) + { + Plane = MiscPlanes[MiscSides[MiscLeafs[Leaf].FirstSide+i].PlaneNum]; + + if (!MiscSides[MiscLeafs[Leaf].FirstSide+i].PlaneSide) + { + geVec3d_Inverse(&Plane.Normal); + Plane.Dist = -Plane.Dist; + } + + Dist = geVec3d_DotProduct(&Plane.Normal, Pos) - Plane.Dist; + + if (Dist >= 25.0f) + return FALSE; + } + + LeafHit = TRUE; + return TRUE; +} + +//===================================================================================== +// FindClosestLeafIntersection_r +//===================================================================================== +static void FindClosestLeafIntersection_r(int32 Node) +{ + int32 Leaf, Side, Contents; + + if (Node < 0) + { + Leaf = -(Node+1); + Contents = MiscLeafs[Leaf].Contents; + + //if (Contents != BSP_CONTENTS_SOLID && Contents != BSP_CONTENTS_WINDOW) + if (!(Contents & gContents)) + return; // Only solid leafs contain side info... + + HitSet = FALSE; + + if (!MiscLeafs[Leaf].NumSides) + return; + + IntersectLeafSides_r(&GFront, &GBack, Leaf, 0, 1); + //IntersectLeafSides2(&GBack, Leaf); + + return; + } + + Side = Trace_BoxOnPlaneSide(&GMins2, &GMaxs2, &MiscPlanes[MiscNodes[Node].PlaneNum]); + + // Go down the sides that the box lands in + if (Side & PSIDE_FRONT) + FindClosestLeafIntersection_r(MiscNodes[Node].Children[0]); + + if (Side & PSIDE_BACK) + FindClosestLeafIntersection_r(MiscNodes[Node].Children[1]); +} + +#define SIDE_SPACE 0.1f +//===================================================================================== +// Trace_WorldCollisionBBox +// Shoots a ray through the world, using the expandable leaf hull +// The hull is expanded by the input BBox to simulate the points having volume... +//===================================================================================== +geBoolean Trace_WorldCollisionBBox( geWorld *World, + const geVec3d *Mins, const geVec3d *Maxs, + const geVec3d *Front, const geVec3d *Back, + uint32 Flags, + geVec3d *I, GFX_Plane *P, + geWorld_Model **Model, + Mesh_RenderQ **Mesh, + geActor **Actor, + uint32 UserFlags, + GE_CollisionCB *CollisionCB, + void *Context) +{ + geWorld_Model *Models; + geVec3d NewFront, NewBack, OMins, OMaxs, BestI, Vect; + geVec3d Impact; + int32 i, b; + geFloat Dist, BestD; + Mesh_RenderQ *BestMesh; + #ifdef MESHES + Mesh_RenderQ *Mesh2; + #endif + geActor *BestActor; + geWorld_Model *BestModel; + GFX_Plane BestPlane, Plane2; + geBoolean Hit; + + if (Model) + *Model = NULL; + if (Mesh) + *Mesh = NULL; + if (Actor) + *Actor = NULL; + + BestD = 99999.0f; + BestMesh = NULL; + BestModel = NULL; + BestActor = NULL; + Hit = GE_FALSE; // Have not hit nothing yet... + + // Test meshes first... (record the closest collision) + if (Flags & GE_COLLIDE_MESHES) + { +#ifdef MESHES + if (Mesh_MeshCollisionAll(World, Mins, Maxs, Front, Back, &Impact, &Plane2, &Mesh2, UserFlags)) + { + geVec3d_Subtract(&Impact, Front, &Vect); + Dist = geVec3d_Length(&Vect); + if (Dist < BestD) + { + BestD = Dist; + BestI = Impact; + BestMesh = Mesh2; + BestPlane = Plane2; + Hit = GE_TRUE; // We hit somthing + } + } +#endif + } + + + if (Flags & GE_COLLIDE_ACTORS) + { + BestActor = Trace_ActorCollide(World, Mins,Maxs, Front,Back,&Impact,&Plane2,UserFlags, CollisionCB, Context, &BestD); + if (BestActor != NULL) + { + BestI = Impact; + BestPlane = Plane2; + Hit = GE_TRUE; + } + } + + + // GMins1/GMaxs1 is what is used to exapand the plane out with + GMins1 = *Mins; + GMaxs1 = *Maxs; + + GFront = *Front; + GBack = *Back; + + BSPData = &World->CurrentBSP->BSPData; + Models = World->CurrentBSP->Models; + + MiscNodes = BSPData->GFXNodes; + MiscPlanes = BSPData->GFXPlanes; + MiscLeafs = BSPData->GFXLeafs; + MiscSides = BSPData->GFXLeafSides; + + assert(MiscNodes != NULL); + assert(MiscPlanes != NULL); + assert(MiscLeafs != NULL); + assert(MiscSides != NULL); + + if (!(Flags & GE_COLLIDE_MODELS)) + goto NoModels; + + Trace_GetMoveBox(Mins, Maxs, Front, Back, &OMins, &OMaxs); + + // Then test the world bsp(all models are the world bsp) + // Go through each model, and find out what leafs we hit, keeping the closest intersection + for (i = 0; i < BSPData->NumGFXModels; i++, Models++) + { + + // First, see if the user wants to reject it... + if (CollisionCB && !CollisionCB(Models, NULL, Context)) + continue; + + for (b=0; b<3; b++) + { + if (VectorToSUB(OMaxs, b) < VectorToSUB(Models->TMins, b)) + break; + if (VectorToSUB(OMins, b) > VectorToSUB(Models->TMaxs, b)) + break; + } + + if (b != 3) + continue; + + + // Reset flags + BestDist = 9999.0f; + LeafHit = FALSE; + + geVec3d_Subtract(Front, &Models->Pivot, &GFront); + geVec3d_Subtract(Back , &Models->Pivot, &GBack); + + // InverseTransform the point about models center of rotation + geXForm3d_TransposeTransform(&Models->XForm, &GFront, &NewFront); + geXForm3d_TransposeTransform(&Models->XForm, &GBack , &NewBack); + + // push back into world + geVec3d_Add(&NewFront, &Models->Pivot, &GFront); + geVec3d_Add(&NewBack , &Models->Pivot, &GBack); + + // Make out box out of this move so we only check the leafs it intersected with... + + Trace_GetMoveBox(Mins, Maxs, &GFront, &GBack, &GMins2, &GMaxs2); + + FindClosestLeafIntersection_r(BSPData->GFXModels[i].RootNode[0]); + + if (LeafHit) + { + + // Rotate the impact plane + geXForm3d_Rotate(&Models->XForm, &GlobalPlane.Normal, &GlobalPlane.Normal); + + // Rotate the impact point + geVec3d_Subtract(&GlobalI, &Models->Pivot, &GlobalI); + geXForm3d_Transform(&Models->XForm, &GlobalI, &NewFront); + //geXForm3d_Rotate(&Models->XForm, &GlobalI, &NewFront); + geVec3d_Add(&NewFront, &Models->Pivot, &GlobalI); + + // Find the new plane distance based on the new impact point with the new plane + GlobalPlane.Dist = geVec3d_DotProduct(&GlobalPlane.Normal, &GlobalI); + + geVec3d_Subtract(&GlobalI, Front, &Vect); + + Dist = geVec3d_Length(&Vect); + if (Dist < BestD) + { + BestD = Dist; + BestI = GlobalI; + BestPlane = GlobalPlane; + BestModel = Models; + BestMesh = NULL; // Reset the mesh flag... + BestActor = NULL; + Hit = GE_TRUE; + } + } + + if ((Flags & GE_COLLIDE_NO_SUB_MODELS)) + goto NoModels; + + } + + NoModels: + + if (Hit) + { + if (I) + *I = BestI; + if (P) + *P = BestPlane; + if (Mesh) + *Mesh = BestMesh; + if (Model) + *Model = BestModel; + if (Actor) + *Actor = BestActor; + return GE_TRUE; + } + + return GE_FALSE; +} + +//===================================================================================== +// Trace_TestModelMove +//===================================================================================== +geBoolean Trace_TestModelMove( geWorld *World, + geWorld_Model *Model, + const geXForm3d *DXForm, + const geVec3d *Mins, const geVec3d *Maxs, + const geVec3d *In, geVec3d *Out) +{ + geVec3d NewFront, NewBack, Original; + + assert(World != NULL); + assert(Model != NULL); + + BSPData = &World->CurrentBSP->BSPData; + + MiscNodes = BSPData->GFXNodes; + MiscPlanes = BSPData->GFXPlanes; + MiscLeafs = BSPData->GFXLeafs; + MiscSides = BSPData->GFXLeafSides; + + assert(MiscNodes != NULL); + assert(MiscPlanes != NULL); + assert(MiscLeafs != NULL); + assert(MiscSides != NULL); + + Original = *In; // Save original + + GMins1 = *Mins; + GMaxs1 = *Maxs; + + // Put point about models origin + geVec3d_Subtract(In, &Model->Pivot, &GFront); + GBack = GFront; + + // InverseTransform the points about models center of rotation + geXForm3d_TransposeTransform(&Model->XForm, &GFront, &NewFront); + // The back gets applied by the dest XForm + geXForm3d_TransposeTransform(DXForm, &GBack, &NewBack); + + // push back into world + geVec3d_Add(&NewFront, &Model->Pivot, &GFront); + geVec3d_Add(&NewBack , &Model->Pivot, &GBack); + + // Make out box out of this move so we only check the leafs it intersected with... + Trace_GetMoveBox(Mins, Maxs, &GFront, &GBack, &GMins2, &GMaxs2); + + BestDist = 9999.0f; + LeafHit = FALSE; + + FindClosestLeafIntersection_r(BSPData->GFXModels[Model->GFXModelNum].RootNode[0]); + + if (LeafHit) + { + GE_Collision Collision; + + // Rotate the impact plane + geXForm3d_Rotate(DXForm, &GlobalPlane.Normal, &GlobalPlane.Normal); + + // Rotate the impact point + geVec3d_Subtract(&GlobalI, &Model->Pivot, &NewFront); + geXForm3d_Transform(DXForm, &NewFront, &GlobalI); + geVec3d_Add(&GlobalI, &Model->Pivot, &NewFront); + GlobalI = NewFront; + + // Find the new plane distance based on the new impact point with the new plane + GlobalPlane.Dist = geVec3d_DotProduct(&GlobalPlane.Normal, &GlobalI); + + geVec3d_MA(&GlobalI, ON_EPSILON, &GlobalPlane.Normal, &GlobalI); + + // If the point gets pushed into the world as a result of the move, then cancel it out... + if (Trace_GEWorldCollision(World, Mins, Maxs, In, &GlobalI, GE_CONTENTS_SOLID_CLIP, GE_COLLIDE_ALL, 0xffffffff, NULL, NULL, &Collision)) + { + *Out = Original; + return GE_FALSE; + } + + *Out = GlobalI; + + return GE_TRUE; + } + + *Out = Original; + + return GE_TRUE; +} + +//===================================================================================== +// Trace_ModelCollisionBBox +//===================================================================================== +static +geBoolean Trace_ModelCollisionBBox(geWorld *World, + geWorld_Model *Model, + const geXForm3d *DXForm, + const geVec3d *Mins, const geVec3d *Maxs, + const geVec3d *In, + geVec3d *ImpactPoint) +{ + //MRB BEGIN + // geVec3d NewFront, NewBack, Original; + geVec3d NewFront, NewBack; + //MRB END + assert(World != NULL); + assert(Model != NULL); + BSPData = &World->CurrentBSP->BSPData; + MiscNodes = BSPData->GFXNodes; + MiscPlanes = BSPData->GFXPlanes; + MiscLeafs = BSPData->GFXLeafs; + MiscSides = BSPData->GFXLeafSides; + assert(MiscNodes != NULL); + assert(MiscPlanes != NULL); + assert(MiscLeafs != NULL); + assert(MiscSides != NULL); + //MRB BEGIN + // Original = *In; // Save original + //MRB END + GMins1 = *Mins; + GMaxs1 = *Maxs; + + // Put point about models origin + geVec3d_Subtract(In, &Model->Pivot, &GFront); + GBack = GFront; + // InverseTransform the points about models center of rotation + geXForm3d_TransposeTransform(&Model->XForm, &GFront, &NewFront); + // The back gets applied by the dest XForm + geXForm3d_TransposeTransform(DXForm, &GBack, &NewBack); + // push back into world + geVec3d_Add(&NewFront, &Model->Pivot, &GFront); + geVec3d_Add(&NewBack , &Model->Pivot, &GBack); + // Make out box out of this move so we only check the leafs it intersected with... + Trace_GetMoveBox(Mins, Maxs, &GFront, &GBack, &GMins2, &GMaxs2); + + BestDist = 9999.0f; + LeafHit = FALSE; + FindClosestLeafIntersection_r(BSPData->GFXModels[Model->GFXModelNum].RootNode[0]); + if (LeafHit) + { + // Rotate the impact plane + geXForm3d_Rotate(DXForm, &GlobalPlane.Normal, &GlobalPlane.Normal); + + // Rotate the impact point + //MRB BEGIN + // geVec3d_Subtract(&GlobalI, &Model->Pivot, &NewFront); + // geXForm3d_Transform(DXForm, &NewFront, &GlobalI); + // geVec3d_Add(&GlobalI, &Model->Pivot, &NewFront); + // GlobalI = NewFront; + geVec3d_Subtract(&GlobalI, &Model->Pivot, &GlobalI); + geXForm3d_Transform(DXForm, &GlobalI, &NewFront); + geVec3d_Add(&NewFront, &Model->Pivot, &GlobalI); + //MRB END + // Find the new plane distance based on the new impact point with the new plane + GlobalPlane.Dist = geVec3d_DotProduct(&GlobalPlane.Normal, &GlobalI); + geVec3d_MA(&GlobalI, ON_EPSILON, &GlobalPlane.Normal, &GlobalI); + *ImpactPoint = GlobalI; + return GE_TRUE; + } + return GE_FALSE; +} +//===================================================================================== +// Trace_ModelCollision +//===================================================================================== +geBoolean Trace_ModelCollision(geWorld *World, + geWorld_Model *Model, + const geXForm3d *DXForm, + GE_Collision *Collision, + geVec3d *ImpactPoint) +{ + geExtBox ExtBox; + geVec3d Pos; + geXForm3d myXForm; +#ifdef MESHES + Mesh_RenderQ * CollidableMesh; + Mesh_CollidableMeshIterator Iter; +#endif + gContents = GE_CONTENTS_SOLID_CLIP; // eaa3 from G3D BBS posting 01/29/2001 + memset(Collision, 0, sizeof(GE_Collision)); + // Fixed bug that mike pointed out. I was using 0, instead of 0xffffffff +#ifdef MESHES + CollidableMesh = Mesh_FirstCollidableMesh(World, &Iter, 0xffffffff); + while (CollidableMesh) + { + Mesh_MeshGetBox(World, CollidableMesh->MeshDef, &Mins, &Maxs); + Mesh_MeshGetPosition(CollidableMesh, &Pos); + if (Trace_ModelCollisionBBox(World, Model, DXForm, &Mins, &Maxs, &Pos, ImpactPoint)) + { + Collision->Mesh = (geMesh *)CollidableMesh; + return GE_TRUE; + } + CollidableMesh = Mesh_NextCollidableMesh(&Iter, 0xffffffff); + } +#endif + { + int i,Count; + World_Actor *WA; + //MRB BEGIN + geActor *BestActor; + geFloat BestActorDist; + geVec3d PossibleImpactPoint; + BestActor = NULL; + BestActorDist = 9999.0f; + //MRB END + + Count = World->ActorCount; + WA = &(World->ActorArray[0]); + for (i=0; i < Count; i++, WA++) + { + // if it's active (ignore userflags?) + if ( (WA->Flags & GE_ACTOR_COLLIDE) ) + { + //MRB BEGIN + // if (geActor_GetExtBox(WA->Actor,&ExtBox)!=GE_FALSE) + // { + geActor_GetNonWorldExtBox(WA->Actor,&ExtBox); + geActor_GetPosition(WA->Actor, &Pos); + // eaa3 from posting on G3D message board 01/29/2001 + geActor_GetBoneTransform(WA->Actor, NULL, &myXForm); + geVec3d_Copy(&myXForm.Translation, &Pos); + geVec3d_Subtract(&ExtBox.Min, &Pos, &ExtBox.Min); + geVec3d_Subtract(&ExtBox.Max, &Pos, &ExtBox.Max); + // end eaa3 01/29/2001 + // if (Trace_ModelCollisionBBox(World, Model, DXForm, &(ExtBox.Min), &(ExtBox.Max), &Pos, ImpactPoint)) + if (Trace_ModelCollisionBBox(World, Model, DXForm, &(ExtBox.Min), &(ExtBox.Max), &Pos, &PossibleImpactPoint)) + { + // Collision->Actor = WA->Actor; + if (GlobalPlane.Dist < BestActorDist) + { + BestActorDist = GlobalPlane.Dist; + BestActor = WA->Actor; + (*ImpactPoint) = PossibleImpactPoint; + Collision->Plane.Normal = GlobalPlane.Normal; + Collision->Plane.Dist = GlobalPlane.Dist; + Collision->Ratio = geVec3d_DistanceBetween(&DXForm->Translation, &Model->XForm.Translation); + } + // return GE_TRUE; + } + // } + //MRB END + } + } + //MRB BEGIN + if (BestActor) { + Collision->Actor = BestActor; + return GE_TRUE; + } + //MRB END + } + return GE_FALSE; +} + + +//===================================================================================== +// MoveBox +// Creates a box around the entire move +//===================================================================================== +void Trace_GetMoveBox(const geVec3d *Mins, const geVec3d *Maxs, const geVec3d *Front, const geVec3d *Back, geVec3d *OMins, geVec3d *OMaxs) +{ + int32 i; + + assert(Mins); + assert(Maxs); + assert(Front); + assert(Back); + + for (i=0 ; i<3 ; i++) + { + if (VectorToSUB(*Back, i) > VectorToSUB(*Front, i)) + { + VectorToSUB(*OMins, i) = VectorToSUB(*Front, i) + VectorToSUB(*Mins, i) - 1.0f; + VectorToSUB(*OMaxs, i) = VectorToSUB(*Back, i) + VectorToSUB(*Maxs, i) + 1.0f; + } + else + { + VectorToSUB(*OMins, i) = VectorToSUB(*Back, i) + VectorToSUB(*Mins, i) - 1.0f; + VectorToSUB(*OMaxs, i) = VectorToSUB(*Front, i) + VectorToSUB(*Maxs, i) + 1.0f; + } + } +} + + +static geBoolean VisibleLeaf; +//===================================================================================== +// BBoxInVisibleLeaf_r +//===================================================================================== +static void BBoxInVisibleLeaf_r(geWorld *World, geVec3d *Mins, geVec3d *Maxs, int32 Node) +{ + int32 Leaf, Side; + + if (VisibleLeaf) + return; + + if (Node < 0) // At a leaf, see if it's visible + { + Leaf = -(Node+1); + + if (World->CurrentBSP->LeafData[Leaf].VisFrame == World->CurFrameStatic) + VisibleLeaf = TRUE; + + return; + } + + Side = Trace_BoxOnPlaneSide(Mins, Maxs, &MiscPlanes[MiscNodes[Node].PlaneNum]); + + // Go down the sides that the box lands in + if (Side & PSIDE_FRONT) + BBoxInVisibleLeaf_r(World, Mins, Maxs, MiscNodes[Node].Children[0]); + + if (Side & PSIDE_BACK) + BBoxInVisibleLeaf_r(World, Mins, Maxs, MiscNodes[Node].Children[1]); +} + +geBoolean Trace_BBoxInVisibleLeaf(geWorld *World, geVec3d *Mins, geVec3d *Maxs) +{ + VisibleLeaf = FALSE; + + MiscNodes = World->CurrentBSP->BSPData.GFXNodes; + MiscPlanes = World->CurrentBSP->BSPData.GFXPlanes; + + BBoxInVisibleLeaf_r(World, Mins, Maxs, 0); + + return VisibleLeaf; +} + +//=================================================================================== +// Trace_InverseTreeFromBox +// Builds am inside out collision tree from a box +//=================================================================================== +geBoolean Trace_InverseTreeFromBox(geVec3d *Mins, geVec3d *Maxs, GFX_BNode *BNodes, GFX_Plane *Planes) +{ + int32 i,j,n; + geFloat Bounds[2][3]; + GFX_Plane *Plane; + + for (i=0; i< 3; i++) + { + Bounds[0][i] = VectorToSUB(*Mins, i); + Bounds[1][i] = VectorToSUB(*Maxs, i); + } + + // Build the boxs planes + for (i=0; i< 3; i++) + { + for (j=0; j< 2; j++) + { + n = j*3 + i; + + Plane = &Planes[n]; + + memset(Plane, 0, sizeof(GFX_Plane)); + + if (!j) // Inside out + { + VectorToSUB(Plane->Normal, i) = 1.0f; + Plane->Dist = Bounds[j][i]; + } + else + { + VectorToSUB(Plane->Normal, i) = -1.0f; + Plane->Dist = -Bounds[j][i]; + } + + Plane->Type = PLANE_ANY; + + // + // Build the tree + // + BNodes[n].PlaneNum = n; + + BNodes[n].Children[1] = BSP_CONTENTS_SOLID; + + if (n == 5) + BNodes[n].Children[0] = BSP_CONTENTS_EMPTY; + else + BNodes[n].Children[0] = n+1; + } + } + + return GE_TRUE; +} + +//===================================================================================== +// Trace_FindBNodeContents +// BNodes are special. Instead of having a negative index to a leaf, the negative +// node number represents the contents of the leaf... +//===================================================================================== +int32 Plane_FindBNodeContents( const GFX_BNode *Nodes, + const GFX_Plane *Planes, + int32 Node, + const geVec3d *POV) +{ + geFloat Dist; + + while (Node >= 0) // < 0 == leaf with contents + { + Dist = Plane_PlaneDistanceFast(&Planes[Nodes[Node].PlaneNum], POV); + + if (Dist < 0) + Node = Nodes[Node].Children[1]; + else + Node = Nodes[Node].Children[0]; + } + + return Node; // Return the contents +} + +//===================================================================================== +// FillContents_r +// Traverses the leafs and or's all the contents together +//===================================================================================== +static void FillContents_r(int32 Node, const geVec3d *Pos, uint32 *Contents) +{ + int32 Side; + + if (Node < 0) // At a leaf, fill contens and return + { + int32 Leaf; + + Leaf = -(Node+1); + if (PointInLeafSides(Pos, &MiscLeafs[Leaf])) + *Contents |= MiscLeafs[Leaf].Contents; + return; + } + + Side = Trace_BoxOnPlaneSide(&GMins2, &GMaxs2, &MiscPlanes[MiscNodes[Node].PlaneNum]); + + // Go down the sides that the box lands in + if (Side & PSIDE_FRONT) + FillContents_r(MiscNodes[Node].Children[0], Pos, Contents); + + if (Side & PSIDE_BACK) + FillContents_r(MiscNodes[Node].Children[1], Pos, Contents); +} + +//=================================================================================== +// Trace_GetContents +// Fills a Contents structure with data and returns GE_TRUE if somthing was occupied +// Otherwise, it returns GE_FALSE and nothing is assumed to be occupied +//=================================================================================== +geBoolean Trace_GetContents(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, uint32 Flags, uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, GE_Contents *Contents) +{ + Mesh_RenderQ *MeshHit; + geActor *ActorHit; + geExtBox MeshExtBox; + geVec3d TMins, TMaxs; + geBoolean Hit; + int32 i, k; + uint32 NewContents, FinalContents; + geWorld_Model *Models, *ModelHit; + GFX_Model *GFXModels; + + assert(World); + assert(Contents); + + MeshHit = NULL; + ModelHit = NULL; + FinalContents = 0; + Hit = GE_FALSE; + + BSPData = &World->CurrentBSP->BSPData; + + // Get the translated box from the input pos... + geVec3d_Add(Mins, Pos, &TMins); + geVec3d_Add(Maxs, Pos, &TMaxs); + + NumGetContents++; + + if (Flags & GE_COLLIDE_ACTORS) + { + int32 Count; + World_Actor *WA; + + Count = World->ActorCount; + WA = &(World->ActorArray[0]); + + for (i=0; iFlags & GE_ACTOR_COLLIDE) || !(WA->UserFlags & UserFlags) ) + continue; + + if (CollisionCB && !CollisionCB(NULL, WA->Actor, Context)) + continue; + + + if (geActor_GetExtBox(WA->Actor,&MeshExtBox)==GE_FALSE) + continue; + + for (k=0; k<3; k++) + { + if (geVec3d_GetElement(&TMaxs,k) < geVec3d_GetElement(&(MeshExtBox.Min),k)-1) + break; + if (geVec3d_GetElement(&TMins,k) > geVec3d_GetElement(&(MeshExtBox.Max),k)+1) + break; + } + + if (k != 3) + continue; + + ActorHit = WA->Actor; + Hit = GE_TRUE; + break; // Just return the first actor + } + } + + if (!(Flags & GE_COLLIDE_MODELS)) + goto NoModels; + + MiscNodes = World->CurrentBSP->BSPData.GFXNodes; + MiscPlanes = World->CurrentBSP->BSPData.GFXPlanes; + MiscLeafs = World->CurrentBSP->BSPData.GFXLeafs; + MiscSides = BSPData->GFXLeafSides; + + Models = World->CurrentBSP->Models; + GFXModels = World->CurrentBSP->BSPData.GFXModels; + + GMins1 = *Mins; + GMaxs1 = *Maxs; + + GMins2 = TMins; + GMaxs2 = TMaxs; + + for (i = 0; i < BSPData->NumGFXModels; i++, Models++, GFXModels++) + { + geVec3d TPos; + + if (CollisionCB && !CollisionCB(Models, NULL, Context)) + continue; + + if (i > 0) // Ignore model 0 box (main world, we should always try to collide with world) + { + for (k=0; k<3; k++) + { + if (VectorToSUB(TMaxs, k) < VectorToSUB(Models->TMins, k)) + break; + if (VectorToSUB(TMins, k) > VectorToSUB(Models->TMaxs, k)) + break; + } + + if (k != 3) // Couldn't possibly hit if box's don't hit... + continue; + } + + geVec3d_Subtract(Pos, &Models->RealCenter, &TPos); + + // InverseTransform the point about models center of rotation + geXForm3d_TransposeTransform(&Models->XForm, &TPos, &TPos); + + // push back into world + + geVec3d_Add(&TPos, &Models->RealCenter, &TPos); + + // Reset contents + NewContents = 0; + + FillContents_r(GFXModels->RootNode[0], &TPos, &NewContents); + + if (NewContents && !ModelHit) + { + ModelHit = Models; // First model hit for any arbritrary contents + Hit = GE_TRUE; + } + + if (NewContents & GE_CONTENTS_SOLID_CLIP) // Solid has precedence + { + ModelHit = Models; + } + + // Or final contents with this new contents + FinalContents |= NewContents; + + if ((Flags & GE_COLLIDE_NO_SUB_MODELS)) + goto NoModels; + } + + NoModels: + + if (Hit) + { + Contents->Contents = FinalContents; + Contents->Mesh = (geMesh*)MeshHit; + Contents->Model = ModelHit; + Contents->Actor = ActorHit; + return GE_TRUE; + } + + // If nothing occupied, then make sure the return structure is cleared for cleanness + memset(Contents, 0, sizeof(GE_Contents)); + + return GE_FALSE; +} + + + +//===================================================================================== +// Trace_SetupIntersect +//===================================================================================== +static GFX_Plane *TreePlanes; +static GFX_Node *TreeNodes; +static GFX_Leaf *TreeLeafs; + +void Trace_SetupIntersect(geWorld *World) +{ + BSPData = &World->CurrentBSP->BSPData; + + TreePlanes = BSPData->GFXPlanes; + TreeNodes = BSPData->GFXNodes; + TreeLeafs = BSPData->GFXLeafs; +} + +//===================================================================================== +// Trace_IntersectWorldBSP +// Shoot a ray through the tree finding out what solid leafs it passed through +//===================================================================================== +geBoolean Trace_IntersectWorldBSP(geVec3d *Front, geVec3d *Back, int32 Node) +{ + geFloat Fd, Bd, Dist; + int32 Side; + geVec3d I; + GFX_Plane *Plane; + int32 Contents; + + gContents = GE_CONTENTS_SOLID_CLIP; + + if (Node < 0) + { + Contents = TreeLeafs[-(Node+1)].Contents; + + if (Contents & gContents) + return GE_TRUE; // Ray collided with solid space + return GE_FALSE; + } + + Plane = &TreePlanes[TreeNodes[Node].PlaneNum]; + + Fd = Plane_PlaneDistanceFast(Plane, Front); + Bd = Plane_PlaneDistanceFast(Plane, Back); + + if (Fd >= 0 && Bd >= 0) + return(BSPIntersect(Front, Back, TreeNodes[Node].Children[0])); + if (Fd < 0 && Bd < 0) + return(BSPIntersect(Front, Back, TreeNodes[Node].Children[1])); + + Side = Fd < 0; + Dist = Fd / (Fd - Bd); + + I.X = Front->X + Dist * (Back->X - Front->X); + I.Y = Front->Y + Dist * (Back->Y - Front->Y); + I.Z = Front->Z + Dist * (Back->Z - Front->Z); + + // Work our way to the front, from the back side. As soon as there + // is no more collisions, we can assume that we have the front portion of the + // ray that is in empty space. Once we find this, and see that the back half is in + // solid space, then we found the front intersection point... + if (BSPIntersect(Front, &I, TreeNodes[Node].Children[Side])) + return GE_TRUE; + else if (BSPIntersect(&I, Back, TreeNodes[Node].Children[!Side])) + { + return GE_TRUE; + } + + return GE_FALSE; +} + +static geVec3d gStart, gEnd; +static GFX_Plane gPlane; + +geBoolean Trace_CollideBeam(int32 Node, geVec3d *s, geVec3d *e, geFloat Radius) +{ + geFloat dd, sDist, eDist; + geVec3d tempVec, tempVec2; + geBoolean FrontLeaf, BackLeaf; + GFX_Plane *Plane; + + if(Node < 0) + { + //leaf found, check contents + return !(!(BSPData->GFXLeafs[-(Node+1)].Contents & gContents)); + } + Plane =&BSPData->GFXPlanes[BSPData->GFXNodes[Node].PlaneNum]; + + //startpoint and endpoint plane distances + sDist =Plane_PlaneDistanceFast(Plane, s); + eDist =Plane_PlaneDistanceFast(Plane, e); + + //check sides for start and end... + if(*((uint32 *)&sDist) & 0x80000000) //if sdist < 0 + { + if(sDist < -Radius) + { + if(*((uint32 *)&eDist) & 0x80000000) //if edist < 0 + { + if(eDist < -Radius) + { + //nothing to front, all to back + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius); + } + else + { + //impact to e to front, all back + //find spot where dist==-Radius along motionVec + //make this the front s + dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(s, &tempVec2, &tempVec); + + //send new piece to front + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], &tempVec, e, Radius); + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius); + } + } + else + { + if(eDist > Radius) + { + //impact to e to front, sdist to impact to back + //find spot where dist==-Radius along motionVec + //make this the front s + dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius)); + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(s, &tempVec2, &tempVec); + + //send new piece to front + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], &tempVec, e, Radius); + + //find spot where dist==Radius along motionVec + //make this the back e + dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(e, &tempVec2, &tempVec); + + //send new piece to back + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, &tempVec, Radius); + } + else + { + //impact to edist to front, all to back + //find spot where dist==-Radius along motionVec + //make this the front s + dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(s, &tempVec2, &tempVec); + + //send new piece to front + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], &tempVec, e, Radius); + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius); + } + } + } + else + { + if(*((uint32 *)&eDist) & 0x80000000) //if edist < 0 + { + if(eDist < -Radius) + { + //sdist to impact to front, all back + //find spot where dist==-Radius along motionVec + //make this the front e + dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(e, &tempVec2, &tempVec); + + //send new piece to front + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, &tempVec, Radius); + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius); + } + else + { + //all to front, all to back + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius); + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius); + } + } + else + { + if(eDist > Radius) + { + //all to front, sdist to impact to back + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius); + + //find the spot where dist==Radius along motionVec + //make this the back e + dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(e, &tempVec2, &tempVec); + + //send new piece to back + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, &tempVec, Radius); + } + else + { + //all to front, all to back + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius); + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius); + } + } + } + } + else + { + if(sDist > Radius) + { + if(!(*((uint32 *)&eDist) & 0x80000000)) //if edist > 0 + { + if(eDist > Radius) + { + //all to front, none to back + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius); + } + else + { + //all to front, impact to edist to back + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius); + + //find spot where dist==Radius along motionVec + //make this the back s + dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(e, &tempVec2, &tempVec); + + //send new piece to back + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], &tempVec, e, Radius); + } + } + else + { + if(eDist < -Radius) + { + //sdist to impact to front, impact to edist to back + //find spot where dist==-Radius along motionVec + //make this the front e + dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius)); + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(e, &tempVec2, &tempVec); + + //send new piece to front + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, &tempVec, Radius); + + //find spot where dist==Radius along motionVec + //make this the back s + dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(s, &tempVec2, &tempVec); + + //send new piece to back + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], &tempVec, e, Radius); + } + else + { + //all to front, impact to edist to back + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius); + + //find spot where dist==Radius along motionVec + //make this the back s + dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(s, &tempVec2, &tempVec); + + //send new piece to back + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], &tempVec, e, Radius); + } + } + } + else + { + if(!(*((uint32 *)&eDist) & 0x80000000)) //if edist > 0 + { + if(eDist > Radius) + { + //all to front, sdist to impact to back + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius); + + //find the spot where dist==Radius along motionVec + //make this the back e + dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(e, &tempVec2, &tempVec); + + //send new piece to back + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, &tempVec, Radius); + } + else + { + //all to front, all to back + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius); + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius); + } + } + else + { + if(eDist < -Radius) + { + //sdist to impact to front, all to back + //find spot where dist==-Radius along motionVec + //make this the front e + dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius)); + + //cap the push back factor (don't allow negative) + if(*((uint32 *)&dd) & 0x80000000) //is dd negative? + { + dd =0.0f; + } + + geVec3d_Subtract(e, s, &tempVec); + geVec3d_Scale(&tempVec, dd, &tempVec2); + geVec3d_Add(e, &tempVec2, &tempVec); + + //send new piece to front + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, &tempVec, Radius); + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius); + } + else + { + //all to front, all to back + FrontLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius); + BackLeaf =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius); + } + } + } + } + + //bsp ordering makes the magic happen + //stack based can early out methinks, but it's way too ugly + if(BackLeaf && !FrontLeaf) + { + gStart =*s; + gEnd =*e; + gPlane =*Plane; + } + + //this will nullify farther collisions + return GE_FALSE; +} + +// changed texture name + + +//===================================================================================== +// FillContents_tr +// Traverses the leafs and or's all the contents together +//===================================================================================== +static void FillContents_tr(geWorld *World, int32 Node, const geVec3d *Pos, char *texname) +{ + int32 Side; + + if (Node < 0) // At a leaf, fill contens and return + { + int32 Leaf; + + Leaf = -(Node+1); + if (PointInLeafSides(Pos, &MiscLeafs[Leaf])) + { + //gePoly *Poly = World->CurrentBSP->LeafData[Leaf].PolyList; + //if(Poly) + { + //const geBitmap *Bitmap = Poly->Bitmap; + //char *name = geWBitmap_Pool_GetWNameByBitmap(World->CurrentBSP->WBitmapPool, Bitmap); + char str[100]; + sprintf(str,"Leaf : %d\n",Leaf); + OutputDebugString(str); + //if(name) + //{ + // strcpy(str, name); + // OutputDebugString(str); OutputDebugString("\n"); + //} + } + } + return; + } + + Side = Trace_BoxOnPlaneSide(&GMins2, &GMaxs2, &MiscPlanes[MiscNodes[Node].PlaneNum]); + + // Go down the sides that the box lands in + if (Side & PSIDE_FRONT) + FillContents_tr(World, MiscNodes[Node].Children[0], Pos, texname); + + if (Side & PSIDE_BACK) + FillContents_tr(World, MiscNodes[Node].Children[1], Pos, texname); +} + +//=================================================================================== +// Trace_GetexureName +// Get texture name and returns GE_TRUE if somthing was occupied +// Otherwise, it returns GE_FALSE and nothing is assumed to be occupied +//=================================================================================== +geBoolean Trace_GetTexureName(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, char *TexName) +{ + geVec3d TMins, TMaxs; + geBoolean Hit; + int32 i, k; + geWorld_Model *Models, *ModelHit; + GFX_Model *GFXModels; + + assert(World); + + ModelHit = NULL; + Hit = GE_FALSE; + + BSPData = &World->CurrentBSP->BSPData; + + // Get the translated box from the input pos... + geVec3d_Add(Mins, Pos, &TMins); + geVec3d_Add(Maxs, Pos, &TMaxs); + + MiscNodes = World->CurrentBSP->BSPData.GFXNodes; + MiscPlanes = World->CurrentBSP->BSPData.GFXPlanes; + MiscLeafs = World->CurrentBSP->BSPData.GFXLeafs; + MiscSides = BSPData->GFXLeafSides; + + Models = World->CurrentBSP->Models; + GFXModels = World->CurrentBSP->BSPData.GFXModels; + + GMins1 = *Mins; + GMaxs1 = *Maxs; + + GMins2 = TMins; + GMaxs2 = TMaxs; + + for (i = 0; i < BSPData->NumGFXModels; i++, Models++, GFXModels++) + { + geVec3d TPos; + + if (i > 0) // Ignore model 0 box (main world, we should always try to collide with world) + { + for (k=0; k<3; k++) + { + if (VectorToSUB(TMaxs, k) < VectorToSUB(Models->TMins, k)) + break; + if (VectorToSUB(TMins, k) > VectorToSUB(Models->TMaxs, k)) + break; + } + + if (k != 3) // Couldn't possibly hit if box's don't hit... + continue; + } + + geVec3d_Subtract(Pos, &Models->RealCenter, &TPos); + + // InverseTransform the point about models center of rotation + geXForm3d_TransposeTransform(&Models->XForm, &TPos, &TPos); + + // push back into world + + geVec3d_Add(&TPos, &Models->RealCenter, &TPos); + + FillContents_tr(World, GFXModels->RootNode[0], &TPos, TexName); + + if (!ModelHit) + { + ModelHit = Models; // First model hit for any arbritrary contents + Hit = GE_TRUE; + } + } + + if (Hit) + { + return GE_TRUE; + } + + return GE_FALSE; +} + +// end change texture name \ No newline at end of file diff --git a/G3D/World/USER.H b/G3D/World/USER.H new file mode 100644 index 0000000..d13876d --- /dev/null +++ b/G3D/World/USER.H @@ -0,0 +1,124 @@ +/****************************************************************************************/ +/* User.h */ +/* */ +/* Author: John Pollard */ +/* Description: User poly's */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_USER_H +#define GE_USER_H + +#include +#include + +#include "BaseType.h" +#include "Vec3d.h" +#include "XForm3d.h" +#include "Camera.h" +#include "Genesis.h" +#include "World.h" +#include "Surface.h" + +#include "DCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_USER_VERTS 4 +#define USER_MAX_SORTED_POLYS 1024 + +//================================================================================ +// Structure defines +//================================================================================ + +typedef struct gePoly +{ +#ifdef _DEBUG + struct gePoly *Self1; +#endif + + geWorld *World; + GE_LVertex Verts[MAX_USER_VERTS]; // Copy of user verts + + geWorld_Leaf *LeafData; + geFloat ZOrder; + + int32 NumVerts; + + geBitmap *Bitmap; + + gePoly_Type Type; // Type of poly + int32 RenderFlags; // Fx of poly + + geFloat Scale; // Currently only used for TexturedPoint + + struct gePoly *Prev; + struct gePoly *Next; + + struct gePoly *AddOnceNext; + +#ifdef _DEBUG + struct gePoly *Self2; +#endif +} gePoly; + +typedef struct User_Info +{ + gePoly *AddPolyOnceList; +} User_Info; + +//================================================================================ +// Function ProtoTypes +//================================================================================ +geBoolean User_EngineInit(geEngine *Engine); +void User_EngineShutdown(geEngine *Engine); +geBoolean User_WorldInit(geWorld *World); +void User_WorldShutdown(geWorld *World); + +geBoolean User_RenderPolyList(gePoly *PolyList); + +GENESISAPI gePoly *geWorld_AddPolyOnce( geWorld *World, + GE_LVertex *Verts, + int32 NumVerts, + geBitmap *Bitmap, + gePoly_Type Type, + uint32 RenderFlags, + geFloat Scale); +GENESISAPI gePoly *geWorld_AddPoly( geWorld *World, + GE_LVertex *Verts, + int32 NumVerts, + geBitmap *Bitmap, + gePoly_Type Type, + uint32 RenderFlags, + geFloat Scale); + +GENESISAPI void geWorld_RemovePoly(geWorld *World, gePoly *Poly); +GENESISAPI geBoolean gePoly_GetLVertex(gePoly *Poly, int32 Index, GE_LVertex *LVert); +GENESISAPI geBoolean gePoly_SetLVertex(gePoly *Poly, int32 Index, const GE_LVertex *LVert); + +geBoolean User_SetCameraInfo(geEngine *Engine, geWorld *World, geCamera *Camera, Frustum_Info *Fi); +geBoolean User_DestroyOncePolys(geWorld *World); +void User_DestroyPolyList(geWorld *World, gePoly *List); + +void User_EngineFillRect(geEngine *Engine, const GE_Rect *Rect, const GE_RGBA *Color); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/World/User.c b/G3D/World/User.c new file mode 100644 index 0000000..4b174dc --- /dev/null +++ b/G3D/World/User.c @@ -0,0 +1,1104 @@ +/****************************************************************************************/ +/* User.c */ +/* */ +/* Author: John Pollard */ +/* Description: User poly's */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "User.h" +#include "World.h" +#include "Ram.h" +#include "ErrorLog.h" +#include "System.h" +#include "Surface.h" +#include "Genesis.h" +#include "Camera.h" +#include "Frustum.h" +#include "Plane.h" + +#include "DCommon.h" + +#include "Bitmap._h" + +extern int32 MirrorRecursion; // GLOBAL!!! in World.c + +//===================================================================================== +// Local static globals +//===================================================================================== +static geEngine *gEngine; +static geWorld *gWorld; +static geCamera *gCamera; +static GFX_Leaf *gGFXLeafs; +static GFX_Model *gGFXModels; +static World_BSP *gBSP; +static Frustum_Info gWorldSpaceFrustum; + +static gePoly *SortedPolys[USER_MAX_SORTED_POLYS]; + +//===================================================================================== +// Local Static Function Prototypes +//===================================================================================== +static geBoolean RenderTexturedPoint(DRV_Driver *RDriver, gePoly *Poly, Frustum_Info *FInfo, geCamera *Camera); +static void RenderTexturedPoly(DRV_Driver *RDriver, gePoly *Poly, Frustum_Info *FInfo, geCamera *Camera); +static void RenderGouraudPoly(DRV_Driver *RDriver, gePoly *Poly, Frustum_Info *FInfo, geCamera *Camera); + +static geBoolean RenderUserPoly(geCamera *Camera, gePoly *Poly); + +static void geWorld_LinkPolyToLeaf(const geWorld *World, gePoly *Poly); +static void geWorld_UnLinkPolyFromLeaf(gePoly *Poly); + +#ifdef _DEBUG +geBoolean geWorld_PolyIsValid(gePoly *Poly) +{ + if (!Poly) + return GE_FALSE; + + if (Poly->Self1 != Poly) + return GE_FALSE; + + if (Poly->Self2 != Poly) + return GE_FALSE; + + return GE_TRUE; +} +#endif + +//===================================================================================== +// User_EngineInit +//===================================================================================== +geBoolean User_EngineInit(geEngine *Engine) +{ + User_Info *Info; + + assert(Engine->UserInfo == NULL); + + Info = GE_RAM_ALLOCATE_STRUCT(User_Info); + + if (!Info) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return GE_FALSE;; + } + + memset(Info, 0, sizeof(User_Info)); + + Engine->UserInfo = Info; + + return GE_TRUE; +} + +//===================================================================================== +// User_EngineShutdown +//===================================================================================== +void User_EngineShutdown(geEngine *Engine) +{ + User_Info *Info; + + assert(Engine != NULL); + + Info = Engine->UserInfo; + + if (!Info) + return; // Nothing to do... + + geRam_Free(Info); + + Engine->UserInfo = NULL; +} + +//===================================================================================== +// User_WorldInit +//===================================================================================== +geBoolean User_WorldInit(geWorld *World) +{ + User_Info *Info; + + assert(World != NULL); + + Info = GE_RAM_ALLOCATE_STRUCT(User_Info); + + assert(Info != NULL); + + if (!Info) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return GE_FALSE; + } + + memset(Info, 0, sizeof(User_Info)); + + World->UserInfo = Info; + + return GE_TRUE; +} + +//===================================================================================== +// User_WorldShutdown +//===================================================================================== +void User_WorldShutdown(geWorld *World) +{ + User_Info *Info; + + assert(World != NULL); + + Info = World->UserInfo; + + if (!Info) + return; // Nothing to do... + + geRam_Free(Info); + + World->UserInfo = NULL; +} + +//===================================================================================== +// +//===================================================================================== +static int PolyComp(const void *a, const void *b) +{ + geFloat z1, z2; + + z1 = (*(gePoly**)a)->ZOrder; + z2 = (*(gePoly**)b)->ZOrder; + + if ( z1 == z2) + return 0; + + if (z1 < z2) + return -1; + + return 1; +} + +//===================================================================================== +// User_RenderPolyList +//===================================================================================== +geBoolean User_RenderPolyList(gePoly *PolyList) +{ + int32 i, NumSortedPolys; + gePoly *Poly; + + assert(PolyList); + + NumSortedPolys = 0; + + for (Poly = PolyList; Poly; Poly = Poly->Next) + { + assert(geWorld_PolyIsValid(Poly)); + + if ((Poly->RenderFlags & GE_RENDER_DEPTH_SORT_BF) && NumSortedPolys < USER_MAX_SORTED_POLYS) + { + // Sorted polys (within this list) go in the SortedPoly list, and are sorted and drawn below + geVec3d Src; + geVec3d Dest; + + Src.X = Poly->Verts->X; + Src.Y = Poly->Verts->Y; + Src.Z = Poly->Verts->Z; + + geCamera_Transform(gCamera, &Src, &Dest); + Poly->ZOrder = Dest.Z; + + SortedPolys[NumSortedPolys++] = Poly; + continue; + } + + // If it is not a sorted poly, render it now... + RenderUserPoly(gCamera, Poly); + } + + if (!NumSortedPolys) // nothing more to do, if no sorted polys + return GE_TRUE; + + // Now render all sorted polys + // Sort the polys + qsort(&SortedPolys, NumSortedPolys, sizeof(SortedPolys[0]), PolyComp); + + // Render them + for (i=0; i< NumSortedPolys; i++) + { + Poly = SortedPolys[i]; + + RenderUserPoly(gCamera, Poly); + } + + return GE_TRUE; +} + +//===================================================================================== +// User_DestroyPolyOnceList +//===================================================================================== +void User_DestroyPolyOnceList(geWorld *World, gePoly *List) +{ + gePoly *Poly, *Next; + + // Clear out all the AddPolyOnce polys... + for (Poly = List; Poly; Poly = Next) + { + Next = Poly->AddOnceNext; + + assert(geWorld_PolyIsValid(Poly)); + + geWorld_RemovePoly(World, Poly); + } +} + +//===================================================================================== +// User_DestroyPolyList +//===================================================================================== +void User_DestroyPolyList(geWorld *World, gePoly *List) +{ + gePoly *Poly, *Next; + + // Clear out all the AddPolyOnce polys... + for (Poly = List; Poly; Poly = Next) + { + Next = Poly->Next; + + assert(geWorld_PolyIsValid(Poly)); + + geWorld_RemovePoly(World, Poly); + } +} + +//===================================================================================== +// User_SetCameraInfo +//===================================================================================== +geBoolean User_SetCameraInfo(geEngine *Engine, geWorld *World, geCamera *Camera, Frustum_Info *Fi) +{ + assert(Engine != NULL); + assert(World != NULL); + assert(World->UserInfo != NULL); + assert(Camera != NULL); + assert(Fi != NULL); + + gWorld = World; + gEngine = Engine; + gCamera = Camera; + gBSP = World->CurrentBSP; + gGFXLeafs = World->CurrentBSP->BSPData.GFXLeafs; + gGFXModels = World->CurrentBSP->BSPData.GFXModels; + + // Make the frustum go to World/Model space + Frustum_TransformToWorldSpace(Fi, Camera, &gWorldSpaceFrustum); + + return GE_TRUE; +} + +//===================================================================================== +// User_DestroyOncePolys +//===================================================================================== +geBoolean User_DestroyOncePolys(geWorld *World) +{ + if (World->UserInfo->AddPolyOnceList) + { + User_DestroyPolyOnceList(World, World->UserInfo->AddPolyOnceList); + World->UserInfo->AddPolyOnceList = NULL; + } + + return GE_TRUE; +} + +//===================================================================================== +// RenderTexturedPoint +//===================================================================================== +static geBoolean RenderTexturedPoint(DRV_Driver *RDriver, gePoly *Poly, Frustum_Info *FInfo, geCamera *Camera) +{ + assert(geWorld_PolyIsValid(Poly)); + + if (MirrorRecursion > 0) + { + GE_LVertex *pVerts, Save; + geVec3d Up, Left, Start; + geFloat Scale, XScale, YScale; + const geXForm3d *MXForm; + + pVerts = Poly->Verts; + + Poly->NumVerts = 4; + + Start.X = pVerts[0].X; + Start.Y = pVerts[0].Y; + Start.Z = pVerts[0].Z; + + Save = pVerts[1] = pVerts[2] = pVerts[3] = pVerts[0]; + + MXForm = geCamera_GetWorldSpaceXForm(Camera); + + geXForm3d_GetLeft(MXForm, &Left); + geXForm3d_GetUp(MXForm, &Up); + + Scale = Poly->Scale * 0.5f; + + XScale = (geFloat)geBitmap_Width(Poly->Bitmap) * Scale; + YScale = (geFloat)geBitmap_Height(Poly->Bitmap) * Scale; + + geVec3d_Scale(&Left, XScale, &Left); + geVec3d_Scale(&Up, YScale, &Up); + + pVerts->X = Start.X - Left.X + Up.X; + pVerts->Y = Start.Y - Left.Y + Up.Y; + pVerts->Z = Start.Z - Left.Z + Up.Z; + pVerts->u = 0.0f; + pVerts->v = 0.0f; + + pVerts++; + + pVerts->X = Start.X + Left.X + Up.X; + pVerts->Y = Start.Y + Left.Y + Up.Y; + pVerts->Z = Start.Z + Left.Z + Up.Z; + pVerts->u = 1.0f; + pVerts->v = 0.0f; + + pVerts++; + + pVerts->X = Start.X + Left.X - Up.X; + pVerts->Y = Start.Y + Left.Y - Up.Y; + pVerts->Z = Start.Z + Left.Z - Up.Z; + pVerts->u = 1.0f; + pVerts->v = 1.0f; + + pVerts++; + + pVerts->X = Start.X - Left.X - Up.X; + pVerts->Y = Start.Y - Left.Y - Up.Y; + pVerts->Z = Start.Z - Left.Z - Up.Z; + pVerts->u = 1.0f; + pVerts->v = 0.0f; + + RenderTexturedPoly(RDriver, Poly, FInfo, Camera); + + Poly->NumVerts = 1; // Restore the poly + Poly->Verts[0] = Save; + } + else + { + //GFX_Plane *Planes; + geVec3d Src, Dest; + GE_LVertex *pVerts; + DRV_TLVertex ScreenPnts[4]; + geBitmap *Bitmap; + geFloat Sx, Sy, z, UVAdd, Width, Height; + geFloat Left, Right, Top, Bottom; + geFloat Scale; + uint32 RenderFlags; + int32 i; + + assert(Poly != NULL); + assert(Camera != NULL); + + pVerts = &Poly->Verts[0]; + + // Xform the point + Src.X = pVerts->X; + Src.Y = pVerts->Y; + Src.Z = pVerts->Z; + + geCamera_Transform(Camera,&Src,&Dest); + + geCamera_Project(Camera, &Dest, &Src); + + for (i=0; i<4; i++) + { + ScreenPnts[i].x = Src.X; + ScreenPnts[i].y = Src.Y; + ScreenPnts[i].z = Src.Z; + ScreenPnts[i].r = pVerts->r; + ScreenPnts[i].g = pVerts->g; + ScreenPnts[i].b = pVerts->b; + ScreenPnts[i].a = pVerts->a; + } + + z = -Dest.Z; + + if (z < 1) + return GE_TRUE; + + { + geRect Rect; + geCamera_GetClippingRect(Camera,&Rect); + + Left = (geFloat)Rect.Left; + Right = (geFloat)Rect.Right+1.0f; + Top = (geFloat)Rect.Top; + Bottom = (geFloat)Rect.Bottom+1.0f; + } + + Scale = ((geCamera_GetScale(Camera) / z) * Poly->Scale); + + Bitmap = Poly->Bitmap; + Width = (geFloat)geBitmap_Width(Bitmap) * Scale; + Height = (geFloat)geBitmap_Height(Bitmap) * Scale; + + Sx = Width * 0.5f; + Sy = Height * 0.5f; + + // Build the screen poly from the point + ScreenPnts[0].x -= Sx; + ScreenPnts[0].y -= Sy; + + ScreenPnts[1].x += Sx; + ScreenPnts[1].y -= Sy; + + ScreenPnts[2].x += Sx; + ScreenPnts[2].y += Sy; + + ScreenPnts[3].x -= Sx; + ScreenPnts[3].y += Sy; + + ScreenPnts[0].u = 0.0f + pVerts->u; + ScreenPnts[0].v = 0.0f + pVerts->v; + ScreenPnts[1].u = 1.0f + pVerts->u; + ScreenPnts[1].v = 0.0f + pVerts->v; + ScreenPnts[2].u = 1.0f + pVerts->u; + ScreenPnts[2].v = 1.0f + pVerts->v; + ScreenPnts[3].u = 0.0f + pVerts->u; + ScreenPnts[3].v = 1.0f + pVerts->v; + + // Now, clip it against the 2d camera viewport + if (ScreenPnts[0].x < Left) + { + if (ScreenPnts[1].x <= Left) + return GE_TRUE; + + UVAdd = (Left-ScreenPnts[0].x) / Width; + Width -= Left-ScreenPnts[0].x; + + ScreenPnts[0].u += UVAdd; + ScreenPnts[3].u += UVAdd; + + ScreenPnts[0].x = Left; + ScreenPnts[3].x = Left; + } + if (ScreenPnts[0].y < Top) + { + if (ScreenPnts[2].y <= Top) + return GE_TRUE; + + UVAdd = (Top-ScreenPnts[0].y) / Height; + Height -= (Top-ScreenPnts[0].y); + + ScreenPnts[0].v += UVAdd; + ScreenPnts[1].v += UVAdd; + + ScreenPnts[0].y = Top; + ScreenPnts[1].y = Top; + } + if (ScreenPnts[1].x >= Right) + { + if (ScreenPnts[0].x >= Right) + return GE_TRUE; + + UVAdd = (ScreenPnts[1].x-Right) / Width; + Width -= (ScreenPnts[1].x-Right); + + ScreenPnts[1].u -= UVAdd; + ScreenPnts[2].u -= UVAdd; + + ScreenPnts[1].x = Right-1; + ScreenPnts[2].x = Right-1; + } + if (ScreenPnts[2].y >= Bottom) + { + if (ScreenPnts[0].y >= Bottom) + return GE_TRUE; + + UVAdd = (ScreenPnts[2].y-Bottom) / Height; + Height -= (ScreenPnts[2].x-Bottom); + + ScreenPnts[2].v -= UVAdd; + ScreenPnts[3].v -= UVAdd; + + ScreenPnts[2].y = Bottom-1; + ScreenPnts[3].y = Bottom-1; + } + + // Lastly, render it... + ScreenPnts[0].a = pVerts->a; + // Fixed bug where i fogot to set RGB's... + ScreenPnts[0].r = pVerts->r; + ScreenPnts[0].g = pVerts->g; + ScreenPnts[0].b = pVerts->b; + + if (Poly->RenderFlags & GE_RENDER_DO_NOT_OCCLUDE_OTHERS) + RenderFlags = DRV_RENDER_NO_ZWRITE; + else + RenderFlags = 0; + + if (Poly->RenderFlags & GE_RENDER_DO_NOT_OCCLUDE_SELF) + RenderFlags |= DRV_RENDER_NO_ZMASK; + + if (pVerts->a != 255.0f) + RenderFlags |= DRV_RENDER_ALPHA; + + if (Poly->RenderFlags & GE_RENDER_DEPTH_SORT_BF) + RenderFlags |= DRV_RENDER_FLUSH; + + if (Poly->RenderFlags & GE_RENDER_CLAMP_UV) + RenderFlags |= DRV_RENDER_CLAMP_UV; + + if (Poly->RenderFlags & GE_RENDER_NO_FOG) // skybox fog + RenderFlags |= DRV_RENDER_POLY_NO_FOG; + + assert(geWorld_HasBitmap(gWorld, Bitmap)); + assert(geBitmap_GetTHandle(Bitmap)); + + RDriver->RenderMiscTexturePoly((DRV_TLVertex*)ScreenPnts, 4, geBitmap_GetTHandle(Bitmap), RenderFlags); + } + + return GE_TRUE; +} + +//===================================================================================== +// RenderTexturedPoly +//===================================================================================== +static void RenderTexturedPoly(DRV_Driver *RDriver, gePoly *Poly, Frustum_Info *FInfo, geCamera *Camera) +{ + geVec3d Dest1[30], Dest2[30], *pDest1, *pDest2, *pDest3, *pTempDest; + GE_LVertex *pLVert; + Surf_TexVert Tex1[30], Tex2[30]; + Surf_TexVert *pTex1, *pTex2, *pTempTex; + DRV_TLVertex Clipped1[90]; + int32 Length1, Length2; + geBitmap *pBitmap; + GFX_Plane *pFPlanes; + int32 i, p; + uint32 RenderFlags; +// skydome + int32 plan; + + assert(geWorld_PolyIsValid(Poly)); + + pFPlanes = FInfo->Planes; + + pDest1 = Dest1; + pTex1 = Tex1; + pLVert = Poly->Verts; + + for (i=0; i< Poly->NumVerts; i++) + { + pDest1->X = pLVert->X; + pDest1->Y = pLVert->Y; + pDest1->Z = pLVert->Z; + + pTex1->u = pLVert->u; + pTex1->v = pLVert->v; + pTex1->r = pLVert->r; + pTex1->g = pLVert->g; + pTex1->b = pLVert->b; + + pDest1++; + pLVert++; + pTex1++; + } + + pDest1 = Dest1; + pDest2 = Dest2; + pTex1 = Tex1; + pTex2 = Tex2; + Length1 = Poly->NumVerts; + +// skydome + plan = FInfo->NumPlanes; + if (((Poly->RenderFlags & GE_RENDER_NO_CLIP)==GE_RENDER_NO_CLIP) && plan==5) + plan -= 1; + + for (p=0; p< plan; p++, pFPlanes++) + { + if (!Frustum_ClipToPlaneUVRGB(pFPlanes, pDest1, pDest2, pTex1, pTex2, Length1, &Length2)) + return; + + // Swap them + pTempDest = pDest1; + pDest1 = pDest2; + pDest2 = pTempDest; + + pTempTex = pTex1; + pTex1 = pTex2; + pTex2 = pTempTex; + + Length1 = Length2; + } + + if (Length1 < 3) + return; + + pDest3 = pDest2; + for (i=0; i< Length1; i++) + { + //geXForm3d_Transform(&Camera->XForm, pDest1, pDest2); + geCamera_Transform(Camera,pDest1,pDest2); + pDest1++; + pDest2++; + } + + Frustum_ProjectRGB(pDest3, pTex1, Clipped1, Length1, Camera); + + pBitmap = Poly->Bitmap; + + Clipped1[0].a = Poly->Verts[0].a; + + if (Poly->RenderFlags & GE_RENDER_DO_NOT_OCCLUDE_OTHERS) + RenderFlags = DRV_RENDER_NO_ZWRITE; + else + RenderFlags = 0; + + if (Poly->RenderFlags & GE_RENDER_DO_NOT_OCCLUDE_SELF) + RenderFlags |= DRV_RENDER_NO_ZMASK; + + if (Clipped1[0].a != 255.0f) + RenderFlags |= DRV_RENDER_ALPHA; + + if (Poly->RenderFlags & GE_RENDER_DEPTH_SORT_BF) + RenderFlags |= DRV_RENDER_FLUSH; + + if (Poly->RenderFlags & GE_RENDER_CLAMP_UV) + RenderFlags |= DRV_RENDER_CLAMP_UV; + + if (Poly->RenderFlags & GE_RENDER_NO_FOG) // skybox fog + RenderFlags |= DRV_RENDER_POLY_NO_FOG; + + // Render it... + assert(geWorld_HasBitmap(gWorld, pBitmap)); + assert(geBitmap_GetTHandle(pBitmap)); + + RDriver->RenderMiscTexturePoly(Clipped1, Length1, geBitmap_GetTHandle(pBitmap), RenderFlags); + +} + +//===================================================================================== +// RenderGouraudPoly +//===================================================================================== +static void RenderGouraudPoly(DRV_Driver *RDriver, gePoly *Poly, Frustum_Info *FInfo, geCamera *Camera) +{ + geVec3d Verts[30], *pVert; + GE_LVertex *pLVert; + geVec3d Dest1[30], Dest2[30], *pDest1, *pDest2, *pDest3; + Surf_TexVert Tex1[30], Tex2[30]; + Surf_TexVert *pTex1, *pTex2; + DRV_TLVertex Clipped1[90]; + int32 Length1, Length2; + GFX_Plane *pFPlanes; + int32 i, p; + + assert(geWorld_PolyIsValid(Poly)); + + pFPlanes = FInfo->Planes; + + pVert = Verts; + pLVert = Poly->Verts; + pTex1 = Tex1; + + for (i=0; i< Poly->NumVerts; i++) + { + pVert->X = pLVert->X; + pVert->Y = pLVert->Y; + pVert->Z = pLVert->Z; + + pTex1->r = pLVert->r; + pTex1->g = pLVert->g; + pTex1->b = pLVert->b; + + pVert++; + pLVert++; + pTex1++; + } + + pDest1 = Verts; + pDest2 = Dest2; + pTex1 = Tex1; + pTex2 = Tex2; + Length1 = Poly->NumVerts; + + for (p=0; p< 4; p++) + { + if (!Frustum_ClipToPlaneRGB(&pFPlanes[p], pDest1, pDest2, pTex1, pTex2, Length1, &Length2)) + return; + + if (pDest1 == Dest2) + { + pDest1 = Dest1; + pDest2 = Dest2; + pTex1 = Tex1; + pTex2 = Tex2; + } + else + { + pDest1 = Dest2; + pDest2 = Dest1; + pTex1 = Tex2; + pTex2 = Tex1; + } + Length1 = Length2; + } + + if (Length1 < 3) + return; + + pDest3 = pDest2; + for (i=0; i< Length1; i++) + { + //geXForm3d_Transform(&Camera->XForm, pDest1, pDest2); + geCamera_Transform(Camera,pDest1,pDest2); + pDest1++; + pDest2++; + } + + Frustum_ProjectRGB(pDest3, pTex1, Clipped1, Length1, Camera); + + Clipped1[0].a = Poly->Verts[0].a; + + // Render it... + if (Clipped1[0].a != 255.0f) + RDriver->RenderGouraudPoly(Clipped1, Length1, DRV_RENDER_ALPHA); + else + RDriver->RenderGouraudPoly(Clipped1, Length1, 0); + +} + +//===================================================================================== +// User_EngineFillRect +//===================================================================================== +void User_EngineFillRect(geEngine *Engine, const GE_Rect *Rect, const GE_RGBA *Color) +{ + DRV_TLVertex DrvVertex[4]; + DRV_Driver * RDriver; + + RDriver = Engine->DriverInfo.RDriver; + + assert(RDriver != NULL); +// changed for RF +#define NEARZ 1.0f + DrvVertex[0].x = (geFloat)Rect->Left; + DrvVertex[0].y = (geFloat)Rect->Top; + DrvVertex[0].z = NEARZ; + DrvVertex[0].u = + DrvVertex[0].v = 0.0f; + DrvVertex[0].r = Color->r; + DrvVertex[0].g = Color->g; + DrvVertex[0].b = Color->b; + DrvVertex[0].a = Color->a; + + DrvVertex[1].x = (geFloat)Rect->Right; + DrvVertex[1].y = (geFloat)Rect->Top; + DrvVertex[1].z = NEARZ; + DrvVertex[1].u = + DrvVertex[1].v = 0.0f; + DrvVertex[1].r = Color->r; + DrvVertex[1].g = Color->g; + DrvVertex[1].b = Color->b; + DrvVertex[1].a = Color->a; + + DrvVertex[2].x = (geFloat)Rect->Right; + DrvVertex[2].y = (geFloat)Rect->Bottom; + DrvVertex[2].z = NEARZ; + DrvVertex[2].u = + DrvVertex[2].v = 0.0f; + DrvVertex[2].r = Color->r; + DrvVertex[2].g = Color->g; + DrvVertex[2].b = Color->b; + DrvVertex[2].a = Color->a; + + DrvVertex[3].x = (geFloat)Rect->Left; + DrvVertex[3].y = (geFloat)Rect->Bottom; + DrvVertex[3].z = NEARZ; + DrvVertex[3].u = + DrvVertex[3].v = 0.0f; + DrvVertex[3].r = Color->r; + DrvVertex[3].g = Color->g; + DrvVertex[3].b = Color->b; + DrvVertex[3].a = Color->a; + + if (Color->a != 255.0f) + RDriver->RenderGouraudPoly(DrvVertex, 4, DRV_RENDER_FLUSH); + else + RDriver->RenderGouraudPoly(DrvVertex, 4, DRV_RENDER_ALPHA | DRV_RENDER_FLUSH); +} + +//===================================================================================== +// RenderUserPoly +//===================================================================================== +static geBoolean RenderUserPoly(geCamera *Camera, gePoly *Poly) +{ + DRV_Driver *RDriver; + + assert(Camera); + assert(geWorld_PolyIsValid(Poly)); + + RDriver = gEngine->DriverInfo.RDriver; + + gWorld->DebugInfo.NumUserPolys++; + + assert(RDriver != NULL); + + switch(Poly->Type) + { + case GE_TEXTURED_POLY: + RenderTexturedPoly(RDriver, Poly, &gWorldSpaceFrustum, Camera); + break; + + case GE_GOURAUD_POLY: + RenderGouraudPoly(RDriver, Poly, &gWorldSpaceFrustum, Camera); + break; + + case GE_TEXTURED_POINT: + RenderTexturedPoint(RDriver, Poly, &gWorldSpaceFrustum, Camera); + break; + + default: + //geErrorLog_Add(GE_ERR_, NULL); + return GE_FALSE; + } + return GE_TRUE; +} + +//===================================================================================== +// geWorld_LinkPolyToLeaf +//===================================================================================== +void geWorld_LinkPolyToLeaf(const geWorld *World, gePoly *Poly) +{ +#if SEARCH_ALL_VERTS_FOR_LEAF + int32 i; +#endif + geWorld_Leaf *pLeafData; + int32 Leaf; + GE_LVertex *Verts; + + assert(World); + assert(Poly); + assert(geWorld_PolyIsValid(Poly)); + assert(Poly->LeafData == NULL); + + Verts = Poly->Verts; + +#if SEARCH_ALL_VERTS_FOR_LEAF + // Take the first vert that is in a valid leaf + for (i=0; iNumVerts; i++, Verts++) +#endif + { + geVec3d Src; + + Src.X = Verts->X; + Src.Y = Verts->Y; + Src.Z = Verts->Z; + + Leaf = Plane_FindLeaf(World, gGFXModels[0].RootNode[0], &Src); + +#if SEARCH_ALL_VERTS_FOR_LEAF + if (!(gGFXLeafs[Leaf].Contents & GE_CONTENTS_SOLID)) // Try to find the first leaf NOT in solid!!! + break; +#endif + } + + assert(Leaf >=0 && Leaf < World->CurrentBSP->BSPData.NumGFXLeafs); + + pLeafData = &World->CurrentBSP->LeafData[Leaf]; + + // Insert into the beginning of the list + if (pLeafData->PolyList) + pLeafData->PolyList->Prev = Poly; + + Poly->Next = pLeafData->PolyList; + Poly->Prev = NULL; // This is TRUE cause the poly is always added to the front of the list + pLeafData->PolyList = Poly; + + Poly->LeafData = pLeafData; // Save the leaf data +} + +//===================================================================================== +// geWorld_UnLinkPolyFromLeaf +//===================================================================================== +void geWorld_UnLinkPolyFromLeaf(gePoly *Poly) +{ + geWorld_Leaf *pLeafData; + + assert(Poly); + assert(geWorld_PolyIsValid(Poly)); + + pLeafData = Poly->LeafData; + assert(pLeafData); // Polys are allways in some kind of leaf, solid or not!!! (they just don't always render) + + if (Poly->Prev) + { + assert(Poly->Prev->Next == Poly); + Poly->Prev->Next = Poly->Next; + } + if (Poly->Next) + { + assert(Poly->Next->Prev == Poly); + Poly->Next->Prev = Poly->Prev; + } + + // Cut the poly from the leaf it was inserted into originally + if (Poly == pLeafData->PolyList) + { + assert(Poly->Prev == NULL); + pLeafData->PolyList = Poly->Next; + } + + Poly->LeafData = NULL; + Poly->Next = NULL; + Poly->Prev = NULL; +} + +//===================================================================================== +// **** Public GENESISAPI's **** +//===================================================================================== + +//===================================================================================== +// geWorld_AddPoly +//===================================================================================== +GENESISAPI gePoly *geWorld_AddPoly( geWorld *World, + GE_LVertex *Verts, + int32 NumVerts, + geBitmap *Bitmap, + gePoly_Type Type, + uint32 RenderFlags, + geFloat Scale) +{ + gePoly *Poly; + + assert(World != NULL); + assert(World->UserInfo != NULL); + + assert(Bitmap != NULL || Type == GE_GOURAUD_POLY); + assert(Verts != NULL); + assert(NumVerts <= MAX_USER_VERTS); + + Poly = GE_RAM_ALLOCATE_STRUCT(gePoly); + + if (!Poly) + return NULL; + + if ( World->CurrentBSP ) + gGFXModels = World->CurrentBSP->BSPData.GFXModels; + else + gGFXModels = NULL; + +#ifdef _DEBUG + Poly->Self1 = Poly; + Poly->Self2 = Poly; +#endif + + Poly->NumVerts = NumVerts; + Poly->Bitmap = Bitmap; + Poly->Type = Type; + Poly->RenderFlags = RenderFlags; + Poly->Scale = Scale; + Poly->World = World; // I could think of no other way!!! Poly needs world in SetLVertex. Should we require it as a parm??? + Poly->AddOnceNext = NULL; + Poly->Next = NULL; + Poly->Prev = NULL; + Poly->LeafData = NULL; + + memcpy(Poly->Verts, Verts, sizeof(GE_LVertex)*NumVerts); + + // Link the poly to the leaf it is in + geWorld_LinkPolyToLeaf(World, Poly); + + World->ActiveUserPolys++; + + return Poly; +} + +//===================================================================================== +// geWorld_AddPolyOnce +//===================================================================================== +GENESISAPI gePoly *geWorld_AddPolyOnce( geWorld *World, + GE_LVertex *Verts, + int32 NumVerts, + geBitmap *Bitmap, + gePoly_Type Type, + uint32 RenderFlags, + geFloat Scale) +{ + gePoly *Poly; + + assert(World != NULL); + assert(World->UserInfo != NULL); + + // For AddPOlyOnce, do an AddPoly, then put it in the list to be removed at the end of the frame + Poly = geWorld_AddPoly(World, Verts, NumVerts, Bitmap, Type, RenderFlags, Scale); + + if (!Poly) + return NULL; + + // Insert add poly once polys into the AddPolyOnceList so they can be removed at the end of the frame + Poly->AddOnceNext = World->UserInfo->AddPolyOnceList; + World->UserInfo->AddPolyOnceList = Poly; + + return Poly; +} + +//===================================================================================== +// geWorld_RemovePoly +//===================================================================================== +GENESISAPI void geWorld_RemovePoly(geWorld *World, gePoly *Poly) +{ + assert(World != NULL); + assert(Poly != NULL); + assert(geWorld_PolyIsValid(Poly)); + + // Remove the poly from the leaf that it is in (it must be in one. or it would not have been added to the world) + geWorld_UnLinkPolyFromLeaf(Poly); + + World->ActiveUserPolys--; + + geRam_Free(Poly); +} + +//===================================================================================== +// gePoly_GetLVertex +//===================================================================================== +GENESISAPI geBoolean gePoly_GetLVertex(gePoly *Poly, int32 Index, GE_LVertex *LVert) +{ + assert (Poly != NULL); + assert(LVert != NULL); + assert(geWorld_PolyIsValid(Poly)); + + assert(Index >= 0); + assert(Index < Poly->NumVerts); + + *LVert= Poly->Verts[Index]; + + return GE_TRUE; +} + +//===================================================================================== +// gePoly_SetLVertex +//===================================================================================== +GENESISAPI geBoolean gePoly_SetLVertex(gePoly *Poly, int32 Index, const GE_LVertex *LVert) +{ + assert (Poly != NULL); + assert(LVert != NULL); + assert(geWorld_PolyIsValid(Poly)); + + assert(Index >= 0); + assert(Index < Poly->NumVerts); + + Poly->Verts[Index] = *LVert; + + assert(Poly->LeafData); // A poly does not get created UNLESS it gets attaches to a leaf!!! + + geWorld_UnLinkPolyFromLeaf(Poly); // Detach the poly from it's current leaf + geWorld_LinkPolyToLeaf(Poly->World, Poly); // Re-attach to the new leaf (if any, check for cohearency!) + + return GE_TRUE; +} diff --git a/G3D/World/VIS.H b/G3D/World/VIS.H new file mode 100644 index 0000000..cadb1d5 --- /dev/null +++ b/G3D/World/VIS.H @@ -0,0 +1,52 @@ +/****************************************************************************************/ +/* Vis.h */ +/* */ +/* Author: John Pollard */ +/* Description: Code to vis the world from a given pov */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_VIS_H +#define GE_VIS_H + +#include "Genesis.h" +#include "BaseType.h" + +#include "Frustum.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//===================================================================================== +// Defines / Structure defines +//===================================================================================== + +//===================================================================================== +// Function ProtoTypes +//===================================================================================== +geBoolean Vis_WorldInit(geWorld *World); +void Vis_WorldShutdown(geWorld *World); + +geBoolean Vis_VisWorld(geEngine *Engine, geWorld *World, const geCamera *Camera, Frustum_Info *Fi); + +geBoolean Vis_MarkWaterFaces(World_BSP *WBSP); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/World/Vis.c b/G3D/World/Vis.c new file mode 100644 index 0000000..69a9894 --- /dev/null +++ b/G3D/World/Vis.c @@ -0,0 +1,510 @@ +/****************************************************************************************/ +/* Vis.c */ +/* */ +/* Author: John Pollard */ +/* Description: Code to vis the world from a given pov */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "BaseType.h" +#include "World.h" +#include "Plane.h" +#include "Vec3d.h" +#include "Ram.h" +#include "Surface.h" +#include "Trace.h" +#include "Camera.h" +#include "Frustum.h" +#include "System.h" + +#include "Fog.h" + +#ifdef _TSC +#include "tsc.h" +#endif + +//#define SUPER_VIS1 + +static void MarkVisibleParents(geWorld *World, int32 Leaf); +static void FindParents(World_BSP *Bsp); +static void VisFog(geEngine *Engine, geWorld *World, const geCamera *Camera, Frustum_Info *Fi, int32 Area); + +//===================================================================================== +// Vis_WorldInit +//===================================================================================== +geBoolean Vis_WorldInit(geWorld *World) +{ + World_BSP *BSP; + int32 i; + static int32 StartupParams[]={0x696C6345,0x21657370}; + + assert(World != NULL); + + BSP = World->CurrentBSP; + + assert(BSP != NULL); + + if (!BSP) + return GE_FALSE; + + BSP->NodeVisFrame = GE_RAM_ALLOCATE_ARRAY(int32, BSP->BSPData.NumGFXNodes); + + if (!BSP->NodeVisFrame) + goto Error; + + BSP->ClusterVisFrame = GE_RAM_ALLOCATE_ARRAY(int32, BSP->BSPData.NumGFXClusters); + + if (!BSP->ClusterVisFrame) + goto Error; + + BSP->AreaVisFrame = GE_RAM_ALLOCATE_ARRAY(int32, BSP->BSPData.NumGFXAreas); + + if (!BSP->AreaVisFrame) + goto Error; + + BSP->NodeParents = GE_RAM_ALLOCATE_ARRAY(int32, BSP->BSPData.NumGFXNodes); + + if (!BSP->NodeParents) + goto Error; + + memset(BSP->NodeVisFrame, 0, sizeof(int32)*BSP->BSPData.NumGFXNodes); + memset(BSP->ClusterVisFrame, 0, sizeof(int32)*BSP->BSPData.NumGFXClusters); + memset(BSP->AreaVisFrame, 0, sizeof(int32)*BSP->BSPData.NumGFXAreas); + + memset(BSP->NodeParents, 0, sizeof(int32)*BSP->BSPData.NumGFXNodes); + + FindParents(World->CurrentBSP); + + // Set the identity on the AreaMatrix + for (i=0; i<256; i++) + World->CurrentBSP->AreaConnections[i][i] = 1; + + return GE_TRUE; + + Error: + if (BSP->NodeVisFrame) + geRam_Free(BSP->NodeVisFrame); + if (BSP->ClusterVisFrame) + geRam_Free(BSP->ClusterVisFrame); + if (BSP->AreaVisFrame) + geRam_Free(BSP->AreaVisFrame); + if (BSP->NodeParents) + geRam_Free(BSP->NodeParents); + + BSP->NodeVisFrame = NULL; + BSP->ClusterVisFrame = NULL; + BSP->AreaVisFrame = NULL; + BSP->NodeParents = NULL; + return GE_FALSE; +} + +//===================================================================================== +// Vis_WorldShutdown +//===================================================================================== +void Vis_WorldShutdown(geWorld *World) +{ + World_BSP *BSP; + + assert(World != NULL); + + if (!World->CurrentBSP) + return; + + BSP = World->CurrentBSP; + + if (BSP->NodeVisFrame) + geRam_Free(BSP->NodeVisFrame); + if (BSP->ClusterVisFrame) + geRam_Free(BSP->ClusterVisFrame); + if (BSP->AreaVisFrame) + geRam_Free(BSP->AreaVisFrame); + if (BSP->NodeParents) + geRam_Free(BSP->NodeParents); + + BSP->NodeVisFrame = NULL; + BSP->ClusterVisFrame = NULL; + BSP->AreaVisFrame = NULL; + BSP->NodeParents = NULL; +} + +//===================================================================================== +// ModelVisible +//===================================================================================== +geBoolean ModelVisible(geWorld *World, geWorld_Model *Model) +{ + return Trace_BBoxInVisibleLeaf(World, &Model->TMins, &Model->TMaxs); +} + +//===================================================================================== +// Vis_FloodAreas_r +//===================================================================================== +void Vis_FloodAreas_r(geWorld *World, int32 Area) +{ + GBSP_BSPData *BSP; + GFX_Area *a; + GFX_AreaPortal *p; + int32 i; + + if (World->CurrentBSP->AreaVisFrame[Area] == World->CurFrameStatic) + return; // Area already set + + World->CurrentBSP->AreaVisFrame[Area] = World->CurFrameStatic; // Mark this area visible + + BSP = &World->CurrentBSP->BSPData; + + a = &BSP->GFXAreas[Area]; + + p = &BSP->GFXAreaPortals[a->FirstAreaPortal]; + + for (i=0; i< a->NumAreaPortals; i++, p++) + { + geWorld_Model *Model; + + Model = &World->CurrentBSP->Models[p->ModelNum]; + + if (Model->Open) + Vis_FloodAreas_r(World, p->Area); + } +} + +//===================================================================================== +// Vis_VisWorld +//===================================================================================== +geBoolean Vis_VisWorld(geEngine *Engine, geWorld *World, const geCamera *Camera, Frustum_Info *Fi) +{ + uint8 *VisData; + int32 k, i, Area; + GFX_Node *GFXNodes; + GFX_Leaf *GFXLeafs; + Surf_SurfInfo *SurfInfo; + uint8 *GFXVisData; + int32 Leaf, Cluster; + GFX_Model *GFXModels; + int32 *GFXLeafFaces; + GFX_Cluster *GFXClusters; + GBSP_BSPData *BSPData; + geWorld_Model *Models; + const geVec3d *Pos; + GFX_Leaf *pLeaf; + +#ifdef _TSC + pushTSC(); +#endif + + Pos = geCamera_GetVisPov(Camera); + + BSPData = &World->CurrentBSP->BSPData; + + GFXNodes = BSPData->GFXNodes; + GFXLeafs = BSPData->GFXLeafs; + GFXClusters = BSPData->GFXClusters; + GFXVisData = BSPData->GFXVisData; + GFXModels = BSPData->GFXModels; + GFXLeafFaces = BSPData->GFXLeafFaces; + + SurfInfo = World->CurrentBSP->SurfInfo; + + Leaf = Plane_FindLeaf(World, GFXModels[0].RootNode[0], Pos); + Area = GFXLeafs[Leaf].Area; + + // Check to see if we cen get rid of most of the work load by seeing if the leaf has not changed... + if (World->CurrentLeaf == Leaf && !World->ForceVis) + goto LeafDidNotChange; + + World->ForceVis = GE_FALSE; // Reset force vis flag + + World->CurrentLeaf = Leaf; + + World->CurFrameStatic++; // Make all old vis info obsolete + + Cluster = GFXLeafs[Leaf].Cluster; + + if (Cluster == -1 || GFXClusters[Cluster].VisOfs == -1) + { + World->VisInfo = GE_FALSE; + return GE_TRUE; + } + + if (Area) + Vis_FloodAreas_r(World, Area); + + World->VisInfo = GE_TRUE; + + VisData = &GFXVisData[GFXClusters[Cluster].VisOfs]; + + // Mark all visible clusters + for (i=0; i>3] & (1<<(i&7)) ) + World->CurrentBSP->ClusterVisFrame[i] = World->CurFrameStatic; + } + + pLeaf = &GFXLeafs[GFXModels[0].FirstLeaf]; + + // Go through and find all visible leafs based on the visible clusters the leafs are in + for (i=0; i< GFXModels[0].NumLeafs; i++, pLeaf++) + { + int32 *pFace; + + Cluster = pLeaf->Cluster; + + if (Cluster == -1) // No cluster info for this leaf (must be solid) + continue; + + // If the cluster is not visible, then the leaf is not visible + if (World->CurrentBSP->ClusterVisFrame[Cluster] != World->CurFrameStatic) + continue; + + // If the area is not visible, then the leaf is not visible + if (World->CurrentBSP->AreaVisFrame[pLeaf->Area] != World->CurFrameStatic) + continue; + + // Mark all visible nodes by bubbling up the tree from the leaf + MarkVisibleParents(World, i); + + // Mark the leafs vis frame to worlds current frame + World->CurrentBSP->LeafData[i].VisFrame = World->CurFrameStatic; + + pFace = &GFXLeafFaces[pLeaf->FirstFace]; + + // Go ahead and vis surfaces here... + for (k=0; k< pLeaf->NumFaces; k++) + { + // Update each surface infos visframe thats touches each visible leaf + SurfInfo[*pFace++].VisFrame = World->CurFrameStatic; + } + } + + LeafDidNotChange: + + // The world is always visible as a model + World->CurrentBSP->Models[0].VisFrame = World->CurFrameDynamic; + + Models = &World->CurrentBSP->Models[1]; + // Do models, skipping world models (it's always visible) + for (i=1; i< BSPData->NumGFXModels; i++, Models++) + { + #if 0 + int32 Cluster; + + // First, lets cheat, and see if the center is in a valid location to test for vis + Leaf = Plane_FindLeaf(World, GFXModels[0].RootNode[0], &Models->Pivot); + + Cluster = GFXLeafs[Leaf].Cluster; + + if (Cluster >= 0 && GFXClusters[Cluster].VisOfs >= 0) // If there is vis data for this leaf + { + if (World->CurrentBSP->LeafData[Leaf].VisFrame == World->CurFrameStatic) + Models->VisFrame = World->CurFrameDynamic; + else + { + GFX_Model *pModel; + + pModel = &BSPData->GFXModels[i]; + + if (pModel->Areas[0] == Area || pModel->Areas[1] == Area && + World->CurrentBSP->ClusterVisFrame[Cluster] == World->CurFrameStatic) + Models->VisFrame = World->CurFrameDynamic; + } + } + else if (ModelVisible(World, Models)) + Models->VisFrame = World->CurFrameDynamic; + #else + + if (ModelVisible(World, Models)) + Models->VisFrame = World->CurFrameDynamic; + + #endif + + Models->ChangedFlags &= ~MODEL_CHANGED_XFORM; + } + + VisFog(Engine, World, Camera, Fi, Area); + +#ifdef _TSC + showPopTSC("Vis_VisWorld"); +#endif + + return GE_TRUE; +} + +//===================================================================================== +// Vis_MarkWaterFaces +//===================================================================================== +geBoolean Vis_MarkWaterFaces(World_BSP *WBSP) +{ + GFX_Leaf *GFXLeafs; + int32 i, f, FNum; + int32 NumLeafs, Contents; + Surf_SurfInfo *SurfInfo; + S32 *GFXLeafFaces; + + assert(WBSP != NULL); + + GFXLeafs = WBSP->BSPData.GFXLeafs; + GFXLeafFaces = WBSP->BSPData.GFXLeafFaces; + + NumLeafs = WBSP->BSPData.GFXModels[0].NumLeafs; + + SurfInfo = WBSP->SurfInfo; + + assert(SurfInfo != NULL); + + for (i = 0; i< NumLeafs; i++) + { + Contents = GFXLeafs[i].Contents; + + if (!(Contents & GE_CONTENTS_WAVY)) + continue; + + for (f=0; f< GFXLeafs[i].NumFaces; f++) + { + FNum = GFXLeafFaces[GFXLeafs[i].FirstFace + f]; + + // Disable for now, not working quite right... + // There is a problem with the leafs... + SurfInfo[FNum].Flags |= SURFINFO_WAVY; + } + } + + return GE_TRUE; +} + +static GFX_Node *GFXNodes; +static int32 *NodeParents; +static geWorld_Leaf *LeafData; + +//===================================================================================== +// FindParents_r +//===================================================================================== +static void FindParents_r(int32 Node, int32 Parent) +{ + if (Node < 0) // At a leaf, mark leaf parent and return + { + LeafData[-(Node+1)].Parent = Parent; + return; + } + + // At a node, mark node parent, and keep going till hitting a leaf + NodeParents[Node] = Parent; + + // Go down front and back markinf parents on the way down... + FindParents_r(GFXNodes[Node].Children[0], Node); + FindParents_r(GFXNodes[Node].Children[1], Node); +} + +//===================================================================================== +// Vis_FindParents +//===================================================================================== +static void FindParents(World_BSP *Bsp) +{ + assert(Bsp != NULL); + + // Assign some static globals so they don't flood the stack... + GFXNodes = Bsp->BSPData.GFXNodes; + LeafData = Bsp->LeafData; + NodeParents = Bsp->NodeParents; + + FindParents_r(Bsp->BSPData.GFXModels[0].RootNode[0], -1); +} + +//===================================================================================== +// MarkVisibleParents +//===================================================================================== +static void MarkVisibleParents(geWorld *World, int32 Leaf) +{ + int32 Node; + World_BSP *Bsp; + + assert(Leaf >= 0); + assert(Leaf < World->CurrentBSP->BSPData.NumGFXLeafs); + + Bsp = World->CurrentBSP; + + // Find the leafs parent + Node = Bsp->LeafData[Leaf].Parent; + + // Bubble up the tree from the current node, marking them as visible + while (Node >= 0) + { + Bsp->NodeVisFrame[Node] = World->CurFrameStatic; + Node = Bsp->NodeParents[Node]; + } +} + +// FIXME: Put the fog in Fog.c +//===================================================================================== +// VisFog +//===================================================================================== +static void VisFog(geEngine *Engine, geWorld *World, const geCamera *Camera, Frustum_Info *Fi, int32 Area) +{ + GBSP_BSPData *BSPData; + GFX_Leaf *GFXLeafs; + geFog *Fog; + World_BSP *CBSP; + Frustum_Info WorldSpaceFrustum; + //geVec3d *Pos; + + assert(World); + assert(Camera); + assert(Fi); + + World->NumVisibleFog = 0; + + if (!World->FogList) + return; // Don't waste time + + //return; + + // Make the frustum go to world space + Frustum_TransformToWorldSpace(Fi, Camera, &WorldSpaceFrustum); + + CBSP = World->CurrentBSP; + + BSPData = &CBSP->BSPData; + + GFXLeafs = BSPData->GFXLeafs; + + for (Fog = World->FogList; Fog; Fog = Fog->Next) + { + geWorld_FogData *FogData; + + if (World->NumVisibleFog >= MAX_VISIBLE_FOG) + return; // Oh well... + + FogData = (geWorld_FogData*)geFog_GetUserData(Fog); + + if (CBSP->LeafData[FogData->Leaf].VisFrame != World->CurFrameStatic) + continue; // might not be visible + + if (Area != GFXLeafs[FogData->Leaf].Area) + continue; // Fog only effects it's own area + + // If not in the view frustum, then tottaly ignore... + if (!Frustum_PointInFrustum(&WorldSpaceFrustum, &Fog->Pos, Fog->VolumeRadius-1.0f)) + continue; + + FogData->VisFrame = World->CurFrameDynamic; + + // Add it to the list + World->VisibleFog[World->NumVisibleFog++] = Fog; + + // For debugging... + Engine->DebugInfo.NumFog++; + } +} diff --git a/G3D/World/WBitmap.c b/G3D/World/WBitmap.c new file mode 100644 index 0000000..f5ece18 --- /dev/null +++ b/G3D/World/WBitmap.c @@ -0,0 +1,570 @@ +/****************************************************************************************/ +/* WBitmap.c */ +/* */ +/* Author: John Pollard */ +/* Description: Creates geBitmaps from the data in the BSP, that are used to render */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +//===================================================================================== +//===================================================================================== +#include "WBitmap.h" +#include "GBSPFile.h" +#include "Ram.h" +#include "Bitmap.h" +#include "Errorlog.h" +#include "Bitmap._h" + +// NOTES - +// WBitmap is the original owner of all the bitmaps in the .BSP file. They are kind of a hack right now. +// Right now, the textures are raw data in the .BSP. This module, takes that data, and creates geBitmaps +// for each texture in the.BSP file. The faces are then referred to these geBitmaps, and NOT the texture data. +// The texture data can then be freed. +// The way it really should eventually work, is that the bitmaps will be in the .BSP upon load time!!! +// JP + +#define ZeroMem(Ptr) memset(Ptr,0,sizeof(*Ptr)) + +typedef struct geWBitmap +{ + char Name[64]; + geBitmap *Bitmap; + + int32 VisFrame; + + uint32 Flags; +} geWBitmap; + +typedef struct geWBitmap_Pool +{ + int32 NumWBitmaps; + + geWBitmap *WBitmaps; // Linear array of WBitmaps created when the Pool was created +} geWBitmap_Pool; + +//===================================================================================== +// geWBitmap_Pool_Create +//===================================================================================== +geWBitmap_Pool *geWBitmap_Pool_Create(GBSP_BSPData *BSPData) +{ + geWBitmap_Pool *Pool; + + assert(BSPData); + + Pool = GE_RAM_ALLOCATE_STRUCT(geWBitmap_Pool); + + if (!Pool) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_Create: Could not create the Pool. Out of memory.", NULL); + goto ExitWithError; + } + + // Clear out the memory for the Pool + ZeroMem(Pool); + + // Create all the bitmaps from the bspdata... (this should eventually just stream right out of the file...) + if (!geWBitmap_Pool_CreateAllWBitmaps(Pool, BSPData)) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_Create: geWBitmap_Pool_CreateAllWBitmaps failed.", NULL); + goto ExitWithError; + } + + return Pool; // Done, good to go + + // Error + ExitWithError: + { + if (Pool) + geWBitmap_Pool_Destroy(Pool); + + return NULL; + } +} + +//===================================================================================== +// geWBitmap_Pool_Destroy +//===================================================================================== +void geWBitmap_Pool_Destroy(geWBitmap_Pool *Pool) +{ + assert(Pool); + + geWBitmap_Pool_DestroyAllWBitmaps(Pool); + + geRam_Free(Pool); +} + +//===================================================================================== +// geWBitmap_PoolGetWBitmapCount +//===================================================================================== +int32 geWBitmap_Pool_GetWBitmapCount(geWBitmap_Pool *Pool) +{ + assert(Pool); + + return Pool->NumWBitmaps; +} + +//===================================================================================== +// geWBitmap_Pool_GetBitmapByIndex +//===================================================================================== +geWBitmap *geWBitmap_Pool_GetWBitmapByIndex(geWBitmap_Pool *Pool, int32 Index) +{ + assert(Pool); + assert(Index >= 0); + assert(Index < Pool->NumWBitmaps); + + return &Pool->WBitmaps[Index]; +} + +//===================================================================================== +// geWBitmap_Pool_GetWBitmapByBitmap +//===================================================================================== +geWBitmap *geWBitmap_Pool_GetWBitmapByBitmap(geWBitmap_Pool *Pool, const geBitmap *Bitmap) +{ + geWBitmap *pWBitmap; + int32 i; + + assert(Pool); + assert(Bitmap); + + pWBitmap = Pool->WBitmaps; + + for (i=0; i< Pool->NumWBitmaps; i++, pWBitmap++) + { + if (pWBitmap->Bitmap == Bitmap) + return pWBitmap; + } + + return NULL; +} + +//===================================================================================== +// geWBitmap_Pool_GetBitmapByIndex +//===================================================================================== +geBitmap *geWBitmap_Pool_GetBitmapByIndex(geWBitmap_Pool *Pool, int32 Index) +{ + assert(Pool); + assert(Index >= 0); + assert(Index < Pool->NumWBitmaps); + assert(Pool->WBitmaps[Index].Bitmap); + + return Pool->WBitmaps[Index].Bitmap; +} + +//===================================================================================== +// geWBitmap_Pool_GetBitmapByName +//===================================================================================== +geBitmap *geWBitmap_Pool_GetBitmapByName(geWBitmap_Pool *Pool, const char *BitmapName) +{ + geWBitmap *pWBitmap; + int32 i; + + assert(Pool); + assert(BitmapName); + + pWBitmap = Pool->WBitmaps; + for (i=0; i< Pool->NumWBitmaps; i++, pWBitmap++) + { + if (!stricmp(pWBitmap->Name, BitmapName)) + return pWBitmap->Bitmap; // Found it + } + + return NULL; +} + +#define MAX_MIPS_ALLOWED 4 + +//===================================================================================== +// geWBitmap_Pool_CreateAllWBitmaps +//===================================================================================== +geBoolean geWBitmap_Pool_CreateAllWBitmaps(geWBitmap_Pool *Pool, GBSP_BSPData *BSPData) +{ + int32 i; + geWBitmap *pWBitmap; + GFX_Texture *pGFXTexture; + uint8 *BitmapIsTransparent; + GFX_Face *pFace; + geBoolean UseColorKey; + uint32 ColorKey; + + assert(Pool); + assert(BSPData); + assert(Pool->NumWBitmaps == 0); + assert(Pool->WBitmaps == NULL); + + if (!BSPData->NumGFXTextures) + return GE_TRUE; + + assert(BSPData->GFXTextures); + + // BitmapIsTransparent is a temporary array, that is filled in with a 1, if any face that uses it, has the + // TEXINFO_TRANS flag set. If they expect to "see" thru the surface, then they should have set this flag + // in the editor. If this flag is not set, then we won't allow a color key on the surface... + BitmapIsTransparent = GE_RAM_ALLOCATE_ARRAY(uint8, BSPData->NumGFXTextures); + + if (!BitmapIsTransparent) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: Could not create the BitmapIsTransparent array. Out of memory.", NULL); + goto ExitWithError; + } + + memset(BitmapIsTransparent,0,BSPData->NumGFXTextures); + + // Now, go mark all the bitmaps that have transparent set in the texinfo + pFace = BSPData->GFXFaces; + for (i=0; i< BSPData->NumGFXFaces; i++, pFace++) + { + GFX_TexInfo *pTexInfo; + + pTexInfo = &BSPData->GFXTexInfo[pFace->TexInfo]; + + assert(pTexInfo->Texture >= 0 || pTexInfo->Texture < BSPData->NumGFXTextures); + + if (pTexInfo->Flags & TEXINFO_TRANS) + { + BitmapIsTransparent[pTexInfo->Texture] = 1; // This face has the transparent value set, so mark the bitmap it references + } + } + + // Create the bitmap pool. + Pool->WBitmaps = GE_RAM_ALLOCATE_ARRAY(geWBitmap, BSPData->NumGFXTextures); + + if (!Pool->WBitmaps) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: Could not create the Pool bitmaps. Out of memory.", NULL); + goto ExitWithError; + } + + // Clear the bitmap array + memset(Pool->WBitmaps,0,sizeof(geWBitmap)*BSPData->NumGFXTextures); + Pool->NumWBitmaps = BSPData->NumGFXTextures; // Store the number of slots + + pWBitmap = Pool->WBitmaps; + pGFXTexture = BSPData->GFXTextures; + + for (i=0; i< BSPData->NumGFXTextures; i++, pGFXTexture++, pWBitmap++) + { + geBitmap *Mips[MAX_MIPS_ALLOWED]; + int32 NumMips, m, Width, Height, Stride; + uint8 *pSrc; + + if (BitmapIsTransparent[i]) + { + UseColorKey = GE_TRUE; + //Start Dec2001DCS - ColorKey = 24 bit version of bright magenta. NOTE: Blue value is 254 (0xfe) + // because I couldn't make a 24 bit bitmap + // with MSPaint using the color + // 255 0 255. Even though Paint said it + // was the right value, by the time the + // bitmap got to Genesis it was read as + // 255 0 254 ??? + ColorKey = 0xffff00fe; + //End Dec2001DCS + } + else + { + UseColorKey = GE_FALSE; + ColorKey = 0; + } + + strcpy(pWBitmap->Name, pGFXTexture->Name); + + // <> CB this is the main loop where GFX BSP textures are made into bitmaps + + // Get width and height + Width = pGFXTexture->Width; + Height = pGFXTexture->Height; + + if (pGFXTexture->Flags & TEXTURE_SKYBOX) + NumMips = 1; + else + NumMips = 4; + + assert(NumMips <= MAX_MIPS_ALLOWED); + + // Create the bitmap +//Start Dec2001DCS - Changed format to 32 bit +// added transparent textures + pWBitmap->Bitmap = geBitmap_Create(Width, Height, NumMips, GE_PIXELFORMAT_32BIT_ARGB); +//End Dec2001DCS + + if (!pWBitmap->Bitmap) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: Could not create geBitmap.", NULL); + goto ExitWithError; + } + + // Set the driver flags + if (pGFXTexture->Flags & TEXTURE_SKYBOX) + { + geBitmap_SetDriverFlags(pWBitmap->Bitmap, RDRIVER_PF_3D); // Skybox textures do not need to combine with lightmaps + } + else + { + geBitmap_SetDriverFlags(pWBitmap->Bitmap, RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP); + } + + //<> + NumMips = 1; + // Lock all the miplevels + if (!geBitmap_LockForWrite(pWBitmap->Bitmap, Mips, 0, NumMips-1)) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: geBitmap_LockForWrite failed.", NULL); + goto ExitWithError; + } + + // Get the src from the .bsp texture data + pSrc = &BSPData->GFXTexData[pGFXTexture->Offset]; + + // Fill all the mip levels + for (m=0; m< NumMips; m++) + { + uint8 *pDest; + geBitmap_Info Info; + + if (!geBitmap_GetInfo(Mips[m], &Info, NULL)) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: geBitmap_GetInfo failed.", NULL); + goto ExitWithError; + } + + pDest = geBitmap_GetBits(Mips[m]); + assert( pDest ); + + Stride = Info.Stride; + Width = Info.Width; + Height = Info.Height; + + assert(Stride >= Width); + + if ( Stride == Width ) + { + //Start Dec2001DCS - Added * 4 since textures are now 32 bit + // added transparent textures + memcpy(pDest,pSrc,Width*Height*4); + //End Dec2001DCS + } + else + { + int h; + for (h=Height;h--;) + { + //Start Dec2001DCS - Added * 4 since textures are now 32 bit + // added transparent textures + memcpy(pDest,pSrc,Width*4); + //End Dec2001DCS + pSrc += Width*4; + pDest += Stride*4; + } + } + + // Unlock this mip level, it is filled with the data + if (!geBitmap_UnLock(Mips[m])) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: geBitmap_Unlock failed.", NULL); + goto ExitWithError; + } + } + + // Create the palette... + { + geBitmap_Palette *Pal; + int32 PalSize,cnt; + gePixelFormat Format; + uint32 *DstPalPtr,*DstPalData; + DRV_RGB *SrcPalPtr; + + //Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_ARGB, 256); + Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_XRGB, 256); + + if (!Pal) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: geBitmap_Palette_Create failed.", NULL); + return GE_FALSE; + } + + if (!geBitmap_Palette_Lock(Pal, &DstPalData, &Format, &PalSize)) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: geBitmap_Palette_Lock failed.", NULL); + return GE_FALSE; + } + + //cnt = sizeof(DRV_Palette); + // <> this doesn't seem to respect the pragma pack in dcommon ! + // I get size == 768 + + SrcPalPtr = BSPData->GFXPalettes[pGFXTexture->PaletteIndex]; + DstPalPtr = DstPalData; + for(cnt=PalSize;cnt--;) + { + *DstPalPtr++ = ((uint32)0xFF000000) + ((SrcPalPtr->r)<<16) + ((SrcPalPtr->g)<<8) + (SrcPalPtr->b); + SrcPalPtr ++; + } + //debug to see if anyone is using entry 255 : + // DstPalData[255] = 255; // color key (it's bright blue & transparent) + //or black it : DstPalData[255] = 0; + + if (!geBitmap_Palette_UnLock(Pal)) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: geBitmap_Palette_UnLock failed.", NULL); + return GE_FALSE; + } + + if (!geBitmap_SetPalette(pWBitmap->Bitmap, Pal)) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: geBitmap_SetPalette failed.", NULL); + return GE_FALSE; + } + + geBitmap_Palette_Destroy(&Pal); + } //done making the palette + + if (!geBitmap_SetColorKey(pWBitmap->Bitmap, UseColorKey, ColorKey, GE_TRUE)) + { + geErrorLog_AddString(-1, "geWBitmap_Pool_CreateAllWBitmaps: geBitmap_SetColorKey failed.", NULL); + goto ExitWithError; + } + + } + + // added to stop a leak + if (BitmapIsTransparent) + { + geRam_Free(BitmapIsTransparent); + BitmapIsTransparent = NULL; + } + + return GE_TRUE; + + // Error + ExitWithError: + { + if (Pool->WBitmaps) + { + geWBitmap_Pool_DestroyAllWBitmaps(Pool); + Pool->WBitmaps = NULL; + } + + if (BitmapIsTransparent) + { + geRam_Free(BitmapIsTransparent); + BitmapIsTransparent = NULL; + } + + return GE_FALSE; + } +} + +//===================================================================================== +// geWBitmap_Pool_DestroyAllWBitmaps +//===================================================================================== +void geWBitmap_Pool_DestroyAllWBitmaps(geWBitmap_Pool *Pool) +{ + assert(Pool); + + if (Pool->WBitmaps) + { + int32 i; + geWBitmap *pWBitmap; + + pWBitmap = Pool->WBitmaps; + + for (i=0; i< Pool->NumWBitmaps; i++, pWBitmap++) + { + // Destroy the geBitmap + if (pWBitmap->Bitmap) + { + geBitmap_Destroy(&pWBitmap->Bitmap); + pWBitmap->Bitmap = NULL; + } + } + + geRam_Free(Pool->WBitmaps); + } + + Pool->WBitmaps = NULL; // Just to be sure +} + +//===================================================================================== +// geWBitmap_GetFlags +//===================================================================================== +uint32 geWBitmap_GetFlags(geWBitmap *WBitmap) +{ + assert(WBitmap); + + return WBitmap->Flags; +} + +//===================================================================================== +// geWBitmap_GetBitmap +//===================================================================================== +geBitmap *geWBitmap_GetBitmap(geWBitmap *WBitmap) +{ + assert(WBitmap); + + return WBitmap->Bitmap; +} + +//===================================================================================== +// geWBitmap_GetVisFrame +//===================================================================================== +int32 geWBitmap_GetVisFrame(geWBitmap *WBitmap) +{ + assert(WBitmap); + + return WBitmap->VisFrame; +} + +//===================================================================================== +// geWBitmap_SetVisFrame +//===================================================================================== +geBoolean geWBitmap_SetVisFrame(geWBitmap *WBitmap, int32 VisFrame) +{ + assert(WBitmap); + + WBitmap->VisFrame = VisFrame; + + return GE_TRUE; +} + +// changed texture name + +//===================================================================================== +// geWBitmap_Pool_GetWNameByBitmap +//===================================================================================== +char *geWBitmap_Pool_GetWNameByBitmap(geWBitmap_Pool *Pool, const geBitmap *Bitmap) +{ + geWBitmap *pWBitmap; + int32 i; + + assert(Pool); + assert(Bitmap); + + pWBitmap = Pool->WBitmaps; + + for (i=0; i< Pool->NumWBitmaps; i++, pWBitmap++) + { + char str[100]; + sprintf(str,"WBitmap : %x\n",pWBitmap->Bitmap); + OutputDebugString(str); + if (pWBitmap->Bitmap == Bitmap) + return pWBitmap->Name; + } + + return NULL; +} +// end change texture name \ No newline at end of file diff --git a/G3D/World/WBitmap.h b/G3D/World/WBitmap.h new file mode 100644 index 0000000..727f014 --- /dev/null +++ b/G3D/World/WBitmap.h @@ -0,0 +1,86 @@ +/****************************************************************************************/ +/* WBitmap.h */ +/* */ +/* Author: John Pollard */ +/* Description: Creates geBitmaps from the data in the BSP, that are used to render */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef WBITMAP_H +#define WBITMAP_H + +#include + +#include "BaseType.h" +#include "GBSPFile.h" +#include "Bitmap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//== +// This stuff should really go in GBSPFile.h... + #define TEXTURE_SKYBOX (1<<0) // This is a skybox texture + + // TexInfo Flags (Global shared info about each surface) + #define TEXINFO_MIRROR (1<<0) + #define TEXINFO_FULLBRIGHT (1<<1) // No lightmap/fullbright + #define TEXINFO_SKY (1<<2) // Sky face + #define TEXINFO_LIGHT (1<<3) // Face produces light + #define TEXINFO_TRANS (1<<4) // Face has transparency + #define TEXINFO_GOURAUD (1<<5) + #define TEXINFO_FLAT (1<<6) + #define TEXINFO_NO_LIGHTMAP (1<<15) +//== + +//================================================================================ +// #defs +//================================================================================ +#define WBITMAP_SKYBOX (1<<0) // This is a skybox wbitmap + +//================================================================================ +// Structure defines +//================================================================================ +typedef struct geWBitmap geWBitmap; +typedef struct geWBitmap_Pool geWBitmap_Pool; + +//================================================================================ +// Function defines +//================================================================================ +geWBitmap_Pool *geWBitmap_Pool_Create(GBSP_BSPData *BSPData); +void geWBitmap_Pool_Destroy(geWBitmap_Pool *Pool); +int32 geWBitmap_Pool_GetWBitmapCount(geWBitmap_Pool *Pool); +geWBitmap *geWBitmap_Pool_GetWBitmapByBitmap(geWBitmap_Pool *Pool, const geBitmap *Bitmap); +geWBitmap *geWBitmap_Pool_GetWBitmapByIndex(geWBitmap_Pool *Pool, int32 Index); +geBitmap *geWBitmap_Pool_GetBitmapByIndex(geWBitmap_Pool *Pool, int32 Index); +geBitmap *geWBitmap_Pool_GetBitmapByName(geWBitmap_Pool *Pool, const char *BitmapName); +geBoolean geWBitmap_Pool_CreateAllWBitmaps(geWBitmap_Pool *Pool, GBSP_BSPData *BSPData); +void geWBitmap_Pool_DestroyAllWBitmaps(geWBitmap_Pool *Pool); +uint32 geWBitmap_GetFlags(geWBitmap *WBitmap); +geBitmap *geWBitmap_GetBitmap(geWBitmap *WBitmap); +int32 geWBitmap_GetVisFrame(geWBitmap *WBitmap); +geBoolean geWBitmap_SetVisFrame(geWBitmap *WBitmap, int32 VisFrame); + +// changed texture name +char *geWBitmap_Pool_GetWNameByBitmap(geWBitmap_Pool *Pool, const geBitmap *Bitmap); +// end change texture name + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/World/World.c b/G3D/World/World.c new file mode 100644 index 0000000..a7314f4 --- /dev/null +++ b/G3D/World/World.c @@ -0,0 +1,3505 @@ +/****************************************************************************************/ +/* World.c */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render the world, and distribute work to other modules */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "World.h" +#include "System.h" +#include "Ram.h" +#include "BaseType.h" +#include "GBSPFile.h" +#include "Camera.h" +#include "Plane.h" +#include "Surface.h" +#include "Light.h" +#include "WBitmap.h" +#include "Frustum.h" +#ifdef MESHES +#include "Mesh.h" +#endif +#include "Entities.h" +#include "Vis.h" +#include "User.h" +#include "VFile.h" + +#include "Trace.h" + +#include "list.h" + +#include "Bitmap.h" +#include "Bitmap._h" + +#include "Puppet.h" +#include "Body.h" +#include "Motion.h" + +//#define BSP_BACK_TO_FRONT + +//#define DO_ADDREMOVE_MESSAGES +#ifndef _DEBUG +#undef DO_ADDREMOVE_MESSAGES +#endif + +//============================================================================ +// Dirty HACKS that need to be removed +//============================================================================ +#pragma message ("HACK!!! remove geCamera_FillDriverInfo (uses GlobalInfo)") + +int32 MirrorRecursion; // GLOBAL!!! + +GInfo GlobalInfo; +void geCamera_FillDriverInfo(geCamera *Camera); + +extern geVec3d GlobalEyePos; + +Frustum_Info g_HackFrustum; + +//============================================================================ +// **END** HACK section +//============================================================================ +geBoolean geWorld_BitmapListInit(geWorld *World); +geBoolean geWorld_BitmapListShutdown(geWorld *World); +geBoolean geWorld_AddBitmap(geWorld *World, geBitmap *Bitmap); +geBoolean geWorld_RemoveBitmap(geWorld *World,geBitmap *Bitmap); + +//===================================================================================== +// Local Static Globals +//===================================================================================== +typedef struct +{ + geCamera *Camera; + Frustum_Info *Frustum; + geWorld_SkyBoxTData *SkyTData; + +} geWorld_RenderInfo; + +static geEngine *CEngine = NULL; +static geWorld *CWorld = NULL; +static World_BSP *CBSP; +static GBSP_BSPData *BSPData = NULL; // This is in globals, but is also kept here for speed +static geBoolean CanDoMirrors; +static geWorld_DebugInfo *CDebugInfo; +static Frustum_Info *CFrustumInfo; + +static Surf_SurfInfo *pSurfInfo; +static DRV_Driver *RDriver; +static geWorld_Model *g_CurrentModel; + +// Temp trans poly structure +#define MAX_TRANS_POLYS 256 +#define MAX_CACHE_VERTS 16 + +#define TRANS_MIRROR (1<<0) + +typedef struct +{ + U32 Flags; + S32 Face; // Face this trans poly belongs too + S32 NumVerts; + DRV_TLVertex TLVerts[MAX_CACHE_VERTS]; // Screen points +} World_TransPoly; + +World_TransPoly TransPolys[MAX_TRANS_POLYS]; +S32 NumTransPolys[MAX_MIRROR_RECURSION+1]; +S32 FirstTransPolys[MAX_MIRROR_RECURSION+1]; + +static void RenderTransPoly(geCamera *Camera, World_TransPoly *pPoly); + +// GList.c +#define GLIST_MAX_OPERATIONS 1024 + +typedef struct +{ + uint8 Type; + uint32 Data; +} GList_Operation; + +typedef struct +{ + GList_Operation GListOperations[GLIST_MAX_OPERATIONS]; + int32 NumGListOperations; +} GList; + +GList_Operation GListOperations[GLIST_MAX_OPERATIONS]; +int32 FirstGListOperations[MAX_MIRROR_RECURSION+1]; +int32 NumGListOperations[MAX_MIRROR_RECURSION+1]; + +//===================================================================================== +//===================================================================================== +GList *GList_Create(geEngine *Engine, geWorld *World) +{ + return NULL; +} + +//===================================================================================== +//===================================================================================== +void GList_Destroy(GList *GList) +{ + assert(GList); +} + +//===================================================================================== +// GList_AddOperation +//===================================================================================== +void GList_AddOperation(uint8 Type, uint32 Data) +{ + int32 Op; + + if (NumGListOperations[MirrorRecursion] >= GLIST_MAX_OPERATIONS) + return; // Oh well... + + Op = FirstGListOperations[MirrorRecursion] + NumGListOperations[MirrorRecursion]; + + GListOperations[Op].Type = Type; + GListOperations[Op].Data = Data; + + NumGListOperations[MirrorRecursion]++; +} + +//======================================================================================== +// GList_RenderOperations +//======================================================================================== +geBoolean GList_RenderOperations(geCamera *Camera) +{ + int32 i; + + // Render the list from back to front + for (i=NumGListOperations[MirrorRecursion]-1; i>= 0; i--) + { + int32 Op; + + Op = FirstGListOperations[MirrorRecursion] + i; + + switch(GListOperations[Op].Type) + { + case 0: + RenderTransPoly(Camera, (World_TransPoly*)GListOperations[Op].Data); + break; + case 1: + User_RenderPolyList((gePoly*)GListOperations[Op].Data); + break; + + default: + assert(0); + } + } + + NumGListOperations[MirrorRecursion] = 0; + + return GE_TRUE; +} + +//===================================================================================== +// Local Static Functions +//===================================================================================== +static void CalcBSPModelInfo(World_BSP *BSP); +static geBoolean RenderScene(geEngine *Engine, geWorld *World, geCamera *Camera, Frustum_Info *FrustumInfo); +static void RenderBSPFrontBack_r(int32 Node, const geWorld_RenderInfo *RenderInfo, int32 ClipFlags); +static void RenderBSPFrontBackMirror_r(int32 Node, geCamera *Camera, Frustum_Info *Fi, int32 ClipFlags); +static void RenderFace(int32 Face, const geWorld_RenderInfo *RenderInfo, int32 ClipFlags); +static geBoolean RenderWorldModel(geCamera *Camera, Frustum_Info *FrustumInfo, geWorld_SkyBoxTData *SkyTData); +static geBoolean RenderSubModels(geCamera *Camera, Frustum_Info *FrustumInfo, geWorld_SkyBoxTData *SkyTData); +static geBoolean WorldSetGBSP(geWorld *World, World_BSP *BSP); +static World_BSP *CreateGBSP(geVFile *File); + +static geBoolean CreateStaticFogList(geWorld *World); + +// SkyBox functions +static geBoolean BuildSkyBox(World_SkyBox *SkyBox, const GFX_SkyData *SkyData); +static void RenderSkyThroughFrustum(World_SkyBox *SkyBox, geWorld_SkyBoxTData *SkyTData, geCamera *Camera, Frustum_Info *Fi); +static void SetupSkyBoxFaceForScene(World_SkyBox *SkyBox, int32 Face, const geXForm3d *XForm, Frustum_Info *Fi, geWorld_SkyBoxTData *SkyTData); +static void SetupSkyForScene(World_SkyBox *SkyBox, geCamera *Camera, Frustum_Info *Fi, geWorld_SkyBoxTData *SkyTData); + +//===================================================================================== +// World_EngineInit +//===================================================================================== +geBoolean World_EngineInit(geEngine *Engine) +{ + return GE_TRUE; +} + +//===================================================================================== +// World_EngineShutdown +//===================================================================================== +void World_EngineShutdown(geEngine *Engine) +{ + CEngine = NULL; + CWorld = NULL; + BSPData = NULL; +} + +//===================================================================================== +// World_CreateFromBox +// Fill in a world with a blank bsp, with one leaf +//===================================================================================== +World_BSP *World_CreateBSPFromBox(const geVec3d *Mins, const geVec3d *Maxs) +{ + World_BSP *WorldBSP; + GBSP_BSPData *pBSP; + GFX_Leaf *pLeaf; + GFX_Model *pModel; + GFX_Node *pNode; + int32 i; + + WorldBSP = GE_RAM_ALLOCATE_STRUCT(World_BSP); + + if (!WorldBSP) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return NULL; + } + + memset(WorldBSP, 0, sizeof(World_BSP)); + + pBSP = &WorldBSP->BSPData; + + memset(pBSP, 0, sizeof(GBSP_BSPData)); + + pBSP->NumGFXModels = 1; + pBSP->NumGFXNodes = 1; + pBSP->NumGFXBNodes = 0; + pBSP->NumGFXLeafs = 1; + pBSP->NumGFXClusters = 1; + pBSP->NumGFXAreas = 1; + pBSP->NumGFXAreaPortals = 0; + pBSP->NumGFXPlanes = 0; + pBSP->NumGFXFaces = 0; + pBSP->NumGFXLeafFaces = 0; + pBSP->NumGFXLeafSides = 0; + pBSP->NumGFXVerts = 0; + pBSP->NumGFXVertIndexList = 0; + + pBSP->NumGFXEntData = 0; + pBSP->NumGFXTextures = 0; + pBSP->NumGFXTexInfo = 0; + pBSP->NumGFXTexData = 0; + pBSP->NumGFXPalettes = 0; + + pBSP->NumGFXLightData = 0; + pBSP->NumGFXVisData = 0; + pBSP->NumGFXPortals = 0; + + pBSP->GFXNodes = GE_RAM_ALLOCATE_ARRAY(GFX_Node, pBSP->NumGFXNodes); + if (!pBSP->GFXNodes) + return NULL; + + pBSP->GFXModels = GE_RAM_ALLOCATE_ARRAY(GFX_Model, pBSP->NumGFXModels); + if (!pBSP->GFXModels) + return NULL; + + pBSP->GFXLeafs = GE_RAM_ALLOCATE_ARRAY(GFX_Leaf, pBSP->NumGFXLeafs); + if (!pBSP->GFXLeafs) + return NULL; + + pBSP->GFXClusters = GE_RAM_ALLOCATE_ARRAY(GFX_Cluster, pBSP->NumGFXClusters); + if (!pBSP->GFXClusters) + return NULL; + + // Setup node 0 (point it to the only leaf in the level) + pNode = &pBSP->GFXNodes[0]; + memset(pNode, 0, sizeof(*pNode)); + pNode->Children[0] = -1; + pNode->Children[1] = -1; + pNode->PlaneNum = -1; + + // Setup the worlds only model + pModel = &pBSP->GFXModels[0]; + + memset(pModel, 0, sizeof(GFX_Model)); + + pModel->RootNode[0] = -1; + pModel->Mins = *Mins; + pModel->Maxs = *Maxs; + + // Setup the leaf + pLeaf = &pBSP->GFXLeafs[0]; + memset(pLeaf, 0, sizeof(GFX_Leaf)); + + pLeaf->Contents = 0; + pLeaf->Mins = *Mins; + pLeaf->Maxs = *Maxs; + + pLeaf->Cluster = 0; + pLeaf->Area = 0; + + // Setup the cluster that the above leaf points to + pBSP->GFXClusters[pLeaf->Cluster].VisOfs = -1; // No visinfo for this cluster + + // Set up NULL sky + for (i=0; i<6; i++) + pBSP->GFXSkyData.Textures[i] = -1; + + return WorldBSP; +} + +//===================================================================================== +// geWorld_Create +//===================================================================================== +GENESISAPI geWorld *geWorld_Create(geVFile *File) +{ + geWorld *NewWorld; + int32 i; + geWorld_Model *Models; + + NewWorld = GE_RAM_ALLOCATE_STRUCT(geWorld); + + if (!NewWorld) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return NULL; + } + + memset(NewWorld, 0, sizeof(geWorld)); + + // Create a ref on the world now, so if there is an error, it will free what is in the world... + geWorld_CreateRef(NewWorld); + + if ( ! List_Start() ) + goto Error; + + if (!File) + { + geVec3d TMins = {-1000.0f, -1000.0f, -1000.0f}; + geVec3d TMaxs = { 1000.0f, 1000.0f, 1000.0f}; + + NewWorld->CurrentBSP = World_CreateBSPFromBox(&TMins, &TMaxs); + } + else + { + assert(File != NULL); + + NewWorld->CurrentBSP = CreateGBSP(File); + } + + // The world has changed + NewWorld->Changed = GE_TRUE; + + if (!NewWorld->CurrentBSP) + goto Error; + + assert(NewWorld->CurrentBSP->BSPData.NumGFXLeafs > 0); + + // Create the leafdata array + NewWorld->CurrentBSP->LeafData = GE_RAM_ALLOCATE_ARRAY(geWorld_Leaf, NewWorld->CurrentBSP->BSPData.NumGFXLeafs); + + if (!NewWorld->CurrentBSP->LeafData) + goto Error; + + memset(NewWorld->CurrentBSP->LeafData, 0, sizeof(geWorld_Leaf)*NewWorld->CurrentBSP->BSPData.NumGFXLeafs); + + if (!Light_WorldInit(NewWorld)) + goto Error; + + if (!Ent_WorldInit(NewWorld)) + goto Error; + + if (!Vis_WorldInit(NewWorld)) + goto Error; + + if (!Surf_WorldInit(NewWorld)) + goto Error; + + // Create the wbitmaps out of the GFXTexData + NewWorld->CurrentBSP->WBitmapPool = geWBitmap_Pool_Create(&NewWorld->CurrentBSP->BSPData); + + if (!NewWorld->CurrentBSP->WBitmapPool) + goto Error; + + #if 1 + // HACK + // We can now free the texturedata in the BSP that was loaded off disk. + // Eventually, the BSP disk format will be bitmaps, and no conversion will be needed, JP. + if (NewWorld->CurrentBSP->BSPData.GFXTexData) // Not all worlds have tex data!!! + { + geRam_Free(NewWorld->CurrentBSP->BSPData.GFXTexData); + NewWorld->CurrentBSP->BSPData.GFXTexData = NULL; // This is to assure that FreeGBSPFile does not touch this again + NewWorld->CurrentBSP->BSPData.NumGFXTexData = 0; + } + #endif + + // Add all the bitmaps in the WBitmapPool to the world + if (!geWorld_BitmapListInit(NewWorld)) + { + geErrorLog_AddString(-1, "geWorld_WorldCreate: geWorld_BitmapListInit failed.", NULL); + return GE_FALSE; + } + + // Init user stuff + if (!User_WorldInit(NewWorld)) + goto Error; + + Models = NewWorld->CurrentBSP->Models; + + //#pragma message ("Fixed number of models supported") + for (i=0; i< MAX_MODELS; i++) + { + memset(&Models[i], 0, sizeof(geWorld_Model)); + + Models[i].VisFrame = -1; + + geXForm3d_SetIdentity(&Models[i].XForm); + } + + CalcBSPModelInfo(NewWorld->CurrentBSP); + + if (!BuildSkyBox(&NewWorld->SkyBox, &NewWorld->CurrentBSP->BSPData.GFXSkyData)) + goto Error; + + NewWorld->CurrentLeaf = -1; // Make sure the level gets vised for the first time... + + NewWorld->ActorCount = 0; + NewWorld->ActorArray = NULL; + +//MRB BEGIN +//geSprite + NewWorld->SpriteCount = 0; + NewWorld->SpriteArray = NULL; +//MRB END + + if (!CreateStaticFogList(NewWorld)) + { + geErrorLog_AddString(-1,"Failed to create static FogList", NULL); + goto Error; + } + + return NewWorld; + + Error:; + geWorld_Free(NewWorld); + + return NULL; +} + +//===================================================================================== +// geWorld_Free +//===================================================================================== +GENESISAPI void geWorld_Free(geWorld *World) +{ + int i; + geFog *Fog, *Next; + /*extern geActor_Count; + extern geActor_RefCount; + extern geActor_DefCount; + extern geActor_DefRefCount;*/ + + assert(World); + assert(World->RefCount > 0); + + World->RefCount--; + + if (World->RefCount > 0) + return; // No need to destroy till ref count goes to zero... + +if (World->CurrentBSP) +{ + // Shutdown actors + if (World->ActorCount>0) + { + assert( World->ActorArray != NULL ); + for (i=0; i< World->ActorCount; i++) + { + if(!geActor_Destroy( &( World->ActorArray[i].Actor ) )) + geErrorLog_AddString(-1, "geWorld_Free: geActor_Destroy failed.", NULL); + } + + /*geActor_Count = 0;geActor_DestroyDirect + geActor_RefCount = 0; + geActor_DefCount = 0; + geActor_DefRefCount = 0;*/ + World->ActorCount = 0; + + } + if (World->ActorArray != NULL) + { + geRam_Free( World->ActorArray ); + World->ActorArray = NULL; + } + +//MRB BEGIN +//geSprite + // Shutdown sprites + if (World->SpriteCount>0) + { + assert( World->SpriteArray != NULL ); + for (i=0; i< World->SpriteCount; i++) + { + geSprite_Destroy( &( World->SpriteArray[i].Sprite ) ); + } + World->SpriteCount = 0; + } + if (World->SpriteArray != NULL) + { + geRam_Free( World->SpriteArray ); + World->SpriteArray = NULL; + } +//MRB END + + assert( World->ActorArray == NULL ); + + // Call other modules to release info from the world that they created... +#ifdef MESHES + Mesh_WorldShutdown(World); +#endif + Light_WorldShutdown(World); + Ent_WorldShutdown(World); + Vis_WorldShutdown(World); + Surf_WorldShutdown(World); + + User_WorldShutdown(World); + + if (World->CurrentBSP->WBitmapPool) + { + geWBitmap_Pool_Destroy(World->CurrentBSP->WBitmapPool); + World->CurrentBSP->WBitmapPool = NULL; + } + + // Make sure we free all the fog + for (Fog = World->FogList; Fog; Fog = Next) + { + geWorld_FogData *FogData; + + Next = Fog->Next; + + FogData = (geWorld_FogData*)geFog_GetUserData(Fog); + + if (FogData) + geRam_Free(FogData); + + geFog_SetUserData(Fog, NULL); // Just in case... + + geFog_Destroy(Fog); + } + + // Free the leaf data array in the world + if (World->CurrentBSP->LeafData) + { + int32 l; + geWorld_Leaf *pLeafData; + + pLeafData = World->CurrentBSP->LeafData; + + for (l=0; l< World->CurrentBSP->BSPData.NumGFXLeafs; l++, pLeafData++) + { + if (pLeafData->PolyList) + { + User_DestroyPolyList(World, pLeafData->PolyList); + pLeafData->PolyList = NULL; + } + } + + geRam_Free(World->CurrentBSP->LeafData); + World->CurrentBSP->LeafData = NULL; + } + + GBSP_FreeGBSPFile(&World->CurrentBSP->BSPData); + geRam_Free(World->CurrentBSP); + + // Shutdown the bitmaplist (this should be done last, to give others a chance to remove their bitmaps) + geWorld_BitmapListShutdown(World); +} + + geRam_Free(World); + + List_Stop(); +} + +//================================================================================ +// geWorld_CreateRef +//================================================================================ +geBoolean geWorld_CreateRef(geWorld *World) +{ + World->RefCount++; + + return GE_TRUE; +} + +//===================================================================================== +// World_SetEngine +// Lets this module and all its children know that the engine has changed +//===================================================================================== +geBoolean World_SetEngine(geEngine *Engine) +{ + assert (Engine != NULL); + + CEngine = Engine; + + // Let all sub modules know what's going on... + if (!Light_SetEngine(Engine)) + return GE_FALSE; + if (!Plane_SetEngine(Engine)) + return GE_FALSE; + if (!Surf_SetEngine(Engine)) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// World_SetWorld +// Lets this module (and all of its children) know that the world has changed +//===================================================================================== +geBoolean World_SetWorld(geWorld *World) +{ + assert(World != NULL); + + CWorld = World; + + // Let all sub modules know what's going on... + if (!Light_SetWorld(World)) + return GE_FALSE; + if (!Plane_SetWorld(World)) + return GE_FALSE; + if (!Surf_SetWorld(World)) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// World_SetGBSP +// Tells each module bsp data they are dealing with, and lets them update +// various pointers to the bsp, in their local statics +//===================================================================================== +geBoolean World_SetGBSP(World_BSP *BSP) +{ + assert(BSP != NULL); + + // Make quick pointer to the world bsp data + CBSP = BSP; + BSPData = &BSP->BSPData; + + // Let all sub modules know what's going on... + if (!Light_SetGBSP(BSP)) + return GE_FALSE; + if (!Plane_SetGBSP(BSP)) + return GE_FALSE; + + if (!Surf_SetGBSP(BSP)) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// SetupStaticData +//===================================================================================== +void SetupStaticData(void) +{ + pSurfInfo = CBSP->SurfInfo; + RDriver = CEngine->DriverInfo.RDriver; +} + +//===================================================================================== +// World_RenderQ +// Render the worlds render Q using the supplied engine, world, and camera +//===================================================================================== +geBoolean World_WorldRenderQ(geEngine *Engine, geWorld *World, geCamera *Camera) +{ + Frustum_Info FrustumInfo; + geFloat Rpm; + World_SkyBox *pSkyBox; + + assert(Engine != NULL); + assert(World != NULL); + assert(Camera!= NULL); + + World->CurFrameDynamic++; + + MirrorRecursion = 0; + NumTransPolys[MirrorRecursion] = 0; + NumGListOperations[MirrorRecursion] = 0; + + // Clear the debug info for this world + //memset(&World->DebugInfo, 0, sizeof(geWorld_DebugInfo)); + CDebugInfo = &World->DebugInfo; + + // Setup modules that need info that we don't want to lug around with us... + // NOTE - This might screw up multi-threading, so it might need to be changed + // around a little to work with multi-threading + World_SetEngine(Engine); + World_SetWorld(World); + World_SetGBSP(World->CurrentBSP); + + // FIXME: REMOVE!!!!! + GlobalEyePos = *geCamera_GetPov(Camera); + + // Setup some globals for this pass (this must be done before anyone uses them, or KABOOM) + SetupStaticData(); + + CFrustumInfo = &FrustumInfo; + + // Se if we can do mirrors with this driver + CanDoMirrors = (RDriver->EngineSettings->PreferenceFlags & DRV_PREFERENCE_NO_MIRRORS)==0; + + // Setup the View Frustum to default window from the camera + Frustum_SetFromCamera(&FrustumInfo, Camera); + + // Have the Vis module setup all vising info + Vis_VisWorld(Engine, World, Camera, &FrustumInfo); + + // Setup the dynamic lights, etc... + if (!Light_SetupLights(World)) + return GE_FALSE; + + g_HackFrustum = FrustumInfo; + + // Render the entire scene through the DEFAULT FRUSTUM + if (!RenderScene(Engine, World, Camera, &FrustumInfo)) + return GE_FALSE; + + // Adjust current sky angle + pSkyBox = &World->SkyBox; + Rpm = (pSkyBox->Dpm/180.0f)*3.14159f; // Get radiuns per minute + pSkyBox->Angle += Rpm*(1/30.0f); // Assume 30 fps for now :) + + // Little hack to flush the scene + RDriver->BeginModels(); + RDriver->EndModels(); + + if (!User_DestroyOncePolys(World)) + return GE_FALSE; + +#if 1 + // <> CB remember the last camera we rendered with, + // so we can avoiding redoing view-dependent calculation + World->LastCameraXForm = * geCamera_GetCameraSpaceXForm(Camera); +#endif + + return GE_TRUE; +} + + +GENESISAPI geBoolean GENESISCC geWorld_IsActorPotentiallyVisible(const geWorld *World, const geActor *Actor, const geCamera *Camera) + // if the actor doesn't have a render hint box, we assume it's potentially visible +{ + #pragma message ("This is a fairly poor test: ") + // mirrors aren't checked. + // this doesn't check the extents of the actor, just the center point. + // if the render hint box isn't set, should this return true, or find the DynamicExtBox? + geExtBox Box; + geBoolean Enabled; + geVec3d Center; + const geXForm3d *CameraTransform; + int32 Leaf,CameraLeaf; + + assert( World != NULL ); + assert( geActor_IsValid(Actor)!= GE_FALSE ); + assert( Camera != NULL ); + + geActor_GetRenderHintExtBox(Actor,&Box,&Enabled); + if (Enabled == GE_FALSE) + return GE_TRUE; + geExtBox_GetTranslation ( &Box, &Center ); + // NOTE - We are not taking into acount that a actor may live in more than one leaf... + geWorld_GetLeaf(World, &Center, &Leaf); + + CameraTransform = geCamera_GetWorldSpaceVisXForm( Camera ); + geWorld_GetLeaf(World, &(CameraTransform->Translation), &CameraLeaf); + + #pragma message ("geWorld_MightSeeLeaf would be WAY FASTER here, but would be a frame behind...") + if (geWorld_LeafMightSeeLeaf(World, Leaf, CameraLeaf, 0 )==GE_FALSE) + return GE_FALSE; + + { + // perhaps this should be a 'geCamera_IsExtBoxOnScreen(Camera,Box)' function? + // see if the hint box is visible on the screen. + // (transform and project it to the screen, then check extents of that projection + // against the clipping rect) + #pragma message ("This should use frustum in world space, and use Trace_BoxOnPlaneSides with frustum planes...") + geRect ClippingRect; + geVec3d BoxCorners[8]; + const geXForm3d *ObjectToCamera; + geVec3d Maxs,Mins; + #define BIG_NUMBER (99e9f) + int i; + + geCamera_GetClippingRect(Camera,&ClippingRect); + BoxCorners[0] = Box.Min; + BoxCorners[1] = BoxCorners[0]; BoxCorners[1].X = Box.Max.X; + BoxCorners[2] = BoxCorners[0]; BoxCorners[2].Y = Box.Max.Y; + BoxCorners[3] = BoxCorners[0]; BoxCorners[3].Z = Box.Max.Z; + BoxCorners[4] = Box.Max; + BoxCorners[5] = BoxCorners[4]; BoxCorners[5].X = Box.Min.X; + BoxCorners[6] = BoxCorners[4]; BoxCorners[6].Y = Box.Min.Y; + BoxCorners[7] = BoxCorners[4]; BoxCorners[7].Z = Box.Min.Z; + + ObjectToCamera = geCamera_GetCameraSpaceXForm(Camera); + assert( ObjectToCamera ); + + geVec3d_Set(&Maxs,-BIG_NUMBER,-BIG_NUMBER,-BIG_NUMBER); + geVec3d_Set(&Mins, BIG_NUMBER, BIG_NUMBER, BIG_NUMBER); + for (i=0; i<8; i++) + { + geVec3d V; + geXForm3d_Transform( ObjectToCamera,&(BoxCorners[i]),&(BoxCorners[i])); + geCamera_Project( Camera,&(BoxCorners[i]),&V); + if (V.X > Maxs.X ) Maxs.X = V.X; + if (V.X < Mins.X ) Mins.X = V.X; + if (V.Y > Maxs.Y ) Maxs.Y = V.Y; + if (V.Y < Mins.Y ) Mins.Y = V.Y; + if (V.Z > Maxs.Z ) Maxs.Z = V.Z; + if (V.Z < Mins.Z ) Mins.Z = V.Z; + } + + if ( (Maxs.X < ClippingRect.Left) + || (Mins.X > ClippingRect.Right) + || (Maxs.Y < ClippingRect.Top) + || (Mins.Y > ClippingRect.Bottom) + || (Maxs.Z < 0.0f) ) + { + return GE_FALSE; + } + } + + return GE_TRUE; + +} + +//MRB BEGIN +//geSprite +GENESISAPI geBoolean GENESISCC geWorld_IsSpritePotentiallyVisible(const geWorld *World, const geSprite *Sprite, const geCamera *Camera) +{ + #pragma message ("This is a fairly poor test: ") + // mirrors aren't checked. + // this doesn't check the extents of the sprite, just the center point. + geVec3d Center; + const geXForm3d *CameraTransform; + int32 Leaf,CameraLeaf; + + assert( World != NULL ); + assert( geSprite_IsValid(Sprite)!= GE_FALSE ); + assert( Camera != NULL ); + + geSprite_GetPosition ( Sprite, &Center ); + + // NOTE - We are not taking into acount that a sprite may live in more than one leaf... + geWorld_GetLeaf(World, &Center, &Leaf); + + CameraTransform = geCamera_GetWorldSpaceVisXForm( Camera ); + geWorld_GetLeaf(World, &(CameraTransform->Translation), &CameraLeaf); + + #pragma message ("geWorld_MightSeeLeaf would be WAY FASTER here, but would be a frame behind...") + if (geWorld_LeafMightSeeLeaf(World, Leaf, CameraLeaf, 0 )==GE_FALSE) + return GE_FALSE; + + return GE_TRUE; +} +//MRB END + + +//===================================================================================== +// RenderScene +// This can be recursivly re-entered +//===================================================================================== +static geBoolean RenderScene(geEngine *Engine, geWorld *World, geCamera *Camera, Frustum_Info *FrustumInfo) +{ + geWorld_SkyBoxTData SkyTData; + + if (MirrorRecursion > 0) + { + FirstTransPolys[MirrorRecursion] = NumTransPolys[MirrorRecursion-1]; + FirstGListOperations[MirrorRecursion] = NumGListOperations[MirrorRecursion-1]; + } + else + { + FirstTransPolys[MirrorRecursion] = 0; + FirstGListOperations[MirrorRecursion] = 0; + } + + NumTransPolys[MirrorRecursion] = 0; + NumGListOperations[MirrorRecursion] = 0; + + memset(&SkyTData, 0, sizeof(SkyTData)); + + // + // Setup the sky for this scene + // + SetupSkyForScene(&World->SkyBox, Camera, FrustumInfo, &SkyTData); + + // + // Render the world... + // + if (!RenderWorldModel(Camera, FrustumInfo, &SkyTData)) + return GE_FALSE; + + // + // Then render the Sub models of the world + // + if (!RenderSubModels(Camera, FrustumInfo, &SkyTData)) + return GE_FALSE; + + // + // Render the actors + // + { + int i; + World_Actor *WActor; + +//MRB BEGIN +//geSprite + World_Sprite *WSprite; +//MRB END + + //geXForm3d XForm; + geVec3d Center; + int32 Leaf; + Frustum_Info ActorFrustum; + + // Make the frustum go to world space for actors + Frustum_TransformToWorldSpace(FrustumInfo, Camera, &ActorFrustum); + + // Tell the driver we want to render meshes + if (!Engine->DriverInfo.RDriver->BeginMeshes()) + { + geErrorLog_Add(GE_ERR_BEGIN_MESHES_FAILED, NULL); + return GE_FALSE; + } + + // We were using the actor array alot, so I though I'd move it out... + // There were also going to be a lot of nested if's, so they are continues now... + WActor = World->ActorArray; + + for (i=0; i< World->ActorCount; i++, WActor++) + { + if (MirrorRecursion == 0 && !(WActor->Flags & (GE_ACTOR_RENDER_NORMAL | GE_ACTOR_RENDER_ALWAYS))) + continue; // Not visible in normal views, skip it + if (MirrorRecursion > 0 && !(WActor->Flags & (GE_ACTOR_RENDER_MIRRORS | GE_ACTOR_RENDER_ALWAYS))) + continue; // Not visible in mirros, skip it + + { + geExtBox Box; + geBoolean Enabled; + geActor_GetRenderHintExtBox(WActor->Actor,&Box,&Enabled); + if (Enabled == GE_TRUE) + { + geExtBox_GetTranslation ( &Box, &Center ); + if (!(WActor->Flags & GE_ACTOR_RENDER_ALWAYS)) + { + // NOTE - We are not taking into acount that a actor may live in more than one leaf... + geWorld_GetLeaf(World, &Center, &Leaf); + + if (World->CurrentBSP->LeafData[Leaf].VisFrame != World->CurFrameStatic) + continue; // Not in PVS, skip it + } + } + } + + if (MirrorRecursion == 0) + { + geActor_Render( WActor->Actor, Engine, World, Camera); + // For debugging... + // This is set inside Actor/Puppet. Engine->DebugInfo.NumActors++; + } + else + { + geActor_RenderThroughFrustum( WActor->Actor, Engine, World, Camera, &ActorFrustum); + // For debugging... + Engine->DebugInfo.NumActors++; + } + + } + +//MRB BEGIN +//geSprite + WSprite = World->SpriteArray; + + for (i = 0; i < World->SpriteCount; i++, WSprite++) + { + // Not visible in normal views, skip it + if ( (MirrorRecursion == 0) && !(WSprite->Flags & (GE_SPRITE_RENDER_NORMAL | GE_SPRITE_RENDER_ALWAYS)) ) + continue; + + // Not visible in mirros, skip it + if ( (MirrorRecursion > 0) && !(WSprite->Flags & (GE_SPRITE_RENDER_MIRRORS | GE_SPRITE_RENDER_ALWAYS)) ) + continue; + + // if it is not always rendered, then make sure it is in a visible leaf + if (!(WSprite->Flags & GE_SPRITE_RENDER_ALWAYS)) + { + // get the position of the sprite + geSprite_GetPosition( WSprite->Sprite, &Center ); + + // NOTE - We are not taking into acount that a sprite may live in more than one leaf... + geWorld_GetLeaf(World, &Center, &Leaf); + + // Not in PVS, skip it + if (World->CurrentBSP->LeafData[Leaf].VisFrame != World->CurFrameStatic) + continue; + } + + // render the sprite through the frustum + geSprite_RenderThroughFrustum(WSprite->Sprite, Engine, World, Camera, &ActorFrustum); + } +//MRB END + + if (!Engine->DriverInfo.RDriver->EndMeshes()) + { + geErrorLog_Add(GE_ERR_END_MESHES_FAILED, NULL); + return GE_FALSE; + } + } + + // Hack... Must restore the camera hack for trans world polys + geCamera_FillDriverInfo(Camera); + + // Setup the user stuff with the world for this scene + if (!User_SetCameraInfo(Engine, World, Camera, FrustumInfo)) + return GE_FALSE; + + // Render all the translucent polys last (on top of everything).... + if (!GList_RenderOperations(Camera)) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// RenderBSPFrontBack_r2 +// Fast traverser, that only traverses to visible leafs, nothing else. +//===================================================================================== +static void RenderBSPFrontBack_r2(int32 Node, geCamera *Camera) +{ + geFloat Dist1; + GFX_Node *pNode; + int32 Side; + + if (Node < 0) // At leaf, no more recursing + { + int32 Leaf; + gePoly *PolyList; + + Leaf = -(Node+1); + + assert(Leaf >= 0 && Leaf < CWorld->CurrentBSP->BSPData.NumGFXLeafs); + + PolyList = CWorld->CurrentBSP->LeafData[Leaf].PolyList; + + if (PolyList) + { + CDebugInfo->NumLeafsWithUserPolys++; + GList_AddOperation(1, (uint32)PolyList); + } + + CDebugInfo->NumLeafsHit2++; + + return; + } + + if (CBSP->NodeVisFrame[Node] != CWorld->CurFrameStatic) + { + if (CWorld->VisInfo) + return; + } + + CDebugInfo->NumNodesTraversed2++; + + pNode = &BSPData->GFXNodes[Node]; + + // Get the distance that the eye is from this plane + Dist1 = Plane_PlaneDistanceFast(&BSPData->GFXPlanes[pNode->PlaneNum], geCamera_GetPov(Camera)); + + if (Dist1 < 0) + Side = 1; + else + Side = 0; + + // Go down the side we are on first, then the other side + RenderBSPFrontBack_r2(pNode->Children[Side], Camera); + RenderBSPFrontBack_r2(pNode->Children[!Side], Camera); +} + +//===================================================================================== +// RenderBSPFrontBack_r +//===================================================================================== +static void RenderBSPFrontBack_r(int32 Node, const geWorld_RenderInfo *RenderInfo, int32 ClipFlags) +{ + geFloat Dist1; + int32 i; + int32 k, f, Side; + GFX_Node *pNode; + GFX_Face *pFace; + Surf_SurfInfo *pSurfInfo2; + + if (Node < 0) // At leaf, no more recursing + { + int32 Leaf; + gePoly *PolyList; + + Leaf = -(Node+1); + + assert(Leaf >= 0 && Leaf < CWorld->CurrentBSP->BSPData.NumGFXLeafs); + + PolyList = CWorld->CurrentBSP->LeafData[Leaf].PolyList; + + if (PolyList) + { + CDebugInfo->NumLeafsWithUserPolys++; + GList_AddOperation(1, (uint32)PolyList); + } + + CDebugInfo->NumLeafsHit1++; + + return; + } + + if (CBSP->NodeVisFrame[Node] != CWorld->CurFrameStatic) + { + if (CWorld->VisInfo) + return; + } + + CDebugInfo->NumNodesTraversed1++; + + pNode = &BSPData->GFXNodes[Node]; + + if (ClipFlags) + { + geFloat *MinMaxs; + int32 *Index; + geFloat Dist; + geVec3d Pnt; + GFX_Plane *Planes; + Frustum_Info *Fi; + + Fi = RenderInfo->Frustum; + + MinMaxs = (geFloat*)&pNode->Mins; + Planes = Fi->Planes; + + for (k=0; k< Fi->NumPlanes; k++) + { + if (!(ClipFlags & (1<pFrustumBBoxIndexes[k]; + + Pnt.X = MinMaxs[Index[0]]; + Pnt.Y = MinMaxs[Index[1]]; + Pnt.Z = MinMaxs[Index[2]]; + + Dist = geVec3d_DotProduct(&Pnt, &Planes[k].Normal); + Dist -= Fi->Planes[k].Dist; + + if (Dist <= 0) + { + // We have no more visible nodes from this POV, so just traverse to leafs from here + RenderBSPFrontBack_r2(Node, RenderInfo->Camera); + return; + } + + Pnt.X = MinMaxs[Index[3+0]]; + Pnt.Y = MinMaxs[Index[3+1]]; + Pnt.Z = MinMaxs[Index[3+2]]; + + Dist = geVec3d_DotProduct(&Pnt, &Planes[k].Normal); + Dist -= Planes[k].Dist; + + if (Dist >= 0) + ClipFlags &= ~(1<GFXPlanes[pNode->PlaneNum], geCamera_GetPov(RenderInfo->Camera)); + + pSurfInfo2 = &pSurfInfo[pNode->FirstFace]; + pFace = &BSPData->GFXFaces[pNode->FirstFace]; + + if (Dist1 < 0) + Side = 1; // Back side first + else + Side = 0; // Front side first + + // Render the side of the node we are on first + RenderBSPFrontBack_r(pNode->Children[Side], RenderInfo, ClipFlags); + + // Setup the global driver info about this plane (all the faces share it for this run) + // FIXME: Software driver needs to calculate gradients from uv's, so we can QUIT doing this here... + GlobalInfo.PlaneNormal = BSPData->GFXPlanes[pNode->PlaneNum].Normal; + GlobalInfo.PlaneDist = BSPData->GFXPlanes[pNode->PlaneNum].Dist; + geXForm3d_Rotate(geCamera_GetCameraSpaceXForm(RenderInfo->Camera), &GlobalInfo.PlaneNormal, &GlobalInfo.RPlaneNormal); + + // Render faces on this node + for (i = 0; i < pNode->NumFaces; i++, pSurfInfo2++, pFace++) + { + f = i + pNode->FirstFace; + + if (pSurfInfo2->VisFrame != CWorld->CurFrameStatic && CWorld->VisInfo) + continue; + + if (pFace->PlaneSide != Side) + continue; + + CEngine->DebugInfo.TraversedPolys++; + RenderFace(f, RenderInfo, ClipFlags); + } + + // Render faces on the other side of the node + RenderBSPFrontBack_r(pNode->Children[!Side], RenderInfo, ClipFlags); +} + +void GENESISCC geXForm3d_SetLeft(geXForm3d *M, const geVec3d *Left) + // Gets a vector that is 'left' in the frame of reference of M (facing -Z) +{ + assert( M != NULL ); + assert( Left != NULL ); + + M->AX = -Left->X; + M->BX = -Left->Y; + M->CX = -Left->Z; +} + +void GENESISCC geXForm3d_SetUp(geXForm3d *M, const geVec3d *Up) + // Gets a vector that is 'up' in the frame of reference of M (facing -Z) +{ + assert( M != NULL ); + assert( Up != NULL ); + + M->AY = Up->X; + M->BY = Up->Y; + M->CY = Up->Z; +} + +void GENESISCC geXForm3d_SetIn(geXForm3d *M,const geVec3d *In) + // Gets a vector that is 'in' in the frame of reference of M (facing -Z) +{ + assert( M != NULL ); + assert( In != NULL ); + + M->AZ = -In->X; + M->BZ = -In->Y; + M->CZ = -In->Z; +} + +//================================================================================ +// BackRotateVector +// Rotate a vector from viewspace to worldspace. +//================================================================================ +static void BackRotateVector(const geVec3d *In, geVec3d *Out, const geXForm3d *XForm) +{ + geVec3d VRight, VUp, VIn; + + // Get the 3 vectors that make up the Xform axis + VRight.X = XForm->AX; VRight.Y = XForm->AY; VRight.Z = XForm->AZ; + VUp.X = XForm->BX; VUp.Y = XForm->BY; VUp.Z = XForm->BZ; + VIn.X = XForm->CX; VIn.Y = XForm->CY; VIn.Z = XForm->CZ; + + Out->X = (In->X * VRight.X) + (In->Y * VUp.X) + (In->Z * VIn.X); + Out->Y = (In->X * VRight.Y) + (In->Y * VUp.Y) + (In->Z * VIn.Y); + Out->Z = (In->X * VRight.Z) + (In->Y * VUp.Z) + (In->Z * VIn.Z); +} + +#define GOURAUD_SHADING + +//===================================================================================== +// RenderFace +//===================================================================================== +static void RenderFace(int32 Face, const geWorld_RenderInfo *RenderInfo, int32 ClipFlags) +{ + geVec3d Dest1[MAX_RENDERFACE_VERTS], Dest2[MAX_RENDERFACE_VERTS]; + geVec3d *pDest1, *pDest2; + Surf_TexVert Tex1[MAX_RENDERFACE_VERTS], Tex2[MAX_RENDERFACE_VERTS]; + Surf_TexVert *pTex1, *pTex2; + DRV_TLVertex Clipped1[MAX_RENDERFACE_VERTS]; + geVec3d *pGFXVerts; + int32 Length1, Length2; + int32 i, p; + int32 *pIndex; + int32 TexFlags; + int32 NumVerts; + geBitmap *pBitmap; + GFX_Face *pFace; + GFX_TexInfo *pTexInfo; + const geXForm3d *CXForm; + GFX_Plane *FPlanes; + uint32 RenderFlags; + DRV_TexInfo DrvTexInfo; + geWBitmap *pWBitmap; + geRDriver_THandle *THandle; + Frustum_Info *Fi; + geCamera *Camera; + + Fi = RenderInfo->Frustum; + Camera = RenderInfo->Camera; + + if (pSurfInfo[Face].LInfo.Face == -1) + return; + + pFace = &BSPData->GFXFaces[Face]; + pGFXVerts = BSPData->GFXVerts; + + NumVerts = pFace->NumVerts; + + assert(NumVerts < MAX_RENDERFACE_VERTS); + + pTexInfo = &BSPData->GFXTexInfo[pFace->TexInfo]; + TexFlags = pTexInfo->Flags; + + pDest1 = Dest1; + pIndex = &BSPData->GFXVertIndexList[pFace->FirstVert]; + + if (pSurfInfo[Face].Flags & SURFINFO_WAVY) + { + for (i = 0; i < NumVerts; i++) + { + int32 Offs1, Offs2; + + // HACK + Offs1 = (CEngine->WaveTable[*pIndex & 15]-75) / 25; + Offs2 = (CEngine->WaveTable[*pIndex & 15]-75) / 20; + + pDest1->X = pGFXVerts[*pIndex].X + Offs1; + pDest1->Y = pGFXVerts[*pIndex].Y; + pDest1->Z = pGFXVerts[*pIndex].Z + Offs2; + pDest1++; + pIndex++; + } + } + else + { + for (i = 0; i < NumVerts; i++) + { + pDest1->X = pGFXVerts[*pIndex].X; + pDest1->Y = pGFXVerts[*pIndex].Y; + pDest1->Z = pGFXVerts[*pIndex].Z; + pDest1++; + pIndex++; + + } + } + + pDest1 = Dest1; + pDest2 = Dest2; + pTex1 = &CBSP->TexVerts[pFace->FirstVert]; + pTex2 = Tex2; + Length1 = NumVerts; + + + FPlanes = Fi->Planes; + +#if 0 // Test + // + // Apply any fog to the faces verts + // + TexFlags |= TEXINFO_GOURAUD; + pTexInfo->Flags |= TEXINFO_NO_LIGHTMAP; + + for (i=0; i< Length1; i++) + { + pTex1[i].r = 20.0f; + pTex1[i].g = 20.0f; + pTex1[i].b = 20.0f; + } + for (i=0; iNumVisibleFog; i++) + { + Light_FogVerts(CWorld->VisibleFog[i], geCamera_GetPov(Camera), pDest1, pTex1, Length1); + } + for (i=0; i< Length1; i++) + { + if (pTex1[i].r > 255.0f) + pTex1[i].r = 255.0f; + if (pTex1[i].g > 255.0f) + pTex1[i].g = 255.0f; + if (pTex1[i].b > 255.0f) + pTex1[i].b = 255.0f; + } +#endif + + if (ClipFlags) + { + for (p=0; p< Fi->NumPlanes; p++) + { + // Only do clipping if we have to + if (!(ClipFlags & (1<WBitmapPool, pTexInfo->Texture); + assert(pWBitmap); + geWBitmap_SetVisFrame(pWBitmap, CWorld->CurFrameDynamic); + + // + // Get the camera XForm + // + CXForm = geCamera_GetCameraSpaceXForm(Camera); + + // + // Transform the array of verts + // + geXForm3d_TransformArray(CXForm, pDest1, pDest2, Length1); + + if (TexFlags & TEXINFO_SKY) // If this is a sky face, then render the sky through it, and return + { + Frustum_Info SkyFrustum; + + // Create a frustum from the poly + Frustum_SetFromPoly(&SkyFrustum, pDest2, Length1, MirrorRecursion&1); + + // Render the sky through the poly's frustum + RenderSkyThroughFrustum(&CWorld->SkyBox, RenderInfo->SkyTData, Camera, &SkyFrustum); + return; // Once the sky was rendered through the face, return + } + else if (TexFlags & TEXINFO_GOURAUD) + { + Frustum_ProjectRGB(pDest2, pTex1, Clipped1, Length1, Camera); + } + else + { + Frustum_Project(pDest2, pTex1, Clipped1, Length1, Camera); + + for (i=0; i< Length1; i++) + { + Clipped1[i].r = 255.0f; + Clipped1[i].g = 255.0f; + Clipped1[i].b = 255.0f; + } + } + + // If we hit a mirror face, render the world through the mirror's POV, then draw the mirror poly on top of the + // hole made by the mirror (NOTE - we only do this if the Driver wants to do recursive scenes) + if ((TexFlags & TEXINFO_MIRROR) && CanDoMirrors && MirrorRecursion < MAX_MIRROR_RECURSION) + { + Frustum_Info MirrorFrustum; + geXForm3d MirrorXForm, OldXForm; + GFX_Plane *pPlane; + geVec3d FaceNormal; + geFloat FaceDist; + + // + // Create the mirror frustum, for the mirrored scene. + // Use the transformed data, since the Frustum is expected to start out in camera space + // + if (!Frustum_SetFromPoly(&MirrorFrustum, pDest2, Length1, MirrorRecursion&1)) + return; + + if (MirrorFrustum.NumPlanes+1 >= MAX_FCP) + return; // Oh well... + + // Add the transformed face plane to the frustum, so we only draw what is on the front + // side of the mirror + pPlane = &MirrorFrustum.Planes[MirrorFrustum.NumPlanes++]; + + if (MirrorRecursion&1) + gePlane_SetFromVerts(pPlane, &pDest2[0], &pDest2[1], &pDest2[2]); + else + gePlane_SetFromVerts(pPlane, &pDest2[2], &pDest2[1], &pDest2[0]); + + // + // Mirror the camera + // Use the world space face for this + // + #pragma message ("Rotated models are broken in mirrors. Quick fix: Rotate the plane against the models xform") + + FaceNormal = BSPData->GFXPlanes[pFace->PlaneNum].Normal; + FaceDist = BSPData->GFXPlanes[pFace->PlaneNum].Dist; + + if (pFace->PlaneSide) + { + geVec3d_Inverse(&FaceNormal); + FaceDist = -FaceDist; + } + + // Save old camera xform + OldXForm = *geCamera_GetWorldSpaceXForm(Camera); + + // Create the xform that will mirror the camera, by taking the surfaca plane of this face + geXForm3d_Mirror(&OldXForm, &FaceNormal, FaceDist, &MirrorXForm); + + // Mirror the camera using this xform + geCamera_SetWorldSpaceXForm(Camera, &MirrorXForm); + + MirrorRecursion++; + CEngine->DebugInfo.NumMirrors++; + + // Render the world through the poly, from the mirrored camera + RenderScene(CEngine, CWorld, Camera, &MirrorFrustum); + + MirrorRecursion--; + + // Restore the camera + geCamera_SetWorldSpaceXForm(Camera, &OldXForm); + } + + // Get a pointer to the bitmap (texture) + pBitmap = geWBitmap_GetBitmap(pWBitmap); + assert(geWorld_HasBitmap(CWorld, pBitmap)); + + RenderFlags = 0; + + CEngine->DebugInfo.SentPolys++; + + // All transparent polys (either some alpha translucency, or color key) will be drawn last, and sorted. + // They are then added to the TransPoly list (front to back), then when all is done, the Trans polys are drawn + // in reverse order (back to front) last. + // NOTE - Mirrors are not put in this list. They are drawn below, to cover up the "hole" made by the mirror... + if ((pSurfInfo[Face].Flags & SURFINFO_TRANS) && !(pTexInfo->Flags & TEXINFO_MIRROR)) + { + DRV_TLVertex *pVerts; + World_TransPoly *pPoly; + int32 Start; + + Start = FirstTransPolys[MirrorRecursion]+NumTransPolys[MirrorRecursion]; + + if (Start+1 >= MAX_TRANS_POLYS || Length1 > MAX_CACHE_VERTS) + return; // Oh well... + + pPoly = &TransPolys[Start]; + + pVerts = pPoly->TLVerts; + + for (i = 0; i < Length1; i++, pVerts++) + *pVerts = Clipped1[i]; + + pPoly->Flags = 0; + pPoly->Face = Face; + pPoly->NumVerts = Length1; + + // Add this TransPoly to the GList (Geometry List) that is rendered after the current subscene is done + GList_AddOperation(0, (uint32)pPoly); + + NumTransPolys[MirrorRecursion]++; + + // Just return, the Trans poly will get rendered at the end of the scene in GList_RenderOperations... + return; + } + + // If this surface is a mirror, and we can do mirrors, then render it with some alpha + if ((pTexInfo->Flags & TEXINFO_MIRROR) && CanDoMirrors) + { + RenderFlags |= DRV_RENDER_ALPHA | DRV_RENDER_FLUSH; + Clipped1[0].a = pTexInfo->Alpha; + } + else + { + // Else, don't render with any alpha + Clipped1[0].a = 255.0f; + } + + DrvTexInfo.ShiftU = pSurfInfo[Face].ShiftU; + DrvTexInfo.ShiftV = pSurfInfo[Face].ShiftV; + //DrvTexInfo.ShiftU = pTexInfo->Shift[0]; + //DrvTexInfo.ShiftV = pTexInfo->Shift[1]; + DrvTexInfo.DrawScaleU = pTexInfo->DrawScale[0]; + DrvTexInfo.DrawScaleV = pTexInfo->DrawScale[1]; + + GlobalInfo.VecU = pTexInfo->Vecs[0]; + GlobalInfo.VecV = pTexInfo->Vecs[1]; + GlobalInfo.TexShiftX = pTexInfo->Shift[0]; + GlobalInfo.TexShiftY = pTexInfo->Shift[1]; + + // Get the THandle from the bitmap + THandle = geBitmap_GetTHandle(pBitmap); + assert(THandle); + + if (pTexInfo->Flags & TEXINFO_NO_LIGHTMAP) + { + RDriver->RenderWorldPoly(Clipped1, Length1, THandle, &DrvTexInfo, NULL, RenderFlags); + } + else + { + DRV_LInfo *pLInfo = &pSurfInfo[Face].LInfo; + + // The camera is set up at the beginning of the world... + GlobalInfo.TexMinsX = pLInfo->MinU; + GlobalInfo.TexMinsY = pLInfo->MinV; + GlobalInfo.TexWidth = pLInfo->Width<<4; + GlobalInfo.TexHeight = pLInfo->Height<<4; + + RDriver->RenderWorldPoly(Clipped1, Length1, THandle, &DrvTexInfo, &pSurfInfo[Face].LInfo, RenderFlags); + } +} + +//===================================================================================== +// RenderWorldModel +// Renders model 0 (the world model) +//===================================================================================== +static geBoolean RenderWorldModel(geCamera *Camera, Frustum_Info *FrustumInfo, geWorld_SkyBoxTData *SkyTData) +{ + geXForm3d OldXForm,NewXForm, CXForm; + geWorld_Model *Models; + Frustum_Info WorldSpaceFrustum; + uint32 StartClipFlags; + geWorld_RenderInfo RenderInfo; + + assert(CWorld != NULL); // Asser that some globals are true (hopefully)... + assert(CBSP != NULL); + + Models = CBSP->Models; + + g_CurrentModel = Models; + + if (!RDriver->BeginWorld()) + { + geErrorLog_Add(GE_ERR_BEGIN_WORLD_FAILED, NULL); + return GE_FALSE; + } + + OldXForm = *geCamera_GetWorldSpaceXForm(Camera); //Camera->MXForm; // Save old camera for this model + + NewXForm = OldXForm; + + // Put the camera model about models origin + geVec3d_Subtract(&NewXForm.Translation, &Models[0].Pivot, &NewXForm.Translation); + + // Transform the cameras xform against the models xform + + // treat the model as a camera, and apply it to the camera model + geCamera_ConvertWorldSpaceToCameraSpace(&Models[0].XForm, &CXForm); + + geXForm3d_Multiply(&CXForm, &NewXForm, &NewXForm); + + // Put back into camera space + geVec3d_Add(&NewXForm.Translation, &Models[0].Pivot, &NewXForm.Translation); + + // Convert the NewXForm back into a real camera + geCamera_SetWorldSpaceXForm(Camera, &NewXForm); + + // Make the frustum go to world space + Frustum_TransformToWorldSpace(FrustumInfo, Camera, &WorldSpaceFrustum); + + geCamera_FillDriverInfo(Camera); + + // Make a ClipFlags bits for for each side of the frustum... + assert(WorldSpaceFrustum.NumPlanes < 32); + + StartClipFlags = (1<GFXModels[0].RootNode[0], + &RenderInfo, + StartClipFlags); + + // Restore the camera + geCamera_SetWorldSpaceXForm(Camera, &OldXForm); + + if (!RDriver->EndWorld()) + { + geErrorLog_Add(GE_ERR_END_WORLD_FAILED, NULL); + return GE_FALSE; + } + return GE_TRUE; +} + +//===================================================================================== +// RenderSubModels +// Renders all other models besides world model +//===================================================================================== +static geBoolean RenderSubModels(geCamera *Camera, Frustum_Info *FrustumInfo, geWorld_SkyBoxTData *SkyTData) +{ + int32 i; + BOOL OldVis; + geWorld_Model *Model; + geXForm3d OldXForm, NewXForm, CXForm; + Frustum_Info ModelSpaceFrustum; + uint32 StartClipFlags; + geWorld_RenderInfo RenderInfo; + + + if (!RDriver->BeginModels()) + { + geErrorLog_Add(GE_ERR_BEGIN_MODELS_FAILED, NULL); + return GE_FALSE; + } + + assert(CWorld != NULL); // Assert that some globals are true (hopefully)... + assert(CBSP != NULL); + + OldVis = CWorld->VisInfo; // Save old vis info flag + + CWorld->VisInfo = FALSE; // Fake no vis info so ALL model faces/modes will draw + + Model = &CBSP->Models[1]; // Start with the model (skip the world, Models[0]) + + // Render all sub models + for (i=1; i< BSPData->NumGFXModels; i++, Model++) + { + g_CurrentModel = Model; + + if (Model->VisFrame != CWorld->CurFrameDynamic) + continue; + if (MirrorRecursion == 0 && !(Model->Flags & (GE_MODEL_RENDER_NORMAL | GE_MODEL_RENDER_ALWAYS))) + continue; + if (MirrorRecursion > 0 && !(Model->Flags & (GE_MODEL_RENDER_MIRRORS | GE_MODEL_RENDER_ALWAYS))) + continue; + + CEngine->DebugInfo.NumModels++; + + OldXForm = *geCamera_GetWorldSpaceXForm(Camera);//Camera->MXForm; // Save old camera for this model + + NewXForm = OldXForm; + + // Put the camera model about models origin + geVec3d_Subtract(&NewXForm.Translation, &Model->Pivot, &NewXForm.Translation); + + // Transform the cameras xform against the models xform + + // treat the model as a camera, and apply it to the camera model + geCamera_ConvertWorldSpaceToCameraSpace(&Model->XForm, &CXForm); + + geXForm3d_Multiply(&CXForm, &NewXForm, &NewXForm); + + // Put back into camera space + geVec3d_Add(&NewXForm.Translation, &Model->Pivot, &NewXForm.Translation); + + // Convert the NewXForm back into a real camera + geCamera_SetWorldSpaceXForm(Camera, &NewXForm); + + // Make the frustum go to World/Model space + Frustum_TransformToWorldSpace(FrustumInfo, Camera, &ModelSpaceFrustum); + + geCamera_FillDriverInfo(Camera); + + // Make a ClipFlags bits for for each side of the frustum... + StartClipFlags = (1<GFXModels[i].RootNode[0], + &RenderInfo, + StartClipFlags); + + // Restore the camera + geCamera_SetWorldSpaceXForm(Camera, &OldXForm); + } + + CWorld->VisInfo = OldVis; // Restore original vis info + + if (!RDriver->EndModels()) + { + geErrorLog_Add(GE_ERR_END_MODELS_FAILED, NULL); + return GE_FALSE; + } + return GE_TRUE; +} + +//======================================================================================== +// CreateGBSP +//======================================================================================== +static World_BSP *CreateGBSP(geVFile *File) +{ + World_BSP *NewBSP; + + assert(File != NULL); + + // Create a new bsp World + NewBSP = GE_RAM_ALLOCATE_STRUCT(World_BSP); + + if (!NewBSP) + { + geErrorLog_Add(GE_ERR_OUT_OF_MEMORY, NULL); + return NULL; + } + + memset(NewBSP, 0, sizeof(World_BSP)); + + if (!GBSP_LoadGBSPFile(File, &NewBSP->BSPData)) + { + geErrorLog_Add(GE_ERR_GBSP_LOAD_FAILURE, NULL); + return NULL; + } + + return NewBSP; +} + +//======================================================================================== +// RenderTransPoly +//======================================================================================== +static void RenderTransPoly(geCamera *Camera, World_TransPoly *pPoly) +{ + int32 Face; + DRV_TLVertex *pTLVerts; + GFX_Face *pFace; + GFX_TexInfo *pTexInfo; + geBitmap *pBitmap; + int32 NumVerts; + Surf_SurfInfo *pSurfInfo2; + DRV_LInfo *pLInfo; + DRV_TexInfo DrvTexInfo; + + Face = pPoly->Face; + + pFace = &BSPData->GFXFaces[Face]; + + pTLVerts = pPoly->TLVerts; + NumVerts = pPoly->NumVerts; + + pTexInfo = &BSPData->GFXTexInfo[pFace->TexInfo]; + pSurfInfo2 = &pSurfInfo[Face]; + pLInfo = &pSurfInfo2->LInfo; + + // Get a pointer to the bitmap (texture) + pBitmap = geWBitmap_Pool_GetBitmapByIndex(CBSP->WBitmapPool, pTexInfo->Texture); + + assert(geWorld_HasBitmap(CWorld, pBitmap)); + + pTLVerts->a = pTexInfo->Alpha; + + DrvTexInfo.ShiftU = pSurfInfo2->ShiftU; + DrvTexInfo.ShiftV = pSurfInfo2->ShiftV; + //DrvTexInfo.ShiftU = pTexInfo->Shift[0]; + //DrvTexInfo.ShiftV = pTexInfo->Shift[1]; + DrvTexInfo.DrawScaleU = pTexInfo->DrawScale[0]; + DrvTexInfo.DrawScaleV = pTexInfo->DrawScale[1]; + + // Setup the global info (pass this in the driver the right way!!!) + GlobalInfo.VecU = pTexInfo->Vecs[0]; + GlobalInfo.VecV = pTexInfo->Vecs[1]; + GlobalInfo.TexShiftX = pTexInfo->Shift[0]; + GlobalInfo.TexShiftY = pTexInfo->Shift[1]; + + GlobalInfo.PlaneNormal = BSPData->GFXPlanes[pFace->PlaneNum].Normal; + GlobalInfo.PlaneDist = BSPData->GFXPlanes[pFace->PlaneNum].Dist; + geXForm3d_Rotate(geCamera_GetCameraSpaceXForm(Camera), &GlobalInfo.PlaneNormal, &GlobalInfo.RPlaneNormal); + + if (pTexInfo->Flags & TEXINFO_NO_LIGHTMAP) + { + geRDriver_THandle *THandle; + + THandle = geBitmap_GetTHandle(pBitmap); + + assert(THandle); + + RDriver->RenderWorldPoly(pTLVerts, NumVerts, THandle, &DrvTexInfo, NULL, DRV_RENDER_ALPHA | DRV_RENDER_FLUSH); + } + else + { + geRDriver_THandle *THandle; + + // This global info only needs to be set up for faces that have lightmaps... + GlobalInfo.TexMinsX = pLInfo->MinU; + GlobalInfo.TexMinsY = pLInfo->MinV; + GlobalInfo.TexWidth = pLInfo->Width<<4; + GlobalInfo.TexHeight = pLInfo->Height<<4; + + THandle = geBitmap_GetTHandle(pBitmap); + + assert(THandle); + + RDriver->RenderWorldPoly(pTLVerts, NumVerts, THandle, &DrvTexInfo, pLInfo, DRV_RENDER_ALPHA | DRV_RENDER_FLUSH); + } +} + +//======================================================================================== +// CalcBSPModelInfo +// Calculates the center of each BModel by taking the center of their bounding boxs... +// Calcs other info as well... +//======================================================================================== +static void CalcBSPModelInfo(World_BSP *BSP) +{ + int32 m, Node; + geWorld_Model *Models; + GBSP_BSPData *BData; + geVec3d Mins, Maxs; + + assert(BSP != NULL); + + Models = BSP->Models; + BData = &BSP->BSPData; + + for (m=0; m< BData->NumGFXModels; m++) + { + int32 i; + + Node = BData->GFXModels[m].RootNode[0]; + + if (Node < 0 ) + continue; + + Mins = BData->GFXNodes[Node].Mins; + Maxs = BData->GFXNodes[Node].Maxs; + + // Need this so that we can get the motions later. Horrible. + Models[m].BSPModel = &BData->GFXModels[m]; + + // Get the models REAL center + for (i=0; i<3; i++) + VectorToSUB(Models[m].RealCenter, i) = + (VectorToSUB(Mins, i) + VectorToSUB(Maxs, i)) * 0.5f; + + // Get the models rotational pivot point + Models[m].Pivot = BData->GFXModels[m].Origin; + + Models[m].GFXModelNum = m; + + Models[m].Mins = Mins; + Models[m].Maxs = Maxs; + + // Set the translated mins/maxs to some default value... + Models[m].TMins = Mins; + Models[m].TMaxs = Maxs; + + Models[m].Flags = GE_MODEL_RENDER_NORMAL | GE_MODEL_RENDER_MIRRORS; + Models[m].ChangedFlags = MODEL_CHANGED_XFORM; + } +} + +// FIXME: Put all this model stuff into Model.c +#pragma message ("Fix naming convention in models i.e: geWorld_SetModelXForm ---> geWorld_ModelSetXForm...") +//======================================================================================== +// World_SetModelXForm +//======================================================================================== +GENESISAPI geBoolean geWorld_SetModelXForm(geWorld *World, geWorld_Model *Model, const geXForm3d *XForm) +{ + geVec3d AxisVecs[3], Center; + int i, j; + + assert(World != NULL); + assert(Model != NULL); + + Model->XForm = *XForm; + memset(AxisVecs, 0, sizeof(geVec3d)*3); + + //grab the box center + geVec3d_Add(&Model->Mins, &Model->Maxs, &Center); + geVec3d_Scale(&Center, 0.5f, &Center); + + //build a local rotated axis based on extent vectors + //(this could be simplified to less fmuls) + for(i=0;i < 3;i++) + { + VectorToSUB(AxisVecs[i], i) =VectorToSUB(Model->Maxs, i) - VectorToSUB(Center, i); + geXForm3d_Rotate(XForm, &AxisVecs[i], &AxisVecs[i]); + } + + //mask off the sign bits + for(i=0;i < 3;i++) + { + for(j=0;j < 3;j++) + { + *((int *)(&AxisVecs[i])+j) =*((int *)(&AxisVecs[i])+j) & 0x7fffffff; + } + } + + //add up vecs to get max + for(i=0;i < 3;i++) + { + VectorToSUB(Model->TMaxs, i) + =VectorToSUB(AxisVecs[0], i) + + VectorToSUB(AxisVecs[1], i) + + VectorToSUB(AxisVecs[2], i); + } + + //local min is opposite of max + Model->TMins =Model->TMaxs; + geVec3d_Inverse(&Model->TMins); + + //move back to world + geVec3d_Add(&XForm->Translation, &Center, &Center); + geVec3d_Add(&Model->TMins, &Center, &Model->TMins); + geVec3d_Add(&Model->TMaxs, &Center, &Model->TMaxs); + + //add a small epsilon + for(i=0;i < 3;i++) + { + VectorToSUB(Model->TMaxs, i) +=1.0f; + VectorToSUB(Model->TMins, i) -=1.0f; + } + + Model->ChangedFlags |= MODEL_CHANGED_XFORM; + + return GE_TRUE; +} + +//======================================================================================== +// World_GetModelXForm +//======================================================================================== +GENESISAPI geBoolean geWorld_GetModelXForm(const geWorld *World, const geWorld_Model *Model, geXForm3d *XForm) +{ + assert(World != NULL); + assert(Model != NULL); + assert(XForm != NULL); + + *XForm = Model->XForm; + + return GE_TRUE; +} + +//===================================================================================== +// FillAreas_r +//===================================================================================== +void FillAreas_r(geWorld *World, uint32 Area, uint8 *List, uint32 *Count) +{ + GBSP_BSPData *BSP; + GFX_Area *a; + GFX_AreaPortal *p; + int32 i; + + List[*Count] = (uint8)Area; + *Count++; + + BSP = &World->CurrentBSP->BSPData; + + a = &BSP->GFXAreas[Area]; + + p = &BSP->GFXAreaPortals[a->FirstAreaPortal]; + + for (i=0; i< a->NumAreaPortals; i++, p++) + { + geWorld_Model *Model; + + Model = &World->CurrentBSP->Models[p->ModelNum]; + + if (Model->Open) + FillAreas_r(World, p->Area, List, Count); + } +} + +//======================================================================================== +// geWorld_OpenModel +//======================================================================================== +GENESISAPI geBoolean geWorld_OpenModel(geWorld *World, geWorld_Model *Model, geBoolean Open) +{ + World_BSP *WBSP; + int32 a0, a1; + GFX_Model *GFXModel; +#if 0 + int32 i0, i1; + int32 NumWorkAreas0; + uint8 WorkAreas0[256]; + int32 NumWorkAreas1; + uint8 WorkAreas1[256]; +#endif + + assert(World); + assert(Model); + + if (Model->Open == Open) + return GE_TRUE; // Nothing changed + + Model->Open = Open; + World->ForceVis = GE_TRUE; // Force an update + + WBSP = World->CurrentBSP; + + GFXModel = &WBSP->BSPData.GFXModels[Model->GFXModelNum]; + + a0 = GFXModel->Areas[0]; + a1 = GFXModel->Areas[1]; + + // We know these 2 can see each other + WBSP->AreaConnections[a0][a1] = Open; + WBSP->AreaConnections[a1][a0] = Open; + +#if 0 + NumWorkAreas0 = NumWorkAreas1 = 0; + + if (Open) + { + // Combine list into one, and combine vis sets + FillAreas_r(World, a0, WorkAreas0, &NumWorkAreas0); + FillAreas_r(World, a1, WorkAreas0, &NumWorkAreas0); + + // Connect all areas that were flooded into on each side + for (i0=0; i0AreaConnections[*pWork0][*pWork1] = 1; + WBSP->AreaConnections[*pWork1][*pWork0] = 1; + } + } + } + else + { + // Seperate list into two list, and seperate vis list + FillAreas_r(World, a0, WorkAreas0, &NumWorkAreas0); + FillAreas_r(World, a1, WorkAreas1, &NumWorkAreas1); + + // Seperate visiblity from one side to the other + for (i0=0; i0AreaConnections[*pWork0][*pWork1] = 0; + WBSP->AreaConnections[*pWork1][*pWork0] = 0; + } + } + } + #endif + + return GE_TRUE; +} + +//======================================================================================== +//======================================================================================== +GENESISAPI geBoolean geWorld_GetModelRotationalCenter( + const geWorld * World, + const geWorld_Model * Model, + geVec3d * Center) +{ + assert(World != NULL); + assert(Model != NULL); + assert(Center != NULL); + + *Center = Model->Pivot; + + return GE_TRUE; +} + +//======================================================================================== +// World_ModelGetBBox +//======================================================================================== +GENESISAPI geBoolean geWorld_ModelGetBBox(const geWorld *World, const geWorld_Model *Model, geVec3d *Mins, geVec3d *Maxs) +{ + int32 i; + + assert(World != NULL); + assert(Model != NULL); + assert(Mins); + assert(Maxs); + + *Mins = Model->Mins; + *Maxs = Model->Maxs; + + // Translate the BBox to object space + for (i=0; i<3; i++) + { + VectorToSUB(*Mins, i) -= VectorToSUB(Model->Pivot, i); + VectorToSUB(*Maxs, i) -= VectorToSUB(Model->Pivot, i); + } + + return GE_TRUE; +} + +//======================================================================================== +// World_ModelGetMotion +//======================================================================================== +GENESISAPI geMotion * geWorld_ModelGetMotion(geWorld_Model *Model) +{ + assert(Model); + return Model->BSPModel->Motion; +} + +//======================================================================================== +//======================================================================================== +GENESISAPI void * geWorld_ModelGetUserData(const geWorld_Model *Model) +{ + assert(Model); + return Model->UserData; +} + +//======================================================================================== +//======================================================================================== +GENESISAPI void geWorld_ModelSetUserData(geWorld_Model *Model, void *UserData) +{ + assert(Model); + Model->UserData = UserData; +} + +//======================================================================================== +//======================================================================================== +GENESISAPI void geWorld_ModelSetFlags(geWorld_Model *Model, uint32 ModelFlags) +{ + assert(Model); + Model->Flags = ModelFlags; +} + +//======================================================================================== +//======================================================================================== +GENESISAPI uint32 geWorld_ModelGetFlags(geWorld_Model *Model) +{ + assert(Model); + + return Model->Flags; +} + +// eaa3 07/28/2000 Gods, you'd think when you asked for the rotational +// ..center you'd get the REAL center of the model. Fine, this will +// ..return the Actual True Center (feh). + +GENESISAPI void geWorld_ModelGetCenter(geWorld_Model *Model, geVec3d *Center) +{ + *Center = Model->RealCenter; + + return; +} + +//======================================================================================== +//======================================================================================== +GENESISAPI geBoolean geWorld_AddActor( geWorld *World, geActor *Actor, uint32 Flags, uint32 UserFlags) +{ + World_Actor *NewArray; + assert( World != NULL ); + assert( geActor_IsValid(Actor) != GE_FALSE ); + assert( World->ActorCount >= 0 ); + + NewArray = GE_RAM_REALLOC_ARRAY( World->ActorArray, World_Actor , World->ActorCount+1); + if (NewArray == NULL) + { + geErrorLog_AddString(-1,"Failed to grow world actor array", NULL); + return GE_FALSE; + } + World->ActorArray = NewArray; + World->ActorArray[World->ActorCount].Actor = Actor; + World->ActorArray[World->ActorCount].Flags = Flags; + World->ActorArray[World->ActorCount].UserFlags = UserFlags; + if (geActor_RenderPrep( Actor,World )==GE_FALSE) + { + geErrorLog_AddString(-1,"Failed to prepare the actor for rendering", NULL); + return GE_FALSE; + } + World->ActorCount++; + geActor_CreateRef(Actor); + + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"World_AddActor : %08X\n",Actor); + OutputDebugString(str); + } + #endif + + return GE_TRUE; +} + + +//======================================================================================== +//======================================================================================== +GENESISAPI geBoolean geWorld_RemoveActor(geWorld *World, geActor *Actor) +{ + int i,Count; + assert( World != NULL ); + assert( geActor_IsValid(Actor) != GE_FALSE ); + assert( World->ActorCount >= 0 ); + + Count = World->ActorCount; + + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"World_RemoveActor : %08X\n",Actor); + OutputDebugString(str); + } + #endif + + for (i=0; iActorArray[i].Actor == Actor) + { + geActor_Destroy( &Actor ); + World->ActorArray[i] = World->ActorArray[Count-1]; + World->ActorArray[Count-1].Actor = NULL; + World->ActorArray[Count-1].Flags = 0; + World->ActorCount--; + return GE_TRUE; + } + } + geErrorLog_AddString(-1,"Failed to find actor in actor list", NULL); + + return GE_FALSE; +} + +//======================================================================================== +//======================================================================================== +GENESISAPI geBoolean geWorld_SetActorFlags(geWorld *World, geActor *Actor, uint32 Flags) +{ + int i,Count; + assert( World != NULL ); + assert( geActor_IsValid(Actor) != GE_FALSE ); + + Count = World->ActorCount; + + for (i=0; iActorArray[i].Actor == Actor) + { + World->ActorArray[i].Flags = Flags; + return GE_TRUE; + } + } + geErrorLog_AddString(-1,"Failed to find actor in actor list", NULL); + return GE_FALSE; +} + +//MRB BEGIN +//geSprite +//======================================================================================== +//======================================================================================== +GENESISAPI geBoolean geWorld_AddSprite(geWorld *World, geSprite *Sprite, uint32 Flags, uint32 UserFlags) +{ + World_Sprite *NewArray; + + assert( World ); + assert( geSprite_IsValid(Sprite) ); + assert( World->SpriteCount >= 0 ); + + NewArray = GE_RAM_REALLOC_ARRAY( World->SpriteArray, World_Sprite, (World->SpriteCount + 1) ); + + if (NewArray == NULL) + { + geErrorLog_AddString(-1, "Failed to grow world sprite array", NULL); + return GE_FALSE; + } + + World->SpriteArray = NewArray; + World->SpriteArray[World->SpriteCount].Sprite = Sprite; + World->SpriteArray[World->SpriteCount].Flags = Flags; + World->SpriteArray[World->SpriteCount].UserFlags = UserFlags; + + if ( geSprite_RenderPrep(Sprite, World) == GE_FALSE ) + { + geErrorLog_AddString(-1, "Failed to prepare the sprite for rendering", NULL); + return GE_FALSE; + } + + World->SpriteCount++; + geSprite_CreateRef(Sprite); + +#ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + + sprintf(str, "World_AddSprite : %08X\n", Sprite); + OutputDebugString(str); + } +#endif + + return GE_TRUE; +} + + +//======================================================================================== +//======================================================================================== +GENESISAPI geBoolean geWorld_RemoveSprite(geWorld *World, geSprite *Sprite) +{ + int i, Count; + + assert( World ); + assert( geSprite_IsValid(Sprite) ); + assert( World->SpriteCount >= 0 ); + + Count = World->SpriteCount; + +#ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + + sprintf(str,"World_RemoveSprite : %08X\n",Sprite); + OutputDebugString(str); + } +#endif + + for (i=0; i < Count; i++) + { + if (World->SpriteArray[i].Sprite == Sprite) + { + geSprite_Destroy( &Sprite ); + + World->SpriteArray[i] = World->SpriteArray[Count-1]; + + World->SpriteArray[Count-1].Sprite = NULL; + World->SpriteArray[Count-1].Flags = 0; + + World->SpriteCount--; + + return GE_TRUE; + } + } + + geErrorLog_AddString(-1,"Failed to find actor in actor list", NULL); + + return GE_FALSE; +} + +//======================================================================================== +//======================================================================================== +GENESISAPI geBoolean geWorld_SetSpriteFlags(geWorld *World, geSprite *Sprite, uint32 Flags) +{ + int i, Count; + + assert( World ); + assert( geSprite_IsValid(Sprite) ); + + Count = World->SpriteCount; + + for (i = 0; i < Count; i++) + { + if (World->SpriteArray[i].Sprite == Sprite) + { + World->SpriteArray[i].Flags = Flags; + return GE_TRUE; + } + } + + geErrorLog_AddString(-1,"Failed to find actor in actor list", NULL); + + return GE_FALSE; +} +//MRB END + +//======================================================================================== +// geWorld_GetLeaf +//======================================================================================== +GENESISAPI geBoolean geWorld_GetLeaf(const geWorld *World, const geVec3d *Pos, int32 *Leaf) +{ + assert(World); + assert(Leaf); + + // Return the leaf that is model 0 (the main world model) + *Leaf = Plane_FindLeaf(World, World->CurrentBSP->BSPData.GFXModels[0].RootNode[0], Pos); + + return GE_TRUE; +} + +//======================================================================================== +// geWorld_MightSeeLeaf +//======================================================================================== +GENESISAPI geBoolean geWorld_MightSeeLeaf(const geWorld *World, int32 Leaf) +{ + assert(World); + + assert(Leaf >= 0 && Leaf < World->CurrentBSP->BSPData.NumGFXLeafs); + + if (World->CurrentBSP->LeafData[Leaf].VisFrame == World->CurFrameStatic) + return GE_TRUE; + + return GE_FALSE; +} + +//======================================================================================== +// geWorld_LeafMightSeeLeaf +//======================================================================================== +GENESISAPI geBoolean geWorld_LeafMightSeeLeaf(const geWorld *World, int32 Leaf1, int32 Leaf2, uint32 VisFlags) +{ + GBSP_BSPData *BSPData; + int32 Cluster1, Cluster2, VisOfs; + uint8 *VisData; + + assert(World); + assert(World->CurrentBSP); + assert(VisFlags == 0); // VisFlags are not used, and must be set to 0 for future use... + + BSPData = &World->CurrentBSP->BSPData; + + assert(Leaf1 >= 0 && Leaf1 < BSPData->NumGFXLeafs); + assert(Leaf2 >= 0 && Leaf2 < BSPData->NumGFXLeafs); + + // Get the clusters that the leafs are in... + Cluster1 = BSPData->GFXLeafs[Leaf1].Cluster; + Cluster2 = BSPData->GFXLeafs[Leaf2].Cluster; + + if (Cluster1 == -1 || Cluster2 == -1) + return GE_FALSE; // If either on is in solid space, thern assume they can't see each other... + + assert(Cluster1 >= 0 && Cluster1 < BSPData->NumGFXClusters); + assert(Cluster2 >= 0 && Cluster2 < BSPData->NumGFXClusters); + + VisOfs = BSPData->GFXClusters[Cluster1].VisOfs; + + // If no vis data for cluster 1, then assume no vis data in entire map, and just return TRUE... + // This lets them run the map with no vis info, they will just suffer... + if (VisOfs == -1) + return GE_TRUE; + + assert(VisOfs >=0 && VisOfs < BSPData->NumGFXVisData); + + VisData = &BSPData->GFXVisData[VisOfs]; + + // See if Cluster2's bit is set in Cluster1's vis data set + if (VisData[Cluster2>>3] & (1<<(Cluster2&7)) ) + { + int32 Area1, Area2; + + Area1 = BSPData->GFXLeafs[Leaf1].Area; + Area2 = BSPData->GFXLeafs[Leaf2].Area; + + assert(Area1 > 0 && Area2 > 0); + + if (World->CurrentBSP->AreaConnections[Area1][Area2]) + return GE_TRUE; // They can see each other... + } + + return GE_FALSE; // They cannot see each other... +} + +//======================================================================================== +// geWorld_GetSetByClass +//======================================================================================== +GENESISAPI geEntity_EntitySet *geWorld_GetEntitySet(geWorld *World, const char *ClassName) +{ + geWorld_EntClassSet *WSets; + int32 i; + + assert(World); + + // No classname, just return the main set of all entities + if (!ClassName) + { + assert(World->EntClassSets[0].Set); + + return World->EntClassSets[0].Set; + } + + WSets = World->EntClassSets; + + for (i=1; i< World->NumEntClassSets; i++) + { + assert(WSets[i].Set); + + if (!stricmp(WSets[i].ClassName, ClassName)) + return WSets[i].Set; + } + + return NULL; +} + +//==================================================================================== +// geWorld_GetNextModel +//==================================================================================== +GENESISAPI geWorld_Model *geWorld_GetNextModel(geWorld *World, geWorld_Model *Start) +{ + int32 MNum; + GBSP_BSPData *BSPData; + World_BSP *WorldBSP; + + assert(World != NULL); + + WorldBSP = World->CurrentBSP; + + assert(WorldBSP != NULL); + + BSPData = &WorldBSP->BSPData; + + if (Start) + { + MNum = (Start - WorldBSP->Models); + + assert(MNum >= 0); + assert(MNum < BSPData->NumGFXModels); + + MNum++; + } + else + MNum = 0; + + if (MNum >= BSPData->NumGFXModels) + return NULL; // No more models + + return &WorldBSP->Models[MNum]; +} + +//==================================================================================== +// *********** FOG stuff ************* +//==================================================================================== + +//==================================================================================== +// FogSetAttributesCB +// CB to be called whenever geFog_SetAttributes is called +//==================================================================================== +static geBoolean geFog_SetAttributesCB(geFog *Fog) +{ + geWorld_FogData *FogData; + geVec3d *Mins, *Maxs; + + //Fog->VolumeRadius = 1000.0f; // Test + + FogData = geFog_GetUserData(Fog); + + // Record the leaf the fog is in... + geWorld_GetLeaf(FogData->World, &Fog->Pos, &FogData->Leaf); + + // Set Mins/Maxs to fog radius + Mins = &FogData->Mins; + Maxs = &FogData->Maxs; + + Mins->X = -Fog->VolumeRadius; + Mins->Y = -Fog->VolumeRadius; + Mins->Z = -Fog->VolumeRadius; + + Maxs->X = Fog->VolumeRadius; + Maxs->Y = Fog->VolumeRadius; + Maxs->Z = Fog->VolumeRadius; + + return GE_TRUE; +} + +//==================================================================================== +// geWorld_AddFog +//==================================================================================== +GENESISAPI geFog *geWorld_AddFog(geWorld *World) +{ + geFog *Fog; + geWorld_FogData *FogData; + + assert(World); + + Fog = NULL; + FogData = NULL; + + Fog = geFog_Create(geFog_SetAttributesCB); // Create the fog + + if (!Fog) + goto ExitWithError; + + // Insert at begining of list + if (World->FogList) + World->FogList->Prev = Fog; + + Fog->Next = World->FogList; + World->FogList = Fog; + + // Set up fog user data for the engine to use ONLY + FogData = GE_RAM_ALLOCATE_STRUCT(geWorld_FogData); + + if (!FogData) + goto ExitWithError; + + FogData->World = World; // Remember what world created the fog + + geFog_SetUserData(Fog, FogData); + + return Fog; + + ExitWithError: + { + if (FogData) + geRam_Free(FogData); + + if (Fog) + geWorld_RemoveFog(World, Fog); + } + + return NULL; +} + +//==================================================================================== +// geWorld_RemoveFog +//==================================================================================== +GENESISAPI geBoolean geWorld_RemoveFog(geWorld *World, geFog *Fog) +{ + geWorld_FogData *FogData; + + assert(World); + assert(Fog); + + FogData = geFog_GetUserData(Fog); + + if (FogData) + geRam_Free(FogData); + + geFog_SetUserData(Fog, NULL); // Just in case + + if (Fog->Prev) + Fog->Prev->Next = Fog->Next; + + if (Fog->Next) + Fog->Next->Prev = Fog->Prev; + + if (Fog == World->FogList) + { + assert(Fog->Prev == NULL); + World->FogList = Fog->Next; + } + + geFog_Destroy(Fog); + + return GE_TRUE; +} + +typedef struct +{ + geVec3d Origin; + GE_RGBA Color; + geFloat Brightness; + geFloat Radius; + +} MapFogData; + +//==================================================================================== +// CreateStaticFogList +//==================================================================================== +static geBoolean CreateStaticFogList(geWorld *World) +{ + geEntity *Entity; + geEntity_EntitySet *EntitySet; + geFog *Fog; + + // ONly interested in "FogLight"'s + + if ( World->NumEntClassSets == 0 ) + return GE_TRUE; + + EntitySet = geWorld_GetEntitySet(World, "FogLight"); + + if (!EntitySet) + return GE_TRUE; + + Entity = NULL; + + while (1) + { + MapFogData *Fd; + + Entity = geEntity_EntitySetGetNextEntity(EntitySet, Entity); + + if (!Entity) + break; + + Fd = geEntity_GetUserData(Entity); + + // Must have user data set + if (!Fd) + goto ExitWithError; + + // Add the fog to the world + Fog = geWorld_AddFog(World); + + if (!Fog) + goto ExitWithError; + + if (!geFog_SetAttributes(Fog, &Fd->Origin, &Fd->Color, 1.0f, Fd->Brightness, Fd->Radius)) + goto ExitWithError; + + } + + return GE_TRUE; + + //=== ERROR + ExitWithError: + { + if (Fog) + geWorld_RemoveFog(World, Fog); + + return GE_FALSE; + } +} + +//================================================================================ +// ***** SkyBox stuff ****** +//================================================================================ + +#define SKYBOX_WIDTH 10000.0f +#define SKYBOX_HEIGHT 10000.0f +#define SKYBOX_DEPTH 10000.0f + +//======================================================================================== +// BuildSkyBox +//======================================================================================== +static geBoolean BuildSkyBox(World_SkyBox *SkyBox, const GFX_SkyData *SkyData) +{ + geVec3d *Verts; + int32 i; + geFloat TexWidth, TexHeight; + geVec3d Zero; + + // Copy data over so it is more convenient + SkyBox->Axis = SkyData->Axis; + SkyBox->Dpm = SkyData->Dpm; + SkyBox->DrawScale = SkyData->DrawScale; + + for (i=0; i<6; i++) + SkyBox->Textures[i] = SkyData->Textures[i]; + + geVec3d_Set(&Zero, 0.0f, 0.0f, 0.0f); + if (geVec3d_Compare(&SkyBox->Axis, &Zero, 0.05f)) + geVec3d_Set(&SkyBox->Axis, 1.0f, 0.0f, 0.0f); + + // Build top + Verts = SkyBox->Verts[0]; + + Verts[0].X = -(SKYBOX_WIDTH/2); + Verts[0].Y = (SKYBOX_HEIGHT/2); + Verts[0].Z = (SKYBOX_DEPTH/2); + + Verts[1].X = (SKYBOX_WIDTH/2); + Verts[1].Y = (SKYBOX_HEIGHT/2); + Verts[1].Z = (SKYBOX_DEPTH/2); + + Verts[2].X = (SKYBOX_WIDTH/2); + Verts[2].Y = (SKYBOX_HEIGHT/2); + Verts[2].Z = -(SKYBOX_DEPTH/2); + + Verts[3].X = -(SKYBOX_WIDTH/2); + Verts[3].Y = (SKYBOX_HEIGHT/2); + Verts[3].Z = -(SKYBOX_DEPTH/2); + + // Build Bottom + Verts = SkyBox->Verts[1]; + Verts[0].X = -(SKYBOX_WIDTH/2); + Verts[0].Y = -(SKYBOX_HEIGHT/2); + Verts[0].Z = -(SKYBOX_DEPTH/2); + + Verts[1].X = (SKYBOX_WIDTH/2); + Verts[1].Y = -(SKYBOX_HEIGHT/2); + Verts[1].Z = -(SKYBOX_DEPTH/2); + + Verts[2].X = (SKYBOX_WIDTH/2); + Verts[2].Y = -(SKYBOX_HEIGHT/2); + Verts[2].Z = (SKYBOX_DEPTH/2); + + Verts[3].X = -(SKYBOX_WIDTH/2); + Verts[3].Y = -(SKYBOX_HEIGHT/2); + Verts[3].Z = (SKYBOX_DEPTH/2); + + // Build Left + Verts = SkyBox->Verts[2]; + Verts[0].X = -(SKYBOX_WIDTH/2); + Verts[0].Y = (SKYBOX_HEIGHT/2); + Verts[0].Z = (SKYBOX_DEPTH/2); + + Verts[1].X = -(SKYBOX_WIDTH/2); + Verts[1].Y = (SKYBOX_HEIGHT/2); + Verts[1].Z = -(SKYBOX_DEPTH/2); + + Verts[2].X = -(SKYBOX_WIDTH/2); + Verts[2].Y = -(SKYBOX_HEIGHT/2); + Verts[2].Z = -(SKYBOX_DEPTH/2); + + Verts[3].X = -(SKYBOX_WIDTH/2); + Verts[3].Y = -(SKYBOX_HEIGHT/2); + Verts[3].Z = (SKYBOX_DEPTH/2); + + // Build Right + Verts = SkyBox->Verts[3]; + Verts[0].X = (SKYBOX_WIDTH/2); + Verts[0].Y = (SKYBOX_HEIGHT/2); + Verts[0].Z = -(SKYBOX_DEPTH/2); + + Verts[1].X = (SKYBOX_WIDTH/2); + Verts[1].Y = (SKYBOX_HEIGHT/2); + Verts[1].Z = (SKYBOX_DEPTH/2); + + Verts[2].X = (SKYBOX_WIDTH/2); + Verts[2].Y = -(SKYBOX_HEIGHT/2); + Verts[2].Z = (SKYBOX_DEPTH/2); + + Verts[3].X = (SKYBOX_WIDTH/2); + Verts[3].Y = -(SKYBOX_HEIGHT/2); + Verts[3].Z = -(SKYBOX_DEPTH/2); + + // Build Front + Verts = SkyBox->Verts[4]; + Verts[0].X = -(SKYBOX_WIDTH/2); + Verts[0].Y = (SKYBOX_HEIGHT/2); + Verts[0].Z = -(SKYBOX_DEPTH/2); + + Verts[1].X = (SKYBOX_WIDTH/2); + Verts[1].Y = (SKYBOX_HEIGHT/2); + Verts[1].Z = -(SKYBOX_DEPTH/2); + + Verts[2].X = (SKYBOX_WIDTH/2); + Verts[2].Y = -(SKYBOX_HEIGHT/2); + Verts[2].Z = -(SKYBOX_DEPTH/2); + + Verts[3].X = -(SKYBOX_WIDTH/2); + Verts[3].Y = -(SKYBOX_HEIGHT/2); + Verts[3].Z = -(SKYBOX_DEPTH/2); + + // Build back + Verts = SkyBox->Verts[5]; + Verts[0].X = (SKYBOX_WIDTH/2); + Verts[0].Y = (SKYBOX_HEIGHT/2); + Verts[0].Z = (SKYBOX_DEPTH/2); + + Verts[1].X = -(SKYBOX_WIDTH/2); + Verts[1].Y = (SKYBOX_HEIGHT/2); + Verts[1].Z = (SKYBOX_DEPTH/2); + + Verts[2].X = -(SKYBOX_WIDTH/2); + Verts[2].Y = -(SKYBOX_HEIGHT/2); + Verts[2].Z = (SKYBOX_DEPTH/2); + + Verts[3].X = (SKYBOX_WIDTH/2); + Verts[3].Y = -(SKYBOX_HEIGHT/2); + Verts[3].Z = (SKYBOX_DEPTH/2); + + TexWidth = SkyBox->DrawScale; + TexHeight = SkyBox->DrawScale; + + for (i=0; i<6; i++) + { + Surf_TexVert *TexVerts; + + TexVerts = SkyBox->TexVerts[i]; + + TexVerts[0].u = 0.0f; + TexVerts[0].v = 0.0f; + + TexVerts[1].u = TexWidth; + TexVerts[1].v = 0.0f; + + TexVerts[2].u = TexWidth; + TexVerts[2].v = TexHeight; + + TexVerts[3].u = 0.0f; + TexVerts[3].v = TexHeight; + } + + return GE_TRUE; +} + +//======================================================================================== +// RenderSkyThroughFrustum +//======================================================================================== +static void RenderSkyThroughFrustum(World_SkyBox *SkyBox, geWorld_SkyBoxTData *SkyTData, geCamera *Camera, Frustum_Info *Fi) +{ + int32 i, p; + DRV_TLVertex Clipped1[30]; + geVec3d *pDest1, *pDest2, Dest1[30], Dest2[30]; + Surf_TexVert *pTex1, *pTex2, Tex1[30], Tex2[30]; + int32 Length1, Length2; + geBitmap *pBitmap; + geVec3d CameraPos = {0.0f, 0.0f, 0.0f}; + int32 TexNum; + GFX_Plane *Planes; + uint32 SkyFlags; + int nFoo; + + assert(SkyTData->NumTransformed >= 0); // Now that we have a far clip plane, it is possible to have no sky... + + if (!SkyTData->NumTransformed) + return; + + SkyFlags = DRV_RENDER_FLUSH | DRV_RENDER_POLY_NO_FOG; // skybox fog + + if (SkyBox->DrawScale <= 1.0f) + SkyFlags |= DRV_RENDER_CLAMP_UV; + + Planes = Fi->Planes; + + for (i=0; i< SkyTData->NumTransformed; i++) + { + geRDriver_THandle *THandle; + + // Get a pointer to the bitmap (texture) + // NOTE - The sky box uses textures from the bsp file, but node that they were + // created with RegisterMiscTexture with the driver. The engine knew how to do this + // by looking at the texture flags when it uploaded them... + TexNum = SkyBox->Textures[SkyTData->OriginalFaces[i]]; + + if (TexNum < 0) + continue; + + pBitmap = geWBitmap_Pool_GetBitmapByIndex(CBSP->WBitmapPool, TexNum); + + assert(geWorld_HasBitmap(CWorld, pBitmap)); + + pDest1 = SkyTData->TransformedVerts[i]; + pDest2 = Dest2; + pTex1 = SkyTData->TransformedTexVerts[i]; + pTex2 = Tex2; + Length1 = SkyTData->NumTransformedVerts[i]; + + + // NumVerts is the number of clip planes from the sky poly... + +// eaa3 01/30/2001 EVIL HACK +// ..for some reason, it is possible to get your skybox culled even if you +// ..don't want it to be. Since I like my skybox to draw no matter what my +// ..far clip plane is, this little EVIL HACK makes sure the skybox doesn't +// ..fall prey to the far clip plane, if active. + + nFoo = Fi->NumPlanes; // EVIL HACK + + if(nFoo > 4) // EVIL HACK - 5 planes means far clip enabled + nFoo = Fi->NumPlanes-1; // EVIL HACK - leave my skybox alone! + + for (p=0; p< nFoo; p++) + { + if (!Frustum_ClipToPlaneUV(&Planes[p], pDest1, pDest2, pTex1, pTex2, Length1, &Length2)) + break; + + if (pDest1 == Dest2) + { + pDest1 = Dest1; + pDest2 = Dest2; + pTex1 = Tex1; + pTex2 = Tex2; + } + else + { + pDest1 = Dest2; + pDest2 = Dest1; + pTex1 = Tex2; + pTex2 = Tex1; + } + Length1 = Length2; + } + + if (p != nFoo) + continue; // eaa3 01/30/2001 more EVIL HACK work + + if (Length1 < 3) + continue; + + // Project them to screen space + Frustum_Project(pDest1, pTex1, Clipped1, Length1, Camera); + + for (p=0; pRenderWorldPoly(Clipped1, Length1, THandle, &TexInfo, NULL, SkyFlags); + } + #else + RDriver->RenderMiscTexturePoly(Clipped1, Length1, THandle, SkyFlags); + #endif + + } + +} + +//===================================================================================== +// SetupSkyBoxFaceForScene +//===================================================================================== +static void SetupSkyBoxFaceForScene(World_SkyBox *SkyBox, int32 Face, const geXForm3d *XForm, Frustum_Info *Fi, geWorld_SkyBoxTData *SkyTData) +{ + geVec3d Dest1[MAX_RENDERFACE_VERTS], Dest2[MAX_RENDERFACE_VERTS], *pDest1, *pDest2; + Surf_TexVert Tex1[MAX_RENDERFACE_VERTS], Tex2[MAX_RENDERFACE_VERTS]; + Surf_TexVert *pTex1, *pTex2; + int32 Length1, Length2; + int32 p; + GFX_Plane *pFPlane; + geFloat Width, Height; + int32 TexNum; + GFX_Texture *pTexture; + int nFoo; + + TexNum = CWorld->CurrentBSP->BSPData.GFXSkyData.Textures[Face]; + + if (TexNum < 0) // No texture on sky face + return; + + pDest1 = SkyBox->Verts[Face]; + pDest2 = Dest2; + pTex1 = SkyBox->TexVerts[Face]; + pTex2 = Tex2; + Length1 = 4; + + pFPlane = Fi->Planes; + +// eaa3 01/30/2001 EVIL HACK +// ..for some reason, it is possible to get your skybox culled even if you +// ..don't want it to be. Since I like my skybox to draw no matter what my +// ..far clip plane is, this little EVIL HACK makes sure the skybox doesn't +// ..fall prey to the far clip plane, if active. + + nFoo = Fi->NumPlanes; // EVIL HACK + + if(nFoo > 4) // EVIL HACK - 5 planes means far clip enabled + nFoo = Fi->NumPlanes-1; // EVIL HACK - leave my skybox alone! + + for (p=0; p< nFoo; p++, pFPlane++) + { + if (!Frustum_ClipToPlaneUV(pFPlane, pDest1, pDest2, pTex1, pTex2, Length1, &Length2)) + return; + + if (pDest1 == Dest2) + { + pDest1 = Dest1; + pDest2 = Dest2; + pTex1 = Tex1; + pTex2 = Tex2; + } + else + { + pDest1 = Dest2; + pDest2 = Dest1; + pTex1 = Tex2; + pTex2 = Tex1; + } + Length1 = Length2; + } + + if (Length1 < 3) + return; + + pDest2 = SkyTData->TransformedVerts[SkyTData->NumTransformed]; + pTex2 = SkyTData->TransformedTexVerts[SkyTData->NumTransformed]; + SkyTData->NumTransformedVerts[SkyTData->NumTransformed] = Length1; + SkyTData->OriginalFaces[SkyTData->NumTransformed] = Face; + + pTexture = &CWorld->CurrentBSP->BSPData.GFXTextures[TexNum]; + + Width = (geFloat)pTexture->Width; + Height = (geFloat)pTexture->Height; + + //geXForm3d_RotateArray(CXForm, pDest1, pDest2, Length1); + for (p=0; pu *= Width; + pTex2->v *= Height; + #endif + + pTex1++; + pTex2++; + } + + SkyTData->NumTransformed++; // Increase the number of sky polys transformed... +} + +//===================================================================================== +// SetupSkyForScene +// Sets up sky for rendering through sky portals +//===================================================================================== +static void SetupSkyForScene(World_SkyBox *SkyBox, geCamera *Camera, Frustum_Info *Fi, geWorld_SkyBoxTData *SkyTData) +{ + int32 i; + geXForm3d XForm, OldXForm, QXForm; + Frustum_Info WorldSpaceFrustum; + geQuaternion Quat; + + // Reset the number of skypolys transformed... + SkyTData->NumTransformed = 0; + + // Get the camera matrix + XForm = *geCamera_GetWorldSpaceXForm(Camera); + + // Save it, so we can restore is when we are done + OldXForm = XForm; + + // Rotate the camera's xform about the selected axis + // First, build a quat that will do this + geQuaternion_SetFromAxisAngle(&Quat, &SkyBox->Axis, -SkyBox->Angle); + + // Then convert the quat to a xform + geQuaternion_ToMatrix(&Quat, &QXForm); + + geXForm3d_Multiply(&QXForm, &XForm, &XForm); + + // Put the XForm back into the camera + geCamera_SetWorldSpaceXForm(Camera, &XForm); + + // Setup the View Frustum to look into the world + Frustum_RotateToWorldSpace(Fi, Camera, &WorldSpaceFrustum); + + // NOTE - SetupSkyBoxFaceForScene only rotates the box, and does not translate... + for (i=0; i<6; i++) + SetupSkyBoxFaceForScene(SkyBox, i, geCamera_GetCameraSpaceXForm(Camera), &WorldSpaceFrustum, SkyTData); + + // Restore the camera + geCamera_SetWorldSpaceXForm(Camera, &OldXForm); +} + +//================================================================================ +// *** BitmapList stuff *** +//================================================================================ + +//================================================================================ +// geWorld_BitmapListInit +// Initializes the world bitmaplist +//================================================================================ +geBoolean geWorld_BitmapListInit(geWorld *World) +{ + assert(World); + assert(World->AttachedBitmaps == NULL); + + if (World->AttachedBitmaps == NULL ) + { + World->AttachedBitmaps = BitmapList_Create(); + + if (!World->AttachedBitmaps ) + { + geErrorLog_AddString(-1, "geWorld_BitmapListInit: BitmapList_Create failed.", NULL); + return GE_FALSE; + } + } + + // Only add bitmaps if the list is not NULL (could be an empty world with no textures yet) + if (World->CurrentBSP->WBitmapPool) + { + int32 i, Count; + Count = geWBitmap_Pool_GetWBitmapCount(World->CurrentBSP->WBitmapPool); + + for (i=0; iCurrentBSP->WBitmapPool, i); + assert(pWBitmap); + + pBitmap = geWBitmap_GetBitmap(pWBitmap); + assert(pBitmap); + + Flags = geWBitmap_GetFlags(pWBitmap); + + if (!geBitmap_GetInfo(pBitmap, &Info, NULL)) + { + geErrorLog_AddString(-1, "geWorld_BitmapListInit: geBitmap_GetInfo failed.", NULL); + return GE_FALSE; + } + + if (!geWorld_AddBitmap(World, pBitmap)) + { + geErrorLog_AddString(-1, "geWorld_BitmapListInit: geWorld_AddBitmap failed.", NULL); + return GE_FALSE; + } + + World->Changed = GE_TRUE; + } + } + + return GE_TRUE; +} + +//================================================================================ +// geWorld_BitmapListShutdown +//================================================================================ +geBoolean geWorld_BitmapListShutdown(geWorld *World) +{ + assert(World); + + if (World->AttachedBitmaps ) + { + //BitmapList_DetachAll(World->AttachedBitmaps); + BitmapList_Destroy(World->AttachedBitmaps); + World->AttachedBitmaps = NULL; + } + + return GE_TRUE; +} + +//================================================================================ +// geWorld_AddBitmap +//================================================================================ +GENESISAPI geBoolean geWorld_AddBitmap(geWorld *World, geBitmap *Bitmap) +{ + assert(World); + assert(Bitmap); + assert(World->AttachedBitmaps); + + if (!World->AttachedBitmaps) + { + geErrorLog_AddString(-1, "geWorld_AddBitmap: AttachedBitmapList is NULL.", NULL); + return GE_FALSE; + } + + geBitmap_SetDriverFlags(Bitmap, RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP); + + // Add bitmap to the list of bitmaps attached to the engine + if ( BitmapList_Add(World->AttachedBitmaps, (void*)Bitmap) ) + { + World->Changed = GE_TRUE; + + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"World_AddBitmap : %08X : new\n",Bitmap); + OutputDebugString(str); + } + #endif + } + else + { + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"World_AddBitmap : %08X : old\n",Bitmap); + OutputDebugString(str); + } + #endif + } + + return GE_TRUE; +} + +//================================================================================ +// geWorld_RemoveBitmap +//================================================================================ +GENESISAPI geBoolean geWorld_RemoveBitmap(geWorld *World,geBitmap *Bitmap) +{ + + assert(World); + assert(Bitmap); + assert(World->AttachedBitmaps); + + if (!World->AttachedBitmaps) + return GE_FALSE; + + if ( BitmapList_Remove(World->AttachedBitmaps, Bitmap) ) + { + World->Changed = GE_TRUE; + + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"World_RemoveBitmap : %08X : removed\n",Bitmap); + OutputDebugString(str); + } + #endif + } + else + { + #ifdef DO_ADDREMOVE_MESSAGES + { + char str[100]; + sprintf(str,"World_RemoveBitmap : %08X : left\n",Bitmap); + OutputDebugString(str); + } + #endif + } + + + return GE_TRUE; +} + +//================================================================================ +// geWorld_GetBitmapByName +//================================================================================ +GENESISAPI geBitmap *geWorld_GetBitmapByName(geWorld *World, const char *BitmapName) +{ + if (!World->CurrentBSP) + return NULL; + + assert(World->CurrentBSP->WBitmapPool); + + return geWBitmap_Pool_GetBitmapByName(World->CurrentBSP->WBitmapPool, BitmapName); +} + +//================================================================================ +// geWorld_AttachAll +//================================================================================ +geBoolean geWorld_AttachAll(geWorld *World, DRV_Driver *Driver, geFloat Gamma) +{ + assert(World); + assert(World->AttachedBitmaps); + assert(Driver); + + if (!BitmapList_AttachAll(World->AttachedBitmaps, Driver, Gamma)) + { + geErrorLog_AddString(-1, "geWorld_AttachAll: BitmapList_AttachAll failed.", NULL); + return GE_FALSE; + } + + return GE_TRUE; +} + +//================================================================================ +// geWorld_DetachAll +//================================================================================ +geBoolean geWorld_DetachAll(geWorld *World) +{ + assert(World); + assert(World->AttachedBitmaps); + + if (!BitmapList_DetachAll(World->AttachedBitmaps)) + { + geErrorLog_AddString(-1, "geWorld_DetachAll: BitmapList_DetachAll failed.", NULL); + return GE_FALSE; + } + return GE_TRUE; +} + +//================================================================================ +// geWorld_HasBitmap +//================================================================================ +GENESISAPI geBoolean geWorld_HasBitmap(const geWorld *World, const geBitmap *Bitmap) +{ + assert(World); + assert(World->AttachedBitmaps); + + return BitmapList_Has((BitmapList*)World->AttachedBitmaps, (geBitmap*)Bitmap); +} +//================================================================================ +//================================================================================ +GENESISAPI geBoolean geWorld_BitmapIsVisible(geWorld *World, const geBitmap *Bitmap) +{ + geWBitmap *pWBitmap; + + pWBitmap = geWBitmap_Pool_GetWBitmapByBitmap(World->CurrentBSP->WBitmapPool, Bitmap); + + if (!pWBitmap) // Not in the list! Should this be an error????? + return GE_FALSE; + + if (geWBitmap_GetVisFrame(pWBitmap) == World->CurFrameDynamic) + return GE_TRUE; + + return GE_FALSE; +} + + diff --git a/G3D/World/World.h b/G3D/World/World.h new file mode 100644 index 0000000..f62c7f2 --- /dev/null +++ b/G3D/World/World.h @@ -0,0 +1,315 @@ +/****************************************************************************************/ +/* World.h */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render the world, and distribute work to other modules */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_WORLD_H +#define GE_WORLD_H + +#include "ErrorLog.h" +#include "PtrTypes.h" +#include "Genesis.h" +#include "GBSPFile.h" +#include "Motion.h" +#include "Surface.h" +#include "Fog.h" +#include "WBitmap.h" +#include "User.h" +#include "Light.h" + +#include "Bitmaplist.h" + +#include "Actor.h" + +//MRB BEGIN +//geSprite +#include "Sprite.h" +//MRB END + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MAX_MODELS 256 + +// Upper limits on misc things +#define MAX_MIRROR_RECURSION 1 +#define MAX_RENDERFACE_VERTS 64 + +//===================================================================================== +// Structure defines +//===================================================================================== +#define MODEL_CHANGED_XFORM (1<<0) + +typedef struct geWorld_Model +{ + char Name[64]; // Model's name + int32 GFXModelNum; // Model number in disk tree structure + geXForm3d XForm; // Models transform (Object Space) + geVec3d Mins, Maxs; // Model BBox (World Space) + geVec3d TMins, TMaxs; // Translated Model BBox (World Space) + geVec3d Pivot; // Center of rotation (World Space) + geVec3d RealCenter; + int32 VisFrame; // == World->CurFrame if visible + void *UserData; // Place for client to store data + GFX_Model * BSPModel; // Oh, this is terrible. + + geBoolean Open; // Model Open/Closed (Set by API, used for area vising) + + uint32 Flags; // GE_MODEL_RENDER_NORMAL, etc... (getypes.h) + + uint32 ChangedFlags; +} geWorld_Model; + +typedef struct geWorld_Leaf +{ + int32 VisFrame; + int32 Parent; // Parent nodes of all leafs + + gePoly *PolyList; // List of poly fragments to render for this leaf (geWorld_AddPoly) +} geWorld_Leaf; + +#define MAX_VISIBLE_FOG 12 // Hope to God there is not this much visible at a time!!! + +// This is set in the UserData of the fog the the world creates at load time +typedef struct +{ + int32 Leaf; + + geVec3d Mins; // - Radius + geVec3d Maxs; // + Radius + + int32 VisFrame; // == World->CurFrameDynamic when visible + + geWorld *World; +} geWorld_FogData; + +typedef struct World_BSP +{ + char FileName[200]; + GBSP_BSPData BSPData; // Info in the BSP loaded directly off disk + + // Extra info thats not in the disk bsp structure + Surf_SurfInfo *SurfInfo; // Valid when GE_SetGBSPFile is called + Surf_TexVert *TexVerts; // + + geWBitmap_Pool *WBitmapPool; + + geWorld_Model Models[MAX_MODELS]; // Extra info about models not in disk structure + + geWorld_Leaf *LeafData; + + int32 *ClusterVisFrame; + int32 *NodeVisFrame; + int32 *AreaVisFrame; + uint8 AreaConnections[256][256]; + + int32 *NodeParents; // Parent nodes of all leafs + +} World_BSP; + +typedef struct +{ + // Untransformed original data + geVec3d Verts[6][4]; + Surf_TexVert TexVerts[6][4]; + + geVec3d Axis; // Rotation axis + geFloat Dpm; // Degres per minute + geFloat DrawScale; // Texture drawscale + int32 Textures[6]; + + geFloat Angle; // Current rotation angle around roation axis + +} World_SkyBox; + +typedef struct +{ + // Transformed data + uint32 SkyFlags; + + geVec3d TransformedVecs[6][2]; + GFX_Plane TransformedPlanes[6]; + + int32 NumTransformed; // Num transformed and clipped + geVec3d TransformedVerts[6][10]; // Transformed verts + Surf_TexVert TransformedTexVerts[6][10]; // Transformed tex verts + int32 NumTransformedVerts[6]; // Number of transformed verts/texverts + int32 OriginalFaces[6]; // Indexes to original bitmap + +} geWorld_SkyBoxTData; + +typedef struct World_Actor +{ + geActor *Actor; + uint32 Flags; // GE_ACTOR_RENDER_NORMAL, GE_ACTOR_RENDER_MIRRORS, GE_ACTOR_COLLIDE + uint32 UserFlags; + + //int32 Leaf; // Current leaf the actor is in (currently used for PVS occlusion) +} World_Actor; + +//MRB BEGIN +//geSprite +typedef struct World_Sprite +{ + geSprite *Sprite; + uint32 Flags; // GE_SPRITE_RENDER_NORMAL, GE_SPRITE_RENDER_MIRRORS, GE_SPRITE_COLLIDE + uint32 UserFlags; + + //int32 Leaf; // Current leaf the sprite is in (currently used for PVS occlusion) +} World_Sprite; +//MRB END + +/****** + +Critial : A negative-numbered Node is a Leaf. + Node (-1) is Leaf 0 ; (the first leaf is Leaf 0). + Node (-N) is Leaf (N-1) = (-Node-1) + +******/ + +#define MAX_WORLD_ENT_CLASS_SETS 256 + +typedef struct +{ + const char *ClassName; // NULL for main set + geEntity_EntitySet *Set; +} geWorld_EntClassSet; + +typedef struct +{ + int32 NumNodesTraversed1; + int32 NumNodesTraversed2; + int32 NumLeafsHit1; + int32 NumLeafsHit2; + int32 NumLeafsWithUserPolys; + int32 NumUserPolys; + +} geWorld_DebugInfo; + +typedef struct geWorld +{ + int32 CurFrameStatic; // World CurrentFrame + int32 CurFrameDynamic; // World CurrentFrame + geFloat CurTime; // World CurrentTime + int32 CurrentLeaf; + geBoolean ForceVis; + + geBoolean VisInfo; + + // Info that each respective module fills in... + World_BSP *CurrentBSP; // Valid when geWorld_SetGBSP is called + + World_SkyBox SkyBox; + + Frustum_Info *FrustumInfo; + + Light_LightInfo *LightInfo; // Info that the light module fills in + + Mesh_MeshInfo *MeshInfo; // Info that the mesh module fills in + + int32 ActorCount; // Number of actors in world + World_Actor *ActorArray; // Array of actors + +//MRB BEGIN +//geSprite + int32 SpriteCount; // Number of sprites in world + World_Sprite *SpriteArray; // Array of sprites +//MRB END + + geWorld_EntClassSet EntClassSets[MAX_WORLD_ENT_CLASS_SETS]; + int32 NumEntClassSets; + + User_Info *UserInfo; + + // Debug info + int32 ActiveUserPolys; + geWorld_DebugInfo DebugInfo; + + geFog *FogList; // Linked list of fog in the world currently + + geFog *VisibleFog[MAX_VISIBLE_FOG]; // List of visible fog for this frame + int32 NumVisibleFog; + + BitmapList *AttachedBitmaps; + + geXForm3d LastCameraXForm; + + int32 RefCount; + + geBoolean Changed; // GE_TRUE if this world has changed + +} geWorld; + +//===================================================================================== +// Function prototypes +//===================================================================================== +GENESISAPI geWorld *geWorld_Create(geVFile *File); +GENESISAPI void geWorld_Free(geWorld *World); +geBoolean geWorld_CreateRef(geWorld *World); + +geBoolean World_EngineInit(geEngine *Engine); +void World_EngineShutdown(geEngine *Engine); + +geBoolean World_SetEngine(geEngine *Engine); +geBoolean World_SetWorld(geWorld *World); +geBoolean World_SetGBSP(World_BSP *BSP); + +geBoolean World_WorldRenderQ(geEngine *Engine, geWorld *World, geCamera *Camera); + +GENESISAPI geBoolean geWorld_SetModelXForm( + geWorld * World, + geWorld_Model * Model, + const geXForm3d * XForm); +GENESISAPI geBoolean geWorld_GetModelXForm( + const geWorld * World, + const geWorld_Model * Model, + geXForm3d * XForm); + +GENESISAPI geBoolean geWorld_GetModelRotationalCenter( + const geWorld * World, + const geWorld_Model * Model, + geVec3d * Center); + +GENESISAPI geMotion * geWorld_ModelGetMotion(geWorld_Model *Model); + +GENESISAPI void * geWorld_ModelGetUserData(const geWorld_Model *Model); + +GENESISAPI void geWorld_ModelSetUserData(geWorld_Model *Model, void *UserData); + +// eaa3 07/28/2000 + +GENESISAPI void geWorld_ModelGetCenter(geWorld_Model *Model, geVec3d *Center); + +GENESISAPI geWorld_Model *geWorld_WorldGetNextModel(geWorld *World, geWorld_Model *Start); + +GENESISAPI geBoolean geWorld_AddBitmap(geWorld *World, geBitmap *Bitmap); +GENESISAPI geBoolean geWorld_RemoveBitmap(geWorld *World,geBitmap *Bitmap); + +GENESISAPI geBitmap *geWorld_GetBitmapByName(geWorld *World, const char *BitmapName); + +geBoolean geWorld_AttachAll(geWorld *World, DRV_Driver *Driver, geFloat Gamma); +geBoolean geWorld_DetachAll(geWorld *World); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/G3D/drawbbox.c b/G3D/drawbbox.c new file mode 100644 index 0000000..adf89b0 --- /dev/null +++ b/G3D/drawbbox.c @@ -0,0 +1,67 @@ +/* + This file is provided as a debugging aid. It contains code for drawing an axial + aligned bounding box. You can use this code as you see fit. +*/ + +static void DrawFace(geWorld *World, const geVec3d **Verts) +{ + GE_LVertex LVerts[4]; + int i; + + for (i = 0; i < 4; i++) + { + LVerts[i].r = 40.0f; + LVerts[i].g = 40.0f; + LVerts[i].b = 80.0f + 20.0f * (geFloat)i; + LVerts[i].a = 128.0f; + LVerts[i].X = Verts[i]->X; + LVerts[i].Y = Verts[i]->Y; + LVerts[i].Z = Verts[i]->Z; + } + + geWorld_AddPolyOnce(World, &LVerts[0], 4, NULL, GE_GOURAUD_POLY, GE_FX_TRANSPARENT, 1.0f); +} + +void DrawBoundBox(geWorld *World, const geVec3d *Pos, const geVec3d *Min, const geVec3d *Max) +{ + geFloat dx; + geFloat dy; + geFloat dz; +static geVec3d Verts[8]; +static geVec3d * Faces[6][4] = +{ + { &Verts[0], &Verts[1], &Verts[2], &Verts[3] }, //Top + { &Verts[4], &Verts[5], &Verts[6], &Verts[7] }, //Bottom + { &Verts[3], &Verts[2], &Verts[6], &Verts[7] }, //Side + { &Verts[1], &Verts[0], &Verts[4], &Verts[5] }, //Side + { &Verts[0], &Verts[3], &Verts[7], &Verts[4] }, //Front + { &Verts[2], &Verts[1], &Verts[5], &Verts[6] }, //Back +}; + int i; + + for (i = 0; i < 8; i++) + geVec3d_Add(Pos, Min, &Verts[i]); + + dx = Max->X - Min->X; + dy = Max->Y - Min->Y; + dz = Max->Z - Min->Z; + + Verts[0].Y += dy; + Verts[3].Y += dy; + Verts[3].X += dx; + Verts[7].X += dx; + + Verts[1].Y += dy; + Verts[1].Z += dz; + Verts[5].Z += dz; + Verts[6].Z += dz; + Verts[6].X += dx; + + Verts[2].X += dx; + Verts[2].Y += dy; + Verts[2].Z += dz; + + for (i = 0; i < 6; i++) + DrawFace(World, &Faces[i][0]); +} + diff --git a/G3D/genesis.rc b/G3D/genesis.rc new file mode 100644 index 0000000..1163287 --- /dev/null +++ b/G3D/genesis.rc @@ -0,0 +1,109 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,13,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "WildTangent\0" + VALUE "FileDescription", "Genesis\0" + VALUE "FileVersion", "1, 0, 13, 0\0" + VALUE "InternalName", "Genesis\0" + VALUE "LegalCopyright", "Copyright © 1999\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "Genesis.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Genesis3D\0" + VALUE "ProductVersion", "1, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/G3D/getypes.h b/G3D/getypes.h new file mode 100644 index 0000000..b652832 --- /dev/null +++ b/G3D/getypes.h @@ -0,0 +1,140 @@ +/****************************************************************************************/ +/* GeTypes.h */ +/* */ +/* Description: Genesis Types (not primitive enough for basetype) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GE_TYPES_H +#define GE_TYPES_H + +#include "BaseType.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Collision defines (for geWorld_Collision) +// +#define GE_COLLIDE_MESHES (1<<0) +#define GE_COLLIDE_MODELS (1<<1) +#define GE_COLLIDE_ACTORS (1<<2) +#define GE_COLLIDE_NO_SUB_MODELS (1<<3) +#define GE_COLLIDE_ALL (GE_COLLIDE_MESHES | GE_COLLIDE_MODELS | GE_COLLIDE_ACTORS) + +// +// Actor flags (geWorld_AddActor) +// +#define GE_ACTOR_RENDER_NORMAL (1<<0) // Render in normal views +#define GE_ACTOR_RENDER_MIRRORS (1<<1) // Render in mirror views +#define GE_ACTOR_RENDER_ALWAYS (1<<2) // Render always, skipping all visibility tests +#define GE_ACTOR_COLLIDE (1<<3) // Collide when calling geWorld_Collision + +//MRB BEGIN +//geSprite +// +// Sprite flags (geSprite_AddSprite) +// +#define GE_SPRITE_RENDER_NORMAL (1<<0) // Render in normal views +#define GE_SPRITE_RENDER_MIRRORS (1<<1) // Render in mirror views +#define GE_SPRITE_RENDER_ALWAYS (1<<2) // Render always, skipping all visibility tests +#define GE_SPRITE_COLLIDE (1<<3) // Collide when calling geWorld_Collision +//MRB END + +typedef struct +{ + geBoolean UseEnvironmentMapping; //toggle for actor-level environ-map + geBoolean Supercede; //toggle for material-level + geFloat PercentEnvironment; + geFloat PercentMaterial; //Used when Supercede == GE_FALSE + geFloat PercentPuppet; +} geEnvironmentOptions; + +// +// Model flags (geWorld_ModelSetFlags) +// +#define GE_MODEL_RENDER_NORMAL (1<<0) // Render in normal views +#define GE_MODEL_RENDER_MIRRORS (1<<1) // Render in mirror views +#define GE_MODEL_RENDER_ALWAYS (1<<2) // Render always, skipping all visibility tests +#define GE_MODEL_COLLIDE (1<<3) // Collide when calling geWorld_Collision + +//MRB BEGIN +typedef struct +{ + geFloat r, g, b; +} geColor; + +typedef struct +{ + geFloat u, v; +} geUV; +//MRB END + +typedef struct +{ + geFloat r, g, b, a; +} GE_RGBA; + +typedef struct +{ + int32 Left; + int32 Right; + int32 Top; + int32 Bottom; +} GE_Rect; + +typedef struct +{ + geFloat MinX,MaxX; + geFloat MinY,MaxY; +} geFloatRect; + +//MRB BEGIN +typedef struct +{ + geFloat X; + geFloat Y; +} geCoordinate; +//MRB END + +// Lit vertex +typedef struct +{ + // FIXME: Convert 3d X,Y,Z to geVec3d + geFloat X, Y, Z; // 3d vertex + geFloat u, v; // Uv's + // FIXME: Convert r,g,b,a to GE_RGBA + geFloat r, g, b, a; // color +} GE_LVertex; + +// Transformed Lit vertex +typedef struct +{ + geFloat x, y, z; // screen points + geFloat u, v; // Uv's + geFloat r, g, b, a; // color +} GE_TLVertex; + +typedef GE_Rect geRect; + +#ifdef __cplusplus +} +#endif + + +#endif GETYPES_H diff --git a/G3D/list.c b/G3D/list.c new file mode 100644 index 0000000..0f0859d --- /dev/null +++ b/G3D/list.c @@ -0,0 +1,1415 @@ +/****************************************************************************************/ +/* List */ +/* */ +/* Author: Charles Bloom */ +/* Description: List/Link/Node Primitives */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +//#define SAFE_HASH_DEBUG + +/***** + +List_Ram can still be as high as 30% of the time! + +*******/ + +// #define DO_TIMER + +#include +#include +#include +#include "list.h" +#include "mempool.h" +#include "ram.h" +#include "crc32.h" + +/**********************************/ +// Timer Stuff + +#ifdef DO_TIMER +#include "timer.h" + +TIMER_VARS(List_Ram); +TIMER_VARS(List_RadixWalk); +TIMER_VARS(List_RadixInit); + +#else + +#define TIMER_P(x) +#define TIMER_Q(X) + +#endif // DO_TIMER + +#ifdef _DEBUG +#define Debug(func) func; +#define DebugAlert() do { __asm { int 03h } } while(0) +#else +#define Debug(func) +#define DebugAlert() +#endif + +#define MemAlloc(size) geRam_AllocateClear(size) +#define MemFree(mem) geRam_Free(mem) + +#ifdef DO_TIMER // { +#undef new +#define new(type) mymalloc(sizeof(type)) +#undef destroy +#define destroy(mem) if ( mem ) myfree(mem) + +void * mymalloc(int size) +{ +void *ret; +TIMER_P(List_Ram); +ret = MemAlloc(size); +TIMER_Q(List_Ram); +return ret; +} +void myfree(void *mem) +{ +TIMER_P(List_Ram); +MemFree(mem); +TIMER_Q(List_Ram); +} + +#undef MemAlloc +#define MemAlloc mymalloc +#undef MemFree +#define MemFree myfree + +#else // }{ DO_TIMER + +#undef new +#define new(type) MemAlloc(sizeof(type)) +#undef destroy +#define destroy(mem) if ( mem ) MemFree(mem) + +#endif // } DO_TIMER + +/**********************************/ + +static MemPool *ListPool_g = NULL, *LinkPool_g = NULL, *HashNodePool_g = NULL; +static int UsageCount = 0; + +/**********************************/ + +int LN_ListLen(LinkNode *pList) +{ +LinkNode *pNode; +int Len=0; + if ( ! pList ) + return 0; + LN_Walk(pNode,pList) { + Len++; + } +return Len; +} + +LinkNode * LISTCALL LN_CutHead(LinkNode *pList) +{ +LinkNode * LN; + assert(pList); + LN = pList->Next; + if ( LN == pList ) return NULL; + LN_Cut(LN); +return LN; +} + +LinkNode * LISTCALL LN_CutTail(LinkNode *pList) +{ +LinkNode * LN; + assert(pList); + LN = pList->Prev; + if ( LN == pList ) return NULL; + LN_Cut(LN); +return LN; +} + +/**********************************/ + +struct List +{ + List *Next,*Prev; + void * Data; +}; + +void LISTCALL List_Destroy(List * pList) +{ +List * pNode; + assert(pList); + pNode = pList->Next; + while( pNode != pList ) + { + List *Next; + Next = pNode->Next; + MemPool_FreeHunk(ListPool_g,pNode); + pNode = Next; + } + MemPool_FreeHunk(ListPool_g,pList); +} + +List * LISTCALL List_Create(void) +{ +List * pNew; + + pNew = MemPool_GetHunk(ListPool_g); + assert(pNew); + pNew->Data = NULL; + pNew->Next = pNew->Prev = pNew; +return pNew; +} + +List * LISTCALL List_AddTail(List *pList,void * Data) +{ +List * pNew; + + pNew = MemPool_GetHunk(ListPool_g); + assert(pNew); + + pNew->Next = pList; + pNew->Prev = pList->Prev; + pNew->Next->Prev = pNew; + pNew->Prev->Next = pNew; + + pNew->Data= Data; +return pNew; +} + +List * LISTCALL List_AddHead(List *pList,void * Data) +{ +List * pNew; + + pNew = MemPool_GetHunk(ListPool_g); + assert(pNew); + pNew->Data= Data; + + pNew->Prev = pList; + pNew->Next = pList->Next; + pNew->Next->Prev = pNew; + pNew->Prev->Next = pNew; +return pNew; +} + +void * LISTCALL List_CutHead(List *pList) +{ +List * pNode; +void * pData; + pNode = pList->Next; + if ( pNode == pList ) return NULL; + pData = pNode->Data; + + pList->Next = pNode->Next; + pList->Next->Prev = pList; + + MemPool_FreeHunk(ListPool_g,pNode); + +return pData; +} + +void * LISTCALL List_CutTail(List *pList) +{ +List * pNode; +void * pData; + pNode = pList->Prev; + if ( pNode == pList ) return NULL; + pData = pNode->Data; + + pList->Prev = pNode->Prev; + pList->Prev->Next = pList; + + MemPool_FreeHunk(ListPool_g,pNode); + +return pData; +} + + +void * LISTCALL List_PeekHead(List *pList) +{ +List * pNode; + pNode = pList->Next; + if ( pNode == pList ) return NULL; +return pNode->Data; +} + +void * LISTCALL List_PeekTail(List *pList) +{ +List * pNode; + pNode = pList->Prev; + if ( pNode == pList ) return NULL; +return pNode->Data; +} + +void LISTCALL List_CutNode(List *pNode) +{ + pNode->Prev->Next = pNode->Next; + pNode->Next->Prev = pNode->Prev; + + pNode->Next = pNode->Prev = pNode; +} + +void LISTCALL List_DeleteNode(List *pNode) +{ + List_CutNode(pNode); + List_FreeNode(pNode); +} + +void LISTCALL List_FreeNode(List *pNode) +{ + assert(pNode); + MemPool_FreeHunk(ListPool_g,pNode); +} + +void * LISTCALL List_NodeData(List *pNode) +{ + assert(pNode); + return pNode->Data; +} + +List * LISTCALL List_Next(List *pNode) +{ + return pNode->Next; +} +List * LISTCALL List_Prev(List *pNode) +{ + return pNode->Prev; +} + +List * List_Find(List *pList,void *Data) +{ +List *pNode; + assert(pList); + for(pNode = pList->Next; pNode != pList; pNode = pNode->Next ) + { + if ( pNode->Data == Data ) + return pNode; + } + return NULL; +} + +/***********************************************************/ +// Stack by linked list + +struct Link +{ + Link * Next; + void * Data; +}; + +void LISTCALL Link_Destroy(Link * pLink) +{ + while( pLink ) + { + Link *Next; + Next = pLink->Next; + MemPool_FreeHunk(LinkPool_g,pLink); + pLink = Next; + } +} + +Link * LISTCALL Link_Create(void) +{ +Link * pLink; + pLink = MemPool_GetHunk(LinkPool_g); + assert(pLink); + pLink->Next = NULL; + pLink->Data = NULL; +return pLink; +} + +void LISTCALL Link_Push(Link *pLink,void * Data) +{ +Link * pNode; + assert(pLink); + pNode = MemPool_GetHunk(LinkPool_g); + assert(pNode); +// DebugWarn(geRam_IsValidPtr(pLink)); +// DebugWarn(geRam_IsValidPtr(pNode)); + pNode->Data = Data; + + pNode->Next = pLink->Next; + pLink->Next = pNode; +} + +void * LISTCALL Link_Pop(Link *pLink) +{ +void *pData; +Link * pNode; + if ( ! pLink ) return NULL; +// DebugWarn(geRam_IsValidPtr(pLink)); + pNode = pLink->Next; + if ( ! pNode ) return NULL; +// DebugWarn(geRam_IsValidPtr(pNode)); + pData = pNode->Data; + pLink->Next = pNode->Next; + MemPool_FreeHunk(LinkPool_g,pNode); +return pData; +} + +void * LISTCALL Link_Peek(Link *pLink) +{ +void *pData; +Link * pNode; + if ( ! pLink ) return NULL; +// DebugWarn(geRam_IsValidPtr(pLink)); + pNode = pLink->Next; + if ( ! pNode ) return NULL; +// DebugWarn(geRam_IsValidPtr(pNode)); + pData = pNode->Data; +return pData; +} + +/*************************************************************/ + +#ifdef _DEBUG // else it's in list.h +struct Stack +{ + void ** Buffer, **End; + void ** Head; + int members; +}; +#endif + +void LISTCALL Stack_Destroy(Stack * pStack) +{ + if ( pStack ) + { + destroy(pStack->Buffer); + destroy(pStack); + } +} + +Stack * LISTCALL Stack_Create(void) +{ +Stack * pStack; + pStack = new(Stack); + assert(pStack); + pStack->members = 4096; + pStack->Buffer = MemAlloc(sizeof(void *)*(pStack->members)); + assert(pStack->Buffer); + pStack->End = pStack->Buffer + (pStack->members); + pStack->Head = pStack->Buffer; +return pStack; +} + +int LISTCALL Stack_Extend(Stack *pStack) +{ +void ** NewBuffer; +int newmembers; + // realloc + newmembers = pStack->members + 4096; + NewBuffer = MemAlloc(sizeof(void *)*newmembers); + assert(NewBuffer); + memcpy(NewBuffer,pStack->Buffer, sizeof(void *)*(pStack->members)); + pStack->Head = NewBuffer + pStack->members; + pStack->members = newmembers; + MemFree(pStack->Buffer); + pStack->Buffer = NewBuffer; + + pStack->End = pStack->Buffer + (pStack->members); +return newmembers; +} + +void LISTCALL Stack_Push_Func(Stack *pStack,void * Data) +{ + assert(pStack); + *(pStack->Head)++ = Data; + if ( pStack->Head == pStack->End ) + Stack_Extend(pStack); +} + +void * LISTCALL Stack_Pop_Func(Stack *pStack) +{ + assert(pStack); + if ( pStack->Head == pStack->Buffer ) + return NULL; + pStack->Head --; +return *(pStack->Head); +} + +/*************************************************************/ + +struct RadixList +{ + int NumLists; + int Min,Max; + List ** Lists; +}; + +RadixList * RadixList_Create(int RadixListMax) +{ +RadixList * pRadixList; +int r; + pRadixList = new(RadixList); + assert(pRadixList); + pRadixList->NumLists = RadixListMax+1; + pRadixList->Lists = MemAlloc(sizeof(List *)*(pRadixList->NumLists)); + assert(pRadixList->Lists); + for(r=0;r<(pRadixList->NumLists);r++) + { + pRadixList->Lists[r] = List_Create(); + assert(pRadixList->Lists[r]); + } + pRadixList->Min = pRadixList->NumLists; + pRadixList->Max = - 1; +return pRadixList; +} + +void RadixList_Destroy(RadixList * pRadixList) +{ +int r; + assert(pRadixList); + for(r=0;r<(pRadixList->NumLists);r++) + { + List_Destroy(pRadixList->Lists[r]); + } + MemFree(pRadixList->Lists); + MemFree(pRadixList); +} + +List * RadixList_Add(RadixList *pRadixList,void * Data,int Key) +{ +List * l; + assert(pRadixList); + assert( Key < pRadixList->NumLists && Key >= 0 ); + l = List_AddTail(pRadixList->Lists[Key],Data); + if ( Key < pRadixList->Min ) pRadixList->Min = Key; + if ( Key > pRadixList->Max ) pRadixList->Max = Key; +return l; +} + +void * RadixList_CutMax(RadixList *pRadixList,int *pKey) +{ + assert(pRadixList); + + while ( pRadixList->Max >= 0 ) + { + void * Data; + + if ( Data = List_CutHead(pRadixList->Lists[pRadixList->Max]) ) + { + if ( pKey ) *pKey = pRadixList->Max; + return Data; + } + pRadixList->Max --; + + } + +return NULL; +} + +void * RadixList_CutMin(RadixList *pRadixList,int *pKey) +{ + assert(pRadixList); + + while ( pRadixList->Min < pRadixList->NumLists ) + { + void * Data; + + if ( Data = List_CutHead(pRadixList->Lists[pRadixList->Min]) ) + { + if ( pKey ) *pKey = pRadixList->Min; + return Data; + } + pRadixList->Min ++; + + } + +return NULL; +} + +void * RadixList_CutKey(RadixList *pRadixList,int Key) +{ + assert(pRadixList); +return List_CutHead(pRadixList->Lists[Key]); +} + +/*************************************************/ + +struct RadixLN +{ + int NumLNs; + int Min,Max; + LinkNode * LNs; +}; + +RadixLN * RadixLN_Create(int RadixLNMax) +{ +RadixLN * pRadixLN; +LinkNode * LNs; +int r; + pRadixLN = new(RadixLN); + assert(pRadixLN); + pRadixLN->NumLNs = RadixLNMax+1; + pRadixLN->LNs = MemAlloc(sizeof(LinkNode)*(pRadixLN->NumLNs)); + assert(pRadixLN->LNs); + +TIMER_P(List_RadixInit); // not counting the allocs, tracking in List_Ram + + LNs = pRadixLN->LNs; + for(r=(pRadixLN->NumLNs);r--;LNs++) + { + // LN_InitList( LNs ); + LNs->Next = LNs->Prev = LNs; + } + pRadixLN->Min = RadixLNMax; + pRadixLN->Max = 0; + +TIMER_Q(List_RadixInit); + +return pRadixLN; +} + +void RadixLN_Destroy(RadixLN * pRadixLN) +{ + assert(pRadixLN); + MemFree(pRadixLN->LNs); + MemFree(pRadixLN); +} + +void RadixLN_AddHead(RadixLN *pRadixLN,LinkNode *LN,int Key) +{ + assert(pRadixLN); + assert( Key < pRadixLN->NumLNs && Key >= 0 ); + LN_AddHead(&(pRadixLN->LNs[Key]),LN); + if ( Key < pRadixLN->Min ) pRadixLN->Min = Key; + if ( Key > pRadixLN->Max ) pRadixLN->Max = Key; +} + +void RadixLN_AddTail(RadixLN *pRadixLN,LinkNode *LN,int Key) +{ + assert(pRadixLN); + assert( Key < pRadixLN->NumLNs && Key >= 0 ); + LN_AddTail(&(pRadixLN->LNs[Key]),LN); + if ( Key < pRadixLN->Min ) pRadixLN->Min = Key; + if ( Key > pRadixLN->Max ) pRadixLN->Max = Key; +} + +LinkNode * RadixLN_CutMax(RadixLN *pRadixLN,int *pKey) +{ + assert(pRadixLN); + +TIMER_P(List_RadixWalk); + while ( pRadixLN->Max >= 0 ) + { + LinkNode * LN; + + if ( LN = LN_CutHead(&(pRadixLN->LNs[pRadixLN->Max])) ) + { + if ( pKey ) *pKey = pRadixLN->Max; +TIMER_Q(List_RadixWalk); + return LN; + } + pRadixLN->Max --; + } +TIMER_Q(List_RadixWalk); + +return NULL; +} + +LinkNode * RadixLN_CutMin(RadixLN *pRadixLN,int *pKey) +{ + assert(pRadixLN); + +TIMER_P(List_RadixWalk); + while ( pRadixLN->Min < pRadixLN->NumLNs ) + { + LinkNode * LN; + + if ( LN = LN_CutHead(&(pRadixLN->LNs[pRadixLN->Min])) ) + { + if ( pKey ) *pKey = pRadixLN->Max; +TIMER_Q(List_RadixWalk); + return LN; + } + pRadixLN->Min ++; + } +TIMER_Q(List_RadixWalk); + +return NULL; +} + +LinkNode * RadixLN_CutKey(RadixLN *pRadixLN,int Key) +{ + assert(pRadixLN); +return LN_CutHead(&(pRadixLN->LNs[Key])); +} + + +LinkNode * RadixLN_PeekMax(RadixLN *pRadixLN,int *pKey) +{ +LinkNode * LNs; + assert(pRadixLN); + +TIMER_P(List_RadixWalk); + LNs = & pRadixLN->LNs[pRadixLN->Max]; + while ( pRadixLN->Max >= 0 ) + { + LinkNode * LN; + + LN = LNs->Next; + if ( LN != LNs ) + { + if ( pKey ) *pKey = pRadixLN->Max; +TIMER_Q(List_RadixWalk); + return LN; + } + pRadixLN->Max --; + LNs --; + } +TIMER_Q(List_RadixWalk); + +return NULL; +} + +LinkNode * RadixLN_PeekMin(RadixLN *pRadixLN,int *pKey) +{ +LinkNode * LNlist; + assert(pRadixLN); + +TIMER_P(List_RadixWalk); + LNlist = & pRadixLN->LNs[pRadixLN->Min]; + while ( pRadixLN->Min < pRadixLN->NumLNs ) + { + LinkNode * LN; + + LN = LNlist->Next; + if ( LN != LNlist ) + { + if ( pKey ) *pKey = pRadixLN->Min; +TIMER_Q(List_RadixWalk); + return LN; + } + pRadixLN->Min ++; + LNlist ++; + } +TIMER_Q(List_RadixWalk); + +return NULL; +} + +/*************************************************/ + +struct RadixLink +{ + int NumLinks; + int Min,Max; + Link * Links; +}; + +RadixLink * RadixLink_Create(int RadixLinkMax) +{ +RadixLink * pRadixLink; + pRadixLink = new(RadixLink); + assert(pRadixLink); + pRadixLink->NumLinks = RadixLinkMax+1; + pRadixLink->Links = MemAlloc(sizeof(Link)*(pRadixLink->NumLinks)); + assert(pRadixLink->Links); + //memset(pRadixLink->Links,0,(sizeof(Link)*(pRadixLink->NumLinks))); + pRadixLink->Min = pRadixLink->NumLinks; + pRadixLink->Max = - 1; +return pRadixLink; +} + +void RadixLink_Grow(RadixLink *pRadixLink,int NewMax) +{ +Link * OldLinks; +int OldNumLinks; + + OldNumLinks = pRadixLink->NumLinks; + OldLinks = pRadixLink->Links; + + pRadixLink->NumLinks = NewMax + 1; + pRadixLink->Links = MemAlloc(sizeof(Link)*(pRadixLink->NumLinks)); + + assert(pRadixLink->Links); + + memcpy(pRadixLink->Links, OldLinks, (sizeof(Link)*OldNumLinks)); + //memset(pRadixLink->Links + OldNumLinks,0,(sizeof(Link)*(pRadixLink->NumLinks - OldNumLinks))); + + MemFree(OldLinks); +} + +void RadixLink_Destroy(RadixLink * pRadixLink) +{ +int r; + assert(pRadixLink); + for(r=0;r<(pRadixLink->NumLinks);r++) + { + if ( pRadixLink->Links[r].Next ) + Link_Destroy(pRadixLink->Links[r].Next); + } + MemFree(pRadixLink->Links); + MemFree(pRadixLink); +} + +void RadixLink_Add(RadixLink *pRadixLink,void * Data,int Key) +{ + assert(pRadixLink); + assert( Key >= 0 ); + + if ( Key >= pRadixLink->NumLinks ) + RadixLink_Grow(pRadixLink, Key + (Key>>2) ); + + Link_Push(&(pRadixLink->Links[Key]),Data); + + if ( Key < pRadixLink->Min ) pRadixLink->Min = Key; + if ( Key > pRadixLink->Max ) pRadixLink->Max = Key; +} + +void * RadixLink_CutMax(RadixLink *pRadixLink,int *pKey) +{ +Link * pLink; + pLink = (pRadixLink->Links) + (pRadixLink->Max); + while ( pRadixLink->Max >= 0 ) + { + if ( pLink->Next ) + { + if ( pKey ) *pKey = pRadixLink->Max; + return Link_Pop(pLink); + } + pRadixLink->Max --; + pLink --; + } +return NULL; +} + +void * RadixLink_CutMin(RadixLink *pRadixLink,int *pKey) +{ +Link * pLink; + pLink = (pRadixLink->Links) + (pRadixLink->Min); + while ( pRadixLink->Min < pRadixLink->NumLinks ) + { + if ( pLink->Next ) + { + if ( pKey ) *pKey = pRadixLink->Min; + return Link_Pop(pLink); + } + pRadixLink->Min ++; + pLink ++; + } +return NULL; +} + +void * RadixLink_CutKey(RadixLink *pRadixLink,int Key) +{ + assert(pRadixLink); +return Link_Pop(&(pRadixLink->Links[Key])); +} + + +/***** debug only : **********************/ + +void List_TimerReport(void) +{ +#ifdef DO_TIMER + TIMER_REPORT(List_Ram); + TIMER_REPORT(List_RadixWalk); + TIMER_REPORT(List_RadixInit); +#endif +} + +/*************************************************/ + +/************************************************** + +Hash has separate Keys & Data + +We use a single Circular list of all the nodes. We have +cappers of Hash = 0 and HASH_SIZE at the head and tail. +So a general hash looks like : (with HASH_SIZE == 7) + + +(Head)-->A--x->C--x->E--x-->(Tail) +[0] [1][2][3][4][5][6] + +the brackets are hash buckets; little x's mean that hash bucket +has seen no nodes of its own hash, so it points to the next +larger hash's list. + +to do a Get : + simply look at your current pointer and walk while hash == my hash + example : Get(Hash == 3) + we get node C : ok, test it + next is node E : not my hash, so I'm done + +to do a delete : + simply cut your node, and point yourself to the next node. + example : Delete( Node C ) + +(Head)-->A--x--x--x->E--x-->(Tail) +[0] [1][2][3][4][5][6] + + now hash bucket 3 points to node E + +to do an add : + + first you must take your current pointer and walk backwards until + the preceding node has a lower hash than you (see example later). + + then simply add the new node before the current one and make yourself + point to the new one. + + Example 1: Add an A: + bucket 1 already is in the right place + add before the old node : + + +-A1 + | | +(Head)-+ A2-x--x--x->E--x-->(Tail) +[0] [1][2][3][4][5][6] + + now make the hash point to the new add: + + A2-+ + | | +(Head)---A1 x--x--x->E--x-->(Tail) +[0] [1][2][3][4][5][6] + + Example 2 : we need the extra seek in each _Add() + add a node C at hash 3 + + + A--+--+ + | | +(Head)---A (E) C--x->E--x-->(Tail) +[0] [1][2][3][4][5][6] + + the funny notation is to indicate that bucket 2 still + points to node E. + + now add a node B at hash 2 + we currently point to node (E) + the previous node is (C), which is greater than B, so + we step back; now the current is (C) and the previous is (A) : + + A--+ + | | +(Head)---A +->C--x->E--x-->(Tail) +[0] [1][2][3][4][5][6] + + which is a good list, so we do the normal add: + + A--+ + | | +(Head)---A B->C--x->E--x-->(Tail) +[0] [1][2][3][4][5][6] + +************** + +the whole goal of this system is that the WalkNext() function is +blazing fast. The only thing that hurts in the _Add function, but +the cost of adding N nodes to hash of size M is only O(N + M*M) +(because the first M adds are O(M) and the later adds are O(1)) + +*****************************/ + +#ifdef SAFE_HASH_DEBUG //{ + +#pragma message("using safe debug hash implementation") + +struct Hash +{ + HashNode ** NodeArray; + int NodeArrayLen; + int NodeCount; +}; + + +struct HashNode +{ + uint32 Key; + uint32 Data; +}; + +Hash * Hash_Create(void) +{ +Hash * H; + H = new(Hash); + assert(H); + //memset(H,0,sizeof(*H)); +return H; +} + +void Hash_Destroy(Hash *H) +{ + assert(H); + if ( H->NodeArray ) + { + int n; + for(n=0;nNodeCount;n++) + { + MemPool_FreeHunk(HashNodePool_g,H->NodeArray[n]); + } + destroy(H->NodeArray); + } + + destroy(H); +} + +HashNode * LISTCALL Hash_Add(Hash *H,uint32 Key,uint32 Data) +{ +HashNode * hn; + hn = MemPool_GetHunk(HashNodePool_g); + assert(hn); + hn->Key = Key; + hn->Data = Data; + + if ( H->NodeCount == H->NodeArrayLen ) + { + H->NodeArrayLen = H->NodeCount + 100; + if ( H->NodeArray ) + { + H->NodeArray = geRam_Realloc(H->NodeArray,H->NodeArrayLen*sizeof(HashNode *)); + } + else + { + H->NodeArray = geRam_Allocate(H->NodeArrayLen*sizeof(HashNode *)); + } + assert(H->NodeArray); + } + + H->NodeArray[H->NodeCount] = hn; + H->NodeCount ++; + +return hn; +} + +void LISTCALL Hash_DeleteNode(Hash *pHash,HashNode *pNode) +{ +int n; + + n = 0; + while( pHash->NodeArray[n] != pNode ) + { + n++; + assert( n < pHash->NodeCount ); + } + + pHash->NodeArray[n] = pHash->NodeArray[ pHash->NodeCount - 1]; + assert(pHash->NodeArray[n]); + pHash->NodeArray[ pHash->NodeCount - 1] = NULL; + pHash->NodeCount --; + + MemPool_FreeHunk(HashNodePool_g,pNode); +} + +HashNode * LISTCALL Hash_Get(Hash *pHash,uint32 Key,uint32 *pData) +{ +int n; + for(n=0;nNodeCount;n++) + { + if ( pHash->NodeArray[n]->Key == Key ) + { + if ( pData ) + *pData = pHash->NodeArray[n]->Data; + return pHash->NodeArray[n]; + } + } + return NULL; +} + +HashNode * LISTCALL Hash_WalkNext(Hash *pHash,HashNode *pCur) +{ +int n; + + if ( pCur ) + { + n = 0; + while( pHash->NodeArray[n] != pCur ) + { + n++; + assert( n < pHash->NodeCount ); + } + n ++; + } + else + { + n = 0; + } + if ( n == pHash->NodeCount ) + return NULL; + else + return pHash->NodeArray[n]; +} + +uint32 LISTCALL Hash_NumMembers(Hash *pHash) +{ + return pHash->NodeCount; +} + + +#else //}{ the real thing + +#define HASH_MOD (1009) // or 1013 , a nice prime +#define HASH_SIZE (HASH_MOD + 1) +#define HASH(Key) ((( ((Key)>>15) ^ (Key) )%HASH_MOD)+1) + +struct Hash +{ + + Debug(Hash * MySelf1) + + HashNode * HashTable[HASH_SIZE]; + HashNode * NodeList; + + Debug(int Members) + Debug(Hash * MySelf2) +}; + +struct HashNode +{ + LinkNode LN; + uint32 Key; + uint32 Data; + uint32 Hash; +}; + +Hash * Hash_Create(void) +{ +Hash * pHash; +HashNode *pHead,*pTail; + + pHash = new(Hash); + if ( ! pHash ) + return NULL; + + //memset(pHash,0,sizeof(Hash)); + + Debug( pHash->MySelf1 = pHash ) + Debug( pHash->MySelf2 = pHash ) + + pTail = MemPool_GetHunk(HashNodePool_g); + assert(pTail); + LN_Null(pTail); + pTail->Key = pTail->Data = 0; + pTail->Hash = HASH_SIZE; + + pHead = MemPool_GetHunk(HashNodePool_g); + assert(pHead); + LN_Null(pHead); + pHead->Key = pHead->Data = 0; + pHead->Hash = 0; + + LN_AddBefore(pHead,pTail); + + pHash->NodeList = pHead; + + Debug(pHash->Members = 0) + +return pHash; +} + +void Hash_Destroy(Hash *pHash) +{ + if ( pHash ) + { + HashNode *pList,*pNode,*pNext; + + assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash ); + + Debug(pHash->Members += 2) // count Head & Tail + + pList = pHash->NodeList; + LN_Walk_Editting(pNode,pList,pNext) { + MemPool_FreeHunk(HashNodePool_g,pNode); + assert(pHash->Members > 1); + Debug(pHash->Members --) + } + assert(pHash->Members == 1); + MemPool_FreeHunk(HashNodePool_g,pList); + destroy(pHash); + } +} + +#ifdef _DEBUG +int Hash_ListLen(Hash *pHash,uint32 H) +{ +HashNode *hn; +int Len = 0; + hn = pHash->HashTable[H]; + if ( ! hn ) + return 0; + while( hn->Hash == H ) + { + Len ++; + assert(pHash->Members >= Len); + hn = LN_Next(hn); + } +return Len; +} +#endif + +HashNode * LISTCALL Hash_Add(Hash *pHash,uint32 Key,uint32 Data) +{ +uint32 H; +HashNode *hn,**pTable,*Node,*Prev; +Debug( int ListLen1; int ListLen2; int HashLen1; int HashLen2; int WalkLen) + + assert(pHash); + assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash ); + + hn = MemPool_GetHunk(HashNodePool_g); + assert(hn); + Debug( LN_Null(hn) ) + + hn->Key = Key; + hn->Data = Data; + hn->Hash = H = HASH(Key); + + pTable = &(pHash->HashTable[H]); + Node = *pTable; + + assert( H > 0 ); + assert( pHash->NodeList->Hash == 0 ); + assert( ((HashNode *)LN_Prev(pHash->NodeList))->Hash == HASH_SIZE ); + + Debug(HashLen1 = Hash_NumMembers(pHash)) + Debug(ListLen1 = Hash_ListLen(pHash,H)) + + if ( ! Node ) + { + Prev = pHash->NodeList; + Node = LN_Next(Prev); + + Debug(WalkLen = 0) + + assert(Prev->Hash < H); + while( Node->Hash < H ) + { + Prev = Node; + Node = LN_Next(Prev); + + assert(WalkLen < pHash->Members ); + Debug( WalkLen ++) + + assert(Prev->Hash <= Node->Hash); + assert(Prev->Hash < HASH_SIZE ); + } + + assert(Prev->Hash < H); + assert(Node->Hash >= H); + } + + LN_AddBefore(hn,Node); + *pTable = hn; + + Debug(pHash->Members ++) + + Debug(ListLen2 = Hash_ListLen(pHash,H)) + assert( ListLen2 == (ListLen1 + 1) ); + Debug(HashLen2 = Hash_NumMembers(pHash)) + assert( HashLen2 == (HashLen1 + 1) ); + +return hn; +} + +void LISTCALL Hash_DeleteNode(Hash *pHash,HashNode *pNode) +{ +HashNode ** pHead; +uint32 H; +Debug( int ListLen1; int ListLen2;int HashLen1; int HashLen2) + + assert(pNode ); + assert( pHash ); + assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash ); + + assert( pNode->Hash > 0 && pNode->Hash < HASH_SIZE ); + + H = pNode->Hash; + pHead = & ( pHash->HashTable[H] ); + + Debug( HashLen1 = Hash_NumMembers(pHash) ) + Debug( ListLen1 = Hash_ListLen(pHash,H) ) + assert(pHash->Members > 0); + Debug(pHash->Members --) + + if ( *pHead == pNode ) + { + *pHead = LN_Next(pNode); + if ( (*pHead)->Hash != H ) + { + // pNode was the head of the list + assert( ((HashNode *)LN_Prev(pNode))->Hash < H ); + *pHead = NULL; + } + } + assert( *pHead == NULL || (*pHead)->Hash == H ); + + LN_Cut(pNode); + + MemPool_FreeHunk(HashNodePool_g,pNode); + + Debug( HashLen2 = Hash_NumMembers(pHash) ) + Debug( ListLen2 = Hash_ListLen(pHash,H) ) + assert( HashLen2 == (HashLen1 - 1) ); + +} + +HashNode * LISTCALL Hash_Get(Hash *pHash,uint32 Key,uint32 *pData) +{ +uint32 H; +HashNode *pNode; + + assert(pHash ); + assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash ); + + H = HASH(Key); + assert( H > 0 && H < HASH_SIZE ); + + pNode = pHash->HashTable[H]; + if ( ! pNode ) + return NULL; + + assert( pNode->Hash == H ); + + while( pNode->Hash == H ) + { + if ( pNode->Key == Key ) + { + if ( pData ) + *pData = pNode->Data; + return pNode; + } + pNode = LN_Next(pNode); + } + +return NULL; +} + +HashNode * LISTCALL Hash_WalkNext(Hash *pHash,HashNode *pNode) +{ +HashNode *pNext; + + assert(pHash); + assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash ); + + if ( ! pNode ) + { + pNode = pHash->NodeList; + assert( pNode->Hash == 0 ); + } + + pNext = LN_Next(pNode); + assert( pNext->Hash > 0 ); + assert( pNext->Hash >= pNode->Hash ); + + assert( pNext != pNode ); + assert( LN_Prev(pNext) == pNode ); + + if ( pNext->Hash == HASH_SIZE ) + { + assert( ((HashNode *)LN_Next(pNext)) == pHash->NodeList ); + return NULL; + } + + assert(pNext->Hash < HASH_SIZE); + +return pNext; +} + +uint32 LISTCALL Hash_NumMembers(Hash *pHash) +{ +uint32 N; +HashNode *pNode; + + assert(pHash); + assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash ); + + pNode = pHash->NodeList; + assert( pNode->Hash == 0 ); + pNode = LN_Next(pNode); + assert( pNode->Hash > 0 ); + + N = 0; + while( pNode->Hash < HASH_SIZE ) + { + assert( N < (uint32)pHash->Members ); + pNode = LN_Next(pNode); + N ++; + } + + assert( N == (uint32)pHash->Members ); + +return N; +} + +#endif //}{ hashes + +uint32 Hash_StringToKey(const char * String) +{ +return CRC32_Array(String,strlen(String)); +} + +void HashNode_SetData(HashNode *pNode,uint32 Data) +{ + assert(pNode); + pNode->Data = Data; +} + +void HashNode_GetData(HashNode *pNode,uint32 *pKey,uint32 *pData) +{ + assert(pNode); + *pKey = pNode->Key; + *pData = pNode->Data; +} + +uint32 HashNode_Data(HashNode *pNode) +{ + assert(pNode); +return pNode->Data; +} + +uint32 HashNode_Key(HashNode *pNode) +{ + assert(pNode); +return pNode->Key; +} + +/***************************/ + +geBoolean List_Start(void) +{ + assert(UsageCount >= 0 ); + if ( UsageCount == 0 ) + { + assert(ListPool_g == NULL && LinkPool_g == NULL); + if ( ! (ListPool_g = MemPool_Create(sizeof(List),1024,1024) ) ) + return GE_FALSE; + if ( ! (LinkPool_g = MemPool_Create(sizeof(Link),128,128) ) ) + return GE_FALSE; + if ( ! (HashNodePool_g = MemPool_Create(sizeof(HashNode),128,128) ) ) + return GE_FALSE; + // could latch ListFuncs_Stop() on atexit() , but no need, really.. + } + UsageCount ++; + return GE_TRUE; +} + +geBoolean List_Stop(void) +{ + assert(UsageCount > 0 ); + UsageCount --; + if ( UsageCount == 0 ) + { + assert(ListPool_g && LinkPool_g ); + MemPool_Destroy(&ListPool_g); ListPool_g = NULL; + MemPool_Destroy(&LinkPool_g); LinkPool_g = NULL; + MemPool_Destroy(&HashNodePool_g); HashNodePool_g = NULL; + } + return GE_TRUE; +} diff --git a/G3D/list.h b/G3D/list.h new file mode 100644 index 0000000..be02239 --- /dev/null +++ b/G3D/list.h @@ -0,0 +1,234 @@ +#ifndef LIST_H +#define LIST_H + +/****************************************************************************************/ +/* List */ +/* */ +/* Author: Charles Bloom */ +/* Description: List/Link/Node Primitives */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LISTCALL __fastcall + +/*******************************************/ +/** you must wrap any calls to this module with these: **/ + +geBoolean List_Start(void); +geBoolean List_Stop(void); + +/*******************************************/ +/** basic list types ****/ + +typedef struct List List; + +extern List * LISTCALL List_Create(void); +extern void LISTCALL List_Destroy(List * pList); +extern List * LISTCALL List_AddTail(List *pList,void * Data); +extern List * LISTCALL List_AddHead(List *pList,void * Data); + // returns a pointer to the node created +extern void * LISTCALL List_CutHead(List *pList); +extern void * LISTCALL List_CutTail(List *pList); +extern void * LISTCALL List_PeekHead(List *pList); +extern void * LISTCALL List_PeekTail(List *pList); + +extern List * LISTCALL List_Next(List *pNode); +extern List * LISTCALL List_Prev(List *pNode); + +extern void LISTCALL List_CutNode(List *pNode); +extern void LISTCALL List_DeleteNode(List *pNode); +extern void LISTCALL List_FreeNode(List *pNode); +extern void * LISTCALL List_NodeData(List *pNode); + +extern List * List_Find(List *pList,void *Data); + +/**** + + Iterate on a list via : + + List *pNode,*pList; + for( pNode = List_Next(pList); pNode != pList; pNode = List_Next(pNode) ) + { + //do stuff to pNode + } + +****/ + +typedef struct Stack Stack; + +extern Stack * LISTCALL Stack_Create(void); +extern void LISTCALL Stack_Destroy(Stack * pStack); +extern void LISTCALL Stack_Push_Func(Stack *pStack,void * Data); +extern void * LISTCALL Stack_Pop_Func(Stack *pStack); +extern int LISTCALL Stack_Extend(Stack *pStack); // returns new length + +#ifdef _DEBUG + +#define Stack_Push Stack_Push_Func +#define Stack_Pop Stack_Pop_Func + +#else + +// this struct is exposed only in release mode! +// don't look into it! + +struct Stack +{ + void ** Buffer, **End; + void ** Head; + int members; +}; + +//#define Stack_Push(pStack,Data) do { *((pStack)->Head)++ = (void *)(Data); if ( (pStack)->Head == (pStack)->End ) Stack_Extend(pStack); } while(0) +#define Stack_Push(pStack,Data) *((pStack)->Head)++ = (void *)(Data), ( (pStack)->Head != (pStack)->End ) || Stack_Extend(pStack) +#define Stack_Pop(pStack) ( ((pStack)->Head == (pStack)->Buffer) ? NULL : *( -- ((pStack)->Head) ) ) + +#endif + +typedef struct Link Link; + +extern Link * LISTCALL Link_Create(void); +extern void LISTCALL Link_Destroy(Link * pLink); +extern void LISTCALL Link_Push(Link *pLink,void * Data); +extern void * LISTCALL Link_Pop(Link *pLink); +extern void * LISTCALL Link_Peek(Link *pLink); + +typedef struct LinkNode LinkNode; + +/************************************/ +/*** a radix of each type ****/ + +typedef struct RadixList RadixList; + +extern RadixList * RadixList_Create(int RadixListMax); +extern void RadixList_Destroy(RadixList * pRadixList); +extern List * RadixList_Add(RadixList *pRadixList,void * Data,int Key); + // returns a pointer to the node created +extern void * RadixList_CutMax(RadixList *pRadixList,int * pMaxKey); +extern void * RadixList_CutMin(RadixList *pRadixList,int * pMinKey); +extern void * RadixList_CutKey(RadixList *pRadixList,int Key); + +typedef struct RadixLN RadixLN; + +extern RadixLN * RadixLN_Create(int RadixLNMax); +extern void RadixLN_Destroy(RadixLN * pRadixLN); +extern void RadixLN_AddTail(RadixLN *pRadixLN,LinkNode * LN,int Key); +extern void RadixLN_AddHead(RadixLN *pRadixLN,LinkNode * LN,int Key); +extern LinkNode * RadixLN_CutMax(RadixLN *pRadixLN,int * pMaxKey); +extern LinkNode * RadixLN_CutMin(RadixLN *pRadixLN,int * pMinKey); +extern LinkNode * RadixLN_CutKey(RadixLN *pRadixLN,int Key); +extern LinkNode * RadixLN_PeekMax(RadixLN *pRadixLN,int * pMaxKey); +extern LinkNode * RadixLN_PeekMin(RadixLN *pRadixLN,int * pMinKey); + +typedef struct RadixLink RadixLink; + +extern RadixLink * RadixLink_Create(int RadixLinkMax); +extern void RadixLink_Destroy(RadixLink * pRadixLink); +extern void RadixLink_Add(RadixLink *pRadixLink,void * Data,int Key); +extern void * RadixLink_CutMax(RadixLink *pRadixLink,int * pMaxKey); +extern void * RadixLink_CutMin(RadixLink *pRadixLink,int * pMinKey); +extern void * RadixLink_CutKey(RadixLink *pRadixLink,int Key); +extern void RadixLink_Grow(RadixLink *pRadixLink,int NewMax); + +/******************************/ + +typedef struct Hash Hash; +typedef struct HashNode HashNode; + +extern Hash * Hash_Create(void); +extern void Hash_Destroy(Hash *pHash); +HashNode * LISTCALL Hash_Add(Hash *pHash,uint32 Key,uint32 Data); +void LISTCALL Hash_DeleteNode(Hash *pHash,HashNode *pNode); +HashNode * LISTCALL Hash_Get(Hash *pHash,uint32 Key,uint32 *pData); + // pdata is optional +HashNode * LISTCALL Hash_WalkNext(Hash *pHash,HashNode *pCur); + //use pCur == NULL to start walking + +uint32 LISTCALL Hash_NumMembers(Hash *pHash); + +void HashNode_SetData(HashNode *pNode,uint32 Data); +void HashNode_GetData(HashNode *pNode,uint32 *pKey,uint32 *pData); +uint32 HashNode_Key(HashNode *pNode); +uint32 HashNode_Data(HashNode *pNode); + +uint32 Hash_StringToKey(const char * String); + +/******************************/ + +struct LinkNode +{ + LinkNode *Next,*Prev; +}; + +#define zLN_InitList(List) do { (List)->Next = List; (List)->Prev = List; } while(0) +#define zLN_Cut(Node) do { (Node)->Prev->Next = (Node)->Next; (Node)->Next->Prev = (Node)->Prev; zLN_InitList(Node); } while(0) +#define zLN_Fix(Node) do { (Node)->Prev->Next = Node; (Node)->Next->Prev = Node; } while(0) +#define zLN_AddAfter(Node,List) do { (Node)->Prev = List; (Node)->Next = (List)->Next; LN_Fix(Node); } while(0) +#define zLN_AddBefore(Node,List) do { (Node)->Next = List; (Node)->Prev = (List)->Prev; LN_Fix(Node); } while(0) +#define zLN_Walk_Editting(Node,List,Holder) for( Node = (List)->Next; (Node) != (List) && ((Holder) = (Node)->Next) != NULL ; Node = Holder ) +#define zLN_Walk(Node,List) for( Node = (List)->Next; (Node) != (List) ; Node = (Node)->Next ) +#define zLN_EmptyList(List) ( (List)->Next == (List) ) + +#define LN_InitList(List) zLN_InitList((LinkNode *)List) +#define LN_Cut(Node) zLN_Cut((LinkNode *)Node) +#define LN_Fix(Node) zLN_Fix((LinkNode *)Node) +#define LN_AddAfter(Node,List) zLN_AddAfter((LinkNode *)Node,(LinkNode *)List) +#define LN_AddBefore(Node,List) zLN_AddBefore((LinkNode *)Node,(LinkNode *)List) +#define LN_Walk(Node,List) zLN_Walk((LinkNode *)Node,(LinkNode *)List) +#define LN_Walk_Editting(Node,List,Holder) zLN_Walk_Editting((LinkNode *)Node,(LinkNode *)List,((LinkNode *)Holder)) +#define LN_EmptyList(List) zLN_EmptyList((LinkNode *)List) +#define LN_Prev(Node) (void *)(((LinkNode *)Node)->Prev) +#define LN_Next(Node) (void *)(((LinkNode *)Node)->Next) + +#define LN_Null(node) LN_InitList(node) + +LinkNode * LISTCALL LN_CutHead(LinkNode *pList); +LinkNode * LISTCALL LN_CutTail(LinkNode *pList); + +int LN_ListLen(LinkNode *pList); + +#define LN_AddHead(list,node) LN_AddAfter(node,list) +#define LN_AddTail(list,node) LN_AddBefore(node,list) +#define LN_IsEmpty LN_EmptyList + + + /* use LN_Walk as : + * + + void doStuffOnAllNodes(LinkNode *pList) + { + LinkNode *pNode; + LN_Walk(pNode,pList) { + doStuff(pNode); + } + } + + * + */ + +#ifdef __cplusplus +} +#endif + +#endif // LIST_H + diff --git a/G3D/mssccprj.scc b/G3D/mssccprj.scc new file mode 100644 index 0000000..22be39f --- /dev/null +++ b/G3D/mssccprj.scc @@ -0,0 +1,7 @@ +SCC = This is a Source Code Control file + +[Genesis.mak] +SCC_Project_Name = "$/Genesis10/Source", KQQBAAAA + +[GenesisDLL.mak] +SCC_Project_Name = "$/Genesis10/Source", HTYBAAAA diff --git a/G3D/resource.h b/G3D/resource.h new file mode 100644 index 0000000..0bfaa26 --- /dev/null +++ b/G3D/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by genesis.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/G3D/sprite.c b/G3D/sprite.c new file mode 100644 index 0000000..7876333 --- /dev/null +++ b/G3D/sprite.c @@ -0,0 +1,1430 @@ +/****************************************************************************************/ +/* SPRITE.C */ +/* */ +/* Author: Michael R. Brumm */ +/* Description: Sprite implementation */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/****************************************************************************************/ + +#include +#include + +#include "world.h" +#include "trace.h" + +#include "sprite.h" + +#include "ErrorLog.h" + + +#define BIG_DISTANCE 30000.0f + +extern geBoolean geBitmap_IsValid(const geBitmap *Bmp); + +// sprites are rectangular +#define SPRITE_NUM_CORNERS 4 + +// unit corners used to create scaled corners +#define UNIT_CORNERS { {0.5f, -0.5f}, {-0.5f, -0.5f}, {-0.5f, 0.5f}, {0.5f, 0.5f} } +const geCoordinate UnitCorners[SPRITE_NUM_CORNERS] = UNIT_CORNERS; + + +// dynamic light information is reused between sprites +// saving resources and allocation time +typedef struct geSprite_DynamicLight +{ + geVec3d Normal; + geColor Color; + geFloat Distance; + geFloat Radius; +} geSprite_DynamicLight; + +static geSprite_DynamicLight geSpriteDynamicLights[MAX_DYNAMIC_LIGHTS]; + + +// frustum clipping arrays are reused between sprites +// saving resources and allocation time +#define MAX_TEMP_VERTS 30 + +static Surf_TexVert UnclippedUVRGBA[MAX_TEMP_VERTS]; + +static geVec3d FrustumClippedVertexes1[MAX_TEMP_VERTS]; +static Surf_TexVert FrustumClippedUVRGBA1[MAX_TEMP_VERTS]; +static geVec3d FrustumClippedVertexes2[MAX_TEMP_VERTS]; +static Surf_TexVert FrustumClippedUVRGBA2[MAX_TEMP_VERTS]; + +static int32 FrustumNumClippedTexturedLitVertices; + +static Surf_TLVertex FrustumClippedTexturedLitVertexes[MAX_TEMP_VERTS]; + + +typedef struct geSprite +{ + // number of owners + int32 RefCount; + + // bitmaps used to texture the sprite + geBitmap * Bitmap; + geBitmap * BackfaceBitmap; + + // backface properties + geBoolean BackfaceEnabled; + geBoolean BackfaceMirrorImage; + + // makes the sprite always face the camera + geBoolean AlwaysFaceCamera; + + // transform affects position and orientation of the sprite + geXForm3d Transform; + + // internal transform also affects position and orientation of the sprite + // allows the sprite to be offset from its center of rotation + geBoolean InternalTransformUsed; + geXForm3d InternalTransform; + + // actual center of sprite (both external and internal transforms added) + geVec3d Position; + + // scale of the sprite + // allows sprite to be sized without changing + geFloat ScaleX; + geFloat ScaleY; + + // cached corners and vertexes + // corners are used to build the vertexes + // vertexes are used to build final screen polys + geCoordinate Corners[SPRITE_NUM_CORNERS]; + geVec3d Vertexes[SPRITE_NUM_CORNERS]; + + // texture parameters + geFloat TextureOffsetX; + geFloat TextureOffsetY; + geFloat TextureScaleX; + geFloat TextureScaleY; + + // cached texture mapping information + geUV UVs[SPRITE_NUM_CORNERS]; + geUV BackfaceUVs[SPRITE_NUM_CORNERS]; + + // lighting parameters + // used to build cached lighting information + geColor AmbientLight; + geBoolean UseFillLight; + geColor FillLight; + geVec3d FillLightNormal; + geBoolean UseLightFromFloor; + int32 MaximumDynamicLightsToUse; + + // cached lighting information + GE_RGBA RGBA; + GE_RGBA BackfaceRGBA; + + // surface normal of the sprite's face + geVec3d SurfaceNormal; + geBoolean LightingUsesSurfaceNormal; + + // bounding box which other objects collide against + geVec3d BoundingBoxMinCorner; + geVec3d BoundingBoxMaxCorner; + + // user data + void * UserData; + + // tracks changes made and whether cached data needs + // to be updated + geBoolean TransformChanged; + geBoolean LightingChanged; + +} geSprite; + + + // these are useful globals to monitor resources +int32 geSprite_Count = 0; +int32 geSprite_RefCount = 0; + + +__inline static void geSprite_UpdatePosition(geSprite *S) +{ + if (S->AlwaysFaceCamera) + S->Position = S->Transform.Translation; + else + geVec3d_Add( &(S->Transform.Translation), &(S->InternalTransform.Translation), &(S->Position) ); +} + + +__inline static void geSprite_UpdateCorners(geSprite *S) +{ + int i; + + for (i = 0; i < SPRITE_NUM_CORNERS; i++) + { + S->Corners[i].X = UnitCorners[i].X * S->ScaleX; + S->Corners[i].Y = UnitCorners[i].Y * S->ScaleY; + } +} + + +__inline static void geSprite_UpdateVertexes(geSprite *S) +{ + int i; + + // create a rectangle of the correct size around the origin + for (i = 0; i < SPRITE_NUM_CORNERS; i++) + { + S->Vertexes[i].X = S->Corners[i].X; + S->Vertexes[i].Y = S->Corners[i].Y; + S->Vertexes[i].Z = 0.0f; + } + + // apply the internal and external transform if an internal transform is used + if (S->InternalTransformUsed) + geXForm3d_TransformArray(&(S->InternalTransform), S->Vertexes, S->Vertexes, SPRITE_NUM_CORNERS); + + // apply the sprites external transform + geXForm3d_TransformArray(&(S->Transform), S->Vertexes, S->Vertexes, SPRITE_NUM_CORNERS); +} + + +__inline static void geSprite_UpdateVertexesToFaceCamera(geSprite *S, geCamera *Camera) +{ + int i; + const geXForm3d *CameraXForm; + geVec3d Left; + geVec3d Up; + geVec3d In; + geFloat Dot; + + // optimized out: + // + // geXForm3d FaceCameraXForm; + + // get the camera's transform + CameraXForm = geCamera_GetWorldSpaceXForm(Camera); + + // get the vector opposite to the direction the camera is looking + // + // optimized from: + // + // geXForm3d_GetIn(CameraXForm, &In); + // In.X = -In.X; + // In.Y = -In.Y; + // In.Z = -In.Z; + // + In.X = CameraXForm->AZ; + In.Y = CameraXForm->BZ; + In.Z = CameraXForm->CZ; + + // get the up direction of the camera + geXForm3d_GetUp(CameraXForm, &Up); + + Dot = geVec3d_DotProduct(&Up, &In); + + Up.X = Up.X - (Dot * In.X); + Up.Y = Up.Y - (Dot * In.Y); + Up.Z = Up.Z - (Dot * In.Z); + + geVec3d_Normalize(&Up); + + // get the left vector direction for the sprite based on the 'in' and 'up' + // + // optimized from: + // + // geVec3d_CrossProduct(&Up, &In, &Left); + // + Left.X = (Up.Z * In.Y) - (Up.Y * In.Z); + Left.Y = (Up.X * In.Z) - (Up.Z * In.X); + Left.Z = (Up.Y * In.X) - (Up.X * In.Y); + + // build the transform based on the left, up, in, and position of the sprite + // + // optimized out: + // + // geXForm3d_SetFromLeftUpIn(&RotationXForm, &Left, &Up, &In); + // FaceCameraXForm.Translation = S->Transform.Translation; + + // modify all the vertexes + for (i = 0; i < SPRITE_NUM_CORNERS; i++) + { + // optimized from: + // + // S->Vertexes[i].X = S->Corners[i].X; + // S->Vertexes[i].Y = S->Corners[i].Y; + // S->Vertexes[i].Z = 0.0f; + // + // geXForm3d_Transform(&FaceCameraXForm, &(S->Vertexes[i]), &(S->Vertexes[i])); + // + S->Vertexes[i].X = (S->Corners[i].X * Left.X) + (S->Corners[i].Y * Up.X) + S->Transform.Translation.X; + S->Vertexes[i].Y = (S->Corners[i].X * Left.Y) + (S->Corners[i].Y * Up.Y) + S->Transform.Translation.Y; + S->Vertexes[i].Z = (S->Corners[i].X * Left.Z) + (S->Corners[i].Y * Up.Z) + S->Transform.Translation.Z; + } +} + + +__inline static void geSprite_UpdateSurfaceNormal(geSprite *S) +{ + if (S->InternalTransformUsed) + { + // rotate the surface normal by the internal transform + // + // optimized from: + // + // S->SurfaceNormal.X = 0.0f; + // S->SurfaceNormal.Y = 0.0f; + // S->SurfaceNormal.Z = -1.0f; + // + // geXForm3d_Rotate(&(S->InternalTransform), &(S->SurfaceNormal), &(S->SurfaceNormal)); + // + S->SurfaceNormal.X = -S->InternalTransform.AZ; + S->SurfaceNormal.Y = -S->InternalTransform.BZ; + S->SurfaceNormal.Z = -S->InternalTransform.CZ; + + // rotate the surface normal by the external transform + geXForm3d_Rotate(&(S->Transform), &(S->SurfaceNormal), &(S->SurfaceNormal)); + + } + + else + { + // rotate the surface normal by the external transform + // + // optimized from: + // + // S->SurfaceNormal.X = 0.0f; + // S->SurfaceNormal.Y = 0.0f; + // S->SurfaceNormal.Z = -1.0f; + // + // geXForm3d_Rotate(&(S->Transform), &(S->SurfaceNormal), &(S->SurfaceNormal)); + // + S->SurfaceNormal.X = -S->Transform.AZ; + S->SurfaceNormal.Y = -S->Transform.BZ; + S->SurfaceNormal.Z = -S->Transform.CZ; + } +} + + +__inline static void geSprite_UpdateSurfaceNormalToFaceCamera(geSprite *S, geCamera *Camera) +{ + // get the camera's transform + const geXForm3d *CameraXForm; + CameraXForm = geCamera_GetWorldSpaceXForm(Camera); + + // get the vector opposite to the direction the camera is looking + // + // optimized from: + // + // geXForm3d_GetIn(CameraXForm, &(S->SurfaceNormal)); + // S->SurfaceNormal.X = -S->SurfaceNormal.X; + // S->SurfaceNormal.Y = -S->SurfaceNormal.Y; + // S->SurfaceNormal.Z = -S->SurfaceNormal.Z; + // + S->SurfaceNormal.X = CameraXForm->AZ; + S->SurfaceNormal.Y = CameraXForm->BZ; + S->SurfaceNormal.Z = CameraXForm->CZ; +} + + +__inline static void geSprite_CreateFrustumClippedScreenPoly(geSprite *S, geCamera *Camera, Frustum_Info *FInfo, geBoolean *Render, geBoolean *RenderBackface) +{ + int i; + + const geXForm3d *CameraXForm; + + GFX_Plane *FPlanes; + + geVec3d *pVerts1; + geVec3d *pVerts2; + Surf_TexVert *pTexs1; + Surf_TexVert *pTexs2; + int32 Length; + + geVec3d CameraNormal; + + // if the face is always facing the camera, the backface will not + // be rendered + if (S->AlwaysFaceCamera) + { + *RenderBackface = GE_FALSE; + } + + // if the sprite is not always facing the camera, figure out which + // face is facing the camera + else + { + // get the camera's transform + CameraXForm = geCamera_GetWorldSpaceXForm(Camera); + + // get the direction vector from the camera to the sprite + geVec3d_Subtract(&(S->Position), &(CameraXForm->Translation), &CameraNormal); + geVec3d_Normalize(&CameraNormal); + + // check to see how similar the sprite's surface normal is to the direction + // between the camera and the sprite, and determine if the backface is being + // shown to the camera + *RenderBackface = (geVec3d_DotProduct(&CameraNormal, &(S->SurfaceNormal)) > 0); + + // if the backface is facing the camera, and it is disabled, then + // don't render it + if ( (*RenderBackface) && (!S->BackfaceEnabled) ) + { + *Render = GE_FALSE; + return; + } + } + + // no sense in rendering a completely transparent face + if ( ((!(*RenderBackface)) && (S->RGBA.a == 0.0f)) || + ((*RenderBackface) && (S->BackfaceRGBA.a == 0.0f)) ) + { + *Render = GE_FALSE; + return; + } + + // copy the correct texture mappings + if (*RenderBackface) + { + for (i = 0; i < SPRITE_NUM_CORNERS; i++) + { + UnclippedUVRGBA[i].u = S->BackfaceUVs[i].u; + UnclippedUVRGBA[i].v = S->BackfaceUVs[i].v; + } + } + else + { + for (i = 0; i < SPRITE_NUM_CORNERS; i++) + { + UnclippedUVRGBA[i].u = S->UVs[i].u; + UnclippedUVRGBA[i].v = S->UVs[i].v; + } + } + + // initialize pointers for frustum clipping + FPlanes = FInfo->Planes; + pVerts1 = S->Vertexes; + pTexs1 = UnclippedUVRGBA; + pVerts2 = FrustumClippedVertexes1; + pTexs2 = FrustumClippedUVRGBA1; + Length = SPRITE_NUM_CORNERS; + + // clip the vertexes (including their texture and lighting) to the frustum + for (i = 0; i < FInfo->NumPlanes; i++, FPlanes++) + { + + if (!Frustum_ClipToPlaneUV(FPlanes, pVerts1, pVerts2, pTexs1, pTexs2, Length, &FrustumNumClippedTexturedLitVertices)) + break; + + assert(FrustumNumClippedTexturedLitVertices < MAX_TEMP_VERTS); + + // this is hard to read, but essentially what is happening is that + // source data is swapping with destination data every frustum clip. + // in this way, vertexes are further clipped each time + if (pVerts2 == FrustumClippedVertexes1) + { + pVerts1 = FrustumClippedVertexes1; + pVerts2 = FrustumClippedVertexes2; + pTexs1 = FrustumClippedUVRGBA1; + pTexs2 = FrustumClippedUVRGBA2; + } + else + { + pVerts1 = FrustumClippedVertexes2; + pVerts2 = FrustumClippedVertexes1; + pTexs1 = FrustumClippedUVRGBA2; + pTexs2 = FrustumClippedUVRGBA1; + } + + Length = FrustumNumClippedTexturedLitVertices; + } + + assert(FrustumNumClippedTexturedLitVertices < MAX_TEMP_VERTS); + + // Not visible or not enough vertexes + if ( (i != FInfo->NumPlanes) || (FrustumNumClippedTexturedLitVertices < 3) ) + { + *Render = GE_FALSE; + return; + } + + // Transform the face to camera space + geCamera_TransformArray(Camera, pVerts1, pVerts1, FrustumNumClippedTexturedLitVertices); + + // Project the face, and combine vertex and texture and lighting data into one structure + Frustum_ProjectRGBA(pVerts1, pTexs1, (DRV_TLVertex*)&FrustumClippedTexturedLitVertexes, FrustumNumClippedTexturedLitVertices, Camera); + + *Render = GE_TRUE; +} + + +__inline static void geSprite_UpdateBackfaceTextureMap(geSprite *S) +{ + if (S->BackfaceMirrorImage) + { + S->BackfaceUVs[0].u = S->UVs[0].u; + S->BackfaceUVs[0].v = S->UVs[0].v; + S->BackfaceUVs[1].u = S->UVs[1].u; + S->BackfaceUVs[1].v = S->UVs[1].v; + S->BackfaceUVs[2].u = S->UVs[2].u; + S->BackfaceUVs[2].v = S->UVs[2].v; + S->BackfaceUVs[3].u = S->UVs[3].u; + S->BackfaceUVs[3].v = S->UVs[3].v; + } + else + { + S->BackfaceUVs[0].u = S->UVs[1].u; + S->BackfaceUVs[0].v = S->UVs[1].v; + S->BackfaceUVs[1].u = S->UVs[0].u; + S->BackfaceUVs[1].v = S->UVs[0].v; + S->BackfaceUVs[2].u = S->UVs[3].u; + S->BackfaceUVs[2].v = S->UVs[3].v; + S->BackfaceUVs[3].u = S->UVs[2].u; + S->BackfaceUVs[3].v = S->UVs[2].v; + } +} + + +__inline static void geSprite_UpdateTextureMap(geSprite *S) +{ +/* + S->UVs[0].u = TextureOffsetX; + S->UVs[0].v = 1 - TextureOffsetY; + + S->UVs[1].u = TextureOffsetX + TextureScaleX; + S->UVs[1].v = 1 - TextureOffsetY; + + S->UVs[2].u = TextureOffsetX + TextureScaleX; + S->UVs[2].v = 1 - TextureOffsetY - TextureScaleY; + + S->UVs[3].u = TextureOffsetX; + S->UVs[3].v = 1 - TextureOffsetY - TextureScaleY; +*/ + // optimized (compiler probably would figure it out, but why take the chance) + S->UVs[3].u = S->UVs[0].u = S->TextureOffsetX; + S->UVs[1].v = S->UVs[0].v = 1 - S->TextureOffsetY; + + S->UVs[2].u = S->UVs[1].u = S->TextureOffsetX + S->TextureScaleX; + S->UVs[1].v = 1 - S->TextureOffsetY; + + S->UVs[3].v = S->UVs[2].v = 1 - S->TextureOffsetY - S->TextureScaleY; + + geSprite_UpdateBackfaceTextureMap(S); +} + + +#pragma warning(disable : 4700 ) +__inline static void geSprite_UpdateLighting(geSprite *S, geWorld *World) +{ + int32 i, j; + + geFloat Intensity; + + geBoolean DoBackface; + + geSprite_DynamicLight TempSwap; + + geFloat Scale; + + geVec3d PositionBelowFloor; + + geBoolean InsideWorldModel; + geBoolean FloorBeneath; + + geVec3d Impact; + int32 Node; + int32 Plane; + + GFX_Node *GFXNodes; + Surf_SurfInfo *Surf; + GE_RGBA FaceLightmapColor; + + + // first apply the ambient light + S->RGBA.r = S->AmbientLight.r; + S->RGBA.g = S->AmbientLight.g; + S->RGBA.b = S->AmbientLight.b; + + // apply the ambient to the backface, if there is one + DoBackface = ( (S->BackfaceEnabled) && !(S->AlwaysFaceCamera) ); + if (DoBackface) + { + S->BackfaceRGBA.r = S->AmbientLight.r; + S->BackfaceRGBA.g = S->AmbientLight.g; + S->BackfaceRGBA.b = S->AmbientLight.b; + } + + // calculate the fill light, if it applies + if (S->UseFillLight) + { + Intensity = geVec3d_DotProduct( &(S->FillLightNormal), &(S->SurfaceNormal) ); + + if (Intensity < 0.0f) + { + S->RGBA.r -= (Intensity * S->FillLight.r); + S->RGBA.g -= (Intensity * S->FillLight.g); + S->RGBA.b -= (Intensity * S->FillLight.b); + } + else + { + // apply the fill light to the backface, if there is one + if (DoBackface) + { + S->BackfaceRGBA.r += (Intensity * S->FillLight.r); + S->BackfaceRGBA.g += (Intensity * S->FillLight.g); + S->BackfaceRGBA.b += (Intensity * S->FillLight.b); + } + } + } + + if (S->MaximumDynamicLightsToUse > 0) + { + // a pointer to make things easier + Light_DLight *DynamicLights = World->LightInfo->DynamicLights; + + // start out with no dynamic lights available for lighting + int32 DLCount = 0; + + // get all the dynamic lights that are active + for (i = 0; i < MAX_DYNAMIC_LIGHTS; i++) + { + if (DynamicLights[i].Active) + { + // the normal is a vector distance + geVec3d Normal; + geVec3d_Subtract(&(S->Position), &(DynamicLights[i].Pos), &Normal); + + // which is why it can be used to calculate distance (squared) + geSpriteDynamicLights[DLCount].Distance = (Normal.X * Normal.X) + + (Normal.Y * Normal.Y) + + (Normal.Z * Normal.Z); + + // if the sprite is inside the active dynamic light's radius, then add it to the array + if (geSpriteDynamicLights[DLCount].Distance < (DynamicLights[i].Radius * DynamicLights[i].Radius)) + { + geSpriteDynamicLights[DLCount].Color.r = DynamicLights[i].Color.r; + geSpriteDynamicLights[DLCount].Color.g = DynamicLights[i].Color.g; + geSpriteDynamicLights[DLCount].Color.b = DynamicLights[i].Color.b; + geSpriteDynamicLights[DLCount].Radius = DynamicLights[i].Radius; + // this normal will be normalized later + geSpriteDynamicLights[DLCount].Normal = Normal; + DLCount++; + } + } + } + + // try to eliminate some easy out possibilities + if (DLCount > 1) + { + // if there is only one light needed, just make sure the closest + // is in the first location + if ( (S->MaximumDynamicLightsToUse == 1) ) + { + for (i = 1; i < DLCount; i++) + { + if (geSpriteDynamicLights[i].Distance < geSpriteDynamicLights[0].Distance) + geSpriteDynamicLights[0] = geSpriteDynamicLights[i]; + } + } + // if there is not just one light to get out of the array, then + // sort the active dynamic lights by distance (squared) + else + { + for (i = 0; i < DLCount; i++) + { + for (j = 0; j < (DLCount - 1); j++) + { + if (geSpriteDynamicLights[j].Distance > geSpriteDynamicLights[j+1].Distance) + { + TempSwap = geSpriteDynamicLights[j]; + geSpriteDynamicLights[j] = geSpriteDynamicLights[j+1]; + geSpriteDynamicLights[j+1] = TempSwap; + } + } + } + } + } + + // use whatever dynamic lights are available, under the maximum number + if (DLCount > S->MaximumDynamicLightsToUse) + DLCount = S->MaximumDynamicLightsToUse; + + // calculate the effect the closest lights have on the face + for (i = 0; i < DLCount; i++) + { + // makes the code more readable + geVec3d *LightNormal = &(geSpriteDynamicLights[i].Normal); + + // get the real distance (not the distance squared) + geFloat Distance = (geFloat)sqrt(geSpriteDynamicLights[i].Distance); + + // see, I told you it would get normalized (although not perfectly) + if (Distance > 1.0f) + geVec3d_Scale(LightNormal, (1.0f / Distance), LightNormal); + else + Distance = 1.0f; + + Scale = 1.0f - (Distance / geSpriteDynamicLights[i].Radius); + + Intensity = geVec3d_DotProduct( LightNormal, &(S->SurfaceNormal) ); + + if (Intensity < 0.0f) + { + S->RGBA.r -= (Intensity * geSpriteDynamicLights[i].Color.r * Scale); + S->RGBA.g -= (Intensity * geSpriteDynamicLights[i].Color.g * Scale); + S->RGBA.b -= (Intensity * geSpriteDynamicLights[i].Color.b * Scale); + } + else + { + if (DoBackface) + { + S->BackfaceRGBA.r += (Intensity * geSpriteDynamicLights[i].Color.r * Scale); + S->BackfaceRGBA.g += (Intensity * geSpriteDynamicLights[i].Color.g * Scale); + S->BackfaceRGBA.b += (Intensity * geSpriteDynamicLights[i].Color.b * Scale); + } + } + } + } + + if (S->UseLightFromFloor) + { + PositionBelowFloor.X = S->Position.X; + PositionBelowFloor.Y = S->Position.Y - BIG_DISTANCE; + PositionBelowFloor.Z = S->Position.Z; + + // Get shadow hit plane impact point + InsideWorldModel = Trace_WorldCollisionExact2(World, &(S->Position), &(S->Position), &Impact, &Node, &Plane, NULL); + FloorBeneath = Trace_WorldCollisionExact2(World, &(S->Position), &PositionBelowFloor, &Impact, &Node, &Plane, NULL); + + // Now find the color of the mesh by getting the lightmap point he is standing on... + if ( (!InsideWorldModel) && FloorBeneath) + { + // make things a bit more readable + GFXNodes = World->CurrentBSP->BSPData.GFXNodes; + + // get the surface infomation for the node below the sprite + Surf = &(World->CurrentBSP->SurfInfo[GFXNodes[Node].FirstFace]); + + // if there are lightmap faces, then find the light mapped face below the sprite + if (Surf->LInfo.Face >= 0) + { + // go through each face looking for one below the sprite + for (i = 0; i < GFXNodes[Node].NumFaces; i++) + { + // if the surface is located at the point below the sprite, + // get the lightmap + if (Surf_InSurfBoundingBox(Surf, &Impact, 20.0f)) + { + // setup the lightmap for the surface + Light_SetupLightmap(&Surf->LInfo, NULL); + + // get the lightmap color at the point and add it to the + // light of the sprite, and stop looking for any more light + if (Light_GetLightmapRGB(Surf, &Impact, &FaceLightmapColor)) + { + S->RGBA.r += FaceLightmapColor.r; + S->RGBA.g += FaceLightmapColor.g; + S->RGBA.b += FaceLightmapColor.b; + + if (DoBackface) + { + S->BackfaceRGBA.r += FaceLightmapColor.r; + S->BackfaceRGBA.g += FaceLightmapColor.g; + S->BackfaceRGBA.b += FaceLightmapColor.b; + } + + break; + } + } + + // go to the next surface + Surf++; + } + } + } + } + + // fix up any over or under flow + if (S->RGBA.r > 255.0f) + S->RGBA.r = 255.0f; + else if (S->RGBA.r < 0.0f) + S->RGBA.r = 0.0f; + + if (S->RGBA.g > 255.0f) + S->RGBA.g = 255.0f; + else if (S->RGBA.g < 0.0f) + S->RGBA.g = 0.0f; + + if (S->RGBA.b > 255.0f) + S->RGBA.b = 255.0f; + else if (S->RGBA.b < 0.0f) + S->RGBA.b = 0.0f; + + if (DoBackface) + { + // fix up any over or under flow + if (S->BackfaceRGBA.r > 255.0f) + S->BackfaceRGBA.r = 255.0f; + else if (S->BackfaceRGBA.r < 0.0f) + S->BackfaceRGBA.r = 0.0f; + + if (S->BackfaceRGBA.g > 255.0f) + S->BackfaceRGBA.g = 255.0f; + else if (S->BackfaceRGBA.g < 0.0f) + S->BackfaceRGBA.g = 0.0f; + + if (S->BackfaceRGBA.b > 255.0f) + S->BackfaceRGBA.b = 255.0f; + else if (S->BackfaceRGBA.b < 0.0f) + S->BackfaceRGBA.b = 0.0f; + } +} +#pragma warning(default : 4700 ) + + +GENESISAPI int32 GENESISCC geSprite_GetCount() +{ + return geSprite_Count; +} + + +GENESISAPI geSprite *GENESISCC geSprite_Create(geBitmap *SpriteBitmap, geBitmap *SpriteBackfaceBitmap) +{ + geSprite *S; + + if (SpriteBitmap) + { + if ( geBitmap_IsValid(SpriteBitmap) == GE_FALSE ) + { + geErrorLog_Add( ERR_SPRITE_INVALIDBITMAP , NULL); + return NULL; + } + } + + if ( (SpriteBackfaceBitmap) && (SpriteBackfaceBitmap != SpriteBitmap) ) + { + if ( geBitmap_IsValid(SpriteBackfaceBitmap) == GE_FALSE ) + { + geErrorLog_Add( ERR_SPRITE_INVALIDBITMAP , NULL); + return NULL; + } + } + + + S = GE_RAM_ALLOCATE_STRUCT( geSprite ); + if ( S == NULL ) + { + geErrorLog_Add( ERR_SPRITE_ENOMEM , NULL); + return NULL; + } + + S->RefCount = 0; + + S->Bitmap = SpriteBitmap; + if (SpriteBitmap) + geBitmap_CreateRef(SpriteBitmap); + + S->BackfaceBitmap = SpriteBackfaceBitmap; + if ( (SpriteBackfaceBitmap) && (SpriteBitmap != SpriteBackfaceBitmap) ) + geBitmap_CreateRef(SpriteBackfaceBitmap); + + S->BackfaceEnabled = GE_TRUE; + S->BackfaceMirrorImage = GE_TRUE; + + S->AlwaysFaceCamera = GE_FALSE; + + geXForm3d_SetIdentity(&(S->Transform)); + + S->InternalTransformUsed = GE_FALSE; + geXForm3d_SetIdentity(&(S->InternalTransform)); + + geSprite_UpdatePosition(S); + + S->ScaleX = 1.0f; + S->ScaleY = 1.0f; + geSprite_UpdateCorners(S); + + S->TextureOffsetX = 0.0f; + S->TextureOffsetY = 0.0f; + S->TextureScaleX = 1.0f; + S->TextureScaleY = 1.0f; + geSprite_UpdateTextureMap(S); + + geVec3d_Clear(&(S->BoundingBoxMinCorner)); + geVec3d_Clear(&(S->BoundingBoxMaxCorner)); + + S->AmbientLight.r = 0.1f; + S->AmbientLight.g = 0.1f; + S->AmbientLight.b = 0.1f; + S->UseFillLight = GE_FALSE; + S->UseLightFromFloor = GE_FALSE; + S->MaximumDynamicLightsToUse = 0; + + S->LightingUsesSurfaceNormal = GE_FALSE; + + S->RGBA.a = 255.0f; + S->BackfaceRGBA.a = 255.0f; + + S->UserData = NULL; + + S->TransformChanged = GE_TRUE; + S->LightingChanged = GE_TRUE; + + assert( geSprite_IsValid(S) ); + + geSprite_Count++; + + return S; +} + + +GENESISAPI void GENESISCC geSprite_CreateRef(geSprite *S) +{ + assert( geSprite_IsValid(S) ); + + S->RefCount++; + geSprite_RefCount++; +} + + +GENESISAPI void GENESISCC geSprite_Destroy(geSprite **pS) +{ + geSprite *S; + assert( pS != NULL ); + assert( *pS != NULL ); + assert( geSprite_IsValid(*pS) ); + + S = *pS; + if (S->RefCount > 0) + { + S->RefCount --; + geSprite_RefCount--; + return; + } + + if (S->Bitmap) + { + geBitmap_Destroy(&(S->Bitmap)); + } + + if ( (S->BackfaceBitmap) && (S->BackfaceBitmap != S->Bitmap) ) + { + geBitmap_Destroy(&(S->BackfaceBitmap)); + } + + geRam_Free(*pS); + geSprite_Count--; + *pS = NULL; +} + + +GENESISAPI geBoolean GENESISCC geSprite_IsValid(const geSprite *S) +{ + if (S == NULL) + return GE_FALSE; + + return GE_TRUE; +} + + +GENESISAPI geBitmap *GENESISCC geSprite_GetBitmap(const geSprite *S) +{ + assert ( (S->Bitmap == NULL) || (geBitmap_IsValid(S->Bitmap)) ); + + return S->Bitmap; +} + + +GENESISAPI geBitmap *GENESISCC geSprite_GetBackfaceBitmap(const geSprite *S) +{ + assert ( (S->BackfaceBitmap == NULL) || (geBitmap_IsValid(S->BackfaceBitmap)) ); + + return S->BackfaceBitmap; +} + + +GENESISAPI void GENESISCC geSprite_GetBackface(const geSprite *S, geBoolean *Enabled, geBoolean *MirrorImage) +{ + assert ( Enabled ); + assert ( MirrorImage ); + + *Enabled = S->BackfaceEnabled; + *MirrorImage = S->BackfaceMirrorImage; +} + + +GENESISAPI void GENESISCC geSprite_SetBackface(geSprite *S, const geBoolean Enabled, const geBoolean MirrorImage) +{ + assert( geSprite_IsValid(S) ); + + // because lighting the backface requires a lot of extra calculations, the + // backface doesn't have correct lighting if it has been turned off. so, if it + // is turned on, lighting needs to be updated + S->LightingChanged = (S->LightingChanged || ((Enabled) && (!S->BackfaceEnabled)) ); + + // if the mirror imaging is changed, then update the texture map for the backface + if (S->BackfaceMirrorImage != MirrorImage) + { + S->BackfaceMirrorImage = MirrorImage; + geSprite_UpdateBackfaceTextureMap(S); + } + + S->BackfaceEnabled = Enabled; +} + + +GENESISAPI void GENESISCC geSprite_GetFaceCamera(const geSprite *S, geBoolean *Enabled) +{ + assert( geSprite_IsValid(S) ); + assert( Enabled != NULL ); + + *Enabled = S->AlwaysFaceCamera; +} + + +GENESISAPI void GENESISCC geSprite_SetFaceCamera(geSprite *S, geBoolean Enabled) +{ + assert( geSprite_IsValid(S) ); + + // if facing the camera is being disabled, then force an + // update on everything the transform affects + if ( (S->AlwaysFaceCamera) && (!Enabled) ) + { + S->TransformChanged = GE_TRUE; + } + + S->AlwaysFaceCamera = Enabled; + + geSprite_UpdatePosition(S); +} + + +GENESISAPI void GENESISCC geSprite_GetPosition(const geSprite *S, geVec3d *Pos) +{ + assert( geSprite_IsValid(S) ); + assert( Pos != NULL ); + assert( geXForm3d_IsOrthonormal(&(S->Transform)) ); + + *Pos = S->Transform.Translation; +} + + +GENESISAPI void GENESISCC geSprite_SetPosition(geSprite *S, const geVec3d *Pos) +{ + assert( geSprite_IsValid(S) ); + assert( Pos != NULL ); + assert( geXForm3d_IsOrthonormal(&(S->Transform)) ); + + S->Transform.Translation = *Pos; + + geSprite_UpdatePosition(S); + + S->TransformChanged = GE_TRUE; +} + + +GENESISAPI void GENESISCC geSprite_GetTransform(const geSprite *S, geXForm3d *Transform) +{ + assert( geSprite_IsValid(S) ); + assert( Transform!= NULL ); + + *Transform = S->Transform; +} + + +GENESISAPI void GENESISCC geSprite_SetTransform(geSprite *S, const geXForm3d *Transform) +{ + assert( geSprite_IsValid(S) ); + assert( Transform ); + + S->Transform = *Transform; + + geSprite_UpdatePosition(S); + + S->TransformChanged = GE_TRUE; +} + + +GENESISAPI void GENESISCC geSprite_GetInternalTransform(const geSprite *S, geXForm3d *Transform) +{ + assert( geSprite_IsValid(S) ); + assert( Transform ); + + *Transform = S->InternalTransform; +} + + +GENESISAPI void GENESISCC geSprite_SetInternalTransform(geSprite *S, const geXForm3d *Transform) +{ + assert( geSprite_IsValid(S) ); + assert( Transform ); + + S->InternalTransform = *Transform; + S->InternalTransformUsed = !( geXForm3d_IsIdentity(Transform) ); + + geSprite_UpdatePosition(S); + + S->TransformChanged = GE_TRUE; +} + + +GENESISAPI void GENESISCC geSprite_GetScale(const geSprite *S, geFloat *ScaleX, geFloat *ScaleY) +{ + assert( geSprite_IsValid(S)!=GE_FALSE ); + + *ScaleX = S->ScaleX; + *ScaleY = S->ScaleY; +} + + +GENESISAPI void GENESISCC geSprite_SetScale(geSprite *S, geFloat ScaleX, geFloat ScaleY) +{ + assert( geSprite_IsValid(S)!=GE_FALSE ); + + if ( (S->ScaleX != ScaleX) || (S->ScaleY != ScaleY) ) + { + S->ScaleX = ScaleX; + S->ScaleY = ScaleY; + + geSprite_UpdateCorners(S); + + S->TransformChanged = GE_TRUE; + } +} + + +GENESISAPI void GENESISCC geSprite_GetExtBox(const geSprite *S, geExtBox *ExtBox) +{ + assert( geSprite_IsValid(S) ); + assert( ExtBox != NULL ); + assert( geXForm3d_IsOrthonormal(&(S->Transform)) ); + + geVec3d_Add( &(S->Transform.Translation), &(S->BoundingBoxMinCorner), &(ExtBox->Min)); + geVec3d_Add( &(S->Transform.Translation), &(S->BoundingBoxMaxCorner), &(ExtBox->Max)); +} + + +GENESISAPI void GENESISCC geSprite_GetNonWorldExtBox(const geSprite *S, geExtBox *ExtBox) +{ + assert( geSprite_IsValid(S) ); + assert( ExtBox != NULL ); + + ExtBox->Min = S->BoundingBoxMinCorner; + ExtBox->Max = S->BoundingBoxMaxCorner; +} + + +GENESISAPI void GENESISCC geSprite_SetExtBox(geSprite *S, const geExtBox *ExtBox) +{ + assert( geSprite_IsValid(S) ); + assert( geExtBox_IsValid(ExtBox) ); + + S->BoundingBoxMinCorner = ExtBox->Min; + S->BoundingBoxMaxCorner = ExtBox->Max; +} + + +GENESISAPI void GENESISCC geSprite_GetTextureParameters(const geSprite *S, + geFloat *OffsetX, + geFloat *OffsetY, + geFloat *ScaleX, + geFloat *ScaleY) +{ + assert( geSprite_IsValid(S) ); + assert( OffsetX != NULL ); + assert( OffsetY != NULL ); + assert( ScaleX != NULL ); + assert( ScaleY != NULL ); + + *OffsetX = S->TextureOffsetX; + *OffsetY = S->TextureOffsetY; + *ScaleX = S->TextureScaleX; + *ScaleY = S->TextureScaleY; +} + + +GENESISAPI void GENESISCC geSprite_SetTextureParameters(geSprite *S, + geFloat OffsetX, + geFloat OffsetY, + geFloat ScaleX, + geFloat ScaleY) +{ + assert( geSprite_IsValid(S) ); + + S->TextureOffsetX = OffsetX; + S->TextureOffsetY = OffsetY; + S->TextureScaleX = ScaleX; + S->TextureScaleY = ScaleY; + + geSprite_UpdateTextureMap(S); +} + + +GENESISAPI void GENESISCC geSprite_GetLightingOptions(const geSprite *S, + geFloat *AmbientLightRed, + geFloat *AmbientLightGreen, + geFloat *AmbientLightBlue, + geBoolean *UseFillLight, + geVec3d *FillLightNormal, + geFloat *FillLightRed, + geFloat *FillLightGreen, + geFloat *FillLightBlue, + geBoolean *UseLightFromFloor, + int32 *MaximumDynamicLightsToUse) +{ + assert( geSprite_IsValid(S) ); + + assert( AmbientLightRed != NULL ); + assert( AmbientLightGreen != NULL ); + assert( AmbientLightBlue != NULL ); + assert( UseFillLight != NULL ); + assert( FillLightNormal != NULL ); + assert( FillLightRed != NULL ); + assert( FillLightGreen != NULL ); + assert( FillLightBlue != NULL ); + assert( UseLightFromFloor != NULL ); + assert( MaximumDynamicLightsToUse != NULL ); + + *AmbientLightRed = S->AmbientLight.r; + *AmbientLightGreen = S->AmbientLight.g; + *AmbientLightBlue = S->AmbientLight.b; + *UseFillLight = S->UseFillLight; + *FillLightNormal = S->FillLightNormal; + *FillLightRed = S->FillLight.r; + *FillLightGreen = S->FillLight.g; + *FillLightBlue = S->FillLight.b; + *UseLightFromFloor = S->UseLightFromFloor; + *MaximumDynamicLightsToUse = S->MaximumDynamicLightsToUse; +} + + +GENESISAPI void GENESISCC geSprite_SetLightingOptions(geSprite *S, + geFloat AmbientLightRed, // 0 .. 255 + geFloat AmbientLightGreen, // 0 .. 255 + geFloat AmbientLightBlue, // 0 .. 255 + geBoolean UseFillLight, + const geVec3d *FillLightNormal, + geFloat FillLightRed, // 0 .. 255 + geFloat FillLightGreen, // 0 .. 255 + geFloat FillLightBlue, // 0 .. 255 + geBoolean UseLightFromFloor, + int32 MaximumDynamicLightsToUse // 0 for none +) +{ + assert( geSprite_IsValid(S) ); + assert( geVec3d_IsValid(FillLightNormal) ); + + S->AmbientLight.r = AmbientLightRed; + S->AmbientLight.g = AmbientLightGreen; + S->AmbientLight.b = AmbientLightBlue; + S->UseFillLight = UseFillLight; + S->FillLightNormal = *FillLightNormal; + S->FillLight.r = FillLightRed; + S->FillLight.g = FillLightGreen; + S->FillLight.b = FillLightBlue; + S->UseLightFromFloor = UseLightFromFloor; + S->MaximumDynamicLightsToUse = MaximumDynamicLightsToUse; + + // if fill light or dynamic lights are now used, and they weren't before, + // then the surface normal will be needed. + // + // if the transform has changed, then it will be updated next render, so + // don't do it now + // + // if the camera always faces the camera, then this will be updated every + // render (and using a different normal), so don't do it now. + if ( (!S->TransformChanged) && + (!S->AlwaysFaceCamera) && + (!S->LightingUsesSurfaceNormal) && ((UseFillLight) || (MaximumDynamicLightsToUse > 0)) ) + geSprite_UpdateSurfaceNormal(S); + + // store whether vertexes are required for lighting (only for fill lights and dynamic lights) + S->LightingUsesSurfaceNormal = (S->UseFillLight) || (S->MaximumDynamicLightsToUse > 0); +} + + +GENESISAPI void GENESISCC geSprite_GetAlpha(const geSprite *S, geFloat *Alpha, geFloat *BackfaceAlpha) +{ + assert( geSprite_IsValid(S) ); + assert( Alpha ); + assert( BackfaceAlpha ); + + *Alpha = S->RGBA.a; + *BackfaceAlpha = S->BackfaceRGBA.a; +} + + +GENESISAPI void GENESISCC geSprite_SetAlpha(geSprite *S, geFloat Alpha, geFloat BackfaceAlpha) +{ + assert( geSprite_IsValid(S) ); + + S->RGBA.a = Alpha; + S->BackfaceRGBA.a = BackfaceAlpha; + + // alphas cannot be less than 0 or greater than 255 + if (S->RGBA.a < 0) + S->RGBA.a = 0.0f; + else if (S->RGBA.a > 255.0f) + S->RGBA.a = 255.0f; + if (S->BackfaceRGBA.a < 0) + S->BackfaceRGBA.a = 0.0f; + else if (S->BackfaceRGBA.a > 255.0f) + S->BackfaceRGBA.a = 255.0f; +} + + +GENESISAPI void *GENESISCC geSprite_GetUserData(const geSprite *S) +{ + assert( geSprite_IsValid(S) ); + + return S->UserData; +} + + +GENESISAPI void GENESISCC geSprite_SetUserData(geSprite *S, void *UserData) +{ + assert( geSprite_IsValid(S) ); + + S->UserData = UserData; +} + + +geBoolean GENESISCC geSprite_RenderPrep(geSprite *S, geWorld *World) +{ + assert( geSprite_IsValid(S) ); + + // if the sprite uses a front face bitmap, add the bitmap to the world + if (S->Bitmap) + { + if ( geWorld_AddBitmap(World, S->Bitmap) == GE_FALSE ) + { + geErrorLog_AddString(-1, "Sprite_RenderPrep : World_AddBitmap", NULL); + return GE_FALSE; + } + } + + // if the sprite uses a backface bitmap (and it is not the same as the front), + // add the bitmap to the world + if ( (S->BackfaceBitmap) && (S->BackfaceBitmap != S->Bitmap) ) + { + if ( geWorld_AddBitmap(World, S->Bitmap) == GE_FALSE ) + { + geErrorLog_AddString(-1, "Sprite_RenderPrep : World_AddBitmap", NULL); + return GE_FALSE; + } + } + + return GE_TRUE; +} + + +geBoolean GENESISCC geSprite_RenderThroughFrustum(geSprite *S, geEngine *Engine, geWorld *World, geCamera *Camera, Frustum_Info *FInfo) +{ + int i; + geBoolean Render; + geBoolean RenderBackface; + + assert( geSprite_IsValid(S) ); + + // if the sprite always faces the camera, the surface normal and lighting + // may need to be updated + if (S->AlwaysFaceCamera) + { + // vertexes are needed both to build the final screen poly which is rendered, + // but also for lighting + geSprite_UpdateVertexesToFaceCamera(S, Camera); + + // only modify the surface normal if lighting needs it + if (S->LightingUsesSurfaceNormal) + { + geSprite_UpdateSurfaceNormalToFaceCamera(S, Camera); + S->LightingChanged = GE_TRUE; + } + + // if the sprite uses ambient light from the floor and its transform has + // changed (transform includes location), then update the lighting + else if ( (S->TransformChanged) && (S->UseLightFromFloor) ) + { + S->LightingChanged = GE_TRUE; + } + } + + // otherwise only update the vertexes if the transform has changed + else if (S->TransformChanged) + { + // vertexes are needed both to build the final screen poly which is rendered, + // but also for lighting + geSprite_UpdateVertexes(S); + + // update the surface normal + // this is needed to determine lighting and which face is being viewed + geSprite_UpdateSurfaceNormal(S); + + // if the sprite uses the surface normal to light its faces, then + // update the surface normal and update the lighting + // + // if the sprite uses ambient light from the floor and its transform has + // changed (transform includes location), then update the lighting + if ( (S->LightingUsesSurfaceNormal) || (S->UseLightFromFloor) ) + { + S->LightingChanged = GE_TRUE; + } + + S->TransformChanged = GE_FALSE; + } + + // generate the frustum clipped screen poly based on the vertexes for the camera + geSprite_CreateFrustumClippedScreenPoly(S, Camera, FInfo, &Render, &RenderBackface); + + // only render if there is something to render + if (Render) + { + // moved inside here because there is no sense in dynamically + // lighting the vertexes if they won't be drawn. + // update the lighting only if lighting has changed or + // lighting uses dynamic lights (which may change) + if ( (S->LightingChanged) || (S->MaximumDynamicLightsToUse > 0) ) + { + geSprite_UpdateLighting(S, World); + S->LightingChanged = GE_FALSE; + } + + // render the poly using the front or backface data + if (RenderBackface) + { + // add the lighting data to the poly + for (i = 0; i < FrustumNumClippedTexturedLitVertices; i++) + { + FrustumClippedTexturedLitVertexes[i].r = S->BackfaceRGBA.r; + FrustumClippedTexturedLitVertexes[i].g = S->BackfaceRGBA.g; + FrustumClippedTexturedLitVertexes[i].b = S->BackfaceRGBA.b; + FrustumClippedTexturedLitVertexes[i].a = S->BackfaceRGBA.a; + } + + // render the poly using the backface bitmap + geEngine_RenderPoly(Engine, (GE_TLVertex*)FrustumClippedTexturedLitVertexes, FrustumNumClippedTexturedLitVertices, S->BackfaceBitmap, 0); + } + else + { + // add the lighting data to the poly + for (i = 0; i < FrustumNumClippedTexturedLitVertices; i++) + { + FrustumClippedTexturedLitVertexes[i].r = S->RGBA.r; + FrustumClippedTexturedLitVertexes[i].g = S->RGBA.g; + FrustumClippedTexturedLitVertexes[i].b = S->RGBA.b; + FrustumClippedTexturedLitVertexes[i].a = S->RGBA.a; + } + + // render the poly using the front bitmap + geEngine_RenderPoly(Engine, (GE_TLVertex*)FrustumClippedTexturedLitVertexes, FrustumNumClippedTexturedLitVertices, S->Bitmap, 0); + } + } + + return GE_TRUE; +} diff --git a/G3D/sprite.h b/G3D/sprite.h new file mode 100644 index 0000000..66b6002 --- /dev/null +++ b/G3D/sprite.h @@ -0,0 +1,210 @@ +/****************************************************************************************/ +/* SPRITE.H */ +/* */ +/* Author: Michael R. Brumm */ +/* Description: Sprite interface */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/****************************************************************************************/ + + +#ifndef GE_SPRITE_H +#define GE_SPRITE_H + +#include "genesis.h" +#include "basetype.h" +#include "extbox.h" +#include "bitmap.h" + +#ifdef GE_WORLD_H +#include "camera.h" +#include "Frustum.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// GENESIS_PUBLIC_APIS + +typedef struct geSprite geSprite; // an instance of a sprite + + +//--------------------------------------------------------------------------------- +// Creation/Destruction functions +//--------------------------------------------------------------------------------- + + // create a sprite instance associated with the given bitmaps as faces + // pass in a NULL bitmap for a gouraud face + // backface bitmap can be the same as the front face bitmap +GENESISAPI geSprite *GENESISCC geSprite_Create(geBitmap *SpriteBitmap, geBitmap *SpriteBackfaceBitmap); + + // create an additional reference (owner) for the sprite +GENESISAPI void GENESISCC geSprite_CreateRef(geSprite *Sprite); + + // destroy a sprite +GENESISAPI void GENESISCC geSprite_Destroy(geSprite **pS); + + // returns number of sprites that are currently created +GENESISAPI int32 GENESISCC geSprite_GetCount(); + + // checks to see if a sprite is valid or not +GENESISAPI geBoolean GENESISCC geSprite_IsValid(const geSprite *S); + +//--------------------------------------------------------------------------------- +// Queries +//--------------------------------------------------------------------------------- + // In general: Objects retuned from Get functions should not not be destroyed. + // if ownership is desired, call the objects _CreateRef() function to create another owner. + // (An 'owner' has access to the object regardless of the number of other owners, and + // an owner must call the object's _Destroy() function to relinquish ownership ) + + // Returns the Bitmap associated with the sprite's front face +GENESISAPI geBitmap *GENESISCC geSprite_GetBitmap(const geSprite *S); + + // Returns the Bitmap associated with the sprite's backface +GENESISAPI geBitmap *GENESISCC geSprite_GetBackfaceBitmap(const geSprite *S); + + // Gets backface parameters +GENESISAPI void GENESISCC geSprite_GetBackface(const geSprite *S, geBoolean *Enabled, geBoolean *MirrorImage); + + // Sets the backface parameters +GENESISAPI void GENESISCC geSprite_SetBackface(geSprite *S, const geBoolean Enabled, const geBoolean MirrorImage); + + // Gets whether the sprite always faces the camera +GENESISAPI void GENESISCC geSprite_GetFaceCamera(const geSprite *S, geBoolean *Enabled); + + // Sets whether the sprite always faces the camera +GENESISAPI void GENESISCC geSprite_SetFaceCamera(geSprite *S, geBoolean Enabled); + + // Gets the position of the sprite +GENESISAPI void GENESISCC geSprite_GetPosition(const geSprite *S, geVec3d *Pos); + + // Sets the position of the sprite + // + // For easy modification of the sprite position if the sprite always faces the camera +GENESISAPI void GENESISCC geSprite_SetPosition(geSprite *S, const geVec3d *Pos); + + // Gets the current transform for the sprite +GENESISAPI void GENESISCC geSprite_GetTransform(const geSprite *S, geXForm3d *Transform); + + // Sets the current transform for the sprite + // + // Rotation information is ignored if the sprite always faces the camera +GENESISAPI void GENESISCC geSprite_SetTransform(geSprite *S, const geXForm3d *Transform); + + // Gets the internal transform for the sprite +GENESISAPI void GENESISCC geSprite_GetInternalTransform(const geSprite *S, geXForm3d *Transform); + + // Sets the internal transform for the sprite + // + // Allows the sprite to be rendered offset from its main transform. For example, + // translation could make the bottom of the sprite its center of rotation. + // + // This is totally ignored if the sprite always faces the camera +GENESISAPI void GENESISCC geSprite_SetInternalTransform(geSprite *S, const geXForm3d *Transform); + + // Gets the scale of the sprite (width and height) +GENESISAPI void GENESISCC geSprite_GetScale(const geSprite *S, geFloat *ScaleX, geFloat *ScaleY); + + // Sets the scale of the sprite (width and height) +GENESISAPI void GENESISCC geSprite_SetScale(geSprite *S, geFloat ScaleX, geFloat ScaleY); + + // Gets an assigned general non changing bounding box from the sprite +GENESISAPI void GENESISCC geSprite_GetExtBox(const geSprite *S, geExtBox *ExtBox); + + // Gets the bounding box in non-world coordinates + // Whatever you put in with geSprite_SetExtBox, you get out with this function +GENESISAPI void GENESISCC geSprite_GetNonWorldExtBox(const geSprite *S, geExtBox *ExtBox); + + // Sets an assigned general non changing bounding box from the sprite +GENESISAPI void GENESISCC geSprite_SetExtBox(geSprite *S, const geExtBox *ExtBox); + + // Gets the texture parameters for the sprite +GENESISAPI void GENESISCC geSprite_GetTextureParameters(const geSprite *S, + geFloat *OffsetX, + geFloat *OffsetY, + geFloat *ScaleX, + geFloat *ScaleY + ); + + // Sets the texture parameters for the sprite +GENESISAPI void GENESISCC geSprite_SetTextureParameters(geSprite *S, + geFloat OffsetX, + geFloat OffsetY, + geFloat ScaleX, + geFloat ScaleY + ); + + // Gets the lighting options for the sprite +GENESISAPI void GENESISCC geSprite_GetLightingOptions(const geSprite *S, + geFloat *AmbientLightRed, // 0 .. 255 + geFloat *AmbientLightGreen, // 0 .. 255 + geFloat *AmbientLightBlue, // 0 .. 255 + geBoolean *UseFillLight, // GE_TRUE or GE_FALSE + geVec3d *FillLightNormal, // normalized vector + geFloat *FillLightRed, // 0 .. 255 + geFloat *FillLightGreen, // 0 .. 255 + geFloat *FillLightBlue, // 0 .. 255 + geBoolean *UseLightFromFloor,// GE_TRUE or GE_FALSE + int32 *MaximumDynamicLightsToUse + ); + + // Sets the lighting options for the sprite +GENESISAPI void GENESISCC geSprite_SetLightingOptions(geSprite *S, + geFloat AmbientLightRed, // 0 .. 255 + geFloat AmbientLightGreen, // 0 .. 255 + geFloat AmbientLightBlue, // 0 .. 255 + geBoolean UseFillLight, // GE_TRUE or GE_FALSE + const geVec3d *FillLightNormal, // normalized vector + geFloat FillLightRed, // 0 .. 255 + geFloat FillLightGreen, // 0 .. 255 + geFloat FillLightBlue, // 0 .. 255 + geBoolean UseLightFromFloor, // GE_TRUE or GE_FALSE + int32 MaximumDynamicLightsToUse // 0 for none + ); + + // Gets the alpha transparency of the sprite +GENESISAPI void GENESISCC geSprite_GetAlpha(const geSprite *S, geFloat *Alpha, geFloat *BackfaceAlpha); + + // Sets the alpha transparency of the sprite +GENESISAPI void GENESISCC geSprite_SetAlpha(geSprite *S, geFloat Alpha, geFloat BackfaceAlpha); + + // Returns the pointer which was set with geSprite_SetUserData. NULL if not set. +GENESISAPI void *GENESISCC geSprite_GetUserData(const geSprite *S); + + // Sets the sprites user data pointer to the given value. For clients only. +GENESISAPI void GENESISCC geSprite_SetUserData(geSprite *S, void *UserData); + + +//-------------------------------------------------------------------------------- +// Rendering +//-------------------------------------------------------------------------------- + +// GENESIS_PRIVATE_APIS + +#ifdef GE_WORLD_H + // Prepares the geSprite for rendering and posing. Call Once once the sprite is fully created. + // Must be called prior to render/pose/setworldtransform +geBoolean GENESISCC geSprite_RenderPrep( geSprite *A, geWorld *World); + + // Draws the geSprite. (RenderPrep must be called first) +geBoolean GENESISCC geSprite_RenderThroughFrustum(geSprite *S, geEngine *Engine, geWorld *World, geCamera *Camera, Frustum_Info *FInfo); +#endif + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/G3D/tclip.h b/G3D/tclip.h new file mode 100644 index 0000000..231028c --- /dev/null +++ b/G3D/tclip.h @@ -0,0 +1,76 @@ +/****************************************************************************************/ +/* TClip */ +/* */ +/* Author: Mike Sandige & Charles Bloom */ +/* Description: Triangle Clipping to the screen rectangle */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#ifndef GE_TCLIP_H +#define GE_TCLIP_H + +#include "basetype.h" +#include "getypes.h" +#include "bitmap.h" +#include "engine.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******* + +TClip is a state machine like OpenGL + +you should call it like : + + _Push() + _SetupEdges() + _SetTexture() + _Triangle() + _Triangle() + _SetTexture() + _Triangle() + _Triangle() + ... + _Pop() + +********/ + +GENESISAPI void GENESISCC geTClip_SetupEdges(geEngine *Engine, + geFloat LeftEdge, + geFloat RightEdge, + geFloat TopEdge , + geFloat BottomEdge, + geFloat BackEdge); + +GENESISAPI geBoolean GENESISCC geTClip_Push(void); +GENESISAPI geBoolean GENESISCC geTClip_Pop(void); + +GENESISAPI geBoolean GENESISCC geTClip_SetTexture(const geBitmap * Bitmap); +GENESISAPI void GENESISCC geTClip_Triangle(const GE_LVertex TriVertex[3]); + +GENESISAPI void GENESISCC geTClip_SetRenderFlags(uint32 newflags); // LA +GENESISAPI void GENESISCC geTClip_UnclippedTriangle(const GE_LVertex TriVertex[3]); // LA + +#ifdef __cplusplus +} +#endif + + +#endif + + diff --git a/G3D/timer.c b/G3D/timer.c new file mode 100644 index 0000000..0e71a72 --- /dev/null +++ b/G3D/timer.c @@ -0,0 +1,41 @@ +/****************************************************************************************/ +/* Timer */ +/* */ +/* Author: Charles Bloom */ +/* Description: A nice little profiling utility */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "timer.h" + +FILE * timerFP = stdout; + +int timerCount = 0; + +double time_Master = 0.0; +static tsc_type tsc_Master; + +void Timer_Start(void) +{ +readTSC(tsc_Master); +} +void Timer_Stop(void) +{ +tsc_type tsc_Master2; +readTSC(tsc_Master2); +time_Master += diffTSC(tsc_Master,tsc_Master2); +} diff --git a/G3D/timer.h b/G3D/timer.h new file mode 100644 index 0000000..153e1c0 --- /dev/null +++ b/G3D/timer.h @@ -0,0 +1,118 @@ +#ifndef TIMER_H +#define TIMER_H + +/****************************************************************************************/ +/* Timer */ +/* */ +/* Author: Charles Bloom */ +/* Description: A nice little profiling utility */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include +#include "tsc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//{ + +extern FILE * timerFP; +extern int timerCount; +extern double time_Master; + +extern void Timer_Start(void); +extern void Timer_Stop(void); + +#ifdef DO_TIMER //}{ + +#pragma message("timer ON") + +#define TIMER_VARS(func) static double time_##func =0.0; static tsc_type tsc_##func##1,tsc_##func##2; + +#define TIMER_P(func) readTSC(tsc_##func##1) +#define TIMER_Q(func) do { readTSC(tsc_##func##2); time_##func += diffTSC(tsc_##func##1,tsc_##func##2); } while(0) + +#define TIMER_REPORT(func) fprintf(timerFP,"%-20s : %1.6f : %2.1f %%\n", (#func) , (time_##func)/(double)timerCount , (time_##func)*100.0/(time_Master) ); + +#define TIMER_COUNT() timerCount++ + +#define TIMER_START() Timer_Start(); +#define TIMER_STOP() Timer_Stop(); + +#else //}{ + +#pragma message("timer OFF") + +#define TIMER_VARS(func) +#define TIMER_P(func) +#define TIMER_Q(func) +#define TIMER_REPORT(func) + +#define TIMER_COUNT() + +#define TIMER_START() +#define TIMER_STOP() + +#endif //}{ + +/********** + +//example usage: + +TIMER_VARS(test1); +TIMER_VARS(test2); + +int main(int argc,char *argv[]) +{ +int i,j; + + timerFP = stdout; + + TIMER_START(); + + TIMER_P(test1); + + for(i=0;i<1000;i++) + { + TIMER_P(test2); + j = 99/(i+1); + TIMER_Q(test2); + } + + TIMER_Q(test1); + + TIMER_COUNT(); + TIMER_STOP(); + + TIMER_REPORT(test2); + TIMER_REPORT(test1); + +return 0; +} + +**********/ + +//} + +#ifdef __cplusplus +} +#endif + +#endif // TIMER_H + diff --git a/G3D/tsc.c b/G3D/tsc.c new file mode 100644 index 0000000..e0ce4c7 --- /dev/null +++ b/G3D/tsc.c @@ -0,0 +1,135 @@ + +//#define _TSC // do this in the project settings! + +/****************************************************************************************/ +/* TSC */ +/* */ +/* Author: Charles Bloom */ +/* Description: tsc accessors */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +typedef unsigned long ulong; + +// { +#ifdef _TSC + +#pragma message("TSC on") + +#include "ram.h" +#include "log.h" +#include //sprintf +#include //outputdebug + +#define MemAlloc(size) geRam_Allocate(size) +#define MemFree(mem) geRam_Free(mem) + +#undef new +#define new(type) MemAlloc(sizeof(type)) +#undef destroy +#define destroy(mem) MemFree(mem) + +#include "tsc.h" + +typedef struct tscNode tscNode; +struct tscNode +{ + tscNode *next; + ulong tsc[2]; +}; +tscNode * head = NULL; + +void pushTSC(void) +{ +tscNode *tn; + tn = new(tscNode); + if ( !tn ) return; + tn->next = head; + head = tn; + readTSC(tn->tsc); +} + +double popTSC(void) +{ +tscNode *tn; +ulong tsc[2]; + readTSC(tsc); + if ( ! head ) return 0.0; + tn = head; + head = head->next; +return diffTSC(tn->tsc,tsc); +} + +void showPopTSC(const char *tag) +{ +double time; + time = popTSC(); + Log_Printf("%s : %f seconds\n",tag,time); +} + +void showPopTSCper(const char *tag,int items,const char *itemTag) +{ +double time,per; + time = popTSC(); + per = (time/(double)items); + if ( per < 0.000001 ) + Log_Printf("%s : %f = %e per %s\n",tag,time,per,itemTag); + else + Log_Printf("%s : %f = %f per %s\n",tag,time,per,itemTag); +} + +void readTSC(ulong *hi) +{ +ulong *lo = hi + 1; + __asm + { + _emit 0x0F; + _emit 0x31; // rdtsc + mov EBX,hi + mov DWORD PTR [EBX],EDX; + mov EBX,lo + mov DWORD PTR [EBX],EAX; + } + return; +} + +#define CPU_HZ (_TSC_CPU_MHZ*1000000.0) +#define msw_scale (4294967296.0/CPU_HZ) +#define lsw_scale (1.0/CPU_HZ) + +double diffTSC(ulong *tsc1,ulong *tsc2) +{ + + return (tsc2[1] - tsc1[1])*lsw_scale + + (tsc2[0] - tsc1[0])*msw_scale; + +} + +#else // _TSC +// }{ + +#pragma message("TSC off") + +void pushTSC(void) {} +double popTSC(void) { return 0.0; } +void showPopTSC(const char *tag) { } +void showPopTSCper(const char *tag,int items,const char *itemTag) { } +void readTSC(ulong *hi) {} +double diffTSC(ulong *tsc1,ulong *tsc2) { return 0; } + +#endif // _TSC +// } diff --git a/G3D/tsc.h b/G3D/tsc.h new file mode 100644 index 0000000..17514ec --- /dev/null +++ b/G3D/tsc.h @@ -0,0 +1,65 @@ +/****************************************************************************************/ +/* TSC */ +/* */ +/* Author: Charles Bloom */ +/* Description: tsc accessors */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#ifndef TSC_H +#define TSC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********** +* + + routines to access the TSC + will do nothing unless you compile tsc.c with _TSC turned on + + to convert clocks to seconds we use this MHZ define: + +* +********/ + +#define _TSC_CPU_MHZ 300 + + // show() will Pop() two and print the delta to log() + // does nothing unless debug is on + +extern void pushTSC(void); + + // the pop reads once & pop once & take difference + +extern double popTSC(void); +extern void showPopTSC(const char *tag); +extern void showPopTSCper(const char *tag,int items,const char *itemTag); + + // primitives + +typedef unsigned long tsc_type [2]; + +extern void readTSC(unsigned long *tsc); +extern double diffTSC(unsigned long *tsc1,unsigned long*tsc2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GBSPLib/BRUSH2.H b/GBSPLib/BRUSH2.H new file mode 100644 index 0000000..38530ed --- /dev/null +++ b/GBSPLib/BRUSH2.H @@ -0,0 +1,94 @@ +/****************************************************************************************/ +/* Brush2.h */ +/* */ +/* Author: John Pollard */ +/* Description: Code to load, csg, and split brushes, etc... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef BRUSH2_H +#define BRUSH2_H + +#include + +#include "Mathlib.h" +#include "Map.h" + +#include "VFile.h" +#include "Vec3d.h" + +#define NUM_BRUSH_DEFAULT_SIDES 6 + +typedef struct MAP_Brush +{ + MAP_Brush *Next; + + int32 EntityNum; + int32 BrushNum; + + int32 Contents; + + geVec3d Mins, Maxs; + + int32 OrderID; + + int32 NumSides; + GBSP_Side OriginalSides[NUM_BRUSH_DEFAULT_SIDES]; +} MAP_Brush; + +typedef struct GBSP_Brush +{ + GBSP_Brush *Next; + geVec3d Mins, Maxs; + int32 Side, TestSide; + MAP_Brush *Original; + int32 NumSides; + GBSP_Side Sides[NUM_BRUSH_DEFAULT_SIDES]; + +} GBSP_Brush; + +extern int32 gTotalBrushes; +extern int32 gPeekBrushes; + +MAP_Brush *AllocMapBrush(int32 NumSides); +void FreeMapBrush(MAP_Brush *Brush); +MAP_Brush *LoadMapBrush(geVFile *VFile); +void FreeMapBrushList(MAP_Brush *Brushes); +geBoolean MakeMapBrushPolys(MAP_Brush *ob); +MAP_Brush *CopyMapBrush(MAP_Brush *Brush); +int32 CountMapBrushList(MAP_Brush *Brushes); + +GBSP_Brush *AllocBrush(int32 NumSides); +void FreeBrush(GBSP_Brush *Brush); +void FreeBrushList(GBSP_Brush *Brushes); +void ShowBrushHeap(void); +GBSP_Brush *CopyBrush(GBSP_Brush *Brush); +void BoundBrush(GBSP_Brush *Brush); +GBSP_Brush *AddBrushListToTail(GBSP_Brush *List, GBSP_Brush *Tail); +int32 CountBrushList(GBSP_Brush *Brushes); +GBSP_Brush *RemoveBrushList(GBSP_Brush *List, GBSP_Brush *Remove); +geFloat BrushVolume (GBSP_Brush *Brush); +void CreateBrushPolys(GBSP_Brush *Brush); +GBSP_Brush *BrushFromBounds (geVec3d *Mins, geVec3d *Maxs); +geBoolean CheckBrush(GBSP_Brush *Brush); +void SplitBrush(GBSP_Brush *Brush, int32 PNum, int32 PSide, uint8 MidFlags, geBoolean Visible, GBSP_Brush **Front, GBSP_Brush **Back); +GBSP_Brush *SubtractBrush(GBSP_Brush *a, GBSP_Brush *b); +GBSP_Brush *CSGBrushes(GBSP_Brush *Head); + +geBoolean OutputBrushes(char *FileName, GBSP_Brush *Brushes); +geBoolean OutputMapBrushes(char *FileName, MAP_Brush *Brushes); + +#endif \ No newline at end of file diff --git a/GBSPLib/BSP.CPP b/GBSPLib/BSP.CPP new file mode 100644 index 0000000..aa30d09 --- /dev/null +++ b/GBSPLib/BSP.CPP @@ -0,0 +1,432 @@ +/****************************************************************************************/ +/* BSP.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Module distributes code to all the other modules */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "GBSPPrep.h" +#include "BSP.h" +#include "Map.h" +#include "Poly.h" +#include "Portals.h" +#include "Brush2.h" +#include "Vis.h" +#include "Leaf.h" +#include "Fill.h" +#include "Utils.h" +#include "Light.h" +#include "GBSPFile.h" + +#include "Ram.h" + +// Globals +GBSP_Model BSPModels[MAX_BSP_MODELS]; +int32 NumBSPModels; + +geBoolean Verbose = GE_TRUE; +geBoolean OriginalVerbose; +geBoolean EntityVerbose = GE_FALSE; + +// +// BSP2.cpp defs +// +geBoolean ProcessEntities(void); +void FreeBSP_r(GBSP_Node *Node); + +//======================================================================================= +// InsertModelNumbers +//======================================================================================= +geBoolean InsertModelNumbers(void) +{ + int32 i, NumModels; + char ModelNum[128]; + + NumModels = 0; + + for (i=0; i< NumEntities; i++) + { + if (CancelRequest) + return GE_FALSE; + + if (!Entities[i].Brushes2) // No model if no brushes + continue; + + Entities[i].ModelNum = NumModels; + + if (i != 0) + { + sprintf(ModelNum, "%i", NumModels); + SetKeyValue(&Entities[i], "Model", ModelNum); + } + NumModels++; + } + return GE_TRUE; +} + +//======================================================================================== +// CreateBSP +//======================================================================================== +geBoolean CreateBSP(char *FileName, BspParms *Parms) +{ + OriginalVerbose = Verbose = Parms->Verbose; + EntityVerbose = Parms->EntityVerbose; + + gCountVerts = GE_TRUE; + + NumLeafSides = 0; + NumLeafClusters = 0; + NumLeafBevels = 0; + NumPlanes = 0; + + if (!LoadBrushFile(FileName)) + { + FreeAllEntities(); + return GE_FALSE; + } + + InsertModelNumbers(); + + BeginGBSPModels(); + + if (!ProcessEntities()) + { + FreeAllGBSPData(); + FreeAllEntities(); + return GE_FALSE; + } + + return GE_TRUE; +} + +//======================================================================================== +// UpdateEntities +// Updates the entities only... +//======================================================================================== +geBoolean UpdateEntities(char *MapName, char *BSPName) +{ + GHook.Printf("--- Update Entities --- \n"); + + if (!LoadBrushFile(MapName)) + goto ExitWithError; + + InsertModelNumbers(); + + // Load the old .BSP + if (!LoadGBSPFile(BSPName)) + { + GHook.Error("UpdateEntities: Could not load .bsp file.\n"); + goto ExitWithError; + } + + // Destroy any old GFXEntData in the .BSP file + if (GFXEntData) + { + geRam_Free(GFXEntData); + GFXEntData = NULL; + } + NumGFXEntData = 0; + + if (!ConvertEntitiesToGFXEntData()) + { + GHook.Error("UpdateEntities: ConvertEntitiesToGFXEntData failed.\n"); + return GE_FALSE; + } + + // Save it!!! + if (!SaveGBSPFile(BSPName)) + { + GHook.Error("UpdateEntities: SaveGBSPFile failed.\n"); + goto ExitWithError; + } + + FreeAllEntities(); // Free any entities that might be left behind + FreeGBSPFile(); // Free any GFX BSP data left over + return GE_TRUE; + + ExitWithError: + FreeAllEntities(); // Free any entities that might be left behind + FreeGBSPFile(); // Free any GFX BSP data left over + return GE_FALSE; +} + +//======================================================================================== +// AllocNode +//======================================================================================== +GBSP_Node *AllocNode(void) +{ + GBSP_Node *Node; + + Node = GE_RAM_ALLOCATE_STRUCT(GBSP_Node); + + if (Node == NULL) + { + GHook.Error("AllocNode: Out of memory!\n"); + return NULL; + } + + memset(Node, 0, sizeof(GBSP_Node)); + + return Node; +} + +//======================================================================================== +// FreeNode +//======================================================================================== +void FreeNode(GBSP_Node *Node) +{ + GBSP_Face *Face, *Next; + GBSP_Brush *Brush, *NextB; + + if (Node->LeafFaces) + geRam_Free(Node->LeafFaces); + + for (Face = Node->Faces; Face; Face = Next) + { + Next = Face->Next; + FreeFace(Face); + } + + for (Brush = Node->BrushList; Brush; Brush = NextB) + { + NextB = Brush->Next; + + FreeBrush(Brush); + } + + geRam_Free(Node); +} + +//======================================================================================== +// FreeAllGBSPData +//======================================================================================== +geBoolean FreeAllGBSPData(void) +{ + int32 i; + + for (i=0; i< NumBSPModels; i++) + { + if (!FreePortals(BSPModels[i].RootNode[0])) + { + GHook.Error("FreeAllGBSPData: Could not free portals.\n"); + return GE_FALSE; + } + FreeBSP_r(BSPModels[i].RootNode[0]); + + memset(&BSPModels[i], 0, sizeof(GBSP_Model)); + } + + return GE_TRUE; +} + +//======================================================================================== +// CleanupGBSP +//======================================================================================== +void CleanupGBSP(void) +{ + FreeAllGBSPData(); + FreeAllEntities(); +} + +// +// Planes +// + +GBSP_Plane Planes[MAX_BSP_PLANES]; +int32 NumPlanes = 0; + +//==================================================================================== +// PlaneFromVerts +// Expects at least 3 verts +//==================================================================================== +void PlaneFromVerts(geVec3d *Verts, GBSP_Plane *Plane) +{ + geVec3d Vect1, Vect2; + + geVec3d_Subtract(&Verts[0], &Verts[1], &Vect1); + geVec3d_Subtract(&Verts[2], &Verts[1], &Vect2); + + geVec3d_CrossProduct(&Vect1, &Vect2, &Plane->Normal); + geVec3d_Normalize(&Plane->Normal); + + Plane->Dist = geVec3d_DotProduct(&Verts[0], &Plane->Normal); + + Plane->Type = geVec3d_PlaneType(&Plane->Normal); +} + +//==================================================================================== +// SidePlane +//==================================================================================== +void SidePlane(GBSP_Plane *Plane, int32 *Side) +{ + int32 Type; + + *Side = 0; // Default to same direction + + Plane->Type = geVec3d_PlaneType(&Plane->Normal); + + Type = Plane->Type % PLANE_ANYX; + + // Point the major axis in the positive direction + if (VectorToSUB(Plane->Normal, Type) < 0) + { + geVec3d_Inverse(&Plane->Normal); + Plane->Dist = -Plane->Dist; + *Side = 1; // Flip if direction is opposite match + } +} + +#define NORMAL_EPSILON (geFloat)0.00001 + +//==================================================================================== +// PlaneEqual +//==================================================================================== +geBoolean PlaneEqual(GBSP_Plane *Plane1, GBSP_Plane *Plane2) +{ + if (fabs(Plane1->Normal.X - Plane2->Normal.X) < NORMAL_EPSILON && + fabs(Plane1->Normal.Y - Plane2->Normal.Y) < NORMAL_EPSILON && + fabs(Plane1->Normal.Z - Plane2->Normal.Z) < NORMAL_EPSILON && + fabs(Plane1->Dist - Plane2->Dist) < DIST_EPSILON ) + return GE_TRUE; + + return GE_FALSE; +} + +//==================================================================================== +// SnapVector +//==================================================================================== +void SnapVector(geVec3d *Normal) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if ( fabs(VectorToSUB(*Normal,i) - (geFloat)1) < ANGLE_EPSILON ) + { + geVec3d_Clear(Normal); + VectorToSUB(*Normal,i) = (geFloat)1; + break; + } + + if ( fabs(VectorToSUB(*Normal,i) - (geFloat)-1) < ANGLE_EPSILON ) + { + geVec3d_Clear(Normal); + VectorToSUB(*Normal,i) = (geFloat)-1; + break; + } + } +} + +//==================================================================================== +// RoundInt +//==================================================================================== +geFloat RoundInt(geFloat In) +{ + return (geFloat)floor(In + (geFloat)0.5); +} + +//==================================================================================== +// SnapPlane +//==================================================================================== +void SnapPlane(geVec3d *Normal, geFloat *Dist) +{ + SnapVector (Normal); + + if (fabs(*Dist-RoundInt(*Dist)) < DIST_EPSILON) + *Dist = RoundInt(*Dist); +} + + +//======================================================================================= +// PlaneInverse +//======================================================================================= +void PlaneInverse(GBSP_Plane *Plane) +{ + geVec3d_Inverse(&Plane->Normal); + Plane->Dist = -Plane->Dist; + +} + +//==================================================================================== +// FindPlane +//==================================================================================== +int32 FindPlane(GBSP_Plane *Plane, int32 *Side) +{ + GBSP_Plane Plane1; + GBSP_Plane *Plane2; + //geFloat Dot; + int32 i; + + SnapPlane(&Plane->Normal, &Plane->Dist); + + Plane1 = *Plane; + + SidePlane(&Plane1, Side); // Find axis, and flip if necessary, to make major axis positive + + Plane2 = Planes; + + for (i=0; i< NumPlanes; i++) // Try to return a plane allready in the list + { + if (PlaneEqual(&Plane1, Plane2)) + return i; + + Plane2++; + } + + if (NumPlanes >= MAX_BSP_PLANES) + { + GHook.Error("Max BSP Planes.\n"); + return -1; + } + + Planes[NumPlanes++] = Plane1; + + return i; +} + +//======================================================================================= +//======================================================================================= +geFloat _fastcall Plane_PointDistanceFast(GBSP_Plane *Plane, geVec3d *Point) +{ + geFloat Dist,Dist2; + + Dist2 = Plane->Dist; + + switch (Plane->Type) + { + + case PLANE_X: + Dist = (Point->X - Dist2); + break; + case PLANE_Y: + Dist = (Point->Y - Dist2); + break; + case PLANE_Z: + Dist = (Point->Z - Dist2); + break; + + default: + Dist = geVec3d_DotProduct(Point, &Plane->Normal) - Dist2; + break; + } + + return Dist; +} diff --git a/GBSPLib/Brush2.cpp b/GBSPLib/Brush2.cpp new file mode 100644 index 0000000..7fdf94d --- /dev/null +++ b/GBSPLib/Brush2.cpp @@ -0,0 +1,1382 @@ +/****************************************************************************************/ +/* Brush2.Cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Code to load, csg, and split brushes, etc... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "Brush2.h" +#include "Mathlib.h" +#include "Poly.h" +#include "BSP.h" +#include "Texture.h" + +#include "VFile.h" +#include "Vec3d.h" +#include "Ram.h" + +#define BSP_BRUSH_SIZE(s) ((sizeof(GBSP_Brush)-sizeof(GBSP_Side[NUM_BRUSH_DEFAULT_SIDES]))+(sizeof(GBSP_Side)*(s))); +#define MAP_BRUSH_SIZE(s) ((sizeof(MAP_Brush)-sizeof(GBSP_Side[NUM_BRUSH_DEFAULT_SIDES]))+(sizeof(GBSP_Side)*(s))); + +int32 gTotalBrushes; +int32 gPeekBrushes; + +extern int32 NumSolidBrushes; +extern int32 NumCutBrushes; +extern int32 NumHollowCutBrushes; +extern int32 NumDetailBrushes; +extern int32 NumTotalBrushes; + +//======================================================================================= +// AllocMapBrush +//======================================================================================= +MAP_Brush *AllocMapBrush(int32 NumSides) +{ + MAP_Brush *MapBrush; + int32 Size; + + Size = MAP_BRUSH_SIZE(NumSides); + + MapBrush = (MAP_Brush*)geRam_Allocate(Size); + + memset(MapBrush, 0, Size); + + return MapBrush; +} + +//======================================================================================= +// FreeMapBrush +//======================================================================================= +void FreeMapBrush(MAP_Brush *Brush) +{ + int32 i; + + for (i=0 ; iNumSides ; i++) + if (Brush->OriginalSides[i].Poly) + FreePoly(Brush->OriginalSides[i].Poly); + + geRam_Free(Brush); +} + +//================================================================================ +// LoadMapBrush +//================================================================================ +MAP_Brush *LoadMapBrush(geVFile *VFile) +{ + MAP_Brush *Brush; + MAP_FaceHeader FaceHeader; + MAP_BrushHeader BrushHeader; + GBSP_Side *Side; + int32 k, NumSides; + int32 PlaneNum, PlaneSide, s; + GFX_TexInfo Tx; + + GBSP_Plane Plane; + geFloat FDist; + geVec3d VertF; + + // Get the number of faces + if (!geVFile_Read(VFile, &BrushHeader, sizeof(MAP_BrushHeader))) + { + GHook.Error("LoadMapBrush: There was an error reading the brush header.\n"); + return NULL; + } + + Brush = AllocMapBrush(BrushHeader.NumFaces); + Brush->NumSides = BrushHeader.NumFaces; + + NumSides = 0; + + for (k = 0; k< BrushHeader.NumFaces; k++) + { + memset (&Tx, 0, sizeof(GFX_TexInfo)); + + // Get the face header + if (!geVFile_Read(VFile, &FaceHeader, sizeof(MAP_FaceHeader))) + { + GHook.Error("LoadMapBrush: There was an error reading the face header.\n"); + return NULL; + } + + // Fill in the tex info + Tx.Texture = FindTextureIndex(FaceHeader.TexName, 0); + + //if (fread(&VertF, sizeof(Vec3dF), 1, f) != 1) + if (!geVFile_Read(VFile, &VertF, sizeof(geVec3d))) + { + FreeMapBrush(Brush); + return NULL; + } + + if (!geVFile_Read(VFile, &FDist, sizeof(geFloat))) + { + GHook.Error("LoadMapBrush: Could not read face plane dist.\n"); + FreeMapBrush(Brush); + return NULL; + } + + Plane.Normal.X = (geFloat)VertF.X; + Plane.Normal.Y = (geFloat)VertF.Y; + Plane.Normal.Z = (geFloat)VertF.Z; + + Plane.Dist = (geFloat)FDist; + + Plane.Type = PLANE_ANY; + if (geVec3d_Compare(&Plane.Normal, &VecOrigin, VCOMPARE_EPSILON)) + { + GHook.Error("LoadMapBrush: Invalid Normal, skipping!!!\n"); + GHook.Error("Normal - X: %2.2f, Y:%2.2f, Z:%2.2f\n", Plane.Normal.X, Plane.Normal.Y, Plane.Normal.Z); + continue; + } + + geVec3d_Normalize(&Plane.Normal); + + SnapPlane(&Plane.Normal, &Plane.Dist); + + PlaneNum = FindPlane(&Plane, &PlaneSide); + + Side = Brush->OriginalSides; + for (s = 0; sPlaneNum == PlaneNum && Side->PlaneSide == PlaneSide) + break; + } + + if (s != NumSides) + { + GHook.Printf("*WARNING* LoadMapBrush: Brush with duplicate plane.\n"); + continue; + } + + // Get the snapped plane... + Plane = Planes[PlaneNum]; + + if (PlaneSide) + PlaneInverse(&Plane); + + Tx.Vecs[0].X = FaceHeader.uVecX; + Tx.Vecs[0].Y = FaceHeader.uVecY; + Tx.Vecs[0].Z = FaceHeader.uVecZ; + + Tx.Vecs[1].X = FaceHeader.vVecX; + Tx.Vecs[1].Y = FaceHeader.vVecY; + Tx.Vecs[1].Z = FaceHeader.vVecZ; + + Tx.Shift[0] = FaceHeader.OffsetX; + Tx.Shift[1] = FaceHeader.OffsetY; + + Tx.DrawScale[0] = FaceHeader.DrawScaleX; + Tx.DrawScale[1] = FaceHeader.DrawScaleY; + + Tx.FaceLight = (geFloat)FaceHeader.FaceLight; + Tx.Flags = FaceHeader.Flags; + + + // Don't allow alpha values on faces that don't have the TRANS flag set... + if (!(Tx.Flags & TEXINFO_TRANS)) + { + FaceHeader.Alpha = 255.0f; + //Tx.Flags |= TEXINFO_TRANS; + } + + // Copy the brush's alpha directly over to the faces texinfo + Tx.Alpha = (geFloat)FaceHeader.Alpha; + Tx.MipMapBias = FaceHeader.MipMapBias; + Tx.ReflectiveScale = FaceHeader.ReflectiveScale; + + if (Tx.Flags & TEXINFO_MIRROR) + { + Tx.Flags |= TEXINFO_TRANS; + Side->Flags |= SIDE_HINT; + + if (Tx.Alpha > 240.0f) + GHook.Printf("*WARNING* HIGH Alpha value for mirror face: %f\n", Tx.Alpha); + } + + // If any side has some transparancy, make is so that you can see through the brush, and make it detail + // NOTE - We don't include mirror faces, since you can't actually see through those faces... + if ((Tx.Flags & TEXINFO_TRANS) && !(Tx.Flags&TEXINFO_MIRROR)) + { + BrushHeader.Flags |= BSP_CONTENTS_TRANSLUCENT2; + } + + + Side->PlaneNum = PlaneNum; + Side->PlaneSide = (uint8)PlaneSide; + Side->TexInfo = FindTexInfo (&Tx); + + if (Side->TexInfo == -1) + { + GHook.Error("LoadMapBrush: Could not find texinfo.\n"); + FreeMapBrush(Brush); + return NULL; + } + + NumSides++; + } + + if (NumSides > Brush->NumSides) + { + GHook.Error("LoadMapBrush: Num sides do not match.\n"); + return NULL; + } + + Brush->Contents = BrushHeader.Flags; + Brush->EntityNum = NumEntities-1; + Brush->NumSides = NumSides; + + MakeMapBrushPolys(Brush); + + // If no contents, then make empty (so it will at least have a visibility bit set...) + // Contents of 0 are invisible (air) + // Only Contents with at least one bit matching BSP_VISIBLE_CONTENTS will be visible + if (!Brush->Contents) + Brush->Contents |= BSP_CONTENTS_EMPTY2; + + // HACK! Convert solid sheets to clip... + if ((Brush->Contents & BSP_CONTENTS_SHEET) && (Brush->Contents & BSP_CONTENTS_SOLID2)) + { + Brush->Contents &= ~BSP_CONTENTS_SOLID2; + Brush->Contents |= BSP_CONTENTS_CLIP2; + } + + // Force clip to solid/detail, and mark faces as not visible (they will get put last in the tree) + if (Brush->Contents & BSP_CONTENTS_CLIP2) + { + for (k=0; kOriginalSides[k].Flags &= ~SIDE_VISIBLE; // Clips won't have faces + + Brush->Contents |= BSP_CONTENTS_DETAIL2; // Clips are allways detail + } + + if (Brush->Contents & BSP_CONTENTS_SHEET) + { + // Only the first side is visible for sheets + Brush->OriginalSides[0].Flags |= SIDE_SHEET; + // Sheets are allways detail!!! + Brush->Contents |= BSP_CONTENTS_DETAIL2; + } + + // Force non-solid/non-hint to detail + //if (!(Brush->Contents & BSP_CONTENTS_SOLID2)) + // Brush->Contents |= BSP_CONTENTS_DETAIL2; + + // Convert all sides to hint if need so... + if (Brush->Contents & BSP_CONTENTS_HINT2) + { + for (k=0; kOriginalSides[k].Flags |= SIDE_HINT; + Brush->OriginalSides[k].Flags |= SIDE_VISIBLE; + } + + if (Brush->Contents & BSP_CONTENTS_DETAIL2) + Brush->Contents &= ~BSP_CONTENTS_DETAIL2; + } + + if (Brush->Contents&BSP_CONTENTS_WINDOW2) + { + Brush->Contents |= BSP_CONTENTS_TRANSLUCENT2; + Brush->Contents |= BSP_CONTENTS_DETAIL2; + } + + // Count up what types of brushes we've loaded + if (Brush->Contents & BSP_CONTENTS_SOLID2) + NumSolidBrushes++; + + if (Brush->Contents & BSP_CONTENTS_DETAIL2) + NumDetailBrushes++; + + NumTotalBrushes++; + + return Brush; +} + +//======================================================================================= +// FreeMapBrushList +//======================================================================================= +void FreeMapBrushList(MAP_Brush *Brushes) +{ + MAP_Brush *Next; + + for ( ; Brushes ; Brushes = Next) + { + Next = Brushes->Next; + + FreeMapBrush(Brushes); + } +} + +//======================================================================================= +// MakeMapBrushPolys +// Builds the faces for all the planes on a MAP_Brush +// Or's all side flags with SIDE_VISIBLE +//======================================================================================= +geBoolean MakeMapBrushPolys(MAP_Brush *ob) +{ + int32 i, j; + GBSP_Poly *p; + GBSP_Side *Side; + GBSP_Plane Plane, *Plane2; + + ClearBounds(&ob->Mins, &ob->Maxs); + + for (i=0 ; iNumSides ; i++) + { + Plane = Planes[ob->OriginalSides[i].PlaneNum]; + + if (ob->OriginalSides[i].PlaneSide) + PlaneInverse(&Plane); + + p = CreatePolyFromPlane(&Plane); + + for (j=0 ; jNumSides && p; j++) + { + if (i == j) + continue; + + Plane2 = &Planes[ob->OriginalSides[j].PlaneNum]; + + ClipPolyEpsilon(p, 0.0f, Plane2, !ob->OriginalSides[j].PlaneSide, &p); + } + + Side = &ob->OriginalSides[i]; + Side->Poly = p; + + if (p) + { + // All sides default to being visible... + Side->Flags |= SIDE_VISIBLE; + for (j=0 ; jNumVerts ; j++) + AddPointToBounds(&p->Verts[j], &ob->Mins, &ob->Maxs); + } + } + + for (i=0 ; i<3 ; i++) + { + if (VectorToSUB(ob->Mins,i) <= -MIN_MAX_BOUNDS || VectorToSUB(ob->Maxs, i) >= MIN_MAX_BOUNDS) + GHook.Printf("Entity %i, Brush %i: Bounds out of range\n", ob->EntityNum, ob->BrushNum); + } + + return GE_TRUE; +} + +//======================================================================================= +// CopyMapBrush +//======================================================================================= +MAP_Brush *CopyMapBrush(MAP_Brush *Brush) +{ + MAP_Brush *NewBrush; + int32 Size; + int32 i; + + Size = MAP_BRUSH_SIZE(Brush->NumSides); + + NewBrush = AllocMapBrush(Brush->NumSides); + memcpy (NewBrush, Brush, Size); + + for (i=0 ; iNumSides ; i++) + { + if (Brush->OriginalSides[i].Poly) + { + if (!CopyPoly(Brush->OriginalSides[i].Poly, &NewBrush->OriginalSides[i].Poly)) + { + GHook.Error("Error copying brush.\n"); + return NULL; + } + } + } + + NewBrush->Contents = Brush->Contents; + + return NewBrush; +} + +//======================================================================================= +// CountMapBrushList +//======================================================================================= +int32 CountMapBrushList(MAP_Brush *Brushes) +{ + int32 Count; + + for (Count=0; Brushes ; Brushes = Brushes->Next) + Count++; + + return Count; +} + +// +// BSP Brush code +// + +//======================================================================================= +// AllocBrush +//======================================================================================= +GBSP_Brush *AllocBrush(int32 NumSides) +{ + GBSP_Brush *Brush; + int32 Size; + + Size = BSP_BRUSH_SIZE(NumSides); + + Brush = (GBSP_Brush*)geRam_Allocate(Size); + + if (!Brush) + return NULL; + + memset(Brush, 0, Size); + +#ifdef SHOW_DEBUG_STATS + gTotalBrushes++; + + if (gTotalBrushes > gPeekBrushes) + gPeekBrushes = gTotalBrushes; +#endif + + return Brush; +} + +//======================================================================================= +// FreeBrush +//======================================================================================= +void FreeBrush(GBSP_Brush *Brush) +{ + int32 i; + + for (i=0 ; iNumSides ; i++) + if (Brush->Sides[i].Poly) + FreePoly(Brush->Sides[i].Poly); + +#ifdef SHOW_DEBUG_STATS + gTotalBrushes--; +#endif + + geRam_Free(Brush); +} + +//======================================================================================= +// FreeBrushList +//======================================================================================= +void FreeBrushList(GBSP_Brush *Brushes) +{ + GBSP_Brush *Next; + + for ( ; Brushes ; Brushes = Next) + { + Next = Brushes->Next; + + FreeBrush(Brushes); + } +} + +void ShowBrushHeap(void) +{ + GHook.Printf("Active Brushes : %5i \n", gTotalBrushes); + GHook.Printf("Peek Brushes : %5i \n", gPeekBrushes); +} + +#define BOGUS_SIDES 256 +//======================================================================================= +// CopyBrush +//======================================================================================= +GBSP_Brush *CopyBrush(GBSP_Brush *Brush) +{ + GBSP_Brush *NewBrush; + int32 Size; + int32 i; + + if (!Brush) + { + GHook.Error("CopyBrush: NULL brush!!!\n"); + return NULL; + } + + if (Brush->NumSides <= 0 || Brush->NumSides >= BOGUS_SIDES) + { + GHook.Error("CopyBrush: Bogus number of sides: %i\n", Brush->NumSides); + return NULL; + } + + Size = (int)&(((GBSP_Brush *)0)->Sides[Brush->NumSides]); + + NewBrush = AllocBrush(Brush->NumSides); + + if (!NewBrush) + { + GHook.Error("CopyBrush: Out of memory for brush.\n"); + return NULL; + } + + memcpy (NewBrush, Brush, Size); + + for (i=0 ; iNumSides ; i++) + { + if (!Brush->Sides[i].Poly) + continue; + + if (Brush->Sides[i].Poly->NumVerts < 0 || Brush->Sides[i].Poly->NumVerts > 256) + { + GHook.Error("CopyBrush: Bad number of verts in poly: %i.\n", Brush->Sides[i].Poly->NumVerts); + return NULL; + } + + //if (!CopyPoly(Brush->Sides[i].Poly, &NewBrush->Sides[i].Poly)) + NewBrush->Sides[i].Poly = CopyPoly2(Brush->Sides[i].Poly); + if (!NewBrush->Sides[i].Poly) + { + GHook.Error("Error copying brush.\n"); + return NULL; + } + } + + return NewBrush; +} + +//======================================================================================= +// BoundBrush +//======================================================================================= +void BoundBrush(GBSP_Brush *Brush) +{ + int32 i, j; + GBSP_Poly *p; + + ClearBounds (&Brush->Mins, &Brush->Maxs); + + for (i=0 ; iNumSides ; i++) + { + p = Brush->Sides[i].Poly; + + if (!p) + continue; + + for (j=0 ; jNumVerts ; j++) + AddPointToBounds(&p->Verts[j], &Brush->Mins, &Brush->Maxs); + } +} + +//======================================================================================= +// AddBrushListToTail +//======================================================================================= +GBSP_Brush *AddBrushListToTail(GBSP_Brush *List, GBSP_Brush *Tail) +{ + GBSP_Brush *Walk, *Next; + + for (Walk=List ; Walk ; Walk=Next) + { // add to end of list + Next = Walk->Next; + Walk->Next = NULL; + Tail->Next = Walk; + Tail = Walk; + } + + return Tail; +} + +//======================================================================================= +// CountBrushList +//======================================================================================= +int32 CountBrushList(GBSP_Brush *Brushes) +{ + int32 c; + + c = 0; + + for ( ; Brushes ; Brushes = Brushes->Next) + c++; + + return c; +} + +//======================================================================================= +// RemoveBrushList +//======================================================================================= +GBSP_Brush *RemoveBrushList(GBSP_Brush *List, GBSP_Brush *Remove) +{ + GBSP_Brush *NewList; + GBSP_Brush *Next; + + NewList = NULL; + + for ( ; List ; List = Next) + { + Next = List->Next; + + if (List == Remove) + { + FreeBrush(List); + continue; + } + + List->Next = NewList; + NewList = List; + } + + return NewList; +} + +//======================================================================================= +// BrushVolume +//======================================================================================= +geFloat BrushVolume(GBSP_Brush *Brush) +{ + int32 i; + GBSP_Poly *p; + geVec3d Corner; + geFloat d, Area, Volume; + GBSP_Plane Plane; + + if (!Brush) + return 0.0f; + + p = NULL; + for (i=0 ; iNumSides ; i++) + { + p = Brush->Sides[i].Poly; + if (p) + break; + } + if (!p) + return 0.0f; + + geVec3d_Copy(&p->Verts[0], &Corner); + + Volume = 0.0f; + for ( ; iNumSides ; i++) + { + p = Brush->Sides[i].Poly; + if (!p) + continue; + + Plane = Planes[Brush->Sides[i].PlaneNum]; + + if (Brush->Sides[i].PlaneSide) + PlaneInverse(&Plane); + + d = -(geVec3d_DotProduct(&Corner, &Plane.Normal) - Plane.Dist); + Area = PolyArea(p); + Volume += d*Area; + } + + Volume /= 3.0f; + return Volume; +} + +//======================================================================================= +// CreateBrushPolys +//======================================================================================= +void CreateBrushPolys(GBSP_Brush *Brush) +{ + int32 i, j; + GBSP_Poly *p; + GBSP_Side *Side; + GBSP_Plane Plane, *pPlane; + + for (i=0 ; iNumSides ; i++) + { + Side = &Brush->Sides[i]; + Plane = Planes[Side->PlaneNum]; + Plane.Type = PLANE_ANY; + + if (Side->PlaneSide) + PlaneInverse(&Plane); + + p = CreatePolyFromPlane(&Plane); + + for (j=0 ; jNumSides && p; j++) + { + if (i == j) + continue; + + pPlane = &Planes[Brush->Sides[j].PlaneNum]; + + ClipPolyEpsilon(p, 0.0f, pPlane, !Brush->Sides[j].PlaneSide, &p); + } + + Side->Poly = p; + } + + BoundBrush(Brush); +} + +//======================================================================================= +// BrushFromBounds +//======================================================================================= +GBSP_Brush *BrushFromBounds (geVec3d *Mins, geVec3d *Maxs) +{ + GBSP_Brush *b; + int32 i; + GBSP_Plane Plane; + int32 Side; + + b = AllocBrush(6); + b->NumSides = 6; + + for (i=0 ; i<3 ; i++) + { + geVec3d_Clear(&Plane.Normal); + VectorToSUB(Plane.Normal, i) = 1.0f; + Plane.Dist = VectorToSUB(*Maxs, i)+1; + b->Sides[i].PlaneNum = FindPlane(&Plane, &Side); + b->Sides[i].PlaneSide = (uint8)Side; + + VectorToSUB(Plane.Normal, i) = -1.0f; + Plane.Dist = -(VectorToSUB(*Mins, i)-1); + b->Sides[i+3].PlaneNum = FindPlane(&Plane, &Side); + b->Sides[i+3].PlaneSide = (uint8)Side; + } + + CreateBrushPolys(b); + + return b; +} + +//======================================================================================= +// BrushMostlyOnSide +//======================================================================================= +int32 BrushMostlyOnSide(GBSP_Brush *Brush, GBSP_Plane *Plane) +{ + int32 i, j; + GBSP_Poly *p; + geFloat d, Max; + int32 Side; + + Max = 0.0f; + Side = PSIDE_FRONT; + + for (i=0 ; iNumSides ; i++) + { + p = Brush->Sides[i].Poly; + if (!p) + continue; + + for (j=0 ; jNumVerts ; j++) + { + d = geVec3d_DotProduct(&p->Verts[j], &Plane->Normal) - Plane->Dist; + if (d > Max) + { + Max = d; + Side = PSIDE_FRONT; + } + if (-d > Max) + { + Max = -d; + Side = PSIDE_BACK; + } + } + } + + return Side; +} + +//======================================================================================= +// CheckBrush +//======================================================================================= +geBoolean CheckBrush(GBSP_Brush *Brush) +{ + int32 j; + + if (Brush->NumSides < 3) + return GE_FALSE; + + for (j=0 ; j<3 ; j++) + { + if (VectorToSUB(Brush->Mins, j) <= -MIN_MAX_BOUNDS || VectorToSUB(Brush->Maxs, j) >= MIN_MAX_BOUNDS) + return GE_FALSE; + } + + return GE_TRUE; +} + +//======================================================================================= +// SplitBrush +//======================================================================================= +void SplitBrush(GBSP_Brush *Brush, int32 PNum, int32 PSide, uint8 MidFlags, geBoolean Visible, GBSP_Brush **Front, GBSP_Brush **Back) +{ + int32 i, j; + GBSP_Side *pSide; + GBSP_Poly *p, *MidPoly; + GBSP_Plane Plane, *Plane2; + geFloat d, FrontD, BackD; + GBSP_Plane *pPlane1; + GBSP_Brush *Brushes[2]; + + pPlane1 = &Planes[PNum]; + + Plane = *pPlane1; + Plane.Type = PLANE_ANY; + + if (PSide) + PlaneInverse(&Plane); + + *Front = *Back = NULL; + + // Check all points + FrontD = BackD = 0.0f; + + for (i=0 ; iNumSides ; i++) + { + geVec3d *pVert; + + p = Brush->Sides[i].Poly; + + if (!p) + continue; + + for (pVert = p->Verts, j=0 ; jNumVerts ; j++, pVert++) + { + #if 1 + d = Plane_PointDistanceFast(pPlane1, pVert); + + if (PSide) + d = -d; + #else + d = geVec3d_DotProduct(pVert, &Plane.Normal) - Plane.Dist; + #endif + + if (d > FrontD) + FrontD = d; + else if (d < BackD) + BackD = d; + } + } + + if (FrontD < 0.1f) + { + *Back = CopyBrush(Brush); + return; + } + + if (BackD > -0.1f) + { + *Front = CopyBrush(Brush); + return; + } + + // create a new poly from the split plane + p = CreatePolyFromPlane(&Plane); + + if (!p) + { + GHook.Error("Could not create poly.\n"); + } + + // Clip the poly by all the planes of the brush being split + for (i=0 ; iNumSides && p ; i++) + { + Plane2 = &Planes[Brush->Sides[i].PlaneNum]; + + ClipPolyEpsilon(p, 0.0f, Plane2, !(Brush->Sides[i].PlaneSide), &p); + } + + if (!p || PolyIsTiny (p) ) + { + int32 Side; + + Side = BrushMostlyOnSide(Brush, &Plane); + + if (Side == PSIDE_FRONT) + *Front = CopyBrush(Brush); + if (Side == PSIDE_BACK) + *Back = CopyBrush(Brush); + return; + } + + // Store the mid poly + MidPoly = p; + + // Create 2 brushes + for (i=0 ; i<2 ; i++) + { + Brushes[i] = AllocBrush(Brush->NumSides+1); + + if (!Brushes[i]) + { + GHook.Error("SplitBrush: Out of memory for brush.\n"); + //return NULL; + } + + Brushes[i]->Original = Brush->Original; + } + + // Split all the current polys of the brush being split, and distribute it to the other 2 brushes + pSide = Brush->Sides; + for (i=0 ; iNumSides ; i++, pSide++) + { + GBSP_Poly *Poly[2]; + + if (!pSide->Poly) + continue; + + if (!CopyPoly (pSide->Poly, &p)) + { + GHook.Error("Error Copying poly...\n"); + } + + if (!SplitPolyEpsilon(p, 0.0f, &Plane, &Poly[0], &Poly[1], GE_FALSE)) + { + GHook.Error("Error Splitting poly...\n"); + } + + for (j=0 ; j<2 ; j++) + { + GBSP_Side *pDestSide; + + if (!Poly[j]) + continue; + + #if 0 + if (PolyIsTiny(Poly[j])) + { + FreePoly(Poly[j]); + continue; + } + #endif + + pDestSide = &Brushes[j]->Sides[Brushes[j]->NumSides]; + Brushes[j]->NumSides++; + + *pDestSide = *pSide; + + pDestSide->Poly = Poly[j]; + pDestSide->Flags &= ~SIDE_TESTED; + } + } + + for (i=0 ; i<2 ; i++) + { + BoundBrush(Brushes[i]); + + if (!CheckBrush(Brushes[i])) + { + FreeBrush(Brushes[i]); + Brushes[i] = NULL; + } + + } + + + if (!(Brushes[0] && Brushes[1]) ) + { + + if (!Brushes[0] && !Brushes[1]) + GHook.Printf("Split removed brush\n"); + else + GHook.Printf("Split not on both sides\n"); + + if (Brushes[0]) + { + FreeBrush(Brushes[0]); + *Front = CopyBrush(Brush); + } + if (Brushes[1]) + { + FreeBrush(Brushes[1]); + *Back = CopyBrush(Brush); + } + return; + } + + for (i=0 ; i<2 ; i++) + { + pSide = &Brushes[i]->Sides[Brushes[i]->NumSides]; + Brushes[i]->NumSides++; + + pSide->PlaneNum = PNum; + pSide->PlaneSide = (uint8)PSide; + + if (Visible) + pSide->Flags |= SIDE_VISIBLE; + + pSide->Flags &= ~SIDE_TESTED; + + pSide->Flags |= MidFlags; + + if (!i) + { + pSide->PlaneSide = !pSide->PlaneSide; + + if (!ReversePoly(MidPoly, &pSide->Poly)) + GHook.Error("Error copying poly.\n"); + } + else + pSide->Poly = MidPoly; + } + + { + geFloat v1; + int32 i; + + for (i=0 ; i<2 ; i++) + { + v1 = BrushVolume(Brushes[i]); + if (v1 < 1.0f) + { + FreeBrush(Brushes[i]); + Brushes[i] = NULL; + //GHook.Printf("Tiny volume after clip\n"); + } + } + } + + if (!Brushes[0] && !Brushes[1]) + { + GHook.Error("SplitBrush: Brush was not split.\n"); + } + + *Front = Brushes[0]; + *Back = Brushes[1]; +} + +//======================================================================================= +// SubtractBrush +// Result = a - b. a, and b are NOT freed. Result could = instance of a (a is NOT ref'd) +//======================================================================================= +GBSP_Brush *SubtractBrush(GBSP_Brush *a, GBSP_Brush *b) +{ + GBSP_Brush *Outside, *Inside; + GBSP_Brush *Front, *Back; + int32 i; + + Inside = a; // Default a being inside b + Outside = NULL; + + // Splitting the inside list against each plane of brush b, only keeping peices that fall on the + // outside + for (i=0 ; iNumSides && Inside; i++) + { + SplitBrush(Inside, b->Sides[i].PlaneNum, b->Sides[i].PlaneSide, SIDE_NODE, GE_FALSE, &Front, &Back); + + if (Inside != a) // Make sure we don't free a, but free all other fragments + FreeBrush(Inside); + + if (Front) // Kepp all front sides, and put them in the Outside list + { + Front->Next = Outside; + Outside = Front; + } + + Inside = Back; + } + + if (!Inside) + { + FreeBrushList(Outside); + return a; // Nothing on inside list, so cancel all cuts, and return original + } + + FreeBrush(Inside); // Free all inside fragments + + return Outside; // Return what was on the outside +} + +//======================================================================================= +// BrushCanBite +//======================================================================================= +geBoolean BrushCanBite(GBSP_Brush *Brush1, GBSP_Brush *Brush2) +{ + uint32 c1, c2; + + c1 = Brush1->Original->Contents; + c2 = Brush2->Original->Contents; + + if ((c1 & BSP_CONTENTS_DETAIL2) && !(c2 & BSP_CONTENTS_DETAIL2) ) + return GE_FALSE; + + if ((c1|c2) & BSP_CONTENTS_FLOCKING) + return GE_FALSE; + + if (c1 & BSP_CONTENTS_SOLID2) + return GE_TRUE; + + return GE_FALSE; +} + +//======================================================================================= +// BrushesOverlap +//======================================================================================= +geBoolean BrushesOverlap(GBSP_Brush *Brush1, GBSP_Brush *Brush2) +{ + int32 i, j; + + // Check the boxs of the brushes first + for (i=0 ; i<3 ; i++) + { + if (VectorToSUB(Brush1->Mins, i) >= VectorToSUB(Brush2->Maxs, i) || + VectorToSUB(Brush1->Maxs, i) <= VectorToSUB(Brush2->Mins, i)) + return GE_FALSE; + } + + for (i=0 ; iNumSides ; i++) + { + for (j=0 ; jNumSides ; j++) + { + if (Brush1->Sides[i].PlaneNum == Brush2->Sides[j].PlaneNum && + Brush1->Sides[i].PlaneSide != Brush2->Sides[j].PlaneSide) + return GE_FALSE; // Since brushes are convex, opposite planes result in no overlap + } + } + + return GE_TRUE; +} + +//======================================================================================= +// CSGBrushes +//======================================================================================= +GBSP_Brush *CSGBrushes (GBSP_Brush *Head) +{ + GBSP_Brush *b1, *b2, *Next; + GBSP_Brush *Tail; + GBSP_Brush *Keep; + GBSP_Brush *Sub, *Sub2; + int32 c1, c2; + + if (Verbose) + { + GHook.Printf ("---- CSGBrushes ----\n"); + GHook.Printf ("Num brushes before CSG : %5i\n", CountBrushList (Head)); + } + + Keep = NULL; + +NewList: + + if (!Head) + return NULL; + + for (Tail=Head ; Tail->Next ; Tail=Tail->Next); + + for (b1=Head ; b1 ; b1=Next) + { + Next = b1->Next; + + if (CancelRequest) + break; + + for (b2=b1->Next ; b2 ; b2 = b2->Next) + { + if (CancelRequest) + continue; // Don't stop, let it finish this round, so things get cleaned up... + + if (!BrushesOverlap(b1, b2)) + continue; + + Sub = NULL; + Sub2 = NULL; + c1 = 999999; + c2 = 999999; + + if (BrushCanBite(b2, b1)) + { + Sub = SubtractBrush(b1, b2); + + if (Sub == b1) + continue; + + if (!Sub) + { + Head = RemoveBrushList(b1, b1); + goto NewList; + } + c1 = CountBrushList (Sub); + } + + if (BrushCanBite(b1, b2)) + { + Sub2 = SubtractBrush(b2, b1); + + if (Sub2 == b2) + continue; + + if (!Sub2) + { + FreeBrushList(Sub); + Head = RemoveBrushList(b1, b2); + goto NewList; + } + c2 = CountBrushList(Sub2); + } + + if (!Sub && !Sub2) + continue; + + if (c1 > 4 && c2 > 4) + { + if (Sub2) + FreeBrushList(Sub2); + if (Sub) + FreeBrushList(Sub); + continue; + } + + + if (c1 < c2) + { + if (Sub2) + FreeBrushList(Sub2); + Tail = AddBrushListToTail (Sub, Tail); + Head = RemoveBrushList(b1, b1); + goto NewList; + } + else + { + if (Sub) + FreeBrushList(Sub); + Tail = AddBrushListToTail (Sub2, Tail); + Head = RemoveBrushList(b1, b2); + goto NewList; + } + + + } + + if (!b2) + { + b1->Next = Keep; + Keep = b1; + } + } + + if (Verbose) + GHook.Printf("Num brushes after CSG : %5i\n", CountBrushList (Keep)); + + return Keep; +} + +// +// 3dt output code +// + +//===================================================================================== +// OutputBrushes +//===================================================================================== +geBoolean OutputBrushes(char *FileName, GBSP_Brush *Brushes) +{ + FILE *f; + int32 i, v; + geVec3d *Verts; + GBSP_Brush *Brush; + GBSP_Side *Side; + + f = fopen(FileName, "wb"); + + if (!f) + return GE_FALSE; + + // Write out the header + fprintf(f, "3dtVersion 1.6\n"); + fprintf(f, "PalLoc gedit.pal\n"); + fprintf(f, "TexLoc gedit.txl\n"); + + fprintf(f, "NumBrushes %i\n", CountBrushList(Brushes)); + fprintf(f, "NumEntities 0\n"); + fprintf(f, "NumModels 0\n"); + fprintf(f, "NumGroups 0\n"); + + for (Brush = Brushes; Brush; Brush = Brush->Next) + { + fprintf(f, "Brush blue\n"); + fprintf(f, " Flags 0\n"); + fprintf(f, " ModelId 0\n"); + fprintf(f, " GroupId 0\n"); + fprintf(f, " HullSize 0.0\n"); + + fprintf(f, " BrushFaces %i\n", Brush->NumSides); + + for (i=0; i< Brush->NumSides; i++) + { + Side = &Brush->Sides[i]; + + fprintf(f, " NumPoints %i\n", Side->Poly->NumVerts); + Verts = Side->Poly->Verts; + for (v=0; v< Side->Poly->NumVerts; v++) + { + fprintf(f, " Vec3d %f %f %f\n", Verts[v].X, Verts[v].Y, Verts[v].Z); + } + fprintf(f, " TexInfo Rotate 0 Shift 0 0 Scale 1.000000 1.000000 Name blue\n"); + } + } + + fprintf(f, "Class CEntList\n"); + fprintf(f, "EntCount 0\n"); + fprintf(f, "CurCount 0\n"); + + fclose (f); + + return GE_TRUE; +} + +//===================================================================================== +// OutputMapBrushes +//===================================================================================== +geBoolean OutputMapBrushes(char *FileName, MAP_Brush *Brushes) +{ + FILE *f; + int32 i, v; + geVec3d *Verts; + MAP_Brush *Brush; + GBSP_Side *Side; + + f = fopen(FileName, "wb"); + + if (!f) + return GE_FALSE; + + // Write out the header + fprintf(f, "3dtVersion 1.6\n"); + fprintf(f, "PalLoc gedit.pal\n"); + fprintf(f, "TexLoc gedit.txl\n"); + + fprintf(f, "NumBrushes %i\n", CountMapBrushList(Brushes)); + fprintf(f, "NumEntities 0\n"); + fprintf(f, "NumModels 0\n"); + fprintf(f, "NumGroups 0\n"); + + for (Brush = Brushes; Brush; Brush = Brush->Next) + { + fprintf(f, "Brush blue\n"); + fprintf(f, " Flags 0\n"); + fprintf(f, " ModelId 0\n"); + fprintf(f, " GroupId 0\n"); + fprintf(f, " HullSize 0.0\n"); + + fprintf(f, " BrushFaces %i\n", Brush->NumSides); + + for (i=0; i< Brush->NumSides; i++) + { + Side = &Brush->OriginalSides[i]; + + fprintf(f, " NumPoints %i\n", Side->Poly->NumVerts); + Verts = Side->Poly->Verts; + for (v=0; v< Side->Poly->NumVerts; v++) + { + fprintf(f, " Vec3d %f %f %f\n", Verts[v].X, Verts[v].Y, Verts[v].Z); + } + fprintf(f, " TexInfo Rotate 0 Shift 0 0 Scale 1.000000 1.000000 Name blue\n"); + } + } + + fprintf(f, "Class CEntList\n"); + fprintf(f, "EntCount 0\n"); + fprintf(f, "CurCount 0\n"); + + fclose (f); + + return GE_TRUE; +} diff --git a/GBSPLib/Bsp.h b/GBSPLib/Bsp.h new file mode 100644 index 0000000..d2fbdde --- /dev/null +++ b/GBSPLib/Bsp.h @@ -0,0 +1,267 @@ +/****************************************************************************************/ +/* BSP.h */ +/* */ +/* Author: John Pollard */ +/* Description: Module distributes code to all the other modules */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef BSP_H +#define BSP_H + +#include + +#include "GBSPLib.h" + +//==================================================================================== +// Global defines +//==================================================================================== +#define MAX_BSP_MODELS 2048*2 + +#define PSIDE_FRONT 1 +#define PSIDE_BACK 2 +#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK) +#define PSIDE_FACING 4 + +#define PLANENUM_LEAF -1 + +#define MAX_BSP_PLANES 32000*2 + +#define DIST_EPSILON (geFloat)0.01 +#define ANGLE_EPSILON (geFloat)0.00001 + +//==================================================================================== +// Global sructures +//==================================================================================== + +struct _GBSP_Portal; + +typedef struct GBSP_Brush GBSP_Brush; +typedef struct GBSP_Side GBSP_Side; + +typedef struct +{ + int32 NumVerts; + geVec3d *Verts; +} GBSP_Poly; + + +typedef struct _GBSP_Face +{ + _GBSP_Face *Next; + _GBSP_Face *Original; + GBSP_Poly *Poly; + int32 Contents[2]; + int32 TexInfo; + int32 PlaneNum; + int32 PlaneSide; + + int32 Entity; // Originating entity + + uint8 Visible; + + // For GFX file saving + int32 OutputNum; + + int32 *IndexVerts; + int32 FirstIndexVert; + int32 NumIndexVerts; + + _GBSP_Portal *Portal; + _GBSP_Face *Split[2]; + _GBSP_Face *Merged; +} GBSP_Face; + +typedef struct +{ + geVec3d Normal; + geFloat Dist; + int32 Type; +} GBSP_Plane; + +typedef struct +{ + int32 Contents; // Contents of leaf +} GBSP_Leaf; + +typedef struct _GBSP_Node +{ + // Info for this node as a node or leaf + int32 PlaneNum; // -1 if a leaf + int32 PlaneSide; // CHANGE1!!! + int32 Contents; // Contents node/leaf + GBSP_Face *Faces; // Faces on this node + _GBSP_Node *Children[2]; // Front and back child + _GBSP_Node *Parent; // Parent of this node + geVec3d Mins; // Current BBox of node + geVec3d Maxs; + + // Info for this node as a leaf + _GBSP_Portal *Portals; // Portals on this leaf + int32 NumLeafFaces; // Number of faces touching this leaf + GBSP_Face **LeafFaces; // Pointer to Faces touching this leaf + int32 CurrentFill; // For the outside filling stage + int32 Entity; // 1 if entity touching leaf + int32 Occupied; // FIXME: Can use Entity!!! + int32 PortalLeafNum; // For portal saving + + geBoolean Detail; + int32 Cluster; + int32 Area; // Area number, 0 == invalid area + + GBSP_Brush *Volume; + GBSP_Side *Side; + GBSP_Brush *BrushList; + + // For GFX file saving + int32 ChildrenID[2]; + int32 FirstFace; + int32 NumFaces; + int32 FirstPortal; + int32 NumPortals; + + int32 FirstSide; // For bevel bbox clipping + int32 NumSides; + +} GBSP_Node; + +typedef struct +{ + int32 PlaneNum; + int32 PlaneSide; +} GBSP_LeafSide; + +typedef struct _GBSP_Node2 +{ + _GBSP_Node2 *Children[2]; + int32 PlaneNum; // -1 == Leaf + + // For leafs + int32 Contents; +} GBSP_Node2; + +// Side flags... +#define SIDE_HINT (1<<0) // Side is a hint side +#define SIDE_SHEET (1<<1) // Side is a sheet (only visible face in a sheet contents) +#define SIDE_VISIBLE (1<<2) // +#define SIDE_TESTED (1<<3) // +#define SIDE_NODE (1<<4) // + +typedef struct GBSP_Side +{ + GBSP_Poly *Poly; + + int32 PlaneNum; + uint8 PlaneSide; + + int32 TexInfo; + + uint8 Flags; +} GBSP_Side; + +typedef struct _GBSP_Portal +{ + GBSP_Poly *Poly; // Convex poly that holds the shape of the portal + GBSP_Node *Nodes[2]; // Node on each side of the portal + _GBSP_Portal *Next[2]; // Next portal for each node + int32 PlaneNum; + + GBSP_Node *OnNode; + GBSP_Face *Face[2]; + GBSP_Side *Side; + uint8 SideFound; +} GBSP_Portal; + +typedef struct MAP_Brush MAP_Brush; + +typedef struct +{ + GBSP_Node *RootNode[2]; // 0 = DrawHull, 1 = Bevel ClipHull + + geVec3d Origin; + + GBSP_Node OutsideNode; // So each model can have it's own outside node + + geVec3d Mins; + geVec3d Maxs; + + // For GFX File saving + int32 RootNodeID[2]; + int32 FirstFace; + int32 NumFaces; + int32 FirstLeaf; + int32 NumLeafs; + int32 FirstCluster; + int32 NumClusters; + int32 NumSolidLeafs; // So we can skip over solid leafs for vis stuff + + // Temorary area portal stuff + geBoolean IsAreaPortal; + int32 Areas[2]; // Used when this model is an area sperator (AreaPortal) + +} GBSP_Model; + +//==================================================================================== +// Globals +//==================================================================================== +extern GBSP_Model BSPModels[MAX_BSP_MODELS]; +extern int32 NumBSPModels; + +extern geBoolean Verbose; +extern geBoolean OriginalVerbose; +extern geBoolean EntityVerbose; + +#define MAX_WELDED_VERTS 64000*2 + +// Defined in TJunct.cpp +extern int32 NumWeldedVerts; +extern int32 TotalIndexVerts; +extern geVec3d WeldedVerts[MAX_WELDED_VERTS]; + +geBoolean FixModelTJunctions(void); + +//==================================================================================== +// Global functions +//==================================================================================== +geBoolean CreateBSP(char *FileName, BspParms *Parms); +geBoolean UpdateEntities(char *MapName, char *BSPName); + +GBSP_Node *AllocNode(void); +void FreeNode(GBSP_Node *Node); + +geBoolean FreeAllGBSPData(void); +void CleanupGBSP(void); + +// +// Planes +// + +extern GBSP_Plane Planes[MAX_BSP_PLANES]; +extern int32 NumPlanes; + +void PlaneFromVerts(geVec3d *Verts, GBSP_Plane *Plane); +void SidePlane(GBSP_Plane *Plane, int32 *Side); +geBoolean PlaneEqual(GBSP_Plane *Plane1, GBSP_Plane *Plane2); +geBoolean PlaneCompare(GBSP_Plane *Plane1, GBSP_Plane *Plane2); +void SnapVector(geVec3d *Normal); +geFloat RoundInt(geFloat In); +void SnapPlane(geVec3d *Normal, geFloat *Dist); +void PlaneInverse(GBSP_Plane *Plane); +int32 FindPlane(GBSP_Plane *Plane, int32 *Side); +void PlaneInverse(GBSP_Plane *Plane); +geFloat _fastcall Plane_PointDistanceFast(GBSP_Plane *Plane, geVec3d *Point); + +#endif diff --git a/GBSPLib/Bsp2.cpp b/GBSPLib/Bsp2.cpp new file mode 100644 index 0000000..27f9f41 --- /dev/null +++ b/GBSPLib/Bsp2.cpp @@ -0,0 +1,1521 @@ +/****************************************************************************************/ +/* BSP2.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Code to actually build the tree */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "Mathlib.h" +#include "Poly.h" +#include "BSP.h" +#include "GBSPFile.h" +#include "Map.h" +#include "Portals.h" +#include "Texture.h" +#include "Fill.h" +#include "Brush2.h" + +#include "Vec3d.h" +#include "Ram.h" + +#define USE_VOLUMES + +geVec3d TreeMins; +geVec3d TreeMaxs; + +geFloat MicroVolume = 0.1f; +int32 NumVisNodes, NumNonVisNodes; + +extern int32 NumMerged; +extern int32 NumSubdivided; + +int32 NumMakeFaces = 0; + +#define PLANESIDE_EPSILON 0.001f + +//======================================================================================= +// VisibleContents +//======================================================================================= +uint32 VisibleContents(uint32 Contents) +{ + int32 j; + uint32 MajorContents; + + if (!Contents) + return 0; + + // Only check visible contents + Contents &= BSP_VISIBLE_CONTENTS; + + // Return the strongest one, return the first lsb + for (j=0; j<32; j++) + { + MajorContents = (Contents & (1<Nodes[0]->Contents & BSP_CONTENTS_SHEET) && (p->Nodes[1]->Contents & BSP_CONTENTS_SHEET)) + { + // The contents are intersecting sheets, so or them together + VisContents = p->Nodes[0]->Contents | p->Nodes[1]->Contents; + } + else + { + // Make sure the contents on both sides are not the same + VisContents = p->Nodes[0]->Contents ^ p->Nodes[1]->Contents; + } + + // There must be a visible contents on at least one side of the portal... + MajorContents = VisibleContents(VisContents); + + if (!MajorContents) + return; + + PlaneNum = p->OnNode->PlaneNum; + BestSide = NULL; + BestDot = 0.0f; + + for (j=0 ; j<2 ; j++) + { + GBSP_Node *Node; + + Node = p->Nodes[j]; + p1 = &Planes[p->OnNode->PlaneNum]; + + for (Brush=Node->BrushList ; Brush ; Brush=Brush->Next) + { + MAP_Brush *MapBrush; + GBSP_Side *pSide; + + MapBrush = Brush->Original; + + // Only use the brush that contains a major contents (solid) + if (!(MapBrush->Contents & MajorContents)) + continue; + + pSide = MapBrush->OriginalSides; + + for (i=0 ; iNumSides ; i++, pSide++) + { + if (pSide->Flags & SIDE_NODE) + continue; // Side not visible (result of a csg'd topbrush) + + // First, Try an exact match + if (pSide->PlaneNum == PlaneNum) + { + BestSide = pSide; + goto GotSide; + } + // In the mean time, try for the closest match + p2 = &Planes[pSide->PlaneNum]; + Dot = geVec3d_DotProduct(&p1->Normal, &p2->Normal); + if (Dot > BestDot) + { + BestDot = Dot; + BestSide = pSide; + } + } + + } + + } + + GotSide: + + if (!BestSide) + GHook.Printf("WARNING: Could not map portal to original brush...\n"); + + p->SideFound = GE_TRUE; + p->Side = BestSide; +} + +//======================================================================================= +// MarkVisibleSides_r +//======================================================================================= +void MarkVisibleSides_r (GBSP_Node *Node) +{ + GBSP_Portal *p; + int32 s; + + // Recurse to leafs + if (Node->PlaneNum != PLANENUM_LEAF) + { + MarkVisibleSides_r (Node->Children[0]); + MarkVisibleSides_r (Node->Children[1]); + return; + } + + // Empty (air) leafs don't have faces + if (!Node->Contents) + return; + + for (p=Node->Portals ; p ; p = p->Next[s]) + { + s = (p->Nodes[1] == Node); + + if (!p->OnNode) + continue; // Outside node (assert for it here!!!) + + if (!p->SideFound) + FindPortalSide (p, s); + + if (p->Side) + p->Side->Flags |= SIDE_VISIBLE; + + #if 1 + if (p->Side) + { + if (!(p->Nodes[!s]->Contents & BSP_CONTENTS_SOLID2) && + (p->Nodes[s]->Contents & BSP_CONTENTS_SHEET) && + !(p->Side->Flags & SIDE_SHEET)) + { + p->Side->Flags &= ~SIDE_VISIBLE; + p->Side = NULL; + p->SideFound = GE_TRUE; // Don't look for this side again!!! + } + } + #endif + } + +} + +//======================================================================================= +// MarkVisibleSides +// Looks at all the portals, and marks leaf boundrys that seperate different contents +// into faces. +//======================================================================================= +void MarkVisibleSides(GBSP_Node *Node, MAP_Brush *Brushes) +{ + int32 j; + MAP_Brush *Brush; + int32 NumSides; + + if (Verbose) + GHook.Printf("--- Map Portals to Brushes ---\n"); + + // Clear all the visible flags + for (Brush = Brushes; Brush; Brush = Brush->Next) + { + NumSides = Brush->NumSides; + + for (j=0 ; jOriginalSides[j].Flags &= ~SIDE_VISIBLE; + } + + // Set visible flags on the sides that are used by portals + MarkVisibleSides_r (Node); +} + +//======================================================================================= +// BoxOnPlaneSide +//======================================================================================= +int32 BoxOnPlaneSide(geVec3d *Mins, geVec3d *Maxs, GBSP_Plane *Plane) +{ + int32 Side; + int32 i; + geVec3d Corners[2]; + geFloat Dist1, Dist2; + + if (Plane->Type < 3) + { + Side = 0; + if (VectorToSUB(*Maxs, Plane->Type) > Plane->Dist+PLANESIDE_EPSILON) + Side |= PSIDE_FRONT; + if (VectorToSUB(*Mins, Plane->Type) < Plane->Dist-PLANESIDE_EPSILON) + Side |= PSIDE_BACK; + return Side; + } + + for (i=0 ; i<3 ; i++) + { + if (VectorToSUB(Plane->Normal, i) < 0) + { + VectorToSUB(Corners[0], i) = VectorToSUB(*Mins, i); + VectorToSUB(Corners[1], i) = VectorToSUB(*Maxs, i); + } + else + { + VectorToSUB(Corners[1], i) = VectorToSUB(*Mins, i); + VectorToSUB(Corners[0], i) = VectorToSUB(*Maxs, i); + } + } + + Dist1 = geVec3d_DotProduct(&Plane->Normal, &Corners[0]) - Plane->Dist; + Dist2 = geVec3d_DotProduct(&Plane->Normal, &Corners[1]) - Plane->Dist; + Side = 0; + if (Dist1 >= PLANESIDE_EPSILON) + Side = PSIDE_FRONT; + if (Dist2 < PLANESIDE_EPSILON) + Side |= PSIDE_BACK; + + return Side; +} + +//======================================================================================= +// MakeBSPBrushes +// Converts map brushes into useable bsp brushes +//======================================================================================= +GBSP_Brush *MakeBSPBrushes(MAP_Brush *MapBrushes) +{ + MAP_Brush *MapBrush; + GBSP_Brush *NewBrush, *NewBrushes; + int32 j, NumSides; + int32 Vis; + + NewBrushes = NULL; + + for (MapBrush = MapBrushes; MapBrush; MapBrush = MapBrush->Next) + { + NumSides = MapBrush->NumSides; + + if (!NumSides) + continue; + + Vis = 0; + for (j=0; j< NumSides; j++) + { + if (MapBrush->OriginalSides[j].Poly) + Vis++; + } + + if (!Vis) + continue; + + NewBrush = AllocBrush(NumSides); + + NewBrush->Original = MapBrush; + NewBrush->NumSides = NumSides; + + memcpy (NewBrush->Sides, MapBrush->OriginalSides, NumSides*sizeof(GBSP_Side)); + + for (j=0 ; jOriginalSides[j].Flags & SIDE_HINT) + NewBrush->Sides[j].Flags |= SIDE_VISIBLE; + + if (NewBrush->Sides[j].Poly) + { + CopyPoly(NewBrush->Sides[j].Poly, &NewBrush->Sides[j].Poly); + } + } + + NewBrush->Mins = MapBrush->Mins; + NewBrush->Maxs = MapBrush->Maxs; + + BoundBrush (NewBrush); + + if (!CheckBrush(NewBrush)) + { + GHook.Error("MakeBSPBrushes: Bad brush.\n"); + continue; + } + + NewBrush->Next = NewBrushes; + NewBrushes = NewBrush; + } + + return NewBrushes; +} + +//======================================================================================= +// TestBrushToPlane +//======================================================================================= +int32 TestBrushToPlane( GBSP_Brush *Brush, int32 PlaneNum, int32 PSide, + int32 *NumSplits, geBoolean *HintSplit, int32 *EpsilonBrush) +{ + int32 i, j, Num; + GBSP_Plane *Plane; + int32 s; + GBSP_Poly *p; + geFloat d, FrontD, BackD; + int32 Front, Back; + GBSP_Side *pSide; + + *NumSplits = 0; + *HintSplit = GE_FALSE; + + for (i=0 ; iNumSides ; i++) + { + Num = Brush->Sides[i].PlaneNum; + + if (Num == PlaneNum && !Brush->Sides[i].PlaneSide) + return PSIDE_BACK|PSIDE_FACING; + + if (Num == PlaneNum && Brush->Sides[i].PlaneSide) + return PSIDE_FRONT|PSIDE_FACING; + } + + // See if it's totally on one side or the other + Plane = &Planes[PlaneNum]; + s = BoxOnPlaneSide (&Brush->Mins, &Brush->Maxs, Plane); + + if (s != PSIDE_BOTH) + return s; + + // The brush is split, count the number of splits + FrontD = BackD = 0.0f; + + for (pSide = Brush->Sides, i=0 ; iNumSides ; i++, pSide++) + { + geVec3d *pVert; + uint8 PSide; + + if (pSide->Flags & SIDE_NODE) + continue; + + if (!(pSide->Flags & SIDE_VISIBLE)) + continue; + + p = pSide->Poly; + + if (!p) + continue; + + PSide = pSide->PlaneSide; + + Front = Back = 0; + + for (pVert = p->Verts, j=0 ; jNumVerts; j++, pVert++) + { + #if 1 + d = Plane_PointDistanceFast(Plane, pVert); + #else + d = geVec3d_DotProduct(pVert, &Plane->Normal) - Plane->Dist; + #endif + + if (d > FrontD) + FrontD = d; + else if (d < BackD) + BackD = d; + + if (d > 0.1) + Front = 1; + else if (d < -0.1) + Back = 1; + } + + if (Front && Back) + { + (*NumSplits)++; + if (pSide->Flags & SIDE_HINT) + *HintSplit = GE_TRUE; + } + } + + // Check to see if this split would produce a tiny brush (would result in tiny leafs, bad for vising) + if ( (FrontD > 0.0 && FrontD < 1.0) || (BackD < 0.0 && BackD > -1.0) ) + (*EpsilonBrush)++; + + return s; +} + +//======================================================================================= +// CheckPlaneAgainstParents +// Makes sure no plane gets used twice in the tree, from the children up. +// This would screw up the portals +//======================================================================================= +geBoolean CheckPlaneAgainstParents (int32 PNum, GBSP_Node *Node) +{ + GBSP_Node *p; + + for (p=Node->Parent ; p ; p=p->Parent) + { + if (p->PlaneNum == PNum) + { + GHook.Error ("Tried parent"); + return GE_FALSE; + } + } + + return GE_TRUE; +} + +//======================================================================================= +// CheckPlaneAgainstVolume +// Makes sure that a potential splitter does not make tiny volumes from the parent volume +//======================================================================================= +geBoolean CheckPlaneAgainstVolume (int32 PNum, GBSP_Node *Node) +{ + GBSP_Brush *Front, *Back; + geBoolean Good; + + SplitBrush(Node->Volume, PNum, 0, SIDE_NODE, GE_FALSE, &Front, &Back); + + Good = (Front && Back); + + if (Front) + FreeBrush(Front); + if (Back) + FreeBrush(Back); + + return Good; +} + +//======================================================================================= +// SelectSplitSide +//======================================================================================= +GBSP_Side *SelectSplitSide(GBSP_Brush *Brushes, GBSP_Node *Node) +{ + int32 Value, BestValue; + GBSP_Brush *Brush, *Test; + GBSP_Side *Side, *BestSide; + int32 i, j, Pass, NumPasses; + int32 PNum, PSide; + int32 s; + int32 Front, Back, Both, Facing, Splits; + int32 BSplits; + int32 BestSplits; + int32 EpsilonBrush; + geBoolean HintSplit; + + if (CancelRequest) + return NULL; + + BestSide = NULL; + BestValue = -999999; + BestSplits = 0; + + NumPasses = 4; + for (Pass = 0 ; Pass < NumPasses ; Pass++) + { + for (Brush = Brushes ; Brush ; Brush=Brush->Next) + { + if ( (Pass & 1) && !(Brush->Original->Contents & BSP_CONTENTS_DETAIL2) ) + continue; + if ( !(Pass & 1) && (Brush->Original->Contents & BSP_CONTENTS_DETAIL2) ) + continue; + + for (i=0 ; iNumSides ; i++) + { + Side = &Brush->Sides[i]; + + if (!Side->Poly) + continue; + if (Side->Flags & (SIDE_TESTED|SIDE_NODE)) + continue; + if (!(Side->Flags&SIDE_VISIBLE) && Pass<2) + continue; + + PNum = Side->PlaneNum; + PSide = Side->PlaneSide; + + assert(CheckPlaneAgainstParents (PNum, Node) == GE_TRUE); + + #ifdef USE_VOLUMES + if (!CheckPlaneAgainstVolume (PNum, Node)) + continue; + #endif + + Front = 0; + Back = 0; + Both = 0; + Facing = 0; + Splits = 0; + EpsilonBrush = 0; + + for (Test = Brushes ; Test ; Test=Test->Next) + { + s = TestBrushToPlane(Test, PNum, PSide, &BSplits, &HintSplit, &EpsilonBrush); + + Splits += BSplits; + + if (BSplits && (s&PSIDE_FACING) ) + GHook.Error("PSIDE_FACING with splits\n"); + + Test->TestSide = s; + + if (s & PSIDE_FACING) + { + Facing++; + for (j=0 ; jNumSides ; j++) + { + if (Test->Sides[j].PlaneNum == PNum) + Test->Sides[j].Flags |= SIDE_TESTED; + } + } + if (s & PSIDE_FRONT) + Front++; + if (s & PSIDE_BACK) + Back++; + if (s == PSIDE_BOTH) + Both++; + } + + Value = 5*Facing - 5*Splits - abs(Front-Back); + + if (Planes[PNum].Type < 3) + Value+=5; + + Value -= EpsilonBrush*1000; + + if (HintSplit && !(Side->Flags & SIDE_HINT) ) + Value = -999999; + + if (Value > BestValue) + { + BestValue = Value; + BestSide = Side; + BestSplits = Splits; + for (Test = Brushes ; Test ; Test=Test->Next) + Test->Side = Test->TestSide; + } + } + + #if 0 + if (BestSide) // Just take the first side... + break; + #endif + + } + + if (BestSide) + { + if (Pass > 1) + NumNonVisNodes++; + + if (Pass > 0) + { + Node->Detail = GE_TRUE; // Not needed for vis + if (BestSide->Flags & SIDE_HINT) + GHook.Printf("*** Hint as Detail!!! ***\n"); + } + + break; + } + } + + for (Brush = Brushes ; Brush ; Brush=Brush->Next) + { + for (i=0 ; iNumSides ; i++) + Brush->Sides[i].Flags &= ~SIDE_TESTED; + } + + return BestSide; +} + +//======================================================================================= +// SplitBrushList +//======================================================================================= +void SplitBrushList (GBSP_Brush *Brushes, GBSP_Node *Node, GBSP_Brush **Front, GBSP_Brush **Back) +{ + GBSP_Brush *Brush, *NewBrush, *NewBrush2, *Next; + GBSP_Side *Side; + int32 Sides; + int32 i; + + *Front = *Back = NULL; + + for (Brush = Brushes ; Brush ; Brush = Next) + { + Next = Brush->Next; + + Sides = Brush->Side; + + if (Sides == PSIDE_BOTH) + { + SplitBrush(Brush, Node->PlaneNum, 0, SIDE_NODE, GE_FALSE, &NewBrush, &NewBrush2); + if (NewBrush) + { + NewBrush->Next = *Front; + *Front = NewBrush; + } + if (NewBrush2) + { + NewBrush2->Next = *Back; + *Back = NewBrush2; + } + continue; + } + + NewBrush = CopyBrush(Brush); + + if (Sides & PSIDE_FACING) + { + for (i=0 ; iNumSides ; i++) + { + Side = NewBrush->Sides + i; + if (Side->PlaneNum == Node->PlaneNum) + Side->Flags |= SIDE_NODE; + } + } + + + if (Sides & PSIDE_FRONT) + { + NewBrush->Next = *Front; + *Front = NewBrush; + continue; + } + if (Sides & PSIDE_BACK) + { + NewBrush->Next = *Back; + *Back = NewBrush; + continue; + } + } +} + +//======================================================================================= +// LeafNode +// Converts a node into a leaf, and create the contents +//======================================================================================= +void LeafNode (GBSP_Node *Node, GBSP_Brush *Brushes) +{ + GBSP_Brush *Brush; + int32 i; + + Node->PlaneNum = PLANENUM_LEAF; + Node->Contents = 0; + + // Get the contents of this leaf, by examining all the brushes that made this leaf + for (Brush = Brushes; Brush; Brush = Brush->Next) + { + if (Brush->Original->Contents & BSP_CONTENTS_SOLID2) + { + for (i=0 ; i < Brush->NumSides ;i++) + { + if (!(Brush->Sides[i].Flags & SIDE_NODE)) + break; + } + + // If all the planes in this leaf where caused by splits, then + // we can force this leaf to be solid... + if (i == Brush->NumSides) + { + //Node->Contents &= 0xffff0000; + Node->Contents |= BSP_CONTENTS_SOLID2; + //break; + } + + } + + Node->Contents |= Brush->Original->Contents; + } + + // Once brushes get down to the leafs, we don't need to keep the polys on them anymore... + // We can free them now... + for (Brush = Brushes ; Brush ; Brush=Brush->Next) + { + // Don't need to keep polygons anymore... + for (i=0; i< Brush->NumSides; i++) + { + if (Brush->Sides[i].Poly) + { + FreePoly(Brush->Sides[i].Poly); + Brush->Sides[i].Poly = NULL; + } + } + } + + Node->BrushList = Brushes; +} + +//======================================================================================= +// BuildTree_r +//======================================================================================= +GBSP_Node *BuildTree_r (GBSP_Node *Node, GBSP_Brush *Brushes) +{ + GBSP_Node *NewNode; + GBSP_Side *BestSide; + int32 i; + GBSP_Brush *Children[2]; + + NumVisNodes++; + + // find the best plane to use as a splitter + BestSide = SelectSplitSide (Brushes, Node); + + if (!BestSide) + { + // leaf node + Node->Side = NULL; + Node->PlaneNum = PLANENUM_LEAF; + LeafNode (Node, Brushes); + + #ifdef USE_VOLUMES + FreeBrush(Node->Volume); + #endif + return Node; + } + + // This is a splitplane node + Node->Side = BestSide; + Node->PlaneNum = BestSide->PlaneNum; + + SplitBrushList (Brushes, Node, &Children[0], &Children[1]); + FreeBrushList(Brushes); + + // Allocate children before recursing + for (i=0 ; i<2 ; i++) + { + NewNode = AllocNode (); + NewNode->Parent = Node; + Node->Children[i] = NewNode; + } + +#ifdef USE_VOLUMES + // Distribute this nodes volume to its children + SplitBrush(Node->Volume, Node->PlaneNum, 0, SIDE_NODE, GE_FALSE, &Node->Children[0]->Volume, + &Node->Children[1]->Volume); + + if (!Node->Children[0]->Volume || !Node->Children[1]->Volume) + GHook.Printf("*WARNING* BuildTree_r: Volume was not split on both sides...\n"); + + FreeBrush(Node->Volume); +#endif + + // Recursively process children + for (i=0 ; i<2 ; i++) + Node->Children[i] = BuildTree_r (Node->Children[i], Children[i]); + + return Node; +} + + +//======================================================================================= +// BuildBSP +//======================================================================================= +GBSP_Node *BuildBSP(GBSP_Brush *BrushList) +{ + GBSP_Node *Node; + GBSP_Brush *b; + int32 NumVisFaces, NumNonVisFaces; + int32 NumVisBrushes; + int32 i; + geFloat Volume; + geVec3d Mins, Maxs; + + if (Verbose) + GHook.Printf("--- Build BSP Tree ---\n"); + + ClearBounds(&Mins, &Maxs); + + NumVisFaces = 0; + NumNonVisFaces = 0; + NumVisBrushes = 0; + + for (b=BrushList ; b ; b=b->Next) + { + NumVisBrushes++; + + Volume = BrushVolume (b); + + if (Volume < MicroVolume) + { + GHook.Printf("**WARNING** BuildBSP: Brush with NULL volume\n"); + } + + for (i=0 ; iNumSides ; i++) + { + if (!b->Sides[i].Poly) + continue; + if (b->Sides[i].Flags & SIDE_NODE) + continue; + if (b->Sides[i].Flags & SIDE_VISIBLE) + NumVisFaces++; + else + NumNonVisFaces++; + } + + AddPointToBounds (&b->Mins, &Mins, &Maxs); + AddPointToBounds (&b->Maxs, &Mins, &Maxs); + + } + + if (Verbose) + { + GHook.Printf("Total Brushes : %5i\n", NumVisBrushes); + GHook.Printf("Total Faces : %5i\n", NumVisFaces); + GHook.Printf("Faces Removed : %5i\n", NumNonVisFaces); + } + + NumVisNodes = 0; + NumNonVisNodes = 0; + + Node = AllocNode(); + +#ifdef USE_VOLUMES + Node->Volume = BrushFromBounds (&Mins, &Maxs); + + if (BrushVolume(Node->Volume) < 1.0f) + GHook.Printf("**WARNING** BuildBSP: BAD world volume.\n"); +#endif + + Node = BuildTree_r (Node, BrushList); + + // Top node is always valid, this way portals can use top node to get box of entire bsp... + Node->Mins = Mins; + Node->Maxs = Maxs; + + TreeMins = Mins; + TreeMaxs = Maxs; + + if (Verbose) + { + GHook.Printf("Total Nodes : %5i\n", NumVisNodes/2 - NumNonVisNodes); + GHook.Printf("Nodes Removed : %5i\n", NumNonVisNodes); + GHook.Printf("Total Leafs : %5i\n", (NumVisNodes+1)/2); + } + + return Node; +} + +//======================================================================================= +// FaceFromPortal +//======================================================================================= +GBSP_Face *FaceFromPortal (GBSP_Portal *p, int32 PSide) +{ + GBSP_Face *f; + GBSP_Side *Side; + + Side = p->Side; + + if (!Side) + return NULL; // Portal does not bridge different visible contents + + if ( (p->Nodes[PSide]->Contents & BSP_CONTENTS_WINDOW2) + && VisibleContents(p->Nodes[!PSide]->Contents^p->Nodes[PSide]->Contents) == BSP_CONTENTS_WINDOW2) + return NULL; + + f = AllocFace (0); + + if (Side->TexInfo >= NumTexInfo || Side->TexInfo < 0) + GHook.Printf("*WARNING* FaceFromPortal: Bad texinfo.\n"); + + f->TexInfo = Side->TexInfo; + f->PlaneNum = Side->PlaneNum; + f->PlaneSide = PSide; + f->Portal = p; + f->Visible = GE_TRUE; + + if (PSide) + ReversePoly(p->Poly, &f->Poly); + else + CopyPoly(p->Poly, &f->Poly); + + return f; +} + +void SubdivideNodeFaces (GBSP_Node *Node); + +//======================================================================================= +// CountLeafFaces_r +//======================================================================================= +void CountLeafFaces_r(GBSP_Node *Node, GBSP_Face *Face) +{ + + while (Face->Merged) + Face = Face->Merged; + + if (Face->Split[0]) + { + CountLeafFaces_r(Node, Face->Split[0]); + CountLeafFaces_r(Node, Face->Split[1]); + return; + } + + Node->NumLeafFaces++; +} + +//======================================================================================= +// GetLeafFaces_r +//======================================================================================= +void GetLeafFaces_r(GBSP_Node *Node, GBSP_Face *Face) +{ + + while (Face->Merged) + Face = Face->Merged; + + if (Face->Split[0]) + { + GetLeafFaces_r(Node, Face->Split[0]); + GetLeafFaces_r(Node, Face->Split[1]); + return; + } + + Node->LeafFaces[Node->NumLeafFaces++] = Face; +} + +//======================================================================================= +// MakeLeafFaces_r +//======================================================================================= +void MakeLeafFaces_r(GBSP_Node *Node) +{ + GBSP_Portal *p; + int32 s; + + // Recurse down to leafs + if (Node->PlaneNum != PLANENUM_LEAF) + { + MakeLeafFaces_r (Node->Children[0]); + MakeLeafFaces_r (Node->Children[1]); + return; + } + + // Solid leafs never have visible faces + if (Node->Contents & BSP_CONTENTS_SOLID2) + return; + + // Reset counter + Node->NumLeafFaces = 0; + + // See which portals are valid + for (p=Node->Portals ; p ; p = p->Next[s]) + { + s = (p->Nodes[1] == Node); + + if (!p->Face[s]) + continue; + + CountLeafFaces_r(Node, p->Face[s]); + } + + Node->LeafFaces = (GBSP_Face**)geRam_Allocate(sizeof(GBSP_Face*)*(Node->NumLeafFaces+1)); + + // Reset counter + Node->NumLeafFaces = 0; + + // See which portals are valid + for (p=Node->Portals ; p ; p = p->Next[s]) + { + s = (p->Nodes[1] == Node); + + if (!p->Face[s]) + continue; + + GetLeafFaces_r(Node, p->Face[s]); + } +} + +//======================================================================================= +// MakeLeafFaces +//======================================================================================= +void MakeLeafFaces(GBSP_Node *Root) +{ + MakeLeafFaces_r(Root); +} + +geBoolean MergeFaceList2(GBSP_Face *Faces); + +//======================================================================================= +// MakeFaces_r +//======================================================================================= +void MakeFaces_r (GBSP_Node *Node) +{ + GBSP_Portal *p; + int32 s; + + // Recurse down to leafs + if (Node->PlaneNum != PLANENUM_LEAF) + { + MakeFaces_r (Node->Children[0]); + MakeFaces_r (Node->Children[1]); + + // Marge list + MergeFaceList2(Node->Faces); + // Subdivide them for lightmaps + SubdivideNodeFaces(Node); + return; + } + + // Solid leafs never have visible faces + if (Node->Contents & BSP_CONTENTS_SOLID2) + return; + + // See which portals are valid + for (p=Node->Portals ; p ; p = p->Next[s]) + { + s = (p->Nodes[1] == Node); + + p->Face[s] = FaceFromPortal (p, s); + if (p->Face[s]) + { + // Record the contents on each side of the face + p->Face[s]->Contents[0] = Node->Contents; // Front side contents is this leaf + p->Face[s]->Contents[1] = p->Nodes[!s]->Contents; // Back side contents is the leaf on the other side of this portal + + // Add the face to the list of faces on the node that originaly created the portal + p->Face[s]->Next = p->OnNode->Faces; + p->OnNode->Faces = p->Face[s]; + + NumMakeFaces++; + } + } +} + + +//======================================================================================= +// MakeFaces +//======================================================================================= +void MakeFaces (GBSP_Node *Node) +{ + if (Verbose) + GHook.Printf("--- Finalize Faces ---\n"); + + NumMerged = 0; + NumSubdivided = 0; + NumMakeFaces = 0; + + MakeFaces_r (Node); + + if (Verbose) + { + GHook.Printf("TotalFaces : %5i\n", NumMakeFaces); + GHook.Printf("Merged Faces : %5i\n", NumMerged); + GHook.Printf("Subdivided Faces : %5i\n", NumSubdivided); + GHook.Printf("FinalFaces : %5i\n", (NumMakeFaces-NumMerged)+NumSubdivided); + } +} + +int32 MergedNodes; + +//======================================================================================= +//======================================================================================= +void MergeNodes_r (GBSP_Node *Node) +{ + GBSP_Brush *b, *Next; + + if (Node->PlaneNum == PLANENUM_LEAF) + return; + + MergeNodes_r (Node->Children[0]); + MergeNodes_r (Node->Children[1]); + + if (Node->Children[0]->PlaneNum == PLANENUM_LEAF && Node->Children[1]->PlaneNum == PLANENUM_LEAF) + //if ((Node->Children[0]->Contents == Node->Children[1]->Contents) || + if ((Node->Children[0]->Contents & BSP_CONTENTS_SOLID2) && (Node->Children[1]->Contents & BSP_CONTENTS_SOLID2)) + if ((Node->Children[0]->Contents & 0xffff0000) == (Node->Children[1]->Contents & 0xffff0000)) + { + if (Node->Faces) + GHook.Error ("Node->Faces seperating BSP_CONTENTS_SOLID!"); + + if (Node->Children[0]->Faces || Node->Children[1]->Faces) + GHook.Error ("!Node->faces with children"); + + // FIXME: free stuff + Node->PlaneNum = PLANENUM_LEAF; + //Node->Contents = BSP_CONTENTS_SOLID2; + Node->Contents = Node->Children[0]->Contents; + Node->Contents |= Node->Children[1]->Contents; + + Node->Detail = GE_FALSE; + + if (Node->BrushList) + GHook.Error ("MergeNodes: node->brushlist"); + + // combine brush lists + Node->BrushList = Node->Children[1]->BrushList; + + for (b=Node->Children[0]->BrushList ; b ; b=Next) + { + Next = b->Next; + b->Next = Node->BrushList; + Node->BrushList = b; + } + + MergedNodes++; + } +} + + +//======================================================================================= +//======================================================================================= +void MergeNodes(GBSP_Node *Node) +{ + if (Verbose) + GHook.Printf("--- Merge Nodes ---\n"); + + MergedNodes = 0; + + MergeNodes_r (Node); + + if (Verbose) + GHook.Printf("Num Merged : %5i\n", MergedNodes); +} + +//======================================================================================= +// FreeBSP_r +//======================================================================================= +void FreeBSP_r(GBSP_Node *Node) +{ + if (!Node) + return; + + if (Node->PlaneNum == PLANENUM_LEAF) + { + FreeNode(Node); + return; + } + + FreeBSP_r(Node->Children[0]); + FreeBSP_r(Node->Children[1]); + + FreeNode(Node); +} + +//======================================================================================= +//======================================================================================= +geBoolean ProcessWorldModel(GBSP_Model *Model, MAP_Brush *MapBrushes) +{ + GBSP_Brush *Brushes; + GBSP_Node *Node; + + // Make the bsp brush list + Brushes = MakeBSPBrushes(MapBrushes); + + if (!Brushes) + { + GHook.Error("ProcessWorldModel: Could not make real brushes.\n"); + return GE_FALSE; + } + + // Csg the brushes together so none of them are overlapping + // (this is legal, but makes alot more brushes that land in leafs in the long run...) + Brushes = CSGBrushes(Brushes); + +#if 0 + OutputBrushes("Test.3dt", Brushes); +#endif + + // Build the bsp + Node = BuildBSP(Brushes); + + Model->Mins = TreeMins; + Model->Maxs = TreeMaxs; + + if (!CreatePortals(Node, Model, GE_FALSE)) + { + GHook.Error("Could not create the portals.\n"); + return GE_FALSE; + } + + // Remove "unseen" leafs so MarkVisibleSides won't reach unseeen areas + if (RemoveHiddenLeafs(Node, &BSPModels[0].OutsideNode) == -1) + { + GHook.Printf("Failed to remove hidden leafs.\n"); + return GE_FALSE; + } + + // Mark visible sided on the portals + MarkVisibleSides (Node, MapBrushes); + + // Free vis portals... + if (!FreePortals(Node)) + { + GHook.Printf("BuildBSP: Could not free portals.\n"); + return GE_FALSE; + } + + // Free the tree + FreeBSP_r(Node); + + // Make the bsp brush list + Brushes = MakeBSPBrushes(MapBrushes); + + if (!Brushes) + { + GHook.Error("ProcessWorldModel: Could not make real brushes.\n"); + return GE_FALSE; + } + + // Csg the brushes + Brushes = CSGBrushes(Brushes); + + // Build the bsp + Node = BuildBSP(Brushes); + + Model->Mins = TreeMins; + Model->Maxs = TreeMaxs; + + if (!CreatePortals(Node, Model, GE_FALSE)) + { + GHook.Error("Could not create the portals.\n"); + return GE_FALSE; + } + + // Remove hidden leafs one last time + if (RemoveHiddenLeafs(Node, &BSPModels[0].OutsideNode) == -1) + { + GHook.Printf("Failed to remove hidden leafs.\n"); + return GE_FALSE; + } + + // Mark visible sides one last time + MarkVisibleSides (Node, MapBrushes); + + // Finally make the faces on the visible portals + MakeFaces(Node); + + // Make the leaf LeafFaces (record what faces touch what leafs...) + MakeLeafFaces(Node); + + // Free portals... + if (!FreePortals(Node)) + { + GHook.Printf("BuildBSP: Could not free portals.\n"); + return GE_FALSE; + } + + // Prune the tree + MergeNodes (Node); + + //FreeBrushList(Brushes); + + // Assign the root node to the model + Model->RootNode[0] = Node; + + //ShowBrushHeap(); + + return GE_TRUE; +} + +//======================================================================================= +//======================================================================================= +geBoolean ProcessSubModel(GBSP_Model *Model, MAP_Brush *MapBrushes) +{ + GBSP_Brush *Brushes; + GBSP_Node *Node; + + // Make the bsp brush list + Brushes = MakeBSPBrushes(MapBrushes); + Brushes = CSGBrushes(Brushes); + + // Build the bsp + Node = BuildBSP(Brushes); + + Model->Mins = TreeMins; + Model->Maxs = TreeMaxs; + + if (!CreatePortals(Node, Model, GE_FALSE)) + { + GHook.Error("Could not create the portals.\n"); + return NULL; + } + + MarkVisibleSides (Node, MapBrushes); + + MakeFaces(Node); + + if (!FreePortals(Node)) + { + GHook.Printf("BuildBSP: Could not free portals.\n"); + return GE_FALSE; + } + + MergeNodes (Node); + + // Assign the root node to the model + Model->RootNode[0] = Node; + + return GE_TRUE; +} + +char SkyNames[6][32] = { + "SkyTop", + "SkyBottom", + "SkyLeft", + "SkyRight", + "SkyFront", + "SkyBack" +}; + +//======================================================================================== +// GetSkyBoxInfo +//======================================================================================== +geBoolean GetSkyBoxInfo(void) +{ + + char *Name; + int32 i; + + for (i=0; i<6; i++) + GFXSkyData.Textures[i] = -1; + + for (i=0; i<6; i++) + { + Name = ValueForKey(&Entities[0], SkyNames[i]); + + if (!Name || !Name[0]) + continue; + + GFXSkyData.Textures[i] = FindTextureIndex(Name, TEXTURE_SKYBOX); + + //GHook.Printf("Sky %i, %s, %s\n", i, SkyNames[i], Name); + } + + if (!GetVectorForKey2(&Entities[0], "SkyAxis", &GFXSkyData.Axis)) + { + GFXSkyData.Axis.X = 0.0f; + GFXSkyData.Axis.Y = 0.0f; + GFXSkyData.Axis.Z = 0.0f; + } + + GFXSkyData.Dpm = FloatForKey(&Entities[0], "SkyRotation"); + + //if (!GFXSkyData.Dpm) + // GFXSkyData.Dpm = 10.0f; + + GFXSkyData.DrawScale = FloatForKey(&Entities[0], "SkyDrawScale"); + + if (!GFXSkyData.DrawScale) + GFXSkyData.DrawScale = 1.0f; // Default to 1.0f + + return GE_TRUE; +} + +//======================================================================================= +// ProcessEntities +//======================================================================================= +geBoolean ProcessEntities(void) +{ + int32 i; + geBoolean OldVerbose; + + OldVerbose = Verbose; + + for (i=0; i< NumEntities; i++) + { + if (CancelRequest) + { + GHook.Printf("Cancel requested...\n"); + return GE_FALSE; + } + + if (!Entities[i].Brushes2) // No model if no brushes + continue; + + BSPModels[Entities[i].ModelNum].Origin = Entities[i].Origin; + + if (i == 0) + { + if (!ProcessWorldModel(&BSPModels[0], Entities[i].Brushes2)) + return GE_FALSE; + + if (!GetSkyBoxInfo()) + { + GHook.Error("Could not get SkyBox names from world...\n"); + return GE_FALSE; + } + } + else + { + if (!EntityVerbose) + Verbose = GE_FALSE; + + if (!ProcessSubModel(&BSPModels[NumBSPModels], Entities[i].Brushes2)) + return GE_FALSE; + } + + NumBSPModels++; + } + + Verbose = OldVerbose; + + return GE_TRUE; +} + +//======================================================================================= +// SaveGFXMotionData +//======================================================================================= +geBoolean SaveGFXMotionData(geVFile *VFile) +{ + int32 i, NumMotions; + GBSP_Chunk Chunk; + long StartPos; + long EndPos; + + geVFile_Tell(VFile, &StartPos); + Chunk.Type = GBSP_CHUNK_MOTIONS; + Chunk.Size = 0; + Chunk.Elements = 1; + + WriteChunk(&Chunk, NULL, VFile); + + geVFile_Printf(VFile, "Genesis_Motion_File v1.0\r\n"); + + // Count the motions + NumMotions = 0; + for (i=0; i< NumEntities; i++) + { + if (!Entities[i].Brushes2) + continue; + + if (!Entities[i].Motion) // No motion data for model + continue; + + NumMotions++; + } + + geVFile_Printf(VFile, "NumMotions %i\r\n", NumMotions); // Save out number of motions + + // For all entities that have motion, save their motion out in a motion file... + for (i=0; i< NumEntities; i++) + { + if (!Entities[i].Brushes2) // No model if no brushes + continue; + + if (!Entities[i].Motion) // No motion data for model + continue; + + geVFile_Printf(VFile, "ModelNum %i\r\n", Entities[i].ModelNum); + + // Save out the motion + if (!geMotion_WriteToFile(Entities[i].Motion, VFile)) + { + GHook.Error("Error saving motion data.\n"); + return GE_FALSE; + } + geMotion_Destroy(&Entities[i].Motion); + Entities[i].Motion = NULL; + } + + geVFile_Tell(VFile, &EndPos); + + geVFile_Seek(VFile, StartPos, GE_VFILE_SEEKSET); + + Chunk.Type = GBSP_CHUNK_MOTIONS; + Chunk.Size = 1; + Chunk.Elements = EndPos - StartPos - sizeof(Chunk); + WriteChunk(&Chunk, NULL, VFile); + geVFile_Seek(VFile, EndPos, GE_VFILE_SEEKSET); + NumGFXMotionBytes = Chunk.Elements; + + return GE_TRUE; +} + diff --git a/GBSPLib/Fill.Cpp b/GBSPLib/Fill.Cpp new file mode 100644 index 0000000..40e1f58 --- /dev/null +++ b/GBSPLib/Fill.Cpp @@ -0,0 +1,436 @@ +/****************************************************************************************/ +/* Fill.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Does the flood filling of the leafs, and removes untouchable leafs */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "Fill.h" +#include "Map.h" +#include "Portals.h" +#include "Leaf.h" +#include "Poly.h" +#include "GBSPFile.h" +#include "Bsp.h" + +int32 CurrentFill; +geBoolean HitEntity = GE_FALSE; +int32 EntityHit = 0; +GBSP_Node *HitNode; + +int32 NumRemovedLeafs; + +//===================================================================================== +// PlaceEntities +//===================================================================================== +geBoolean PlaceEntities(GBSP_Node *RootNode) +{ + int32 i; + GBSP_Node *Node; + geBoolean Empty; + + Empty = GE_FALSE; + + for (i=1; i< NumEntities; i++) + { + if (!(Entities[i].Flags & ENTITY_HAS_ORIGIN)) // No "Origin" in entity + continue; + + Node = FindLeaf(RootNode, &Entities[i].Origin); + if (!Node) + return GE_FALSE; + + if (!(Node->Contents & BSP_CONTENTS_SOLID2)) + { + Node->Entity = i; + Empty = GE_TRUE; + } + } + + if (!Empty) + { + GHook.Error("PlaceEntities: No valid entities for operation %i.\n", NumEntities); + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// FillUnTouchedLeafs_r +//===================================================================================== +void FillUnTouchedLeafs_r(GBSP_Node *Node) +{ + if (Node->PlaneNum != PLANENUM_LEAF) + { + FillUnTouchedLeafs_r(Node->Children[0]); + FillUnTouchedLeafs_r(Node->Children[1]); + return; + } + + if ((Node->Contents & BSP_CONTENTS_SOLID2)) + return; //allready solid or removed... + + if (Node->CurrentFill != CurrentFill) + { + // Fill er in with solid so it does not show up...(Preserve user contents) + Node->Contents &= (0xffff0000); + Node->Contents |= BSP_CONTENTS_SOLID2; + NumRemovedLeafs++; + } +} + +//===================================================================================== +// FillLeafs2_r +//===================================================================================== +geBoolean FillLeafs2_r(GBSP_Node *Node) +{ + GBSP_Portal *Portal; + int32 Side; + + if (Node->Contents & BSP_CONTENTS_SOLID2) + return GE_TRUE; + + if (Node->CurrentFill == CurrentFill) + return GE_TRUE; + + Node->CurrentFill = CurrentFill; + + for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) + { + if (Portal->Nodes[0] == Node) + Side = 0; + else if (Portal->Nodes[1] == Node) + Side = 1; + else + { + GHook.Error("RemoveOutside2_r: Portal does not look at either node.\n"); + return GE_FALSE; + } + + // Go though the portal to the node on the other side (!side) + if (!FillLeafs2_r(Portal->Nodes[!Side])) + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// CanPassPortal +// See if a portal can be passed through or not +//===================================================================================== +geBoolean CanPassPortal(GBSP_Portal *Portal) +{ + if (Portal->Nodes[0]->PlaneNum != PLANENUM_LEAF) + GHook.Printf("*WARNING* CanPassPortal: Portal does not seperate leafs.\n"); + + if (Portal->Nodes[1]->PlaneNum != PLANENUM_LEAF) + GHook.Printf("*WARNING* CanPassPortal: Portal does not seperate leafs.\n"); + + if (Portal->Nodes[0]->Contents & BSP_CONTENTS_SOLID2) + return GE_FALSE; + + if (Portal->Nodes[1]->Contents & BSP_CONTENTS_SOLID2) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// FillLeafs_r +//===================================================================================== +geBoolean FillLeafs_r(GBSP_Node *Node, geBoolean Fill, int32 Dist) +{ + GBSP_Portal *Portal; + int32 Side; + + //if (HitEntity) + // return GE_TRUE; + + if (Node->Contents & BSP_CONTENTS_SOLID2) + return GE_TRUE; + + if (Node->CurrentFill == CurrentFill) + return GE_TRUE; + + Node->CurrentFill = CurrentFill; + + Node->Occupied = Dist; + + if (Fill) + { + // Preserve user contents + Node->Contents &= 0xffff0000; + Node->Contents |= BSP_CONTENTS_SOLID2; + } + else + { + if (Node->Entity) + { + HitEntity = GE_TRUE; + EntityHit = Node->Entity; + HitNode = Node; + return GE_TRUE; + } + } + + for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) + { + if (Portal->Nodes[0] == Node) + Side = 0; + else if (Portal->Nodes[1] == Node) + Side = 1; + else + { + GHook.Error("FillLeafs_r: Portal does not look at either node.\n"); + return GE_FALSE; + } + + //if (!CanPassPortal(Portal)) + // continue; + + if (!FillLeafs_r(Portal->Nodes[!Side], Fill, Dist+1)) + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// FillFromEntities +//===================================================================================== +geBoolean FillFromEntities(GBSP_Node *RootNode) +{ + int32 i; + GBSP_Node *Node; + geBoolean Empty; + + Empty = GE_FALSE; + + for (i=1; i< NumEntities; i++) // Don't use the world as an entity (skip 0)!! + { + if (!(Entities[i].Flags & ENTITY_HAS_ORIGIN)) // No "Origin" in entity + continue; + + Node = FindLeaf(RootNode, &Entities[i].Origin); + + if (Node->Contents & BSP_CONTENTS_SOLID2) + continue; + + // There is at least one entity in empty space... + Empty = GE_TRUE; + + if (!FillLeafs2_r(Node)) + return GE_FALSE; + } + + if (!Empty) + { + GHook.Error("FillFromEntities: No valid entities for operation.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// LeafCenter +//===================================================================================== +void LeafCenter(GBSP_Node *Node, geVec3d *PortalMid) +{ + int32 NumPortals, Side; + geVec3d Mid; + GBSP_Portal *Portal; + + NumPortals = 0; + geVec3d_Clear(PortalMid); + + for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) + { + Side = Portal->Nodes[1] == Node; + + PolyCenter(Portal->Poly, &Mid); + geVec3d_Add(PortalMid, &Mid, PortalMid); + NumPortals++; + } + + geVec3d_Scale(PortalMid, 1.0f/(geFloat)NumPortals, PortalMid); +} + +//===================================================================================== +// WriteLeakFile +//===================================================================================== +geBoolean WriteLeakFile (char *FileName, GBSP_Node *Start, GBSP_Node *Outside) +{ + geVec3d Mid; + FILE *PntFile; + char FileName2[1024]; + int32 Count; + GBSP_Node *Node; + int Pos1, Pos2; + char TAG[5]; + geBoolean Stop; + + GHook.Printf("--- WriteLeakFile ---\n"); + + // + // Write the points to the file + // + sprintf (FileName2, "%s.Pnt", FileName); + PntFile = fopen (FileName2, "wb"); + + if (!PntFile) + GHook.Error ("WriteLeakFile: Couldn't open %s\n", FileName); + + Count = 0; + + strcpy(TAG, "LEAK"); + fwrite(TAG, sizeof(char), 4, PntFile); + + Pos1 = ftell(PntFile); + + fwrite(&Count, sizeof(int32), 1, PntFile); + + Node = Start; + + fwrite(&Entities[EntityHit].Origin, sizeof(geVec3d), 1, PntFile); + Count++; + + Stop = GE_FALSE; + + while (Node && Node->Occupied > 1) + { + int32 Next; + GBSP_Portal *p, *NextPortal; + GBSP_Node *NextNode; + int32 s; + + // find the best portal exit + Next = Node->Occupied; + NextNode = NULL; + NextPortal = NULL; + + GHook.Printf("Occupied : %5i\n", Node->Occupied); + + for (p=Node->Portals ; p ; p = p->Next[!s]) + { + s = (p->Nodes[0] == Node); + + if (p->Nodes[s] == Outside) + { + Stop = GE_TRUE; + break; + } + + if (p->Nodes[s]->Occupied && p->Nodes[s]->Occupied < Next) + { + NextPortal = p; + NextNode = p->Nodes[s]; + Next = NextNode->Occupied; + } + } + + Node = NextNode; + + if (Stop) + break; + + if (NextPortal && Node && Node != Outside) + { + // Write out the center of the portal + PolyCenter(NextPortal->Poly, &Mid); + fwrite(&Mid, sizeof(geVec3d), 1, PntFile); + Count++; + // Then writer out the center of the leaf it goes too + LeafCenter(Node, &Mid); + fwrite(&Mid, sizeof(geVec3d), 1, PntFile); + Count++; + } + } + + GHook.Printf("Num Points : %5i\n", Count); + + // HACK!!!! + Pos2 = ftell(PntFile); + + GHook.Printf("Pos1 = %5i\n", Pos1); + GHook.Printf("Pos2 = %5i\n", Pos2); + + fseek(PntFile, Pos1, SEEK_SET); + //Count-=2; + fwrite(&Count, sizeof(int32), 1, PntFile); + + fseek(PntFile, Pos2, SEEK_SET); + + fclose (PntFile); + + return GE_TRUE; +} + +//===================================================================================== +// RemoveHiddenLeafs +//===================================================================================== +int32 RemoveHiddenLeafs(GBSP_Node *RootNode, GBSP_Node *ONode) +{ + int32 Side; + + GHook.Printf(" --- Remove Hidden Leafs --- \n"); + + OutsideNode = ONode; + + Side = OutsideNode->Portals->Nodes[0] == OutsideNode; + + NumRemovedLeafs = 0; + + if (!PlaceEntities(RootNode)) + return -1; + + HitEntity = GE_FALSE; + HitNode = NULL; + + CurrentFill = 1; + if (!FillLeafs_r(OutsideNode->Portals->Nodes[Side], GE_FALSE, 1)) + return -1; + + if (HitEntity) + { + GHook.Printf("*****************************************\n"); + GHook.Printf("* *** LEAK *** *\n"); + GHook.Printf("* Level is NOT sealed. *\n"); + GHook.Printf("* Optimal removal will not be performed.*\n"); + GHook.Printf("*****************************************\n"); + + WriteLeakFile("Test", HitNode, ONode); + return -1; + } + + CurrentFill = 2; + + if (!FillFromEntities(RootNode)) + return -1; + + FillUnTouchedLeafs_r(RootNode); + + if (Verbose) + GHook.Printf("Removed Leafs : %5i\n", NumRemovedLeafs); + + return NumRemovedLeafs; +} diff --git a/GBSPLib/Fill.h b/GBSPLib/Fill.h new file mode 100644 index 0000000..7005810 --- /dev/null +++ b/GBSPLib/Fill.h @@ -0,0 +1,31 @@ +/****************************************************************************************/ +/* Fill.h */ +/* */ +/* Author: John Pollard */ +/* Description: Does the flood filling of the leafs, and removes untouchable leafs */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef FILL_H +#define FILL_H + +#include + +#include "BSP.h" + +int32 RemoveHiddenLeafs(GBSP_Node *RootNode, GBSP_Node *ONode); + +#endif diff --git a/GBSPLib/GBSPFILE.CPP b/GBSPLib/GBSPFILE.CPP new file mode 100644 index 0000000..8e7566c --- /dev/null +++ b/GBSPLib/GBSPFILE.CPP @@ -0,0 +1,625 @@ +/****************************************************************************************/ +/* GBSPFile.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Loads a BSP */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "DCommon.h" +#include "GBSPFile.h" +#include "VFile.h" +#include "Ram.h" + +//======================================================================================== +// Globals +//======================================================================================== +GBSP_Header GBSPHeader; // Header +GFX_SkyData GFXSkyData; + +GFX_Model *GFXModels; // Model data +GFX_Node *GFXNodes; // Nodes +GFX_BNode *GFXBNodes; // Bevel Clip nodes +GFX_Leaf *GFXLeafs; // Leafs +GFX_Cluster *GFXClusters; // CHANGE: CLUSTER +GFX_Area *GFXAreas; +GFX_AreaPortal *GFXAreaPortals; +GFX_Plane *GFXPlanes; // Planes +GFX_Face *GFXFaces; // Faces +int32 *GFXLeafFaces; +GFX_LeafSide *GFXLeafSides; +geVec3d *GFXVerts; // Verts +int32 *GFXVertIndexList; // Index list +geVec3d *GFXRGBVerts; + +uint8 *GFXEntData; +GFX_Texture *GFXTextures; // Textures +GFX_TexInfo *GFXTexInfo; // TexInfo +uint8 *GFXTexData; // TexData + +uint8 *GFXLightData; // Lightmap data +uint8 *GFXVisData; // Vis data +GFX_Portal *GFXPortals; // Portal data +DRV_Palette *GFXPalettes; // Texture palettes +uint8 *GFXMotionData; // Model motion keyframe data + +int32 NumGFXModels; +int32 NumGFXNodes; +int32 NumGFXBNodes; +int32 NumGFXLeafs; +int32 NumGFXClusters; // CHANGE: CLUSTER +int32 NumGFXAreas; +int32 NumGFXAreaPortals; +int32 NumGFXPlanes; +int32 NumGFXFaces; +int32 NumGFXLeafFaces; +int32 NumGFXLeafSides; +int32 NumGFXVerts; +int32 NumGFXVertIndexList; +int32 NumGFXRGBVerts; + +int32 NumGFXEntData; +int32 NumGFXTextures; +int32 NumGFXTexInfo; +int32 NumGFXTexData; + +int32 NumGFXLightData; +int32 NumGFXVisData; +int32 NumGFXPortals; +int32 NumGFXPalettes; +int32 NumGFXMotionBytes; + +//#define DEBUGCHUNKS +#ifdef DEBUGCHUNKS +static char *ChunkNames[] = +{ +"GBSP_CHUNK_HEADER", +"GBSP_CHUNK_MODELS", +"GBSP_CHUNK_NODES", +"GBSP_CHUNK_BNODES", +"GBSP_CHUNK_LEAFS", +"GBSP_CHUNK_CLUSTERS", +"GBSP_CHUNK_AREAS", +"GBSP_CHUNK_LEAF_SIDES", +"GBSP_CHUNK_PORTALS", +"GBSP_CHUNK_PLANES", +"GBSP_CHUNK_FACES", +"GBSP_CHUNK_LEAF_FACES", +"GBSP_CHUNK_VERT_INDEX", +"GBSP_CHUNK_VERTS", +"GBSP_CHUNK_RGB_VERTS", +"GBSP_CHUNK_ENTDATA", +"GBSP_CHUNK_TEXINFO", +"GBSP_CHUNK_TEXTURES", +"GBSP_CHUNK_TEXDATA", +"GBSP_CHUNK_LIGHTDATA", +"GBSP_CHUNK_VISDATA", +"GBSP_CHUNK_SKYDATA", +"GBSP_CHUNK_PALETTES", +"GBSP_CHUNK_MOTIONS", +}; +#endif + +//======================================================================================== +// WriteChunk +//======================================================================================== +geBoolean WriteChunk(GBSP_Chunk *Chunk, void *Data, geVFile *f) +{ + if (geVFile_Write(f, Chunk, sizeof(GBSP_Chunk)) != GE_TRUE) + { + //Hook.Error("WriteChunk: There was an error writing the chunk (Duh...).\n"); + return GE_FALSE; + } + +#ifdef DEBUGCHUNKS + if (Chunk->Type != GBSP_CHUNK_END) + { + long Pos; + + geVFile_Tell(f, &Pos); + GHook.Printf(" WriteChunkData: @%08x '%s', %d elements of %d size\n", Pos, + ChunkNames[Chunk->Type], Chunk->Elements, Chunk->Size); + } + else + { + long Pos; + + geVFile_Tell(f, &Pos); + GHook.Printf(" WriteChunk: @%08x 'GBSP_CHUNK_END', %d elements of %d size\n", Pos, Chunk->Elements, Chunk->Size); + } +#endif + if (Chunk->Size * Chunk->Elements > 0) + { + if (!Data) + return GE_TRUE; + + if (geVFile_Write(f, Data, Chunk->Size * Chunk->Elements) != GE_TRUE) + { + //Hook.Error("WriteChunk: There was an error writing the chunk data.\n"); + return GE_FALSE; + } + } + + return GE_TRUE; +} + +//======================================================================================== +// ReadChunkData +//======================================================================================== +geBoolean ReadChunkData(GBSP_Chunk *Chunk, void *Data, geVFile *f) +{ + if (geVFile_Read(f, Data, Chunk->Size * Chunk->Elements) != GE_TRUE) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================== +// ReadChunk +//======================================================================================== +geBoolean ReadChunk(GBSP_Chunk *Chunk, geVFile *f) +{ + if (geVFile_Read(f, Chunk, sizeof(GBSP_Chunk)) != GE_TRUE) + { + return GE_FALSE; + } + +#ifdef DEBUGCHUNKS + if (Chunk->Type != GBSP_CHUNK_END) + { + long Pos; + + geVFile_Tell(f, &Pos); + GHook.Printf(" ReadChunk: @%08x '%s', %d elements of %d size\n", Pos, + ChunkNames[Chunk->Type], Chunk->Elements, Chunk->Size); + } + else + { + long Pos; + + geVFile_Tell(f, &Pos); + GHook.Printf(" ReadChunk: @%08x 'GBSP_CHUNK_END', %d elements of %d size\n", Pos, Chunk->Elements, Chunk->Size); + } +#endif + + switch(Chunk->Type) + { + case GBSP_CHUNK_HEADER: + { + if (!ReadChunkData(Chunk, (void*)&GBSPHeader, f)) + return GE_FALSE; + if (strcmp(GBSPHeader.TAG, "GBSP")) + return GE_FALSE; + if (GBSPHeader.Version != GBSP_VERSION) + return GE_FALSE; + + break; + } + case GBSP_CHUNK_MODELS: + { + NumGFXModels = Chunk->Elements; + GFXModels = GE_RAM_ALLOCATE_ARRAY(GFX_Model, NumGFXModels); + if (!ReadChunkData(Chunk, GFXModels, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_NODES: + { + NumGFXNodes = Chunk->Elements; + GFXNodes = GE_RAM_ALLOCATE_ARRAY(GFX_Node,NumGFXNodes); + if (!ReadChunkData(Chunk, GFXNodes, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_BNODES: + { + NumGFXBNodes = Chunk->Elements; + GFXBNodes = GE_RAM_ALLOCATE_ARRAY(GFX_BNode,NumGFXBNodes); + if (!ReadChunkData(Chunk, GFXBNodes, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_LEAFS: + { + NumGFXLeafs = Chunk->Elements; + GFXLeafs = GE_RAM_ALLOCATE_ARRAY(GFX_Leaf,NumGFXLeafs); + if (!ReadChunkData(Chunk, GFXLeafs, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_CLUSTERS: + { + NumGFXClusters = Chunk->Elements; + + GFXClusters = GE_RAM_ALLOCATE_ARRAY(GFX_Cluster,NumGFXClusters); + if (!ReadChunkData(Chunk, GFXClusters, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_AREAS: + { + NumGFXAreas = Chunk->Elements; + GFXAreas = GE_RAM_ALLOCATE_ARRAY(GFX_Area,NumGFXAreas); + if (!ReadChunkData(Chunk, GFXAreas, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_AREA_PORTALS: + { + NumGFXAreaPortals = Chunk->Elements; + GFXAreaPortals = GE_RAM_ALLOCATE_ARRAY(GFX_AreaPortal,NumGFXAreaPortals); + if (!ReadChunkData(Chunk, GFXAreaPortals, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_PORTALS: + { + NumGFXPortals = Chunk->Elements; + GFXPortals = GE_RAM_ALLOCATE_ARRAY(GFX_Portal,NumGFXPortals); + if (!ReadChunkData(Chunk, GFXPortals, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_PLANES: + { + NumGFXPlanes = Chunk->Elements; + GFXPlanes = GE_RAM_ALLOCATE_ARRAY(GFX_Plane,NumGFXPlanes); + if (!ReadChunkData(Chunk, GFXPlanes, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_FACES: + { + NumGFXFaces = Chunk->Elements; + GFXFaces = GE_RAM_ALLOCATE_ARRAY(GFX_Face,NumGFXFaces); + if (!ReadChunkData(Chunk, GFXFaces, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_LEAF_FACES: + { + NumGFXLeafFaces = Chunk->Elements; + GFXLeafFaces = GE_RAM_ALLOCATE_ARRAY(int32,NumGFXLeafFaces); + if (!ReadChunkData(Chunk, GFXLeafFaces, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_LEAF_SIDES: + { + NumGFXLeafSides = Chunk->Elements; + + GFXLeafSides = GE_RAM_ALLOCATE_ARRAY(GFX_LeafSide,NumGFXLeafSides); + if (!ReadChunkData(Chunk, GFXLeafSides, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_VERTS: + { + NumGFXVerts = Chunk->Elements; + GFXVerts = GE_RAM_ALLOCATE_ARRAY(geVec3d,NumGFXVerts); + if (!ReadChunkData(Chunk, GFXVerts, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_VERT_INDEX: + { + NumGFXVertIndexList = Chunk->Elements; + GFXVertIndexList = GE_RAM_ALLOCATE_ARRAY(int32,NumGFXVertIndexList); + if (!ReadChunkData(Chunk, GFXVertIndexList, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_RGB_VERTS: + { + NumGFXRGBVerts = Chunk->Elements; + GFXRGBVerts = GE_RAM_ALLOCATE_ARRAY(geVec3d,NumGFXRGBVerts); + if (!ReadChunkData(Chunk, GFXRGBVerts, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_TEXINFO: + { + NumGFXTexInfo = Chunk->Elements; + GFXTexInfo = GE_RAM_ALLOCATE_ARRAY(GFX_TexInfo,NumGFXTexInfo); + if (!ReadChunkData(Chunk, GFXTexInfo, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_TEXTURES: + { + NumGFXTextures = Chunk->Elements; + GFXTextures = GE_RAM_ALLOCATE_ARRAY(GFX_Texture,NumGFXTextures); + if (!ReadChunkData(Chunk, GFXTextures, f)) + return GE_FALSE; + break; + } + + case GBSP_CHUNK_TEXDATA: + { +// GHook.Printf(" Reading TEXDATA: %d bytes of %d size \n", Chunk->Elements, Chunk->Size); + NumGFXTexData = Chunk->Elements; + GFXTexData = GE_RAM_ALLOCATE_ARRAY(uint8,NumGFXTexData); + if (!ReadChunkData(Chunk, GFXTexData, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_ENTDATA: + { + NumGFXEntData = Chunk->Elements; + GFXEntData = GE_RAM_ALLOCATE_ARRAY(uint8,NumGFXEntData); + if (!ReadChunkData(Chunk, GFXEntData, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_LIGHTDATA: + { + NumGFXLightData = Chunk->Elements; + GFXLightData = GE_RAM_ALLOCATE_ARRAY(uint8,NumGFXLightData); + if (!ReadChunkData(Chunk, GFXLightData, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_VISDATA: + { + NumGFXVisData = Chunk->Elements; + GFXVisData = GE_RAM_ALLOCATE_ARRAY(uint8,NumGFXVisData); + if (!ReadChunkData(Chunk, GFXVisData, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_SKYDATA: + { + if (!ReadChunkData(Chunk, &GFXSkyData, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_PALETTES: + { + NumGFXPalettes = Chunk->Elements; + GFXPalettes = GE_RAM_ALLOCATE_ARRAY(DRV_Palette,NumGFXPalettes); + if (!GFXPalettes) + return GE_FALSE; + if (!ReadChunkData(Chunk, GFXPalettes, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_MOTIONS: + { + // GHook.Printf(" Reading motions: %d Elements of %d size\n", Chunk->Elements, Chunk->Size); + NumGFXMotionBytes = Chunk->Elements; + GFXMotionData = GE_RAM_ALLOCATE_ARRAY(uint8,NumGFXMotionBytes); + if (!ReadChunkData(Chunk, GFXMotionData, f)) + return GE_FALSE; + break; + } + case GBSP_CHUNK_END: + { + break; + } + default: + return GE_FALSE; + } + + return GE_TRUE; +} + +//======================================================================================== +// LoadGBSPFile +//======================================================================================== +geBoolean LoadGBSPFile(char *FileName) +{ + geVFile *f; + GBSP_Chunk Chunk; + + f = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_DOS, FileName, NULL, GE_VFILE_OPEN_READONLY); + + if (!f) + return GE_FALSE; + + while (1) + { + if (!ReadChunk(&Chunk, f)) + return GE_FALSE; + + if (Chunk.Type == GBSP_CHUNK_END) + break; + } + + return GE_TRUE; +} + +//======================================================================================== +// FreeGBSPFile +//======================================================================================== +geBoolean FreeGBSPFile(void) +{ + if (GFXModels) + geRam_Free(GFXModels); + if (GFXNodes) + geRam_Free(GFXNodes); + if (GFXBNodes) + geRam_Free(GFXBNodes); + if (GFXLeafs) + geRam_Free(GFXLeafs); + if (GFXClusters) // CHANGE: CLUSTER + geRam_Free(GFXClusters); + if (GFXAreas) + geRam_Free(GFXAreas); + if (GFXPortals) + geRam_Free(GFXPortals); + if (GFXPlanes) + geRam_Free(GFXPlanes); + if (GFXFaces) + geRam_Free(GFXFaces); + if (GFXLeafFaces) + geRam_Free(GFXLeafFaces); + if (GFXLeafSides) + geRam_Free(GFXLeafSides); + if (GFXVerts) + geRam_Free(GFXVerts); + if (GFXVertIndexList) + geRam_Free(GFXVertIndexList); + if (GFXRGBVerts) + geRam_Free(GFXRGBVerts); + if (GFXTextures) + geRam_Free(GFXTextures); + if (GFXTexInfo) + geRam_Free(GFXTexInfo); + if (GFXTexData) + geRam_Free(GFXTexData); + if (GFXEntData) + geRam_Free(GFXEntData); + if (GFXLightData) + geRam_Free(GFXLightData); + if (GFXVisData) + geRam_Free(GFXVisData); + if (GFXPalettes) + geRam_Free(GFXPalettes); + if (GFXMotionData) + geRam_Free(GFXMotionData); + + GFXModels = NULL; + GFXNodes = NULL; + GFXBNodes = NULL; + GFXLeafs = NULL; + GFXClusters = NULL; // CHANGE: CLUSTER + GFXAreas = NULL; + GFXPlanes = NULL; + GFXFaces = NULL; + GFXLeafFaces = NULL; + GFXLeafSides = NULL; + GFXVerts = NULL; + GFXVertIndexList = NULL; + GFXRGBVerts = NULL; + GFXEntData = NULL; + + GFXTextures = NULL; + GFXTexInfo = NULL; + GFXTexData = NULL; + GFXPalettes = NULL; + GFXMotionData = NULL; + + GFXLightData = NULL; + GFXVisData = NULL; + GFXPortals = NULL; + + NumGFXModels = 0; + NumGFXNodes = 0; + NumGFXBNodes = 0; + NumGFXLeafs = 0; + NumGFXClusters = 0; // CHANGE: CLUSTER + NumGFXAreas = 0; + NumGFXPlanes = 0; + NumGFXFaces = 0; + NumGFXLeafFaces = 0; + NumGFXLeafSides = 0; + NumGFXVerts = 0; + NumGFXVertIndexList = 0; + NumGFXRGBVerts = 0; + + NumGFXEntData = 0; + NumGFXTexInfo = 0; + NumGFXTextures = 0; + NumGFXTexData = 0; + NumGFXPalettes = 0; + + NumGFXMotionBytes = 0; + + NumGFXLightData = 0; + NumGFXVisData = 0; + NumGFXPortals = 0; + + return GE_TRUE; +} + +//================================================================================ +// WriteChunks +//================================================================================ +geBoolean WriteChunks(GBSP_ChunkData *Data, int32 NumChunkData, geVFile *f) +{ + int32 i; + GBSP_Chunk Chunk; + + for (i=0; i< NumChunkData; i++) + { + Chunk.Type = Data[i].Type; + Chunk.Size = Data[i].Size; + Chunk.Elements = Data[i].Elements; + if (!WriteChunk(&Chunk, Data[i].Data, f)) + return GE_FALSE; + } + + return GE_TRUE; +} + +//================================================================================ +// SaveGBSPFile +//================================================================================ +geBoolean SaveGBSPFile(char *FileName) +{ + GBSP_ChunkData CurrentChunkData[] = { + { GBSP_CHUNK_HEADER , sizeof(GBSP_Header) ,1 , &GBSPHeader}, + { GBSP_CHUNK_MODELS , sizeof(GFX_Model) ,NumGFXModels , GFXModels }, + { GBSP_CHUNK_NODES , sizeof(GFX_Node) ,NumGFXNodes , GFXNodes }, + { GBSP_CHUNK_PORTALS , sizeof(GFX_Portal) ,NumGFXPortals , GFXPortals}, + { GBSP_CHUNK_BNODES , sizeof(GFX_BNode) ,NumGFXBNodes , GFXBNodes }, + { GBSP_CHUNK_PLANES , sizeof(GFX_Plane) ,NumGFXPlanes , GFXPlanes }, + { GBSP_CHUNK_FACES , sizeof(GFX_Face) ,NumGFXFaces , GFXFaces }, + { GBSP_CHUNK_AREAS , sizeof(GFX_Area) ,NumGFXAreas , GFXAreas }, + { GBSP_CHUNK_AREA_PORTALS , sizeof(GFX_AreaPortal),NumGFXAreaPortals , GFXAreaPortals }, + { GBSP_CHUNK_LEAF_FACES , sizeof(int32) ,NumGFXLeafFaces , GFXLeafFaces }, + { GBSP_CHUNK_LEAF_SIDES , sizeof(GFX_LeafSide) ,NumGFXLeafSides , GFXLeafSides }, + { GBSP_CHUNK_VERTS , sizeof(geVec3d) ,NumGFXVerts , GFXVerts }, + { GBSP_CHUNK_VERT_INDEX , sizeof(int32) ,NumGFXVertIndexList , GFXVertIndexList}, + { GBSP_CHUNK_RGB_VERTS , sizeof(geVec3d) ,NumGFXRGBVerts , GFXRGBVerts }, + { GBSP_CHUNK_ENTDATA , sizeof(uint8) ,NumGFXEntData , GFXEntData}, + { GBSP_CHUNK_TEXTURES , sizeof(GFX_Texture) ,NumGFXTextures , GFXTextures}, + { GBSP_CHUNK_TEXINFO , sizeof(GFX_TexInfo) ,NumGFXTexInfo , GFXTexInfo}, + { GBSP_CHUNK_TEXDATA , sizeof(uint8) ,NumGFXTexData , GFXTexData}, + { GBSP_CHUNK_LIGHTDATA , sizeof(uint8) ,NumGFXLightData , GFXLightData}, + { GBSP_CHUNK_LEAFS , sizeof(GFX_Leaf) ,NumGFXLeafs , GFXLeafs }, + { GBSP_CHUNK_CLUSTERS , sizeof(GFX_Cluster) ,NumGFXClusters , GFXClusters}, + { GBSP_CHUNK_VISDATA , sizeof(uint8) ,NumGFXVisData , GFXVisData}, + { GBSP_CHUNK_SKYDATA , sizeof(GFX_SkyData) ,1 , &GFXSkyData}, + { GBSP_CHUNK_PALETTES , sizeof(DRV_Palette) ,NumGFXPalettes , GFXPalettes}, + { GBSP_CHUNK_MOTIONS , sizeof(uint8) ,NumGFXMotionBytes , GFXMotionData}, + { GBSP_CHUNK_END , 0 ,0 ,NULL }, + }; + + geVFile *f; + + f = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_DOS, FileName, NULL, GE_VFILE_OPEN_CREATE); + + if (!f) + return GE_FALSE; + + if (!WriteChunks(CurrentChunkData, sizeof(CurrentChunkData) / sizeof(CurrentChunkData[0]), f)) + { + geVFile_Close(f); + return GE_FALSE; + } + + geVFile_Close(f); + + return GE_TRUE; +} + diff --git a/GBSPLib/GBSPLib.dsp b/GBSPLib/GBSPLib.dsp new file mode 100644 index 0000000..ebd886b --- /dev/null +++ b/GBSPLib/GBSPLib.dsp @@ -0,0 +1,247 @@ +# Microsoft Developer Studio Project File - Name="GBSPLib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GBSPLib - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GBSPLib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GBSPLib.mak" CFG="GBSPLib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GBSPLib - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GBSPLib - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Tools/GBSPLib", KTRBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GBSPLib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GBSPLIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W3 /GX /Ot /Ow /Og /Oi /Op /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GBSPLIB_EXPORTS" /YX /FD /c +# SUBTRACT CPP /X +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /x /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib genesis.lib /nologo /dll /machine:I386 +# SUBTRACT LINK32 /nodefaultlib + +!ELSEIF "$(CFG)" == "GBSPLib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GBSPLIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GBSPLIB_EXPORTS" /YX /FD /GZ /c +# SUBTRACT CPP /X +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib genesisd.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "GBSPLib - Win32 Release" +# Name "GBSPLib - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Brush2.cpp +# End Source File +# Begin Source File + +SOURCE=.\Brush2.h +# End Source File +# Begin Source File + +SOURCE=.\Bsp.cpp +# End Source File +# Begin Source File + +SOURCE=.\Bsp.h +# End Source File +# Begin Source File + +SOURCE=.\Bsp2.cpp +# End Source File +# Begin Source File + +SOURCE=.\Fill.Cpp +# End Source File +# Begin Source File + +SOURCE=.\Fill.h +# End Source File +# Begin Source File + +SOURCE=.\Gbspfile.cpp +# End Source File +# Begin Source File + +SOURCE=.\Gbspfile.h +# End Source File +# Begin Source File + +SOURCE=.\Gbsplib.cpp +# End Source File +# Begin Source File + +SOURCE=.\Gbsplib.h +# End Source File +# Begin Source File + +SOURCE=.\Gbspprep.cpp +# End Source File +# Begin Source File + +SOURCE=.\Gbspprep.h +# End Source File +# Begin Source File + +SOURCE=.\Leaf.cpp +# End Source File +# Begin Source File + +SOURCE=.\Leaf.h +# End Source File +# Begin Source File + +SOURCE=.\Light.cpp +# End Source File +# Begin Source File + +SOURCE=.\Light.h +# End Source File +# Begin Source File + +SOURCE=.\Map.cpp +# End Source File +# Begin Source File + +SOURCE=.\Map.h +# End Source File +# Begin Source File + +SOURCE=.\Mathlib.cpp +# End Source File +# Begin Source File + +SOURCE=.\Mathlib.h +# End Source File +# Begin Source File + +SOURCE=.\Poly.cpp +# End Source File +# Begin Source File + +SOURCE=.\Poly.h +# End Source File +# Begin Source File + +SOURCE=.\Portals.cpp +# End Source File +# Begin Source File + +SOURCE=.\Portals.h +# End Source File +# Begin Source File + +SOURCE=.\PortFile.cpp +# End Source File +# Begin Source File + +SOURCE=.\Rad.cpp +# End Source File +# Begin Source File + +SOURCE=.\Texture.cpp +# End Source File +# Begin Source File + +SOURCE=.\Texture.h +# End Source File +# Begin Source File + +SOURCE=.\TJunct.cpp +# End Source File +# Begin Source File + +SOURCE=.\Utils.cpp +# End Source File +# Begin Source File + +SOURCE=.\Utils.h +# End Source File +# Begin Source File + +SOURCE=.\Vis.cpp +# End Source File +# Begin Source File + +SOURCE=.\Vis.h +# End Source File +# Begin Source File + +SOURCE=.\Visflood.cpp +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# End Group +# End Target +# End Project diff --git a/GBSPLib/GBSPLib.dsw b/GBSPLib/GBSPLib.dsw new file mode 100644 index 0000000..28f40ce --- /dev/null +++ b/GBSPLib/GBSPLib.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "GBSPLib"=.\GBSPLib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/GBSPLib/GBSPLib.mak b/GBSPLib/GBSPLib.mak new file mode 100644 index 0000000..2543f66 --- /dev/null +++ b/GBSPLib/GBSPLib.mak @@ -0,0 +1,352 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on GBSPLib.dsp +!IF "$(CFG)" == "" +CFG=GBSPLib - Win32 Debug +!MESSAGE No configuration specified. Defaulting to GBSPLib - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "GBSPLib - Win32 Release" && "$(CFG)" != "GBSPLib - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GBSPLib.mak" CFG="GBSPLib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GBSPLib - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GBSPLib - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GBSPLib - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +ALL : "$(OUTDIR)\GBSPLib.dll" + + +CLEAN : + -@erase "$(INTDIR)\Brush2.obj" + -@erase "$(INTDIR)\Bsp.obj" + -@erase "$(INTDIR)\Bsp2.obj" + -@erase "$(INTDIR)\Fill.obj" + -@erase "$(INTDIR)\Gbspfile.obj" + -@erase "$(INTDIR)\Gbsplib.obj" + -@erase "$(INTDIR)\Gbspprep.obj" + -@erase "$(INTDIR)\Leaf.obj" + -@erase "$(INTDIR)\Light.obj" + -@erase "$(INTDIR)\Map.obj" + -@erase "$(INTDIR)\Mathlib.obj" + -@erase "$(INTDIR)\Poly.obj" + -@erase "$(INTDIR)\Portals.obj" + -@erase "$(INTDIR)\PortFile.obj" + -@erase "$(INTDIR)\Rad.obj" + -@erase "$(INTDIR)\Texture.obj" + -@erase "$(INTDIR)\TJunct.obj" + -@erase "$(INTDIR)\Utils.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\Vis.obj" + -@erase "$(INTDIR)\Visflood.obj" + -@erase "$(OUTDIR)\GBSPLib.dll" + -@erase "$(OUTDIR)\GBSPLib.exp" + -@erase "$(OUTDIR)\GBSPLib.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MT /W3 /GX /O2 /X /I "..\\" /I "SDKShare\Include" /I "..\..\MSDev60\Include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GBSPLIB_EXPORTS" /Fp"$(INTDIR)\GBSPLib.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\GBSPLib.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:no /pdb:"$(OUTDIR)\GBSPLib.pdb" /machine:I386 /nodefaultlib /out:"$(OUTDIR)\GBSPLib.dll" /implib:"$(OUTDIR)\GBSPLib.lib" +LINK32_OBJS= \ + "$(INTDIR)\Brush2.obj" \ + "$(INTDIR)\Bsp.obj" \ + "$(INTDIR)\Bsp2.obj" \ + "$(INTDIR)\Fill.obj" \ + "$(INTDIR)\Gbspfile.obj" \ + "$(INTDIR)\Gbsplib.obj" \ + "$(INTDIR)\Gbspprep.obj" \ + "$(INTDIR)\Leaf.obj" \ + "$(INTDIR)\Light.obj" \ + "$(INTDIR)\Map.obj" \ + "$(INTDIR)\Mathlib.obj" \ + "$(INTDIR)\Poly.obj" \ + "$(INTDIR)\Portals.obj" \ + "$(INTDIR)\PortFile.obj" \ + "$(INTDIR)\Rad.obj" \ + "$(INTDIR)\Texture.obj" \ + "$(INTDIR)\TJunct.obj" \ + "$(INTDIR)\Utils.obj" \ + "$(INTDIR)\Vis.obj" \ + "$(INTDIR)\Visflood.obj" \ + ".\SDKShare\Lib\genesis.lib" \ + "..\..\MSDev60\lib\Winspool.lib" \ + "..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\MSDev60\lib\Libcmt.lib" \ + "..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\MSDev60\lib\Shell32.lib" \ + "..\..\MSDev60\lib\User32.lib" \ + "..\..\MSDev60\lib\Uuid.lib" \ + "..\..\MSDev60\lib\Advapi32.lib" + +"$(OUTDIR)\GBSPLib.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "GBSPLib - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\GBSPLib.dll" + + +CLEAN : + -@erase "$(INTDIR)\Brush2.obj" + -@erase "$(INTDIR)\Bsp.obj" + -@erase "$(INTDIR)\Bsp2.obj" + -@erase "$(INTDIR)\Fill.obj" + -@erase "$(INTDIR)\Gbspfile.obj" + -@erase "$(INTDIR)\Gbsplib.obj" + -@erase "$(INTDIR)\Gbspprep.obj" + -@erase "$(INTDIR)\Leaf.obj" + -@erase "$(INTDIR)\Light.obj" + -@erase "$(INTDIR)\Map.obj" + -@erase "$(INTDIR)\Mathlib.obj" + -@erase "$(INTDIR)\Poly.obj" + -@erase "$(INTDIR)\Portals.obj" + -@erase "$(INTDIR)\PortFile.obj" + -@erase "$(INTDIR)\Rad.obj" + -@erase "$(INTDIR)\Texture.obj" + -@erase "$(INTDIR)\TJunct.obj" + -@erase "$(INTDIR)\Utils.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(INTDIR)\Vis.obj" + -@erase "$(INTDIR)\Visflood.obj" + -@erase "$(OUTDIR)\GBSPLib.dll" + -@erase "$(OUTDIR)\GBSPLib.exp" + -@erase "$(OUTDIR)\GBSPLib.ilk" + -@erase "$(OUTDIR)\GBSPLib.lib" + -@erase "$(OUTDIR)\GBSPLib.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /X /I "..\\" /I "SDKShare\Include" /I "..\..\MSDev60\Include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GBSPLIB_EXPORTS" /Fp"$(INTDIR)\GBSPLib.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\GBSPLib.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:yes /pdb:"$(OUTDIR)\GBSPLib.pdb" /debug /machine:I386 /nodefaultlib /out:"$(OUTDIR)\GBSPLib.dll" /implib:"$(OUTDIR)\GBSPLib.lib" /pdbtype:sept +LINK32_OBJS= \ + "$(INTDIR)\Brush2.obj" \ + "$(INTDIR)\Bsp.obj" \ + "$(INTDIR)\Bsp2.obj" \ + "$(INTDIR)\Fill.obj" \ + "$(INTDIR)\Gbspfile.obj" \ + "$(INTDIR)\Gbsplib.obj" \ + "$(INTDIR)\Gbspprep.obj" \ + "$(INTDIR)\Leaf.obj" \ + "$(INTDIR)\Light.obj" \ + "$(INTDIR)\Map.obj" \ + "$(INTDIR)\Mathlib.obj" \ + "$(INTDIR)\Poly.obj" \ + "$(INTDIR)\Portals.obj" \ + "$(INTDIR)\PortFile.obj" \ + "$(INTDIR)\Rad.obj" \ + "$(INTDIR)\Texture.obj" \ + "$(INTDIR)\TJunct.obj" \ + "$(INTDIR)\Utils.obj" \ + "$(INTDIR)\Vis.obj" \ + "$(INTDIR)\Visflood.obj" \ + ".\SDKShare\Lib\genesisd.lib" \ + "..\..\MSDev60\lib\Winspool.lib" \ + "..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\MSDev60\lib\Libcmtd.lib" \ + "..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\MSDev60\lib\Shell32.lib" \ + "..\..\MSDev60\lib\User32.lib" \ + "..\..\MSDev60\lib\Uuid.lib" \ + "..\..\MSDev60\lib\Advapi32.lib" + +"$(OUTDIR)\GBSPLib.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("GBSPLib.dep") +!INCLUDE "GBSPLib.dep" +!ELSE +!MESSAGE Warning: cannot find "GBSPLib.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "GBSPLib - Win32 Release" || "$(CFG)" == "GBSPLib - Win32 Debug" +SOURCE=.\Brush2.cpp + +"$(INTDIR)\Brush2.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Bsp.cpp + +"$(INTDIR)\Bsp.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Bsp2.cpp + +"$(INTDIR)\Bsp2.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Fill.Cpp + +"$(INTDIR)\Fill.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Gbspfile.cpp + +"$(INTDIR)\Gbspfile.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Gbsplib.cpp + +"$(INTDIR)\Gbsplib.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Gbspprep.cpp + +"$(INTDIR)\Gbspprep.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Leaf.cpp + +"$(INTDIR)\Leaf.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Light.cpp + +"$(INTDIR)\Light.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Map.cpp + +"$(INTDIR)\Map.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Mathlib.cpp + +"$(INTDIR)\Mathlib.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Poly.cpp + +"$(INTDIR)\Poly.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Portals.cpp + +"$(INTDIR)\Portals.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\PortFile.cpp + +"$(INTDIR)\PortFile.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Rad.cpp + +"$(INTDIR)\Rad.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Texture.cpp + +"$(INTDIR)\Texture.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\TJunct.cpp + +"$(INTDIR)\TJunct.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Utils.cpp + +"$(INTDIR)\Utils.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Vis.cpp + +"$(INTDIR)\Vis.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Visflood.cpp + +"$(INTDIR)\Visflood.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/GBSPLib/GBSPPREP.CPP b/GBSPLib/GBSPPREP.CPP new file mode 100644 index 0000000..f01f508 --- /dev/null +++ b/GBSPLib/GBSPPREP.CPP @@ -0,0 +1,1131 @@ +/****************************************************************************************/ +/* GBSPPrep.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Saves non GFX data to GFX data (GFX data is data on disk) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + + +#include "GBSPPrep.h" +#include "GBSPFile.h" +#include "Poly.h" // For Planes, and NumPlanes +#include "BSP.h" +#include "Map.h" // For texture +#include "Texture.h" +#include "Portals.h" +#include "Leaf.h" + +#include "VFile.h" +#include "Ram.h" + +geBoolean SaveGFXModelData(geVFile *f); +geBoolean SaveGFXNodes(geVFile *f); +geBoolean SaveGFXPortals(geVFile *f); +geBoolean SaveGFXBNodes(geVFile *f); +geBoolean SaveGFXLeafs(geVFile *f); +geBoolean SaveGFXClusters(geVFile *f); // CHANGE: CLUSTER +geBoolean SaveGFXAreasAndPortals(geVFile *f); +geBoolean SaveGFXFaces(geVFile *f); +geBoolean SaveGFXLeafSides(geVFile *f); +geBoolean SaveGFXVerts(geVFile *f); +geBoolean SaveGFXVertIndexList(geVFile *f); +geBoolean SaveGFXPlanes(geVFile *f); +geBoolean SaveGFXTextures(geVFile *f); +geBoolean SaveGFXEntData(geVFile *f); +geBoolean SaveGFXMotionData(geVFile *VFile); + +char VisFile[300]; + +int32 NumSolidLeafs; + +geBoolean ConvertGBSPToFile(char *FileName) +{ + geVFile *f; + GBSP_Chunk Chunk; + + strcpy(VisFile, FileName); + + if (!FixModelTJunctions()) + { + GHook.Error("ConvertGBSPToFile: FixModelTJunctions failed.\n"); + return GE_FALSE; + } + + GFXVertIndexList = GE_RAM_ALLOCATE_ARRAY(int32,TotalIndexVerts); + NumGFXVerts = NumWeldedVerts; + GFXVerts = WeldedVerts; + + // Go through all the bsp models and setup data that the gfxmodels need + if (!PrepAllGBSPModels()) + { + GHook.Error("ConvertGBSPToFile: Could not Prep Models.\n"); + return GE_FALSE; + } + + f = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_DOS, FileName, NULL, GE_VFILE_OPEN_CREATE); + + if (!f) + { + GHook.Error("ConvertGBSPToFile: geVFile_OpenNewSystem failed.\n"); + return GE_FALSE; + } + + strcpy(GBSPHeader.TAG, "GBSP"); + GBSPHeader.TAG[4] = NULL; + + GBSPHeader.Version = GBSP_VERSION; + + // Record the time the bsp was saved... + GetSystemTime(&GBSPHeader.BSPTime); + + Chunk.Type = GBSP_CHUNK_HEADER; + Chunk.Size = sizeof(GBSP_Header); + Chunk.Elements = 1; + WriteChunk(&Chunk, (void*)&GBSPHeader, f); + + // HACK! Just point these to the GBSP versions, but reset them below... + NumGFXLeafSides = NumLeafSides; + GFXLeafSides = (GFX_LeafSide*)LeafSides; + + //GHook.Printf("Saving GFX Model Data\n"); + if (!SaveGFXModelData(f)) + { + GHook.Error("ConvertGBSPToFile: SaveGFXModelData failed.\n"); + return GE_FALSE; + } + if (!SaveGFXNodes(f)) + return GE_FALSE; + if (!SaveGFXLeafs(f)) + { + GHook.Error("ConvertGBSPToFile: SaveGFXLeafs failed.\n"); + return GE_FALSE; + } + if (!SaveGFXClusters(f)) + return GE_FALSE; + if (!SaveGFXAreasAndPortals(f)) + return GE_FALSE; + if (!SaveGFXLeafSides(f)) + return GE_FALSE; + if (!SaveGFXFaces(f)) + return GE_FALSE; + if (!SaveGFXPlanes(f)) + return GE_FALSE; + if (!SaveGFXVerts(f)) + return GE_FALSE; + if (!SaveGFXVertIndexList(f)) + return GE_FALSE; + if (!SaveGFXTextures(f)) + return GE_FALSE; + if (!SaveGFXEntData(f)) + return GE_FALSE; + if (!SaveGFXMotionData(f)) + return GE_FALSE; + + Chunk.Type = GBSP_CHUNK_END; + Chunk.Elements = 0; + Chunk.Size = 0; + WriteChunk(&Chunk, NULL, f); + + geVFile_Close(f); + + GHook.Printf(" --- Save GBSP File --- \n"); + + GHook.Printf("Num Models : %5i, %6i\n", NumBSPModels, NumBSPModels*sizeof(GFX_Model)); + GHook.Printf("Num Nodes : %5i, %6i\n", NumGFXNodes, NumGFXNodes*sizeof(GFX_Node)); + GHook.Printf("Num Solid Leafs : %5i, %6i\n", NumSolidLeafs, NumSolidLeafs*sizeof(GFX_Leaf)); + GHook.Printf("Num Total Leafs : %5i, %6i\n", NumGFXLeafs, NumGFXLeafs*sizeof(GFX_Leaf)); + GHook.Printf("Num Clusters : %5i, %6i\n", NumGFXClusters, NumGFXClusters*sizeof(GFX_Cluster)); + GHook.Printf("Num Areas : %5i, %6i\n", NumGFXAreas-1, (NumGFXAreas-1)*sizeof(GFX_Area)); + GHook.Printf("Num Area Portals : %5i, %6i\n", NumGFXAreaPortals, NumGFXAreaPortals*sizeof(GFX_AreaPortal)); + GHook.Printf("Num Leafs Sides : %5i, %6i\n", NumGFXLeafSides, NumGFXLeafSides*sizeof(GFX_LeafSide)); + GHook.Printf("Num Planes : %5i, %6i\n", NumPlanes, NumPlanes*sizeof(GBSP_Plane)); + GHook.Printf("Num Faces : %5i, %6i\n", NumGFXFaces, NumGFXFaces*sizeof(GFX_Face)); + GHook.Printf("Num Leaf Faces : %5i, %6i\n", NumGFXLeafFaces, NumGFXLeafFaces*sizeof(int32)); + GHook.Printf("Num Vert Index : %5i, %6i\n", NumGFXVertIndexList, NumGFXVertIndexList*sizeof(int32)); + GHook.Printf("Num Verts : %5i, %6i\n", NumGFXVerts, NumGFXVerts*sizeof(geVec3d)); + GHook.Printf("Num FaceInfo : %5i, %6i\n", NumGFXTexInfo, NumGFXTexInfo*sizeof(GFX_TexInfo)); + GHook.Printf("Num Textures : %5i, %6i\n", NumGFXTextures, NumGFXTextures*sizeof(GFX_Texture)); + GHook.Printf("Motion Data Size : %6i\n", NumGFXMotionBytes); + GHook.Printf("Tex Data Size : %6i\n", NumGFXTexData); + + geRam_Free(GFXVertIndexList); + GFXVertIndexList = NULL; + NumGFXVertIndexList = 0; + + //geRam_Free(GFXVerts); + GFXVerts = NULL; + + NumGFXEntData = 0; + + // Reset these back, since we did not actually create them, we just + // pointed them to the GBSP_LeafSide structure version (same structure size/type) + GFXLeafSides = NULL; + NumGFXLeafSides = 0; + + FreeGBSPFile(); + + return GE_TRUE; +} + +geBoolean SaveGFXModelData(geVFile *f) +{ + int32 i; + GBSP_Chunk Chunk; + GFX_Model GModel; + + Chunk.Type = GBSP_CHUNK_MODELS; + Chunk.Size = sizeof(GFX_Model); + Chunk.Elements = NumBSPModels; + + WriteChunk(&Chunk, NULL, f); + + for (i=0; i< NumBSPModels; i++) + { + // FIXME: Make a (BSPModel ---> GFXModel) function + GModel.RootNode[0] = BSPModels[i].RootNodeID[0]; + GModel.Origin = BSPModels[i].Origin; + GModel.Mins = BSPModels[i].Mins; + GModel.Maxs = BSPModels[i].Maxs; + GModel.RootNode[1] = BSPModels[i].RootNodeID[1]; + GModel.FirstFace = BSPModels[i].FirstFace; + GModel.NumFaces = BSPModels[i].NumFaces; + GModel.FirstLeaf = BSPModels[i].FirstLeaf; + GModel.NumLeafs = BSPModels[i].NumLeafs; + GModel.FirstCluster = BSPModels[i].FirstCluster; + GModel.NumClusters = BSPModels[i].NumClusters; + GModel.Areas[0] = BSPModels[i].Areas[0]; + GModel.Areas[1] = BSPModels[i].Areas[1]; + if (geVFile_Write(f, &GModel, sizeof(GFX_Model)) != GE_TRUE) + { + GHook.Error("SaveGFXModelData: There was an error writing the model.\n"); + return GE_FALSE; + } + } + + return GE_TRUE; +} + +geBoolean SaveGFXNodes_r(GBSP_Node *Node, geVFile *f) +{ + GFX_Node GNode; + + if (Node->PlaneNum == PLANENUM_LEAF) + return GE_TRUE; + + GNode.Children[0] = Node->ChildrenID[0]; + GNode.Children[1] = Node->ChildrenID[1]; + GNode.NumFaces = Node->NumFaces; + GNode.FirstFace = Node->FirstFace; + GNode.PlaneNum = Node->PlaneNum; + GNode.Mins = Node->Mins; + GNode.Maxs = Node->Maxs; + + if (geVFile_Write(f, &GNode, sizeof(GFX_Node)) != GE_TRUE) + { + GHook.Error("SaveGFXNodes_r: There was an error writing the node.\n"); + return GE_FALSE; + } + + if (!SaveGFXNodes_r(Node->Children[0], f)) + return GE_FALSE; + + if (!SaveGFXNodes_r(Node->Children[1], f)) + return GE_FALSE; + + return GE_TRUE; +} + +geBoolean SaveGFXNodes(geVFile *f) +{ + int32 i; + GBSP_Chunk Chunk; + + Chunk.Type = GBSP_CHUNK_NODES; + Chunk.Size = sizeof(GFX_Node); + Chunk.Elements = NumGFXNodes; + + WriteChunk(&Chunk, NULL, f); + + for (i=0; i< NumBSPModels; i++) + { + if (!SaveGFXNodes_r(BSPModels[i].RootNode[0], f)) + return GE_FALSE; + } + + return GE_TRUE; +} + +geBoolean SaveGFXPortals_r(GBSP_Node *Node, geVFile *f) +{ + GBSP_Portal *Portal; + GFX_Portal GPortal; + int32 Side, i; + geVec3d Origin; + GBSP_Poly *Poly; + + if (Node->PlaneNum == PLANENUM_LEAF) + { + if (Node->Contents & BSP_CONTENTS_SOLID2) + return GE_TRUE; + + for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) + { + Side = (Portal->Nodes[1] == Node); + + if (!(Portal->Nodes[0]->Contents & BSP_CONTENTS_SOLID2) && + !(Portal->Nodes[1]->Contents & BSP_CONTENTS_SOLID2)) + { + Poly = Portal->Poly; + geVec3d_Clear(&Origin); + for (i=0; i< Poly->NumVerts; i++) + geVec3d_Add(&Origin, &Poly->Verts[i], &Origin); + for (i=0; i<3; i++) + VectorToSUB(Origin, i) /= Poly->NumVerts; + + GPortal.Origin = Origin; + GPortal.LeafTo = Portal->Nodes[!Side]->PortalLeafNum; + + if (geVFile_Write(f, &GPortal, sizeof(GFX_Portal)) != GE_TRUE) + { + GHook.Error("SaveGFXPortals_r: There was an error writing the portal.\n"); + return GE_FALSE; + } + } + } + return GE_TRUE; + } + + if (!SaveGFXPortals_r(Node->Children[0], f)) + return GE_FALSE; + + if (!SaveGFXPortals_r(Node->Children[1], f)) + return GE_FALSE; + + return GE_TRUE; +} + +geBoolean SaveGFXPortals(geVFile *f) +{ + int32 i; + GBSP_Chunk Chunk; + + Chunk.Type = GBSP_CHUNK_PORTALS; + Chunk.Size = sizeof(GFX_Portal); + Chunk.Elements = NumGFXPortals; + + WriteChunk(&Chunk, NULL, f); + + for (i=0; i< NumBSPModels; i++) + { + if (!SaveGFXPortals_r(BSPModels[i].RootNode[0], f)) + return GE_FALSE; + } + + return GE_TRUE; +} + +geBoolean SaveGFXBNodes_r(GBSP_Node *Node, geVFile *f) +{ + GFX_BNode GBNode; + + if (Node->PlaneNum == PLANENUM_LEAF) + return GE_TRUE; + + GBNode.Children[0] = Node->ChildrenID[0]; + GBNode.Children[1] = Node->ChildrenID[1]; + GBNode.PlaneNum = Node->PlaneNum; + //GBNode.PlaneSide = Node->PlaneSide; + + if (geVFile_Write(f, &GBNode, sizeof(GFX_BNode)) != GE_TRUE) + { + GHook.Error("SaveGFXBNodes_r: There was an error writing the node.\n"); + return GE_FALSE; + } + + if (!SaveGFXBNodes_r(Node->Children[0], f)) + return GE_FALSE; + if (!SaveGFXBNodes_r(Node->Children[1], f)) + return GE_FALSE; + + return GE_TRUE; +} + +geBoolean SaveGFXBNodes(geVFile *f) +{ + int32 i; + GBSP_Chunk Chunk; + + Chunk.Type = GBSP_CHUNK_BNODES; + Chunk.Size = sizeof(GFX_BNode); + Chunk.Elements = NumGFXBNodes; + + WriteChunk(&Chunk, NULL, f); + + for (i=0; i< NumBSPModels; i++) + if (!SaveGFXBNodes_r(BSPModels[i].RootNode[1], f)) + return GE_FALSE; + + return GE_TRUE; +} + +int32 TotalLeafSize; + +//======================================================================================== +// SaveGFXLeafs_r +//======================================================================================== +geBoolean SaveGFXLeafs_r(GBSP_Node *Node, geVFile *f) +{ + GFX_Leaf GLeaf; + int32 i; + + if (Node->PlaneNum == PLANENUM_LEAF) + { + GLeaf.Contents = Node->Contents; + + #if 0 + if (!GLeaf.Contents) + GLeaf.Contents = BSP_CONTENTS_AIR; + #endif + + GLeaf.Mins = Node->Mins; + GLeaf.Maxs = Node->Maxs; + + GLeaf.FirstFace = NumGFXLeafFaces; + GLeaf.FirstPortal = Node->FirstPortal; + GLeaf.NumPortals = Node->NumPortals; + + GLeaf.Cluster = Node->Cluster; // CHANGE: CLUSTER + GLeaf.Area = Node->Area; + + GLeaf.FirstSide = Node->FirstSide; + GLeaf.NumSides = Node->NumSides; + + GLeaf.NumFaces = 0; + + for (i=0; i< Node->NumLeafFaces; i++) + { + if (!Node->LeafFaces[i]->Visible) + continue; + + // Don't output mark face if it was skipped in the face output stage + // (or it will reference an invalid face...) + if (Node->LeafFaces[i]->NumIndexVerts <= 0) + continue; + + GFXLeafFaces[NumGFXLeafFaces] = Node->LeafFaces[i]->OutputNum; + NumGFXLeafFaces++; + + GLeaf.NumFaces++; + } + + TotalLeafSize += sizeof(GFX_Leaf); + + if (geVFile_Write(f, &GLeaf, sizeof(GFX_Leaf)) != GE_TRUE) + { + GHook.Error("SaveGFXLeafs_r: There was an error writing the leaf.\n"); + return GE_FALSE; + } + return GE_TRUE; + } + + if (!SaveGFXLeafs_r(Node->Children[0], f)) + return GE_FALSE; + if (!SaveGFXLeafs_r(Node->Children[1], f)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================== +// SaveGFXLeafs +//======================================================================================== +geBoolean SaveGFXLeafs(geVFile *f) +{ + int32 i; + GBSP_Chunk Chunk; + + Chunk.Type = GBSP_CHUNK_LEAFS; + Chunk.Size = sizeof(GFX_Leaf); + Chunk.Elements = NumGFXLeafs; + + WriteChunk(&Chunk, NULL, f); + + TotalLeafSize = 0; + + // NumGFXLeafFaces was counted earlier in the PrepGfxNodes Stage + GFXLeafFaces = GE_RAM_ALLOCATE_ARRAY(int32,NumGFXLeafFaces); + + NumGFXLeafFaces = 0; // We must reset this... + + for (i=0; i< NumBSPModels; i++) + { + // Save all the leafs for this model + if (!SaveGFXLeafs_r(BSPModels[i].RootNode[0], f)) + { + GHook.Error("SaveGFXLeafs: SaveGFXLeafs_r failed.\n"); + return GE_FALSE; + } + } + + if (TotalLeafSize != Chunk.Size * Chunk.Elements) + { + GHook.Error("SaveGFXLeafs: Leaf sizes don't match.\n"); + // return GE_FALSE; + } + + // Save gfx leaf faces here... + Chunk.Type = GBSP_CHUNK_LEAF_FACES; + Chunk.Size = sizeof(int32); + Chunk.Elements = NumGFXLeafFaces; + + WriteChunk(&Chunk, GFXLeafFaces, f); + + return GE_TRUE; +} + +// CHANGE: CLUSTER +//======================================================================================== +// SaveGFXClusters +//======================================================================================== +geBoolean SaveGFXClusters(geVFile *f) +{ + int32 i; + GBSP_Chunk Chunk; + GFX_Cluster GCluster; + + NumGFXClusters = NumLeafClusters; + Chunk.Type = GBSP_CHUNK_CLUSTERS; + Chunk.Size = sizeof(GFX_Cluster); + Chunk.Elements = NumGFXClusters; + + WriteChunk(&Chunk, NULL, f); + + for (i=0; i< NumGFXClusters; i++) + { + GCluster.VisOfs = -1; + + if (geVFile_Write(f, &GCluster, sizeof(GFX_Cluster)) != GE_TRUE) + { + GHook.Error("SaveGFXClusters: There was an error saving the cluster.\n"); + return GE_FALSE; + } + } + + return GE_TRUE; +} +//======================================================================================== +// SaveGFXAreasAndPortals +//======================================================================================== +geBoolean SaveGFXAreasAndPortals(geVFile *f) +{ + GBSP_Chunk Chunk; + + // + // Save the areas first + // + Chunk.Type = GBSP_CHUNK_AREAS; + Chunk.Size = sizeof(GFX_Area); + Chunk.Elements = NumGFXAreas; + + WriteChunk(&Chunk, GFXAreas, f); + + // + // Then, save the areaportals + // + Chunk.Type = GBSP_CHUNK_AREA_PORTALS; + Chunk.Size = sizeof(GFX_AreaPortal); + Chunk.Elements = NumGFXAreaPortals; + + WriteChunk(&Chunk, GFXAreaPortals, f); + + return GE_TRUE; +} + +//======================================================================================== +// SaveGFXFaces_r +//======================================================================================== +geBoolean SaveGFXFaces_r(GBSP_Node *Node, geVFile *f) +{ + GBSP_Face *Face; + GFX_Face GFace; + + if (Node->PlaneNum == PLANENUM_LEAF) + return GE_TRUE; + + for (Face = Node->Faces; Face; Face = Face->Next) + { + if (!Face->Visible) + continue; + + if (Face->Merged || Face->Split[0] || Face->Split[1]) + continue; + + if (Face->NumIndexVerts > 0) + { + GFace.FirstVert = Face->FirstIndexVert; + GFace.NumVerts = Face->NumIndexVerts; + GFace.PlaneNum = Face->PlaneNum; + GFace.PlaneSide = Face->PlaneSide; + GFace.TexInfo = Face->TexInfo; + #pragma message ("Make LWidth/Height correct!") + GFace.LWidth = 0; + GFace.LHeight = 0; + GFace.LightOfs = -1; // No light info yet + GFace.LTypes[0] = 255; // Of course, no styles yet either + GFace.LTypes[1] = 255; + GFace.LTypes[2] = 255; + GFace.LTypes[3] = 255; + + if (geVFile_Write(f, &GFace, sizeof(GFX_Face)) != GE_TRUE) + { + GHook.Error("SaveGFXFace_r: There was an error writing the face.\n"); + return GE_FALSE; + } + } + } + + if (!SaveGFXFaces_r(Node->Children[0], f)) + return GE_FALSE; + + if (!SaveGFXFaces_r(Node->Children[1], f)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================== +// SaveGFXFaces +//======================================================================================== +geBoolean SaveGFXFaces(geVFile *f) +{ + int32 i; + GBSP_Chunk Chunk; + + Chunk.Type = GBSP_CHUNK_FACES; + Chunk.Size = sizeof(GFX_Face); + Chunk.Elements = NumGFXFaces; + + WriteChunk(&Chunk, NULL, f); + + for (i=0; i< NumBSPModels; i++) + if (!SaveGFXFaces_r(BSPModels[i].RootNode[0], f)) + return GE_FALSE; + + return GE_TRUE; +} + +//======================================================================================== +// SaveGFXPlanes +//======================================================================================== +geBoolean SaveGFXPlanes(geVFile *f) +{ + int32 i; + GBSP_Chunk Chunk; + GFX_Plane GPlane; + + NumGFXPlanes = NumPlanes; + Chunk.Type = GBSP_CHUNK_PLANES; + Chunk.Size = sizeof(GFX_Plane); + Chunk.Elements = NumGFXPlanes; + + WriteChunk(&Chunk, NULL, f); + + for (i=0; i< NumGFXPlanes; i++) + { + GPlane.Normal = Planes[i].Normal; + GPlane.Dist = Planes[i].Dist; + GPlane.Type = Planes[i].Type; + + if (geVFile_Write(f, &GPlane, sizeof(GFX_Plane)) != GE_TRUE) + { + GHook.Error("SaveGFXPlanes: There was an error saving the plane.\n"); + return GE_FALSE; + } + } + + return GE_TRUE; +} + +//======================================================================================== +// SaveGFXLeafSides +//======================================================================================== +geBoolean SaveGFXLeafSides(geVFile *f) +{ + GBSP_Chunk Chunk; + + Chunk.Type = GBSP_CHUNK_LEAF_SIDES; + Chunk.Size = sizeof(GFX_LeafSide); + Chunk.Elements = NumGFXLeafSides; + + if (!WriteChunk(&Chunk, GFXLeafSides, f)) + { + GHook.Error("There was an error writing the verts.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//======================================================================================== +// SaveGFXVerts +//======================================================================================== +geBoolean SaveGFXVerts(geVFile *f) +{ + GBSP_Chunk Chunk; + + Chunk.Type = GBSP_CHUNK_VERTS; + Chunk.Size = sizeof(geVec3d); + Chunk.Elements = NumGFXVerts; + + if (!WriteChunk(&Chunk, GFXVerts, f)) + { + GHook.Error("There was an error writing the verts.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//======================================================================================== +// SaveGFXVertIndexList +//======================================================================================== +geBoolean SaveGFXVertIndexList(geVFile *f) +{ + GBSP_Chunk Chunk; + + Chunk.Type = GBSP_CHUNK_VERT_INDEX; + Chunk.Size = sizeof(int32); + Chunk.Elements = NumGFXVertIndexList; + + if (!WriteChunk(&Chunk, GFXVertIndexList, f)) + { + GHook.Error("SaveGFXvertIndexList: There was an error saving the VertIndexList.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//======================================================================================== +// PrepGFXNode +//======================================================================================== +void PrepGFXNode(GBSP_Node *Node) +{ + GBSP_Face *Face; + int32 NumFaces; + int32 i; + geVec3d *Verts; + + NumFaces = 0; + Node->FirstFace = NumGFXFaces; + + for (Face = Node->Faces; Face; Face = Face->Next) + { + if (!Face->Visible) + continue; + + if (Face->Merged || Face->Split[0] || Face->Split[1]) + continue; + + // Skip output of face, if IndexVerts not > 0 + // NOTE - The leaf faces output stage will also skip these same faces... + if (Face->NumIndexVerts <= 0) + continue; + + Face->FirstIndexVert = NumGFXVertIndexList; + Face->OutputNum = NumGFXFaces; + + Verts = Face->Poly->Verts; + + for (i=0; i< Face->NumIndexVerts; i++) + { + GFXVertIndexList[NumGFXVertIndexList] = Face->IndexVerts[i]; + Verts++; + NumGFXVertIndexList++; + } + NumGFXFaces ++; + NumFaces++; + } + + Node->NumFaces = NumFaces; +} + +//======================================================================================== +// PrepGFXNodes_r +// Store current nodes for model in GFXNodes/GFXLeafs so they can be saved to disk +//======================================================================================== +int32 PrepGFXNodes_r(int32 Original, GBSP_Node *Node) +{ + int32 CurrentNode; + + // Prep the leaf and it's portals + if (Node->PlaneNum == PLANENUM_LEAF) + { + if (Node->Contents & BSP_CONTENTS_SOLID2) + NumSolidLeafs++; // Remember how many solid leafs there are + + Node->NumPortals = 0; + Node->FirstPortal = -1; + + // To be able to save out portal LeafTo's + Node->PortalLeafNum = NumGFXLeafs; + + // Count num gfx leaf faces here, so we know how big to make the array + // later, when they are saved out... + NumGFXLeafFaces += Node->NumLeafFaces; + + #if 0 + { + GBSP_Portal *Portal; + int32 Side; + + // Setup leaf portals + Node->FirstPortal = NumGFXPortals; + for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) + { + Side = (Portal->Nodes[1] == Node); + + if (!(Portal->Nodes[0]->Contents & BSP_CONTENTS_SOLID2) && + !(Portal->Nodes[1]->Contents & BSP_CONTENTS_SOLID2)) + { + Node->NumPortals++; + NumGFXPortals++; + } + } + } + #endif + + // Increase the number of leafs + NumGFXLeafs++; + + return -(NumGFXLeafs); + } + + CurrentNode = NumGFXNodes; + + PrepGFXNode(Node); + + NumGFXNodes++; + + Node->ChildrenID[0] = PrepGFXNodes_r(Node->ChildrenID[0], Node->Children[0]); + Node->ChildrenID[1] = PrepGFXNodes_r(Node->ChildrenID[1], Node->Children[1]); + + return CurrentNode; +} + +//typedef unsigned char RawPalette[256*3]; + +geBoolean SaveGFXTextures(geVFile *f) +{ + GBSP_Chunk Chunk; + int32 Pos1, Pos2; + uint8 Data[256*256*4]; + int32 Size, Width, Height, Offset, i; + char *File; + DRV_Palette Palette; + int TexNum; + + File = ValueForKey(&Entities[0], "TextureLib"); + if (!File || !File[0]) + { + GHook.Error("SaveGFXTextures: No TextureLib specified in map file.\n"); + return GE_FALSE; + } + + if (!InitTextureLib(File)) + return GE_FALSE; + + Offset = 0; + + geVFile_Tell(f, &Pos1); + + Chunk.Type = GBSP_CHUNK_TEXDATA; + Chunk.Size = 0; + Chunk.Elements = 1; + + WriteChunk(&Chunk, NULL, f); + + //GHook.Printf("Num Textures: %i\n", NumTextures); + + for (i=0; i< NumTextures; i++) + { + //GHook.Printf("Texture : %i, %s\n", i, Textures[i].Name); + + if (!GetTexture(Textures[i].Name, Data, &Size, &Width, &Height, f)) + return GE_FALSE; + + Textures[i].Width = Width; + Textures[i].Height = Height; + Textures[i].Offset = NumGFXTexData; + Textures[i].PaletteIndex = i; + + NumGFXTexData += Size; + } + + geVFile_Tell(f, &Pos2); + + geVFile_Seek(f, Pos1, GE_VFILE_SEEKSET); + + Chunk.Type = GBSP_CHUNK_TEXDATA; + Chunk.Size = 1; + Chunk.Elements = NumGFXTexData; + WriteChunk(&Chunk, NULL, f); + + geVFile_Seek(f, Pos2, GE_VFILE_SEEKSET); + + // Now save textures + NumGFXTextures = NumTextures; + + Chunk.Type = GBSP_CHUNK_TEXTURES; + Chunk.Size = sizeof(GFX_Texture); + Chunk.Elements = NumGFXTextures; + + WriteChunk(&Chunk, NULL, f); + + if (geVFile_Write(f, (GFX_Texture*)Textures, sizeof(GFX_Texture) * NumGFXTextures) != GE_TRUE) + { + GHook.Error("SaveGFXTexture: There was an error saving the texture.\n"); + return GE_FALSE; + } +// added transparent textures + for(i=0;iRootNode[0], Model, GE_TRUE)) + { + GHook.Printf("PrepGBSPModel: Could not create VIS portals.\n"); + return GE_FALSE; + } + + // Mark clusters + Model->FirstCluster = NumLeafClusters; + + if (!CreateLeafClusters(Model->RootNode[0])) + { + GHook.Error("Could not create leaf clusters.\n"); + return GE_FALSE; + } + + Model->NumClusters = NumLeafClusters - Model->FirstCluster; + + if (!SavePortalFile(Model, VisFile)) + return GE_FALSE; + + // Free vis portals... + if (!FreePortals(Model->RootNode[0])) + { + GHook.Printf("PrepGBSPModel: Could not free portals.\n"); + return GE_FALSE; + } + + } + else // Models > 0 are assumed simple and no vising performed, clusters are not needed either... + { + Model->FirstCluster = -1; + Model->NumClusters = 0; + } + + // Create the REAL structural portals + if (!CreatePortals(Model->RootNode[0], Model, GE_FALSE)) + { + GHook.Printf("PrepGBSPModel: Could not create REAL portals.\n"); + return GE_FALSE; + } + + // Create the leaf collision hulls for bevel bbox collisions + if (!CreateLeafSides(Model->RootNode[0])) + { + GHook.Error("Could not create leaf sides.\n"); + return GE_FALSE; + } + + // Create the area leafs + if (Model == BSPModels) // Only world needs areas set... + if (!CreateAreas(Model->RootNode[0])) + { + GHook.Error("Could not create Areas.\n"); + return GE_FALSE; + } + + //==== + Model->FirstFace = NumGFXFaces; + Model->FirstLeaf = NumGFXLeafs; + + // Prep the nodes, so we can save them out later to disk + Model->RootNodeID[0] = PrepGFXNodes_r(Model->RootNodeID[0], Model->RootNode[0]); + + Model->NumFaces = NumGFXFaces - Model->FirstFace; + Model->NumLeafs = NumGFXLeafs - Model->FirstLeaf; + + return GE_TRUE; +} + +geBoolean PrepAllGBSPModels(void) +{ + int32 i; + + // Restore verbose since BSP stage turns it off for entities + Verbose = OriginalVerbose; + + for (i=0; i< NumBSPModels; i++) + { + // Turn it back off for entities if asked to do so... + if (i > 0 && !EntityVerbose) + Verbose = GE_FALSE; + + if (!PrepGBSPModel(&BSPModels[i], i == 0)) + { + GHook.Error("PrepAllGBSPModels: Could not prep model %i.\n", i); + return GE_FALSE; + } + } + + return GE_TRUE; +} diff --git a/GBSPLib/GBSPPREP.H b/GBSPLib/GBSPPREP.H new file mode 100644 index 0000000..b757d41 --- /dev/null +++ b/GBSPLib/GBSPPREP.H @@ -0,0 +1,35 @@ +/****************************************************************************************/ +/* GBSPPrep.h */ +/* */ +/* Author: John Pollard */ +/* Description: Saves non GFX data to GFX data (GFX data is data on disk) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GBSPPREP_H +#define GBSPPREP_H + +#include +#include + +#include "BSP.h" + +void BeginGBSPModels(void); +geBoolean PrepGBSPModel(GBSP_Model *Model, geBoolean SaveVis); +geBoolean PrepAllGBSPModels(void); +geBoolean ConvertGBSPToFile(char *FileName); + +#endif diff --git a/GBSPLib/Gbspfile.h b/GBSPLib/Gbspfile.h new file mode 100644 index 0000000..f2849cd --- /dev/null +++ b/GBSPLib/Gbspfile.h @@ -0,0 +1,353 @@ +/****************************************************************************************/ +/* GBSPFile.h */ +/* */ +/* Author: John Pollard */ +/* Description: Loads a BSP */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GBSPFILE_H +#define GBSPFILE_H + +#include +#include + +#include "DCommon.h" +#include "MathLib.h" +#include "vfile.h" +#include "motion.h" +#include "Vec3d.h" + +#define GBSP_VERSION 15 + +#define GBSP_CHUNK_HEADER 0 + +#define GBSP_CHUNK_MODELS 1 +#define GBSP_CHUNK_NODES 2 +#define GBSP_CHUNK_BNODES 3 +#define GBSP_CHUNK_LEAFS 4 +#define GBSP_CHUNK_CLUSTERS 5 +#define GBSP_CHUNK_AREAS 6 +#define GBSP_CHUNK_AREA_PORTALS 7 +#define GBSP_CHUNK_LEAF_SIDES 8 +#define GBSP_CHUNK_PORTALS 9 +#define GBSP_CHUNK_PLANES 10 +#define GBSP_CHUNK_FACES 11 +#define GBSP_CHUNK_LEAF_FACES 12 +#define GBSP_CHUNK_VERT_INDEX 13 +#define GBSP_CHUNK_VERTS 14 +#define GBSP_CHUNK_RGB_VERTS 15 +#define GBSP_CHUNK_ENTDATA 16 + +#define GBSP_CHUNK_TEXINFO 17 +#define GBSP_CHUNK_TEXTURES 18 +#define GBSP_CHUNK_TEXDATA 19 + +#define GBSP_CHUNK_LIGHTDATA 20 +#define GBSP_CHUNK_VISDATA 21 + +#define GBSP_CHUNK_SKYDATA 22 + +#define GBSP_CHUNK_PALETTES 23 + +#define GBSP_CHUNK_MOTIONS 24 + +#define GBSP_CHUNK_END 0xffff + +#define MAX_GBSP_ENTDATA 200000*2 + +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= +// IF THESE FLAGS CHANGE, THEY MUST CHANGE IN GBSPFILE.H in Genesis AND GBSPLIB!!!!! +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= +#define BSP_CONTENTS_SOLID2 (1<<0) // Solid (Visible) +#define BSP_CONTENTS_WINDOW2 (1<<1) // Window (Visible) +#define BSP_CONTENTS_EMPTY2 (1<<2) // Empty but Visible (water, lava, etc...) + +#define BSP_CONTENTS_TRANSLUCENT2 (1<<3) // Vis will see through it +#define BSP_CONTENTS_WAVY2 (1<<4) // Wavy (Visible) +#define BSP_CONTENTS_DETAIL2 (1<<5) // Won't be included in vis oclusion + +#define BSP_CONTENTS_CLIP2 (1<<6) // Structural but not visible +#define BSP_CONTENTS_HINT2 (1<<7) // Primary splitter (Non-Visible) +#define BSP_CONTENTS_AREA2 (1<<8) // Area seperator leaf (Non-Visible) + +#define BSP_CONTENTS_FLOCKING (1<<9) // flocking flag. Not really a contents type +#define BSP_CONTENTS_SHEET (1<<10) +#define RESERVED3 (1<<11) +#define RESERVED4 (1<<12) +#define RESERVED5 (1<<13) +#define RESERVED6 (1<<14) +#define RESERVED7 (1<<15) + +// 16-31 reserved for user contents +#define BSP_CONTENTS_USER1 (1<<16) +#define BSP_CONTENTS_USER2 (1<<17) +#define BSP_CONTENTS_USER3 (1<<18) +#define BSP_CONTENTS_USER4 (1<<19) +#define BSP_CONTENTS_USER5 (1<<20) +#define BSP_CONTENTS_USER6 (1<<21) +#define BSP_CONTENTS_USER7 (1<<22) +#define BSP_CONTENTS_USER8 (1<<23) +#define BSP_CONTENTS_USER9 (1<<24) +#define BSP_CONTENTS_USER10 (1<<25) +#define BSP_CONTENTS_USER11 (1<<26) +#define BSP_CONTENTS_USER12 (1<<27) +#define BSP_CONTENTS_USER13 (1<<28) +#define BSP_CONTENTS_USER14 (1<<29) +#define BSP_CONTENTS_USER15 (1<<30) +#define BSP_CONTENTS_USER16 (1<<31) +// 16-31 reserved for user contents + + +// These contents are all solid types +#define BSP_CONTENTS_SOLID_CLIP (BSP_CONTENTS_SOLID2 | BSP_CONTENTS_WINDOW2 | BSP_CONTENTS_CLIP2) + +// These contents are all visible types +#define BSP_VISIBLE_CONTENTS ( BSP_CONTENTS_SOLID2 | \ + BSP_CONTENTS_EMPTY2 | \ + BSP_CONTENTS_WINDOW2 | \ + BSP_CONTENTS_SHEET | \ + BSP_CONTENTS_WAVY2) + +// These contents define where faces are NOT allowed to merge across +#define BSP_MERGE_SEP_CONTENTS ( BSP_CONTENTS_WAVY2 | \ + BSP_CONTENTS_HINT2 | \ + BSP_CONTENTS_AREA2) +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= +//*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + +typedef struct +{ + int32 Type; // Type of chunk + int32 Size; // Size of each element + int32 Elements; // Number of elements +} GBSP_Chunk; + +typedef struct +{ + int32 Type; + int32 Size; + int32 Elements; + void *Data; +} GBSP_ChunkData; + +typedef struct +{ + char TAG[5]; // 'G','B','S','P','0' + int32 Version; + SYSTEMTIME BSPTime; // Time at which the BSP data was created... +} GBSP_Header; + +typedef struct +{ + geVec3d Axis; // Axis of rotation + geFloat Dpm; // Degres per minute + int32 Textures[6]; // Texture indexes for all six sides... + geFloat DrawScale; +} GFX_SkyData; + +typedef struct +{ + geVec3d Normal; + geFloat Dist; + int32 Type; // Defined in MathLib.h (PLANE_X, PLANE_Y, etc...) +} GFX_Plane; + +typedef struct +{ + int32 Children[2]; // Children, indexed into GFXNodes, < 0 = Leaf + int32 NumFaces; // Num faces + int32 FirstFace; // First face + int32 PlaneNum; // + geVec3d Mins; // For BBox frustum culling + geVec3d Maxs; +} GFX_Node; + +typedef struct +{ + int32 Children[2]; // Children, indexed into GFXBNodes, < 0 = Contents + int32 PlaneNum; // +} GFX_BNode; + +typedef struct +{ + int32 PlaneNum; + int32 PlaneSide; +} GFX_LeafSide; + +typedef struct +{ + int32 ModelNum; + int32 Area; +} GFX_AreaPortal; + +typedef struct +{ + int32 NumAreaPortals; + int32 FirstAreaPortal; +} GFX_Area; + +typedef struct +{ + int32 Contents; // Contents of leaf + geVec3d Mins; // For BBox vis testing + geVec3d Maxs; + int32 FirstFace; // First face in GFXLeafFaces + int32 NumFaces; + + int32 FirstPortal; // Number of portals + int32 NumPortals; // First portal + + int32 Cluster; // CHANGE: CLUSTER + int32 Area; + + int32 FirstSide; // Planes (plus bevels) pointing out of leaf + int32 NumSides; // (For axial bounding box collisions) +} GFX_Leaf; + +typedef struct +{ + int32 VisOfs; +} GFX_Cluster; + +typedef struct +{ + int32 FirstVert; // First vertex indexed in GFXVertices + int32 NumVerts; // Number of vertices in face + int32 PlaneNum; // PlaneNum + int32 PlaneSide; // 0 = Same direction of plane normal + int32 TexInfo; + int32 LightOfs; // Offset info GFXLightData, -1 = No light + int32 LWidth; + int32 LHeight; + uint8 LTypes[4]; +} GFX_Face; + +typedef struct +{ + int32 RootNode[2]; // Top level Node in GFXNodes/GFXBNodes + geVec3d Mins; + geVec3d Maxs; + geVec3d Origin; // Center of model + int32 FirstFace; // First face in GFXFaces + int32 NumFaces; // Number of faces + int32 FirstLeaf; // First leaf in GFXLeafs; + int32 NumLeafs; // Number of leafs (not including solid leaf) + int32 FirstCluster; + int32 NumClusters; + int32 Areas[2]; // Area on each side of the model + geMotion * Motion; +} GFX_Model; + +typedef struct +{ + uint8 RGB[256*3]; +} GFX_Palette; + +typedef struct +{ + char Name[32]; + uint32 Flags; + int32 Width; + int32 Height; + int32 Offset; + int32 PaletteIndex; +} GFX_Texture; + +typedef struct +{ + geVec3d Vecs[2]; + geFloat Shift[2]; + geFloat DrawScale[2]; + int32 Flags; + geFloat FaceLight; + geFloat ReflectiveScale; + geFloat Alpha; + geFloat MipMapBias; + int32 Texture; +} GFX_TexInfo; + +typedef struct +{ + geVec3d Origin; // Center of portal + int32 LeafTo; // Leaf looking into +} GFX_Portal; + +extern GBSP_Header GBSPHeader; // Header +extern GFX_SkyData GFXSkyData; +extern GFX_Model *GFXModels; // Model data +extern GFX_Node *GFXNodes; // Nodes +extern GFX_BNode *GFXBNodes; // Bevel Clip Nodes +extern GFX_Leaf *GFXLeafs; // Leafs +extern GFX_Cluster *GFXClusters; // CHANGE: CLUSTER +extern GFX_Area *GFXAreas; +extern GFX_AreaPortal *GFXAreaPortals; +extern GFX_Plane *GFXPlanes; // Planes +extern GFX_Face *GFXFaces; // Faces +extern int32 *GFXLeafFaces; +extern GFX_LeafSide *GFXLeafSides; +extern geVec3d *GFXVerts; // Verts +extern int32 *GFXVertIndexList; // Index list +extern geVec3d *GFXRGBVerts; + +extern uint8 *GFXEntData; +extern GFX_Texture *GFXTextures; // Textures +extern GFX_TexInfo *GFXTexInfo; // TexInfo +extern uint8 *GFXTexData; // TexData +extern DRV_Palette *GFXPalettes; // Palettes + +extern uint8 *GFXMotionData; // Model motion keyframe data + +extern uint8 *GFXLightData; // Lightmap data +extern uint8 *GFXVisData; // Vis data +extern GFX_Portal *GFXPortals; // Portal data + +extern int32 NumGFXModels; +extern int32 NumGFXNodes; +extern int32 NumGFXBNodes; +extern int32 NumGFXLeafs; +extern int32 NumGFXClusters; // CHANGE: CLUSTER +extern int32 NumGFXAreas; +extern int32 NumGFXAreaPortals; +extern int32 NumGFXPlanes; +extern int32 NumGFXFaces; +extern int32 NumGFXLeafFaces; +extern int32 NumGFXLeafSides; +extern int32 NumGFXVerts; +extern int32 NumGFXVertIndexList; // For RGB verts, and regular verts +extern int32 NumGFXRGBVerts; + +extern int32 NumGFXEntData; +extern int32 NumGFXTextures; +extern int32 NumGFXTexInfo; +extern int32 NumGFXTexData; +extern int32 NumGFXPalettes; + +extern int32 NumGFXLightData; +extern int32 NumGFXVisData; +extern int32 NumGFXPortals; + +extern int32 NumGFXMotionBytes; + +geBoolean LoadGBSPFile(char *FileName); +geBoolean SaveGBSPFile(char *FileName); +geBoolean FreeGBSPFile(void); +geBoolean WriteChunk(GBSP_Chunk *Chunk, void *Data, geVFile *f); + +geBoolean WriteChunks(GBSP_ChunkData *Data, int32 NumChunkData, geVFile *f); + + +#endif \ No newline at end of file diff --git a/GBSPLib/Gbsplib.cpp b/GBSPLib/Gbsplib.cpp new file mode 100644 index 0000000..b2d1959 --- /dev/null +++ b/GBSPLib/Gbsplib.cpp @@ -0,0 +1,274 @@ +/****************************************************************************************/ +/* GBSPLib.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: API to GBSPLIB */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "GBSPPrep.h" +#include "BSP.h" +#include "Vis.h" +#include "Light.h" +#include "Map.h" + +#define HANDLE_EXCEPTIONS + +GBSP_Hook GHook; + +GBSP_RETVAL GBSP_CreateBSP(char *FileName); +GBSP_RETVAL GBSP_SaveGBSPFile(char *FileName); +void GBSP_FreeBSP(void); +GBSP_RETVAL GBSP_VisGBSPFile(char *FileName); +GBSP_RETVAL GBSP_LightGBSPFile(char *FileName, LightParms *Parms); +geBoolean GBSP_Cancel(void); +geBoolean GBSP_UpdateEntities(char *MapName, char *BSPName); + +geBoolean CancelRequest; + +//======================================================================================== +// GBSP_CreateBSP +//======================================================================================== +GBSP_RETVAL GBSP_CreateBSP(char *FileName, BspParms *Parms) +{ + CancelRequest = GE_FALSE; + + GHook.Printf("** BSP Compile Version: %i \n", GBSP_VERSION); + GHook.Printf("** Build Date/Time: "__DATE__","__TIME__"\n"); + +#ifdef HANDLE_EXCEPTIONS + __try + { + if (!CreateBSP(FileName, Parms)) + { + if (CancelRequest) + return GBSP_CANCEL; + else + return GBSP_ERROR; + } + + return GBSP_OK; + } + __except(1) + { + // Clean up all errors, free any possible left-over data + GHook.Printf("GBSPLib: Fatal error in BSP! Doing Clean-up work.\n"); + + CleanupGBSP(); + return GBSP_ERROR; + } +#else + if (!CreateBSP(FileName, Parms)) + { + if (CancelRequest) + return GBSP_CANCEL; + else + return GBSP_ERROR; + } +#endif + + return GBSP_OK; +} + +//======================================================================================== +// GBSP_UpdateEntities +//======================================================================================== +geBoolean GBSP_UpdateEntities(char *MapName, char *BSPName) +{ + if (!UpdateEntities(MapName, BSPName)) + { + if (CancelRequest) + return GBSP_CANCEL; + else + return GBSP_ERROR; + } + + return GBSP_OK; +} + +//======================================================================================== +// GBSP_SaveGBSPFile +//======================================================================================== +GBSP_RETVAL GBSP_SaveGBSPFile(char *FileName) +{ + CancelRequest = GE_FALSE; + +#ifdef HANDLE_EXCEPTIONS + __try + { + if (!ConvertGBSPToFile(FileName)) + { + if (CancelRequest) + return GBSP_CANCEL; + else + return GBSP_ERROR; + } + } + __except(1) + { + // Clean up all errors, free any possible left-over data + GHook.Printf("GBSPLib: Fatal error Saving BSP! Doing Clean-up work.\n"); + + CleanupGBSP(); + return GBSP_ERROR; + } +#else + if (!ConvertGBSPToFile(FileName)) + { + if (CancelRequest) + return GBSP_CANCEL; + else + return GBSP_ERROR; + } +#endif + + return GBSP_OK; +} + +#ifdef SHOW_DEBUG_STATS + #include "Poly.h" + #include "Brush2.h" +#endif +//======================================================================================== +// GBSP_FreeBSP +//======================================================================================== +void GBSP_FreeBSP(void) +{ + FreeAllGBSPData(); + FreeAllEntities(); + +#ifdef SHOW_DEBUG_STATS + GHook.Printf("------------------------\n"); + GHook.Printf("Num Total Verts : %5i\n", gTotalVerts); + GHook.Printf("Num Peek Verts : %5i\n", gPeekVerts); + GHook.Printf("Num Total Brushes : %5i\n", gTotalBrushes); + GHook.Printf("Num Peek Brushes : %5i\n", gPeekBrushes); + GHook.Printf("------------------------\n"); +#endif +} + +//======================================================================================== +// GBSP_VisGBSPFile +//======================================================================================== +GBSP_RETVAL GBSP_VisGBSPFile(char *FileName, VisParms *Parms) +{ + CancelRequest = GE_FALSE; + +#ifdef HANDLE_EXCEPTIONS + __try + { + if (!VisGBSPFile(FileName, Parms)) + { + if (CancelRequest) + return GBSP_CANCEL; + else + return GBSP_ERROR; + } + } + __except(1) + { + // Clean up all errors, free any possible left-over data + GHook.Printf("GBSPLib: Fatal error in Vis! Doing Clean-up work.\n"); + + CleanupVis(); + return GBSP_ERROR; + } +#else + if (!VisGBSPFile(FileName, Parms)) + { + if (CancelRequest) + return GBSP_CANCEL; + else + return GBSP_ERROR; + } +#endif + + return GBSP_OK; +} + +//======================================================================================== +// GBSP_LightGBSPFile +//======================================================================================== +GBSP_RETVAL GBSP_LightGBSPFile(char *FileName, LightParms *Parms) +{ + CancelRequest = GE_FALSE; + +#ifdef HANDLE_EXCEPTIONS + __try + { + if (!LightGBSPFile(FileName, Parms)) + { + if (CancelRequest) + return GBSP_CANCEL; + else + return GBSP_ERROR; + } + } + __except(1) + { + // Clean up all errors, free any possible left-over data + GHook.Printf("GBSPLib: Fatal error in Radiosity! Doing Clean-up work.\n"); + + CleanupLight(); + return GBSP_ERROR; + } +#else + if (!LightGBSPFile(FileName, Parms)) + { + if (CancelRequest) + return GBSP_CANCEL; + else + return GBSP_ERROR; + } +#endif + + return GBSP_OK; +} + +geBoolean GBSP_Cancel(void) +{ + CancelRequest = GE_TRUE; + + GHook.Printf("Cancel requested...\n"); + + return GE_TRUE; +} + +GBSP_FuncHook GBSP_FHook = { + //5, + GBSP_VERSION_MAJOR, + GBSP_VERSION_MINOR, + GBSP_CreateBSP, + GBSP_SaveGBSPFile, + GBSP_FreeBSP, + GBSP_VisGBSPFile, + GBSP_LightGBSPFile, + GBSP_Cancel, + GBSP_UpdateEntities +}; + +//======================================================================================== +// GBSP_Init +//======================================================================================== +DllExport GBSP_FuncHook *GBSP_Init(GBSP_Hook *Hook) +{ + GHook = *Hook; + + return &GBSP_FHook; +} + diff --git a/GBSPLib/Gbsplib.h b/GBSPLib/Gbsplib.h new file mode 100644 index 0000000..1ab5942 --- /dev/null +++ b/GBSPLib/Gbsplib.h @@ -0,0 +1,118 @@ +/****************************************************************************************/ +/* GBSPLib.h */ +/* */ +/* Author: John Pollard */ +/* Description: API to GBSPLIB */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef GBSPLIB_H +#define GBSPLIB_H + +#include + +#include "MathLib.h" + +#include "Vec3d.h" + +#define GBSP_VERSION_MAJOR 6 +#define GBSP_VERSION_MINOR 0 + +//#define SHOW_DEBUG_STATS + +//==================================================================================== +// Main driver interfaces +//==================================================================================== +#define DllImport extern "C" __declspec( dllimport ) +#define DllExport extern "C" __declspec( dllexport ) + +typedef void ERROR_CB(char *String, ...); +typedef void PRINTF_CB(char *String, ...); + +typedef struct +{ + geBoolean Verbose; + geBoolean EntityVerbose; + +} BspParms; + +typedef struct +{ + geBoolean Verbose; + geBoolean ExtraSamples; + geFloat LightScale; + geBoolean Radiosity; + int32 NumBounce; + geFloat PatchSize; + geBoolean FastPatch; + geFloat ReflectiveScale; + + geVec3d MinLight; // R,G,B (XYZ) min color for each faces lightmap + +} LightParms; + +typedef struct +{ + geBoolean Verbose; + geBoolean FullVis; + geBoolean SortPortals; + +} VisParms; + +typedef enum +{ + GBSP_ERROR, + GBSP_OK, + GBSP_CANCEL +} GBSP_RETVAL; + +extern geBoolean CancelRequest; // Global cancel request... + +typedef GBSP_RETVAL GBSP_CREATE_BSP(char *MapText, BspParms *Parms); +typedef GBSP_RETVAL GBSP_S_FILE(char *FileName); +typedef void GBSP_FREE_BSP(void); +typedef GBSP_RETVAL GBSP_VIS_FILE(char *FileName, VisParms *Parms); +typedef GBSP_RETVAL GBSP_LIGHT_FILE(char *FileName, LightParms *Parms); +typedef geBoolean GBSP_CANCEL_COMPILE(void); +typedef geBoolean GBSP_UPDATE_ENTITIES(char *MapName, char *BSPName); + +typedef struct +{ + ERROR_CB *Error; // This must be set by caller + PRINTF_CB *Printf; // This too + +} GBSP_Hook; + +typedef struct +{ + int32 VersionMajor; // Major changes, like function parms... + int32 VersionMinor; // Internal changes, that do not effect caller + GBSP_CREATE_BSP *GBSP_CreateBSP; + GBSP_S_FILE *GBSP_SaveGBSPFile; + GBSP_FREE_BSP *GBSP_FreeBSP; + GBSP_VIS_FILE *GBSP_VisGBSPFile; + GBSP_LIGHT_FILE *GBSP_LightGBSPFile; + GBSP_CANCEL_COMPILE *GBSP_Cancel; + GBSP_UPDATE_ENTITIES *GBSP_UpdateEntities; +} GBSP_FuncHook; + +extern GBSP_Hook GHook; + +typedef GBSP_FuncHook *GBSP_INIT(GBSP_Hook *Hook); + +#endif + + diff --git a/GBSPLib/Leaf.cpp b/GBSPLib/Leaf.cpp new file mode 100644 index 0000000..4370a49 --- /dev/null +++ b/GBSPLib/Leaf.cpp @@ -0,0 +1,612 @@ +/****************************************************************************************/ +/* Leaf.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Creates leaf collision hulls, areas, etc... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "Ram.h" +#include "Portals.h" +#include "GBSPFile.h" +#include "BSP.h" +#include "Poly.h" +#include "Leaf.h" +#include "Brush2.h" + +#include "Vec3d.h" + +int32 NumLeafClusters; + +//====================================================================================== +// FillLeafClusters_r +//====================================================================================== +geBoolean FillLeafClusters_r(GBSP_Node *Node, int32 Cluster) +{ + if (Node->PlaneNum == PLANENUM_LEAF) + { + if ((Node->Contents & BSP_CONTENTS_SOLID2)) + Node->Cluster = -1; + else + Node->Cluster = Cluster; + + return GE_TRUE; + } + + Node->Cluster = Cluster; + + FillLeafClusters_r(Node->Children[0], Cluster); + FillLeafClusters_r(Node->Children[1], Cluster); + + return GE_TRUE; +} + +//====================================================================================== +// FindLeafClusters_r +//====================================================================================== +geBoolean CreateLeafClusters_r(GBSP_Node *Node) +{ + if (Node->PlaneNum != PLANENUM_LEAF && !Node->Detail) + { + CreateLeafClusters_r(Node->Children[0]); + CreateLeafClusters_r(Node->Children[1]); + return GE_TRUE; + } + + // Either a leaf or detail node + if (Node->Contents & BSP_CONTENTS_SOLID2) + { + Node->Cluster = -1; + return GE_TRUE; + } + + if (!FillLeafClusters_r(Node, NumLeafClusters)) + return GE_FALSE; + + NumLeafClusters++; + + return GE_TRUE; +} + +//====================================================================================== +// CreateLeafClusters +//====================================================================================== +geBoolean CreateLeafClusters(GBSP_Node *RootNode) +{ + GHook.Printf(" --- CreateLeafClusters --- \n"); + + if (!CreateLeafClusters_r(RootNode)) + { + GHook.Error("CreateLeafClusters: Failed to find leaf clusters.\n"); + return GE_FALSE; + } + + if (Verbose) + GHook.Printf("Num Clusters : %5i\n", NumLeafClusters); + + return GE_TRUE; +} + +//====================================================================================== +// Leaf Sides (Used for expandable collision HULL) +//====================================================================================== + +int32 NumLeafSides; +int32 NumLeafBevels; + +GBSP_LeafSide LeafSides[MAX_LEAF_SIDES]; + +#define MAX_TEMP_LEAF_SIDES 100 + +int32 CNumLeafSides; +int32 LPlaneNumbers[MAX_TEMP_LEAF_SIDES]; +int32 LPlaneSides[MAX_TEMP_LEAF_SIDES]; + +//==================================================================================== +// FinishLeafSides +//==================================================================================== +geBoolean FinishLeafSides(GBSP_Node *Node) +{ + geVec3d Mins, Maxs; + GBSP_Plane Plane; + int32 Axis, i, Dir; + + if (!GetLeafBBoxFromPortals(Node, &Mins, &Maxs)) + { + GHook.Error("FinishLeafSides: Could not get leaf portal BBox.\n"); + return GE_FALSE; + } + + if (CNumLeafSides < 4) + GHook.Printf("*WARNING* FinishLeafSides: Incomplete leaf volume.\n"); + + // Add any bevel planes to the sides so we can expand them for axial box collisions + else for (Axis=0 ; Axis <3 ; Axis++) + { + for (Dir=-1 ; Dir <= 1 ; Dir+=2) + { + // See if the plane is allready in the sides + for (i=0; i< CNumLeafSides; i++) + { + Plane = Planes[LPlaneNumbers[i]]; + if (LPlaneSides[i]) + { + geVec3d_Inverse(&Plane.Normal); + Plane.Dist = -Plane.Dist; + } + + if (VectorToSUB(Plane.Normal, Axis) == (geFloat)Dir) + break; + } + + if (i >= CNumLeafSides) + { + // Add a new axial aligned side + + geVec3d_Clear(&Plane.Normal); + + VectorToSUB(Plane.Normal, Axis) = (geFloat)Dir; + + // get the mins/maxs from the gbsp brush + if (Dir == 1) + Plane.Dist = VectorToSUB(Maxs, Axis); + else + Plane.Dist = -VectorToSUB(Mins, Axis); + + LPlaneNumbers[i] = FindPlane(&Plane, &LPlaneSides[i]); + + if (LPlaneNumbers[i] == -1) + { + GHook.Error("FinishLeafSides: Could not create the plane.\n"); + return GE_FALSE; + } + + CNumLeafSides++; + + NumLeafBevels++; + } + } + } + + Node->FirstSide = NumLeafSides; + Node->NumSides = CNumLeafSides; + + for (i=0; i< CNumLeafSides; i++) + { + if (NumLeafSides >= MAX_LEAF_SIDES) + { + GHook.Error("FinishLeafSides: Max Leaf Sides.\n"); + return GE_FALSE; + } + + LeafSides[NumLeafSides].PlaneNum = LPlaneNumbers[i]; + LeafSides[NumLeafSides].PlaneSide = LPlaneSides[i]; + + NumLeafSides++; + } + + return GE_TRUE; +} + +//==================================================================================== +// CreateLeafSides_r +//==================================================================================== +geBoolean CreateLeafSides_r(GBSP_Node *Node) +{ + GBSP_Portal *Portal, *Next; + int32 Side, i; + + Node->FirstSide = -1; + Node->NumSides = 0; + + if (Node->PlaneNum == PLANENUM_LEAF) // At a leaf, convert portals to leaf sides... + { + if (!(Node->Contents & BSP_CONTENTS_SOLID_CLIP)) // Don't convert empty leafs + return GE_TRUE; + + if (!Node->Portals) + { + GHook.Printf("*WARNING* CreateLeafSides: Contents leaf with no portals!\n"); + return GE_TRUE; + } + + // Reset number of sides for this solid leaf (should we save out other contents?) + // (this is just for a collision hull for now...) + CNumLeafSides = 0; + + for (Portal = Node->Portals; Portal; Portal = Next) + { + Side = (Portal->Nodes[0] == Node); + Next = Portal->Next[!Side]; + + for (i=0; i< CNumLeafSides; i++) + { + if (LPlaneNumbers[i] == Portal->PlaneNum && LPlaneSides[i] == Side) + break; + } + + // Make sure we don't duplicate planes (this happens with portals) + if (i >= MAX_TEMP_LEAF_SIDES) + { + GHook.Error("CreateLeafSides_r: Max portal leaf sides.\n"); + return GE_FALSE; + } + + if (i >= CNumLeafSides) + { + LPlaneNumbers[i] = Portal->PlaneNum; + LPlaneSides[i] = Side; + CNumLeafSides++; + } + + } + + if (!FinishLeafSides(Node)) + { + return GE_FALSE; + } + + return GE_TRUE; + } + + if (!CreateLeafSides_r(Node->Children[0])) + return GE_FALSE; + + if (!CreateLeafSides_r(Node->Children[1])) + return GE_FALSE; + + return GE_TRUE; +} + +//==================================================================================== +// CreateLeafSides +// Creates leaf sides with bevel edges for axial bounding box clipping hull +//==================================================================================== +geBoolean CreateLeafSides(GBSP_Node *RootNode) +{ + if (Verbose) + GHook.Printf(" --- Create Leaf Sides --- \n"); + + if (!CreateLeafSides_r(RootNode)) + return GE_FALSE; + + if (Verbose) + { + GHook.Printf("Num Leaf Sides : %5i\n", NumLeafSides); + GHook.Printf("Num Leaf Bevels : %5i\n", NumLeafBevels); + } + + return GE_TRUE; +} + +//===================================================================================== +// *** AREA LEAFS *** +//===================================================================================== + +#define MAX_AREAS 256 +#define MAX_AREA_PORTALS 1024 + +//===================================================================================== +// ModelForLeafNode +//===================================================================================== +GBSP_Model *ModelForLeafNode(GBSP_Node *Node) +{ + GBSP_Brush *Brush; + + if (Node->PlaneNum != PLANENUM_LEAF) + { + GHook.Error("ModelForLeafNode: Node not a leaf!\n"); + return NULL; + } + + for (Brush = Node->BrushList; Brush; Brush = Brush->Next) + { + if (Brush->Original->EntityNum) + break; + } + + if (!Brush) + return NULL; + + return &BSPModels[Entities[Brush->Original->EntityNum].ModelNum]; +} + +//===================================================================================== +// FillAreas_r +//===================================================================================== +geBoolean FillAreas_r(GBSP_Node *Node, int32 Area) +{ + GBSP_Portal *Portal; + int32 Side; + + if ((Node->Contents & BSP_CONTENTS_SOLID2)) + return GE_TRUE; // Stop at solid leafs + + if ((Node->Contents & BSP_CONTENTS_AREA2)) + { + GBSP_Model *Model; + + Model = ModelForLeafNode(Node); + + if (!Model) + { + GHook.Error("FillAreas_r: No model for leaf.\n"); + return GE_FALSE; + } + + if (Model->Areas[0] == Area || Model->Areas[1] == Area) + return GE_TRUE; // Already flooded into this portal from this area + + if (!Model->Areas[0]) + Model->Areas[0] = Area; + else if (!Model->Areas[1]) + Model->Areas[1] = Area; + else + GHook.Printf("*WARNING* FillAreas_r: Area Portal touched more than 2 areas.\n"); + + return GE_TRUE; + } + + if (Node->Area != 0) // Already set + return GE_TRUE; + + // Mark it + Node->Area = Area; + + // Flood through all of this leafs portals + for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) + { + Side = (Portal->Nodes[1] == Node); + + if (!FillAreas_r(Portal->Nodes[!Side], Area)) + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// CreateAreas_r +//===================================================================================== +geBoolean CreateAreas_r(GBSP_Node *Node) +{ + if (Node->PlaneNum == PLANENUM_LEAF) + { + if (Node->Contents & BSP_CONTENTS_SOLID2) // Stop at solid + return GE_TRUE; + + if (Node->Contents & BSP_CONTENTS_AREA2) // Don't start at area portals + return GE_TRUE; + + if (Node->Area != 0) // Already set + return GE_TRUE; + + if (NumGFXAreas >= MAX_AREAS) + { + GHook.Error("CreateAreas_r: Max Areas.\n"); + return GE_FALSE; + } + + // Once we find a normal leaf, flood out marking the current area + // stopping at other areas leafs, and solid leafs (unpassable leafs) + if (!FillAreas_r(Node, NumGFXAreas++)) + return GE_FALSE; + + return GE_TRUE; + } + + if (!CreateAreas_r(Node->Children[0])) + return GE_FALSE; + if (!CreateAreas_r(Node->Children[1])) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// FinishAreaPortals_r +//===================================================================================== +geBoolean FinishAreaPortals_r(GBSP_Node *Node) +{ + GBSP_Model *Model; + + if (Node->PlaneNum != PLANENUM_LEAF) + { + if (!FinishAreaPortals_r(Node->Children[0])) + return GE_FALSE; + if (!FinishAreaPortals_r(Node->Children[1])) + return GE_FALSE; + } + + if (!(Node->Contents & BSP_CONTENTS_AREA2)) + return GE_TRUE; // Only interested in area portals + + if (Node->Area) + return GE_TRUE; // Already set... + + Model = ModelForLeafNode(Node); + + if (!Model) + { + GHook.Error("FinishAreaPortals_r: No model for leaf.\n"); + return GE_FALSE; + } + + Node->Area = Model->Areas[0]; // Set to first area that flooded into portal + Model->IsAreaPortal = GE_TRUE; + + return GE_TRUE; +} + +//===================================================================================== +// FinishAreas +//===================================================================================== +geBoolean FinishAreas(void) +{ + int32 i; + GFX_Area *a; + GBSP_Model *pModel; + int32 m; + + // First, go through and print out all errors pertaining to model areas + for (pModel = BSPModels+1, m=1; m < NumBSPModels; m++, pModel++) // Skip world model + { + if (!pModel->IsAreaPortal) + continue; // Not an area portal model + + if (!pModel->Areas[0]) + GHook.Printf("*WARNING* FinishAreas: AreaPortal did not touch any areas!\n"); + else if (!pModel->Areas[1]) + GHook.Printf("*WARNING* FinishAreas: AreaPortal only touched one area.\n"); + } + + NumGFXAreaPortals = 0; // Clear the Portals var + + // Area 0 is the invalid area, set it here, and skip it in the loop below + GFXAreas[0].FirstAreaPortal = 0; + GFXAreas[0].NumAreaPortals = 0; + + for (a = GFXAreas+1, i = 1; i < NumGFXAreas; i++, a++) // Skip invalid area (area 0) + { + a->FirstAreaPortal = NumGFXAreaPortals; + + // Go through all the area portals (models), and create all portals that belong to this area + for (pModel = BSPModels+1, m=1; m < NumBSPModels; m++, pModel++) // Skip world model + { + int32 a0, a1; + GFX_AreaPortal *p; + + a0 = pModel->Areas[0]; + a1 = pModel->Areas[1]; + + if (!a0 || !a1) + continue; // Model didn't seperate 2 areas + + if (a0 == a1) // Portal seperates same area + continue; + + if (a0 != i && a1 != i) + continue; // Portal is not a part of this area + + if (NumGFXAreaPortals >= MAX_AREA_PORTALS) + { + GHook.Error("FinishAreas: Max area portals.\n"); + return GE_FALSE; // Oops + } + + p = &GFXAreaPortals[NumGFXAreaPortals]; + + if (a0 == i) // Grab the area on the opposite side of the portal + p->Area = a1; + else if (a1 == i) + p->Area = a0; + + p->ModelNum = m; // Set the portals model number + NumGFXAreaPortals++; + } + a->NumAreaPortals = NumGFXAreaPortals - a->FirstAreaPortal; + } + + return GE_TRUE; +} + +//===================================================================================== +// CreateAreas +//===================================================================================== +geBoolean CreateAreas(GBSP_Node *RootNode) +{ + GBSP_Model *pModel; + int32 m; + + GHook.Printf(" --- Create Area Leafs --- \n"); + + // Clear all model area info + for (pModel = BSPModels+1, m=1; m < NumBSPModels; m++, pModel++) // Skip world model + { + pModel->Areas[0] = pModel->Areas[1] = 0; + pModel->IsAreaPortal = GE_FALSE; + } + + if (GFXAreas) + geRam_Free(GFXAreas); + if (GFXAreaPortals) + geRam_Free(GFXAreaPortals); + + GFXAreas = GE_RAM_ALLOCATE_ARRAY(GFX_Area, MAX_AREAS); + + if (!GFXAreas) + return GE_FALSE; + + GFXAreaPortals = GE_RAM_ALLOCATE_ARRAY(GFX_AreaPortal, MAX_AREA_PORTALS); + + if (!GFXAreaPortals) + return GE_FALSE; + + NumGFXAreas = 1; // 0 is invalid + NumGFXAreaPortals = 0; + + if (!CreateAreas_r(RootNode)) + { + GHook.Error("Could not create model areas.\n"); + return GE_FALSE; + } + + if (!FinishAreaPortals_r(RootNode)) + { + GHook.Error("CreateAreas: FinishAreaPortals_r failed.\n"); + return GE_FALSE; + } + + if (!FinishAreas()) + { + GHook.Error("Could not finalize model areas.\n"); + return GE_FALSE; + } + + //GHook.Printf("Num Areas : %5i\n", NumGFXAreas-1); + + return GE_TRUE; +} + +//===================================================================================== +// FindLeaf +//===================================================================================== +GBSP_Node *FindLeaf(GBSP_Node *Node, geVec3d *Origin) +{ + GBSP_Plane *Plane; + geFloat Dist; + + while(Node && Node->PlaneNum != PLANENUM_LEAF) + { + Plane = &Planes[Node->PlaneNum]; + Dist = geVec3d_DotProduct(Origin, &Plane->Normal) - Plane->Dist; + if (Dist > 0) + Node = Node->Children[0]; + else + Node = Node->Children[1]; + } + + if (!Node) + { + GHook.Error("FindLeaf: NULL Node/Leaf.\n"); + return NULL; + } + + return Node; +} diff --git a/GBSPLib/Leaf.h b/GBSPLib/Leaf.h new file mode 100644 index 0000000..092c1ba --- /dev/null +++ b/GBSPLib/Leaf.h @@ -0,0 +1,43 @@ +/****************************************************************************************/ +/* Leaf.h */ +/* */ +/* Author: John Pollard */ +/* Description: Creates leaf collision hulls, areas, etc... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef LEAF_H +#define LEAF_H + +#include + +#include "BSP.h" + +#define MAX_LEAF_SIDES 64000*4 + + +extern int32 NumLeafClusters; +extern int32 NumLeafSides; +extern int32 NumLeafBevels; + +extern GBSP_LeafSide LeafSides[MAX_LEAF_SIDES]; + +geBoolean CreateLeafClusters(GBSP_Node *RootNode); +geBoolean CreateLeafSides(GBSP_Node *RootNode); +geBoolean CreateAreas(GBSP_Node *RootNode); +GBSP_Node *FindLeaf(GBSP_Node *Node, geVec3d *Origin); + +#endif \ No newline at end of file diff --git a/GBSPLib/Light.cpp b/GBSPLib/Light.cpp new file mode 100644 index 0000000..68aeafd --- /dev/null +++ b/GBSPLib/Light.cpp @@ -0,0 +1,2411 @@ +/****************************************************************************************/ +/* Light.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Lights a BSP */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "Math.h" +#include "MathLib.h" +#include "GBSPFile.h" +#include "Light.h" +#include "Map.h" +#include "Texture.h" +#include "Utils.h" +#include "BSP.h" + +#include "Vec3d.h" +#include "XForm3d.h" + +#include "Ram.h" + +#define RWM_GOURAUD 1 +#define DEBUG_RWM_GOURAUD 1 + +float LightScale = 1.00f; +float EntityScale = 1.00f; +float MaxLight = 230.0f; +int32 NumSamples = 5; + + +geBoolean LVerbose = GE_TRUE; +geBoolean DoRadiosity = GE_TRUE; +float PatchSize = 128.0f; +int32 NumBounce = 8; +geBoolean FastPatch = GE_TRUE; +geBoolean ExtraLightCorrection = GE_TRUE; +float ReflectiveScale = 1.0f; + +geVec3d MinLight; + +int32 NumLMaps; +int32 LightOffset; + +int32 RGBMaps = 0; +int32 REGMaps = 0; + +LInfo *Lightmaps; +FInfo *FaceInfo; + +geVec3d *VertNormals; + +void FinalizeRGBVerts(void); +void FinalizeRGBVert( geVec3d* a_Color ) ; +geBoolean LightFaces(int a_GouraudShading); +geBoolean MakeVertNormals(void); +geBoolean SaveLightmaps(geVFile *f); +void FreeLightmaps(void); +geBoolean ApplyLightsToFace(FInfo *FaceInfo, LInfo *LightInfo, float Scale); +geBoolean GouraudShadeFace(int32 FaceNum); +void GetFacePlane(int32 Face, GFX_Plane *Plane); +geBoolean CalcFaceInfo(FInfo *FaceInfo, LInfo *LightInfo); +void CalcFacePoints(FInfo *FaceInfo, LInfo *LightInfo, float UOfs, float VOfs); +float PlaneDistanceFast(geVec3d *Point, GFX_Plane *Plane); +geBoolean CreateDirectLights(void); +void FreeDirectLights(void); + +geBoolean StartWriting(geVFile *f); +geBoolean FinishWriting(geVFile *f); + +// For RayIntersect +int32 GlobalPlane; +int32 GlobalNode; +int32 GlobalSide; +geVec3d GlobalI; + +#define MAX_DIRECT_CLUSTER_LIGHTS 25000 +#define MAX_DIRECT_LIGHTS 5000 + +typedef enum +{ + DLight_Blank, + DLight_Point, + DLight_Spot, + DLight_Surface, + // LWM: start + DLight_Sun, + // LWM: end + // Wismerhill + DLight_SunLight +} Light_DirectLightType; + +typedef struct Light_DirectLight +{ + Light_DirectLight *Next; + int32 LType; + geVec3d Origin; + geVec3d Normal; + float Angle; + geVec3d Color; + float Intensity; + Light_DirectLightType Type; + // LWM: start + int SunFallOffType ; + float SunFallOffRadiusInTexels ; + float SunFallOff100PercentRadius ; + float SunFallOffAlpha ; + bool SunRGBOnly ; + bool SunRGBAlwaysVisible ; + // LWM: end +} Light_DirectLight; + +// LWM: start +#define SUN_MIN_FALLOFF_TYPE 0 +#define SUN_FALLOFF_NONE 0 +#define SUN_FALLOFF_HARD_RADIUS 1 +#define SUN_FALLOFF_GRADUALLY1 2 +#define SUN_FALLOFF_GRADUALLY2 3 +#define SUN_MAX_FALLOFF_TYPE 3 + +#define DEBUG_SUN 0 +// LWM: end + +Light_DirectLight *DirectClusterLights[MAX_DIRECT_CLUSTER_LIGHTS]; +Light_DirectLight *DirectLights[MAX_DIRECT_LIGHTS]; +int32 NumDirectLights = 0; + +#if DEBUG_RWM_GOURAUD +static void DebugWriteVertexSetFileName( const char* a_FileName ) ; +static void DebugWriteVertex( + const geVec3d* a_Vert, + const geVec3d* a_Color, + const geVec3d* a_Normal, + int a_LightsCount, Light_DirectLight** a_LightsFound ); +#endif + +//==================================================================================== +// LightGBSPFile +//==================================================================================== +geBoolean LightGBSPFile(char *FileName, LightParms *Parms) +{ + geVFile *f; + char PalFile[MAX_PATH]; + char RecFile[MAX_PATH]; + +#if DEBUG_RWM_GOURAUD + // TODO: remove? + GHook.Printf("FileName %s\n", FileName ) ; + DebugWriteVertexSetFileName( FileName ) ; +#endif + + f = NULL; + + LVerbose = GE_TRUE; + + if (Parms->ExtraSamples) + NumSamples = 5; + else + NumSamples = 1; + + EntityScale = Parms->LightScale; + DoRadiosity = Parms->Radiosity; + NumBounce = Parms->NumBounce; + PatchSize = Parms->PatchSize; + FastPatch = Parms->FastPatch; + ReflectiveScale = Parms->ReflectiveScale; + + MinLight = Parms->MinLight; + + GHook.Printf(" --- Radiosity GBSP File --- \n"); + + if (!LoadGBSPFile(FileName)) + { + GHook.Error("LightGBSPFile: Could not load GBSP file: %s.\n", FileName); + return GE_FALSE; + } + + // Allocate some RGBLight data now + NumGFXRGBVerts = NumGFXVertIndexList; + GFXRGBVerts = GE_RAM_ALLOCATE_ARRAY(geVec3d,NumGFXRGBVerts); + memset(GFXRGBVerts, 0, sizeof(geVec3d)*NumGFXRGBVerts); + + if (!MakeVertNormals()) + { + GHook.Error("LightGBSPFile: MakeVertNormals failed...\n"); + goto ExitWithError; + } + + // Make sure no existing light exist... + if (GFXLightData) + geRam_Free(GFXLightData); + + GFXLightData = NULL; + NumGFXLightData = 0; + + // Get the palette file name + strcpy(PalFile, FileName); + StripExtension(PalFile); + DefaultExtension(PalFile, ".PAL"); + + // Get the receiver file name + strcpy(RecFile, FileName); + StripExtension(RecFile); + DefaultExtension(RecFile, ".REC"); + + if (!ConvertGFXEntDataToEntities()) + goto ExitWithError; + + f = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_DOS, FileName, NULL, GE_VFILE_OPEN_CREATE); + + if (!f) + { + GHook.Error("LightGBSPFile: Could not open GBSP file for writing: %s.\n", FileName); + goto ExitWithError; + } + + GHook.Printf("Num Faces : %5i\n", NumGFXFaces); + + // Build the patches (before direct lights are created) + if (DoRadiosity) + { + if (!BuildPatches()) + goto ExitWithError; + } + + if (!CreateDirectLights()) + { + GHook.Error("LightGBSPFile: Could not create main lights.\n"); + goto ExitWithError; + } + + // Light faces, and apply to patches + if (!LightFaces(Parms->Verbose)) // Light all the faces lightmaps, and apply to patches + goto ExitWithError; + + FreeDirectLights(); + + if (DoRadiosity) + { + // Pre-calc how much light is distributed to each patch from every patch + if (!CalcReceivers(RecFile)) + goto ExitWithError; + + // Bounce patches around to their receivers + if (!BouncePatches()) // Bounce them around + goto ExitWithError; + + FreeReceivers(); // Don't need these anymore + + // Apply the patches back into the light maps + if (!AbsorbPatches()) // Apply the patches to the lightmaps + goto ExitWithError; + + FreePatches(); // Don't need these anymore... + } + + FinalizeRGBVerts(); + + if (!StartWriting(f)) // Open bsp file and save all current bsp data (except lightmaps) + goto ExitWithError; + + if (!SaveLightmaps(f)) // Save them + goto ExitWithError; + + if (!FinishWriting(f)) // Write the END chunk to the file + goto ExitWithError; + + geVFile_Close(f); + CleanupLight(); + + GHook.Printf("Num Light Maps : %5i\n", RGBMaps); + + return GE_TRUE; + + ExitWithError: + { + if (f) + geVFile_Close(f); + + CleanupLight(); + + return GE_FALSE; + } +} + +//==================================================================================== +// CleanuoLight +//==================================================================================== +void CleanupLight(void) +{ + // Don't need these anymore + FreeDirectLights(); + FreePatches(); + FreeLightmaps(); + FreeReceivers(); + + if (VertNormals) + { + geRam_Free(VertNormals); + VertNormals = NULL; + } + + FreeGBSPFile(); // Free rest of GBSP GFX data +} + + +//==================================================================================== +// FinalizeRGBVerts +//==================================================================================== +void FinalizeRGBVert( geVec3d* a_Color ) +{ + // add ambient light (min light) + geVec3d_Add(a_Color, &MinLight, a_Color); + // force (scale) into range 0..255 + ColorClamp(a_Color, MaxLight, a_Color); +} + +//==================================================================================== +// FinalizeRGBVerts +//==================================================================================== +void FinalizeRGBVerts(void) +{ + int32 i; + + for (i=0; i< NumGFXRGBVerts; i++) + { + FinalizeRGBVert( &GFXRGBVerts[i] ) ; + } +} + + +//==================================================================================== +// MakeVertNormals +//==================================================================================== +geBoolean MakeVertNormals(void) +{ + GFX_Face *pGFXFace; + int32 i; + + VertNormals = GE_RAM_ALLOCATE_ARRAY(geVec3d, NumGFXVerts); + + if (!VertNormals) + { + GHook.Error("MakeVertNormals: Out of memory for normals.\n"); + return GE_FALSE; + } + + memset(VertNormals, 0, sizeof(geVec3d)*NumGFXVerts); + + pGFXFace = GFXFaces; + + for (i=0; i< NumGFXFaces; i++, pGFXFace++) + { + int32 v; + geVec3d Normal; + + Normal = GFXPlanes[pGFXFace->PlaneNum].Normal; + + if (pGFXFace->PlaneSide) + geVec3d_Inverse(&Normal); + + for (v=0; v< pGFXFace->NumVerts; v++) + { + int32 vn, Index; + + vn = pGFXFace->FirstVert + v; + + Index = GFXVertIndexList[vn]; + + geVec3d_Add(&VertNormals[Index], &Normal, &VertNormals[Index]); + } + } + + for (i=0; i< NumGFXVerts; i++) + { + geVec3d_Normalize(&VertNormals[i]); + } + + return GE_TRUE; +} + +//==================================================================================== +// TransferLightToPatches +//==================================================================================== +void TransferLightToPatches(int32 Face) +{ + GFX_Face *pGFXFace; + RAD_Patch *Patch; + + pGFXFace = &GFXFaces[Face]; + + for (Patch = FacePatches[Face] ;Patch ; Patch=Patch->Next) + { + geVec3d *pRGB, *pVert; + int32 i; + + pRGB = &GFXRGBVerts[pGFXFace->FirstVert]; + + Patch->NumSamples = 0; + //geVec3d_Clear(&Patch->RadStart); + + for (i=0; i< pGFXFace->NumVerts; i++) + { + int32 k; + + pVert = &GFXVerts[GFXVertIndexList[i+pGFXFace->FirstVert]]; + + for (k=0 ; k<3 ; k++) + { + if (VectorToSUB(Patch->Mins, k) > VectorToSUB(pVert[0], k) + 16) + break; + + if (VectorToSUB(Patch->Maxs, k) < VectorToSUB(pVert[0], k) - 16) + break; + } + + if (k == 3) + { + // Add the Color to the patch + Patch->NumSamples++; + geVec3d_Add(&Patch->RadStart, pRGB, &Patch->RadStart); + } + + pRGB++; + } + + if (Patch->NumSamples) + geVec3d_Scale(&Patch->RadStart, 1.0f/(float)Patch->NumSamples, &Patch->RadStart); + } + +} + +//==================================================================================== +// ApplyLightmapToPatches +//==================================================================================== +void ApplyLightmapToPatches(int32 Face) +{ + int32 i, k; + geVec3d *pVert, *pRGB;//, RGB; + RAD_Patch *Patch; + + pRGB = Lightmaps[Face].RGBLData[0]; // Only contribute light type 0 to patches + + if (!pRGB) + return; + + // Check each patch and see if the points lands in it's BBox + for (Patch = FacePatches[Face] ;Patch ; Patch=Patch->Next) + { + pVert = FaceInfo[Face].Points; + pRGB = Lightmaps[Face].RGBLData[0]; // Only contribute light type 0 to patches + + Patch->NumSamples = 0; + //geVec3d_Clear(&Patch->RadStart); + + for (i=0; i< FaceInfo[Face].NumPoints; i++) + { + //geVec3d_Scale(pRGB, 1.2f, &RGB); + + //if (pRGB->X + pRGB->Y + pRGB->Z < 3) + // continue; // Not enought light to worry about + + for (k=0 ; k<3 ; k++) + { + if (VectorToSUB(Patch->Mins, k) > VectorToSUB(pVert[0], k) + 16) + break; + + if (VectorToSUB(Patch->Maxs, k) < VectorToSUB(pVert[0], k) - 16) + break; + } + + if (k == 3) + { + // Add the Color to the patch + Patch->NumSamples++; + geVec3d_Add(&Patch->RadStart, pRGB, &Patch->RadStart); + } + + pRGB++; + pVert++; + } + + if (Patch->NumSamples) + geVec3d_Scale(&Patch->RadStart, 1.0f/(float)Patch->NumSamples, &Patch->RadStart); + + //if (Patch->RadStart.X < 16 && Patch->RadStart.Y < 16 && Patch->RadStart.Z < 16) + // geVec3d_Clear(&Patch->RadStart); + + } +} + +float UOfs[5] = { 0.0f,-0.5f, 0.5f, 0.5f,-0.5f}; +float VOfs[5] = { 0.0f,-0.5f,-0.5f, 0.5f, 0.5f}; + +//==================================================================================== +// LightFaces +//==================================================================================== +geBoolean LightFaces(int a_GouraudShading) +{ + int32 i, s; + geBoolean Hit; + int32 Perc; + +#if DEBUG_RWM_GOURAUD + if( a_GouraudShading ) + { + GHook.Printf("Using RWM Gouraud coloring %d RGB faces\n", NumGFXRGBVerts ); + } + else + { + GHook.Printf("Skipping RWM Gouraud coloring %d RGB faces (Full Vis only)\n", NumGFXRGBVerts ); + } +#endif + + Lightmaps = GE_RAM_ALLOCATE_ARRAY(LInfo,NumGFXFaces); + + if (!Lightmaps) + { + GHook.Error("LightFaces: Out of memory for Lightmaps.\n"); + return GE_FALSE; + } + + FaceInfo = GE_RAM_ALLOCATE_ARRAY(FInfo,NumGFXFaces); + + if (!FaceInfo) + { + GHook.Error("LightFaces: Out of memory for FaceInfo.\n"); + return GE_FALSE; + } + + memset(Lightmaps, 0, sizeof(LInfo) * NumGFXFaces); + memset(FaceInfo, 0, sizeof(FInfo) * NumGFXFaces); + + NumLMaps = 0; + + Perc = NumGFXFaces / 20; + + for (i=0; i< NumGFXFaces; i++) + { + Hit = GE_FALSE; + + if (CancelRequest) + { + GHook.Printf("Cancel requested...\n"); + return GE_FALSE; + } + + if (Perc) + { + if (!(i%Perc) && (i/Perc) <= 20) + GHook.Printf(".%i", (i/Perc)); + } + + GetFacePlane(i, &FaceInfo[i].Plane); + FaceInfo[i].Face = i; + +#if RWM_GOURAUD + if( a_GouraudShading ) + { + // always RGB (also for LM faces) + if (!GouraudShadeFace(i)) + { + GHook.Error("LightFaces: GouraudShadeFace failed...\n"); + return GE_FALSE; + } + } + + if (DoRadiosity) + TransferLightToPatches(i); +#else + // only RGB coloring for Gouraud shaded faces + if (GFXTexInfo[GFXFaces[i].TexInfo].Flags & TEXINFO_GOURAUD) + { + if (!GouraudShadeFace(i)) + { + GHook.Error("LightFaces: GouraudShadeFace failed...\n"); + return GE_FALSE; + } + + if (DoRadiosity) + TransferLightToPatches(i); + + continue; // NOTE: (!) + } +#endif + + /* + if (GFXTexInfo[GFXFaces[i].TexInfo].Flags & TEXINFO_FLAT) + { + FlatShadeFace(i); + continue; + } + */ + + if (GFXTexInfo[GFXFaces[i].TexInfo].Flags & TEXINFO_NO_LIGHTMAP) + continue; // Faces with no lightmap don't need to light them + + + if (!CalcFaceInfo(&FaceInfo[i], &Lightmaps[i])) + { + return GE_FALSE; + } + + int32 Size = (Lightmaps[i].LSize[0]+1)*(Lightmaps[i].LSize[1]+1); + FaceInfo[i].Points = GE_RAM_ALLOCATE_ARRAY(geVec3d, Size); + + if (!FaceInfo[i].Points) + { + GHook.Error("LightFaces: Out of memory for face points.\n"); + return GE_FALSE; + } + + for (s=0; s< NumSamples; s++) + { + //Hook.Printf("Sample : %3i of %3i\n", s+1, NumSamples); + CalcFacePoints(&FaceInfo[i], &Lightmaps[i], UOfs[s], VOfs[s]); + + if (!ApplyLightsToFace(&FaceInfo[i], &Lightmaps[i], 1 / (float)NumSamples)) + return GE_FALSE; + } + + if (DoRadiosity) + { + // Update patches for this face + ApplyLightmapToPatches(i); + } + } + + GHook.Printf("\n"); + + return GE_TRUE; +} + +// LWM: start +float SunCalcLightValue( Light_DirectLight* DLight, float Dist, float Angle, float Intensity, bool a_SkipRGBOnly ) +{ + float result = 0.0f ; + + if( a_SkipRGBOnly && DLight->SunRGBOnly ) + { + return 0.0f ; + } + + switch( DLight->SunFallOffType ) + { + default : + case SUN_FALLOFF_NONE : + result = Intensity * Angle ; + break ; + case SUN_FALLOFF_HARD_RADIUS : + if( Dist > DLight->SunFallOffRadiusInTexels ) + { + result = 0.0f ; + } + else + { + result = Intensity * Angle ; + } + break ; + case SUN_FALLOFF_GRADUALLY1: + case SUN_FALLOFF_GRADUALLY2: + if( Dist > DLight->SunFallOffRadiusInTexels ) + { + // outside any radius + result = 0.0f ; + } + if( Dist < DLight->SunFallOff100PercentRadius ) + { + // inside the 100% radius + result = Intensity * Angle ; + } + else + { + // somewhere between + float r, dr, alpha ; + dr = Dist - DLight->SunFallOff100PercentRadius; + r = DLight->SunFallOffRadiusInTexels - DLight->SunFallOff100PercentRadius ; + alpha = DLight->SunFallOffAlpha ; + + if( DLight->SunFallOffType == SUN_FALLOFF_GRADUALLY1 ) + { + //result = (( DLight->SunFallOffRadiusInTexels - Dist ) / DLight->SunFallOffRadiusInTexels ) * + result = 1.0f - (float) pow( dr / r, alpha ) ; + } + else + { + result = (float) pow( ( r - dr ) / r, alpha ) ; + } + result *= Intensity * Angle ; + } + break ; + } + return result ; +} +// LWM: end + +#if DEBUG_RWM_GOURAUD +static char MODULE_VertexFileName[ 512 ] = "test.v" ; +static void DebugWriteVertexSetFileName( const char* a_FileName ) +{ + char* p; + strcpy( MODULE_VertexFileName, a_FileName ) ; + p = strrchr( MODULE_VertexFileName, '.' ) ; + if( p ) + { + strcpy( p, ".V" ) ; + } +} +static void DebugWriteVertex( const geVec3d* a_Vert, const geVec3d* a_Normal, + const geVec3d* a_Color, int a_LightsCount, Light_DirectLight** a_LightsFound ) +{ + static bool firstTime = true ; + const char* name = MODULE_VertexFileName ; + FILE* fp ; + + if (firstTime) { + firstTime = false ; + fp = fopen( name, "w" ) ; + // write verion number + fprintf( fp, "%f ", 1.0f ) ; + } + else { + fp = fopen( name, "a" ) ; + } + + if ( fp ) { + geVec3d color ; + + fprintf( fp, "%f %f %f ", a_Vert->X, a_Vert->Y, a_Vert->Z ) ; + + // give the color the same treatment as FinalizeRGBVerts() would + color = *a_Color ; + FinalizeRGBVert( &color ) ; + fprintf( fp, "%f %f %f ", color.X, color.Y, color.Z ) ; + + fprintf( fp, "%f %f %f ", a_Normal->X, a_Normal->Y, a_Normal->Z ) ; + // write light count + fprintf( fp, "%d ", a_LightsCount ) ; + for( int i = 0 ; i < a_LightsCount ; i ++ ) + { + // write light position + fprintf( fp, "%f %f %f ", + a_LightsFound[ i ]->Origin.X, + a_LightsFound[ i ]->Origin.Y, + a_LightsFound[ i ]->Origin.Z ) ; + } + fprintf( fp, "\n" ) ; + fclose( fp ) ; + fp = NULL ; + } +} +#endif + + +//==================================================================================== +// GouraudShadeFace +//==================================================================================== +geBoolean GouraudShadeFace(int32 FaceNum) +{ + int32 NumVerts; + Light_DirectLight *DLight; + GFX_Face *pGFXFace; + int32 v; + GFX_TexInfo *pGFXTexInfo; + + + if (!GFXRGBVerts || !NumGFXRGBVerts) + { +#if DEBUG_RWM_GOURAUD + GHook.Printf("DON'T GouraudShadeFace()\n") ; +#endif + return GE_FALSE; + } + + pGFXFace = &GFXFaces[FaceNum]; + + pGFXTexInfo = &GFXTexInfo[pGFXFace->TexInfo]; + + NumVerts = pGFXFace->NumVerts; + + + for (v=0; v< pGFXFace->NumVerts; v++) + { + int32 vn, Index, i; + geVec3d *pVert, Normal ; + float Dist, Angle, Val, Intensity; +#if DEBUG_RWM_GOURAUD + int lightsCount ; + #define MAX_LIGHTS 250 + Light_DirectLight* lightsFound[ MAX_LIGHTS ] ; + + lightsCount = 0 ; +#endif + + vn = pGFXFace->FirstVert+v; + + Index = GFXVertIndexList[vn]; + + pVert = &GFXVerts[Index]; + +#if RWM_GOURAUD + + Normal = FaceInfo[FaceNum].Plane.Normal; + + #if DEBUG_RWM_GOURAUD + /* + if (pGFXTexInfo->Flags & TEXINFO_FLAT) + { + GHook.Printf("Found FLAT shaded face\n" ) ; + } + */ + #endif + +#else + if (pGFXTexInfo->Flags & TEXINFO_FLAT) + Normal = FaceInfo[FaceNum].Plane.Normal; + else + Normal = VertNormals[Index]; +#endif + + if( GFXTexInfo[GFXFaces[FaceNum].TexInfo].Flags & TEXINFO_FULLBRIGHT ) + { + GFXRGBVerts[vn].X = 255 ; + GFXRGBVerts[vn].Y = 255 ; + GFXRGBVerts[vn].Z = 255 ; + #if DEBUG_RWM_GOURAUD + DebugWriteVertex( pVert, &Normal, &GFXRGBVerts[vn], 0, NULL ) ; + #endif + continue ; // NOTE: (!) + } + + + for (i=0; i< NumDirectLights; i++) + { + geVec3d Vect; + + DLight = DirectLights[i]; + + Intensity = DLight->Intensity; + + // Find the angle between the light, and the face normal + geVec3d_Subtract(&DLight->Origin, pVert, &Vect); + + Dist = geVec3d_Normalize (&Vect); + + Angle = geVec3d_DotProduct(&Vect, &Normal); + + Val = 0 ; + + // Wismerhill + if (DLight->Type != DLight_SunLight && Angle <= 0.001f) + goto Skip; + + switch(DLight->Type) + { + // Wismerhill + case DLight_SunLight: + { + // Find the angle between the light normal, and the face normal + Angle = -geVec3d_DotProduct(&DLight->Normal, &Normal); + Val = Intensity * Angle; + break; + } + + // LWM: start + case DLight_Sun: + { +#if 0 // #if RWM_GOURAUD + float l_r = 1.25f * DLight->SunFallOffRadiusInTexels ; + float l_v ; + if ( Dist < l_r ) + l_v = 1.25f * ( l_r - Dist ) / l_r ; + else + l_v = 0.0f ; + Val = l_v * Intensity * Angle; //(Angle*0.5f+0.5f); +#else + Val = 1.25f * SunCalcLightValue( DLight, Dist, Angle, Intensity, false ) ; +#endif + break ; + } + // LWM: end + case DLight_Point: + { + Val = (Intensity - Dist) * Angle;//(Angle*0.5f+0.5f); + break; + } + case DLight_Spot: + { + float Angle2 = -geVec3d_DotProduct(&Vect, &DLight->Normal); + + if (Angle2 < DLight->Angle) + goto Skip; + + Val = (Intensity - Dist) * Angle; + break; + } + case DLight_Surface: + { + float Angle2 = -geVec3d_DotProduct (&Vect, &DLight->Normal); + if (Angle2 <= 0.001f) + goto Skip; // Behind light surface + + Val = (Intensity / (Dist*Dist) ) * Angle * Angle2; + break; + } + default: + { + GHook.Error("ApplyLightsToFace: Invalid light.\n"); + return GE_FALSE; + } + } + + if (Val <= 0.0f) + goto Skip; + // Wismerhill + if(DLight->Type == DLight_SunLight) + { + geVec3d_AddScaled(pVert, &DLight->Normal, -20000.0f, &Vect); //SMALL CORRECTION + if (RayCollisionButSky(pVert, &Vect, NULL)) + goto Skip; // Ray is in shadow + } + else + { + Vect = DLight->Origin; + if (RayCollision(pVert, &Vect, NULL)) + goto Skip; // Ray is in shadow + } + +#if RWM_GOURAUD + // allow some obstructions + { + geVec3d n ; // normalized normal + geVec3d test ; // point to test for visibility of the light + geVec3d x, y, crossWith ; // to build x,y axis in plane + int dist ; // counter + #define NR_DISTANCES 4 + #define USE_NR_DISTANCES 3 + float texels[ NR_DISTANCES ] = { 2.0f, 5.0f, 20.0f, 40.0f } ; // distance from plane + float intensities[ NR_DISTANCES ] = { 1.0f, 0.9f, 0.7f, 0.5f } ; // intensityfactor + float result = 0 ; // resulting Val + int found = 0 ; + + n = Normal ; + geVec3d_Normalize( &n ) ; + + // see if Y-axis is OK for crossproduct + crossWith.X = 0.0f ; + crossWith.Y = 1.0f ; + crossWith.Z = 0.0f ; + if( geVec3d_Compare( &crossWith, &n, 0.1f ) ) + { + // try Z-axis for crossproduct + crossWith.X = 0.0f ; + crossWith.Y = 0.0f ; + crossWith.Z = 1.0f ; + } + + // build X and Y axis inside plane + geVec3d_CrossProduct( &n, &crossWith, &x ) ; + geVec3d_Normalize( &x ) ; + geVec3d_CrossProduct( &n, &x, &y ) ; + geVec3d_Normalize( &y ) ; + + for( dist = 0 ; dist < USE_NR_DISTANCES ; dist ++ ) + { + int quadrant ; + float XY_SCALE = texels[ dist ] / 2.0f ; + + for( quadrant = 0 ; quadrant < 5 ; quadrant ++ ) + { + // create a test point somewhat removed from the face + // and somewhat away from the direction the normal points in + // to avoid getting inside planes nearby + int sunQuadrant ; + #define SUN_SIZE 32.0f + + geVec3d_AddScaled( pVert, &n, texels[ dist ], &test ) ; + switch( quadrant ) + { + case 0 : + geVec3d_AddScaled( &test, &x, +1.0f * XY_SCALE, &test ) ; + geVec3d_AddScaled( &test, &y, +1.0f * XY_SCALE, &test ) ; + break ; + case 1 : + geVec3d_AddScaled( &test, &x, -1.0f * XY_SCALE, &test ) ; + geVec3d_AddScaled( &test, &y, +1.0f * XY_SCALE, &test ) ; + break ; + case 2 : + geVec3d_AddScaled( &test, &x, -1.0f * XY_SCALE, &test ) ; + geVec3d_AddScaled( &test, &y, -1.0f * XY_SCALE, &test ) ; + break ; + case 3 : + geVec3d_AddScaled( &test, &x, +1.0f * XY_SCALE, &test ) ; + geVec3d_AddScaled( &test, &y, -1.0f * XY_SCALE, &test ) ; + break ; + case 4 : + // straight up along normal + break ; + } +#if 1 + // just use the origin of the light + for( sunQuadrant = 0 ; sunQuadrant < 1 ; sunQuadrant ++ ) +#else + // check some points around the light too + for( sunQuadrant = 0 ; sunQuadrant < 9 ; sunQuadrant ++ ) +#endif + { + // see if this testpoint can see the light + geVec3d origin ; + + origin = DLight->Origin ; + switch( sunQuadrant ) + { + case 0 : + // just take origin + break ; + case 1 : + case 2 : + origin.X -= SUN_SIZE ; + origin.Z -= SUN_SIZE ; + break ; + case 3 : + case 4 : + origin.X += SUN_SIZE ; + origin.Z -= SUN_SIZE ; + break ; + case 5 : + case 6 : + origin.X += SUN_SIZE ; + origin.Z += SUN_SIZE ; + break ; + case 7 : + case 8 : + origin.X -= SUN_SIZE ; + origin.Z += SUN_SIZE ; + break ; + } + if( sunQuadrant > 0 ) + { + if( sunQuadrant % 2 ) + { + origin.Y -= SUN_SIZE ; + } + else + { + origin.Y += SUN_SIZE ; + } + } + if ( (DLight->SunRGBAlwaysVisible) + || (! RayCollision(&test, &origin, NULL)) + ) { + // yes + result = Val * intensities[ dist ] ; + found = 1 ; + break ; + } + } + if( found ) + { + break ; + } + } + if( found ) + { + break ; + } + } + if( ! found ) + { + goto Skip; + } + Val = result ; + } +#else + // This is the slowest test, so make it last + if (RayCollision(pVert, &DLight->Origin, NULL)) + goto Skip; // Ray is in shadow +#endif + + geVec3d_AddScaled(&GFXRGBVerts[vn], &DLight->Color, Val, &GFXRGBVerts[vn]); + + #if DEBUG_RWM_GOURAUD + // remember light found + if( lightsCount < MAX_LIGHTS ) + { + lightsFound[ lightsCount ++ ] = DLight ; + } + #endif + Skip:; + + } + #if DEBUG_RWM_GOURAUD + DebugWriteVertex( pVert, &Normal, &GFXRGBVerts[vn], lightsCount, lightsFound ) ; + #endif + } + + return GE_TRUE; +} + +#pragma pack(1) + +typedef struct +{ + float r, g, b; +} RGB; + +#pragma pack() + +//==================================================================================== +// ApplyLightsToFace +//==================================================================================== +geBoolean ApplyLightsToFace(FInfo *FaceInfo, LInfo *LightInfo, float Scale) +{ + int32 c, v; + geVec3d *Verts; + geFloat Dist; + int32 LType; + geVec3d *pRGBLData, Normal, Vect; + float Val, Angle; + uint8 *VisData; + int32 Leaf, Cluster; + float Intensity; + Light_DirectLight *DLight; + + Normal = FaceInfo->Plane.Normal; + + Verts = FaceInfo->Points; + + for (v=0; v< FaceInfo->NumPoints; v++) + { + Leaf = FindGFXLeaf(0, &Verts[v]); + + if (Leaf < 0 || Leaf >= NumGFXLeafs) + { + GHook.Error("ApplyLightsToFace: Invalid leaf num.\n"); + return GE_FALSE; + } + + Cluster = GFXLeafs[Leaf].Cluster; + + if (Cluster < 0) + continue; + + if (Cluster >= NumGFXClusters) + { + GHook.Error("*WARNING* ApplyLightsToFace: Invalid cluster num.\n"); + //return GE_FALSE; + continue; + } + + VisData = &GFXVisData[GFXClusters[Cluster].VisOfs]; + + for (c=0; c< NumGFXClusters; c++) + { + if (!(VisData[c>>3] & (1<<(c&7))) ) + continue; + + for (DLight = DirectClusterLights[c]; DLight; DLight = DLight->Next) + { + Intensity = DLight->Intensity; + + #if 0 + geVec3d_Subtract(&FaceInfo->Center, &DLight->Origin, &Vect); + Dist = geVec3d_Length(&Vect); + if (Dist > Intensity+FaceInfo->Radius) + continue; // Can't possibly touch... + #endif + + // Find the angle between the light, and the face normal + geVec3d_Subtract(&DLight->Origin, &Verts[v], &Vect); + Dist = geVec3d_Normalize(&Vect); + + Angle = geVec3d_DotProduct(&Vect, &Normal); + // Wismerhill + if (DLight->Type != DLight_SunLight && Angle <= 0.001f) //no skip if it's a sun + + goto Skip; + + switch(DLight->Type) + { + // Wismerhill + case DLight_SunLight: + { + // Find the angle between the light normal, and the face normal + Angle = -geVec3d_DotProduct(&DLight->Normal, &Normal); + Val = Intensity * Angle; + break; + } + // LWM: start + case DLight_Sun: + { + Val = SunCalcLightValue( DLight, Dist, Angle, Intensity, true ) ; + break ; + } + // LWM: end + case DLight_Point: + { + Val = (Intensity - Dist) * Angle; + break; + } + case DLight_Spot: + { + float Angle2 = -geVec3d_DotProduct(&Vect, &DLight->Normal); + + if (Angle2 < DLight->Angle) + goto Skip; + + Val = (Intensity - Dist) * Angle; + break; + } + case DLight_Surface: + { + float Angle2 = -geVec3d_DotProduct (&Vect, &DLight->Normal); + if (Angle2 <= 0.001f) + goto Skip; // Behind light surface + + Val = (Intensity / (Dist*Dist) ) * Angle * Angle2; + break; + } + default: + { + GHook.Error("ApplyLightsToFace: Invalid light.\n"); + return GE_FALSE; + } + } + + if (Val <= 0.0f) + goto Skip; + + // Wismerhill + // Test if the ray is in shadow with a collision test between a lighted point and the light + if(DLight->Type == DLight_SunLight) + { + //simulate a veeeeery far light + geVec3d_AddScaled(&Verts[v], &DLight->Normal, -20000.0f, &Vect); + if (RayCollisionButSky(&Verts[v], &Vect, NULL)) + goto Skip; // Ray is in shadow + } + else + { + Vect = DLight->Origin; + if (RayCollision(&Verts[v], &Vect, NULL)) + goto Skip; // Ray is in shadow + } + + LType = DLight->LType; + + // If the data for this LType has not been allocated, allocate it now... + if (!LightInfo->RGBLData[LType]) + { + if (LightInfo->NumLTypes >= MAX_LTYPES) + { + GHook.Error("Max Light Types on face.\n"); + return GE_FALSE; + } + + LightInfo->RGBLData[LType] = GE_RAM_ALLOCATE_ARRAY(geVec3d,FaceInfo->NumPoints); + memset(LightInfo->RGBLData[LType], 0, FaceInfo->NumPoints*sizeof(geVec3d)); + LightInfo->NumLTypes++; + } + + pRGBLData = LightInfo->RGBLData[LType]; + geVec3d_AddScaled(&pRGBLData[v], &DLight->Color, Val*Scale, &pRGBLData[v]); + + Skip:; + } + } + } + + return GE_TRUE; +} + +//==================================================================================== +// SaveLightmaps +//==================================================================================== +geBoolean SaveLightmaps(geVFile *f) +{ + LInfo *L; + int32 i, j, k,l, Size; + float Max, Max2; + GBSP_Chunk Chunk; + uint8 LData[MAX_LMAP_SIZE*MAX_LMAP_SIZE*3*4], *pLData; + int32 Pos1, Pos2; + int32 NumLTypes; + FInfo *pFaceInfo; + + geVFile_Tell(f, &Pos1); + + // Write out fake chunk (so we can write the real one here later) + Chunk.Type = GBSP_CHUNK_LIGHTDATA; + Chunk.Size = sizeof(uint8); + Chunk.Elements = 0; + + if (!WriteChunk(&Chunk, NULL, f)) + { + GHook.Error("SaveLightmaps: Could not write Chunk Info.\n"); + return GE_FALSE; + } + + // Reset the light offset + LightOffset = 0; + + // Go through all the faces + for (i=0; i< NumGFXFaces; i++) + { + L = &Lightmaps[i]; + pFaceInfo = &FaceInfo[i]; + + // Set face defaults + GFXFaces[i].LightOfs = -1; + GFXFaces[i].LWidth = L->LSize[0]+1; + GFXFaces[i].LHeight = L->LSize[1]+1; + GFXFaces[i].LTypes[0] = 255; + GFXFaces[i].LTypes[1] = 255; + GFXFaces[i].LTypes[2] = 255; + GFXFaces[i].LTypes[3] = 255; + + // Skip special faces with no lightmaps + if (GFXTexInfo[GFXFaces[i].TexInfo].Flags & TEXINFO_NO_LIGHTMAP) + continue; + + // Get the size of map + Size = pFaceInfo->NumPoints; + + // Create style 0, if min light is set, and style 0 does not exist + if (!L->RGBLData[0] && (MinLight.X > 1 || MinLight.Y > 1 || MinLight.Z > 1)) + { + L->RGBLData[0] = GE_RAM_ALLOCATE_ARRAY(geVec3d,Size); + if (!L->RGBLData[0]) + { + GHook.Error("SaveLightmaps: Out of memory for lightmap.\n"); + return GE_FALSE; + } + L->NumLTypes++; + memset(L->RGBLData[0], 0, Size*sizeof(geVec3d)); + } + + // At this point, if no styles hit the face, skip it... + if (!L->NumLTypes) + continue; + + // Mark the start of the lightoffset + GFXFaces[i].LightOfs = LightOffset; + + // At this point, all lightmaps are currently RGB + uint8 RGB2 = 1; + + if (RGB2) + RGBMaps++; + else + REGMaps++; + + if (geVFile_Write(f, &RGB2, sizeof(uint8)) != GE_TRUE) + { + GHook.Error("SaveLightMaps: There was an error saving the Lightmap type.\n"); + return GE_FALSE; + } + + LightOffset++; // Skip the rgb light byte + + NumLTypes = 0; // Reset number of LTypes for this face + for (k=0; k< MAX_LTYPE_INDEX; k++) + { + if (!L->RGBLData[k]) + continue; + + if (NumLTypes >= MAX_LTYPES) + { + GHook.Error("SaveLightmaps: Max LightTypes on face.\n"); + return GE_FALSE; + } + + GFXFaces[i].LTypes[NumLTypes] = (uint8)k; + NumLTypes++; + + pLData = LData; + geVec3d *pRGB = L->RGBLData[k]; + + for (j=0; j< Size; j++, pRGB++) + { + geVec3d WorkRGB; + + geVec3d_Scale(pRGB, LightScale, &WorkRGB); + + if (k == 0) + geVec3d_Add(&WorkRGB, &MinLight, &WorkRGB); + + Max = 0.0f; + + for (l=0; l<3; l++) + { + geFloat Val; + + Val = geVec3d_GetElement(&WorkRGB, l); + + if (Val < 1.0f) + { + Val = 1.0f; + VectorToSUB(WorkRGB, l) = Val; + } + + if (Val > Max) + Max = Val; + } + + assert(Max > 0.0f); + + Max2 = min(Max, MaxLight); + + for (l=0; l<3; l++) + { + *pLData= (uint8)(geVec3d_GetElement(&WorkRGB, l)*Max2/Max); + pLData++; + LightOffset++; + } + } + + if (geVFile_Write(f, LData, 3 * Size) != GE_TRUE) + { + GHook.Error("There was an error saving the Lightmap data.\n"); + return GE_FALSE; + } + + geRam_Free(L->RGBLData[k]); // Free them as soon as we don't need them + L->RGBLData[k] = NULL; + } + + if (L->NumLTypes != NumLTypes) + { + GHook.Error("SaveLightMaps: Num LightTypes was incorrectly calculated.\n"); + return GE_FALSE; + } + } + + GHook.Printf("Light Data Size : %6i\n", LightOffset); + + geVFile_Tell(f, &Pos2); + + geVFile_Seek(f, Pos1, GE_VFILE_SEEKSET); + + Chunk.Type = GBSP_CHUNK_LIGHTDATA; + Chunk.Size = sizeof(uint8); + Chunk.Elements = LightOffset; + + if (!WriteChunk(&Chunk, NULL, f)) + { + GHook.Error("SaveLightmaps: Could not write Chunk Info.\n"); + return GE_FALSE; + } + + geVFile_Seek(f, Pos2, GE_VFILE_SEEKSET); + + return GE_TRUE; +} + +//==================================================================================== +// GetFacePlane +//==================================================================================== +void GetFacePlane(int32 Face, GFX_Plane *Plane) +{ + Plane->Normal = GFXPlanes[GFXFaces[Face].PlaneNum].Normal; + Plane->Dist = GFXPlanes[GFXFaces[Face].PlaneNum].Dist; + Plane->Type = GFXPlanes[GFXFaces[Face].PlaneNum].Type; + + if (GFXFaces[Face].PlaneSide) + { + geVec3d_Subtract(&VecOrigin, &Plane->Normal, &Plane->Normal); + Plane->Dist = -Plane->Dist; + } +} + +//==================================================================================== +// CalcFaceInfo +//==================================================================================== +geBoolean CalcFaceInfo(FInfo *FaceInfo, LInfo *LightInfo) +{ + int32 i, k; + GFX_TexInfo *TexInfo; + geVec3d *Vert; + float Val, Mins[2], Maxs[2]; + int32 Face = FaceInfo->Face; + geVec3d TexNormal; + float DistScale; + geFloat Dist, Len; + int32 *pIndex; + + for (i=0; i<2; i++) + { + Mins[i] = MIN_MAX_BOUNDS; + Maxs[i] =-MIN_MAX_BOUNDS; + } + + TexInfo = &GFXTexInfo[GFXFaces[Face].TexInfo]; + + geVec3d_Clear(&FaceInfo->Center); + + pIndex = &GFXVertIndexList[GFXFaces[Face].FirstVert]; + + for (i=0; i< GFXFaces[Face].NumVerts; i++, pIndex++) + { + Vert = &GFXVerts[*pIndex]; + for (k=0; k< 2; k++) + { + Val = geVec3d_DotProduct(Vert, &TexInfo->Vecs[k]); + + if (Val > Maxs[k]) + Maxs[k] = Val; + if (Val < Mins[k]) + Mins[k] = Val; + } + + // Find center + geVec3d_Add(&FaceInfo->Center, Vert, &FaceInfo->Center); + } + + // Finish center + geVec3d_Scale(&FaceInfo->Center, 1.0f/(float)GFXFaces[Face].NumVerts, &FaceInfo->Center); + +#if 0 + // Find radius + FaceInfo->Radius = 0.0f; + pIndex = &GFXVertIndexList[GFXFaces[Face].FirstVert]; + for (i=0; i< GFXFaces[Face].NumVerts; i++, pIndex++) + { + geVec3d Vect; + + Vert = &GFXVerts[*pIndex]; + + geVec3d_Subtract(&FaceInfo->Center, Vert, &Vect); + + Dist = geVec3d_Length(&Vect); + + if (Dist > FaceInfo->Radius) + FaceInfo->Radius = Dist; + } +#endif + + // Get the Texture U/V mins/max, and Grid aligned lmap mins/max/size + for (i=0; i<2; i++) + { + LightInfo->Mins[i] = Mins[i]; + LightInfo->Maxs[i] = Maxs[i]; + + Mins[i] = (float)floor(Mins[i]/LGRID_SIZE); + Maxs[i] = (float)ceil(Maxs[i]/LGRID_SIZE); + + LightInfo->LMins[i] = (int32)Mins[i]; + LightInfo->LMaxs[i] = (int32)Maxs[i]; + LightInfo->LSize[i] = (int32)(Maxs[i] - Mins[i]); + + if (LightInfo->LSize[i]+1 > MAX_LMAP_SIZE) + //if (LightInfo->LSize[i] > 17) + { + GHook.Error("CalcFaceInfo: Face was not subdivided correctly.\n"); + return GE_FALSE; + } + } + + // Get the texture normal from the texture vecs + geVec3d_CrossProduct(&TexInfo->Vecs[0], &TexInfo->Vecs[1], &TexNormal); + // Normalize it + geVec3d_Normalize(&TexNormal); + + // Flip it towards plane normal + DistScale = geVec3d_DotProduct (&TexNormal, &FaceInfo->Plane.Normal); + + if (!DistScale) + { + GHook.Error ("CalcFaceInfo: Invalid Texture vectors for face.\n"); + return GE_FALSE; + } + + if (DistScale < 0) + { + DistScale = -DistScale; + geVec3d_Inverse(&TexNormal); + } + + DistScale = 1/DistScale; + + // Get the tex to world vectors + for (i=0 ; i<2 ; i++) + { + Len = geVec3d_Length(&TexInfo->Vecs[i]); + Dist = geVec3d_DotProduct(&TexInfo->Vecs[i], &FaceInfo->Plane.Normal); + Dist *= DistScale; + geVec3d_AddScaled(&TexInfo->Vecs[i], &TexNormal, -Dist, &FaceInfo->T2WVecs[i]); + geVec3d_Scale(&FaceInfo->T2WVecs[i], (1/Len)*(1/Len), &FaceInfo->T2WVecs[i]); + } + + + for (i=0 ; i<3 ; i++) + VectorToSUB(FaceInfo->TexOrg,i) = + - TexInfo->Vecs[0].Z * VectorToSUB(FaceInfo->T2WVecs[0], i) + - TexInfo->Vecs[1].Z * VectorToSUB(FaceInfo->T2WVecs[1], i); + + Dist = geVec3d_DotProduct (&FaceInfo->TexOrg, &FaceInfo->Plane.Normal) - FaceInfo->Plane.Dist - 1; + Dist *= DistScale; + geVec3d_AddScaled(&FaceInfo->TexOrg, &TexNormal, -Dist, &FaceInfo->TexOrg); + + return GE_TRUE; +} + +//==================================================================================== +// CalcFacePoints +//==================================================================================== +void CalcFacePoints(FInfo *FaceInfo, LInfo *LightInfo, float UOfs, float VOfs) +{ + geVec3d *pPoint, FaceMid, I; + float MidU, MidV, StartU, StartV, CurU, CurV; + int32 i, u, v, Width, Height, Leaf; + geVec3d Vect; + uint8 InSolid[MAX_LMAP_SIZE*MAX_LMAP_SIZE], *pInSolid; + + MidU = (LightInfo->Maxs[0] + LightInfo->Mins[0])*0.5f; + MidV = (LightInfo->Maxs[1] + LightInfo->Mins[1])*0.5f; + + for (i=0; i< 3; i++) + VectorToSUB(FaceMid,i) = VectorToSUB(FaceInfo->TexOrg,i) + + VectorToSUB(FaceInfo->T2WVecs[0], i) * MidU + + VectorToSUB(FaceInfo->T2WVecs[1], i) * MidV; + + Width = (LightInfo->LSize[0]) + 1; + Height = (LightInfo->LSize[1]) + 1; + StartU = ((float)LightInfo->LMins[0]+UOfs) * (float)LGRID_SIZE; + StartV = ((float)LightInfo->LMins[1]+VOfs) * (float)LGRID_SIZE; + + FaceInfo->NumPoints = Width*Height; + + pPoint = &FaceInfo->Points[0]; + pInSolid = InSolid; + + for (v=0; v < Height; v++) + { + for (u=0; u < Width; u++, pPoint++, pInSolid++) + { + CurU = StartU + u * LGRID_SIZE; + CurV = StartV + v * LGRID_SIZE; + + for (i=0; i< 3; i++) + VectorToSUB(*pPoint,i) = VectorToSUB(FaceInfo->TexOrg,i) + + VectorToSUB(FaceInfo->T2WVecs[0], i) * CurU + + VectorToSUB(FaceInfo->T2WVecs[1], i) * CurV; + + Leaf = FindGFXLeaf(0, pPoint); + + // Pre-compute if this point is in solid space, so we can re-use it in the code below + if (GFXLeafs[Leaf].Contents & BSP_CONTENTS_SOLID2) + *pInSolid = 1; + else + *pInSolid = 0; + + if (!ExtraLightCorrection) + { + if (*pInSolid) + { + if (RayCollision(&FaceMid, pPoint, &I)) + { + geVec3d_Subtract(&FaceMid, pPoint, &Vect); + geVec3d_Normalize(&Vect); + geVec3d_Add(&I, &Vect, pPoint); + } + } + } + } + } + + if (!ExtraLightCorrection) + return; + + pPoint = FaceInfo->Points; + pInSolid = InSolid; + + for (v=0; v< FaceInfo->NumPoints; v++, pPoint++, pInSolid++) + { + uint8 *pInSolid2; + geVec3d *pPoint2, *pBestPoint; + geFloat BestDist, Dist; + + if (!(*pInSolid)) + continue; // Point is good, leav it alone + + pPoint2 = FaceInfo->Points; + pInSolid2 = InSolid; + pBestPoint = &FaceMid; + BestDist = MIN_MAX_BOUNDS; + + for (u=0; u< FaceInfo->NumPoints; u++, pPoint2++, pInSolid2++) + { + if (pPoint == pPoint2) + continue; // We know this point is bad + + if (*pInSolid2) + continue; // We know this point is bad + + // At this point, we have a good point, now see if it's closer than the current good point + geVec3d_Subtract(pPoint2, pPoint, &Vect); + Dist = geVec3d_Length(&Vect); + if (Dist < BestDist) + { + BestDist = Dist; + pBestPoint = pPoint2; + + if (Dist <= (LGRID_SIZE-0.1f)) + break; // This should be good enough... + } + } + + *pPoint = *pBestPoint; + } +} + +float PlaneDistanceFast(geVec3d *Point, GFX_Plane *Plane) +{ + float Dist,Dist2; + Dist2 = Plane->Dist; + + switch (Plane->Type) + { + + case PLANE_X: + Dist = (Point->X - Dist2); + break; + case PLANE_Y: + Dist = (Point->Y - Dist2); + break; + case PLANE_Z: + Dist = (Point->Z - Dist2); + break; + + default: + Dist = geVec3d_DotProduct(Point, &Plane->Normal) - Dist2; + break; + } + + return Dist; +} + +static geBoolean HitLeaf; + +//==================================================================================== +// RayIntersect +//==================================================================================== +geBoolean RayIntersect(geVec3d *Front, geVec3d *Back, int32 Node) +{ + float Fd, Bd, Dist; + uint8 Side; + geVec3d I; + + if (Node < 0) + { + int32 Leaf = -(Node+1); + + if (GFXLeafs[Leaf].Contents & BSP_CONTENTS_SOLID2) + return GE_TRUE; // Ray collided with solid space + else + return GE_FALSE; // Ray collided with empty space + } + + Fd = PlaneDistanceFast(Front, &GFXPlanes[GFXNodes[Node].PlaneNum]); + Bd = PlaneDistanceFast(Back , &GFXPlanes[GFXNodes[Node].PlaneNum]); + + if (Fd >= -1 && Bd >= -1) + return(RayIntersect(Front, Back, GFXNodes[Node].Children[0])); + if (Fd < 1 && Bd < 1) + return(RayIntersect(Front, Back, GFXNodes[Node].Children[1])); + + Side = Fd < 0; + Dist = Fd / (Fd - Bd); + + I.X = Front->X + Dist * (Back->X - Front->X); + I.Y = Front->Y + Dist * (Back->Y - Front->Y); + I.Z = Front->Z + Dist * (Back->Z - Front->Z); + + // Work our way to the front, from the back side. As soon as there + // is no more collisions, we can assume that we have the front portion of the + // ray that is in empty space. Once we find this, and see that the back half is in + // solid space, then we found the front intersection point... + if (RayIntersect(Front, &I, GFXNodes[Node].Children[Side])) + return GE_TRUE; + else if (RayIntersect(&I, Back, GFXNodes[Node].Children[!Side])) + { + if (!HitLeaf) + { + GlobalPlane = GFXNodes[Node].PlaneNum; + GlobalSide = Side; + GlobalI = I; + GlobalNode = Node; + HitLeaf = GE_TRUE; + } + return GE_TRUE; + } + + return GE_FALSE; +} + +geBoolean RayCollision(geVec3d *Front, geVec3d *Back, geVec3d *I) +{ + HitLeaf = GE_FALSE; + if (RayIntersect(Front, Back, GFXModels[0].RootNode[0])) + { + if (I) + *I = GlobalI; // Set the intersection point + return GE_TRUE; + } + + return GE_FALSE; +} + +// Wismerhill +#define COLLISION_BOX 1.0f +geBoolean RayCollisionButSky(geVec3d *Front, geVec3d *Back, geVec3d *I) +{ + HitLeaf = GE_FALSE; + if (RayIntersect(Front, Back, GFXModels[0].RootNode[0])) + { + if(HitLeaf) + { + GFX_Node *pNode; + GFX_Face *pFace; + int32 i, k, v, *pIndex; + geVec3d VMins, VMaxs; + geVec3d Vert; + pNode = &GFXNodes[GlobalNode]; + pFace = &GFXFaces[pNode->FirstFace]; + //this code retrieves the face that we hit + //by calculating its coords and testing if the impact point is in + for(i=0;iNumFaces;i++,pFace++) + { + //dummy mins/maxs + for (k=0; k<3; k++) + { + VectorToSUB(VMins, k) = 99999.0f; + VectorToSUB(VMaxs, k) =-99999.0f; + } + //points into the list of index for this face + pIndex = &GFXVertIndexList[pFace->FirstVert]; + //loop through vertices of the face + for (v=0; v < pFace->NumVerts; v++, pIndex++) + { + //extract the vertex vector + Vert = GFXVerts[*pIndex]; + //compute mins/maxs + for (k=0; k<3; k++) + { + if (VectorToSUB(Vert, k) < VectorToSUB(VMins, k)) + VectorToSUB(VMins, k) = VectorToSUB(Vert, k); + if (VectorToSUB(Vert, k) > VectorToSUB(VMaxs, k)) + VectorToSUB(VMaxs, k) = VectorToSUB(Vert, k); + } + } + //Mins & Maxs are calculated for this face + //is the Impact on it? + if (GlobalI.X + COLLISION_BOX >= VMins.X && GlobalI.X - COLLISION_BOX <= VMaxs.X) + if (GlobalI.Y + COLLISION_BOX >= VMins.Y && GlobalI.Y - COLLISION_BOX <= VMaxs.Y) + if (GlobalI.Z + COLLISION_BOX >= VMins.Z && GlobalI.Z - COLLISION_BOX <= VMaxs.Z) + { //yes! It's our face + if(GFXTexInfo[pFace->TexInfo].Flags & TEXINFO_SKY) { //is it face marked sky? + return GE_FALSE; //undo the collision: sunlight must pass + } + } + } + } + + if (I) + *I = GlobalI; // Set the intersection point + return GE_TRUE; + } +return GE_FALSE; +} + +//================================================================================ +// StartWriting +//================================================================================ +geBoolean StartWriting(geVFile *f) +{ + // Write out everything but the light data + // Don't include LIGHT_DATA since it was allready saved out... + + GBSP_ChunkData CurrentChunkData[] = { + { GBSP_CHUNK_HEADER , sizeof(GBSP_Header) ,1 , &GBSPHeader}, + { GBSP_CHUNK_MODELS , sizeof(GFX_Model) ,NumGFXModels , GFXModels }, + { GBSP_CHUNK_NODES , sizeof(GFX_Node) ,NumGFXNodes , GFXNodes }, + { GBSP_CHUNK_PORTALS , sizeof(GFX_Portal) ,NumGFXPortals , GFXPortals}, + { GBSP_CHUNK_BNODES , sizeof(GFX_BNode) ,NumGFXBNodes , GFXBNodes }, + { GBSP_CHUNK_LEAFS , sizeof(GFX_Leaf) ,NumGFXLeafs , GFXLeafs }, + { GBSP_CHUNK_AREAS , sizeof(GFX_Area) ,NumGFXAreas , GFXAreas }, + { GBSP_CHUNK_AREA_PORTALS , sizeof(GFX_AreaPortal),NumGFXAreaPortals , GFXAreaPortals }, + { GBSP_CHUNK_CLUSTERS , sizeof(GFX_Cluster) ,NumGFXClusters , GFXClusters}, + { GBSP_CHUNK_PLANES , sizeof(GFX_Plane) ,NumGFXPlanes , GFXPlanes }, + { GBSP_CHUNK_LEAF_FACES , sizeof(int32) ,NumGFXLeafFaces, GFXLeafFaces }, + { GBSP_CHUNK_LEAF_SIDES , sizeof(GFX_LeafSide) ,NumGFXLeafSides, GFXLeafSides }, + { GBSP_CHUNK_VERTS , sizeof(geVec3d) ,NumGFXVerts , GFXVerts }, + { GBSP_CHUNK_VERT_INDEX , sizeof(int32) ,NumGFXVertIndexList , GFXVertIndexList}, + { GBSP_CHUNK_ENTDATA , sizeof(uint8) ,NumGFXEntData , GFXEntData}, + { GBSP_CHUNK_TEXTURES , sizeof(GFX_Texture) ,NumGFXTextures , GFXTextures}, + { GBSP_CHUNK_TEXINFO , sizeof(GFX_TexInfo) ,NumGFXTexInfo , GFXTexInfo}, + { GBSP_CHUNK_TEXDATA , sizeof(uint8) ,NumGFXTexData , GFXTexData}, + { GBSP_CHUNK_VISDATA , sizeof(uint8) ,NumGFXVisData , GFXVisData}, + { GBSP_CHUNK_SKYDATA , sizeof(GFX_SkyData) ,1 , &GFXSkyData}, + { GBSP_CHUNK_PALETTES , sizeof(DRV_Palette) ,NumGFXPalettes , GFXPalettes}, + { GBSP_CHUNK_MOTIONS , sizeof(uint8) ,NumGFXMotionBytes, GFXMotionData}, + }; + + if (!WriteChunks(CurrentChunkData, sizeof(CurrentChunkData) / sizeof(CurrentChunkData[0]), f)) + { + GHook.Error("StartWriting: Could not write ChunkData.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//================================================================================ +// FinishWriting +//================================================================================ +geBoolean FinishWriting(geVFile *f) +{ + GBSP_ChunkData ChunkDataEnd[] = { + { GBSP_CHUNK_RGB_VERTS , sizeof(geVec3d) ,NumGFXRGBVerts , GFXRGBVerts }, + { GBSP_CHUNK_FACES , sizeof(GFX_Face) ,NumGFXFaces , GFXFaces }, + { GBSP_CHUNK_END , 0 , 0 , NULL}, + }; + + if (!WriteChunks(ChunkDataEnd, 3, f)) + { + GHook.Error("FinishWriting: Could not write ChunkData.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//================================================================================ +// FindGFXLeaf +//================================================================================ +int32 FindGFXLeaf(int32 Node, geVec3d *Vert) +{ + float Dist; + + while (Node >= 0) + { + Dist = PlaneDistanceFast(Vert, &GFXPlanes[GFXNodes[Node].PlaneNum]); + if (Dist < 0) + Node = GFXNodes[Node].Children[1]; + else + Node = GFXNodes[Node].Children[0]; + } + + return (-Node-1); +} + +//================================================================================ +// FreeLightmaps +//================================================================================ +void FreeLightmaps(void) +{ + int32 i, k; + + for (i=0; i< NumGFXFaces; i++) + { + if (FaceInfo) + { + if (FaceInfo[i].Points) + geRam_Free(FaceInfo[i].Points); + FaceInfo[i].Points = NULL; + } + + if (Lightmaps) + { + for (k=0; k< MAX_LTYPE_INDEX; k++) + { + if (Lightmaps[i].RGBLData[k]) + geRam_Free(Lightmaps[i].RGBLData[k]); + Lightmaps[i].RGBLData[k] = NULL; + } + } + } + + if (FaceInfo) + geRam_Free(FaceInfo); + if (Lightmaps) + geRam_Free(Lightmaps); + + FaceInfo = NULL; + Lightmaps = NULL; +} + +//======================================================================================== +// AllocDirectLight +//======================================================================================== +Light_DirectLight *AllocDirectLight(void) +{ + Light_DirectLight *DLight; + + DLight = GE_RAM_ALLOCATE_STRUCT(Light_DirectLight); + + if (!DLight) + { + GHook.Error("AllocDirectLight: Could not create direct light.\n"); + return NULL; + } + + memset(DLight, 0, sizeof(Light_DirectLight)); + + return DLight; +} + +//======================================================================================== +// FreeDirectLight +//======================================================================================== +void FreeDirectLight(Light_DirectLight *DLight) +{ + if (!DLight) + { + GHook.Printf("*WARNING* FreeDirectLight: NULL Light.\n"); + return; + } + + geRam_Free(DLight); +} + +geBoolean StringContains( const char* a_String, const char* a_SubStr ) +{ + char stringBuf[ 512 ]; + char subStrBuf[ 512 ]; + memset( stringBuf, 0, sizeof( stringBuf ) ) ; + memset( subStrBuf, 0, sizeof( subStrBuf ) ) ; + strncpy( stringBuf, a_String, sizeof( stringBuf ) ) ; + strncpy( subStrBuf, a_SubStr, sizeof( subStrBuf ) ) ; + strupr( stringBuf ) ; + strupr( subStrBuf ) ; + return strstr( stringBuf, subStrBuf ) != NULL ; +} + +//======================================================================================== +// CreateDirectLights +//======================================================================================== +geBoolean CreateDirectLights(void) +{ + int32 i, Leaf, Cluster; + geVec3d Color; + MAP_Entity *Entity; + Light_DirectLight *DLight; + RAD_Patch *Patch; + geVec3d Angles; + geVec3d Angles2; + geXForm3d XForm; + GFX_TexInfo *pTexInfo; + int32 NumSurfLights; + int rgbOnlyCount = 0 ; + int rgbAlwaysVisibleCount = 0 ; + int SunsWithoutRadiusCount = 0 ; + + NumDirectLights = 0; + NumSurfLights = 0; + + for (i=0; i< MAX_DIRECT_CLUSTER_LIGHTS; i++) + DirectClusterLights[i] = NULL; + + // Create the entity lights first + for (i=0; i< NumEntities; i++) + { + Entity = &Entities[i]; + + if (!Entity->Light) + continue; + + if (NumDirectLights+1 >= MAX_DIRECT_LIGHTS) + { + GHook.Printf("*WARNING* Max lights.\n"); + goto Done; + } + + DLight = AllocDirectLight(); + + if (!DLight) + return GE_FALSE; + + GetColorForKey (Entity, "Color", &Color); + + // Default it to 255/255/255 if no light is specified + if (!Color.X && !Color.Y && !Color.Z) + { + Color.X = 1.0f; + Color.Y = 1.0f; + Color.Z = 1.0f; + } + else + ColorNormalize(&Color, &Color); + + DLight->Origin = Entity->Origin; + DLight->Color = Color; + DLight->Intensity = (float)Entity->Light * EntityScale; + DLight->LType = Entity->LType; + + if (GetVectorForKey2 (Entity, "Angles", &Angles)) + { + Angles2.X = (Angles.X / (geFloat)180) * GE_PI; + Angles2.Y = (Angles.Y / (geFloat)180) * GE_PI; + Angles2.Z = (Angles.Z / (geFloat)180) * GE_PI; + + geXForm3d_SetEulerAngles(&XForm, &Angles2); + + geXForm3d_GetLeft(&XForm, &Angles2); + DLight->Normal.X = -Angles2.X; + DLight->Normal.Y = -Angles2.Y; + DLight->Normal.Z = -Angles2.Z; + + DLight->Angle = FloatForKey(Entity, "Arc"); + DLight->Angle = (float)cos(DLight->Angle/180.0f*GE_PI); + + } + + // Find out what type of light it is by it's classname... + if (!stricmp(Entity->ClassName, "Light")) + DLight->Type = DLight_Point; + else if (!stricmp(Entity->ClassName, "SpotLight")) + DLight->Type = DLight_Spot; + // Wismerhill + else if (!stricmp(Entity->ClassName, "SunLight")) + DLight->Type = DLight_SunLight; + // LWM: start + else if (!stricmp(Entity->ClassName, "Sun")) + { + char* name ; + + DLight->Type = DLight_Sun; + + // ================== DaviName + + DLight->SunRGBOnly = false ; + if( strcmpi( ValueForKey( Entity, name = "DaviName" ), "" ) ) + { + char* daviName = ValueForKey( Entity, name ) ; + + if( StringContains( daviName, "rgb" ) ) + { + DLight->SunRGBOnly = true ; + rgbOnlyCount ++ ; + } + } + + DLight->SunRGBAlwaysVisible = false ; + if( (DLight->SunRGBOnly) + && (strcmpi( ValueForKey( Entity, name = "DaviName" ), "" )) + ) { + char* daviName = ValueForKey( Entity, name ) ; + if( StringContains( daviName, "visible" ) ) + { + DLight->SunRGBAlwaysVisible = true ; + rgbAlwaysVisibleCount ++ ; + } + } + + if( DLight->SunFallOffRadiusInTexels < 0.0f ) + { + GHook.Printf("*WARNING* Invalid Sun %s %f.\n", + (const char*) name, + (float) DLight->SunFallOffRadiusInTexels + ); + DLight->SunFallOffRadiusInTexels = 32.0f ; + } + // ================== FallOffType + + // test if entity has "FallOffType" field + if( strcmp( ValueForKey( Entity, name = "FallOffType" ), "" ) ) + { + // let's hope it is an integer... + DLight->SunFallOffType = atoi( ValueForKey( Entity, name ) ) ; + if( DLight->SunFallOffType < SUN_MIN_FALLOFF_TYPE + || DLight->SunFallOffType > SUN_MAX_FALLOFF_TYPE + ) { + GHook.Printf("*WARNING* Invalid Sun %s %d.\n", + (const char*) name, + (int) DLight->SunFallOffType + ); + } + if( DLight->SunFallOffType==SUN_FALLOFF_NONE ) + { + SunsWithoutRadiusCount ++ ; + } + } + else + { + // field doesn't exist + GHook.Printf("*WARNING* Sun has no %s.\n", + (const char*) name + ); + DLight->SunFallOffType = SUN_MIN_FALLOFF_TYPE ; + } + + // ================== FallOffRadiusInTexels + + if( strcmpi( ValueForKey( Entity, name = "FallOffRadiusInTexels" ), "" ) ) + { + // let's hope it is a float + DLight->SunFallOffRadiusInTexels = FloatForKey( Entity, name ) ; + } + else + { + // field doesn't exist + GHook.Printf("*WARNING* Sun has no %s.\n", + (const char*) name + ); + DLight->SunFallOffRadiusInTexels = 32.0f ; + } + if( DLight->SunFallOffRadiusInTexels < 0.0f ) + { + GHook.Printf("*WARNING* Invalid Sun %s %f.\n", + (const char*) name, + (float) DLight->SunFallOffRadiusInTexels + ); + DLight->SunFallOffRadiusInTexels = 32.0f ; + } + + + // ================== FallOffRadiusTopIntensity + + if( strcmpi( ValueForKey( Entity, name = "FallOffRadiusTopIntensity" ), "" ) ) + { + // let's hope it is a float + DLight->SunFallOff100PercentRadius = FloatForKey( Entity, name ) ; + + } + else + { + // field doesn't exist + GHook.Printf("*WARNING* Sun has no %s.\n", + (const char*) name + ); + DLight->SunFallOff100PercentRadius = 0 ; + } + if( DLight->SunFallOff100PercentRadius < 0.0f + || DLight->SunFallOff100PercentRadius > DLight->SunFallOffRadiusInTexels + ) { + GHook.Printf("*WARNING* Invalid Sun %s %f.\n", + (const char*) name, + (float) DLight->SunFallOff100PercentRadius + ); + DLight->SunFallOff100PercentRadius = 0 ; + } + + // ================== FallOffSecretNumber + + if( strcmpi( ValueForKey( Entity, name = "FallOffSecretNumber" ), "" ) ) + { + // let's hope it is a float + DLight->SunFallOffAlpha = FloatForKey( Entity, name ) ; + + } + else + { + // field doesn't exist + GHook.Printf("*WARNING* Sun has no %s.\n", + (const char*) name + ); + DLight->SunFallOffAlpha = 1.0f ; + } + + if( DLight->SunFallOffAlpha < 0.0f + || DLight->SunFallOffAlpha > 100.0f ) + { + GHook.Printf("*ERROR* Invalid Sun %s %f.\n", + (const char*) name, + (float) DLight->SunFallOffAlpha + ); + DLight->SunFallOffAlpha = 1.0f ; + } + + +#if DEBUG_SUN + GHook.Printf("*DEBUG* Sun SunFallOffType %d.\n", (int) DLight->SunFallOffType ); + GHook.Printf("*DEBUG* Sun SunFallOffRadiusInTexels %f.\n", (float) DLight->SunFallOffRadiusInTexels ); + GHook.Printf("*DEBUG* Sun SunFallOff100PercentRadius %f.\n", (float) DLight->SunFallOff100PercentRadius ); + GHook.Printf("*DEBUG* Sun SunFallOffAlpha %f.\n", (float) DLight->SunFallOffAlpha ); +#endif + } + // LWM: end + + + Leaf = FindGFXLeaf(0, &Entity->Origin); + Cluster = GFXLeafs[Leaf].Cluster; + + if (Cluster < 0) + { + GHook.Printf("*WARNING* CreateLights: Light in solid leaf.\n"); + continue; + } + + if (Cluster >= MAX_DIRECT_CLUSTER_LIGHTS) + { + GHook.Printf("*WARNING* CreateLights: Max cluster for light.\n"); + continue; + } + + DLight->Next = DirectClusterLights[Cluster]; + DirectClusterLights[Cluster] = DLight; + + DirectLights[NumDirectLights++] = DLight; + + } + + GHook.Printf("Num Normal Lights : %5i\n", NumDirectLights); + GHook.Printf("Num RGB only Lights : %5i\n", rgbOnlyCount ); + GHook.Printf("Num RGB Always Visible Lights : %5i\n", rgbAlwaysVisibleCount ); + GHook.Printf("Num Suns with fallofftype 0 : %5i\n", SunsWithoutRadiusCount ) ; + + if (!DoRadiosity) // Stop here if no radisosity is going to be done + return GE_TRUE; + + // Now create the radiosity direct lights (surface emitters) + for (i=0; i< NumGFXFaces; i++) + { + pTexInfo = &GFXTexInfo[GFXFaces[i].TexInfo]; + + // Only look at surfaces that want to emit light + if (!(pTexInfo->Flags & TEXINFO_LIGHT)) + continue; + + for (Patch = FacePatches[i]; Patch; Patch = Patch->Next) + { + Leaf = Patch->Leaf; + Cluster = GFXLeafs[Leaf].Cluster; + + if (Cluster < 0) + continue; // Skip, solid + + if (Cluster >= MAX_DIRECT_CLUSTER_LIGHTS) + { + GHook.Printf("*WARNING* CreateLights: Max cluster for surface light.\n"); + continue; + } + + if (NumDirectLights+1 >= MAX_DIRECT_LIGHTS) + { + GHook.Printf("*WARNING* Max lights.\n"); + goto Done; + } + + DLight = AllocDirectLight(); + + if (!DLight) + return GE_FALSE; + + DLight->Origin = Patch->Origin; + DLight->Color = Patch->Reflectivity; + + DLight->Normal = Patch->Plane.Normal; + DLight->Type = DLight_Surface; + + DLight->Intensity = pTexInfo->FaceLight * Patch->Area; + // Make sure the emitter ends up with some light too + geVec3d_AddScaled(&Patch->RadFinal, &Patch->Reflectivity, DLight->Intensity, &Patch->RadFinal); + + // Insert this surface direct light into the list of lights + DLight->Next = DirectClusterLights[Cluster]; + DirectClusterLights[Cluster] = DLight; + + DirectLights[NumDirectLights++] = DLight; + NumSurfLights++; + } + } + + Done: + + GHook.Printf("Num Surf Lights : %5i\n", NumSurfLights); + + return GE_TRUE; +} + +//======================================================================================== +// FreeDirectLights +//======================================================================================== +void FreeDirectLights(void) +{ + int32 i; + + for (i=0; i< MAX_DIRECT_LIGHTS; i++) + { + if (DirectLights[i]) + FreeDirectLight(DirectLights[i]); + + DirectLights[i] = NULL; + } + + for (i=0; i< MAX_DIRECT_CLUSTER_LIGHTS; i++) + { + DirectClusterLights[i] = NULL; + } + + NumDirectLights = 0; +} + diff --git a/GBSPLib/Light.h b/GBSPLib/Light.h new file mode 100644 index 0000000..5c7ba31 --- /dev/null +++ b/GBSPLib/Light.h @@ -0,0 +1,187 @@ +/****************************************************************************************/ +/* Light.h */ +/* */ +/* Author: John Pollard */ +/* Description: Lights a BSP */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef LIGHT_H +#define LIGHT_H + +#include +#include + +#include "GBSPfile.h" +#include "GBSPLib.h" // Lightparms +#include "BSP.h" + +#define MAX_PATCHES 65000*2 // eaa3 using int32 for lights, so pushed the size up + +#define MAX_LTYPES 4 +#define MAX_LTYPE_INDEX 12 + +#define LGRID_SIZE 16 // Must be multiple of 2 +//#define MAX_LMAP_SIZE 128 // In lightmap pexels (This will allow the face to be 128*16 in floating units at lmap scale of 1.0f) +//#define MAX_LMAP_SIZE 64 // In lightmap pexels (This will allow the face to be 64*16 in floating units at lmap scale of 1.0f) +#define MAX_LMAP_SIZE 18 // In lightmap pexels + +extern geFloat LightScale; +extern geFloat EntityScale; +extern geFloat MaxLight; +extern int32 NumSamples; + +extern geBoolean LVerbose; +extern geBoolean DoRadiosity; +extern geFloat PatchSize; +extern int32 NumBounce; +extern geBoolean FastPatch; +extern geFloat ReflectiveScale; + +extern geVec3d MinLight; + +int32 FindGFXLeaf(int32 Node, geVec3d *Vert); +geBoolean RayCollision(geVec3d *Front, geVec3d *Back, geVec3d *I); +geBoolean RayCollisionButSky(geVec3d *Front, geVec3d *Back, geVec3d *I); + +typedef struct +{ + geVec3d *RGBLData[MAX_LTYPE_INDEX]; + int32 NumLTypes; + geBoolean RGB; + geFloat Mins[2]; + geFloat Maxs[2]; + int32 LMaxs[2]; + int32 LMins[2]; + int32 LSize[2]; +} LInfo; + +typedef struct +{ + int32 Face; + GFX_Plane Plane; + geVec3d T2WVecs[2]; + geVec3d TexOrg; + geVec3d *Points; + int32 NumPoints; + + geVec3d Center; + geFloat Radius; +} FInfo; + +extern LInfo *Lightmaps; +extern FInfo *FaceInfo; + +geBoolean LightGBSPFile(char *FileName, LightParms *Parms); + +void CleanupLight(void); + +//==================================================================================== +// Radiosity stuff +//==================================================================================== +struct _RAD_Receiver; + +typedef struct _RAD_Patch +{ + _RAD_Patch *Next; // Next patch in list + + GBSP_Poly *Poly; // Poly for patch (Not used thoughout entire life) + geVec3d Origin; // Origin + int32 Leaf; // Leaf patch is looking into + geFloat Area; // Area of patch + GBSP_Plane Plane; // Plane + uint32 NumReceivers; + _RAD_Receiver *Receivers; // What patches this patch emits to + int32 NumSamples; // Number of samples lightmaps has contributed + + geVec3d RadStart; // Power of patch from original lightmap + geVec3d RadSend; // How much to send each bounce + geVec3d RadReceive; // How much received from current bounce + geVec3d RadFinal; // How much received from all bounces (what to add back to the lightmap) + + geVec3d Reflectivity; + + geVec3d Mins; // Mins/ Max of patch + geVec3d Maxs; +} RAD_Patch, *pRAD_Patch; + +typedef struct _RAD_Receiver +{ + //_RAD_Receiver *Next; // Next Receiver for patch + //RAD_Patch *Patch; // Patch this Receiver emits ti + //geFloat Amount; // How much to the receiving patch gets + uint32 Patch; + uint32 Amount; +} RAD_Receiver; + +extern pRAD_Patch *FacePatches; +extern pRAD_Patch *PatchList; +extern geFloat *RecAmount; + +extern int32 NumPatches; +extern int32 NumReceivers; + +geBoolean BuildPatches(void); +void FreePatches(void); +geBoolean CalcReceivers(char *FileName); +void FreeReceivers(void); +geBoolean BouncePatches(void); +geBoolean AbsorbPatches(void); + +typedef struct Tri_Edge +{ + int32 p0, p1; + geVec3d normal; + geFloat dist; + struct Tri *tri; +} Tri_Edge; + +typedef struct Tri +{ + Tri_Edge *Edges[3]; +} Tri; + +#define MAX_TRI_POINTS 1024*4 +#define MAX_TRI_EDGES (MAX_TRI_POINTS*6) +#define MAX_TRI_TRIS (MAX_TRI_POINTS*2) + +typedef struct +{ + int32 NumPoints; + int32 NumEdges; + int32 NumTris; + GBSP_Plane *Plane; + Tri_Edge *EdgeMatrix[MAX_TRI_POINTS][MAX_TRI_POINTS]; + RAD_Patch *Points[MAX_TRI_POINTS]; + Tri_Edge Edges[MAX_TRI_EDGES]; + Tri TriList[MAX_TRI_TRIS]; +} Tri_Patch; + +Tri_Patch *Tri_PatchCreate(GBSP_Plane *Plane); +void Tri_PatchDestroy(Tri_Patch *tr); +Tri_Edge *FindEdge (Tri_Patch *TriPatch, int p0, int p1); +Tri *AllocTriangle(Tri_Patch *TriPatch); +geBoolean Tri_Edge_r(Tri_Patch *TriPatch, Tri_Edge *e); +geBoolean TriangulatePoints(Tri_Patch *TriPatch); +geBoolean AddPointToTriangulation (RAD_Patch *patch, Tri_Patch *TriPatch); +void LerpTriangle (Tri_Patch *TriPatch, Tri *t, geVec3d *Point, geVec3d *Color); +geBoolean Tri_PointInside(Tri *Tri, geVec3d *Point); +geBoolean SampleTriangulation(geVec3d *Point, Tri_Patch *TriPatch, geVec3d *Color); +geBoolean FindClosestTriPoint(geVec3d *Point, Tri_Patch *Tri, geVec3d *Color); + + +#endif + diff --git a/GBSPLib/MATHLIB.CPP b/GBSPLib/MATHLIB.CPP new file mode 100644 index 0000000..2dfafb3 --- /dev/null +++ b/GBSPLib/MATHLIB.CPP @@ -0,0 +1,145 @@ +/****************************************************************************************/ +/* MathLib.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Various math functions not included in Vec3d.h, etc... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "Math.h" +#include "MathLib.h" + +geVec3d VecOrigin = {0.0f, 0.0f, 0.0f}; + +//==================================================================================== +// ClearBounds +//==================================================================================== +void ClearBounds(geVec3d *Mins, geVec3d *Maxs) +{ + Mins->X = MIN_MAX_BOUNDS; + Mins->Y = MIN_MAX_BOUNDS; + Mins->Z = MIN_MAX_BOUNDS; + + Maxs->X = -MIN_MAX_BOUNDS; + Maxs->Y = -MIN_MAX_BOUNDS; + Maxs->Z = -MIN_MAX_BOUNDS; +} + +//======================================================================================= +// AddPointToBounds +//======================================================================================= +void AddPointToBounds(geVec3d *v, geVec3d *Mins, geVec3d *Maxs) +{ + int32 i; + geFloat Val; + + for (i=0 ; i<3 ; i++) + { + Val = VectorToSUB(*v, i); + + if (Val < VectorToSUB(*Mins, i)) + VectorToSUB(*Mins, i) = Val; + if (Val > VectorToSUB(*Maxs, i)) + VectorToSUB(*Maxs, i) = Val; + } +} + +//======================================================================================= +// ColorNormalize +//======================================================================================= +geFloat ColorNormalize(geVec3d *C1, geVec3d *C2) +{ + geFloat Max; + + Max = C1->X; + if (C1->Y > Max) + Max = C1->Y; + if (C1->Z > Max) + Max = C1->Z; + + if (Max == 0.0f) + return 0.0f; + + geVec3d_Scale(C1, 1.0f/Max, C2); + + return Max; +} + +//======================================================================================= +// ColorClamp +//======================================================================================= +geFloat ColorClamp(geVec3d *C1, geFloat Clamp, geVec3d *C2) +{ + int32 i; + geFloat Max, Max2; + geVec3d C3; + + Max = -1.0f; + + C3 = *C1; + + for (i=0; i<3; i++) + { + if (VectorToSUB(C3, i) < 1.0f) + VectorToSUB(C3, i) = 1.0f; + + if (VectorToSUB(C3, i) > Max) + Max = VectorToSUB(C3, i); + } + + Max2 = Max; + + if (Max2 > Clamp) + Max2 = Clamp; + + geVec3d_Scale(C1, Max2/Max, C2); + + return Max; +} + +//======================================================================================= +// geVec3d_PlaneType +//======================================================================================= +int32 geVec3d_PlaneType(geVec3d *V1) +{ + geFloat X, Y, Z; + + X = (geFloat)fabs(V1->X); + Y = (geFloat)fabs(V1->Y); + Z = (geFloat)fabs(V1->Z); + + if (X == 1.0f) + return PLANE_X; + + else if (Y == 1.0f) + return PLANE_Y; + + else if (Z == 1.0f) + return PLANE_Z; + + if (X >= Y && X >= Z) + return PLANE_ANYX; + + else if (Y >= X && Y >= Z) + return PLANE_ANYY; + + else + return PLANE_ANYZ; +} + + diff --git a/GBSPLib/MATHLIB.H b/GBSPLib/MATHLIB.H new file mode 100644 index 0000000..39fc0ac --- /dev/null +++ b/GBSPLib/MATHLIB.H @@ -0,0 +1,56 @@ +/****************************************************************************************/ +/* MathLib.h */ +/* */ +/* Author: John Pollard */ +/* Description: Various math functions not included in Vec3d.h, etc... */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef MATHLIB_H +#define MATHLIB_H + +#include "Vec3d.h" + +//#define ON_EPSILON (geFloat)0.05 +#define ON_EPSILON (geFloat)0.1 +//#define ON_EPSILON 0.05f +#define VCOMPARE_EPSILON ON_EPSILON + +//#define MIN_MAX_BOUNDS 8192.0f +#define MIN_MAX_BOUNDS 15192.0f +#define MIN_MAX_BOUNDS2 MIN_MAX_BOUNDS*2 + +#define VectorToSUB(a, b) (*(((geFloat*)&a) + b) ) + +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 +#define PLANE_ANY 6 + +extern geVec3d VecOrigin; + +void ClearBounds(geVec3d *Mins, geVec3d *Maxs); +void AddPointToBounds(geVec3d *v, geVec3d *Mins, geVec3d *Maxs); + +geFloat ColorNormalize(geVec3d *C1, geVec3d *C2); +geFloat ColorClamp(geVec3d *C1, geFloat Clamp, geVec3d *C2); + +int32 geVec3d_PlaneType(geVec3d *V1); + +#endif diff --git a/GBSPLib/Map.cpp b/GBSPLib/Map.cpp new file mode 100644 index 0000000..4dabc02 --- /dev/null +++ b/GBSPLib/Map.cpp @@ -0,0 +1,758 @@ +/****************************************************************************************/ +/* Map.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Module for loading a .map file. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "Map.h" +#include "GBSPFile.h" +#include "Texture.h" +#include "BSP.h" +#include "Stdio.h" +#include "Math.h" +#include "Brush2.h" +#include "Poly.h" +#include "Mathlib.h" + +#include "Motion.h" // From Genesis (in include path) +#include "Errorlog.h" +#include "Ram.h" + +int32 NumEntities; +MAP_Entity Entities[MAX_MAP_ENTITIES]; + +//===================================================================================== +// Entity parsing stuff +//===================================================================================== +char *ValueForKey (MAP_Entity *Ent, char *Key) +{ + MAP_Epair *Ep; + + for (Ep=Ent->Epairs ; Ep ; Ep=Ep->Next) + if (!stricmp (Ep->Key, Key) ) + return Ep->Value; + return ""; +} + +//===================================================================================== +//===================================================================================== +void SetKeyValue (MAP_Entity *Ent, char *Key, char *Value) +{ + MAP_Epair *Ep; + + for (Ep=Ent->Epairs ; Ep ; Ep=Ep->Next) + { + if (!stricmp (Ep->Key, Key) ) + { + geRam_Free(Ep->Value); + Ep->Value = NewString(Value); + return; + } + } + + Ep = GE_RAM_ALLOCATE_STRUCT(MAP_Epair); + Ep->Next = Ent->Epairs; + Ent->Epairs = Ep; + Ep->Key = NewString(Key); + Ep->Value = NewString(Value); +} + +//===================================================================================== +//===================================================================================== +geFloat FloatForKey (MAP_Entity *Ent, char *Key) +{ + char *k; + + k = ValueForKey (Ent, Key); + return (geFloat)atof(k); +} + +//===================================================================================== +//===================================================================================== +void GetVectorForKey (MAP_Entity *Ent, char *Key, geVec3d *Vec) +{ + char *k; + double v1, v2, v3; + + k = ValueForKey (Ent, Key); + v1 = v2 = v3 = 0; + + sscanf (k, "%lf %lf %lf", &v1, &v2, &v3); + + Vec->X = (geFloat)v1; + Vec->Y = (geFloat)v2; + Vec->Z = (geFloat)v3; +} + +//===================================================================================== +//===================================================================================== +geBoolean GetVectorForKey2 (MAP_Entity *Ent, char *Key, geVec3d *Vec) +{ + char *k; + double v1, v2, v3; + + Vec->X = (geFloat)0; + Vec->Y = (geFloat)0; + Vec->Z = (geFloat)0; + + k = ValueForKey (Ent, Key); + if (!k || !k[0]) + return GE_FALSE; + + v1 = v2 = v3 = 0; + + sscanf (k, "%lf %lf %lf", &v1, &v2, &v3); + + Vec->X = (geFloat)v1; + Vec->Y = (geFloat)v2; + Vec->Z = (geFloat)v3; + + return GE_TRUE; +} + +//===================================================================================== +//===================================================================================== +void GetColorForKey (MAP_Entity *Ent, char *Key, geVec3d *Vec) +{ + char *k; + double v1, v2, v3; + + k = ValueForKey (Ent, Key); + v1 = v2 = v3 = 0; + + sscanf (k, "%lf %lf %lf", &v1, &v2, &v3); + + Vec->X = (geFloat)v1; + Vec->Y = (geFloat)v2; + Vec->Z = (geFloat)v3; +} + +//============================================================================ +//============================================================================ +char *NewString(char *Str) +{ + char *NewStr = GE_RAM_ALLOCATE_ARRAY(char, strlen(Str)+1); + + if (!NewStr) + { + GHook.Error("New string: Not enough memory.\n"); + return NULL; + } + + strcpy(NewStr, Str); + + return NewStr; +} + +//============================================================================ +// SaveEntityData +// Reads and writes to/from global Entities structure (love them globals :) +//============================================================================ + +//============================================================================ +// SaveEntityData +//============================================================================ +geBoolean SaveEntityData(geVFile *VFile) +{ + int32 i; + + // Write the number of entities + if (!geVFile_Write(VFile, &NumEntities, sizeof(int32))) + return GE_FALSE; + + // Write out each entity + for (i=0 ; i< NumEntities; i++) + { + MAP_Epair *Ep; + int32 NumEpairs; + + // Count the epairs + for (NumEpairs = 0, Ep = Entities[i].Epairs ; Ep ; Ep = Ep->Next, NumEpairs++); + + // Write out how many epsirs + if (!geVFile_Write(VFile, &NumEpairs, sizeof(int32))) + return GE_FALSE; + + for (Ep = Entities[i].Epairs ; Ep ; Ep = Ep->Next) + { + int32 Size; + + // Write out the Key + Size = strlen(Ep->Key)+1; + + if (!geVFile_Write(VFile, &Size, sizeof(int32))) + return GE_FALSE; + + if (!geVFile_Write(VFile, Ep->Key, sizeof(uint8)*Size)) + return GE_FALSE; + + // Write out the Value + Size = strlen(Ep->Value)+1; + + if (!geVFile_Write(VFile, &Size, sizeof(int32))) + return GE_FALSE; + + if (!geVFile_Write(VFile, Ep->Value, sizeof(uint8)*Size)) + return GE_FALSE; + + //GHook.Printf(" Writing: Key: %s, Value: %s\n", Ep->Key, Ep->Value); + } + } + + return GE_TRUE; +} + +//============================================================================ +// LoadEntityData +//============================================================================ +geBoolean LoadEntityData(geVFile *VFile) +{ + int32 i; + + // Get the number of entities + if (!geVFile_Read(VFile, &NumEntities, sizeof(int32))) + return GE_FALSE; + + //GHook.Printf("Reading %i Entities...\n", NumEntities); + + // Load all entities + for (i=0; i< NumEntities; i++) + { + MAP_Entity *Entity; + MAP_Epair *Epair, *Current; + int32 Size, e; + int32 NumEpairs; + + //GHook.Printf(" Reading Entity...\n"); + + Entity = &Entities[i]; + + memset(Entity, 0, sizeof(MAP_Entity)); + + if (!geVFile_Read(VFile, &NumEpairs, sizeof(int32))) + return GE_FALSE; + + Current = NULL; + + //GHook.Printf(" Reading %i Epairs...\n", NumEpairs); + + for (e=0; e< NumEpairs; e++) + { + Epair = GE_RAM_ALLOCATE_STRUCT(MAP_Epair); + + if (!Epair) + return GE_FALSE; + + memset (Epair, 0, sizeof(MAP_Epair)); + + // Read the size of the key + if (!geVFile_Read(VFile, &Size, sizeof(int32))) + return GE_FALSE; + + Epair->Key = GE_RAM_ALLOCATE_ARRAY(char, Size); + if (!Epair->Key) + return GE_FALSE; + + // Read the Key + if (!geVFile_Read(VFile, Epair->Key, Size)) + return GE_FALSE; + + // Read the size of the value + if (!geVFile_Read(VFile, &Size, sizeof(int32))) + return GE_FALSE; + + Epair->Value = GE_RAM_ALLOCATE_ARRAY(char, Size); + if (!Epair->Value) + return GE_FALSE; + + // Read the Value + if (!geVFile_Read(VFile, Epair->Value, Size)) + return GE_FALSE; + + // Add to end of list + Epair->Next = NULL; + + if (!Current) + { + Entity->Epairs = Epair; + Current = Epair; + } + else + { + Current->Next = Epair; + Current = Epair; + } + + //GHook.Printf(" Reading: Key: %s, Value: %s\n", Epair->Key, Epair->Value); + + if (!stricmp(Epair->Key, "ClassName")) + strcpy (Entity->ClassName, Epair->Value); + else if (!stricmp(Epair->Key, "Target")) + strcpy (Entity->Target, Epair->Value); + else if (!stricmp(Epair->Key, "TargetName")) + strcpy (Entity->TargetName, Epair->Value); + else if (!stricmp(Epair->Key, "Origin")) + { + double Val[3]; + + Entity->Flags |= ENTITY_HAS_ORIGIN; + + if (sscanf(Epair->Value, "%lf %lf %lf", &Val[0], &Val[1], &Val[2]) == 3) + { + int32 j; + + for (j=0; j< 3; j++) + VectorToSUB(Entity->Origin, j) = (geFloat)Val[j]; + } + } + else if (!strnicmp(Epair->Key, "Light", 5) || !strnicmp(Epair->Key, "_Light", 5)) + { + Entity->Light = (int32)atof(Epair->Value); + } + else if (!stricmp(Epair->Key, "LType") || !stricmp(Epair->Key, "Style")) + { + Entity->LType = (int32)atof(Epair->Value); + + //GHook.Printf ("LType: %i\n", Entity->LType); + + if (Entity->LType > 254) + { + GHook.Error ("Bad light LType %i (must be 0-254)\n", Entity->LType); + return GE_FALSE; + } + } + else if (!strcmp(Epair->Key, "Angle")) + { + Entity->Angle = (geFloat)atof(Epair->Value); + } + + if (Entity->Light < 0 || Entity->Light > 2500) + GHook.Printf("*WARNING* Bad light value: %i\n", Entity->Light); + } + } + //GHook.Printf ("Num Entities Read : %5i\n", NumEntities); + + return GE_TRUE; +} + +//======================================================================================== +// ConvertGFXEntDataToEntities +//======================================================================================== +geBoolean ConvertGFXEntDataToEntities(void) +{ + geVFile_MemoryContext Context; + geVFile *MemFile; + + //GHook.Printf("ConvertGFXEntDataToEntities: %i\n", NumGFXEntData); + + Context.Data = GFXEntData; + Context.DataLength = NumGFXEntData; + + MemFile = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_MEMORY, NULL, &Context, GE_VFILE_OPEN_READONLY); + + if (!MemFile) + return GE_FALSE; + + if (!LoadEntityData(MemFile)) + { + geVFile_Close(MemFile); + return GE_FALSE; + } + + geVFile_Close(MemFile); + + return GE_TRUE; +} + +//======================================================================================== +// ConvertEntitiesToGFXEntData +//======================================================================================== +geBoolean ConvertEntitiesToGFXEntData(void) +{ + geVFile_MemoryContext Context; + geVFile *MemFile; + + Context.Data = NULL; + Context.DataLength = 0; + + MemFile = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_MEMORY, NULL, &Context, GE_VFILE_OPEN_CREATE); + + if (!MemFile) + return GE_FALSE; + + if (!SaveEntityData(MemFile)) + { + geVFile_Close(MemFile); + return GE_FALSE; + } + + if (!geVFile_UpdateContext(MemFile, &Context, sizeof(Context))) + { + geVFile_Close(MemFile); + return GE_FALSE; + } + + GFXEntData = GE_RAM_ALLOCATE_ARRAY(uint8, Context.DataLength); + + memcpy(GFXEntData, Context.Data, Context.DataLength); + + NumGFXEntData = Context.DataLength; + + geVFile_Close(MemFile); + + return GE_TRUE; +} + +//============================================================================ +// FreeAllEntities +//============================================================================ +void FreeAllEntities(void) +{ + MAP_Entity *Entity; + MAP_Epair *Epair, *Next; + int32 i; + + for (i=0; i< NumEntities; i++) + { + Entity = &Entities[i]; + + if (Entity->Brushes2) + FreeMapBrushList(Entity->Brushes2); + + Entity->Brushes2 = NULL; + + for (Epair = Entity->Epairs; Epair; Epair = Next) + { + Next = Epair->Next; + geRam_Free(Epair->Key); + geRam_Free(Epair->Value); + geRam_Free(Epair); + } + + Entity->Epairs = NULL; + } + + NumEntities = 0; +} + +geBoolean LoadEntity(geVFile *VFile); + +int32 NumSolidBrushes; +int32 NumCutBrushes; +int32 NumHollowCutBrushes; +int32 NumDetailBrushes; +int32 NumTotalBrushes; + +//================================================================================ +// CopyBrush2ToEntity +//================================================================================ +geBoolean CopyBrush2ToEntity(MAP_Brush *Brush, MAP_Entity *Entity, int32 Contents) +{ + MAP_Brush *NewBrush; + int32 i; + + NewBrush = CopyMapBrush(Brush); + + NewBrush->OrderID = -1; + + for (i=0; i< NewBrush->NumSides; i++) + { + NewBrush->OriginalSides[i].Flags &= ~SIDE_VISIBLE; + } + + // Assign the new contents + NewBrush->Contents = Contents; + + // Append it to the beginning of the list... + NewBrush->Next = Entity->Brushes2; + Entity->Brushes2 = NewBrush; + + return GE_TRUE; +} + +//================================================================================ +// LoadBrushFile +//================================================================================ +geBoolean LoadBrushFile(char *FileName) +{ + MAP_BrushFileHeader Header; + int32 i; + char TempName[256]; + geVFile *VFile; + + memset(Entities, 0, sizeof(Entities)); + + GetCurrentDirectory(sizeof(TempName), TempName); + + VFile = geVFile_OpenNewSystem(NULL, + GE_VFILE_TYPE_DOS, + FileName, + NULL, + GE_VFILE_OPEN_READONLY); + + if (!VFile) + { + GHook.Error("LoadBrushFile: Error opening Brush File: %s.\n", FileName); + return GE_FALSE; + } + + GHook.Printf(" --- Load Brush File ---\n"); + + if (!geVFile_Read(VFile, &Header, sizeof(MAP_BrushFileHeader))) + { + geVFile_Close(VFile); + GHook.Error("LoadBrushFile: There was an error loading the header.\n"); + return GE_FALSE; + } + + NumSolidBrushes = 0; + NumCutBrushes = 0; + NumHollowCutBrushes = 0; + NumDetailBrushes = 0; + NumTotalBrushes = 0; + + for (i=0; i< Header.NumEntities; i++) + { + if (!LoadEntity(VFile)) + { + geVFile_Close(VFile); + GHook.Error("LoadBrushFile: Could not load entity.\n"); + return GE_FALSE; + } + } + + geVFile_Close(VFile); + + GHook.Printf("Num Solid Brushes : %5i\n", NumSolidBrushes); + GHook.Printf("Num Cut Brushes : %5i\n", NumCutBrushes); + GHook.Printf("Num Hollow Cut Brushes : %5i\n", NumHollowCutBrushes); + GHook.Printf("Num Detail Brushes : %5i\n", NumDetailBrushes); + GHook.Printf("Num Total Brushes : %5i\n", NumTotalBrushes); + + return GE_TRUE; +} + +#define ENTITY_MODEL_MOTION (1<<0) + +//================================================================================ +// LoadMotion +//================================================================================ +geBoolean LoadMotion(MAP_Entity *Entity, geVFile *VFile) +{ + Entity->Motion = geMotion_CreateFromFile(VFile); + + if (!Entity->Motion) + { + FILE *f; + + f = fopen("Gedit.Log", "wb"); + + if (f) + { + int32 i, NumErrors; + + fprintf(f, " --Error Report--\n"); + + NumErrors = geErrorLog_Count(); + + for (i=0; i= MAX_MAP_ENTITIES) + { + GHook.Error("LoadEntity: Max Entities.\n"); + return GE_FALSE; + } + + Entity = &Entities[NumEntities++]; + + memset(Entity, 0, sizeof(MAP_Entity)); + + if (!geVFile_Read(VFile, &NumBrushes, sizeof(int32))) + { + GHook.Error("LoadEntity: There was an error reading data.\n"); + return GE_FALSE; + } + + for (i=0; i< NumBrushes; i++) + { + MAP_Brush *MBrush2 = LoadMapBrush(VFile); + if (!MBrush2) + { + GHook.Error("LoadEntity: Could not load entities brush.\n"); + return GE_FALSE; + } + MBrush2->OrderID = i; + + // Put at the beginning of entities brush list... + MBrush2->Next = Entity->Brushes2; + Entity->Brushes2 = MBrush2; + } + + if (NumEntities > 1) // For now, only models can contribute area brushes to the world + { + MAP_Brush *Brush; + + for (Brush = Entity->Brushes2; Brush; Brush = Brush->Next) + { + if (!(Brush->Contents & BSP_CONTENTS_AREA2)) + continue; // Only copy area brushes + + CopyBrush2ToEntity(Brush, &Entities[0], BSP_CONTENTS_AREA2 | BSP_CONTENTS_DETAIL2); + } + } + + + if (!geVFile_Read(VFile, &EntityFlags, sizeof(uint32))) + { + GHook.Error("LoadEntity: There was an error reading entity flags.\n"); + return GE_FALSE; + } + + // Check for motion data for model... + if (EntityFlags == ENTITY_MODEL_MOTION) + { + if (!LoadMotion(Entity, VFile)) + { + GHook.Error("LoadEntity: Failed to load motion data for model.\n"); + return GE_FALSE; + } + } + + + if (!geVFile_Read(VFile, &NumFields, sizeof(int32))) + { + GHook.Error("LoadEntity: There was an error reading num fields.\n"); + return GE_FALSE; + } + + Current = NULL; + + for (i=0; i< NumFields; i++) + { + Epair = GE_RAM_ALLOCATE_STRUCT(MAP_Epair); + + if (!geVFile_Read(VFile, &KeySize, sizeof(int32))) + { + geRam_Free(Epair); + GHook.Error("LoadEntity: There was an error reading key size.\n"); + return GE_FALSE; + } + + Epair->Key = GE_RAM_ALLOCATE_ARRAY(char,KeySize+1); + + if (!geVFile_Read(VFile, Epair->Key, sizeof(char)*KeySize)) + { + geRam_Free(Epair->Key); + GHook.Error("LoadEntity: There was an error reading key data.\n"); + return GE_FALSE; + } + Epair->Key[KeySize] = 0; + + if (!geVFile_Read(VFile, &ValueSize, sizeof(int32))) + { + geRam_Free(Epair->Key); + GHook.Error("LoadEntity: There was an error reading value size.\n"); + return GE_FALSE; + } + + Epair->Value = GE_RAM_ALLOCATE_ARRAY(char,ValueSize+1); + + if (!geVFile_Read(VFile, Epair->Value, sizeof(char)*ValueSize)) + { + geRam_Free(Epair->Value); + geRam_Free(Epair->Key); + GHook.Error("LoadEntity: There was an error reading value data.\n"); + return GE_FALSE; + } + + Epair->Value[ValueSize] = 0; + + // Un-Comment for debugging + //GHook.Printf("\"%s\" \"%s\"\n", Epair->Key, Epair->Value); + + Epair->Next = NULL; + + if (!Current) + { + Entity->Epairs = Epair; + Current = Epair; + } + else + { + Current->Next = Epair; + Current = Epair; + } + } + + if (GetVectorForKey2(Entity, "origin", &Entity->Origin)) + Entity->Flags |= ENTITY_HAS_ORIGIN; + + for (Epair = Entity->Epairs; Epair; Epair = Epair->Next) + { + //if (Epair->Value[0] == '%') + // Entity->Flags &= ~ENTITY_HAS_ORIGIN; // Remove the origin flag + + // Remove origin flag on typedefs and model entities. + if (!stricmp(Epair->Value, "%typedef%")) + Entity->Flags &= ~ENTITY_HAS_ORIGIN; + else if ((stricmp (Epair->Key, "classname") == 0) && + (stricmp (Epair->Value, "%Model%") == 0)) + { + Entity->Flags &= ~ENTITY_HAS_ORIGIN; + } + } + + return GE_TRUE; +} + diff --git a/GBSPLib/Map.h b/GBSPLib/Map.h new file mode 100644 index 0000000..036cba6 --- /dev/null +++ b/GBSPLib/Map.h @@ -0,0 +1,122 @@ +/****************************************************************************************/ +/* Map.h */ +/* */ +/* Author: John Pollard */ +/* Description: Module for loading a .map file. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef MAP_H +#define MAP_H + +#include + +#include "BSP.h" +#include "Motion.h" + +#define MAX_MAP_ENTITIES 4096*2 +#define MAX_MAP_TEXINFO 8192*2 +#define MAX_MAP_TEXTURES 1024*2 + +#pragma pack(1) + +typedef struct +{ + int32 Version; + char TAG[4]; + int32 NumEntities; +} MAP_BrushFileHeader; + +typedef struct +{ + int32 Flags; + int32 NumFaces; +} MAP_BrushHeader; + +typedef struct +{ + int32 Flags; + geFloat MipMapBias; + geFloat Alpha; // Alpha for brush + geFloat FaceLight; // Light intensity for face light + geFloat ReflectiveScale; + char TexName[32]; + geFloat uVecX, uVecY, uVecZ; + geFloat DrawScaleX, OffsetX; + geFloat vVecX, vVecY, vVecZ; + geFloat DrawScaleY, OffsetY; + +} MAP_FaceHeader; + +#pragma pack() + +typedef struct _MAP_Epair +{ + _MAP_Epair *Next; + char *Key; + char *Value; + +} MAP_Epair; + +#define ENTITY_HAS_ORIGIN (1<<0) + +typedef struct +{ + MAP_Brush *Brushes2; + + geMotion *Motion; // Temp motion data for entity if it contains a model + + MAP_Epair *Epairs; + + int32 ModelNum; // If brushes != NULL, entity will have a model num + + // For light stage + char ClassName[64]; + geVec3d Origin; // Well, this is used everywhere... + geFloat Angle; + int32 Light; + int32 LType; + char Target[32]; + char TargetName[32]; + + uint32 Flags; +} MAP_Entity; + +extern int32 NumEntities; +extern MAP_Entity Entities[MAX_MAP_ENTITIES]; + +//===================================================================================== +// Entity parsing functions +//===================================================================================== +char *ValueForKey(MAP_Entity *Ent, char *Key); +void SetKeyValue(MAP_Entity *Ent, char *Key, char *Value); +geFloat FloatForKey(MAP_Entity *Ent, char *Key); +void GetVectorForKey(MAP_Entity *Ent, char *Key, geVec3d *Vec); +geBoolean GetVectorForKey2(MAP_Entity *Ent, char *Key, geVec3d *Vec); +void GetColorForKey(MAP_Entity *Ent, char *Key, geVec3d *Vec); +char *NewString(char *Str); + +//===================================================================================== +// Misc functions +//===================================================================================== +geBoolean SaveEntityData(geVFile *VFile); +geBoolean LoadEntityData(geVFile *VFile); +geBoolean ConvertGFXEntDataToEntities(void); +geBoolean ConvertEntitiesToGFXEntData(void); +void FreeAllEntities(void); +geBoolean LoadBrushFile(char *FileName); + +#endif diff --git a/GBSPLib/POLY.CPP b/GBSPLib/POLY.CPP new file mode 100644 index 0000000..c37ad2f --- /dev/null +++ b/GBSPLib/POLY.CPP @@ -0,0 +1,1827 @@ +/****************************************************************************************/ +/* Poly.Cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Various Poly routines (clipping, splitting, etc) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "BSP.h" +#include "Mathlib.h" +#include "Map.h" +#include "Poly.h" +#include "Texture.h" +#include "GBSPFile.h" +#include "Light.h" + +#include "Ram.h" + +int32 NumSubdivides; +geFloat SubdivideSize = 235.0f; +//geFloat SubdivideSize = ((geFloat)((16*MAX_LMAP_SIZE)-20)); +//geFloat SubdivideSize = ((geFloat)((16*MAX_LMAP_SIZE)-32)); + +int32 NumSubdivided; +int32 NumMerged; + +//#define FREAKED_OUT + +geBoolean gCountVerts; +int32 gTotalVerts; +int32 gPeekVerts; + +//#define DEGENERATE_EPSILON 0.05f +#define DEGENERATE_EPSILON 0.001f + +// +// Polys +// + +//==================================================================================== +// AllocPoly +//==================================================================================== +GBSP_Poly *AllocPoly(int32 NumVerts) +{ + GBSP_Poly *NewPoly; + + if (NumVerts > 1000) + { + GHook.Error("Bogus verts: %i\n", NumVerts); + return NULL; + } + + NewPoly = GE_RAM_ALLOCATE_STRUCT(GBSP_Poly); + + if (!NewPoly) + { + GHook.Error("AllocPoly: Not enough memory.\n"); + return NULL; + } + + NewPoly->Verts = GE_RAM_ALLOCATE_ARRAY(geVec3d,NumVerts); + + if (!NewPoly->Verts) + { + GHook.Error("AllocPoly: Not enough memory for verts: %i\n", NumVerts); + geRam_Free(NewPoly); + return NULL; + } + + NewPoly->NumVerts = NumVerts; + +#ifdef SHOW_DEBUG_STATS + if (gCountVerts) + { + gTotalVerts += NumVerts; + if (gTotalVerts > gPeekVerts) + gPeekVerts = gTotalVerts; + } +#endif + + return NewPoly; +} + +//==================================================================================== +// FreePoly +//==================================================================================== +void FreePoly(GBSP_Poly *Poly) +{ + if (!Poly) + { + GHook.Printf("*WARNING* FreePoly: NULL Poly.\n"); + return; + } + + if (Poly->Verts) + { + geRam_Free(Poly->Verts); + + #ifdef SHOW_DEBUG_STATS + if (gCountVerts) + { + gTotalVerts -= Poly->NumVerts; + } + #endif + } + + geRam_Free(Poly); +} + +//===================================================================================== +// TextureAxisFromPlane +//===================================================================================== +geBoolean TextureAxisFromPlane(GBSP_Plane *Pln, geVec3d *Xv, geVec3d *Yv) +{ + int32 BestAxis; + geFloat Dot,Best; + int32 i; + + Best = 0.0f; + BestAxis = -1; + + for (i=0 ; i<3 ; i++) + { + Dot = (geFloat)fabs(VectorToSUB(Pln->Normal, i)); + if (Dot > Best) + { + Best = Dot; + BestAxis = i; + } + } + + switch(BestAxis) + { + case 0: // X + Xv->X = (geFloat)0; + Xv->Y = (geFloat)0; + Xv->Z = (geFloat)1; + + Yv->X = (geFloat)0; + Yv->Y = (geFloat)-1; + Yv->Z = (geFloat)0; + break; + case 1: // Y + Xv->X = (geFloat)1; + Xv->Y = (geFloat)0; + Xv->Z = (geFloat)0; + + Yv->X = (geFloat)0; + Yv->Y = (geFloat)0; + Yv->Z = (geFloat)1; + break; + case 2: // Z + Xv->X = (geFloat)1; + Xv->Y = (geFloat)0; + Xv->Z = (geFloat)0; + + Yv->X = (geFloat)0; + Yv->Y = (geFloat)-1; + Yv->Z = (geFloat)0; + break; + default: + GHook.Error("TextureAxisFromPlane: No Axis found.\n"); + return GE_FALSE; + break; + } + + return GE_TRUE; +} + +//==================================================================================== +// CreatePolyFromPlane +// Create a huge poly with normal pointing in same direction as Plane +//==================================================================================== +GBSP_Poly *CreatePolyFromPlane(GBSP_Plane *Plane) +{ + geVec3d Normal = Plane->Normal; + geVec3d UpVect = {0.0f, 0.0f, 0.0f}; + geVec3d RightVect, Org; + GBSP_Poly *Poly; + + if (!TextureAxisFromPlane(Plane, &RightVect, &UpVect)) + return NULL; + + // Produce some walk vectors + geVec3d_CrossProduct(&Normal, &UpVect, &RightVect); // Get right vector + geVec3d_CrossProduct(&Normal, &RightVect, &UpVect); // Get new Up vector from correct Right vector + + geVec3d_Normalize(&UpVect); + geVec3d_Normalize(&RightVect); + + // Create the poly with 4 verts + Poly = AllocPoly(4); + + if (!Poly) + { + GHook.Error("CreatePolyFromPlane: Not enough memory for new poly!\n"); + return NULL; + } + + geVec3d_Scale(&Normal, Plane->Dist, &Org); // Get the Org + geVec3d_Scale(&UpVect, (geFloat)MIN_MAX_BOUNDS, &UpVect); // Scale walk vectors + geVec3d_Scale(&RightVect, (geFloat)MIN_MAX_BOUNDS, &RightVect); + + geVec3d_Subtract(&Org, &RightVect, &Poly->Verts[0]); + geVec3d_Add(&Poly->Verts[0], &UpVect, &Poly->Verts[0]); + + geVec3d_Add(&Org, &RightVect, &Poly->Verts[1]); + geVec3d_Add(&Poly->Verts[1], &UpVect, &Poly->Verts[1]); + + geVec3d_Add(&Org, &RightVect, &Poly->Verts[2]); + geVec3d_Subtract(&Poly->Verts[2], &UpVect, &Poly->Verts[2]); + + geVec3d_Subtract(&Org, &RightVect, &Poly->Verts[3]); + geVec3d_Subtract(&Poly->Verts[3], &UpVect, &Poly->Verts[3]); + +#ifdef FREAKED_OUT + geVec3d Normal2, V1, V2; + geVec3d_Subtract(&Poly->Verts[0], &Poly->Verts[1], &V1); + geVec3d_Subtract(&Poly->Verts[2], &Poly->Verts[1], &V2); + geVec3d_CrossProduct(&V1, &V2, &Normal2); + geVec3d_Normalize(&Normal2); + + Normal = Plane->Normal; + + if (!geVec3d_Compare(&Normal, &Normal2, VCOMPARE_EPSILON)) + { + GHook.Error("Normal1 X:%2.2f, Y:%2.2f, Z:%2.2f\n", Normal.X, Normal.Y, Normal.Z); + GHook.Error("Normal2 X:%2.2f, Y:%2.2f, Z:%2.2f\n", Normal2.X, Normal2.Y, Normal2.Z); + GHook.Error("CreatePolyFromPlane: Normals do not match.\n"); + return NULL; + } +#endif + + return Poly; + +} + +#define MAX_TEMP_VERTS 200 + +geVec3d TempVerts[MAX_TEMP_VERTS]; +geVec3d TempVerts2[MAX_TEMP_VERTS]; + +#define CLIP_EPSILON (geFloat)0.001 + +//==================================================================================== +// ClipPoly +//==================================================================================== +geBoolean ClipPoly(GBSP_Poly *InPoly, GBSP_Plane *Plane, geBoolean FlipTest, GBSP_Poly **OutPoly) +{ + GBSP_Poly *NewPoly = NULL; + geVec3d *pInVert, Vert1, Vert2; + geVec3d *pFrontVert, *Verts; + int32 i, NextVert, NewNumVerts = 0; + geFloat Scale; + + geVec3d Normal = Plane->Normal; + geFloat Dist = Plane->Dist; + int32 NumVerts = InPoly->NumVerts; + int32 VSides[100]; + geFloat VDist[100]; + int32 CountSides[3]; + + *OutPoly = NULL; + + if (NumVerts >= 100) + { + GHook.Error("ClipPoly: Too many verts.\n"); + return GE_FALSE; + } + + memset(CountSides, 0, sizeof(CountSides)); + + Verts = InPoly->Verts; + pInVert = Verts; + pFrontVert = TempVerts; + + if (FlipTest) // Flip the normal and dist + { + Normal.X = -Normal.X; + Normal.Y = -Normal.Y; + Normal.Z = -Normal.Z; + Dist = -Dist; + } + + // See what side of plane each vert is on + for (i=0; i< NumVerts; i++) + { + VDist[i] = geVec3d_DotProduct(&Verts[i], &Normal) - Dist; + if (VDist[i] > ON_EPSILON) + VSides[i] = 0; + else if (VDist[i] < -ON_EPSILON) + VSides[i] = 1; + else + VSides[i] = 2; + + CountSides[VSides[i]]++; + } + + if (!CountSides[0]) + { + FreePoly(InPoly); + *OutPoly = NULL; + return GE_TRUE; + } + + if (!CountSides[1]) + { + *OutPoly = InPoly; + return GE_TRUE; + } + + // Else we have to split this sucker + for (i=0; i< NumVerts; i++) + { + Vert1 = Verts[i]; + + if (VSides[i] == 2) // On plane, put on both sides + { + *pFrontVert++ = Vert1; + continue; + } + + if (VSides[i] == 0) // Front side, put on front list + *pFrontVert++ = Vert1; + + NextVert = (i+1) % NumVerts; + + if (VSides[NextVert] == 2 || VSides[NextVert] == VSides[i]) + continue; + + Vert2 = Verts[NextVert]; + Scale = VDist[i] / (VDist[i] - VDist[NextVert]); + + pFrontVert->X = Vert1.X + (Vert2.X - Vert1.X) * Scale; + pFrontVert->Y = Vert1.Y + (Vert2.Y - Vert1.Y) * Scale; + pFrontVert->Z = Vert1.Z + (Vert2.Z - Vert1.Z) * Scale; + + pFrontVert++; + } + + FreePoly(InPoly); // Don't need this anymore + + NewNumVerts = pFrontVert - TempVerts; + + if (NewNumVerts < 3) + { + *OutPoly = NULL; + return GE_TRUE; + } + + NewPoly = AllocPoly(NewNumVerts); + + if (!NewPoly) + { + GHook.Error("ClipPoly: Not enough mem for new poly.\n"); + return GE_FALSE; + } + + for (i = 0; i< NewNumVerts; i++) + NewPoly->Verts[i] = TempVerts[i]; + + *OutPoly = NewPoly; + return GE_TRUE; +} + +//==================================================================================== +// ClipPolyEpsilon +//==================================================================================== +geBoolean ClipPolyEpsilon(GBSP_Poly *InPoly, geFloat Epsilon, GBSP_Plane *Plane, geBoolean FlipTest, GBSP_Poly **OutPoly) +{ + GBSP_Poly *NewPoly = NULL; + geVec3d *pInVert, Vert1, Vert2; + geVec3d *pFrontVert, *Verts; + int32 i, NextVert, NewNumVerts = 0; + geFloat Scale; + + geVec3d Normal = Plane->Normal; + geFloat Dist = Plane->Dist; + int32 NumVerts = InPoly->NumVerts; + int32 VSides[100]; + geFloat VDist[100]; + int32 CountSides[3]; + + *OutPoly = NULL; + + if (NumVerts >= 100) + { + GHook.Error("ClipPoly: Too many verts.\n"); + return GE_FALSE; + } + + memset(CountSides, 0, sizeof(CountSides)); + + Verts = InPoly->Verts; + pInVert = Verts; + pFrontVert = TempVerts; + + if (FlipTest) // Flip the normal and dist + { + Normal.X = -Normal.X; + Normal.Y = -Normal.Y; + Normal.Z = -Normal.Z; + Dist = -Dist; + } + + // See what side of plane each vert is on + for (i=0; i< NumVerts; i++) + { + VDist[i] = geVec3d_DotProduct(&Verts[i], &Normal) - Dist; + if (VDist[i] > Epsilon) + VSides[i] = 0; + else if (VDist[i] < -Epsilon) + VSides[i] = 1; + else + VSides[i] = 2; + + CountSides[VSides[i]]++; + } + + if (!CountSides[0]) + { + FreePoly(InPoly); + *OutPoly = NULL; + return GE_TRUE; + } + + if (!CountSides[1]) + { + *OutPoly = InPoly; + return GE_TRUE; + } + + // Else we have to split this sucker + for (i=0; i< NumVerts; i++) + { + Vert1 = Verts[i]; + + if (VSides[i] == 2) // On plane, put on both sides + { + *pFrontVert++ = Vert1; + continue; + } + + if (VSides[i] == 0) // Front side, put on front list + *pFrontVert++ = Vert1; + + NextVert = (i+1) % NumVerts; + + if (VSides[NextVert] == 2 || VSides[NextVert] == VSides[i]) + continue; + + Vert2 = Verts[NextVert]; + Scale = VDist[i] / (VDist[i] - VDist[NextVert]); + + pFrontVert->X = Vert1.X + (Vert2.X - Vert1.X) * Scale; + pFrontVert->Y = Vert1.Y + (Vert2.Y - Vert1.Y) * Scale; + pFrontVert->Z = Vert1.Z + (Vert2.Z - Vert1.Z) * Scale; + + pFrontVert++; + } + + FreePoly(InPoly); // Don't need this anymore + + NewNumVerts = pFrontVert - TempVerts; + + if (NewNumVerts < 3) + { + *OutPoly = NULL; + return GE_TRUE; + } + + NewPoly = AllocPoly(NewNumVerts); + + if (!NewPoly) + { + GHook.Error("ClipPoly: Not enough mem for new poly.\n"); + return GE_FALSE; + } + + for (i = 0; i< NewNumVerts; i++) + NewPoly->Verts[i] = TempVerts[i]; + + *OutPoly = NewPoly; + return GE_TRUE; +} + +//==================================================================================== +// SplitPoly +//==================================================================================== +geBoolean SplitPoly(GBSP_Poly *InPoly, GBSP_Plane *Plane, GBSP_Poly **Front, GBSP_Poly **Back, + geBoolean FlipTest) +{ + GBSP_Poly *NewPoly = NULL; + geVec3d *pInVert, Vert1, Vert2; + geVec3d *pFrontVert, *pBackVert, *Verts; + int32 i, NextVert, NewNumVerts = 0; + geFloat Scale; + + geVec3d Normal = Plane->Normal; + geFloat Dist = Plane->Dist, *pDist; + int32 NumVerts = InPoly->NumVerts; + int32 VSides[100]; + geFloat VDist[100]; + int32 CountSides[3]; + + if (NumVerts >= 100) + { + GHook.Error("SplitPoly: Too many verts.\n"); + return GE_FALSE; + } + + memset(CountSides, 0, sizeof(CountSides)); + + Verts = InPoly->Verts; + pInVert = Verts; + pFrontVert = TempVerts; + pBackVert = TempVerts2; + + if (FlipTest) // Flip the normal and dist + { + Normal.X = -Normal.X; + Normal.Y = -Normal.Y; + Normal.Z = -Normal.Z; + Dist = -Dist; + } + + // See what side of plane each vert is on + if (Plane->Type < PLANE_ANYX) + { + pDist = &VectorToSUB(Verts[0], Plane->Type); + + for (i=0; i< NumVerts ; i++) + { + + //VDist[i] = VectorToSUB(Verts[i], Plane->Type) - Plane->Dist; + VDist[i] = *pDist - Plane->Dist; + if (FlipTest) + VDist[i] = -VDist[i]; + + if (VDist[i] > ON_EPSILON) + VSides[i] = 0; + else if (VDist[i] < -ON_EPSILON) + VSides[i] = 1; + else + VSides[i] = 2; + + CountSides[VSides[i]]++; + + pDist += 3; + } + } + else + { + for (i=0; i< NumVerts; i++) + { + VDist[i] = geVec3d_DotProduct(&Verts[i], &Normal) - Dist; + if (VDist[i] > ON_EPSILON) + VSides[i] = 0; + else if (VDist[i] < -ON_EPSILON) + VSides[i] = 1; + else + VSides[i] = 2; + + CountSides[VSides[i]]++; + } + } + + if (!CountSides[0] && !CountSides[1]) + { + *Back = NULL; + *Front = InPoly; + return GE_TRUE; + } + + // Get out quick, if no splitting is neccesary + if (!CountSides[0]) + { + *Front = NULL; + *Back = InPoly; + return GE_TRUE; + } + if (!CountSides[1]) + { + *Back = NULL; + *Front = InPoly; + return GE_TRUE; + } + + // Else we have to split this sucker + for (i=0; i< NumVerts; i++) + { + Vert1 = Verts[i]; + + if (VSides[i] == 2) // On plane, put on both sides + { + *pFrontVert++ = Vert1; + *pBackVert++ = Vert1; + continue; + } + + if (VSides[i] == 0) // Front side, put on front list + *pFrontVert++ = Vert1; + else if (VSides[i] == 1) // Back side, put on back list + *pBackVert++ = Vert1; + + + NextVert = (i+1) % NumVerts; + + if (VSides[NextVert] == 2 || VSides[NextVert] == VSides[i]) + continue; + + Vert2 = Verts[NextVert]; + Scale = VDist[i] / (VDist[i] - VDist[NextVert]); + + pFrontVert->X = Vert1.X + (Vert2.X - Vert1.X) * Scale; + pFrontVert->Y = Vert1.Y + (Vert2.Y - Vert1.Y) * Scale; + pFrontVert->Z = Vert1.Z + (Vert2.Z - Vert1.Z) * Scale; + + *pBackVert = *pFrontVert; + pFrontVert++; + pBackVert++; + } + + FreePoly(InPoly); // Don't need this anymore + + NewNumVerts = pFrontVert - TempVerts; + + if (NewNumVerts < 3) + *Front = NULL; + else + { + NewPoly = AllocPoly(NewNumVerts); + + if (!NewPoly) + { + GHook.Error("SplitPoly: Not enough mem for new poly.\n"); + return GE_FALSE; + } + + for (i = 0; i< NewNumVerts; i++) + NewPoly->Verts[i] = TempVerts[i]; + + *Front = NewPoly; + } + + NewNumVerts = pBackVert - TempVerts2; + + if (NewNumVerts < 3) + *Back = NULL; + else + { + NewPoly = AllocPoly(NewNumVerts); + + if (!NewPoly) + { + GHook.Error("SplitPoly: Not enough mem for new poly.\n"); + return GE_FALSE; + } + + for (i = 0; i< NewNumVerts; i++) + NewPoly->Verts[i] = TempVerts2[i]; + + *Back = NewPoly; + } + + return GE_TRUE; +} + +//==================================================================================== +// SplitPoly +//==================================================================================== +geBoolean SplitPolyEpsilon(GBSP_Poly *InPoly, geFloat Epsilon, GBSP_Plane *Plane, GBSP_Poly **Front, GBSP_Poly **Back, + geBoolean FlipTest) +{ + GBSP_Poly *NewPoly = NULL; + geVec3d *pInVert, Vert1, Vert2; + geVec3d *pFrontVert, *pBackVert, *Verts; + int32 i, NextVert, NewNumVerts = 0; + geFloat Scale; + + geVec3d Normal = Plane->Normal; + geFloat Dist = Plane->Dist, *pDist; + int32 NumVerts = InPoly->NumVerts; + int32 VSides[100]; + geFloat VDist[100]; + int32 CountSides[3]; + + if (NumVerts >= 100) + { + GHook.Error("SplitPoly: Too many verts.\n"); + return GE_FALSE; + } + + memset(CountSides, 0, sizeof(CountSides)); + + Verts = InPoly->Verts; + pInVert = Verts; + pFrontVert = TempVerts; + pBackVert = TempVerts2; + + if (FlipTest) // Flip the normal and dist + { + Normal.X = -Normal.X; + Normal.Y = -Normal.Y; + Normal.Z = -Normal.Z; + Dist = -Dist; + } + + // See what side of plane each vert is on + if (Plane->Type < PLANE_ANYX) + { + pDist = &VectorToSUB(Verts[0], Plane->Type); + + for (i=0; i< NumVerts ; i++) + { + + //VDist[i] = VectorToSUB(Verts[i], Plane->Type) - Plane->Dist; + VDist[i] = *pDist - Plane->Dist; + if (FlipTest) + VDist[i] = -VDist[i]; + + if (VDist[i] > Epsilon) + VSides[i] = 0; + else if (VDist[i] < -Epsilon) + VSides[i] = 1; + else + VSides[i] = 2; + + CountSides[VSides[i]]++; + + pDist += 3; + } + } + else + { + for (i=0; i< NumVerts; i++) + { + VDist[i] = geVec3d_DotProduct(&Verts[i], &Normal) - Dist; + if (VDist[i] > Epsilon) + VSides[i] = 0; + else if (VDist[i] < -Epsilon) + VSides[i] = 1; + else + VSides[i] = 2; + + CountSides[VSides[i]]++; + } + } + + // Get out quick, if no splitting is neccesary + if (!CountSides[0]) + { + *Front = NULL; + *Back = InPoly; + return GE_TRUE; + } + if (!CountSides[1]) + { + *Back = NULL; + *Front = InPoly; + return GE_TRUE; + } + + // Else we have to split this sucker + for (i=0; i< NumVerts; i++) + { + Vert1 = Verts[i]; + + if (VSides[i] == 2) // On plane, put on both sides + { + *pFrontVert++ = Vert1; + *pBackVert++ = Vert1; + continue; + } + + if (VSides[i] == 0) // Front side, put on front list + *pFrontVert++ = Vert1; + else if (VSides[i] == 1) // Back side, put on back list + *pBackVert++ = Vert1; + + + NextVert = (i+1) % NumVerts; + + if (VSides[NextVert] == 2 || VSides[NextVert] == VSides[i]) + continue; + + Vert2 = Verts[NextVert]; + Scale = VDist[i] / (VDist[i] - VDist[NextVert]); + + pFrontVert->X = Vert1.X + (Vert2.X - Vert1.X) * Scale; + pFrontVert->Y = Vert1.Y + (Vert2.Y - Vert1.Y) * Scale; + pFrontVert->Z = Vert1.Z + (Vert2.Z - Vert1.Z) * Scale; + + *pBackVert = *pFrontVert; + pFrontVert++; + pBackVert++; + } + + FreePoly(InPoly); // Don't need this anymore + + NewNumVerts = pFrontVert - TempVerts; + + if (NewNumVerts < 3) + *Front = NULL; + else + { + NewPoly = AllocPoly(NewNumVerts); + + if (!NewPoly) + { + GHook.Error("SplitPoly: Not enough mem for new poly.\n"); + return GE_FALSE; + } + + for (i = 0; i< NewNumVerts; i++) + NewPoly->Verts[i] = TempVerts[i]; + + *Front = NewPoly; + } + + NewNumVerts = pBackVert - TempVerts2; + + if (NewNumVerts < 3) + *Back = NULL; + else + { + NewPoly = AllocPoly(NewNumVerts); + + if (!NewPoly) + { + GHook.Error("SplitPoly: Not enough mem for new poly.\n"); + return GE_FALSE; + } + + for (i = 0; i< NewNumVerts; i++) + NewPoly->Verts[i] = TempVerts2[i]; + + *Back = NewPoly; + } + + return GE_TRUE; +} + +//==================================================================================== +// RemoveDegenerateEdges +//==================================================================================== +void RemoveDegenerateEdges(GBSP_Poly *Poly) +{ + int32 i, NumVerts; + geVec3d *Verts, V1, V2, NVerts[1000], Vec; + geBoolean Bad = GE_FALSE; + int32 NumNVerts = 0; + + Verts = Poly->Verts; + NumVerts = Poly->NumVerts; + + for (i=0; i< NumVerts; i++) + { + V1 = Verts[i]; + V2 = Verts[(i+1)%NumVerts]; + + geVec3d_Subtract(&V1, &V2, &Vec); + + if (geVec3d_Length(&Vec) > DEGENERATE_EPSILON) + { + NVerts[NumNVerts++] = V1; + } + else + Bad = GE_TRUE; + } + + if (Bad) + { + //Hook.Printf("Removing degenerate edge...\n"); + + Poly->NumVerts = NumNVerts; + for (i=0; i< NumNVerts; i++) + { + Verts[i] = NVerts[i]; + } + } +} + +//==================================================================================== +// RemoveDegenerateEdges2 +//==================================================================================== +geBoolean RemoveDegenerateEdges2(GBSP_Poly *Poly) +{ + int32 i, NumVerts; + geVec3d *Verts, V1, V2, NVerts[1000], Vec; + geBoolean Bad = GE_FALSE; + int32 NumNVerts = 0; + + Verts = Poly->Verts; + NumVerts = Poly->NumVerts; + + for (i=0; i< NumVerts; i++) + { + V1 = Verts[i]; + V2 = Verts[(i+1)%NumVerts]; + + geVec3d_Subtract(&V1, &V2, &Vec); + + if (geVec3d_Length(&Vec) > DEGENERATE_EPSILON) + { + NVerts[NumNVerts++] = V1; + } + else + Bad = GE_TRUE; + } + + if (NumNVerts < 3) + return GE_FALSE; + + if (Bad) + { + Poly->NumVerts = NumNVerts; + for (i=0; i< NumNVerts; i++) + { + Verts[i] = NVerts[i]; + } + } + + return GE_TRUE; +} + +//==================================================================================== +// PolyArea +//==================================================================================== +geFloat PolyArea(GBSP_Poly *Poly) +{ + int32 i; + geVec3d Vect1, Vect2, Cross; + geFloat Total; + + Total = 0.0f; + + for (i=2 ; iNumVerts ; i++) + { + geVec3d_Subtract(&Poly->Verts[i-1], &Poly->Verts[0], &Vect1); + geVec3d_Subtract(&Poly->Verts[i] , &Poly->Verts[0], &Vect2); + geVec3d_CrossProduct (&Vect1, &Vect2, &Cross); + Total += (geFloat)0.5 * geVec3d_Length(&Cross); + } + + return (geFloat)Total; +} + +#define BOGUS_VERTS 256 +//==================================================================================== +// CopyPoly +//==================================================================================== +geBoolean CopyPoly(GBSP_Poly *In, GBSP_Poly **Out) +{ + GBSP_Poly *NewPoly; + int32 i; + + if (!In) + { + GHook.Error("CopyPoly: NULL Poly!!!\n"); + return GE_FALSE; + } + + if (In->NumVerts <= 0 || In->NumVerts >= BOGUS_VERTS) + { + GHook.Error("CopyPoly: Bogus number of verts: %i\n", In->NumVerts); + return GE_FALSE; + } + + NewPoly = AllocPoly(In->NumVerts); + if (!NewPoly) + { + return GE_FALSE; + } + + for (i=0; iNumVerts; i++) + NewPoly->Verts[i] = In->Verts[i]; + + *Out = NewPoly; + + return GE_TRUE; +} + +//==================================================================================== +// CopyPoly2 +//==================================================================================== +GBSP_Poly *CopyPoly2(GBSP_Poly *In) +{ + GBSP_Poly *NewPoly; + int32 i; + + if (!In) + { + GHook.Error("CopyPoly: NULL Poly!!!\n"); + return NULL; + } + + if (In->NumVerts <= 0 || In->NumVerts >= BOGUS_VERTS) + { + GHook.Error("CopyPoly: Bogus number of verts: %i\n", In->NumVerts); + return NULL; + } + + NewPoly = AllocPoly(In->NumVerts); + + if (!NewPoly) + return NULL; + + for (i=0; iNumVerts; i++) + NewPoly->Verts[i] = In->Verts[i]; + + return NewPoly; +} + +//==================================================================================== +// ReversePoly +//==================================================================================== +geBoolean ReversePoly(GBSP_Poly *In, GBSP_Poly **Out) +{ + GBSP_Poly *NewPoly; + int32 i; + + NewPoly = AllocPoly(In->NumVerts); + if (!NewPoly) + { + return GE_FALSE; + } + + for (i=0; iNumVerts; i++) + NewPoly->Verts[i] = In->Verts[In->NumVerts-i-1]; + + *Out = NewPoly; + + return GE_TRUE; +} + +//==================================================================================== +// PolyCenter +//==================================================================================== +void PolyCenter(GBSP_Poly *Poly, geVec3d *Center) +{ + int32 i; + + geVec3d_Clear(Center); + + for (i=0; i< Poly->NumVerts; i++) + geVec3d_Add(Center, &Poly->Verts[i], Center); + + geVec3d_Scale(Center, (geFloat)1.0/(geFloat)Poly->NumVerts, Center); +} + +#define EDGE_LENGTH (geFloat)0.1 + +//==================================================================================== +// PolyIsTiny +//==================================================================================== +geBoolean PolyIsTiny (GBSP_Poly *Poly) +{ + int32 i, j; + geFloat Len; + geVec3d Delta; + int32 Edges; + + Edges = 0; + + //return GE_FALSE; + + for (i=0 ; iNumVerts ; i++) + { + j = i == Poly->NumVerts - 1 ? 0 : i+1; + + geVec3d_Subtract(&Poly->Verts[j], &Poly->Verts[i], &Delta); + + Len = geVec3d_Length(&Delta); + + if (Len > EDGE_LENGTH) + { + if (++Edges == 3) + return GE_FALSE; + } + } + + //GHook.Printf("Poly is tiny...\n"); + + return GE_TRUE; +} + +// +// Faces +// + +//==================================================================================== +// AllocFace +//==================================================================================== +GBSP_Face *AllocFace(int32 NumVerts) +{ + GBSP_Face *Face; + + Face = GE_RAM_ALLOCATE_STRUCT(GBSP_Face); + + if (!Face) + return NULL; + + memset(Face, 0, sizeof(GBSP_Face)); + + if (NumVerts) + { + Face->Poly = AllocPoly(NumVerts); + if (!Face->Poly) + { + FreeFace(Face); + return NULL; + } + } + else + Face->Poly = NULL; + + return Face; +} + +//==================================================================================== +// FreeFace +//==================================================================================== +void FreeFace(GBSP_Face *Face) +{ + if (!Face) + { + GHook.Printf("*WARNING* FreeFace: NULL Face.\n"); + return; + } + + //if (!Face->Poly) + // Hook.Error("FreeFace: NULL Poly.\n"); + if (Face->Poly) + FreePoly(Face->Poly); + Face->Poly = NULL; + + if (Face->IndexVerts) + geRam_Free(Face->IndexVerts); + Face->IndexVerts = NULL; + + geRam_Free(Face); +} + +//==================================================================================== +// void SplitFace +//==================================================================================== +geBoolean SplitFace(GBSP_Face *In, GBSP_Plane *Split, GBSP_Face **Front, GBSP_Face **Back, geBoolean FlipTest) +{ + GBSP_Poly *F, *B; + GBSP_Face *NewFace; + + if (!SplitPoly(In->Poly, Split, &F, &B, FlipTest)) + return GE_FALSE; + + if (!F && !B) + { + GHook.Error("SplitFace: Poly was clipped away.\n"); + return GE_FALSE; + } + + if (!F) + { + In->Poly = B; + *Back = In; + *Front = NULL; + return GE_TRUE; + } + if (!B) + { + In->Poly = F; + *Front = In; + *Back = NULL; + return GE_TRUE; + } + + NewFace = GE_RAM_ALLOCATE_STRUCT(GBSP_Face); + if (!NewFace) + { + GHook.Error("SplitFace: Out of memory for new face.\n"); + return GE_FALSE; + } + + *NewFace = *In; + + In->Poly = F; + NewFace->Poly = B; + + *Front = In; + *Back = NewFace; + + return GE_TRUE; +} + +//==================================================================================== +// CopyFace +//==================================================================================== +geBoolean CopyFace(GBSP_Face *In, GBSP_Face **Out) +{ + GBSP_Face *NewFace; + GBSP_Poly *NewPoly; + int32 i; + + NewFace = AllocFace(0); + + if (!NewFace) + { + GHook.Error("CopyFaceList: Out of memory for new face.\n"); + return GE_FALSE; + } + + *NewFace = *In; + NewPoly = AllocPoly(In->Poly->NumVerts); + + if (!NewPoly) + { + GHook.Error("CopyFaceList: Out of memory for newpoly.\n"); + return GE_FALSE; + } + + NewFace->Poly = NewPoly; + + for (i=0; i< In->Poly->NumVerts; i++) + NewFace->Poly->Verts[i] = In->Poly->Verts[i]; + + return GE_TRUE; +} + +//==================================================================================== +// MergeFaceList2 +//==================================================================================== +geBoolean MergeFaceList2(GBSP_Face *Faces) +{ + GBSP_Face *Face1, *Face2, *End, *Merged; + + for (Face1 = Faces ; Face1 ; Face1 = Face1->Next) + { + if (Face1->Poly->NumVerts == -1) + continue; + + if (Face1->Merged || Face1->Split[0] || Face1->Split[1]) + continue; + + for (Face2 = Faces ; Face2 != Face1 ; Face2 = Face2->Next) + { + if (Face2->Poly->NumVerts == -1) + continue; + + if (Face2->Merged || Face2->Split[0] || Face2->Split[1]) + continue; + + Merged = MergeFace(Face1, Face2); + + if (!Merged) + continue; + + RemoveDegenerateEdges(Merged->Poly); + + if (!CheckFace(Merged, GE_FALSE)) + { + FreeFace(Merged); + Face1->Merged = NULL; + Face2->Merged = NULL; + continue; + } + + NumMerged++; + + // Add the Merged to the end of the face list + // so it will be checked against all the faces again + for (End = Faces ; End->Next ; End = End->Next); + + Merged->Next = NULL; + End->Next = Merged; + break; + } + } + + return GE_TRUE; +} + +//==================================================================================== +// FreeFaceList +//==================================================================================== +void FreeFaceList(GBSP_Face *List) +{ + GBSP_Face *Next; + + while(List) + { + Next = List->Next; + FreeFace(List); + List = Next; + } +} + +//==================================================================================== +// EdgeExist +//==================================================================================== +int32 EdgeExist(geVec3d *Edge1, GBSP_Poly *Poly, int32 *EdgeIndexOut) +{ + int32 i; + geVec3d Edge2[2], *Verts; + int32 NumVerts; + + Verts = Poly->Verts; + NumVerts = Poly->NumVerts; + + for (i=0; i< NumVerts; i++) + { + Edge2[0] = Verts[i]; + Edge2[1] = Verts[(i+1)%NumVerts]; + + if (geVec3d_Compare(Edge1, Edge2, VCOMPARE_EPSILON)) + if (geVec3d_Compare(Edge1+1, Edge2+1, VCOMPARE_EPSILON)) + { + EdgeIndexOut[0] = i; + EdgeIndexOut[1] = (i+1)%NumVerts; + return GE_TRUE; + } + } + + return GE_FALSE; +} + +#define COLINEAR_EPSILON 0.0001f + +//==================================================================================== +// MergeFace +//==================================================================================== +GBSP_Face *MergeFace(GBSP_Face *Face1, GBSP_Face *Face2) +{ + geVec3d Edge1[2], *Verts1, *Verts2; + int32 i, k, NumVerts, NumVerts2, EdgeIndex[2], NumNewVerts; + GBSP_Poly *NewPoly = NULL, *Poly1, *Poly2; + geVec3d Normal1, Normal2, Vec1, Vec2; + GBSP_Face *NewFace = NULL; + geFloat Dot; + //int32 Start, End; + geBoolean Keep1 = GE_TRUE, Keep2 = GE_TRUE; + + // + // Planes and Sides MUST match before even trying to merge + // + if (Face1->PlaneNum != Face2->PlaneNum) + return NULL; + if (Face1->PlaneSide != Face2->PlaneSide) + return NULL; + +#if 1 + if ((Face1->Contents[0]&BSP_MERGE_SEP_CONTENTS) != (Face2->Contents[0]&BSP_MERGE_SEP_CONTENTS)) + return NULL; + if ((Face1->Contents[1]&BSP_MERGE_SEP_CONTENTS) != (Face2->Contents[1]&BSP_MERGE_SEP_CONTENTS)) + return NULL; +#endif + + if (Face1->TexInfo != Face2->TexInfo) + return NULL; + + Poly1 = Face1->Poly; + Poly2 = Face2->Poly; + + if (Poly1->NumVerts == -1 || Poly2->NumVerts == -1) + return NULL; + + Verts1 = Poly1->Verts; + NumVerts = Poly1->NumVerts; + + // + // Go through each edge of Poly1, and see if the reverse of it exist in Poly2 + // + for (i=0; i< NumVerts; i++) + { + Edge1[1] = Verts1[i]; + Edge1[0] = Verts1[(i+1)%NumVerts]; + + if (EdgeExist(Edge1, Poly2, EdgeIndex)) // Found one, break out + break; + } + + if (i >= NumVerts) // Did'nt find an edge, return nothing + return NULL; + + Verts2 = Poly2->Verts; + NumVerts2 = Poly2->NumVerts; + + // + // See if the 2 joined make a convex poly, connect them, and return new one + // + Normal1 = Planes[Face1->PlaneNum].Normal; // Get the normal + if (Face1->PlaneSide) + geVec3d_Subtract(&VecOrigin, &Normal1, &Normal1); + + Vec1 = Verts1[(i+NumVerts-1)%NumVerts]; // Get the normal of the edge just behind edge1 + geVec3d_Subtract(&Vec1, Edge1+1, &Vec1); + geVec3d_CrossProduct(&Normal1, &Vec1, &Normal2); + geVec3d_Normalize(&Normal2); + geVec3d_Subtract(&Verts2[(EdgeIndex[1]+1)%NumVerts2], &Verts2[EdgeIndex[1]], &Vec2); + Dot = geVec3d_DotProduct(&Vec2, &Normal2); + if (Dot > COLINEAR_EPSILON) + return NULL; // Edge makes a non-convex poly + if (Dot >=-COLINEAR_EPSILON) // Drop point, on colinear edge + Keep1 = GE_FALSE; + + Vec1 = Verts1[(i+2)%NumVerts]; // Get the normal of the edge just behind edge1 + geVec3d_Subtract(&Vec1, Edge1, &Vec1); + geVec3d_CrossProduct(&Normal1, &Vec1, &Normal2); + geVec3d_Normalize(&Normal2); + geVec3d_Subtract(&Verts2[(EdgeIndex[0]+NumVerts2-1)%NumVerts2], &Verts2[EdgeIndex[0]], &Vec2); + Dot = geVec3d_DotProduct(&Vec2, &Normal2); + if (Dot > COLINEAR_EPSILON) + return NULL; // Edge makes a non-convex poly + if (Dot >=-COLINEAR_EPSILON) // Drop point, on colinear edge + Keep2 = GE_FALSE; + + //if (NumVerts+NumVerts2 > 30) + // return NULL; + + NewFace = AllocFace(NumVerts+NumVerts2); + NewPoly = NewFace->Poly; + if (!NewFace) + { + GHook.Error("*WARNING* MergeFace: Out of memory for new face!\n"); + return NULL; + } + + // + // Make a new poly, free the old ones... + // + NumNewVerts = 0; + + for (k = (i+1)%NumVerts; k != i ; k = (k+1)%NumVerts) + { + if (k == (i+1)%NumVerts && ! Keep2) + continue; + NewPoly->Verts[NumNewVerts++] = Verts1[k]; + } + + i = EdgeIndex[0]; + + for (k = (i+1)%NumVerts2; k != i ; k = (k+1)%NumVerts2) + { + if (k == (i+1)%NumVerts2 && ! Keep1) + continue; + NewPoly->Verts[NumNewVerts++] = Verts2[k]; + } + + *NewFace = *Face2; + + NewPoly->NumVerts = NumNewVerts; + NewFace->Poly = NewPoly; + + //Hook.Printf("Merged face: %i\n", NumNewVerts); + + Face1->Merged = NewFace; + Face2->Merged = NewFace; + + return NewFace; +} + +//==================================================================================== +// NewFaceFromFace +//==================================================================================== +GBSP_Face *NewFaceFromFace (GBSP_Face *f) +{ + GBSP_Face *Newf; + + Newf = AllocFace (0); + *Newf = *f; + //Newf->merged = NULL; + Newf->Split[0] = Newf->Split[1] = NULL; + Newf->Poly = NULL; + + return Newf; +} + +//==================================================================================== +// FanFace_r +//==================================================================================== +void FanFace_r(GBSP_Node *Node, GBSP_Face *Face) +{ + GBSP_Poly *Poly, *NewPoly; + geVec3d *pVert; + int32 i; + + Poly = Face->Poly; + + if (Poly->NumVerts == 3) // Don't need to fan... + return; + + // Split this poly at the firsdt fan point into 2 more polys, and fan those... + NewPoly = AllocPoly(3); + + NewPoly->Verts[0] = Poly->Verts[0]; + NewPoly->Verts[1] = Poly->Verts[1]; + NewPoly->Verts[2] = Poly->Verts[2]; + + Face->Split[0] = NewFaceFromFace(Face); + Face->Split[0]->Poly = NewPoly; + Face->Split[0]->Next = Node->Faces; + Node->Faces = Face->Split[0]; + + // Now make the rest of the polys + NewPoly = AllocPoly(Poly->NumVerts-1); + + pVert = NewPoly->Verts; + + for (i=0; iNumVerts; i++) + { + if (i==1) + continue; + + *pVert++ = Poly->Verts[i]; + } + + Face->Split[1] = NewFaceFromFace(Face); + Face->Split[1]->Poly = NewPoly; + Face->Split[1]->Next = Node->Faces; + Node->Faces = Face->Split[1]; + + FanFace_r(Node, Face->Split[1]); +} + +//==================================================================================== +// GetLog +//==================================================================================== +uint32 GetLog(uint32 P2) +{ + U32 p = 0; + S32 i = 0; + + if (!P2) + { + GHook.Printf("*WARNING* GetLog: Bad input.\n"); + return 0; + } + + for (i = P2; i > 0; i>>=1) + p++; + + return (p-1); +} + + +//==================================================================================== +// Snaps a number to a power of 2 +//==================================================================================== +int32 SnapToPower2(int32 Width) +{ + int RetWidth; + + for ( RetWidth = 1; RetWidth < Width; RetWidth <<= 1 ) ; + + //assert( RetWidth <= 256 ); + + return RetWidth; +} + +//==================================================================================== +// SubdivideFace +//==================================================================================== +void SubdivideFace(GBSP_Node *Node, GBSP_Face *Face) +{ + geFloat Mins, Maxs; + geFloat v; + int32 Axis, i; + GFX_TexInfo *Tex; + geVec3d Temp; + geFloat Dist; + GBSP_Poly *p, *Frontp, *Backp; + GBSP_Plane Plane; + + if (Face->Merged) + return; + + // Special (non-surface cached) faces don't need subdivision + Tex = &TexInfo[Face->TexInfo]; + + //if ( Tex->Flags & TEXINFO_GOURAUD) + // FanFace_r(Node, Face); + + if ( Tex->Flags & TEXINFO_NO_LIGHTMAP) + return; + + for (Axis = 0 ; Axis < 2 ; Axis++) + { + while (1) + { + geFloat TexSize, SplitDist; + geFloat Mins16, Maxs16; + + Mins = 999999.0f; + Maxs = -999999.0f; + + geVec3d_Copy(&Tex->Vecs[Axis], &Temp); + + for (i=0 ; iPoly->NumVerts ; i++) + { + v = geVec3d_DotProduct (&Face->Poly->Verts[i], &Temp); + if (v < Mins) + Mins = v; + if (v > Maxs) + Maxs = v; + } + + Mins16 = (geFloat)floor(Mins/16.0f)*16.0f; + Maxs16 = (geFloat)ceil(Maxs/16.0f)*16.0f; + + TexSize = Maxs - Mins; + //TexSize = Maxs16 - Mins16; + + // Default to the Subdivide size + SplitDist = SubdivideSize; + + #if 0 + if (TexSize <= SubdivideSize) + { + int32 Log, LogSize; + geFloat Ratio; + + LogSize = SnapToPower2((int32)TexSize); + Log = GetLog(LogSize); + + if (LogSize <= 16) + break; // Don't bother with small lmaps + + Ratio = TexSize / (geFloat)LogSize; // Get the percentage of the space being taken advantage of if it were to be snapped to power of 2 texture in drivers + + if (Ratio >= 0.75f) + break; // No need to split, if going to use at least 50% of the space + + // The lmap is not going to use a big enough percentage of the size it's currently going to be snapped to + // So, cut it along the next size down... + Log--; // Split along next log down + + // Overide the subdivide size with the next size down + SplitDist = (geFloat)(1<Poly, &p); + + // Split it + NumSubdivided++; + + v = geVec3d_Normalize (&Temp); + + Dist = (Mins + SplitDist - 16)/v; + //Dist = (Mins16 + SplitDist)/v; + + Plane.Normal = Temp; + Plane.Dist = Dist; + Plane.Type = PLANE_ANY; + + SplitPoly(p, &Plane, &Frontp, &Backp, GE_FALSE); + + if (!Frontp || !Backp) + { + GHook.Printf("*WARNING* SubdivideFace: didn't split the polygon: %f, %f, %f\n", Mins, Maxs, SplitDist); + break; + } + + Face->Split[0] = NewFaceFromFace (Face); + Face->Split[0]->Poly = Frontp; + Face->Split[0]->Next = Node->Faces; + Node->Faces = Face->Split[0]; + + Face->Split[1] = NewFaceFromFace (Face); + Face->Split[1]->Poly = Backp; + Face->Split[1]->Next = Node->Faces; + Node->Faces = Face->Split[1]; + + SubdivideFace (Node, Face->Split[0]); + SubdivideFace (Node, Face->Split[1]); + return; + } + } +} + +//==================================================================================== +// SubdivideNodeFaces +//==================================================================================== +void SubdivideNodeFaces (GBSP_Node *Node) +{ + GBSP_Face *f; + + for (f = Node->Faces ; f ; f=f->Next) + { + SubdivideFace (Node, f); + } +} + +//==================================================================================== +// CheckFace +//==================================================================================== +geBoolean CheckFace(GBSP_Face *Face, geBoolean Verb) +{ + int32 i, j, NumVerts; + geVec3d Vect1, *Verts, Normal, V1, V2, EdgeNormal; + GBSP_Poly *Poly; + geFloat Dist, PDist, EdgeDist; + + Poly = Face->Poly; + Verts = Poly->Verts; + NumVerts = Poly->NumVerts; + + if (NumVerts < 3) + { + if (Verb) + GHook.Printf("CheckFace: NumVerts < 3.\n"); + return GE_FALSE; + } + + Normal = Planes[Face->PlaneNum].Normal; + PDist = Planes[Face->PlaneNum].Dist; + if (Face->PlaneSide) + { + geVec3d_Subtract(&VecOrigin, &Normal, &Normal); + PDist = -PDist; + } + + // + // Check for degenerate edges, convexity, and make sure it's planar + // + for (i=0; i< NumVerts; i++) + { + V1 = Verts[i]; + V2 = Verts[(i+1)%NumVerts]; + + // Check for degenreate edge + geVec3d_Subtract(&V2, &V1, &Vect1); + Dist = geVec3d_Length(&Vect1); + if (fabs(Dist) < DEGENERATE_EPSILON) + { + if (Verb) + GHook.Printf("WARNING CheckFace: Degenerate Edge.\n"); + return GE_FALSE; + } + + // Check for planar + Dist = geVec3d_DotProduct(&V1, &Normal) - PDist; + if (Dist > ON_EPSILON || Dist <-ON_EPSILON) + { + if (Verb) + GHook.Printf("WARNING CheckFace: Non planar: %f.\n", Dist); + return GE_FALSE; + } + + geVec3d_CrossProduct(&Normal, &Vect1, &EdgeNormal); + geVec3d_Normalize(&EdgeNormal); + EdgeDist = geVec3d_DotProduct(&V1, &EdgeNormal); + + // Check for convexity + for (j=0; j< NumVerts; j++) + { + Dist = geVec3d_DotProduct(&Verts[j], &EdgeNormal) - EdgeDist; + if (Dist > ON_EPSILON) + { + if (Verb) + GHook.Printf("CheckFace: Face not convex.\n"); + return GE_FALSE; + } + } + } + + return GE_TRUE; +} + +//==================================================================================== +// GetFaceListBOX +//==================================================================================== +void GetFaceListBOX(GBSP_Face *Faces, geVec3d *Mins, geVec3d *Maxs) +{ + GBSP_Face *Face; + GBSP_Poly *Poly; + geVec3d Vert; + int32 i; + + ClearBounds(Mins, Maxs); + + // Go through each face in this brush... + for (Face = Faces; Face; Face = Face->Next) + { + Poly = Face->Poly; + for (i=0; i< Poly->NumVerts; i++) + { + Vert = Poly->Verts[i]; + + // First get maxs + if (Vert.X > Maxs->X) + Maxs->X = Vert.X; + if (Vert.Y > Maxs->Y) + Maxs->Y = Vert.Y; + if (Vert.Z > Maxs->Z) + Maxs->Z = Vert.Z; + + // Then check mins + if (Vert.X < Mins->X) + Mins->X = Vert.X; + if (Vert.Y < Mins->Y) + Mins->Y = Vert.Y; + if (Vert.Z < Mins->Z) + Mins->Z = Vert.Z; + } + } +} + diff --git a/GBSPLib/POLY.H b/GBSPLib/POLY.H new file mode 100644 index 0000000..730d233 --- /dev/null +++ b/GBSPLib/POLY.H @@ -0,0 +1,72 @@ +/****************************************************************************************/ +/* Poly.h */ +/* */ +/* Author: John Pollard */ +/* Description: Various Poly routines (clipping, splitting, etc) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef POLY_H +#define POLY_H + +#include + +#include "BSP.h" +#include "MathLib.h" + +extern geBoolean gCountVerts; +extern int32 gTotalVerts; +extern int32 gPeekVerts; + +// +// Polys +// +GBSP_Poly *AllocPoly(int32 NumVerts); +void FreePoly(GBSP_Poly *Poly); +GBSP_Poly *CreatePolyFromPlane(GBSP_Plane *Plane); +geBoolean ClipPoly(GBSP_Poly *InPoly, GBSP_Plane *Plane, geBoolean FlipTest, GBSP_Poly **OutPoly); +geBoolean ClipPolyEpsilon(GBSP_Poly *InPoly, geFloat Epsilon, GBSP_Plane *Plane, geBoolean FlipTest, GBSP_Poly **OutPoly); +geBoolean SplitPoly(GBSP_Poly *InPoly, GBSP_Plane *Plane, GBSP_Poly **Front, GBSP_Poly **Back, + geBoolean FlipTest); +geBoolean SplitPolyEpsilon(GBSP_Poly *InPoly, geFloat Epsilon, GBSP_Plane *Plane, GBSP_Poly **Front, GBSP_Poly **Back, + geBoolean FlipTest); +geFloat PolyArea(GBSP_Poly *Poly); +geBoolean CopyPoly(GBSP_Poly *In, GBSP_Poly **Out); +GBSP_Poly *CopyPoly2(GBSP_Poly *In); +geBoolean ReversePoly(GBSP_Poly *In, GBSP_Poly **Out); +void RemoveDegenerateEdges(GBSP_Poly *Poly); +geBoolean RemoveDegenerateEdges2(GBSP_Poly *Poly); +void PolyCenter(GBSP_Poly *Poly, geVec3d *Center); +geBoolean PolyIsTiny (GBSP_Poly *Poly); + +// +// Faces +// + +GBSP_Face *AllocFace(int32 NumVerts); +void FreeFace(GBSP_Face *Face); +geBoolean SplitFace(GBSP_Face *In, GBSP_Plane *Split, GBSP_Face **Front, GBSP_Face **Back, geBoolean FlipTest); +void FreeFaceList(GBSP_Face *List); +int32 MergeFaceList(GBSP_Face *In, GBSP_Face **Out, geBoolean Mirror); +int32 EdgeExist(geVec3d *Edge1, GBSP_Poly *Poly, int32 *EdgeIndexOut); +GBSP_Face *MergeFace(GBSP_Face *Face1, GBSP_Face *Face2); +geBoolean CheckFace(GBSP_Face *Face, geBoolean Verb); +void GetFaceListBOX(GBSP_Face *Faces, geVec3d *Mins, geVec3d *Maxs); + +extern int32 NumSubdivides; +extern geFloat SubdivideSize; + +#endif diff --git a/GBSPLib/PORTALS.CPP b/GBSPLib/PORTALS.CPP new file mode 100644 index 0000000..1883ab1 --- /dev/null +++ b/GBSPLib/PORTALS.CPP @@ -0,0 +1,687 @@ +/****************************************************************************************/ +/* Portals.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Creates and manages portals (passages from leaf-to-leaf) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "Portals.h" +#include "Poly.h" +#include "Bsp.h" +#include "GBSPFile.h" +#include "Leaf.h" +#include "Utils.h" +#include "Map.h" + +#include "Ram.h" + +GBSP_Node *OutsideNode; +geVec3d NodeMins, NodeMaxs; +geBoolean VisPortals; + +geBoolean CreateAllOutsidePortals(GBSP_Node *Node); +void GetNodeMinsMaxs(GBSP_Node *Node); +geBoolean AddPortalToNodes(GBSP_Portal *Portal, GBSP_Node *Front, GBSP_Node *Back); +geBoolean RemovePortalFromNode(GBSP_Portal *Portal, GBSP_Node *Node); +GBSP_Portal *AllocPortal(void); + +//===================================================================================== +// CreatePolyOnNode +//===================================================================================== +geBoolean CreatePolyOnNode (GBSP_Node *Node, GBSP_Poly **Out) +{ + GBSP_Poly *Poly; + GBSP_Plane *Plane; + GBSP_Node *Parent; + + Poly = CreatePolyFromPlane(&Planes[Node->PlaneNum]); + + if (!Poly) + { + GHook.Error("CreatePolyOnNode: Could not create poly.\n"); + return GE_FALSE; + } + + // Clip this portal by all the parents of this node + for (Parent = Node->Parent ; Parent && Poly ; ) + { + geBoolean Side; + + Plane = &Planes[Parent->PlaneNum]; + + Side = (Parent->Children[0] == Node) ? GE_FALSE : GE_TRUE; + + if (!ClipPolyEpsilon(Poly, 0.001f, Plane, Side, &Poly)) + return GE_FALSE; + + Node = Parent; + Parent = Parent->Parent; + } + + *Out = Poly; + + return GE_TRUE; +} + +//===================================================================================== +// CreatePortals +//===================================================================================== +geBoolean CreatePortals(GBSP_Node *RootNode, GBSP_Model *Model, geBoolean Vis) +{ + if (Verbose) + GHook.Printf(" --- Create Portals --- \n"); + + VisPortals = Vis; + + OutsideNode = &Model->OutsideNode; + + NodeMins = Model->Mins; + NodeMaxs = Model->Maxs; + + if (!CreateAllOutsidePortals(RootNode)) + { + GHook.Error("CreatePortals: Could not create bbox portals.\n"); + return GE_FALSE; + } + + if (!PartitionPortals_r(RootNode)) + { + GHook.Error("CreatePortals: Could not partition portals.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//===================================================================================== +// CreateOutsidePortal +//===================================================================================== +GBSP_Portal *CreateOutsidePortal(GBSP_Plane *Plane, GBSP_Node *Node) +{ + GBSP_Portal *NewPortal; + int32 Side; + + NewPortal = AllocPortal(); + if (!NewPortal) + return NULL; + + NewPortal->Poly = CreatePolyFromPlane(Plane); + if (!NewPortal->Poly) + { + return NULL; + } + NewPortal->PlaneNum = FindPlane(Plane, &Side); + + if (NewPortal->PlaneNum == -1) + { + GHook.Error("CreateOutsidePortal: Could not create plane.\n"); + return NULL; + } + + if (!Side) + { + if (!AddPortalToNodes(NewPortal, Node, OutsideNode)) + return NULL; + } + else + { + if (!AddPortalToNodes(NewPortal, OutsideNode, Node)) + return NULL; + } + + return NewPortal; +} + +//===================================================================================== +// CreateAllOutsidePortals +//===================================================================================== +geBoolean CreateAllOutsidePortals(GBSP_Node *Node) +{ + int32 k, i, Index; + GBSP_Plane PPlanes[6]; + GBSP_Portal *Portals[6]; + + memset(OutsideNode, 0, sizeof(GBSP_Node)); + + memset(PPlanes, 0, 6*sizeof(GBSP_Plane)); + + OutsideNode->PlaneNum = PLANENUM_LEAF; + OutsideNode->Contents = BSP_CONTENTS_SOLID2; + OutsideNode->Portals = NULL; + OutsideNode->BrushList = NULL; + + // So there won't be NULL volume leafs when we create the outside portals + for (k=0; k< 3; k++) + { + if (VectorToSUB(NodeMins, k)-128 <= -MIN_MAX_BOUNDS || VectorToSUB(NodeMaxs, k)+128 >= MIN_MAX_BOUNDS) + { + GHook.Error("CreateAllOutsidePortals: World BOX out of range...\n"); + return GE_FALSE; + } + + VectorToSUB(NodeMins, k) -= (geFloat)128; + VectorToSUB(NodeMaxs, k) += (geFloat)128; + } + + // Create 6 portals, and point to the outside and the RootNode + for (i=0; i<3; i++) + { + for (k=0; k<2; k++) + { + Index = k*3 + i; + geVec3d_Clear(&PPlanes[Index].Normal); + + if (k == 0) + { + VectorToSUB(PPlanes[Index].Normal, i) = (geFloat)1; + PPlanes[Index].Dist = VectorToSUB(NodeMins, i); + } + else + { + VectorToSUB(PPlanes[Index].Normal, i) = (geFloat)-1; + PPlanes[Index].Dist = -VectorToSUB(NodeMaxs, i); + } + + Portals[Index] = CreateOutsidePortal(&PPlanes[Index], Node); + if (!Portals[Index]) + return GE_FALSE; + } + } + + for (i=0; i< 6; i++) + { + for (k=0; k< 6; k++) + { + if (k == i) + continue; + + if (!ClipPoly(Portals[i]->Poly, &PPlanes[k], GE_FALSE, &Portals[i]->Poly)) + { + GHook.Error("CreateAllOutsidePortals: There was an error clipping the portal.\n"); + return GE_FALSE; + } + + if (!Portals[i]->Poly) + { + GHook.Error("CreateAllOutsidePortals: Portal was clipped away.\n"); + return GE_FALSE; + } + } + } + + return GE_TRUE; +} + +//===================================================================================== +// CheckPortal +//===================================================================================== +geBoolean CheckPortal(GBSP_Portal *Portal) +{ + GBSP_Poly *Poly; + geVec3d *Verts; + int32 i, k; + geFloat Val; + + Poly = Portal->Poly; + Verts = Poly->Verts; + + if (Poly->NumVerts < 3) + { + GHook.Error("CheckPortal: NumVerts < 3.\n"); + return GE_FALSE; + } + + for (i=0; i< Poly->NumVerts; i++) + { + for (k=0; k<3; k++) + { + Val = VectorToSUB(Verts[i], k); + + if (Val == MIN_MAX_BOUNDS) + { + GHook.Error("CheckPortal: Portal was not clipped on all sides!!!\n"); + return GE_FALSE; + } + + if (Val == -MIN_MAX_BOUNDS) + { + GHook.Error("CheckPortal: Portal was not clipped on all sides!!!\n"); + return GE_FALSE; + } + } + } + + return GE_TRUE; +} + +//======================================================================================= +// CalcNodeBoundsFromPortals +// Calcs bounds for nodes, and leafs +//======================================================================================= +void CalcNodeBoundsFromPortals(GBSP_Node *Node) +{ + GBSP_Portal *p; + int32 s, i; + + ClearBounds(&Node->Mins, &Node->Maxs); + + for (p=Node->Portals; p; p = p->Next[s]) + { + s = (p->Nodes[1] == Node); + + for (i=0; iPoly->NumVerts; i++) + AddPointToBounds(&p->Poly->Verts[i], &Node->Mins, &Node->Maxs); + } +} + +//===================================================================================== +// PartitionPortals_r +//===================================================================================== +geBoolean PartitionPortals_r(GBSP_Node *Node) +{ + GBSP_Poly *NewPoly, *FPoly, *BPoly; + GBSP_Plane *pPlane, *pPlane2; + GBSP_Portal *Portal, *NewPortal, *Next; + GBSP_Node *Front, *Back, *OtherNode; + int32 Side; + + CalcNodeBoundsFromPortals(Node); + + if (Node->PlaneNum == PLANENUM_LEAF) + return GE_TRUE; + + if (VisPortals && Node->Detail) // We can stop at detail seperators for the vis tree + return GE_TRUE; + + //if (!InitializeNodePortal(Node)) + // return GE_FALSE; + //if (!DistributeNodePortalsToChildren(Node)) + // return GE_FALSE; + + Front = Node->Children[0]; + Back = Node->Children[1]; + + pPlane = &Planes[Node->PlaneNum]; + + // Create a new portal + if (!CreatePolyOnNode (Node, &NewPoly)) + { + GHook.Error("PartitionPortals_r: CreatePolyOnNode failed.\n"); + return GE_FALSE; + } + + // Clip it against all other portals attached to this node + for (Portal = Node->Portals; Portal && NewPoly; Portal = Portal->Next[Side]) + { + if (Portal->Nodes[0] == Node) + Side = 0; + else if (Portal->Nodes[1] == Node) + Side = 1; + else + { + GHook.Error("PartitionPortals_r: Portal does not look at either node.\n"); + return GE_FALSE; + } + + pPlane2 = &Planes[Portal->PlaneNum]; + + if (!ClipPolyEpsilon(NewPoly, 0.001f, pPlane2, Side, &NewPoly)) + { + GHook.Error("PartitionPortals_r: There was an error clipping the poly.\n"); + return GE_FALSE; + } + + if (!NewPoly) + { + GHook.Printf("PartitionPortals_r: Portal was cut away.\n"); + break; + } + } + + if (NewPoly && PolyIsTiny (NewPoly)) + { + FreePoly(NewPoly); + NewPoly = NULL; + } + + if (NewPoly) + { + NewPortal = AllocPortal(); + if (!NewPortal) + { + GHook.Error("PartitionPortals_r: Out of memory for portal.\n"); + return GE_FALSE; + } + NewPortal->Poly = NewPoly; + NewPortal->PlaneNum = Node->PlaneNum; + NewPortal->OnNode = Node; + + if (!CheckPortal(NewPortal)) + { + GHook.Error("PartiionPortals_r: Check Portal failed.\n"); + return GE_FALSE; + } + else + AddPortalToNodes(NewPortal, Front, Back); + + } + + // Partition all portals by this node + for (Portal = Node->Portals; Portal; Portal = Next) + { + if (Portal->Nodes[0] == Node) + Side = 0; + else if (Portal->Nodes[1] == Node) + Side = 1; + else + { + GHook.Error("PartitionPortals_r: Portal does not look at either node.\n"); + return GE_FALSE; + } + + Next = Portal->Next[Side]; + + // Remember the node on the back side + OtherNode = Portal->Nodes[!Side]; + RemovePortalFromNode(Portal, Portal->Nodes[0]); + RemovePortalFromNode(Portal, Portal->Nodes[1]); + + if (!SplitPolyEpsilon(Portal->Poly, 0.001f, pPlane, &FPoly, &BPoly, GE_FALSE)) + { + GHook.Error("PartitionPortals_r: Could not split portal.\n"); + return GE_FALSE; + } + + if (FPoly && PolyIsTiny(FPoly)) + { + FreePoly(FPoly); + FPoly = NULL; + } + + if (BPoly && PolyIsTiny(BPoly)) + { + FreePoly(BPoly); + BPoly = NULL; + } + + if (!FPoly && !BPoly) + continue; + + if (!FPoly) + { + Portal->Poly = BPoly; + if (Side) + AddPortalToNodes(Portal, OtherNode, Back); + else + AddPortalToNodes(Portal, Back, OtherNode); + continue; + } + + if (!BPoly) + { + Portal->Poly = FPoly; + if (Side) + AddPortalToNodes(Portal, OtherNode, Front); + else + AddPortalToNodes(Portal, Front, OtherNode); + continue; + } + + // Portal was split + NewPortal = AllocPortal(); + if (!NewPortal) + { + GHook.Error("PartitionPortals_r: Out of memory for portal.\n"); + return GE_FALSE; + } + Portal->Poly = FPoly; + *NewPortal = *Portal; + NewPortal->Poly = BPoly; + + if (Side) + { + AddPortalToNodes(Portal, OtherNode, Front); + AddPortalToNodes(NewPortal, OtherNode, Back); + } + else + { + AddPortalToNodes(Portal, Front, OtherNode); + AddPortalToNodes(NewPortal, Back, OtherNode); + } + } + + if (Node->Portals != NULL) + { + GHook.Printf("*WARNING* PartitionPortals_r: Portals still on node after distribution...\n"); + } + + if (!PartitionPortals_r(Front)) + return GE_FALSE; + + if (!PartitionPortals_r(Back)) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// AddPortalToNodes +//===================================================================================== +geBoolean AddPortalToNodes(GBSP_Portal *Portal, GBSP_Node *Front, GBSP_Node *Back) +{ + if (Portal->Nodes[0] || Portal->Nodes[1]) + { + GHook.Error("LinkPortal: Portal allready looks at one of the nodes.\n"); + return GE_FALSE; + } + + Portal->Nodes[0] = Front; + Portal->Next[0] = Front->Portals; + Front->Portals = Portal; + + Portal->Nodes[1] = Back; + Portal->Next[1] = Back->Portals; + Back->Portals = Portal; + + return GE_TRUE; +} + +//===================================================================================== +// RemovePortalFromNode +//===================================================================================== +geBoolean RemovePortalFromNode(GBSP_Portal *Portal, GBSP_Node *Node) +{ + GBSP_Portal *p, **p2; + int32 Side; + + assert(Node->Portals); // Better have some portals on this node + assert(!(Portal->Nodes[0] == Node && Portal->Nodes[1] == Node)); + assert(Portal->Nodes[0] == Node || Portal->Nodes[1] == Node); + + // Find the portal on this node + for (p2 = &Node->Portals, p = *p2; p; p2 = &p->Next[Side], p = *p2) + { + assert(!(p->Nodes[0] == Node && p->Nodes[1] == Node)); + assert(p->Nodes[0] == Node || p->Nodes[1] == Node); + + Side = (p->Nodes[1] == Node); // Get the side of the portal that this node is on + + if (p == Portal) + break; // Got it + } + + assert(p && p2 && *p2); + + Side = (Portal->Nodes[1] == Node); // Get the side of the portal that the node was on + + *p2 = Portal->Next[Side]; + Portal->Nodes[Side] = NULL; + + return GE_TRUE; +} + +//===================================================================================== +// AllocPortal +//===================================================================================== +GBSP_Portal *AllocPortal(void) +{ + GBSP_Portal *NewPortal; + + NewPortal = GE_RAM_ALLOCATE_STRUCT(GBSP_Portal); + + if (!NewPortal) + { + GHook.Error("AllocPortal: Out of memory!\n"); + return NULL; + } + + memset(NewPortal, 0, sizeof(GBSP_Portal)); + + return NewPortal; +} + +//===================================================================================== +// FreePortal +//===================================================================================== +geBoolean FreePortal(GBSP_Portal *Portal) +{ + if (!Portal->Poly) + { + GHook.Error("FreePortal: Portal with NULL Poly.\n"); + return GE_FALSE; + } + + FreePoly(Portal->Poly); + + geRam_Free(Portal); + + return GE_TRUE; +} + +//===================================================================================== +// FreePOrtals_r +//===================================================================================== +geBoolean FreePortals_r(GBSP_Node *Node) +{ + GBSP_Portal *Portal, *Next; + int32 Side; + + if (!Node) + return GE_TRUE; + + for (Portal = Node->Portals; Portal; Portal = Next) + { + if (Portal->Nodes[0] == Node) + Side = 0; + else if (Portal->Nodes[1] == Node) + Side = 1; + else + { + GHook.Error("FreePortals_r: Portal does not look at either node.\n"); + return GE_FALSE; + } + + Next = Portal->Next[Side]; + + if (!RemovePortalFromNode(Portal, Portal->Nodes[0])) + return GE_FALSE; + + if (!RemovePortalFromNode(Portal, Portal->Nodes[1])) + return GE_FALSE; + + if (!FreePortal(Portal)) + return GE_FALSE; + } + + Node->Portals = NULL; + + if (Node->PlaneNum == PLANENUM_LEAF) + return GE_TRUE; + + if (!FreePortals_r(Node->Children[0])) + return GE_FALSE; + + if (!FreePortals_r(Node->Children[1])) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// FreePortals +//===================================================================================== +geBoolean FreePortals(GBSP_Node *RootNode) +{ + return(FreePortals_r(RootNode)); +} + +void AddPointToBounds(geVec3d *v, geVec3d *Mins, geVec3d *Maxs); + +//===================================================================================== +// GetNodeMinsMaxs +//===================================================================================== +void GetNodeMinsMaxs(GBSP_Node *Node) +{ + ClearBounds(&NodeMins, &NodeMaxs); + + NodeMins = Node->Mins; + NodeMaxs = Node->Maxs; +} + +//==================================================================================== +// GetLeafBBoxFromPortals +//==================================================================================== +geBoolean GetLeafBBoxFromPortals(GBSP_Node *Node, geVec3d *Mins, geVec3d *Maxs) +{ + GBSP_Poly *Poly; + geVec3d *Verts; + GBSP_Portal *Portal; + int32 i, k, Side; + + if (Node->PlaneNum != PLANENUM_LEAF) + { + GHook.Error("GetLeafBBoxFromPortals: Not a leaf.\n"); + return GE_FALSE; + } + + ClearBounds(Mins, Maxs); + + for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) + { + Side = (Portal->Nodes[1] == Node); + + Poly = Portal->Poly; + + Verts = Poly->Verts; + for (i=0; i< Poly->NumVerts; i++) + { + for (k=0; k<3; k++) + { + if (VectorToSUB(Verts[i], k) < VectorToSUB(*Mins, k)) + VectorToSUB(*Mins, k) = VectorToSUB(Verts[i], k); + if (VectorToSUB(Verts[i], k) > VectorToSUB(*Maxs, k)) + VectorToSUB(*Maxs, k) = VectorToSUB(Verts[i], k); + } + } + } + + return GE_TRUE; +} diff --git a/GBSPLib/PORTALS.H b/GBSPLib/PORTALS.H new file mode 100644 index 0000000..f9f00f1 --- /dev/null +++ b/GBSPLib/PORTALS.H @@ -0,0 +1,41 @@ +/****************************************************************************************/ +/* Portals.h */ +/* */ +/* Author: John Pollard */ +/* Description: Creates and manages portals (passages from leaf-to-leaf) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef PORTALS_H +#define PORTALS_H + +#include + +#include "BSP.h" + +extern GBSP_Node *OutsideNode; // Current outside node being used + +geBoolean CreatePortals(GBSP_Node *RootNode, GBSP_Model *Model, geBoolean Vis); +geBoolean FreePortals(GBSP_Node *RootNode); + +geBoolean GetLeafBBoxFromPortals(GBSP_Node *Node, geVec3d *Mins, geVec3d *Maxs); + +geBoolean PartitionPortals_r(GBSP_Node *Node); + +// This function actually lives in PortFile.cpp +geBoolean SavePortalFile(GBSP_Model *Model, char *FileName); + +#endif diff --git a/GBSPLib/PortFile.cpp b/GBSPLib/PortFile.cpp new file mode 100644 index 0000000..3d09f04 --- /dev/null +++ b/GBSPLib/PortFile.cpp @@ -0,0 +1,410 @@ +/****************************************************************************************/ +/* PortFile.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Saves BSP portals to disk. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "Bsp.h" +#include "Portals.h" +#include "Leaf.h" +#include "GBspFile.h" +#include "Poly.h" +#include "Utils.h" + +int32 NumPortals; +int32 NumPortalLeafs; + +//==================================================================================== +// ContentsPassable +//==================================================================================== +geBoolean ContentsPassable(uint32 Contents) +{ + //return (Contents & BSP_CONTENTS_PASSABLE); + return !(Contents & BSP_CONTENTS_SOLID2); +} + +//==================================================================================== +// ContentsSolid +//==================================================================================== +geBoolean ContentsSolid(uint32 Contents) +{ + /* + Contents &= (BSP_CONTENTS_PASSABLE | BSP_CONTENTS_VISIBLE | BSP_CONTENTS_TRANSLUCENT); + // If it's only visible, then it "bites" other brushes/contents + if (Contents == BSP_CONTENTS_VISIBLE) + return GE_TRUE; + return GE_FALSE; + */ + return (Contents & BSP_CONTENTS_SOLID2); +} + +//==================================================================================== +// MajorVisibleContents +//==================================================================================== +uint32 MajorVisibleContents(uint32 Contents) +{ + /* + Contents &= (BSP_CONTENTS_PASSABLE | BSP_CONTENTS_VISIBLE | BSP_CONTENTS_TRANSLUCENT); + + if (Contents == BSP_CONTENTS_VISIBLE) + return Contents; + + if (Contents == (BSP_CONTENTS_PASSABLE | BSP_CONTENTS_VISIBLE) + return Contents; + + if (Contents == (BSP_CONTENTS_TRANSLUCENT | BSP_CONTENTS_VISIBLE)) + return Contents; + + if (Contents) + return Contents; + return 0; + */ + int32 j; + uint32 MajorContents; + + if (!Contents) + return 0; + + // Only check visible contents + Contents &= BSP_VISIBLE_CONTENTS; + + // Return the strongest one, return the first lsb + for (j=0; j<32; j++) + { + MajorContents = (Contents & (1<PlaneNum == PLANENUM_LEAF) + return Node->Contents; + + c1 = ClusterContents(Node->Children[0]); + c2 = ClusterContents(Node->Children[1]); + + Contents = (c1 | c2); // Or together children, and return + + if (!(c1 & BSP_CONTENTS_SOLID2) || !(c2 & BSP_CONTENTS_SOLID2)) + Contents &= ~BSP_CONTENTS_SOLID2; + + return (Contents); +} + +//==================================================================================== +// CanSeeThroughPortal +//==================================================================================== +geBoolean CanSeeThroughPortal(GBSP_Portal *Portal) +{ + uint32 c1, c2; + + // Can't see into or from solid + if ((Portal->Nodes[0]->Contents & BSP_CONTENTS_SOLID2) || + (Portal->Nodes[1]->Contents & BSP_CONTENTS_SOLID2)) + return GE_FALSE; + //return GE_TRUE; + + if (!Portal->OnNode) + return GE_FALSE; + + // 'Or' together all cluster contents under portals nodes + c1 = ClusterContents(Portal->Nodes[0]); + c2 = ClusterContents(Portal->Nodes[1]); + + // Can only see through portal if contents on both sides are translucent... + //if ((c1 & BSP_CONTENTS_TRANSLUCENT) && (c2 & BSP_CONTENTS_TRANSLUCENT)) + // return GE_TRUE; + + if (!MajorVisibleContents (c1^c2)) + return GE_TRUE; + + // Cancel solid if it's detail, or translucent on the leafs/clusters + if (c1 & (BSP_CONTENTS_TRANSLUCENT2|BSP_CONTENTS_DETAIL2)) + c1 = 0; + if (c2 & (BSP_CONTENTS_TRANSLUCENT2|BSP_CONTENTS_DETAIL2)) + c2 = 0; + + if ( (c1|c2) & BSP_CONTENTS_SOLID2 ) + return GE_FALSE; // If it's solid on either side, return GE_FALSE + + if (! (c1 ^ c2)) + return GE_TRUE; // If it's the same on both sides then we can definitly see through it... + + if (!MajorVisibleContents(c1^c2)) + return GE_TRUE; + + return GE_FALSE; +} + +//==================================================================================== +// PrepPortalFile_r +//==================================================================================== +geBoolean PrepPortalFile_r(GBSP_Node *Node) +{ + GBSP_Node *Nodes[2]; + GBSP_Portal *Portal; + int32 Side; + + // Stop at leafs, and detail nodes (stop at beginning of clusters) + if (Node->PlaneNum == PLANENUM_LEAF || Node->Detail) + { + if (ContentsSolid(Node->Contents)) + return GE_TRUE; + + // Give this portal it's leaf number... + Node->PortalLeafNum = NumPortalLeafs; + NumPortalLeafs++; + + if (!Node->Portals) + { + GHook.Printf("*WARNING* PrepPortalFile_r: Leaf without any portals.\n"); + return GE_TRUE; + } + + // Save out all the portals that belong to this leaf... + for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) + { + Nodes[0] = Portal->Nodes[0]; + Nodes[1] = Portal->Nodes[1]; + + Side = (Nodes[1] == Node); + + if (!Portal->Poly) + { + GHook.Printf("*WARNING* SavePortalFile_r: Portal with NULL poly.\n"); + continue; + } + + if (!CanSeeThroughPortal(Portal)) + continue; + + if (Nodes[0]->Cluster == Nodes[1]->Cluster) + { + GHook.Error("PrepPortalFile_r: Portal seperating the same cluster.\n"); + return GE_FALSE; + } + + // This portal is good... + NumPortals++; + } + + return GE_TRUE; + } + + Node->PortalLeafNum = -1; + + if (Node->Portals) + GHook.Printf("*WARNING* PrepPortalFile_r: Node with portal.\n"); + + if (!PrepPortalFile_r(Node->Children[0])) + return GE_FALSE; + + if (!PrepPortalFile_r(Node->Children[1])) + return GE_FALSE; + + return GE_TRUE; +} + +//==================================================================================== +// SavePortalFile_r +//==================================================================================== +geBoolean SavePortalFile_r(GBSP_Node *Node, FILE *f) +{ + GBSP_Node *Nodes[2]; + GBSP_Portal *Portal; + int32 i, Side, Side2, Cluster; + GBSP_Plane Plane; + GBSP_Poly *Poly; + + if (Node->PlaneNum == PLANENUM_LEAF || Node->Detail) + { + // Can't see from solid + if (ContentsSolid(Node->Contents)) + return GE_TRUE; + + if (!Node->Portals) + return GE_TRUE; + + for (Portal = Node->Portals; Portal; Portal = Portal->Next[Side]) + { + Nodes[0] = Portal->Nodes[0]; + Nodes[1] = Portal->Nodes[1]; + + Side = (Nodes[1] == Node); + + if (!Portal->Poly) + continue; + + if (!CanSeeThroughPortal(Portal)) + continue; + + if (Nodes[0]->Cluster == Nodes[1]->Cluster) + { + GHook.Error("PrepPortalFile_r: Portal seperating the same cluster.\n"); + return GE_FALSE; + } + + Poly = Portal->Poly; + + if (Poly->NumVerts < 3) + { + GHook.Error("SavePortalFile_r: Portal poly verts < 3.\n"); + return GE_FALSE; + } + + if (fwrite(&Poly->NumVerts, sizeof(int32), 1, f) != 1) + { + GHook.Error(" SavePortalFile_r: Error writing portal NumVerts.\n"); + return GE_FALSE; + } + + if (!Side) // If on front side, reverse so it points to the other leaf + { + for (i= Poly->NumVerts-1; i>=0; i--) + { + if (fwrite(&Poly->Verts[i], sizeof(geVec3d), 1, f) != 1) + { + GHook.Error(" SavePortalFile_r: Error writing portal verts.\n"); + return GE_FALSE; + } + } + } + // It's allready pointing to the other leaf + else if (fwrite(Poly->Verts, sizeof(geVec3d), Poly->NumVerts, f) != (uint32)Poly->NumVerts) + { + GHook.Error(" SavePortalFile_r: Error writing portal verts.\n"); + return GE_FALSE; + } + + Side2 = Side; + + PlaneFromVerts(Poly->Verts, &Plane); + + if (geVec3d_DotProduct(&Planes[Portal->PlaneNum].Normal, &Plane.Normal) < 0.99f) + Side2 = !Side2; + + // CHANGE: CLUSTER + if (Nodes[Side2]->Cluster < 0 || Nodes[Side2]->Cluster > NumLeafClusters) + { + GHook.Error("SavePortalFile_r: Bad Leaf Cluster Number.\n"); + return GE_FALSE; + } + + Cluster = Nodes[Side2]->Cluster; + fwrite(&Cluster, sizeof(int32), 1, f); + + if (Nodes[!Side2]->Cluster < 0 || Nodes[!Side2]->Cluster > NumLeafClusters) + { + GHook.Error("SavePortalFile_r: Bad Leaf Cluster Number.\n"); + return GE_FALSE; + } + + Cluster = Nodes[!Side2]->Cluster; + fwrite(&Cluster, sizeof(int32), 1, f); + } + + return GE_TRUE; + } + + if (Node->Portals) + GHook.Printf("*WARNING* SavePortalFile_r: Node with portal.\n"); + + if (!SavePortalFile_r(Node->Children[0], f)) + return GE_FALSE; + + if (!SavePortalFile_r(Node->Children[1], f)) + return GE_FALSE; + + return GE_TRUE; +} + +//==================================================================================== +// SavePortalFile +//==================================================================================== +geBoolean SavePortalFile(GBSP_Model *Model, char *FileName) +{ + char PortalFile[200]; + char TAG[14]; + FILE *f; + + GHook.Printf(" --- Save Portal File --- \n"); + + strcpy(PortalFile, FileName); + + StripExtension(PortalFile); + DefaultExtension(PortalFile, ".GPF"); + + f = fopen(PortalFile, "wb"); + + if (!f) + { + GHook.Error("SavePortalFile: Error opening %s for writing.\n", PortalFile); + return GE_FALSE; + } + + NumPortals = 0; // Number of portals + NumPortalLeafs = 0; // Current leaf number + + if (!PrepPortalFile_r(Model->RootNode[0])) + { + fclose(f); + GHook.Error("SavePortalFile: Could not PrepPortalFile.\n"); + return GE_FALSE; + } + + if (NumPortalLeafs != Model->NumClusters) + { + GHook.Error("SavePortalFile: Invalid number of clusters!!!\n"); + return GE_FALSE; + } + + strcpy(TAG, "GBSP_PRTFILE"); + fwrite(TAG, sizeof(char), 12, f); + + fwrite(&NumPortals, sizeof(int32), 1, f); + fwrite(&Model->NumClusters, sizeof(int32), 1, f); + + if (!SavePortalFile_r(Model->RootNode[0], f)) + { + fclose(f); + return GE_FALSE; + } + + fclose(f); + + if (Verbose) + { + GHook.Printf("Num Portals : %5i\n", NumPortals); + GHook.Printf("Num Portal Leafs : %5i\n", NumPortalLeafs); + } + + return GE_TRUE; +} diff --git a/GBSPLib/RAD.CPP b/GBSPLib/RAD.CPP new file mode 100644 index 0000000..9d553e1 --- /dev/null +++ b/GBSPLib/RAD.CPP @@ -0,0 +1,1848 @@ +/****************************************************************************************/ +/* Rad.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Cacluates radiosity for a BSP. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "DCommon.h" +#include "BSP.h" +#include "GBSPFile.h" +#include "Math.h" +#include "MathLib.h" +#include "Poly.h" +#include "Light.h" +#include "Texture.h" + +#include "Ram.h" + +pRAD_Patch *FacePatches; +pRAD_Patch *PatchList; +geFloat *RecAmount; + +int32 NumPatches; +int32 NumReceivers; + +geBoolean BuildPatch(int32 Face); +geBoolean FinalizePatches(void); +RAD_Patch *AllocPatch(void); +void FreePatch(RAD_Patch *Patch); +void CalcPatchReflectivity(int32 Face, RAD_Patch *Patch); +void GetFaceMinsMaxs(int32 Face, geVec3d *Mins, geVec3d *Maxs); + +geBoolean SaveReceiverFile(char *FileName); +geBoolean LoadReceiverFile(char *FileName); + +//==================================================================================== +// BuildPatches +//==================================================================================== +geBoolean BuildPatches(void) +{ + int32 i; + + GHook.Printf("--- Build Patches --- \n"); + + NumPatches = NumGFXFaces; + + FacePatches = GE_RAM_ALLOCATE_ARRAY(pRAD_Patch,NumGFXFaces); + + if (!FacePatches) + { + GHook.Error("BuilkdPatches: Not enough memory for patches.\n"); + return GE_FALSE; + } + + for (i=0; i< NumGFXFaces; i++) + { + FacePatches[i] = NULL; + + //if (GFXTexInfo[GFXFaces[i].TexInfo].Flags & TEXINFO_NO_LIGHTMAP) + // continue; + + if (!BuildPatch(i)) + return GE_FALSE; + } + + NumPatches = 0; + if (!FinalizePatches()) + { + GHook.Error("BuildPatches: Could not finalize face patches.\n"); + return GE_FALSE; + } + + if (LVerbose) + GHook.Printf("Num Patches : %5i\n", NumPatches); + + return GE_TRUE; +} + +//==================================================================================== +// CalcPatchInfo +//==================================================================================== +geBoolean CalcPatchInfo(RAD_Patch *Patch) +{ + int32 i, k; + GBSP_Poly *Poly; + + ClearBounds(&Patch->Mins, &Patch->Maxs); + + Poly = Patch->Poly; + + if (!Poly) + { + GHook.Error("CalcPatchInfo: No Poly!\n"); + return GE_FALSE; + } + + for (i=0; i< Poly->NumVerts; i++) + { + for (k=0; k< 3; k++) + { + if (VectorToSUB(Poly->Verts[i], k) < VectorToSUB(Patch->Mins, k)) + VectorToSUB(Patch->Mins, k) = VectorToSUB(Poly->Verts[i], k); + if (VectorToSUB(Poly->Verts[i], k) > VectorToSUB(Patch->Maxs, k)) + VectorToSUB(Patch->Maxs, k) = VectorToSUB(Poly->Verts[i], k); + } + } + + return GE_TRUE; +} + +//==================================================================================== +// GBSPPolyFromGFXFace +//==================================================================================== +GBSP_Poly *GBSPPolyFromGFXFace(GFX_Face *Face) +{ + GBSP_Poly *NewPoly; + int32 i, Index; + + NewPoly = AllocPoly(Face->NumVerts); + + for (i=0; i< Face->NumVerts; i++) + { + Index = GFXVertIndexList[i + Face->FirstVert]; + + NewPoly->Verts[i].X = (geFloat)GFXVerts[Index].X; + NewPoly->Verts[i].Y = (geFloat)GFXVerts[Index].Y; + NewPoly->Verts[i].Z = (geFloat)GFXVerts[Index].Z; + } + + RemoveDegenerateEdges(NewPoly); + + return NewPoly; +} + +//==================================================================================== +// PatchNeedsSplit +//==================================================================================== +geBoolean PatchNeedsSplit(RAD_Patch *Patch, GBSP_Plane *Plane) +{ + int32 i; + + + if (NumPatches >= MAX_PATCHES-2) // Do not cut any more if max patches exceeded!!! + return GE_FALSE; + +if (FastPatch) +{ + geFloat Dist; + + for (i=0; i<3; i++) + { + Dist = VectorToSUB(Patch->Maxs, i) - VectorToSUB(Patch->Mins, i); + + if (Dist > PatchSize) + { + // Cut it right through the center... + geVec3d_Clear(&Plane->Normal); + VectorToSUB(Plane->Normal, i) = (geFloat)1; + Plane->Dist = (VectorToSUB(Patch->Maxs, i) + VectorToSUB(Patch->Mins, i))/2.0f; + Plane->Type = PLANE_ANY; + return GE_TRUE; + } + } +} +else +{ + geFloat Min, Max; + + for (i=0 ; i<3 ; i++) + { + Min = VectorToSUB(Patch->Mins,i)+1.0f; + Max = VectorToSUB(Patch->Maxs,i)-1.0f; + if (floor(Min/PatchSize) < floor(Max/PatchSize)) + { + geVec3d_Clear(&Plane->Normal); + VectorToSUB(Plane->Normal, i) = (geFloat)1; + Plane->Dist = PatchSize*(1.0f+(geFloat)floor(Min/PatchSize)); + Plane->Type = PLANE_ANY; + return GE_TRUE; + } + } +} + return GE_FALSE; +} + +//==================================================================================== +// SubdivideFacePatches +//==================================================================================== +RAD_Patch *SubdivideFacePatches(RAD_Patch *Patch) +{ + RAD_Patch *CPatch, *NewPatch, *NextPatch; + GBSP_Poly *Poly, *FPoly, *BPoly; + GBSP_Plane Plane; + + for (CPatch = Patch; CPatch; CPatch = NextPatch) + { + NextPatch = CPatch->Next; + + if (PatchNeedsSplit(CPatch, &Plane)) + { + NumPatches++; + + Poly = CPatch->Poly; + if (!SplitPoly(Poly, &Plane, &FPoly, &BPoly, GE_FALSE)) + return GE_FALSE; + + if (!FPoly || !BPoly) + { + GHook.Error("SubdivideFacePatches: Patch was not split.\n"); + return NULL; + } + + NewPatch = AllocPatch(); + if (!NewPatch) + { + GHook.Error("SubdivideFacePatches: Out of memory for new patch.\n"); + return NULL; + } + + *NewPatch = *CPatch; // Make it take on all the attributes of it's parent + + NewPatch->Next = NextPatch; + NewPatch->Poly = FPoly; + if (!CalcPatchInfo(NewPatch)) + { + GHook.Error("SubdivideFacePatches: Could not calculate patch info.\n"); + return NULL; + } + + // Re-use the first patch + CPatch->Next = NewPatch; + CPatch->Poly = BPoly; + + if (!CalcPatchInfo(CPatch)) + { + GHook.Error("SubdivideFacePatches: Could not calculate patch info.\n"); + return NULL; + } + + NextPatch = CPatch; // Keep working from here till satisfied... + } + } + + return Patch; +} + +//==================================================================================== +// FinalizePatchInfo +//==================================================================================== +geBoolean FinalizePatchInfo(int32 Face, RAD_Patch *Patch) +{ + GBSP_Poly *Poly; + int32 i; + + Poly = Patch->Poly; + + if (!Poly) + { + GHook.Error("FinalizePatchInfo: No Poly!\n"); + return GE_FALSE; + } + + geVec3d_Clear(&Patch->Origin); + + for (i=0; i< Poly->NumVerts; i++) + { + geVec3d_Add(&Patch->Origin, &Poly->Verts[i], &Patch->Origin); + } + + for (i=0; i<3; i++) + VectorToSUB(Patch->Origin, i) /= Poly->NumVerts; + + Patch->Plane.Normal.X = (geFloat)GFXPlanes[GFXFaces[Face].PlaneNum].Normal.X; + Patch->Plane.Normal.Y = (geFloat)GFXPlanes[GFXFaces[Face].PlaneNum].Normal.Y; + Patch->Plane.Normal.Z = (geFloat)GFXPlanes[GFXFaces[Face].PlaneNum].Normal.Z; + + Patch->Plane.Dist = (geFloat)GFXPlanes[GFXFaces[Face].PlaneNum].Dist; + Patch->Plane.Type = PLANE_ANY; + + if (GFXFaces[Face].PlaneSide) + { + geVec3d_Inverse(&Patch->Plane.Normal); + Patch->Plane.Dist = -Patch->Plane.Dist; + } + + geVec3d_AddScaled(&Patch->Origin, &Patch->Plane.Normal, 2.0f, &Patch->Origin); + + Patch->Leaf = FindGFXLeaf(0, &Patch->Origin); + + Patch->Area = PolyArea(Patch->Poly); + if (Patch->Area < 1.0f) + Patch->Area = 1.0f; + + FreePoly(Patch->Poly); // Don't need this anymore + Patch->Poly = NULL; + + return GE_TRUE; +} + +//==================================================================================== +// FinalizePatches +//==================================================================================== +geBoolean FinalizePatches(void) +{ + RAD_Patch *Patch; + int32 i, k; + + for (i=0; i< NumGFXFaces; i++) + for (Patch = FacePatches[i]; Patch; Patch = Patch->Next) + { + FinalizePatchInfo(i, Patch); + NumPatches++; + } + + PatchList = GE_RAM_ALLOCATE_ARRAY(pRAD_Patch,NumPatches); + + if (!PatchList) + { + GHook.Error("FinalizePatches: Out of memory for patch list.\n"); + return GE_FALSE; + } + + // Build the patch list, so we can use indexing, instead of pointers (for receivers)... + k = 0; + for (i=0; i< NumGFXFaces; i++) + for (Patch = FacePatches[i]; Patch; Patch = Patch->Next) + { + PatchList[k] = Patch; + k++; + } + + return GE_TRUE; +} + +//==================================================================================== +// FreePatches +//==================================================================================== +void FreePatches(void) +{ + int32 i; + + for (i=0; i< NumPatches; i++) + { + geRam_Free(PatchList[i]); + } + + NumPatches = 0; + + if (PatchList) + geRam_Free(PatchList); + if (FacePatches) + geRam_Free(FacePatches); + + PatchList = NULL; + FacePatches = NULL; +} + + +geFloat BestPatchSize(int32 Face) +{ + GBSP_Poly *Poly; + int32 i; + int32 Axis; + geFloat Mins, Maxs, Size, BestSize, v; + geVec3d *Verts; + GFX_TexInfo *Tex; + + Poly = FacePatches[Face]->Poly; + + // Special (nonsurface cached) faces don't need subdivision + Tex = &TexInfo[GFXFaces[Face].TexInfo]; + + BestSize = -MIN_MAX_BOUNDS2; + + for (Axis = 0 ; Axis < 2 ; Axis++) + { + Mins = MIN_MAX_BOUNDS; + Maxs = -MIN_MAX_BOUNDS; + + Verts = Poly->Verts; + for (i=0 ; i< Poly->NumVerts ; i++) + { + v = geVec3d_DotProduct(&Verts[i], &Tex->Vecs[Axis]); + if (v < Mins) + Mins = v; + if (v > Maxs) + Maxs = v; + } + + Size = Maxs - Mins; + if (Size > BestSize) + BestSize = Size; + } + + return (BestSize/4); + +} +//==================================================================================== +// BuildPatch +//==================================================================================== +void ApplyLightmapToPatches(int32 Face); + +geBoolean BuildPatch(int32 Face) +{ + + //int32 Texture; + //Texture = GFXTexInfo[GFXFaces[Face].TexInfo].Texture; + + FacePatches[Face] = AllocPatch(); + if (!FacePatches[Face]) + { + GHook.Error("BuildPatch: Could not allocate patch.\n"); + return GE_FALSE; + } + + CalcPatchReflectivity(Face, FacePatches[Face]); + + FacePatches[Face]->Poly = GBSPPolyFromGFXFace(&GFXFaces[Face]); + + if (!CalcPatchInfo(FacePatches[Face])) + { + GHook.Error("BuildPatch: Could not calculate patch info.\n"); + return GE_FALSE; + } + + FacePatches[Face] = SubdivideFacePatches(FacePatches[Face]); + + if (!FacePatches[Face]) + { + GHook.Error("BuildPatch: Could not subdivide patch.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//==================================================================================== +// AllocPatch +//==================================================================================== +RAD_Patch *AllocPatch(void) +{ + RAD_Patch *Patch; + + Patch = GE_RAM_ALLOCATE_STRUCT(RAD_Patch); + + if (!Patch) + { + GHook.Error("AllocPatch: Not enough memory.\n"); + return NULL; + } + + memset(Patch, 0, sizeof(RAD_Patch)); + + return Patch; +} + +//==================================================================================== +// FreePatch +//==================================================================================== +void FreePatch(RAD_Patch *Patch) +{ + if (!Patch) + { + GHook.Printf("*WARNING* FreePatch: Nothing to free!\n"); + return; + } + + if (Patch->Poly) + FreePoly(Patch->Poly); + + Patch->Poly = NULL; + + geRam_Free(Patch); +} + +//==================================================================================== +// AllocReceiver +//==================================================================================== +RAD_Receiver *AllocReceiver(void) +{ + RAD_Receiver *Receiver; + + Receiver = GE_RAM_ALLOCATE_STRUCT(RAD_Receiver); + + if (!Receiver) + { + GHook.Error("AllocReceiver: Not enough memory.\f"); + return NULL; + } + + memset(Receiver, 0, sizeof(RAD_Receiver)); + + return Receiver; +} + +//==================================================================================== +// FreeReceiver +//==================================================================================== +void FreeReceiver(RAD_Receiver *Rec) +{ + if (!Rec) + { + GHook.Printf("*WARNING* FreeReceiver: Nothing to free!\n"); + return; + } + geRam_Free(Rec); +} + +//==================================================================================== +// FindPatchReceivers +// PreCalculate who can see who, and how much they emit +//==================================================================================== +geBoolean FindPatchReceivers(RAD_Patch *Patch) +{ + RAD_Patch *Patch2; + uint8 *VisData; + geBoolean VisInfo; + geFloat Dist; + geFloat Amount; + geFloat Total, Scale; + int32 i, Cluster; + geVec3d Vect, Normal; + RAD_Receiver *Receiver; + GFX_Leaf *pLeaf; + int32 Area; + + pLeaf = &GFXLeafs[Patch->Leaf]; + Cluster = pLeaf->Cluster; + Area = pLeaf->Area; + + if (Cluster >= 0 && GFXClusters[Cluster].VisOfs >= 0) + { + VisData = &GFXVisData[GFXClusters[Cluster].VisOfs]; + VisInfo = GE_TRUE; + } + else + VisInfo = GE_FALSE; + + Total = 0.0f; + + Normal = Patch->Plane.Normal; + + // For each face, go through all it's patches + for (i=0; i< NumPatches; i++) + { + if (CancelRequest) + { + GHook.Printf("Cancel requested...\n"); + return GE_FALSE; + } + + Patch2 = PatchList[i]; + + RecAmount[i] = 0.0f; + + if (Patch2 == Patch) + continue; + + pLeaf = &GFXLeafs[Patch2->Leaf]; + + if (pLeaf->Area != Area) // Radiosity only bounces in it's original area + continue; + + if (VisInfo) + { + Cluster = pLeaf->Cluster; + if (Cluster >= 0 && !(VisData[Cluster>>3] &(1<<(Cluster&7))) ) + continue; + + } + + geVec3d_Subtract(&Patch2->Origin, &Patch->Origin, &Vect); + + Dist = geVec3d_Normalize(&Vect); + + //if (Dist > PatchSize) + if (!Dist) + continue; // Error + + Scale = geVec3d_DotProduct(&Vect, &Normal); + Scale *= -geVec3d_DotProduct(&Vect, &Patch2->Plane.Normal); + + if (Scale <= 0) + continue; + + if (RayCollision(&Patch->Origin, &Patch2->Origin, NULL)) + continue; // Blocked by somthing in the world + + Amount = Scale * Patch2->Area / (Dist*Dist); + + if (Amount <= 0.0f) + continue; + + RecAmount[i] = Amount; + + // Add the receiver + Total += Amount; + NumReceivers++; + Patch->NumReceivers++; + } + + Patch->Receivers = GE_RAM_ALLOCATE_ARRAY(RAD_Receiver,Patch->NumReceivers); + + if (!Patch->Receivers) + { + GHook.Error("CalcReceivers: Out of memory for receiver.\n"); + return GE_FALSE; + } + + Receiver = Patch->Receivers; + + for (i=0; i< NumPatches; i++) + { + if (!RecAmount[i]) + continue; + + Receiver->Patch = (uint16)i; + Receiver->Amount = (uint16)(RecAmount[i]*0x10000 / Total); + Receiver++; + } + + return GE_TRUE; +} + +//==================================================================================== +// CalcReceivers +//==================================================================================== +geBoolean CalcReceivers(char *FileName) +{ + int32 i; + RAD_Patch *Patch; + int32 Perc; + geFloat Megs; + + NumReceivers = 0; + + // Try to load the receiver file first!!! + if (LoadReceiverFile(FileName)) + { + GHook.Printf("--- Found receiver file ---\n"); + return GE_TRUE; + } + + GHook.Printf(" --- Calculating receivers from scratch ---\n"); + + RecAmount = GE_RAM_ALLOCATE_ARRAY(geFloat,NumPatches); + + if (!RecAmount) + { + GHook.Error("CalcReceivers: Out of memory for RecAmount.\n"); + return GE_FALSE; + } + + Perc = (NumPatches/20); + for (i=0; i< NumPatches; i++) + { + if (Perc) + { + if (!(i%Perc) && (i/Perc)<=20) + GHook.Printf(".%i", (i/Perc)); + } + + Patch = PatchList[i]; + + if (!FindPatchReceivers(Patch)) + { + GHook.Error("CalcReceivers: There was an error calculating receivers.\n"); + return GE_FALSE; + } + } + GHook.Printf("\n"); + + + geRam_Free(RecAmount); + RecAmount = NULL; + + Megs = (geFloat)NumReceivers * sizeof(RAD_Receiver) / (1024*1024); + GHook.Printf("Num Receivers : %5i, Megs %2.2f\n", NumReceivers, Megs); + + // Save receiver file for later retreival + if (!SaveReceiverFile(FileName)) + { + GHook.Error("CalcReceivers: Failed to save receiver file...\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//==================================================================================== +// FreeReceivers +//==================================================================================== +void FreeReceivers(void) +{ + int32 i; + RAD_Patch *Patch; + + NumReceivers = 0; + + for (i=0; i< NumPatches; i++) + { + Patch = PatchList[i]; + + if (Patch->NumReceivers) + geRam_Free(Patch->Receivers); + + Patch->Receivers = NULL; + } +} + +//==================================================================================== +// CheckPatch +//==================================================================================== +geBoolean CheckPatch(RAD_Patch *Patch) +{ + int32 i; + + for (i=0; i<3; i++) + { + if (VectorToSUB(Patch->RadFinal, i) < 0.0f) + { + GHook.Error("CheckPatch: Bad final radiosity Color in patch.\n"); + return GE_FALSE; + } + } + + return GE_TRUE; +} + +//==================================================================================== +// CollectPatchLight +//==================================================================================== +geFloat CollectPatchLight(void) +{ + int i, j; + RAD_Patch *Patch; + geFloat Total; + + Total = 0.0f; + + for (i=0; i< NumPatches; i++) + { + Patch = PatchList[i]; + + for (j=0 ; j<3 ; j++) + { + // Add receive amount to Final amount + VectorToSUB(Patch->RadFinal, j) += + VectorToSUB(Patch->RadReceive, j) / Patch->Area; + + VectorToSUB(Patch->RadSend, j) = + VectorToSUB(Patch->RadReceive, j) * VectorToSUB(Patch->Reflectivity, j); + + Total += VectorToSUB(Patch->RadSend, j); + } + + geVec3d_Clear(&Patch->RadReceive); + } + + return Total; +} + + +//==================================================================================== +// SendPatch +//==================================================================================== +void SendPatch(RAD_Patch *Patch) +{ + geVec3d Send; + RAD_Patch *RPatch; + int32 k; + RAD_Receiver *Receiver; + + for (k=0; k<3; k++) + VectorToSUB(Send, k) = VectorToSUB(Patch->RadSend, k) / (geFloat)0x10000; + //VectorToSUB(Send, k) = VectorToSUB(Patch->RadSend, k); + + // Send light out to each pre-computed receiver + Receiver = Patch->Receivers; + for (k=0; k< Patch->NumReceivers; k++, Receiver++) + { + RPatch = PatchList[Receiver->Patch]; + + geVec3d_AddScaled(&RPatch->RadReceive, &Send, (geFloat)Receiver->Amount, &RPatch->RadReceive); + //geVec3d_AddScaled(&RPatch->RadReceive, &Send, .0005f, &RPatch->RadReceive); + } +} + +//==================================================================================== +// BouncePatches +//==================================================================================== +geBoolean BouncePatches(void) +{ + int32 i, j; + RAD_Patch *Patch; + geFloat Total; + + GHook.Printf("--- Bounce Patches --- \n"); + + for (i=0 ; i< NumPatches; i++) + { + // Set each patches first pass send amount with what was obtained + // from their lightmaps... + Patch = PatchList[i]; + for (j=0 ; j<3 ; j++) + { + VectorToSUB(Patch->RadSend, j) = VectorToSUB(Patch->RadStart, j) * + VectorToSUB(Patch->Reflectivity, j) * Patch->Area; + } + + //geVec3d_Clear(&Patch->RadFinal); + } + + for (i=0 ; iGFXFace = i; + PFace->Next = PlaneFaces[PlaneNum]; + PlaneFaces[PlaneNum] = PFace; + } +} + +//==================================================================================== +// FreePlaneFaces +//==================================================================================== +void FreePlaneFaces(void) +{ + int32 i; + PlaneFace *PFace, *Next; + + for (i=0; i< NumGFXPlanes; i++) + { + for (PFace = PlaneFaces[i]; PFace; PFace = Next) + { + Next = PFace->Next; + geRam_Free(PFace); + } + } + + geRam_Free(PlaneFaces); +} + +//==================================================================================== +// GetFaceMinsMaxs +//==================================================================================== +void GetFaceMinsMaxs(int32 Face, geVec3d *Mins, geVec3d *Maxs) +{ + int32 i, k, Index; + geFloat t; + + ClearBounds(Mins, Maxs); + + for (i=0; i< GFXFaces[Face].NumVerts; i++) + { + Index = GFXVertIndexList[GFXFaces[Face].FirstVert+i]; + for (k=0; k<3; k++) + { + t = VectorToSUB(GFXVerts[Index], k); + + if (t < VectorToSUB(*Mins, k)) + VectorToSUB(*Mins, k) = t; + if (t > VectorToSUB(*Maxs, k)) + VectorToSUB(*Maxs, k) = t; + } + } +} + +//==================================================================================== +// MakeCornerPatches +//==================================================================================== +RAD_Patch *MakeCornerPatches(int32 Face, Tri_Patch *Tri) +{ + RAD_Patch *PatchList, *NewPatch; + int32 i, Width, Height, u, v; + geFloat StartU, StartV, CurU, CurV, EndU, EndV; + FInfo *Fi; + LInfo *Li; + + PatchList = NULL; + + Fi = &FaceInfo[Face]; + Li = &Lightmaps[Face]; + + Width = Li->LSize[0]+1; + Height = Li->LSize[1]+1; + StartU = ((geFloat)Li->LMins[0]) * (geFloat)LGRID_SIZE; + StartV = ((geFloat)Li->LMins[1]) * (geFloat)LGRID_SIZE; + + EndU = ((geFloat)Li->LMaxs[0]) * (geFloat)LGRID_SIZE; + EndV = ((geFloat)Li->LMaxs[1]) * (geFloat)LGRID_SIZE; + + for (v=0; v < 2; v++) + { + for (u=0; u < 2; u++) + { + if (u == 0) + CurU = StartU; + else + CurU = EndU; + + if (v == 0) + CurV = StartV; + else + CurV = EndV; + + NewPatch = AllocPatch(); + if (!NewPatch) + { + GHook.Error("CreateCornerPatches: Could not create patch.\n"); + return NULL; + } + + for (i=0; i< 3; i++) + VectorToSUB(NewPatch->Origin, i) = VectorToSUB(Fi->TexOrg,i) + + VectorToSUB(Fi->T2WVecs[0], i) * CurU + + VectorToSUB(Fi->T2WVecs[1], i) * CurV; + + if (!FindClosestTriPoint(&NewPatch->Origin, Tri, &NewPatch->RadFinal)) + { + GHook.Error("MakeCornerPatches: Could not find patch for Color.\n"); + return GE_FALSE; + } + + //NewPatch->RadFinal.X = 0.0f; + //NewPatch->RadFinal.Y = 255.0f; + //NewPatch->RadFinal.Z = 0.0f; + // Insert it into the beginning of the list + NewPatch->Next = PatchList; + PatchList = NewPatch; + } + } + return PatchList; +} + +//==================================================================================== +// FreePatchList +//==================================================================================== +void FreePatchList(RAD_Patch *Patches) +{ + RAD_Patch *Patch, *Next; + + for (Patch = Patches; Patch; Patch = Next) + { + Next = Patch->Next; + FreePatch(Patch); + } +} + +//==================================================================================== +// AbsorbPatches +//==================================================================================== +geBoolean AbsorbPatches(void) +{ + Tri_Patch *Tri; + GBSP_Plane Plane; + geVec3d Add, *pPoint, *pRGB; + int32 i, k, PNum, FNum, PSide; + RAD_Patch *Patch, *OPatch, *TempPatches; + PlaneFace *PFace; + geVec3d FMins, FMaxs; + + LinkPlaneFaces(); // We need all the faces that belong to each Plane + + for (i=0; i< NumGFXFaces; i++) + { + int32 Flags; + GFX_Face *pGFXFace; + + pGFXFace = &GFXFaces[i]; + + if (CancelRequest) + { + GHook.Printf("Cancel requested...\n"); + return GE_FALSE; + } + + pPoint = FaceInfo[i].Points; + pRGB = Lightmaps[i].RGBLData[0]; + + Flags = GFXTexInfo[GFXFaces[i].TexInfo].Flags; + + if ((Flags & TEXINFO_NO_LIGHTMAP) && !(Flags & TEXINFO_GOURAUD)) + continue; + + //if (!pRGB) + // continue; + + Plane.Normal.X = (geFloat)GFXPlanes[GFXFaces[i].PlaneNum].Normal.X; + Plane.Normal.Y = (geFloat)GFXPlanes[GFXFaces[i].PlaneNum].Normal.Y; + Plane.Normal.Z = (geFloat)GFXPlanes[GFXFaces[i].PlaneNum].Normal.Z; + Plane.Dist = (geFloat)GFXPlanes[GFXFaces[i].PlaneNum].Dist; + Plane.Type = PLANE_ANY; + /* + if(GFXFaces[i].PlaneSide) + { + geVec3d_Inverse(&Plane.Normal); + Plane.Dist = -Plane.Dist; + } + */ + + Tri = Tri_PatchCreate(&Plane); + if (!Tri) + { + GHook.Error("AbsorbPatches: Tri_PatchCreate failed.\n"); + return GE_FALSE; + } + + PNum = GFXFaces[i].PlaneNum; + PSide = GFXFaces[i].PlaneSide; + + OPatch = FacePatches[i]; + + GetFaceMinsMaxs(i, &FMins, &FMaxs); + + for (PFace = PlaneFaces[PNum]; PFace; PFace = PFace->Next) + { + FNum = PFace->GFXFace; + + if (GFXFaces[FNum].PlaneSide != PSide) + continue; + + for (Patch = FacePatches[FNum]; Patch; Patch = Patch->Next) + { + for (k=0 ; k < 3 ; k++) + { + if (VectorToSUB(Patch->Origin, k) < VectorToSUB(FMins,k) - (PatchSize*2)) + break; + + if (VectorToSUB(Patch->Origin, k) > VectorToSUB(FMaxs,k) + (PatchSize*2)) + break; + } + if (k != 3) + continue; + + // Don't include patches that might cross through walls or floors, or + // it will cause false light bleeds from patch to patch + //if (OPatch != Patch) + //if (RayCollision(&OPatch->Origin, &Patch->Origin, NULL)) + // continue; + + if (!AddPointToTriangulation (Patch, Tri)) + { + GHook.Error("AbsorbPatches: Could not add patch to triangulation.\n"); + return GE_FALSE; + } + + } + } + /* + TempPatches = NULL; + + TempPatches = MakeCornerPatches(i, Tri); + if (!TempPatches) + { + GHook.Error("AbsorbPatches: Could not create corner temp patches.\n"); + return GE_FALSE; + } + + for (Patch = TempPatches; Patch; Patch = Patch->Next) + { + if (!AddPointToTriangulation (Patch, Tri)) + { + GHook.Error("AbsorbPatches: Could not add temp patch to triangulation.\n"); + return GE_FALSE; + } + } + */ + if (!TriangulatePoints (Tri)) + { + GHook.Error("AbsorbPatches: Could not triangulate patches.\n"); + return GE_FALSE; + } + + if (Flags & TEXINFO_GOURAUD) + { + for (k=0; k< pGFXFace->NumVerts; k++) + { + int32 vn; + + vn = pGFXFace->FirstVert+k; + + pPoint = &GFXVerts[GFXVertIndexList[vn]]; + + SampleTriangulation (pPoint, Tri, &Add); + + geVec3d_Add(&GFXRGBVerts[vn], &Add, &GFXRGBVerts[vn]); + } + } + else + { + + geBoolean Created = (pRGB != NULL); + + for (k=0; k< FaceInfo[i].NumPoints; k++, pRGB++, pPoint++) + { + if (!SampleTriangulation (pPoint, Tri, &Add)) + { + GHook.Error("AbsorbPatches: Could not sample from patch triangles.\n"); + continue; + } + + if (!Created) + { + if (Add.X > 0 || Add.Y > 0 || Add.Z > 0) + { + if (Lightmaps[i].NumLTypes > MAX_LTYPES) + { + GHook.Error("AbsorbPatches: Too many Light Types on Face.\n"); + return GE_FALSE; + } + + Lightmaps[i].RGBLData[0] = GE_RAM_ALLOCATE_ARRAY(geVec3d,FaceInfo[i].NumPoints); + if (!Lightmaps[i].RGBLData[0]) + { + GHook.Error("AbsorbPAtches: Out of memory for lightmap.\n"); + return GE_FALSE; + } + Lightmaps[i].NumLTypes++; + pRGB = Lightmaps[i].RGBLData[0]; + memset(pRGB, 0, FaceInfo[i].NumPoints*sizeof(geVec3d)); + pRGB = &pRGB[k]; + Created = GE_TRUE; + } + } + if (Created) + geVec3d_Add(pRGB, &Add, pRGB); + + } + } + + Tri_PatchDestroy(Tri); + //FreePatchList(TempPatches); + TempPatches = NULL; + } + + FreePlaneFaces(); + + return GE_TRUE; +} + +//==================================================================================== +// Tri_PatchCreate +//==================================================================================== +Tri_Patch *Tri_PatchCreate(GBSP_Plane *Plane) +{ + Tri_Patch *Patch; + + Patch = GE_RAM_ALLOCATE_STRUCT(Tri_Patch); + if (!Patch) + { + GHook.Error("Tri_PatchCreate: Out of memory.\n"); + return NULL; + } + + Patch->NumPoints = 0; + Patch->NumEdges = 0; + Patch->NumTris = 0; + + Patch->Plane = Plane; + + return Patch; +} + +//==================================================================================== +// Tri_PatchDestroy +//==================================================================================== +void Tri_PatchDestroy(Tri_Patch *tr) +{ + geRam_Free(tr); +} + + +//==================================================================================== +// FindEdge +//==================================================================================== +Tri_Edge *FindEdge(Tri_Patch *TriPatch, int p0, int p1) +{ + Tri_Edge *e, *be; + geVec3d v1; + geVec3d normal; + geFloat dist; + + if (TriPatch->EdgeMatrix[p0][p1]) + return TriPatch->EdgeMatrix[p0][p1]; + + if (TriPatch->NumEdges > MAX_TRI_EDGES-2) + { + GHook.Error ("TriPatch->NumEdges > MAX_TRI_EDGES-2"); + return NULL; + } + + geVec3d_Subtract (&TriPatch->Points[p1]->Origin, &TriPatch->Points[p0]->Origin, &v1); + geVec3d_Normalize (&v1); + geVec3d_CrossProduct (&v1, &TriPatch->Plane->Normal, &normal); + dist = geVec3d_DotProduct (&TriPatch->Points[p0]->Origin, &normal); + + e = &TriPatch->Edges[TriPatch->NumEdges]; + e->p0 = p0; + e->p1 = p1; + e->tri = NULL; + geVec3d_Copy(&normal, &e->normal); + e->dist = dist; + TriPatch->NumEdges++; + TriPatch->EdgeMatrix[p0][p1] = e; + + // Go ahead and make the reverse edge ahead of time + be = &TriPatch->Edges[TriPatch->NumEdges]; + be->p0 = p1; + be->p1 = p0; + be->tri = NULL; + geVec3d_Copy(&normal, &be->normal); + geVec3d_Inverse(&be->normal); + be->dist = -dist; + TriPatch->NumEdges++; + TriPatch->EdgeMatrix[p1][p0] = be; + + return e; +} + +//==================================================================================== +// AllocTriangle +//==================================================================================== +Tri *AllocTriangle(Tri_Patch *TriPatch) +{ + Tri *t; + + if (TriPatch->NumTris >= MAX_TRI_TRIS) + { + GHook.Error ("TriPatch->NumTris >= MAX_TRI_TRIS"); + return NULL; + } + + t = &TriPatch->TriList[TriPatch->NumTris]; + TriPatch->NumTris++; + + return t; +} + +//==================================================================================== +// Tri_Edge_r +//==================================================================================== +geBoolean Tri_Edge_r (Tri_Patch *TriPatch, Tri_Edge *e) +{ + int i, bestp; + geVec3d v1, v2; + geVec3d *p0, *p1, *p; + geFloat best, ang; + Tri *nt; + Tri_Edge *e2; + + if (e->tri) + return GE_TRUE; + + p0 = &TriPatch->Points[e->p0]->Origin; + p1 = &TriPatch->Points[e->p1]->Origin; + best = 1.1f; + for (i=0 ; i< TriPatch->NumPoints ; i++) + { + p = &TriPatch->Points[i]->Origin; + + if (geVec3d_DotProduct(p, &e->normal) - e->dist < 0) + continue; + + geVec3d_Subtract(p0, p, &v1); + geVec3d_Subtract(p1, p, &v2); + + if (!geVec3d_Normalize(&v1)) + continue; + if (!geVec3d_Normalize(&v2)) + continue; + + ang = geVec3d_DotProduct (&v1, &v2); + if (ang < best) + { + best = ang; + bestp = i; + } + } + if (best >= 1) + return GE_TRUE; + + nt = AllocTriangle (TriPatch); + if (!nt) + { + GHook.Error("Tri_Edge_r: Could not allocate triangle.\n"); + return GE_FALSE; + } + nt->Edges[0] = e; + if (!nt->Edges[0]) + { + GHook.Error("Tri_Edge_r: There was an error finding an edge.\n"); + return GE_FALSE; + } + nt->Edges[1] = FindEdge (TriPatch, e->p1, bestp); + if (!nt->Edges[1]) + { + GHook.Error("Tri_Edge_r: There was an error finding an edge.\n"); + return GE_FALSE; + } + nt->Edges[2] = FindEdge (TriPatch, bestp, e->p0); + if (!nt->Edges[2]) + { + GHook.Error("Tri_Edge_r: There was an error finding an edge.\n"); + return GE_FALSE; + } + for (i=0 ; i<3 ; i++) + nt->Edges[i]->tri = nt; + + e2 = FindEdge (TriPatch, bestp, e->p1); + if (!e2) + { + GHook.Error("Tri_Edge_r: There was an error finding an edge.\n"); + return GE_FALSE; + } + if (!Tri_Edge_r (TriPatch, e2)) + return GE_FALSE; + + e2 = FindEdge (TriPatch, e->p0, bestp); + if (!e2) + { + GHook.Error("Tri_Edge_r: There was an error finding an edge.\n"); + return GE_FALSE; + } + if (!Tri_Edge_r (TriPatch, e2)) + return GE_FALSE; + + return GE_TRUE; +} + +//==================================================================================== +// TriangulatePoints +//==================================================================================== +geBoolean TriangulatePoints(Tri_Patch *TriPatch) +{ + geFloat d, bestd; + geVec3d v1; + int bp1, bp2, i, j; + geVec3d *p1, *p2; + Tri_Edge *e, *e2; + + for (i=0; iNumPoints; i++) + memset(TriPatch->EdgeMatrix[i], 0, TriPatch->NumPoints*sizeof(TriPatch->EdgeMatrix[0][0]) ); + + if (TriPatch->NumPoints < 2) + return GE_TRUE; + + // Find the two closest Points + bestd = MIN_MAX_BOUNDS2; + for (i=0 ; iNumPoints ; i++) + { + p1 = &TriPatch->Points[i]->Origin; + for (j=i+1 ; jNumPoints ; j++) + { + p2 = &TriPatch->Points[j]->Origin; + geVec3d_Subtract(p2, p1, &v1); + d = geVec3d_Length(&v1); + if (d < bestd && d > .05f) + { + bestd = d; + bp1 = i; + bp2 = j; + } + } + } + + e = FindEdge (TriPatch, bp1, bp2); + if (!e) + { + GHook.Error("There was an error finding an edge.\n"); + return GE_FALSE; + } + e2 = FindEdge (TriPatch, bp2, bp1); + if (!e2) + { + GHook.Error("There was an error finding an edge.\n"); + return GE_FALSE; + } + if (!Tri_Edge_r (TriPatch, e)) + return GE_FALSE; + if (!Tri_Edge_r (TriPatch, e2)) + return GE_FALSE; + + return GE_TRUE; +} + +//==================================================================================== +// AddPointToTriangulation +//==================================================================================== +geBoolean AddPointToTriangulation(RAD_Patch *patch, Tri_Patch *TriPatch) +{ + int pnum; + + pnum = TriPatch->NumPoints; + if (pnum == MAX_TRI_POINTS) + { + GHook.Error ("TriPatch->NumPoints == MAX_TRI_POINTS"); + return GE_FALSE; + } + TriPatch->Points[pnum] = patch; + TriPatch->NumPoints++; + + return GE_TRUE; +} + +//==================================================================================== +// LerpTriangle +//==================================================================================== +void LerpTriangle(Tri_Patch *TriPatch, Tri *t, geVec3d *Point, geVec3d *Color) +{ + RAD_Patch *p1, *p2, *p3; + geVec3d base, d1, d2; + geFloat x, y, x1, y1, x2, y2; + + p1 = TriPatch->Points[t->Edges[0]->p0]; + p2 = TriPatch->Points[t->Edges[1]->p0]; + p3 = TriPatch->Points[t->Edges[2]->p0]; + + geVec3d_Copy(&p1->RadFinal, &base); + geVec3d_Subtract(&p2->RadFinal, &base, &d1); + geVec3d_Subtract(&p3->RadFinal, &base, &d2); + + x = geVec3d_DotProduct(Point, &t->Edges[0]->normal) - t->Edges[0]->dist; + y = geVec3d_DotProduct(Point, &t->Edges[2]->normal) - t->Edges[2]->dist; + + x1 = 0.0f; + y1 = geVec3d_DotProduct(&p2->Origin, &t->Edges[2]->normal) - t->Edges[2]->dist; + + x2 = geVec3d_DotProduct(&p3->Origin, &t->Edges[0]->normal) - t->Edges[0]->dist; + y2 = 0.0f; + + if (fabs(y1)Edges[i]; + + Dist = geVec3d_DotProduct(&pEdge->normal, Point) - pEdge->dist; + + if (Dist < 0.0f) + return GE_FALSE; + } + + return GE_TRUE; +} + +//==================================================================================== +// SampleTriangulation +//==================================================================================== +geBoolean SampleTriangulation(geVec3d *Point, Tri_Patch *TriPatch, geVec3d *Color) +{ + Tri *t; + Tri_Edge *e; + geFloat d; + RAD_Patch *p0, *p1; + geVec3d v1, v2; + int i, j; + + if (TriPatch->NumPoints == 0) + { + geVec3d_Clear(Color); + return GE_TRUE; + } + if (TriPatch->NumPoints == 1) + { + geVec3d_Copy(&TriPatch->Points[0]->RadFinal, Color); + return GE_TRUE; + } + + // See of the Point is inside a tri in the patch + for (t = TriPatch->TriList, j=0 ; j < TriPatch->NumTris ; t++, j++) + { + if (!Tri_PointInside (t, Point)) + continue; + + LerpTriangle (TriPatch, t, Point, Color); + + return GE_TRUE; + } + + for (e=TriPatch->Edges, j=0 ; j< TriPatch->NumEdges ; e++, j++) + { + if (e->tri) + continue; // not an exterior edge + + d = geVec3d_DotProduct(Point, &e->normal) - e->dist; + if (d < 0) + continue; // not in front of edge + + p0 = TriPatch->Points[e->p0]; + p1 = TriPatch->Points[e->p1]; + + geVec3d_Subtract(&p1->Origin, &p0->Origin, &v1); + geVec3d_Normalize (&v1); + + geVec3d_Subtract(Point, &p0->Origin, &v2); + d = geVec3d_DotProduct(&v2, &v1); + + if (d < 0) + continue; + if (d > 1) + continue; + + for (i=0 ; i<3 ; i++) + VectorToSUB(*Color,i) = VectorToSUB(p0->RadFinal,i) + d * (VectorToSUB(p1->RadFinal,i) - VectorToSUB(p0->RadFinal,i)); + return GE_TRUE; + } + + if (!FindClosestTriPoint(Point, TriPatch, Color)) + { + GHook.Error("SampleTriangulation: Could not find closest Color.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//======================================================================================== +// FindClosestTriPoint +//======================================================================================== +geBoolean FindClosestTriPoint(geVec3d *Point, Tri_Patch *Tri, geVec3d *Color) +{ + int32 i; + RAD_Patch *p0, *BestPatch; + geFloat BestDist, d; + geVec3d v1; + + // Search for nearest Point + BestDist = MIN_MAX_BOUNDS2; + BestPatch = NULL; + + for (i=0 ; iNumPoints ; i++) + { + p0 = Tri->Points[i]; + geVec3d_Subtract(Point, &p0->Origin, &v1); + d = geVec3d_Length(&v1); + if (d < BestDist) + { + BestDist = d; + BestPatch = p0; + } + } + + if (!BestPatch) + { + GHook.Error ("FindClosestTriPoint: No Points.\n"); + return GE_FALSE; + } + + geVec3d_Copy(&BestPatch->RadFinal, Color); + + return GE_TRUE; +} + +//======================================================================================== +// CalcPatchReflectivity +//======================================================================================== +void CalcPatchReflectivity(int32 Face, RAD_Patch *Patch) +{ + GFX_Texture *pTexture; + geVec3d Color; + int32 i, Size; + uint8 *pGFXTexData; + DRV_Palette *Palette; + GFX_TexInfo *pTexInfo; + geFloat Scale; + + pTexInfo = &GFXTexInfo[GFXFaces[Face].TexInfo]; + pTexture = &GFXTextures[pTexInfo->Texture]; + + geVec3d_Clear(&Color); + + pGFXTexData = &GFXTexData[pTexture->Offset]; + Size = pTexture->Width*pTexture->Height; + + Palette = &GFXPalettes[pTexture->PaletteIndex]; + + for (i=0; i< Size; i++, pGFXTexData++) + { + DRV_RGB * RGB; + + RGB = &(*Palette)[*pGFXTexData]; + Color.X += (geFloat)RGB->r; + Color.Y += (geFloat)RGB->g; + Color.Z += (geFloat)RGB->b; + } + + geVec3d_Scale(&Color, 1.0f/(geFloat)Size, &Color); + geVec3d_Scale(&Color, 1.0f/255.0f, &Color); + + Scale = ColorNormalize(&Color, &Patch->Reflectivity); + + if (Scale < 0.5f) + { + Scale *= 2; + geVec3d_Scale(&Patch->Reflectivity, Scale, &Patch->Reflectivity); + } + + geVec3d_Scale(&Patch->Reflectivity, ReflectiveScale*pTexInfo->ReflectiveScale, &Patch->Reflectivity); +} + +typedef struct +{ + int32 Version; + SYSTEMTIME BSPTime; + int32 NumPatches; +} Rec_Header; + +Rec_Header RecHeader; + +//======================================================================================== +// SaveReceiverFile +//======================================================================================== +geBoolean SaveReceiverFile(char *FileName) +{ + FILE *f; + int32 i; + + GHook.Printf("--- Save Receiver File --- \n"); + + f = fopen(FileName, "wb"); + + if (!f) + { + GHook.Error("SaveReceiverFile: Could not open receiver file for writing...\n"); + return GE_FALSE; + } + + RecHeader.Version = GBSPHeader.Version; + RecHeader.BSPTime = GBSPHeader.BSPTime; + RecHeader.NumPatches = NumPatches; + + // Save header + if (fwrite(&RecHeader, sizeof(Rec_Header), 1, f) != 1) + { + GHook.Printf("*WARNING* SaveReceiverFile: Could not save header info...\n"); + fclose(f); + return GE_TRUE; + } + + // Patches + for (i=0; i< NumPatches; i++) + { + int32 NumReceivers = PatchList[i]->NumReceivers; + + // Write out the number of receivers for this patch + if (fwrite(&NumReceivers, sizeof(int32), 1, f) != 1) + { + GHook.Printf("*WARNING* SaveReceiverFile: Could not save num receivers...\n"); + fclose(f); + return GE_TRUE; + } + + // Write out the actual receivers + if (fwrite(PatchList[i]->Receivers, sizeof(RAD_Receiver), NumReceivers, f) != (uint32)NumReceivers) + { + GHook.Printf("*WARNING* SaveReceiverFile: Could not save receivers...\n"); + fclose(f); + return GE_TRUE; + } + } + + return GE_TRUE; +} + +//======================================================================================== +// LoadReceiverFile +//======================================================================================== +geBoolean LoadReceiverFile(char *FileName) +{ + FILE *f; + int32 i; + uint8 *pTime1, *pTime2; + + f = fopen(FileName, "rb"); + + if (!f) + return GE_FALSE; + + // Load header + if (fread(&RecHeader, sizeof(Rec_Header), 1, f) != 1) + { + GHook.Error("LoadReceiverFile: Could not load header info...\n"); + fclose(f); + return GE_FALSE; + } + + pTime1 = (uint8*)&(RecHeader.BSPTime); + pTime2 = (uint8*)&(GBSPHeader.BSPTime); + + if (RecHeader.Version != GBSPHeader.Version) + { + GHook.Printf("*WARNING* LoadReceiverFile: Versions do not match, skipping...\n"); + fclose(f); + return GE_FALSE; + } + + // Make sure internal time matches... + for (i=0; i< sizeof(SYSTEMTIME); i++) + { + if (*pTime1 != *pTime2) + { + fclose(f); + return GE_FALSE; + } + + pTime1++; + pTime2++; + } + + // Make sure the number of patches in the receiver file, matches the number loaded + // for this BSP + if (RecHeader.NumPatches != NumPatches) + { + GHook.Printf("*WARNING* LoadReceiverFile: NumPatches do not match, skipping...\n"); + fclose(f); + return GE_FALSE; + } + + // Load Patche receivers + for (i=0; i< NumPatches; i++) + { + int32 NumReceivers; + + // Load the number of receivers for this patch + if (fread(&NumReceivers, sizeof(int32), 1, f) != 1) + { + GHook.Error("LoadReceiverFile: Could not load num receivers...\n"); + fclose(f); + return GE_FALSE; + } + + PatchList[i]->Receivers = GE_RAM_ALLOCATE_ARRAY(RAD_Receiver,NumReceivers); + + if (!PatchList[i]->Receivers) + { + GHook.Error("LoadReceiverFile: Out of memory for receivers.\n"); + FreeReceivers(); + return GE_FALSE; + } + + PatchList[i]->NumReceivers = (uint16)NumReceivers; + + // Load the actual receivers + if (fread(PatchList[i]->Receivers, sizeof(RAD_Receiver), NumReceivers, f) != (uint32)NumReceivers) + { + GHook.Error("SaveReceiverFile: Could not save receivers...\n"); + fclose(f); + return GE_FALSE; + } + } + + return GE_TRUE; +} diff --git a/GBSPLib/TEXTURE.CPP b/GBSPLib/TEXTURE.CPP new file mode 100644 index 0000000..0366250 --- /dev/null +++ b/GBSPLib/TEXTURE.CPP @@ -0,0 +1,445 @@ +/****************************************************************************************/ +/* Texture.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: This code keeps a list of shared textures. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include +#include + +#include "Map.h" +#include "BSP.h" +#include "Texture.h" +#include "Utils.h" + +#include "vfile.h" +#include "bitmap.h" +#include "ram.h" + +int32 NumTextures; +GFX_Texture Textures[MAX_MAP_TEXTURES]; +int32 NumTexInfo; +GFX_TexInfo TexInfo[MAX_MAP_TEXINFO]; + +typedef struct NamedBitmap +{ + char * Name; + geBitmap * Bitmap; +} NamedBitmap; + +static int NumBitmaps; +static NamedBitmap * Bitmaps; + +//======================================================================================== +// FindTextureIndex +//======================================================================================== +int32 FindTextureIndex(char *Name, uint32 Flags) +{ + int32 i; + + for (i=0; i< NumTextures; i++) + { + if (!stricmp(Name, Textures[i].Name) && Textures[i].Flags == Flags) + return i; + } + + if (NumTextures >= MAX_MAP_TEXTURES) + { + GHook.Error("FindTextureIndex: Too many Textures in map."); + return -1; + } + + strcpy(Textures[NumTextures].Name, Name); + Textures[NumTextures].Flags = Flags; + + NumTextures++; + + //Hook.Printf("Adding Texture: %s\n", Name); + + return(NumTextures-1); +} + +int32 NumSurfaceLights; + +//======================================================================================== +// FindTexInfo +//======================================================================================== +int32 FindTexInfo(GFX_TexInfo *Tex2) +{ + int32 i; + GFX_TexInfo *Tex1; + + if ((Tex2->Flags & TEXINFO_FLAT)) + Tex2->Flags |= TEXINFO_GOURAUD; + + if (Tex2->Flags & TEXINFO_SKY) // Force sky to fullbright + Tex2->Flags |= TEXINFO_FULLBRIGHT; + + if ((Tex2->Flags & TEXINFO_SKY) || (Tex2->Flags & TEXINFO_FULLBRIGHT)) + Tex2->Flags |= TEXINFO_NO_LIGHTMAP; + + if ((Tex2->Flags & TEXINFO_GOURAUD)) + Tex2->Flags |= TEXINFO_NO_LIGHTMAP; + + for (i=0; i< NumTexInfo; i++) + { + Tex1 = &TexInfo[i]; + + if (Tex1->Vecs[0].X == Tex2->Vecs[0].X) + if (Tex1->Vecs[0].Y == Tex2->Vecs[0].Y) + if (Tex1->Vecs[0].Z == Tex2->Vecs[0].Z) + if (Tex1->Vecs[1].X == Tex2->Vecs[1].X) + if (Tex1->Vecs[1].Y == Tex2->Vecs[1].Y) + if (Tex1->Vecs[1].Z == Tex2->Vecs[1].Z) + if (Tex1->Shift[0] == Tex2->Shift[0]) + if (Tex1->Shift[1] == Tex2->Shift[1]) + if (Tex1->DrawScale[0] == Tex2->DrawScale[0]) + if (Tex1->DrawScale[1] == Tex2->DrawScale[1]) + if (Tex1->Flags == Tex2->Flags) + if (Tex1->FaceLight == Tex2->FaceLight) + if (Tex1->ReflectiveScale == Tex2->ReflectiveScale) + if (Tex1->Alpha == Tex2->Alpha) + if (Tex1->MipMapBias == Tex2->MipMapBias) + if (Tex1->Texture == Tex2->Texture) + return i; + } + + if (NumTexInfo >= MAX_MAP_TEXINFO) + { + GHook.Error("FindTexInfo: Too much texture information...\n"); + return -1; + } + + TexInfo[i] = *Tex2; + NumTexInfo++; + + return i; +} + +geBoolean InitTextureLib(char *FileName) +{ + char Buff[_MAX_PATH]; + geVFile * VFS; + geVFile_Finder * Finder; + int i; + + Finder = NULL; + + strcpy(Buff, FileName); + StripExtension(Buff); + DefaultExtension(Buff, ".txl"); + + VFS = geVFile_OpenNewSystem(NULL, + GE_VFILE_TYPE_VIRTUAL, + Buff, + NULL, + GE_VFILE_OPEN_DIRECTORY | GE_VFILE_OPEN_READONLY); + if (!VFS) + goto fail; + + Finder = geVFile_CreateFinder(VFS, "*.*"); + if (!Finder) + goto fail; + + i = 0; + while (geVFile_FinderGetNextFile(Finder) == GE_TRUE) + { + i++; + } + + geVFile_DestroyFinder(Finder); + + Finder = geVFile_CreateFinder(VFS, "*.*"); + + if (!Finder) + goto fail; + + NumBitmaps = i; + Bitmaps = (NamedBitmap *)geRam_Allocate(sizeof(*Bitmaps) * NumBitmaps); + + if (!Bitmaps) + goto fail; + + memset(Bitmaps, 0, sizeof(*Bitmaps) * NumBitmaps); + + i = 0; + while (geVFile_FinderGetNextFile(Finder) == GE_TRUE) + { + geVFile_Properties Properties; + geVFile * File; + + geVFile_FinderGetProperties(Finder, &Properties); + Bitmaps[i].Name = strdup(Properties.Name); + if (!Bitmaps[i].Name) + { +// GHook.Error("InitTextures: 5 Unable to load texture library '%s'.\n", Buff); + goto fail; + } + File = geVFile_Open(VFS, Properties.Name, GE_VFILE_OPEN_READONLY); + if (!File) + { + GHook.Error("InitTextures: Unable to load texture file '%s'.\n", Properties.Name); + goto fail; + } + Bitmaps[i].Bitmap = geBitmap_CreateFromFile(File); + geVFile_Close(File); + if (!Bitmaps[i].Bitmap) + { + GHook.Error("InitTextures: Unable to load texture '%s'.\n", Properties.Name); + goto fail; + } +// GHook.Printf("InitTextures: Loaded texture '%s'.\n", Properties.Name); + i++; + } + + geVFile_Close(VFS); + return GE_TRUE; + +fail: + if (VFS) + geVFile_Close(VFS); + + if (Finder) + geVFile_DestroyFinder(Finder); + + ShutdownTextureLib(); + + GHook.Error("InitTextures: Unable to load texture library '%s'.\n", Buff); + + return GE_FALSE; +} + +//======================================================================================== +//======================================================================================== +void ShutdownTextureLib(void) +{ + if (Bitmaps) + { + int i; + + for (i = 0; i < NumBitmaps; i++) + { + if (Bitmaps[i].Name) + free(Bitmaps[i].Name); + if (Bitmaps[i].Bitmap) + geBitmap_Destroy(&Bitmaps[i].Bitmap); + } + geRam_Free(Bitmaps); + Bitmaps = NULL; + } + + NumBitmaps = 0; +} + +static NamedBitmap * FindBitmapByName(const char *Name) +{ + if (Bitmaps) + { + int i; + + for (i = 0; i < NumBitmaps; i++) + { + if (!stricmp(Bitmaps[i].Name, Name)) + { + return &Bitmaps[i]; + } + } + } + + return NULL; +} + +// added transparent textures +geBoolean HasTextureAlpha(char *Name) +{ + geBitmap * Image; + NamedBitmap * Bitmap; + + Bitmap = FindBitmapByName(Name); + + if (Bitmap == NULL) + { + GHook.Printf("Could not find texture alpha'%s' in texture library.\n", Name); + if (!Bitmaps) + { + GHook.Error("Could not find any textures in texture library.\n"); + return GE_FALSE; + } + + assert(NumBitmaps > 0); + + Name = Bitmaps[0].Name; + Image = Bitmaps[0].Bitmap; + } + else + { + Image = Bitmap->Bitmap; + } + + return geBitmap_HasAlpha(Image); +} +// end transparent textures + +//======================================================================================== +//======================================================================================== +geBoolean GetTexture(char *Name, uint8 *Data, int32 *Size, int32 *Width, int32 *Height, geVFile *f) +{ + int32 i; + geBitmap * Image; + NamedBitmap * Bitmap; + + Bitmap = FindBitmapByName(Name); + + if (Bitmap == NULL) + { + GHook.Printf("Could not find texture '%s' in texture library.\n", Name); + if (!Bitmaps) + { + GHook.Error("Could not find any textures in texture library.\n"); + return GE_FALSE; + } + + assert(NumBitmaps > 0); + + Name = Bitmaps[0].Name; + Image = Bitmaps[0].Bitmap; + } + else + { + Image = Bitmap->Bitmap; + } + + //GHook.Printf("%s\n", Name); + + *Width = geBitmap_Width(Image); + *Height = geBitmap_Height(Image); + + if (*Width > 256 || *Height > 256) + { + GHook.Error("Texture '%s' has a dimension bigger than 256.\n", Name); + return GE_FALSE; + } + + *Size = 0; + geBitmap_UpdateMips(Image, 0, 1); + geBitmap_UpdateMips(Image, 1, 2); + geBitmap_UpdateMips(Image, 2, 3); +// added transparent textures - only 1 mip sent + for (i = 0; i < 1; i++) + { + int MipWidth; + int MipHeight; + geBitmap * LockedImage; + void * Bits; + +//Start Dec2001DCS +// added transparent textures + if(geBitmap_LockForRead(Image, &LockedImage, i, i, GE_PIXELFORMAT_32BIT_ARGB, GE_TRUE, 0xffff00ff) == GE_FALSE) +//End Dec2001DCS + { + GHook.Error("Could not get mip level %d for texture '%s'.\n", i, Name); + return GE_FALSE; + } + + Bits = geBitmap_GetBits(LockedImage); + if (!Bits) + { + GHook.Error("Could not get mip bits for texture '%s'.\n", i, Name); + return GE_FALSE; + } + + MipWidth = *Width / (1 << i); + MipHeight = *Height / (1 << i); + +//Start Dec2001DCS - Added * 4 since textures are now 32 bit +// added transparent textures + if (geVFile_Write(f, Bits, MipWidth * MipHeight * 4) != GE_TRUE) +//End Dec2001DCS + { + GHook.Error("Could not write texture data.\n"); + return GE_FALSE; + } + + geBitmap_UnLock(LockedImage); + +//Start Dec2001DCS - Added * 4 since textures are now 32 bit +// added transparent textures + *Size += MipWidth * MipHeight * 4; +//End Dec2001DCS + } + + return GE_TRUE; +} + +geBoolean GetTexturePalette(const char *Name, DRV_Palette Palette) +{ + geBitmap * Image; + NamedBitmap * Bitmap; + geBitmap_Palette * ImagePalette; + int i; + + assert(Name != NULL); + assert(Palette != NULL); + + Bitmap = FindBitmapByName(Name); + + if (Bitmap == NULL) + { + GHook.Printf("Could not find texture '%s' in texture library.\n", Name); + if (!Bitmaps) + { + GHook.Error("Could not find any textures in texture library.\n"); + return GE_FALSE; + } + + Name = Bitmaps[0].Name; + Image = Bitmaps[0].Bitmap; + } + else + { + Image = Bitmap->Bitmap; + } + + ImagePalette = geBitmap_GetPalette(Image); + if (!ImagePalette) + { +//Start Dec2001DCS +// GHook.Error("Could not find get pallette for texture '%s'.\n", Name); +// return GE_FALSE; +// No palette found is not an error anymore - 24 bit color bitmaps do not have a palette + return GE_TRUE; +//End Dec2001DCS + } + + for (i = 0; i < 255; i++) + { + int A; + int R; + int G; + int B; + geBitmap_Palette_GetEntryColor(ImagePalette, i, &R, &G, &B, &A); + Palette[i].r = R; + Palette[i].g = G; + Palette[i].b = B; + } + + return GE_TRUE; +} + diff --git a/GBSPLib/TEXTURE.H b/GBSPLib/TEXTURE.H new file mode 100644 index 0000000..34436f8 --- /dev/null +++ b/GBSPLib/TEXTURE.H @@ -0,0 +1,62 @@ +/****************************************************************************************/ +/* Texture.h */ +/* */ +/* Author: John Pollard */ +/* Description: This code keeps a list of shared textures. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef TEXTURE_H +#define TEXTURE_H + +//#include + +#include +#include "Map.h" +#include "DCommon.h" +#include "GBSPFile.h" +#include "VFile.h" + +#define TEXTURE_SKYBOX (1<<0) + +// Don't let this naming convention full you. TEXINFO is just everything about a face, that could be +// shared with another face or more... +#define TEXINFO_MIRROR (1<<0) // This face is a mirror face +#define TEXINFO_FULLBRIGHT (1<<1) // This face is fully bright +#define TEXINFO_SKY (1<<2) // This face is a sky portal +#define TEXINFO_LIGHT (1<<3) // This face emits light +#define TEXINFO_TRANS (1<<4) // A hint to the engine, that this face is not solid +#define TEXINFO_GOURAUD (1<<5) // This face is gouraud shaded +#define TEXINFO_FLAT (1<<6) // This face is flat shaded +#define TEXINFO_NO_LIGHTMAP (1<<15) // This face does not have a lightmap + +geBoolean InitTextureLib(char *File); +void ShutdownTextureLib(void); +geBoolean GetTexture(char *Name, uint8 *Data, int32 *Size, int32 *Width, int32 *Height, geVFile *f); +geBoolean GetTexturePalette(const char *Name, DRV_Palette Palette); + +extern int32 NumTextures; +extern GFX_Texture Textures[MAX_MAP_TEXTURES]; +extern int32 NumTexInfo; +extern GFX_TexInfo TexInfo[MAX_MAP_TEXINFO]; + +int32 FindTextureIndex(char *Name, uint32 Flags); +int32 FindTexInfo(GFX_TexInfo *Tex2); +// added transparent textures +geBoolean HasTextureAlpha(char *Name); +// end transparent textures + +#endif diff --git a/GBSPLib/TJunct.cpp b/GBSPLib/TJunct.cpp new file mode 100644 index 0000000..c7bc885 --- /dev/null +++ b/GBSPLib/TJunct.cpp @@ -0,0 +1,512 @@ +/****************************************************************************************/ +/* TJunct.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Removes T-Juncts */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "BSP.h" +#include "Poly.h" +#include "Texture.h" + +#include "Ram.h" + +#define OFF_EPSILON 0.05f + +geBoolean FixTJuncts = GE_TRUE; + +#define MAX_TEMP_INDEX_VERTS 1024 + +int32 NumTempIndexVerts; +int32 TempIndexVerts[MAX_TEMP_INDEX_VERTS]; + +int32 NumWeldedVerts; +int32 TotalIndexVerts; +geVec3d WeldedVerts[MAX_WELDED_VERTS]; + +int32 EdgeVerts[MAX_WELDED_VERTS]; +int32 NumEdgeVerts; + +int32 NumFixedFaces; +int32 NumTJunctions; + +#define USE_HASHING + +#define HASH_SIZE 128 // Must be power of 2 +#define HASH_SIZE2 HASH_SIZE*HASH_SIZE // Squared(HASH_SIZE) +#define HASH_SHIFT 8 // Log2(HASH_SIZE)+1 + +int32 VertexChain[MAX_WELDED_VERTS]; // the next vertex in a hash chain +int32 HashVerts[HASH_SIZE*HASH_SIZE]; // a vertex number, or 0 for no verts + +//===================================================================================== +// FinalizeFace +//===================================================================================== +geBoolean FinalizeFace(GBSP_Face *Face, int32 Base) +{ + int32 i; + + TotalIndexVerts += NumTempIndexVerts; + + if (NumTempIndexVerts == Face->NumIndexVerts) + return GE_TRUE; + + if (TexInfo[Face->TexInfo].Flags & TEXINFO_MIRROR) + return GE_TRUE; + + if (TexInfo[Face->TexInfo].Flags & TEXINFO_SKY) + return GE_TRUE; + + if (Face->IndexVerts) + geRam_Free(Face->IndexVerts); + + Face->IndexVerts = GE_RAM_ALLOCATE_ARRAY(int32,NumTempIndexVerts); + + for (i=0; i< NumTempIndexVerts; i++) + Face->IndexVerts[i] = TempIndexVerts[(i+Base)%NumTempIndexVerts]; + + Face->NumIndexVerts = NumTempIndexVerts; + + NumFixedFaces++; + + return GE_TRUE; +} + +geVec3d EdgeStart; +geVec3d EdgeDir; + +geBoolean TestEdge_r(geFloat Start, geFloat End, int32 p1, int32 p2, int32 StartVert) +{ + int32 j, k; + geFloat Dist; + geVec3d Delta; + geVec3d Exact; + geVec3d Off; + geFloat Error; + geVec3d p; + + if (p1 == p2) + { + //GHook.Printf("TestEdge_r: Degenerate Edge.\n"); + return GE_TRUE; // degenerate edge + } + + for (k=StartVert ; k= End) + continue; + + geVec3d_AddScaled(&EdgeStart, &EdgeDir, Dist, &Exact); + geVec3d_Subtract(&p, &Exact, &Off); + Error = geVec3d_Length(&Off); + + if (fabs(Error) > OFF_EPSILON) + continue; + + // break the edge + NumTJunctions++; + + TestEdge_r (Start, Dist, p1, j, k+1); + TestEdge_r (Dist, End, j, p2, k+1); + + return GE_TRUE; + } + + if (NumTempIndexVerts >= MAX_TEMP_INDEX_VERTS) + { + GHook.Error("Max Temp Index Verts.\n"); + return GE_FALSE; + } + + TempIndexVerts[NumTempIndexVerts] = p1; + NumTempIndexVerts++; + + return GE_TRUE; +} + +void FindEdgeVerts(geVec3d *V1, geVec3d *V2) +{ +#ifdef USE_HASHING + int32 x1, y1, x2, y2; + int32 t, x, y, Index; + + x1 = (HASH_SIZE2 + (int32)(V1->X+0.5)) >> HASH_SHIFT; + y1 = (HASH_SIZE2 + (int32)(V1->Y+0.5)) >> HASH_SHIFT; + x2 = (HASH_SIZE2 + (int32)(V2->X+0.5)) >> HASH_SHIFT; + y2 = (HASH_SIZE2 + (int32)(V2->Y+0.5)) >> HASH_SHIFT; + + if (x1 > x2) + { + t = x1; + x1 = x2; + x2 = t; + } + if (y1 > y2) + { + t = y1; + y1 = y2; + y2 = t; + } + + NumEdgeVerts = 0; + for (x=x1 ; x <= x2 ; x++) + { + for (y=y1 ; y <= y2 ; y++) + { + for (Index = HashVerts[y*HASH_SIZE+x] ; Index ; Index = VertexChain[Index]) + { + EdgeVerts[NumEdgeVerts++] = Index; + } + } + } + +#else + int32 i; + + NumEdgeVerts = NumWeldedVerts-1; + + for (i=0; i< NumEdgeVerts; i++) + { + EdgeVerts[i] = i+1; + } +#endif + +} + +//===================================================================================== +// FixFaceTJunctions +//===================================================================================== +geBoolean FixFaceTJunctions(GBSP_Node *Node, GBSP_Face *Face) +{ + int32 i, P1, P2; + int32 Start[MAX_TEMP_INDEX_VERTS]; + int32 Count[MAX_TEMP_INDEX_VERTS]; + geVec3d Edge2; + geFloat Len; + int32 Base; + + NumTempIndexVerts = 0; + + for (i=0; i< Face->NumIndexVerts; i++) + { + P1 = Face->IndexVerts[i]; + P2 = Face->IndexVerts[(i+1)%Face->NumIndexVerts]; + + EdgeStart = WeldedVerts[P1]; + Edge2 = WeldedVerts[P2]; + + FindEdgeVerts(&EdgeStart, &Edge2); + + geVec3d_Subtract(&Edge2, &EdgeStart, &EdgeDir); + Len = geVec3d_Normalize(&EdgeDir); + + Start[i] = NumTempIndexVerts; + + TestEdge_r(0.0f, Len, P1, P2, 0); + + Count[i] = NumTempIndexVerts - Start[i]; + } + + if (NumTempIndexVerts < 3) + { + Face->NumIndexVerts = 0; + + //GHook.Printf("FixFaceTJunctions: Face collapsed.\n"); + return GE_TRUE; + } + + for (i=0 ; iNumIndexVerts; i++) + { + if (Count[i] == 1 && Count[(i+Face->NumIndexVerts-1)%Face->NumIndexVerts] == 1) + break; + } + + if (i == Face->NumIndexVerts) + { + Base = 0; + } + else + { // rotate the vertex order + Base = Start[i]; + } + + if (!FinalizeFace(Face, Base)) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// FixTJunctions_r +//===================================================================================== +geBoolean FixTJunctions_r(GBSP_Node *Node) +{ + GBSP_Face *Face, *Next; + + if (Node->PlaneNum == PLANENUM_LEAF) + return GE_TRUE; + + for (Face = Node->Faces; Face; Face = Next) + { + Next = Face->Next; + + if (Face->Merged || Face->Split[0] || Face->Split[1]) + continue; + + FixFaceTJunctions(Node, Face); + } + + if (!FixTJunctions_r(Node->Children[0])) + return GE_FALSE; + + if (!FixTJunctions_r(Node->Children[1])) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// HashVert +//===================================================================================== +int32 HashVert(geVec3d *Vert) +{ + int32 x, y; + + x = (HASH_SIZE2 + (int32)(Vert->X + 0.5)) >> HASH_SHIFT; + y = (HASH_SIZE2 + (int32)(Vert->Y + 0.5)) >> HASH_SHIFT; + + if ( x < 0 || x >= HASH_SIZE || y < 0 || y >= HASH_SIZE ) + { + GHook.Error ("HashVert: Vert outside valid range"); + return -1; + } + + return y*HASH_SIZE + x; +} + +#define INTEGRAL_EPSILON 0.01f + +//===================================================================================== +// WeldVert +//===================================================================================== +#ifdef USE_HASHING +int32 WeldVert(geVec3d *Vert) +{ + int32 i, h; + + for (i=0; i<3; i++) + if (fabs(VectorToSUB(*Vert, i) - (int32)(VectorToSUB(*Vert, i)+0.5)) < INTEGRAL_EPSILON ) + VectorToSUB(*Vert, i) = (geFloat)((int32)(VectorToSUB(*Vert, i)+0.5)); + + h = HashVert(Vert); + + if (h == -1) + return -1; + + for (i=HashVerts[h]; i; i = VertexChain[i]) + { + if (i >= MAX_WELDED_VERTS) + { + GHook.Error("WeldVert: Invalid hash vert.\n"); + return -1; + } + + if (geVec3d_Compare(Vert, &WeldedVerts[i], VCOMPARE_EPSILON)) + return i; + } + + if (NumWeldedVerts >= MAX_WELDED_VERTS) + { + GHook.Error("WeldVert: Max welded verts.\n"); + return -1; + } + + WeldedVerts[NumWeldedVerts] = *Vert; + + VertexChain[NumWeldedVerts] = HashVerts[h]; + HashVerts[h] = NumWeldedVerts; + + NumWeldedVerts++; + + return NumWeldedVerts-1; +} +#else +int32 WeldVert(geVec3d *Vert) +{ + int32 i; + geVec3d *pWeldedVerts; + + pWeldedVerts = WeldedVerts; + + for (i=0; i< NumWeldedVerts; i++) + { + if (geVec3d_Compare(Vert, pWeldedVerts, VCOMPARE_EPSILON)) + return i; + + pWeldedVerts++; + } + + if (i >= MAX_WELDED_VERTS) + { + GHook.Error("WeldVert: Max welded verts.\n"); + return -1; + } + + WeldedVerts[i] = *Vert; + + NumWeldedVerts++; + + return i; +} +#endif +//===================================================================================== +// GetFaceVertIndexNumbers +//===================================================================================== +geBoolean GetFaceVertIndexNumbers(GBSP_Face *Face) +{ + int32 i, Index; + geVec3d *Verts; + + NumTempIndexVerts = 0; + + Verts = Face->Poly->Verts; + + for (i=0; i< Face->Poly->NumVerts; i++) + { + if (NumTempIndexVerts >= MAX_TEMP_INDEX_VERTS) + { + GHook.Error("GetFaceVertIndexNumbers: Max Temp Index Verts.\n"); + return GE_FALSE; + } + + Index = WeldVert(&Verts[i]); + + if (Index == -1) + { + GHook.Error("GetFaceVertIndexNumbers: Could not FindVert.\n"); + return GE_FALSE; + } + + TempIndexVerts[NumTempIndexVerts] = Index; + NumTempIndexVerts++; + + TotalIndexVerts++; + } + + Face->NumIndexVerts = NumTempIndexVerts; + Face->IndexVerts = GE_RAM_ALLOCATE_ARRAY(int32,NumTempIndexVerts); + + if (!Face->IndexVerts) + { + GHook.Error("GetFaceVertIndexNumbers: Out of memory for index list.\n"); + return GE_FALSE; + } + + for (i=0; i < NumTempIndexVerts; i++) + Face->IndexVerts[i] = TempIndexVerts[i]; + + return GE_TRUE; +} + +//===================================================================================== +// GetFaceVertIndexNumbers_r +//===================================================================================== +geBoolean GetFaceVertIndexNumbers_r(GBSP_Node *Node) +{ + GBSP_Face *Face, *Next; + + if (Node->PlaneNum == PLANENUM_LEAF) + return GE_TRUE; + + for (Face = Node->Faces; Face; Face = Next) + { + Next = Face->Next; + + if (Face->Merged || Face->Split[0] || Face->Split[1]) + continue; + + if (!GetFaceVertIndexNumbers(Face)) + return GE_FALSE; + } + + if (!GetFaceVertIndexNumbers_r(Node->Children[0])) + return GE_FALSE; + + if (!GetFaceVertIndexNumbers_r(Node->Children[1])) + return GE_FALSE; + + return GE_TRUE; +} + +//===================================================================================== +// FixModelTJunctions +//===================================================================================== +geBoolean FixModelTJunctions(void) +{ + int32 i; + + GHook.Printf(" --- Weld Model Verts --- \n"); + + NumWeldedVerts = 0; + TotalIndexVerts = 0; + + for (i=0; i< NumBSPModels; i++) + { + + if (!GetFaceVertIndexNumbers_r(BSPModels[i].RootNode[0])) + return GE_FALSE; + } + + if (!FixTJuncts) // Skip if asked to do so... + return GE_TRUE; + + GHook.Printf(" --- Fix Model TJunctions --- \n"); + + TotalIndexVerts = 0; + + NumTJunctions = 0; + NumFixedFaces = 0; + + for (i=0; i< NumBSPModels; i++) + { + + if (!FixTJunctions_r(BSPModels[i].RootNode[0])) + return GE_FALSE; + } + + if (Verbose) + { + GHook.Printf(" Num TJunctions : %5i\n", NumTJunctions); + GHook.Printf(" Num Fixed Faces : %5i\n", NumFixedFaces); + } + + return GE_TRUE; +} \ No newline at end of file diff --git a/GBSPLib/Utils.cpp b/GBSPLib/Utils.cpp new file mode 100644 index 0000000..7b98780 --- /dev/null +++ b/GBSPLib/Utils.cpp @@ -0,0 +1,135 @@ +/****************************************************************************************/ +/* Utils.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Various handy functions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include +#include + +#include "Utils.h" +#include "Basetype.h" + +//==================================================================================== +// DefaultExtension +//==================================================================================== +void DefaultExtension (char *Path, char *Ext) +{ + char *Src; + + Src = Path + strlen(Path) - 1; + + while (*Src != PATH_SEPERATOR && Src != Path) + { + if (*Src == '.') + return; + + Src--; + } + + strcat (Path, Ext); +} + +//==================================================================================== +// StripFilename +//==================================================================================== +void StripFilename (char *Path) +{ + int32 Length; + + Length = strlen(Path)-1; + while (Length > 0 && Path[Length] != PATH_SEPERATOR) + Length--; + Path[Length] = 0; +} + +//==================================================================================== +// StripExtension +//==================================================================================== +void StripExtension (char *Path) +{ + int32 Length; + + Length = strlen(Path)-1; + while (Length > 0 && Path[Length] != '.') + { + Length--; + if (Path[Length] == '/') + return; + } + if (Length) + Path[Length] = 0; +} + + +//==================================================================================== +// ExtractFilePath +//==================================================================================== +void ExtractFilePath (char *Path, char *Dest) +{ + char *Src; + + Src = Path + strlen(Path) - 1; + + while (Src != Path && *(Src-1) != PATH_SEPERATOR) + Src--; + + memcpy (Dest, Path, Src-Path); + Dest[Src-Path] = 0; +} + +//==================================================================================== +// ExtractFileBase +//==================================================================================== +void ExtractFileBase (char *Path, char *Dest) +{ + char *Src; + + Src = Path + strlen(Path) - 1; + + while (Src != Path && *(Src-1) != PATH_SEPERATOR) + Src--; + + while (*Src && *Src != '.') + { + *Dest++ = *Src++; + } + *Dest = 0; +} + +//==================================================================================== +// ExtractFileExtension +//==================================================================================== +void ExtractFileExtension (char *Path, char *Dest) +{ + char *Src; + + Src = Path + strlen(Path) - 1; + + while (Src != Path && *(Src-1) != '.') + Src--; + if (Src == Path) + { + *Dest = 0; + return; + } + + strcpy (Dest, Src); +} + diff --git a/GBSPLib/Utils.h b/GBSPLib/Utils.h new file mode 100644 index 0000000..f6d16b3 --- /dev/null +++ b/GBSPLib/Utils.h @@ -0,0 +1,40 @@ +/****************************************************************************************/ +/* Utils.h */ +/* */ +/* Author: John Pollard */ +/* Description: Various handy functions */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef UTILS_H +#define UTILS_H + +#include + +#define PATH_SEPERATOR '/' + +// +// File name manipulation +// +void DefaultExtension (char *Path, char *Ext); +void StripFilename (char *Path); +void StripExtension (char *Path); +void ExtractFilePath (char *Path, char *Dest); +void ExtractFileBase (char *Path, char *Dest); +void ExtractFileExtension (char *Path, char *Dest); + + +#endif \ No newline at end of file diff --git a/GBSPLib/VIS.CPP b/GBSPLib/VIS.CPP new file mode 100644 index 0000000..ff34efc --- /dev/null +++ b/GBSPLib/VIS.CPP @@ -0,0 +1,675 @@ +/****************************************************************************************/ +/* Vis.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Vises a BSP */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "Utils.h" +#include "Vis.h" +#include "GBSPFile.h" +#include "Poly.h" +#include "Bsp.h" + +#include "Ram.h" + +int32 NumVisPortals; // Total portals +int32 NumVisPortalBytes; // Total portals / 8 +int32 NumVisPortalLongs; // Total portalbytes / sizeof(uint32) +VIS_Portal *VisPortals; // NumVisPortals +pVIS_Portal *VisSortedPortals; // Pointers to portals sorted by MightSee +uint8 *PortalSeen; // Temp vis array +uint8 *PortalBits; + +int32 NumVisLeafs; // Total VisLeafs +int32 NumVisLeafBytes; // NumVisLeaf / 8 +int32 NumVisLeafLongs; // NumVisBytes / sizeof(uint32) +uint8 *LeafVisBits; // Should be NumVisLeafs * (NumVisLeafs / 8) +VIS_Leaf *VisLeafs; // NumVisLeafs + +int32 TotalVisibleLeafs; + +geBoolean VisVerbose = GE_FALSE; +geBoolean NoSort = GE_FALSE; +geBoolean FullVis = GE_TRUE; + +void FreeFileVisData(void); +geBoolean StartWritingVis(geVFile *f); +geBoolean FinishWritingVis(geVFile *f); +void FreeAllVisData(void); +void SortPortals(void); +geBoolean CalcPortalInfo(VIS_Portal *Portal); + +//======================================================================================= +// VisGBSPFile +//======================================================================================= +geBoolean VisGBSPFile(char *FileName, VisParms *Parms) +{ + char PFile[200]; + geVFile *f; + + f = NULL; + + GHook.Printf(" --- Vis GBSP File --- \n"); + + NoSort = !Parms->SortPortals; + VisVerbose = Parms->Verbose; + FullVis = Parms->FullVis; + + // Fill in the global bsp data + if (!LoadGBSPFile(FileName)) + { + GHook.Error("PvsGBSPFile: Could not load GBSP file: %s\n", FileName); + goto ExitWithError; + } + + // Clean out any old vis data + FreeFileVisData(); + + // Open the bsp file for writing + f = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_DOS, FileName, NULL, GE_VFILE_OPEN_CREATE); + + if (!f) // Oops + { + GHook.Error("VisGBSPFile: Could not open GBSP file for writing: %s.\n", FileName); + goto ExitWithError; + } + + // Prepare the portal file name + strcpy(PFile, FileName); + StripExtension(PFile); + DefaultExtension(PFile, ".GPF"); + + // Load the portal file + if (!LoadPortalFile(PFile)) + goto ExitWithError; + + GHook.Printf("NumPortals : %5i\n", NumVisPortals); + + // Write out everything but vis info + if (!StartWritingVis(f)) + goto ExitWithError; + + // Vis'em + if (!VisAllLeafs()) + goto ExitWithError; + + // Record the vis data + NumGFXVisData = NumVisLeafs*NumVisLeafBytes; + GFXVisData = LeafVisBits; + + // Save the leafs, clusters, vis data, etc + if (!FinishWritingVis(f)) + goto ExitWithError; + + // Free all the vis stuff + FreeAllVisData(); + + // Free any remaining leftover bsp data + FreeGBSPFile(); + + geVFile_Close(f); + + return GE_TRUE; + + // ==== ERROR ==== + ExitWithError: + { + GHook.Error("PvsGBSPFile: Could not vis the file: %s\n", FileName); + + if (f) + geVFile_Close(f); + + FreeAllVisData(); + FreeGBSPFile(); + + return GE_FALSE; + } +} + +//======================================================================================= +// FreeFileVisData +//======================================================================================= +void FreeFileVisData(void) +{ + if (GFXVisData) + geRam_Free(GFXVisData); + GFXVisData = NULL; + NumGFXVisData = 0; +} + +int32 LeafSee; +//======================================================================================= +// VisAllLeafs +//======================================================================================= +geBoolean VisAllLeafs(void) +{ + int32 i; + + // Create PortalSeen array. This is used by Vis flooding routines + // This is deleted below... + PortalSeen = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisPortals); + + if (!PortalSeen) + goto ExitWithError; + + // Flood all the leafs with the fast method first... + for (i=0; i< NumVisLeafs; i++) + FloodLeafPortalsFast(i); + + // Check for cancel request + if (CancelRequest) + { + GHook.Printf("Cancel requested...\n"); + goto ExitWithError; + } + + // Sort the portals with MightSee + SortPortals(); + + if (FullVis) + if (!FloodPortalsSlow()) + return GE_FALSE; + + // Don't need this anymore... + geRam_Free(PortalSeen); + PortalSeen = NULL; + + LeafVisBits = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisLeafs*NumVisLeafBytes); + + if (!LeafVisBits) + { + GHook.Error("VisAllLeafs: Out of memory for LeafVisBits.\n"); + goto ExitWithError; + } + + memset(LeafVisBits, 0, NumVisLeafs*NumVisLeafBytes); + TotalVisibleLeafs = 0; + + PortalBits = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisPortalBytes); + + if (!PortalBits) + goto ExitWithError; + + for (i=0; i< NumVisLeafs; i++) + { + LeafSee = 0; + + if (!CollectLeafVisBits(i)) + goto ExitWithError; + + TotalVisibleLeafs += LeafSee; + } + geRam_Free(PortalBits); + + GHook.Printf("Total visible areas : %5i\n", TotalVisibleLeafs); + GHook.Printf("Average visible from each area: %5i\n", TotalVisibleLeafs / NumVisLeafs); + + return GE_TRUE; + + // ==== ERROR ==== + ExitWithError: + { + // Free all the global vis data + FreeAllVisData(); + + return GE_FALSE; + } +} + +//======================================================================================= +// CollectLeafVisBits +//======================================================================================= +geBoolean CollectLeafVisBits(int32 LeafNum) +{ + VIS_Portal *Portal, *SPortal; + VIS_Leaf *Leaf; + uint8 *LeafBits, *VisBits; + int32 k, Bit, SLeaf; + + Leaf = &VisLeafs[LeafNum]; + + LeafBits = &LeafVisBits[LeafNum * NumVisLeafBytes]; + + memset(PortalBits, 0, NumVisPortalBytes); + + // 'OR' all portals that this portal can see into one list + for (Portal = Leaf->Portals; Portal; Portal = Portal->Next) + { + if (Portal->FinalVisBits) // Try to use final vis info first + VisBits = Portal->FinalVisBits; + else if (Portal->VisBits) + VisBits = Portal->VisBits; + else + { + GHook.Error("No VisInfo for portal.\n"); + return GE_FALSE; + } + + for (k=0; k< NumVisPortalBytes; k++) + PortalBits[k] |= VisBits[k]; + + if (Portal->VisBits) + geRam_Free(Portal->VisBits); + if (Portal->FinalVisBits) + geRam_Free(Portal->FinalVisBits); // Don't need this anymore + + Portal->VisBits = NULL; + Portal->FinalVisBits = NULL; + } + + // Take this list, and or all leafs that each visible portal looks in to + for (k=0; k< NumVisPortals; k++) + { + if (PortalBits[k>>3] & (1<<(k&7)) ) + { + SPortal = VisPortals+k; + SLeaf = SPortal->Leaf; + LeafBits[SLeaf>>3] |= 1<<(SLeaf&7); + } + } + + Bit = 1<<(LeafNum&7); + + // He should not have seen himself (yet...) + if ((LeafBits[LeafNum>>3] & Bit)) + GHook.Printf("*WARNING* CollectLeafVisBits: Leaf:%i can see himself!\n", LeafNum); + + LeafBits[LeafNum>>3] |= Bit; // Make sure he can see himself!!! + + for (k=0; k< NumVisLeafs; k++) + { + Bit = 1<<(k&7); + if ((LeafBits[k>>3] & Bit) ) + LeafSee++; + } + + if (LeafSee == 0) + { + GHook.Error("CollectLeafVisBits: Leaf can't see nothing.\n"); + return GE_FALSE; + } + + GFXClusters[LeafNum].VisOfs = (int32)(LeafBits - LeafVisBits); + + return GE_TRUE; +} + +//======================================================================================= +// LoadPortalFile +//======================================================================================= +geBoolean LoadPortalFile(char *FileName) +{ + int32 LeafFrom, LeafTo; + VIS_Portal *pPortal; + VIS_Leaf *pLeaf; + GBSP_Poly *pPoly; + int32 i, NumVerts; + char TAG[13]; + geVFile *f; + + pPoly = NULL; + + // open the file + f = geVFile_OpenNewSystem(NULL, GE_VFILE_TYPE_DOS, FileName, NULL, GE_VFILE_OPEN_READONLY); + + if (!f) // opps + { + GHook.Error("LoadPortalFile: Could not open %s for reading.\n", FileName); + goto ExitWithError; + } + + // + // Check the TAG + // + if (geVFile_Read(f, TAG, sizeof(char) * 12) != GE_TRUE) + { + GHook.Error("LoadPortalFile: Error reading portal file TAG.\n"); + goto ExitWithError; + } + + if (strncmp(TAG, "GBSP_PRTFILE", 12)) + { + GHook.Error("LoadPortalFile: %s is not a GBSP Portal file.\n", FileName); + goto ExitWithError; + } + + // + // Get the number of portals + // + if (geVFile_Read(f, &NumVisPortals, sizeof(int32)) != GE_TRUE) + { + GHook.Error("LoadPortalFile: Error reading NumVisPortals.\n"); + goto ExitWithError; + } + + if (NumVisPortals >= MAX_TEMP_PORTALS) + { + GHook.Error("LoadPortalFile: Max portals for temp buffers.\n"); + goto ExitWithError; + } + + VisPortals = GE_RAM_ALLOCATE_ARRAY(VIS_Portal,NumVisPortals); + + if (!VisPortals) + { + GHook.Error("LoadPortalFile: Out of memory for VisPortals.\n"); + goto ExitWithError; + } + + memset(VisPortals, 0, sizeof(VIS_Portal)*NumVisPortals); + + VisSortedPortals = GE_RAM_ALLOCATE_ARRAY(pVIS_Portal,NumVisPortals); + + if (!VisSortedPortals) + { + GHook.Error("LoadPortalFile: Out of memory for VisSortedPortals.\n"); + goto ExitWithError; + } + + // + // Get the number of leafs + // + if (geVFile_Read(f, &NumVisLeafs, sizeof(int32)) != GE_TRUE) + { + GHook.Error("LoadPortalFile: Error reading NumVisLeafs.\n"); + goto ExitWithError; + } + + if (NumVisLeafs > NumGFXLeafs) + goto ExitWithError; + + VisLeafs = GE_RAM_ALLOCATE_ARRAY(VIS_Leaf,NumVisLeafs); + if (!VisLeafs) + { + GHook.Error("LoadPortalFile: Out of memory for VisLeafs.\n"); + goto ExitWithError; + } + + memset(VisLeafs, 0, sizeof(VIS_Leaf)*NumVisLeafs); + + // + // Load in the portals + // + for (i=0; i< NumVisPortals; i++) + { + if (geVFile_Read(f, &NumVerts, sizeof(int32)) != GE_TRUE) + { + GHook.Error("LoadPortalFile: Error reading NumVerts.\n"); + goto ExitWithError; + } + + pPoly = AllocPoly(NumVerts); + + if (!pPoly) + goto ExitWithError; + + if (geVFile_Read(f, pPoly->Verts, sizeof(geVec3d) * NumVerts) != GE_TRUE) + { + GHook.Error("LoadPortalFile: Error reading portal vertices.\n"); + goto ExitWithError; + } + + if (geVFile_Read(f, &LeafFrom, sizeof(int32)) != GE_TRUE) + { + GHook.Error("LoadPortalFile: Error reading portal LeafFrom.\n"); + goto ExitWithError; + } + + if (geVFile_Read(f, &LeafTo, sizeof(int32)) != GE_TRUE) + { + GHook.Error("LoadPortalFile: Error reading portal LeafTo.\n"); + goto ExitWithError; + } + + if (LeafFrom >= NumVisLeafs || LeafFrom < 0) + { + GHook.Error("LoadPortalFile: Invalid LeafFrom: %i.\n", LeafFrom); + goto ExitWithError; + } + + if (LeafTo >= NumVisLeafs || LeafTo < 0) + { + GHook.Error("LoadPortalFile: Invalid LeafTo: %i.\n", LeafTo); + goto ExitWithError; + } + + pLeaf = &VisLeafs[LeafFrom]; + pPortal = &VisPortals[i]; + + pPortal->Poly = pPoly; + pPortal->Leaf = LeafTo; + PlaneFromVerts(pPoly->Verts, &pPortal->Plane); + + pPortal->Next = pLeaf->Portals; + pLeaf->Portals = pPortal; + + CalcPortalInfo(pPortal); + } + + NumVisLeafBytes = ((NumVisLeafs+63)&~63) >> 3; + NumVisPortalBytes = ((NumVisPortals+63)&~63) >> 3; + + NumVisPortalLongs = NumVisPortalBytes/sizeof(uint32); + NumVisLeafLongs = NumVisLeafBytes/sizeof(uint32); + + geVFile_Close(f); + + return GE_TRUE; + + // ==== ERROR === + ExitWithError: + { + if (f) + geVFile_Close(f); + + if (VisPortals) + geRam_Free(VisPortals); + if (VisSortedPortals) + geRam_Free(VisSortedPortals); + if (VisLeafs) + geRam_Free(VisLeafs); + + if (pPoly) + FreePoly(pPoly); + + VisPortals = NULL; + VisSortedPortals = NULL; + VisLeafs = NULL; + pPoly = NULL; + + return GE_FALSE; + } +} + +//================================================================================ +// StartWritingVis +//================================================================================ +geBoolean StartWritingVis(geVFile *f) +{ + // Write out everything but the vis data + + GBSP_ChunkData CurrentChunkData[] = { + { GBSP_CHUNK_HEADER , sizeof(GBSP_Header) ,1 , &GBSPHeader}, + { GBSP_CHUNK_MODELS , sizeof(GFX_Model) ,NumGFXModels , GFXModels }, + { GBSP_CHUNK_NODES , sizeof(GFX_Node) ,NumGFXNodes , GFXNodes }, + { GBSP_CHUNK_PORTALS , sizeof(GFX_Portal) ,NumGFXPortals , GFXPortals}, + { GBSP_CHUNK_BNODES , sizeof(GFX_BNode) ,NumGFXBNodes , GFXBNodes }, + { GBSP_CHUNK_PLANES , sizeof(GFX_Plane) ,NumGFXPlanes , GFXPlanes }, + { GBSP_CHUNK_FACES , sizeof(GFX_Face) ,NumGFXFaces , GFXFaces }, + { GBSP_CHUNK_AREAS , sizeof(GFX_Area) ,NumGFXAreas , GFXAreas }, + { GBSP_CHUNK_AREA_PORTALS , sizeof(GFX_AreaPortal),NumGFXAreaPortals , GFXAreaPortals }, + { GBSP_CHUNK_LEAF_FACES , sizeof(int32) ,NumGFXLeafFaces, GFXLeafFaces }, + { GBSP_CHUNK_LEAF_SIDES , sizeof(GFX_LeafSide) ,NumGFXLeafSides, GFXLeafSides }, + { GBSP_CHUNK_VERTS , sizeof(geVec3d) ,NumGFXVerts , GFXVerts }, + { GBSP_CHUNK_VERT_INDEX , sizeof(int32) ,NumGFXVertIndexList , GFXVertIndexList}, + { GBSP_CHUNK_RGB_VERTS , sizeof(geVec3d) ,NumGFXRGBVerts, GFXRGBVerts }, + { GBSP_CHUNK_ENTDATA , sizeof(uint8) ,NumGFXEntData , GFXEntData}, + { GBSP_CHUNK_TEXTURES , sizeof(GFX_Texture) ,NumGFXTextures, GFXTextures}, + { GBSP_CHUNK_TEXINFO , sizeof(GFX_TexInfo) ,NumGFXTexInfo , GFXTexInfo}, + { GBSP_CHUNK_TEXDATA , sizeof(uint8) ,NumGFXTexData , GFXTexData}, + { GBSP_CHUNK_LIGHTDATA , sizeof(uint8) ,NumGFXLightData , GFXLightData}, + { GBSP_CHUNK_SKYDATA , sizeof(GFX_SkyData) ,1 , &GFXSkyData}, + { GBSP_CHUNK_PALETTES , sizeof(DRV_Palette) ,NumGFXPalettes, GFXPalettes}, + { GBSP_CHUNK_MOTIONS , sizeof(uint8) ,NumGFXMotionBytes, GFXMotionData}, + }; + + if (!WriteChunks(CurrentChunkData, sizeof(CurrentChunkData) / sizeof(CurrentChunkData[0]), f)) + { + GHook.Error("leaf StartWritingVis: Could not write ChunkData.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//================================================================================ +// FinishWritingVis +//================================================================================ +geBoolean FinishWritingVis(geVFile *f) +{ + GBSP_ChunkData ChunkDataEnd[] = { + { GBSP_CHUNK_LEAFS , sizeof(GFX_Leaf) ,NumGFXLeafs , GFXLeafs }, + { GBSP_CHUNK_CLUSTERS , sizeof(GFX_Cluster) ,NumGFXClusters, GFXClusters}, + { GBSP_CHUNK_VISDATA , sizeof(uint8) , NumGFXVisData, GFXVisData}, + { GBSP_CHUNK_END , 0 ,0 , NULL }, + }; + + if (!WriteChunks(ChunkDataEnd, 4, f)) + { + GHook.Error("FinishWritingVis: Could not write ChunkData.\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + +//================================================================================ +// FreeAllVisData +//================================================================================ +void FreeAllVisData(void) +{ + + int32 i; + + if (LeafVisBits) + geRam_Free(LeafVisBits); + LeafVisBits = NULL; + + GFXVisData = NULL; + NumGFXVisData = 0; + + if (VisPortals) + { + for (i=0; i< NumVisPortals; i++) + { + FreePoly(VisPortals[i].Poly); + + if (VisPortals[i].FinalVisBits) + geRam_Free(VisPortals[i].FinalVisBits); + + if (VisPortals[i].VisBits) + geRam_Free(VisPortals[i].VisBits); + } + + geRam_Free(VisPortals); + } + + if (VisSortedPortals) + geRam_Free(VisSortedPortals); + if (PortalSeen) + geRam_Free(PortalSeen); + if (VisLeafs) + geRam_Free(VisLeafs); + + VisPortals = NULL; + VisSortedPortals = NULL; + PortalSeen = NULL; + VisLeafs = NULL; + + FreeGBSPFile(); // Free rest of GBSP GFX data +} + +//================================================================================ +// CleanupVis +//================================================================================ +void CleanupVis(void) +{ + FreeAllVisData(); +} + +//================================================================================ +// PComp +//================================================================================ +int PComp(const void *a, const void *b) +{ + if ( (*(VIS_Portal**)a)->MightSee == (*(VIS_Portal **)b)->MightSee) + return 0; + if ( (*(VIS_Portal**)a)->MightSee < (*(VIS_Portal**)b)->MightSee) + return -1; + return 1; +} + +//================================================================================ +// SortPortals +//================================================================================ +void SortPortals(void) +{ + int i; + + for (i=0 ; iPoly; + + PolyCenter(Poly, &Portal->Center); + + BestDist = 0.0f; + + for (i=0; i< Poly->NumVerts; i++) + { + geVec3d_Subtract(&Poly->Verts[i], &Portal->Center, &Vect); + + Dist = geVec3d_Length(&Vect); + + if (Dist > BestDist) + BestDist = Dist; + } + + Portal->Radius = BestDist; + + return GE_TRUE; +} \ No newline at end of file diff --git a/GBSPLib/VISFLOOD.CPP b/GBSPLib/VISFLOOD.CPP new file mode 100644 index 0000000..3f8749a --- /dev/null +++ b/GBSPLib/VISFLOOD.CPP @@ -0,0 +1,596 @@ +/****************************************************************************************/ +/* VisFlood.cpp */ +/* */ +/* Author: John Pollard */ +/* Description: Vises a BSP */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "Utils.h" +#include "Vis.h" +#include "GBSPFile.h" +#include "Poly.h" +#include "Bsp.h" + +#include "Ram.h" + +extern int32 NumVisPortals; // Total portals +extern int32 NumVisPortalBytes; // Total portals / 8 +extern int32 NumVisPortalLongs; // Total portalbytes / 4 +extern VIS_Portal *VisPortals; // NumVisPortals +extern pVIS_Portal *VisSortedPortals; // Pointers to portals sorted by MightSee +extern uint8 *PortalSeen; // Temp vis array + +extern int32 NumVisLeafs; // Total VisLeafs +extern int32 NumVisLeafBytes; // NumVisLeaf / 8 +extern int32 NumVisLeafLongs; // NumVisBytes / sizeof(uint32) +extern uint8 *LeafVisBits; // Should be NumVisLeafs * (NumVisLeafs / 8) +extern VIS_Leaf *VisLeafs; // NumVisLeafs + +int32 CanSee; +int32 SrcLeaf; +int32 MightSee; + +extern geBoolean VisVerbose; +extern geBoolean NoSort; +extern geBoolean FullVis; + +//======================================================================================= +// FloodPortalsFast_r +//======================================================================================= +void FloodPortalsFast_r(VIS_Portal *SrcPortal, VIS_Portal *DestPortal) +{ + VIS_Leaf *Leaf; + VIS_Portal *Portal; + int32 LeafNum; + int32 PNum; + + PNum = (int32)(DestPortal - VisPortals); + + if (CancelRequest) + return; + + if (PortalSeen[PNum]) + return; + + PortalSeen[PNum] = 1; + + // Add the portal that we are Flooding into, to the original portals visbits + LeafNum = DestPortal->Leaf; + + int32 Bit = 1<<(PNum&7); + if (!(SrcPortal->VisBits[PNum>>3] & Bit)) + { + SrcPortal->VisBits[PNum>>3] |= Bit; + SrcPortal->MightSee++; + VisLeafs[SrcLeaf].MightSee++; + MightSee++; + } + + Leaf = &VisLeafs[LeafNum]; + // Now, try and Flood into the leafs that this portal touches + for (Portal = Leaf->Portals; Portal; Portal = Portal->Next) + { + // If SrcPortal can see this Portal, flood into it... + if (PortalCanSeePortal(SrcPortal, Portal)) + FloodPortalsFast_r(SrcPortal, Portal); + } +} + +//======================================================================================= +// FloodLeafPortalsFast +//======================================================================================= +void FloodLeafPortalsFast(int32 LeafNum) +{ + VIS_Leaf *Leaf; + VIS_Portal *Portal; + int32 PNum; + + Leaf = &VisLeafs[LeafNum]; + + if (!Leaf->Portals) + { + //GHook.Printf("*WARNING* FloodLeafPortalsFast: Leaf with no portals.\n"); + return; + } + + SrcLeaf = LeafNum; + + for (Portal = Leaf->Portals; Portal; Portal = Portal->Next) + { + Portal->VisBits = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisPortalBytes); + + // This portal can't see anyone yet... + memset(Portal->VisBits, 0, NumVisPortalBytes); + memset(PortalSeen, 0, NumVisPortals); + + MightSee = 0; + + FloodPortalsFast_r(Portal, Portal); + + PNum = (int32)(Portal - VisPortals); + + //Hook.Printf("Portal: %5i - MightSee: %5i\n", PNum, MightSee); + if (CancelRequest) + return; + } +} + +geFloat PlaneDistanceFastP(geVec3d *Point, GBSP_Plane *Plane) +{ + geFloat Dist,Dist2; + Dist2 = Plane->Dist; + + switch (Plane->Type) + { + case PLANE_X: + //Dist = (Point->X - Dist2); + //break; + case PLANE_Y: + //Dist = (Point->Y - Dist2); + //break; + case PLANE_Z: + //Dist = (Point->Z - Dist2); + //break; + default: + Dist = geVec3d_DotProduct(Point, &Plane->Normal) - Dist2; + break; + } + + return Dist; +} + +//======================================================================================= +// PortalCanSeePortal +// See if Portal1 can see into Portal2 +// (Quick, does not take into acount of other leafs blocking path) +//======================================================================================= +geBoolean PortalCanSeePortal(VIS_Portal *Portal1, VIS_Portal *Portal2) +{ + int32 i; + GBSP_Poly *Poly; + GBSP_Plane *pPlane; + geVec3d *pVert; + geFloat Dist; + + // Check first portal + Poly = Portal1->Poly; + pVert = Poly->Verts; + pPlane = &Portal2->Plane; + + for (i=0; i< Poly->NumVerts; i++) + { + Dist = PlaneDistanceFastP(pVert, pPlane); + + if (Dist < -ON_EPSILON) + break; + + pVert++; + } + + if (i == Poly->NumVerts) + return GE_FALSE; // No points of Portal1 behind Portal2, can't possibly see + + // Check second portal + Poly = Portal2->Poly; + pVert = Poly->Verts; + + pPlane = &Portal1->Plane; + + for (i=0; i< Poly->NumVerts; i++) + { + Dist = PlaneDistanceFastP(pVert, pPlane); + + if (Dist > ON_EPSILON) + break; + + pVert++; + } + + if (i == Poly->NumVerts) + return GE_FALSE; // No points of Portal2 in front of Portal1, can't possibly see + + return GE_TRUE; // It can see through it!!! +} + + +//======================================================================================= +// ClipToSeperators +//======================================================================================= +geBoolean ClipToSeperators (GBSP_Poly *Source, GBSP_Poly *Pass, GBSP_Poly *Target, geBoolean FlipClip, GBSP_Poly **Dest) +{ + int32 i, j, k, l; + GBSP_Plane Plane; + geVec3d v1, v2; + geFloat d; + geFloat Length; + int32 Counts[3]; + geBoolean FlipTest; + + for (i=0 ; iNumVerts ; i++) + { + l = (i+1)%Source->NumVerts; + geVec3d_Subtract(&Source->Verts[l] , &Source->Verts[i], &v1); + + for (j=0 ; jNumVerts ; j++) + { + geVec3d_Subtract(&Pass->Verts[j], &Source->Verts[i], &v2); + + geVec3d_CrossProduct(&v1, &v2, &Plane.Normal); + + Length = geVec3d_Normalize(&Plane.Normal); + + if (Length < ON_EPSILON) + continue; + + Plane.Dist = geVec3d_DotProduct(&Pass->Verts[j], &Plane.Normal); + + #if 1 + FlipTest = GE_FALSE; + for (k=0 ; kNumVerts ; k++) + { + if (k == i || k == l) + continue; + + d = geVec3d_DotProduct(&Source->Verts[k], &Plane.Normal) - Plane.Dist; + if (d < -ON_EPSILON) + { + FlipTest = GE_FALSE; + break; + } + else if (d > ON_EPSILON) + { + FlipTest = GE_TRUE; + break; + } + } + if (k == Source->NumVerts) + continue; +#else + FlipTest = FlipClip; +#endif + if (FlipTest) + { + geVec3d_Inverse(&Plane.Normal); + Plane.Dist = -Plane.Dist; + } +#if 1 + Counts[0] = Counts[1] = Counts[2] = 0; + + for (k=0 ; kNumVerts ; k++) + { + if (k==j) + continue; + d = geVec3d_DotProduct(&Pass->Verts[k], &Plane.Normal) - Plane.Dist; + if (d < -ON_EPSILON) + break; + else if (d > ON_EPSILON) + Counts[0]++; + else + Counts[2]++; + } + if (k != Pass->NumVerts) + continue; + + if (!Counts[0]) + continue; +#else + k = (j+1)%Pass->NumVerts; + d = geVec3d_DotProduct(&Pass->Verts[k], &Plane.Normal) - Plane.Dist; + if (d < -ON_EPSILON) + continue; + k = (j+Pass->NumVerts-1)%Pass->NumVerts; + d = geVec3d_DotProduct(&Pass->Verts[k], &Plane.Normal) - Plane.Dist; + if (d < -ON_EPSILON) + continue; +#endif + if (!ClipPoly(Target, &Plane, FlipClip, &Target)) + { + GHook.Error("ClipToPortals: Error clipping portal.\n"); + return GE_FALSE; + } + + if (!Target) + { + *Dest = NULL; + return GE_TRUE; + } + } + } + + *Dest = Target; + return GE_TRUE; +} + +//======================================================================================= +// FloodPortalsSlow_r +//======================================================================================= +geBoolean FloodPortalsSlow_r(VIS_Portal *SrcPortal, VIS_Portal *DestPortal, VIS_PStack *PrevStack) +{ + VIS_Leaf *Leaf; + VIS_Portal *Portal; + int32 LeafNum, j; + int32 PNum; + uint32 *Test, *Might, *Vis, More; + VIS_PStack Stack; + + PNum = (int32)(DestPortal - VisPortals); + + if (CancelRequest) + { + GHook.Printf("Cancel requested...\n"); + return GE_FALSE; + } + + //if (PortalSeen[PNum]) + // return GE_TRUE; + //PortalSeen[PNum] = 1; + + // Add the portal that we are Flooding into, to the original portals visbits + int32 Bit = 1<<(PNum&7); + if (!(SrcPortal->FinalVisBits[PNum>>3] & Bit)) + { + SrcPortal->FinalVisBits[PNum>>3] |= Bit; + SrcPortal->CanSee++; + VisLeafs[SrcLeaf].CanSee++; + CanSee++; + } + + // Get the leaf that this portal looks into, and flood from there + LeafNum = DestPortal->Leaf; + Leaf = &VisLeafs[LeafNum]; + + Might = (uint32*)Stack.VisBits; + Vis = (uint32*)SrcPortal->FinalVisBits; + + // Now, try and Flood into the leafs that this portal touches + for (Portal = Leaf->Portals; Portal; Portal = Portal->Next) + { + PNum = (int32)(Portal - VisPortals); + Bit = 1<<(PNum&7); + + //GHook.Printf("PrevStack VisBits: %i\n", PrevStack->VisBits[PNum>>3]); + + // If might see could'nt see it, then don't worry about it + if (!(SrcPortal->VisBits[PNum>>3] & Bit)) + continue; + + if (!(PrevStack->VisBits[PNum>>3] & Bit)) + continue; // Can't possibly see it + + // If the portal can't see anything we haven't allready seen, skip it + if (Portal->Done) + Test = (uint32*)Portal->FinalVisBits; + else + Test = (uint32*)Portal->VisBits; + + More = 0; + for (j=0 ; jVisBits)[j] & Test[j]; + More |= (Might[j] & ~Vis[j]); + } + + if (!More && (SrcPortal->FinalVisBits[PNum>>3] & Bit) ) // Can't see anything new + continue; + + // Setup Source/Pass + if (!CopyPoly(Portal->Poly, &Stack.Pass)) + return GE_FALSE; + + #if 0 + geFloat Dist; + + Dist = geVec3d_DotProduct(&Portal->Center, &SrcPortal->Plane.Normal) - SrcPortal->Plane.Dist; + + if (Dist < -Portal->Radius) // Totally behind + continue; + else if (Dist < Portal->Radius) + { + if (!ClipPoly(Stack.Pass, &SrcPortal->Plane, GE_FALSE, &Stack.Pass)) + return GE_FALSE; + if (!Stack.Pass) + continue; + } + #else + // Cut away portion of pass portal we can't see through + if (!ClipPoly(Stack.Pass, &SrcPortal->Plane, GE_FALSE, &Stack.Pass)) + return GE_FALSE; + if (!Stack.Pass) + continue; + #endif + + if (!CopyPoly(PrevStack->Source, &Stack.Source)) + return GE_FALSE; + + #if 0 + Dist = geVec3d_DotProduct(&SrcPortal->Center, &Portal->Plane.Normal) - Portal->Plane.Dist; + + if (Dist > Portal->Radius) // Totally behind + continue; + else if (Dist > -Portal->Radius) + { + if (!ClipPoly(Stack.Source, &Portal->Plane, GE_TRUE, &Stack.Source)) + return GE_FALSE; + if (!Stack.Source) + { + FreePoly(Stack.Pass); + continue; + } + } + #else + // Also, Cut away portion of source portal that can't be seen through pass + if (!ClipPoly(Stack.Source, &Portal->Plane, GE_TRUE, &Stack.Source)) + return GE_FALSE; + if (!Stack.Source) + { + FreePoly(Stack.Pass); + continue; + } + #endif + + // If we don't have a PrevStack->Pass, then we don't have enough to look through. + // This portal can only be blocked by VisBits (Above test)... + if (!PrevStack->Pass) + { + if (!FloodPortalsSlow_r(SrcPortal, Portal, &Stack)) + return GE_FALSE; + + FreePoly(Stack.Source); + FreePoly(Stack.Pass); + continue; + } + + if (!ClipToSeperators(Stack.Source, PrevStack->Pass, Stack.Pass, GE_FALSE, &Stack.Pass)) + return GE_FALSE; + + if (!Stack.Pass) + { + FreePoly(Stack.Source); + continue; + } + + #if 1 + if (!ClipToSeperators(PrevStack->Pass, Stack.Source, Stack.Pass, GE_TRUE, &Stack.Pass)) + return GE_FALSE; + if (!Stack.Pass) + { + FreePoly(Stack.Source); + continue; + } + #else + /* + if (!ClipToSeperators(Stack.Source, PrevStack->Pass, Stack.Source, GE_TRUE, &Stack.Source)) + return GE_FALSE; + + if (!Stack.Source) + { + FreePoly(Stack.Pass); + continue; + } + */ + #endif + // Flood into it... + if (!FloodPortalsSlow_r(SrcPortal, Portal, &Stack)) + return GE_FALSE; + + FreePoly(Stack.Source); + FreePoly(Stack.Pass); + } + + return GE_TRUE; +} + +//======================================================================================= +// FloodLeafPortalsSlow +//======================================================================================= +geBoolean FloodLeafPortalsSlow(int32 LeafNum) +{ + VIS_Leaf *Leaf; + VIS_Portal *Portal; + int32 PNum; + VIS_PStack PStack; + int32 i; + + Leaf = &VisLeafs[LeafNum]; + + if (!Leaf->Portals) + { + //GHook.Printf("*WARNING* FloodLeafPortalsFast: Leaf with no portals.\n"); + return GE_TRUE; + } + + SrcLeaf = LeafNum; + for (Portal = Leaf->Portals; Portal; Portal = Portal->Next) + { + Portal->FinalVisBits = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisPortalBytes); + + // This portal can't see anyone yet... + memset(Portal->FinalVisBits, 0, NumVisPortalBytes); + memset(PortalSeen, 0, NumVisPortals); + + CanSee = 0; + + for (i=0; i< NumVisPortalBytes; i++) + PStack.VisBits[i] = Portal->VisBits[i]; + + // Setup Source/Pass + if (!CopyPoly(Portal->Poly, &PStack.Source)) + return GE_FALSE; + PStack.Pass = NULL; + + if (!FloodPortalsSlow_r(Portal, Portal, &PStack)) + return GE_FALSE; + + Portal->Done = GE_TRUE; + + PNum = (int32)(Portal - VisPortals); + //Hook.Printf("Portal: %5i - MightSee: %5i\n", PNum, MightSee); + } + + return GE_TRUE; +} + +//======================================================================================= +// FloodPortalsSlow +//======================================================================================= +geBoolean FloodPortalsSlow(void) +{ + VIS_Portal *Portal; + int32 PNum; + VIS_PStack PStack; + int32 i, k; + + for (k=0; k< NumVisPortals; k++) + VisPortals[k].Done = GE_FALSE; + + for (k=0; k< NumVisPortals; k++) + { + Portal = VisSortedPortals[k]; + + Portal->FinalVisBits = GE_RAM_ALLOCATE_ARRAY(uint8,NumVisPortalBytes); + + // This portal can't see anyone yet... + memset(Portal->FinalVisBits, 0, NumVisPortalBytes); + memset(PortalSeen, 0, NumVisPortals); + + CanSee = 0; + + for (i=0; i< NumVisPortalBytes; i++) + PStack.VisBits[i] = Portal->VisBits[i]; + + // Setup Source/Pass + if (!CopyPoly(Portal->Poly, &PStack.Source)) + return GE_FALSE; + PStack.Pass = NULL; + + if (!FloodPortalsSlow_r(Portal, Portal, &PStack)) + return GE_FALSE; + + FreePoly(PStack.Source); + + Portal->Done = GE_TRUE; + + PNum = (int32)(Portal - VisPortals); + if (VisVerbose) + GHook.Printf("Portal: %4i - Fast Vis: %4i, Full Vis: %4i\n", k+1, Portal->MightSee, Portal->CanSee); + } + + return GE_TRUE; +} diff --git a/GBSPLib/Vis.h b/GBSPLib/Vis.h new file mode 100644 index 0000000..3aa279b --- /dev/null +++ b/GBSPLib/Vis.h @@ -0,0 +1,82 @@ +/****************************************************************************************/ +/* Vis.h */ +/* */ +/* Author: John Pollard */ +/* Description: Vises a BSP */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef VIS_H +#define VIS_H + +#include +#include + +#include "BSP.h" +#include "GBSPFile.h" + + +typedef struct _VIS_Portal +{ + _VIS_Portal *Next; // Next portal in list + + GBSP_Poly *Poly; // Convex poly shape of portal + GBSP_Plane Plane; // Plane of portal + geVec3d Center; // Center of portal + geFloat Radius; // Radius of portal (Fromt Center to a vert) + + uint8 *VisBits; // What leafs portal might can see (byte compressed) + uint8 *FinalVisBits; // What leafs portal really can see (byte compressed) + int32 Leaf; // What leaf portal is looking directly into + int32 MightSee; + int32 CanSee; + geBoolean Done; + +} VIS_Portal, *pVIS_Portal; + +typedef struct +{ + VIS_Portal *Portals; // List of portals for this leaf + int32 MightSee; + int32 CanSee; +} VIS_Leaf; + + +#define MAX_TEMP_PORTALS 25000*2 + +typedef struct +{ + uint8 VisBits[MAX_TEMP_PORTALS/8]; + GBSP_Poly *Source; + GBSP_Poly *Pass; +} VIS_PStack; + +geBoolean VisGBSPFile(char *FileName, VisParms *Parms); + +void CleanupVis(void); + +geBoolean VisAllLeafs(void); +geBoolean CollectLeafVisBits(int32 LeafNum); +void FloodPortalsFast_r(VIS_Portal *SrcPortal, VIS_Portal *DestPortal); +void FloodLeafPortalsFast(int32 LeafNum); +geBoolean PortalCanSeePortal(VIS_Portal *Portal1, VIS_Portal *Portal2); +geBoolean LoadPortalFile(char *FileName); + +geBoolean FloodLeafPortalsSlow(int32 LeafNum); +geBoolean FloodPortalsSlow(void); + + +#endif diff --git a/GBSPLib/build.bat b/GBSPLib/build.bat new file mode 100644 index 0000000..582bda1 --- /dev/null +++ b/GBSPLib/build.bat @@ -0,0 +1,55 @@ +echo off +REM +REM There is one parameter allowed. It can be: +REM CLEAN: to erase all intermediate and target files +REM DEBUG: builds ONLY the debug versions +REM RELEASE: builds ONLY the release versions + +set BUILD_FAILURE= + + +REM Setup paths for the c compiler and it's tools. +REM (many of the tools within each target's makefile +REM are referenced via a relative path too) + +REM only set up the paths if they haven't already been setup. +if "%PATHS_SET%"== "Yes" GOTO SKIP_PATHS + +REM Need to set a path to a directory that is relative to this batch file. +REM use pathenv to output a simple batch file that resolves the relative +REM path name into a full path name. Run that batch file to set the +REM environment variable (the variable to be set is in the pathenv param list) + +bin\pathenv temp.bat MSDevDir msdev +call temp.bat +erase temp.bat +rem if errorlevel 1 goto BUILD_FAILURE + +if "%OS%" == "Windows_NT" set PATH=%MSDevDir%\BIN;%MASMDir%\BIN;%MSDevDir%\BIN\%VcOsDir%;%PATH% +if "%OS%" == "" set PATH="%MSDevDir%\BIN";%MASMDir%\BIN;"%MSDevDir%\BIN\%VcOsDir%";"%PATH%" +set INCLUDE=%DXDir%\sdk\inc;%MSDevDir%\INCLUDE;%MSDevDir%\MFC\INCLUDE;%INCLUDE% +set LIB=%DXDir%\sdk\lib;%MSDevDir%\LIB;%MSDevDir%\MFC\LIB;%LIB% +set MSDevDir= +set DXDir= +set MASMDir= +Set PATHS_SET=Yes +echo %INCLUDE% +REM goto VERY_END +:SKIP_PATHS + +REM Paths are setup. + + +REM Clean up previous build logs. +if exist buildlog\build.log goto BUILDLOG_EXISTS +mkdir buildlog +:BUILDLOG_EXISTS +echo building: > buildlog\build.log +for %%1 in (buildlog\*.*) do del %%1 +echo building: > buildlog\build.log + +echo Building Debug Version: >> buildlog\build.log +nmake -f gbsplib.mak CFG="GBSPLib - Win32 Debug" >> buildlog\build.log +echo Building Release Version: >> buildlog\build.log +nmake -f gbsplib.mak CFG="GBSPLib - Win32 Release" >> buildlog\build.log + diff --git a/GBSPLib/mssccprj.scc b/GBSPLib/mssccprj.scc new file mode 100644 index 0000000..01e5ac3 --- /dev/null +++ b/GBSPLib/mssccprj.scc @@ -0,0 +1,4 @@ +SCC = This is a Source Code Control file + +[GBSPLib.mak] +SCC_Project_Name = "$/Genesis10/Tools/GBSPLib", LVRBAAAA diff --git a/crafty102/Crafty.exe b/crafty102/Crafty.exe new file mode 100755 index 0000000000000000000000000000000000000000..fb6cb7abd10a564eaee66cb4da809f3bb27122d3 GIT binary patch literal 3391488 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

=tom?pm4<>w<@LIxO2~Q<_l<-c%F9}a0 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 literal 0 HcmV?d00001 diff --git a/G3D/Engine/Drivers/GlideDrv/GlideDrv.opt b/G3D/Engine/Drivers/GlideDrv/GlideDrv.opt new file mode 100644 index 0000000000000000000000000000000000000000..a0ccc2c2fe481a47126870b135455f6ae97b34fe GIT binary patch literal 49664 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 literal 0 HcmV?d00001 diff --git a/G3D/Engine/Drivers/GlideDrv/Render.c b/G3D/Engine/Drivers/GlideDrv/Render.c new file mode 100644 index 0000000..ace0229 --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/Render.c @@ -0,0 +1,1407 @@ +/****************************************************************************************/ +/* Render.c */ +/* */ +/* Author: John Pollard */ +/* Description: Code to render polys in glide */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include + +#include "Render.h" +#include "GMain.h" +#include "GlideDrv.h" +#include "GSpan.h" +#include "GTHandle.h" + +#define ENABLE_WIREFRAME + +#ifdef ENABLE_WIREFRAME +static int DoWireFrame = 0; +#endif + +#define MAX_LMAP_SIZE 32 + +#define SNAP_VERT(v) ( ( geFloat )( ( long )( ( v ) * 16 ) ) * 0.0625f /* 1/16 */ ) + +#define RENDER_MAX_PNTS (64) + +typedef enum +{ + ColorCombine_Undefined, + ColorCombine_Gouraud, + ColorCombine_Texture, + ColorCombine_TextureGouraud, + ColorCombine_TextureGouraudWithFog, +} Render_ColorCombine; + +typedef enum +{ + TexCombine_Undefined, + TexCombine_SinglePassGouraud, + TexCombine_SinglePassTexture, + TexCombine_SimultaneousPass, + TexCombine_PassThrough +} Render_TexCombine; + +DRV_RENDER_MODE RenderMode = RENDER_NONE; +Render_ColorCombine Render_OldColorCombine = ColorCombine_Undefined; +Render_TexCombine Render_OldTexCombine = TexCombine_Undefined; +int32 Render_HardwareMode = RENDER_UNKNOWN_MODE; +uint32 Render_HardwareFlags = 0; + +uint32 PolyMode = DRV_POLYMODE_NORMAL; + +DRV_CacheInfo CacheInfo; + +uint32 CurrentLRU; + +extern g_FogEnable; + +static FxU32 LastTextureAddr[2] = {(FxU32)-1, (FxU32)-1}; + +//========================================================================================== +// TextureSource +//========================================================================================== +void TextureSource(GrChipID_t Tmu, FxU32 startAddress, FxU32 evenOdd, GrTexInfo *info ) +{ + if (LastTextureAddr[Tmu] == startAddress) + return; + + grTexSource(Tmu, startAddress, evenOdd, info); + + LastTextureAddr[Tmu] = startAddress; +} + +//========================================================================================== +// Render_SetColorCombine +//========================================================================================== +void Render_SetColorCombine(Render_ColorCombine ColorCombine) +{ + if (Render_OldColorCombine == ColorCombine) + return; // Nothing to change + + switch(ColorCombine) + { + case ColorCombine_Gouraud: + { + guColorCombineFunction( GR_COLORCOMBINE_ITRGB); + break; + } + case ColorCombine_Texture: + { + guColorCombineFunction( GR_COLORCOMBINE_DECAL_TEXTURE); + break; + } + case ColorCombine_TextureGouraud: + { + guColorCombineFunction( GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB); + break; + } + case ColorCombine_TextureGouraudWithFog: + { + guColorCombineFunction( GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB_ADD_ALPHA); + break; + } + + default: + assert(0); + } + + Render_OldColorCombine = ColorCombine; +} + +//========================================================================================== +// Render_SetTexCombine +//========================================================================================== +void Render_SetTexCombine(Render_TexCombine TexCombine) +{ + if (Render_OldTexCombine == TexCombine) + return; // Nothing to change + + switch(TexCombine) + { + case TexCombine_SinglePassGouraud: + { + guTexCombineFunction( TMU[0], GR_TEXTURECOMBINE_ONE); + + if (g_BoardInfo.NumTMU >= 2) + guTexCombineFunction( TMU[1], GR_TEXTURECOMBINE_ZERO); + break; + } + + case TexCombine_SinglePassTexture: + { + guTexCombineFunction( TMU[0], GR_TEXTURECOMBINE_DECAL); + + if (g_BoardInfo.NumTMU >= 2) + guTexCombineFunction( TMU[1], GR_TEXTURECOMBINE_ZERO); + break; + } + + case TexCombine_SimultaneousPass: + { + assert(g_BoardInfo.NumTMU >= 2); + + guTexCombineFunction( TMU[0], GR_TEXTURECOMBINE_MULTIPLY); + guTexCombineFunction( TMU[1], GR_TEXTURECOMBINE_DECAL); + + break; + } + + case TexCombine_PassThrough: + { + assert(g_BoardInfo.NumTMU >= 2); + + guTexCombineFunction( TMU[0], GR_TEXTURECOMBINE_OTHER); + guTexCombineFunction( TMU[1], GR_TEXTURECOMBINE_DECAL); + + break; + } + + default: + assert(0); + } + + Render_OldTexCombine = TexCombine; +} + +#if 1 +//========================================================================================== +// Render_SetHardwareMode +//========================================================================================== +void Render_SetHardwareMode(int32 NewMode, uint32 NewFlags) +{ + if (NewFlags != Render_HardwareFlags) // See if the flags gave changed,,, + { + if (NewFlags & DRV_RENDER_NO_ZMASK) + grDepthBufferFunction(GR_CMP_ALWAYS); + else if (Render_HardwareFlags & DRV_RENDER_NO_ZMASK) + grDepthBufferFunction( GR_CMP_GEQUAL ); + + if (NewFlags & DRV_RENDER_NO_ZWRITE) + grDepthMask(FXFALSE); + else if (Render_HardwareFlags & DRV_RENDER_NO_ZWRITE) + grDepthMask(FXTRUE); + + if (NewFlags & DRV_RENDER_CLAMP_UV) + grTexClampMode(TMU[0], GR_TEXTURECLAMP_CLAMP,GR_TEXTURECLAMP_CLAMP); + else if (Render_HardwareFlags & DRV_RENDER_CLAMP_UV) + grTexClampMode(TMU[0], GR_TEXTURECLAMP_WRAP,GR_TEXTURECLAMP_WRAP); + } + + // Make these flags recent + Render_HardwareFlags = NewFlags; + + if (NewMode == Render_HardwareMode)// && NewFlags == Render_HardwareFlags) + return; // Nothing to change + + if (Render_HardwareMode == RENDER_DECAL_MODE) + grChromakeyMode(GR_CHROMAKEY_DISABLE); // Restore chroma key mode + + // sets up hardware mode + switch (NewMode) + { + case (RENDER_MISC_TEX_POLY_MODE): + { + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); // Bug fix thanks to Bobtree + + Render_SetColorCombine(ColorCombine_TextureGouraud); + Render_SetTexCombine(TexCombine_SinglePassTexture); + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA); + + if (g_FogEnable) + //grFogMode(GR_FOG_WITH_ITERATED_ALPHA); + grFogMode(GR_FOG_WITH_TABLE); + + break; + } + + case (RENDER_MISC_GOURAD_POLY_MODE): + { + Render_SetColorCombine(ColorCombine_Gouraud); + Render_SetTexCombine(TexCombine_SinglePassGouraud); + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_ONE, GR_BLEND_ONE); + + if (g_FogEnable) + //grFogMode(GR_FOG_WITH_ITERATED_ALPHA); + grFogMode(GR_FOG_WITH_TABLE); + + break; + } + + case (RENDER_LINES_POLY_MODE): + { + Render_SetColorCombine(ColorCombine_Gouraud); + Render_SetTexCombine(TexCombine_SinglePassGouraud); + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_ONE, GR_BLEND_ONE); + + if (g_FogEnable) + //grFogMode(GR_FOG_WITH_ITERATED_ALPHA); + grFogMode(GR_FOG_WITH_TABLE); + + break; + } + + case (RENDER_WORLD_POLY_MODE_NO_LIGHTMAP): + { + Render_SetColorCombine(ColorCombine_TextureGouraud); + Render_SetTexCombine(TexCombine_SinglePassTexture); + + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); + + grAlphaBlendFunction(GR_BLEND_ONE, GR_BLEND_ZERO, + GR_BLEND_ONE, GR_BLEND_ZERO); + + if (g_FogEnable) + //grFogMode(GR_FOG_WITH_ITERATED_ALPHA); + grFogMode(GR_FOG_WITH_TABLE); + + break; + } + + case (RENDER_WORLD_POLY_MODE): + { + Render_SetColorCombine(ColorCombine_TextureGouraud); + Render_SetTexCombine(TexCombine_SinglePassTexture); + + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); + + grAlphaBlendFunction(GR_BLEND_ONE, GR_BLEND_ZERO, + GR_BLEND_ONE, GR_BLEND_ZERO); + + if (g_FogEnable) + //grFogMode(GR_FOG_WITH_ITERATED_ALPHA | GR_FOG_ADD2); + grFogMode(GR_FOG_WITH_TABLE | GR_FOG_ADD2); + + break; + } + + case (RENDER_WORLD_TRANSPARENT_POLY_MODE): + { + Render_SetColorCombine(ColorCombine_TextureGouraud); + Render_SetTexCombine(TexCombine_SinglePassTexture); + + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); // Bug fix thanks to Bobtree + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_SRC_COLOR, GR_BLEND_DST_COLOR); + + if (g_FogEnable) + //grFogMode(GR_FOG_WITH_ITERATED_ALPHA); + grFogMode(GR_FOG_WITH_TABLE); + + break; + } + + // NOTE - IF this card has 2 TMU's, world polys AND lightmap polys will be piped through here + // Notice how Simultaneous mode is turned on when 2 TMU's are detected... -JP + case(RENDER_LIGHTMAP_POLY_MODE): + { + grTexMipMapMode( TMU[1], GR_MIPMAP_DISABLE, FXFALSE ); + + + if (g_BoardInfo.NumTMU >= 2) + { + Render_SetColorCombine(ColorCombine_TextureGouraud); + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_SRC_COLOR, GR_BLEND_DST_COLOR); + + if (g_FogEnable) + //grFogMode(GR_FOG_WITH_ITERATED_ALPHA); + grFogMode(GR_FOG_WITH_TABLE); + + Render_SetTexCombine(TexCombine_SimultaneousPass); + + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); + } + else + { + Render_SetColorCombine(ColorCombine_TextureGouraud); + + // Singlepass mode if there is onle 1 TMU + Render_SetTexCombine(TexCombine_SinglePassTexture); + + // Modulate the texture with the framebuffer + if (g_FogEnable) + { + //grFogMode(GR_FOG_WITH_ITERATED_ALPHA | GR_FOG_MULT2); + grFogMode(GR_FOG_WITH_TABLE | GR_FOG_MULT2); + + grAlphaBlendFunction( GR_BLEND_ONE, GR_BLEND_PREFOG_COLOR, + GR_BLEND_ONE, GR_BLEND_ZERO); + } + else + { + grAlphaBlendFunction( GR_BLEND_DST_COLOR, GR_BLEND_ZERO, + GR_BLEND_ONE, GR_BLEND_ZERO); + } + + // Force clamping to be on if this card only has one TMU + grTexClampMode(TMU[0], GR_TEXTURECLAMP_CLAMP,GR_TEXTURECLAMP_CLAMP); + Render_HardwareFlags |= DRV_RENDER_CLAMP_UV; + } + + break; + } + + case(RENDER_LIGHTMAP_FOG_POLY_MODE): + { + grTexMipMapMode( TMU[1], GR_MIPMAP_DISABLE, FXFALSE ); + + Render_SetColorCombine(ColorCombine_TextureGouraud); + + if (g_BoardInfo.NumTMU >= 2) + { + Render_SetTexCombine(TexCombine_PassThrough); + grTexMipMapMode(TMU[0], GR_MIPMAP_NEAREST, FXFALSE); + } + else + { + Render_SetTexCombine(TexCombine_SinglePassTexture); + } + + if (g_FogEnable) + //grFogMode(GR_FOG_WITH_ITERATED_ALPHA); + grFogMode(GR_FOG_DISABLE); + + grAlphaBlendFunction(GR_BLEND_ONE, GR_BLEND_ONE, + GR_BLEND_ONE, GR_BLEND_ONE); + + break; + } + + case (RENDER_DECAL_MODE): + { + grLfbConstantDepth(0xffff); + grLfbConstantAlpha(0xff); + grChromakeyMode(GR_CHROMAKEY_ENABLE); + grAlphaBlendFunction(GR_BLEND_ONE, GR_BLEND_ZERO, + GR_BLEND_ONE, GR_BLEND_ZERO); + + break; + } + + default: + { + assert(0); + } + } + + Render_HardwareMode = NewMode; +} +#else +//========================================================================================== +// Render_SetHardwareMode +//========================================================================================== +void Render_SetHardwareMode(int32 NewMode, uint32 NewFlags) +{ + if (NewFlags != Render_HardwareFlags) // See if the flags gave changed,,, + { + if (NewFlags & DRV_RENDER_NO_ZMASK) + grDepthBufferFunction(GR_CMP_ALWAYS); + else if (Render_HardwareFlags & DRV_RENDER_NO_ZMASK) + grDepthBufferFunction( GR_CMP_GEQUAL ); + + if (NewFlags & DRV_RENDER_NO_ZWRITE) + grDepthMask(FXFALSE); + else if (Render_HardwareFlags & DRV_RENDER_NO_ZWRITE) + grDepthMask(FXTRUE); + + if (NewFlags & DRV_RENDER_CLAMP_UV) + grTexClampMode(TMU[0], GR_TEXTURECLAMP_CLAMP,GR_TEXTURECLAMP_CLAMP); + else if (Render_HardwareFlags & DRV_RENDER_CLAMP_UV) + grTexClampMode(TMU[0], GR_TEXTURECLAMP_WRAP,GR_TEXTURECLAMP_WRAP); + } + + // Make these flags recent + Render_HardwareFlags = NewFlags; + + if (NewMode == Render_HardwareMode)// && NewFlags == Render_HardwareFlags) + return; // Nothing to change + + if (Render_HardwareMode == RENDER_DECAL_MODE) + grChromakeyMode(GR_CHROMAKEY_DISABLE); // Restore chroma key mode + + // sets up all hardware mode + switch (NewMode) + { + case (RENDER_MISC_TEX_POLY_MODE): + { + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); //Bug fix thanks to Bobtree + + guColorCombineFunction( GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB); + + if (g_BoardInfo.NumTMU >= 2) + { + grTexCombine( TMU[0], + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE ); + grTexCombine( TMU[1], + GR_COMBINE_FUNCTION_NONE, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_NONE, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE ); + } + else + { + grTexCombine( TMU[0], + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE ); + } + + //grChromakeyMode(GR_CHROMAKEY_ENABLE); + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA); + + if (Render_HardwareMode == RENDER_MISC_GOURAD_POLY_MODE) + { + grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_TEXTURE, + FXFALSE ); + } + + break; + } + case (RENDER_MISC_GOURAD_POLY_MODE): + { + guColorCombineFunction( GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB); + guTexCombineFunction( TMU[0], GR_TEXTURECOMBINE_ONE ); + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_ONE, GR_BLEND_ONE); + + //grChromakeyMode(GR_CHROMAKEY_DISABLE); + + break; + } + + case (RENDER_LINES_POLY_MODE): + { + guColorCombineFunction( GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB); + guTexCombineFunction( TMU[0], GR_TEXTURECOMBINE_ONE ); + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_ONE, GR_BLEND_ONE); + + //grChromakeyMode(GR_CHROMAKEY_DISABLE); + break; + } + + case (RENDER_WORLD_POLY_MODE_NO_LIGHTMAP): + case (RENDER_WORLD_POLY_MODE): + { + grTexCombine( TMU[0], + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE ); + + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); + + grAlphaBlendFunction(GR_BLEND_ONE, GR_BLEND_ZERO, + GR_BLEND_ONE, GR_BLEND_ZERO); + + if (Render_HardwareMode == RENDER_MISC_GOURAD_POLY_MODE) + { + grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_TEXTURE, + FXFALSE ); + } + + break; + } + + case (RENDER_WORLD_TRANSPARENT_POLY_MODE): + { + //grChromakeyMode(GR_CHROMAKEY_ENABLE); + + if (g_BoardInfo.NumTMU >= 2) + { + grTexCombine( TMU[0], + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE ); + + grTexCombine( TMU[1], + GR_COMBINE_FUNCTION_NONE, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_NONE, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE ); + } + else + { + grTexCombine( TMU[0], + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE ); + + } + + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); //Bug fix thanks to Bobtree + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_SRC_COLOR, GR_BLEND_DST_COLOR); + + if (Render_HardwareMode == RENDER_MISC_GOURAD_POLY_MODE) + { + grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_TEXTURE, + FXFALSE ); + } + + break; + } + + case(RENDER_LIGHTMAP_POLY_MODE): + { + grTexMipMapMode( TMU[1], GR_MIPMAP_DISABLE, FXFALSE ); + + //grChromakeyMode(GR_CHROMAKEY_DISABLE); + + if (g_BoardInfo.NumTMU >= 2) + { + grTexCombine(TMU[0], + GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + FXFALSE, FXFALSE ); + + // The lightmap textures (TMU[1]) will be blended locally + grTexCombine( TMU[1], + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE ); + + grAlphaBlendFunction(GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, + GR_BLEND_SRC_COLOR, GR_BLEND_DST_COLOR); + + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); + } + else + { + grAlphaBlendFunction(GR_BLEND_SRC_COLOR, GR_BLEND_DST_COLOR, + GR_BLEND_SRC_COLOR, GR_BLEND_DST_COLOR); + + // Force clamping to be on TMU0 if this is a 1 TMU board + grTexClampMode(TMU[0], GR_TEXTURECLAMP_CLAMP,GR_TEXTURECLAMP_CLAMP); + Render_HardwareFlags |= DRV_RENDER_CLAMP_UV; + } + + if (Render_HardwareMode == RENDER_MISC_GOURAD_POLY_MODE) + { + grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_TEXTURE, + FXFALSE ); + } + + break; + } + + case(RENDER_LIGHTMAP_FOG_POLY_MODE): + { + grTexMipMapMode( TMU[1], GR_MIPMAP_DISABLE, FXFALSE ); + + //grChromakeyMode(GR_CHROMAKEY_DISABLE); + + if (g_BoardInfo.NumTMU >= 2) + { + + grTexCombine(TMU[0], + GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_ONE, + GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_ONE, + FXFALSE, FXFALSE ); + + // The lightmap textures (TMU[1]) will be blended locally + grTexCombine( TMU[1], + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_ONE, + GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_ONE, + FXFALSE, FXFALSE ); + + grTexMipMapMode( TMU[0], GR_MIPMAP_NEAREST, FXFALSE); + } + + if (Render_HardwareMode == RENDER_MISC_GOURAD_POLY_MODE) + { + grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, + GR_COMBINE_FACTOR_LOCAL, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_TEXTURE, + FXFALSE ); + } + + grAlphaBlendFunction(GR_BLEND_ONE, GR_BLEND_ONE, + GR_BLEND_ONE, GR_BLEND_ONE); + + break; + } + + case (RENDER_DECAL_MODE): + { + grLfbConstantDepth(0xffff); + grLfbConstantAlpha(0xff); + grChromakeyMode(GR_CHROMAKEY_ENABLE); + grAlphaBlendFunction(GR_BLEND_ONE, GR_BLEND_ZERO, + GR_BLEND_ONE, GR_BLEND_ZERO); + + break; + } + + default: + { + assert(0); + } + } + + Render_HardwareMode = NewMode; +} +#endif + +//**************************************************************************** +// Render a regualar gouraud shaded poly +//**************************************************************************** +geBoolean DRIVERCC Render_GouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags) +{ + int32 i; + GrVertex vrtx[RENDER_MAX_PNTS]; + geFloat Alpha = Pnts->a; + + for (i = 0; i< NumPoints; i++) + { + geFloat ZRecip; + + vrtx[i].r = Pnts->r; + vrtx[i].g = Pnts->g; + vrtx[i].b = Pnts->b; + vrtx[i].a = Alpha; + + // set the SOW, TOW, and OOW values for a 1 TMU configuration TMU0 + ZRecip = (1.0f/(Pnts->z)); + vrtx[i].ooz = (65535.0f) * ZRecip; + vrtx[i].oow = ZRecip; + vrtx[i].tmuvtx[0].oow = ZRecip; + + vrtx[i].x = SNAP_VERT(Pnts->x); + vrtx[i].y = SNAP_VERT(Pnts->y); + + Pnts++; + } + + Render_SetHardwareMode(RENDER_MISC_GOURAD_POLY_MODE, Flags); + + grDrawPolygonVertexList( NumPoints, vrtx); + + GLIDEDRV.NumRenderedPolys++; + + return TRUE; +} + +//========================================================================================== +// Render_LinesPoly +//========================================================================================== +geBoolean DRIVERCC Render_LinesPoly(DRV_TLVertex *Pnts, int32 NumPoints) +{ + int32 i; + GrVertex vrtx[RENDER_MAX_PNTS]; + + for (i = 0; i< NumPoints; i++) + { + geFloat ZRecip; + + vrtx[i].r = 255.0f;//Pnts->r; + vrtx[i].g = 255.0f;//Pnts->g; + vrtx[i].b = 255.0f;//Pnts->b; + vrtx[i].a = 255.0f; + + // set the SOW, TOW, and OOW values for a 1 TMU configuration TMU0 + ZRecip = (1/(Pnts->z)); + vrtx[i].ooz = (65535.0f) / Pnts->z; + vrtx[i].oow = ZRecip; + vrtx[i].tmuvtx[0].oow = ZRecip; + + vrtx[i].x = SNAP_VERT(Pnts->x); + vrtx[i].y = SNAP_VERT(Pnts->y); + + Pnts++; + } + + Render_SetHardwareMode(RENDER_LINES_POLY_MODE, 0); + + for (i=0; i< NumPoints; i++) + { + int32 i2 = ((i+1) < NumPoints) ? (i+1) : 0; + + grDrawLine(&vrtx[i], &vrtx[i2]); + } + + GLIDEDRV.NumRenderedPolys++; + + return TRUE; +} + +//**************************************************************************** +// Render a world texture / lightmap +//**************************************************************************** +geBoolean DRIVERCC Render_WorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ + GrVertex Vrtx[RENDER_MAX_PNTS], *pVrtx; + geFloat OneOverSize_255; + geFloat ShiftU, ShiftV, ScaleU, ScaleV; + DRV_TLVertex *pPnts; + int32 i; + geFloat Alpha; + + assert(Pnts); + assert(TexInfo); + +#ifdef ENABLE_WIREFRAME + if ( DoWireFrame ) + return (Render_LinesPoly(Pnts, NumPoints)); +#endif + +#if 0 + switch (PolyMode) + { + case DRV_POLYMODE_NORMAL: + break; // Use this function + case DRV_POLYMODE_GOURAUD: + return (Render_GouraudPoly(Pnts, NumPoints, 0)); + case DRV_POLYMODE_LINES: + return (Render_LinesPoly(Pnts, NumPoints)); + } +#endif + + GLIDEDRV.NumRenderedPolys++; + + OneOverSize_255 = THandle->OneOverLogSize_255; + + // Get how much to shift U, and V for the Texture + ShiftU = TexInfo->ShiftU; + ShiftV = TexInfo->ShiftV; + ScaleU = 1.0f/TexInfo->DrawScaleU; + ScaleV = 1.0f/TexInfo->DrawScaleV; + + pPnts = Pnts; + + pVrtx = Vrtx; + +#if 0 + // Fix the uv's to be as close to the origin as possible, without affecting their appearance... + //if (pPnts->u > 1000.0f || pPnts->v > 1000.0f) + { + geFloat OneOverLogSize; + + OneOverLogSize = 1.0f / (geFloat)THandle->LogSize; + + ShiftU -= (geFloat)(((int32)(pPnts->u*ScaleU/THandle->Width))*THandle->Width); + ShiftV -= (geFloat)(((int32)(pPnts->v*ScaleV/THandle->Height))*THandle->Height); + } +#endif + + Alpha = Pnts->a; + + for (i = 0; i< NumPoints; i++) + { + geFloat ZRecip; + + pVrtx->a = Alpha; + + pVrtx->r = pPnts->r; + pVrtx->g = pPnts->g; + pVrtx->b = pPnts->b; + + ZRecip = (1.0f/(pPnts->z)); + pVrtx->ooz = 65535.0f * ZRecip; + pVrtx->oow = ZRecip; + + pVrtx->tmuvtx[0].oow = ZRecip; + pVrtx->tmuvtx[1].oow = ZRecip; + + ZRecip *= OneOverSize_255; + + pVrtx->tmuvtx[TMU[0]].sow = (pPnts->u*ScaleU + ShiftU) * ZRecip; + pVrtx->tmuvtx[TMU[0]].tow = (pPnts->v*ScaleV + ShiftV) * ZRecip; + + pVrtx->x = SNAP_VERT(pPnts->x); + pVrtx->y = SNAP_VERT(pPnts->y); + + pPnts++; + pVrtx++; + } + + + // Set the source texture for TMU 0 + SetupTexture(THandle); + + // If only 1 TMU (or no lightmap), then draw first pass poly now. + if (g_BoardInfo.NumTMU == 1 || !LInfo) + { // The lightmap will blend over it + if (Flags & DRV_RENDER_ALPHA) + Render_SetHardwareMode(RENDER_WORLD_TRANSPARENT_POLY_MODE, Flags); + else + { + if (LInfo) + Render_SetHardwareMode(RENDER_WORLD_POLY_MODE, Flags); + else + Render_SetHardwareMode(RENDER_WORLD_POLY_MODE_NO_LIGHTMAP, Flags); + } + + grDrawPolygonVertexList( NumPoints, Vrtx); + } + + if (LInfo) // If there is a lightmap, render it now, on top of the first pass poly + { + geBoolean Dynamic; + + // How much to shift u'vs back into lightmap space + ShiftU = (geFloat)LInfo->MinU-8.0f; + ShiftV = (geFloat)LInfo->MinV-8.0f; + + pPnts = Pnts; + + // Call the engine to set this sucker up, because it's visible... + GLIDEDRV.SetupLightmap(LInfo, &Dynamic); + + OneOverSize_255 = LInfo->THandle->OneOverLogSize_255; + + pVrtx = Vrtx; + + for (i = 0; i< NumPoints; i++) + { + geFloat u = pPnts->u-ShiftU; + geFloat v = pPnts->v-ShiftV; + geFloat ZRecip = pVrtx->oow * OneOverSize_255; + + pVrtx->tmuvtx[TMU[1]].sow = u*ZRecip; + pVrtx->tmuvtx[TMU[1]].tow = v*ZRecip; + pPnts++; + pVrtx++; + } + + RenderLightmapPoly(Vrtx, NumPoints, LInfo, (geBoolean)Dynamic, Flags); + } + + return TRUE; +} + +void RenderLightmapPoly(GrVertex *vrtx, int32 NumPoints, DRV_LInfo *LInfo, geBoolean Dynamic, uint32 Flags) +{ + geRDriver_THandle *THandle; + int32 l; + GCache_Slot *Slot; + + THandle = LInfo->THandle; + + Slot = SetupLMapTexture(THandle, LInfo, Dynamic, 0); + + GCache_SlotSetLRU(Slot, CurrentLRU); + TextureSource(TMU[1], GCache_SlotGetMemAddress(Slot), GR_MIPMAPLEVELMASK_BOTH, GCache_SlotGetInfo(Slot)); + + Render_SetHardwareMode(RENDER_LIGHTMAP_POLY_MODE, Flags); + + grDrawPolygonVertexList( NumPoints, vrtx); + + // Render special maps + for (l=1; l< 2; l++) + { + if (!LInfo->RGBLight[l]) + continue; + + switch(l) + { + case LMAP_TYPE_LIGHT: + DownloadLightmap(LInfo, THandle->LogSize, Slot, 0); + TextureSource(TMU[1], GCache_SlotGetMemAddress(Slot), GR_MIPMAPLEVELMASK_BOTH, GCache_SlotGetInfo(Slot)); + Render_SetHardwareMode(RENDER_LIGHTMAP_POLY_MODE, Flags); + break; + + case LMAP_TYPE_FOG: + DownloadLightmap(LInfo, THandle->LogSize, Slot, l); + TextureSource(TMU[1], GCache_SlotGetMemAddress(Slot), GR_MIPMAPLEVELMASK_BOTH, GCache_SlotGetInfo(Slot)); + Render_SetHardwareMode(RENDER_LIGHTMAP_FOG_POLY_MODE, Flags); + break; + } + + grDrawPolygonVertexList( NumPoints, vrtx); + } +} + +//********************************************************************************** +// Downloads a lightmap to the card +//********************************************************************************** +void DownloadLightmap(DRV_LInfo *LInfo, int32 Wh, GCache_Slot *Slot, int32 LMapNum) +{ + uint16 TempL[MAX_LMAP_SIZE*MAX_LMAP_SIZE]; // Temp to hold converted 565 lightmap + int32 w,h; + uint16 *pTempP = TempL; + uint8 r,g,b; + uint8 *Bits; + int32 W = LInfo->Width; + int32 H = LInfo->Height; + GrTexInfo *Info; + + //memset(TempL, 0, sizeof(uint6)*32*32); + Bits = (uint8*)LInfo->RGBLight[LMapNum]; + + for (h = 0; h< H; h++) + { + for (w = 0; w< W; w++) + { + r = *(Bits++); + g = *(Bits++); + b = *(Bits++); + + r >>= 3; + g >>= 2; + b >>= 3; + + *pTempP++ = (uint16)((r<<(11)) + (g << 5) + b); + } + pTempP += (Wh - w); + } + + Info = GCache_SlotGetInfo(Slot); + Info->data = TempL; + + GCache_UpdateSlot(LMapCache, Slot, Info); +} + + +//************************************************************************************ +// Render a misc texture poly.... +//************************************************************************************ +geBoolean DRIVERCC Render_MiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags) +{ + int32 i; + GrVertex vrtx[RENDER_MAX_PNTS]; + DRV_TLVertex *pPnt = Pnts; + geFloat Alpha, Width_255, Height_255; + +#ifdef ENABLE_WIREFRAME + if ( DoWireFrame ) + return (Render_LinesPoly(Pnts, NumPoints)); +#endif + + assert( Pnts != NULL ); + assert( NumPoints < RENDER_MAX_PNTS ); + assert( THandle != NULL ); + + { + geFloat OneOverLogSize; + + OneOverLogSize = THandle->OneOverLogSize_255; + + Width_255 = (geFloat)THandle->Width * OneOverLogSize; + Height_255 = (geFloat)THandle->Height * OneOverLogSize; + } + + Alpha = Pnts->a; + + for (i = 0; i< NumPoints; i++) + { + geFloat ZRecip; + + vrtx[i].a = Alpha; + vrtx[i].r = pPnt->r; + vrtx[i].g = pPnt->g; + vrtx[i].b = pPnt->b; + // set the SOW, TOW, and OOW values for a 1 TMU configuration TMU0 + ZRecip = (1.0f/(pPnt->z)); // 1/2 frame in this divide. + vrtx[i].ooz = (65535.0f) * ZRecip; + vrtx[i].oow = ZRecip; + vrtx[i].tmuvtx[0].oow = ZRecip; + + vrtx[i].tmuvtx[0].sow = pPnt->u * Width_255 * ZRecip; + vrtx[i].tmuvtx[0].tow = pPnt->v * Height_255 * ZRecip; + + vrtx[i].x = SNAP_VERT(pPnt->x); + vrtx[i].y = SNAP_VERT(pPnt->y); + + pPnt++; + } + + SetupTexture(THandle); + + Render_SetHardwareMode(RENDER_MISC_TEX_POLY_MODE, Flags); + + grDrawPolygonVertexList( NumPoints, vrtx); + //grAADrawPolygonVertexList( NumPoints, vrtx); + + //GLIDEDRV.NumRenderedPolys++; + + return TRUE; +} + +geRDriver_THandle *OldPalHandle; + +//============================================================================================ +// SetupTexture +//============================================================================================ +void SetupTexture(geRDriver_THandle *THandle) +{ + GTHandle_CheckTextures(); + + // Setup the palette + if (THandle->PixelFormat.PixelFormat == GE_PIXELFORMAT_8BIT) + { + assert(THandle->PalHandle); + assert(THandle->PalHandle->Data); + + // CB <> one shared palette in glide; added _UPDATE check + if ((OldPalHandle != THandle->PalHandle) || (THandle->PalHandle->Flags & THANDLE_UPDATE)) + { + grTexDownloadTable(TMU[0], GR_TEXTABLE_PALETTE, THandle->PalHandle->Data); + OldPalHandle = THandle->PalHandle; + THandle->PalHandle->Flags &= ~THANDLE_UPDATE; + } + } + + if (!THandle->Slot || GCache_SlotGetUserData(THandle->Slot) != THandle) + { + THandle->Slot = GCache_TypeFindSlot(THandle->CacheType); + assert(THandle->Slot); + + GCache_SlotSetUserData(THandle->Slot, THandle); + THandle->Flags |= THANDLE_UPDATE; + + CacheInfo.TexMisses++; + } + + if (THandle->Flags & THANDLE_UPDATE) + { + GrTexInfo *Info; + + Info = GCache_SlotGetInfo(THandle->Slot); + + // Set the data to the correct bits + Info->data = THandle->Data; + + // We must make sure the textures formats and the caches format match (formats can change on the fly) + GlideFormatFromGenesisFormat(THandle->PixelFormat.PixelFormat, &Info->format); + + GCache_UpdateSlot(TextureCache, THandle->Slot, Info); + + THandle->Flags &= ~THANDLE_UPDATE; + } + + GCache_SlotSetLRU(THandle->Slot, CurrentLRU); + TextureSource(TMU[0], GCache_SlotGetMemAddress(THandle->Slot), GR_MIPMAPLEVELMASK_BOTH, GCache_SlotGetInfo(THandle->Slot)); +} + +//============================================================================================ +// SetupLMapTexture +//============================================================================================ +GCache_Slot *SetupLMapTexture(geRDriver_THandle *THandle, DRV_LInfo *LInfo, geBoolean Dynamic, int32 LMapNum) +{ + GTHandle_CheckTextures(); + + if (Dynamic) + THandle->Flags |= THANDLE_UPDATE; + + if (!THandle->Slot || GCache_SlotGetUserData(THandle->Slot) != THandle) + { + THandle->Slot = GCache_TypeFindSlot(THandle->CacheType); + assert(THandle->Slot); + + GCache_SlotSetUserData(THandle->Slot, THandle); + THandle->Flags |= THANDLE_UPDATE; + + CacheInfo.LMapMisses++; + } + + if (THandle->Flags & THANDLE_UPDATE) + { + DownloadLightmap(LInfo, THandle->LogSize, THandle->Slot, LMapNum); + } + + if (Dynamic) + THandle->Flags |= THANDLE_UPDATE; + else + THandle->Flags &= ~THANDLE_UPDATE; + + GCache_SlotSetLRU(THandle->Slot, CurrentLRU); + + return THandle->Slot; +} + +//================================================================================== +// Render_DrawDecal +//================================================================================== +geBoolean DRIVERCC Render_DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) +{ + int32 Width, Height, Stride, OriginalWidth, w, h, Add1, Add2; + uint16 *Data; + GrLfbInfo_t Info; + uint16 *BackBuffer; + + if (x >= ClientWindow.Width) + return TRUE; + if (y >= ClientWindow.Height) + return TRUE; + + Width = THandle->Width; + OriginalWidth = Width; + Height = THandle->Height; + Stride = Width<<1; + Data = (uint16*)THandle->Data; + + if (SRect) + { + Data += SRect->top*Width + SRect->left; + Height = SRect->bottom - SRect->top; + Width = SRect->right - SRect->left; + } + + if (x < 0) + { + if (x+Width <= 0) + return TRUE; + Data += -x; + Width -= -x; + x=0; + } + + if (y < 0) + { + if (y+Height <= 0) + return TRUE; + Data += (-y)*OriginalWidth; + Height -= -y; + y=0; + } + + if (x + Width >= ClientWindow.Width) + Width -= (x+Width) - ClientWindow.Width; + + if (y + Height >= ClientWindow.Height) + Height -= (y+Height)- ClientWindow.Height; + + /* + if (!grLfbWriteRegion(GR_BUFFER_BACKBUFFER , + x, y, + GR_LFB_SRC_FMT_1555, + Width, Height, Stride, + (void*)Data)) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_BlitDecal: The GLIDE decal blit operation could not be performed."); + return FALSE; + } + */ + + Info.size = sizeof(Info); + + Render_SetHardwareMode(RENDER_DECAL_MODE, 0); + + if (!grLfbLock(GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_565, 0, FXFALSE, &Info)) + //if (!grLfbLock(GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_1555, 0, FXTRUE, &Info)) + { + SetLastDrvError(DRV_ERROR_GENERIC, "GLIDE_BlitDecal: Could not lock the back buffer."); + return FALSE; + } + + BackBuffer = (uint16*)Info.lfbPtr; + + BackBuffer += (y * (Info.strideInBytes>>1)) + x; + + Add1 = OriginalWidth - Width; + Add2 = (Info.strideInBytes>>1) - Width; + + for (h=0; h + +#include "BaseType.h" +#include "Glide.h" +#include "DCommon.h" +#include "GCAche.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + RENDER_UNKNOWN_MODE, + RENDER_MISC_TEX_POLY_MODE, + RENDER_MISC_GOURAD_POLY_MODE, + RENDER_LINES_POLY_MODE, + RENDER_WORLD_TRANSPARENT_POLY_MODE, + RENDER_WORLD_POLY_MODE_NO_LIGHTMAP, + RENDER_WORLD_POLY_MODE, + RENDER_LIGHTMAP_POLY_MODE, + RENDER_LIGHTMAP_FOG_POLY_MODE, + RENDER_DECAL_MODE, +}; + +extern uint32 PolyMode; +extern DRV_CacheInfo CacheInfo; + +void TextureSource(GrChipID_t Tmu, FxU32 startAddress, FxU32 evenOdd, GrTexInfo *info ); +void Render_SetHardwareMode(int32 NewMode, uint32 NewFlags); +geBoolean DRIVERCC Render_GouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags); +geBoolean DRIVERCC Render_LinesPoly(DRV_TLVertex *Pnts, int32 NumPoints); +geBoolean DRIVERCC Render_WorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +void RenderLightmapPoly(GrVertex *vrtx, int32 NumPoints, DRV_LInfo *LInfo, geBoolean Dynamic, uint32 Flags); +void DownloadLightmap(DRV_LInfo *LInfo, int32 Wh, GCache_Slot *Slot, int32 LMapNum); +geBoolean DRIVERCC Render_MiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags); +void SetupTexture(geRDriver_THandle *THandle); +GCache_Slot *SetupLMapTexture(geRDriver_THandle *THandle, DRV_LInfo *LInfo, geBoolean Dynamic, int32 LMapNum); +geBoolean DRIVERCC Render_DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y); +geBoolean DRIVERCC BeginScene(geBoolean Clear, geBoolean ClearZ, RECT *WorldRect); +geBoolean DRIVERCC EndScene(void); +geBoolean DRIVERCC BeginWorld(void); +geBoolean DRIVERCC EndWorld(void); +geBoolean DRIVERCC BeginMeshes(void); +geBoolean DRIVERCC EndMeshes(void); +geBoolean DRIVERCC BeginModels(void); +geBoolean DRIVERCC EndModels(void); + +//============================================================================================ +//============================================================================================ + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/GlideDrv/mssccprj.scc b/G3D/Engine/Drivers/GlideDrv/mssccprj.scc new file mode 100644 index 0000000..05edfc0 --- /dev/null +++ b/G3D/Engine/Drivers/GlideDrv/mssccprj.scc @@ -0,0 +1,4 @@ +SCC = This is a Source Code Control file + +[GlideDrv.mak] +SCC_Project_Name = "$/Genesis10/Source/Engine/Drivers/GlideDrv", MQQBAAAA diff --git a/G3D/Engine/Drivers/OpenGl/OGLDrv.c b/G3D/Engine/Drivers/OpenGl/OGLDrv.c new file mode 100644 index 0000000..e588eea --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/OGLDrv.c @@ -0,0 +1,411 @@ +/****************************************************************************************/ +/* OglDrv.c */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Exposed interface for OpenGL version of Genesis Driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#include +#include +#include +#include + +#include "OglDrv.h" +#include "OglMisc.h" +#include "THandle.h" +#include "Render.h" +#include "Win32.h" + + +int32 LastError; +char LastErrorStr[255]; + +GLfloat CurrentGamma = 1.0f; +DRV_Window ClientWindow; +static DRV_CacheInfo CacheInfo; + +GLint maxTextureSize = 0; + +// Toggle and function pointers for OpenGL multitexture extention +GLboolean multitexture = GE_FALSE; +PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; +PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB; + + + +DRV_Driver OGLDRV = +{ + + "OpenGL driver. v"DRV_VMAJS"."DRV_VMINS". Copyright 1999, Eclipse Inc.; All Rights Reserved.", + + DRV_VERSION_MAJOR, + DRV_VERSION_MINOR, + + DRV_ERROR_NONE, + NULL, + + EnumSubDrivers, + EnumModes, + + EnumPixelFormats, + + DrvInit, + DrvShutdown, + DrvResetAll, + DrvUpdateWindow, + DrvSetActive, + + THandle_Create, + THandle_Destroy, + + THandle_Lock, + THandle_UnLock, + + NULL, + NULL, + + NULL, + NULL, + + THandle_GetInfo, + + BeginScene, + EndScene, + BeginWorld, + EndWorld, + BeginMeshes, + EndMeshes, + BeginModels, + EndModels, + + Render_GouraudPoly, + Render_WorldPoly, + Render_MiscTexturePoly, + + DrawDecal, + + 0,0,0, + + &CacheInfo, + + ScreenShot, + + SetGamma, + GetGamma, + + SetFogEnable, + + NULL, + NULL, // Init to NULL, engine SHOULD set this (SetupLightmap) + NULL, +}; + +// Not implemented, but you noticed that already huh? +geBoolean DRIVERCC SetFogEnable(geBoolean Enable, float r, float g, float b, float Start, float End) +{ + + return GE_TRUE; +} + + +geBoolean DRIVERCC DrvInit(DRV_DriverHook *Hook) +{ + RECT WRect; + + + WindowSetup(Hook); + + if(Hook->Width == -1 && Hook->Height == -1) + { + GetClientRect(Hook->hWnd, &WRect); + + Hook->Width = (WRect.right - WRect.left); + Hook->Height = (WRect.bottom - WRect.top); + } + else if(!SetFullscreen(Hook)) + { + return GE_FALSE; + } + + SetGLPixelFormat(Hook); + + ClientWindow.Width = Hook->Width; + ClientWindow.Height = Hook->Height; + ClientWindow.hWnd = Hook->hWnd; + +#ifdef USE_LIGHTMAPS + if(ExtensionExists("GL_ARB_multitexture")) + { + glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB"); + glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC)wglGetProcAddress("glMultiTexCoord4fARB"); + + if(glActiveTextureARB != NULL && glMultiTexCoord4fARB != NULL) + { + multitexture = GL_TRUE; + } + } + else +#endif + { + multitexture = GL_FALSE; + } + + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_DEPTH_TEST); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glShadeModel(GL_SMOOTH); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + if(multitexture) + { + glActiveTextureARB(GL_TEXTURE1_ARB); + + glDisable(GL_TEXTURE_1D); + glDisable(GL_TEXTURE_2D); + + glActiveTextureARB(GL_TEXTURE0_ARB); + } + + SetFogEnable(GE_FALSE, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + + InitMatrices(ClientWindow.Width, ClientWindow.Height); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + + if (!THandle_Startup()) + { + SetLastDrvError(DRV_ERROR_GENERIC, "OGL_DrvInit: THandle_Startup failed...\n"); + return GE_FALSE; + } + + return GE_TRUE; +} + + +geBoolean DRIVERCC DrvShutdown(void) +{ + // Tell OpenGL to finish whatever is in the pipe, because we're closing up shop. + glFinish(); + + WindowCleanup(); + + return GE_TRUE; +} + + +// Should handle a resize and re-InitMatrices here... +geBoolean DRIVERCC DrvUpdateWindow(void) +{ + + return GE_TRUE; +} + + +geBoolean DRIVERCC DrvSetActive(geBoolean Active) +{ + + return GE_TRUE; +} + + +geBoolean DRIVERCC SetGamma(float Gamma) +{ + GLfloat lut[256]; + GLint i; + + CurrentGamma = Gamma; + + for(i = 0; i < 256; i++) + { + lut[i] = (GLfloat)pow(i / 255.0, 1.0 / CurrentGamma); + } + + glPixelTransferi(GL_MAP_COLOR, GL_TRUE); + glPixelMapfv(GL_PIXEL_MAP_R_TO_R, 256, lut); + glPixelMapfv(GL_PIXEL_MAP_G_TO_G, 256, lut); + glPixelMapfv(GL_PIXEL_MAP_B_TO_B, 256, lut); + + return GE_TRUE; +} + + +geBoolean DRIVERCC GetGamma(float *Gamma) +{ + *Gamma = CurrentGamma; + + return TRUE; +} + + +DRV_EngineSettings EngineSettings; + +DllExport BOOL DriverHook(DRV_Driver **Driver) +{ + + EngineSettings.CanSupportFlags = (DRV_SUPPORT_ALPHA | DRV_SUPPORT_COLORKEY); + EngineSettings.PreferenceFlags = 0; + + OGLDRV.EngineSettings = &EngineSettings; + + *Driver = &OGLDRV; + + // Make sure the error string ptr is not null, or invalid!!! + OGLDRV.LastErrorStr = LastErrorStr; + + SetLastDrvError(DRV_ERROR_NONE, "OGL: No error."); + + return GE_TRUE; +} + + +geBoolean DRIVERCC EnumModes(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, + void *Context) +{ + GLint modeCount = 0; + + modeCount = EnumNativeModes(Cb, Context); + + return GE_TRUE; +} + + +geBoolean DRIVERCC EnumSubDrivers(DRV_ENUM_DRV_CB *Cb, void *Context) +{ + + if(!Cb(0, "OpenGL Driver v"DRV_VMAJS"."DRV_VMINS".", Context)) + { + return GE_TRUE; + } + + return GE_TRUE; +} + + +// For now, we keep it simple. In the future, we may want to added paletted support +// (or maybe not)...and also check for OpenGL extentions, like GL_EXT_abgr, GL_EXT_bgra, etc. +// Note: OpenGL is traditionally RGBA based. ABGR is used here because of endian-oddness in +// the naming of Genesis's pixel formats. +// See: (Genesis Engine's) Bitmap/pixelformat.h for more information. +geRDriver_PixelFormat PixelFormats[] = +{ + {GE_PIXELFORMAT_32BIT_ABGR, RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP}, + {GE_PIXELFORMAT_24BIT_RGB, RDRIVER_PF_2D | RDRIVER_PF_CAN_DO_COLORKEY}, + {GE_PIXELFORMAT_24BIT_RGB, RDRIVER_PF_LIGHTMAP}, +}; + +#define NUM_PIXEL_FORMATS (sizeof(PixelFormats)/sizeof(geRDriver_PixelFormat)) + + +geBoolean DRIVERCC EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context) +{ + GLint i; + + for(i = 0; i < NUM_PIXEL_FORMATS; i++) + { + if(!Cb(&PixelFormats[i], Context)) + { + return GE_TRUE; + } + } + + return GE_TRUE; +} + + +void SetLastDrvError(int32 Error, char *ErrorStr) +{ + LastError = Error; + + if(ErrorStr) + { + strcpy(LastErrorStr, ErrorStr); + } + else + { + LastErrorStr[0] = 0; + } + + OGLDRV.LastErrorStr = LastErrorStr; + OGLDRV.LastError = LastError; +} + + +// I break the rules here. There's an implied assumption that screenshot will produce +// a BMP, I use TGA instead. BMP is so...Windows. This screws up GTest a bit, as GTest looks +// for files ending in .bmp before writing, and will thus keep overwriting one screenshot. +geBoolean DRIVERCC ScreenShot(const char *Name) +{ + unsigned char tgaHeader[18]; + GLubyte *buffer; + FILE *fp; + char *newName; + int nameLen; + + buffer = (GLubyte *)malloc(sizeof(GLubyte) * ClientWindow.Width * ClientWindow.Height * 3); + + glFinish(); + + glReadPixels(0, 0, ClientWindow.Width, ClientWindow.Height, + GL_BGR_EXT, GL_UNSIGNED_BYTE, buffer); + + memset(tgaHeader, 0, sizeof(tgaHeader)); + tgaHeader[2] = 2; + tgaHeader[12] = (unsigned char)ClientWindow.Width; + tgaHeader[13] = (unsigned char)((unsigned long)ClientWindow.Width >> 8); + tgaHeader[14] = (unsigned char)ClientWindow.Height; + tgaHeader[15] = (unsigned char)((unsigned long)ClientWindow.Height >> 8); + tgaHeader[16] = 24; + + // Convert the extention (if one exists) to .tga. They probably expect a .bmp. + newName = strdup(Name); + + nameLen = strlen(newName); + + if(nameLen > 3) + { + if(newName[nameLen - 4] == '.') + { + strcpy(newName + nameLen - 3, "tga"); + } + } + + fp = fopen(newName, "wb"); + + free(newName); + + if(fp == NULL) + { + free(buffer); + return GE_FALSE; + } + + fwrite(tgaHeader, 1, 18, fp); + fwrite(buffer, 3, ClientWindow.Width * ClientWindow.Height, fp); + fclose(fp); + + free(buffer); + + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/OpenGl/OGLDrv.h b/G3D/Engine/Drivers/OpenGl/OGLDrv.h new file mode 100644 index 0000000..1c934c6 --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/OGLDrv.h @@ -0,0 +1,59 @@ +/****************************************************************************************/ +/* OglDrv.h */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Exposed interface for OpenGL version of Genesis Driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#ifndef OGLDRV_H +#define OGLDRV_H + +#include "DCommon.h" +#include "glext.h" + +// Here are some useful values you can change to meet your needs. +// These should, in the future, really be handled at run-time as opposed to compile-time. +// The defaults work well with TNT2 based cards. +#define COLOR_DEPTH 16 // Bits per pixel to use for OpenGL Window/Context +#define ZBUFFER_DEPTH 16 // Depth of the ZBuffer to use in OpenGL. + +#define USE_LIGHTMAPS // Render lightmaps +#define USE_LINEAR_INTERPOLATION // Comment out to use nearest neighbor interpolation +//#define TRILINEAR_INTERPOLATION // Comment out to use bilinear interpolation + + +extern DRV_Driver OGLDRV; +extern DRV_Window ClientWindow; + +extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; +extern PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB; +extern GLboolean multitexture; + +extern maxTextureSize; + +geBoolean DRIVERCC SetFogEnable(geBoolean Enable, float r, float g, float b, float Start, float End); +geBoolean DRIVERCC DrvInit(DRV_DriverHook *Hook); +geBoolean DRIVERCC DrvShutdown(void); +geBoolean DRIVERCC DrvUpdateWindow(void); +geBoolean DRIVERCC DrvSetActive(geBoolean Active); +geBoolean DRIVERCC SetGamma(float Gamma); +geBoolean DRIVERCC GetGamma(float *Gamma); +geBoolean DRIVERCC ScreenShot(const char *Name); +geBoolean DRIVERCC EnumSubDrivers(DRV_ENUM_DRV_CB *Cb, void *Context); +geBoolean DRIVERCC EnumModes(int32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context); +geBoolean DRIVERCC EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context); +void SetLastDrvError(int32 Error, char *ErrorStr); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/OpenGl/OglDrv.dsp b/G3D/Engine/Drivers/OpenGl/OglDrv.dsp new file mode 100644 index 0000000..9b47e37 --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/OglDrv.dsp @@ -0,0 +1,209 @@ +# Microsoft Developer Studio Project File - Name="OglDrv" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=OglDrv - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "OglDrv.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "OglDrv.mak" CFG="OglDrv - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "OglDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "OglDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Source/Engine/Drivers/OglDrv", CVPBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "OglDrv - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OglDrv_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /X /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OglDrv_EXPORTS" /D "__MSC__" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 glu32.lib opengl32.lib /nologo /dll /machine:I386 /nodefaultlib + +!ELSEIF "$(CFG)" == "OglDrv - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OglDrv_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /X /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OglDrv_EXPORTS" /D "__MSC__" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib /nologo /dll /debug /machine:I386 /nodefaultlib /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "OglDrv - Win32 Release" +# Name "OglDrv - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\Dcommon.h +# End Source File +# Begin Source File + +SOURCE=.\glext.h +# End Source File +# Begin Source File + +SOURCE=.\OglDrv.c +# End Source File +# Begin Source File + +SOURCE=.\OglDrv.h +# End Source File +# Begin Source File + +SOURCE=.\OglMisc.c +# End Source File +# Begin Source File + +SOURCE=.\OglMisc.h +# End Source File +# Begin Source File + +SOURCE=.\Render.c +# End Source File +# Begin Source File + +SOURCE=.\Render.h +# End Source File +# Begin Source File + +SOURCE=.\THandle.c +# End Source File +# Begin Source File + +SOURCE=.\THandle.h +# End Source File +# Begin Source File + +SOURCE=.\Win32.c +# End Source File +# Begin Source File + +SOURCE=.\Win32.h +# End Source File +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Libcmt.lib + +!IF "$(CFG)" == "OglDrv - Win32 Release" + +!ELSEIF "$(CFG)" == "OglDrv - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Libcmtd.lib + +!IF "$(CFG)" == "OglDrv - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "OglDrv - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Winspool.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Uuid.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Comdlg32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Gdi32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Kernel32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Oldnames.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Shell32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\User32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Advapi32.lib +# End Source File +# End Group +# End Target +# End Project diff --git a/G3D/Engine/Drivers/OpenGl/OglDrv.dsw b/G3D/Engine/Drivers/OpenGl/OglDrv.dsw new file mode 100644 index 0000000..21f82aa --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/OglDrv.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "OglDrv"=.\OglDrv.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/G3D/Engine/Drivers/OpenGl/OglMisc.c b/G3D/Engine/Drivers/OpenGl/OglMisc.c new file mode 100644 index 0000000..03ad916 --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/OglMisc.c @@ -0,0 +1,133 @@ +/****************************************************************************************/ +/* OglMisc.c */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Miscellaneous support functions for OpenGL driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#include +#include + +#include "DCommon.h" +#include "OglMisc.h" + + +// Set up the OpenGL viewing frustum using an orthographic projection (as Genesis does all of +// its transforms in the engine... We're just here to rasterize polygons). +void InitMatrices(int width, int height) +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0f, (GLfloat)width, 0.0f, (GLfloat)height, 0.0f, 1.0f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glViewport(0, 0, width, height); + + glScalef(1.0f, -1.0f, 1.0f); + glTranslatef(0, 0 - (GLfloat)height, 0.0); +} + + +// Checks to see if a specific OpenGL extention is present. Used to look for multitexture +// support. +geBoolean ExtensionExists(const char *extension) +{ + const GLubyte *extensions = NULL; + const GLubyte *begin; + GLubyte *cursor, *end; + + cursor = (GLubyte *) strchr(extension, ' '); + + if(cursor || *extension == '\0') + { + return GE_FALSE; + } + + extensions = glGetString(GL_EXTENSIONS); + + begin = extensions; + + while(GE_TRUE) + { + cursor = (GLubyte *) strstr((const char *) begin, extension); + + if(!cursor) + { + break; + } + + end = cursor + strlen(extension); + + if(cursor == begin || *(cursor - 1) == ' ') + { + if (*end == ' ' || *end == '\0') + { + return GE_TRUE; + } + } + + begin = end; + } + + return GE_FALSE; +} + + +// Takes a GE_PIXELFORMAT_24BIT_RGB bitmap and converts it to a GE_PIXELFORMAT_32BIT_ABGR, +// replacing colorkey pixels with alpha information. +void CkBlit24_32(GLubyte *dstPtr, GLint dstWidth, GLint dstHeight, GLubyte *srcPtr, GLint srcWidth, + GLint srcHeight) +{ + GLint width, height; + GLubyte *nextLine; + + memset(dstPtr, 0x00, dstWidth * dstHeight * 4); + + + for(height = 0; height < srcHeight; height++) + { + nextLine = (dstPtr + (dstWidth * 4)); + + for(width = 0; width < srcWidth; width++) + { + if(!(*srcPtr == 0x00 && *(srcPtr + 1) == 0x00 && *(srcPtr + 2) == 0x01)) + { + *dstPtr = *srcPtr; + *(dstPtr + 1) = *(srcPtr + 1); + *(dstPtr + 2) = *(srcPtr + 2); + *(dstPtr + 3) = 0xFF; + } + + srcPtr += 3; + dstPtr += 4; + } + + dstPtr = nextLine; + } +} + + +void Blit32(GLubyte *dstPtr, GLint dstPitch, GLubyte *srcPtr, GLint srcWidth, GLint srcHeight, + GLint srcPitch) +{ + GLint count; + + for(count = 0; count < srcHeight; count++) + { + memcpy(dstPtr, srcPtr, srcWidth * 4); + srcPtr += srcPitch * 4; + dstPtr += dstPitch * 4; + } +} diff --git a/G3D/Engine/Drivers/OpenGl/OglMisc.h b/G3D/Engine/Drivers/OpenGl/OglMisc.h new file mode 100644 index 0000000..b853fd0 --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/OglMisc.h @@ -0,0 +1,29 @@ +/****************************************************************************************/ +/* OglMisc.h */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Miscellaneous support functions for OpenGL driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#ifndef OGLMISC_H +#define OGLMISC_H + +void InitMatrices(int width, int height); +geBoolean ExtensionExists(const char *extension); +void CkBlit24_32(GLubyte *dstPtr, GLint width, GLint dstHeight, GLubyte *srcPtr, GLint srcWidth, GLint srcHeight); +void Blit32(GLubyte *dstPtr, GLint dstPitch, GLubyte *srcPtr, GLint srcWidth, GLint srcHeight, + GLint srcPitch); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/OpenGl/Render.c b/G3D/Engine/Drivers/OpenGl/Render.c new file mode 100644 index 0000000..8b23e4f --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/Render.c @@ -0,0 +1,641 @@ +/****************************************************************************************/ +/* Render.c */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Polygon rasterization functions for OpenGL driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#include +#include + +#include "Render.h" +#include "OglDrv.h" +#include "OglMisc.h" +#include "THandle.h" +#include "Win32.h" + + +DRV_RENDER_MODE RenderMode = RENDER_NONE; +uint32 Render_HardwareFlags = 0; + +GLint boundTexture = -1; // Currently bound OpenGL texture object +GLint boundTexture2 = -1; // Currently bound OpenGL tex object on second TMU + +GLint decalTexObj = -1; + +// Render a world polygon without multitexture support. This will do two-polygon draws, +// one with the regular texture, then another with the lightmap texture. Clearly we hope +// we don't have to use this function (if multitexture is supported in hardware and OpenGL +// ICD, we won't have to), but its here just in case. +void Render_WorldPolyRegular(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, + DRV_LInfo *LInfo, GLfloat shiftU, GLfloat shiftV, + GLfloat scaleU, GLfloat scaleV, + GLubyte alpha) +{ + DRV_TLVertex *pPnt; + GLfloat zRecip; + GLfloat tu, tv; + GLint i; + +#ifdef USE_LIGHTMAPS + if(LInfo != NULL) + { + glDepthMask(GL_FALSE); + } +#endif + + pPnt = Pnts; + + glBegin(GL_TRIANGLE_FAN); + + for(i = 0; i < NumPoints; i++) + { + zRecip = 1.0f / pPnt->z; + + tu = (pPnt->u * scaleU + shiftU); + tv = (pPnt->v * scaleV + shiftV); + + glColor4ub((GLubyte)pPnt->r, (GLubyte)pPnt->g, (GLubyte)pPnt->b, alpha); + + glTexCoord4f(tu * THandle->InvScale * zRecip, + tv * THandle->InvScale * zRecip, 0.0f, zRecip); + + glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip); + + pPnt++; + } + + glEnd(); + +#ifdef USE_LIGHTMAPS + if(LInfo != NULL) + { + glDepthMask(GL_TRUE); + + glBlendFunc(GL_DST_COLOR,GL_ZERO); + + pPnt = Pnts; + + if(boundTexture != LInfo->THandle->TextureID) + { + glBindTexture(GL_TEXTURE_2D, LInfo->THandle->TextureID); + boundTexture = LInfo->THandle->TextureID; + } + + if(LInfo->THandle->Flags & THANDLE_UPDATE) + { + THandle_Update(LInfo->THandle); + } + + shiftU = (GLfloat)LInfo->MinU - 8.0f; + shiftV = (GLfloat)LInfo->MinV - 8.0f; + + glColor4ub(255, 255, 255, 255); + + glBegin(GL_TRIANGLE_FAN); + + for(i = 0; i < NumPoints; i++) + { + zRecip = 1.0f / pPnt->z; + + tu = pPnt->u - shiftU; + tv = pPnt->v - shiftV; + + glTexCoord4f(tu * LInfo->THandle->InvScale * zRecip, + tv * LInfo->THandle->InvScale * zRecip, 0.0f, zRecip); + + glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip); + + pPnt++; + } + + glEnd(); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } +#endif +} + + +// Render a world polygon using multiple TMUs to map the regular texture and lightmap in one pass +void Render_WorldPolyMultitexture(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, + DRV_LInfo *LInfo, GLfloat shiftU, GLfloat shiftV, + GLfloat scaleU, GLfloat scaleV, + GLubyte alpha) +{ + DRV_TLVertex *pPnt; + GLfloat zRecip; + GLfloat tu, tv, lu, lv; + GLfloat shiftU2, shiftV2; + GLint i; + + + if(LInfo != NULL) + { + glActiveTextureARB(GL_TEXTURE1_ARB); + glEnable(GL_TEXTURE_2D); + + if(boundTexture2 != LInfo->THandle->TextureID) + { + glBindTexture(GL_TEXTURE_2D, LInfo->THandle->TextureID); + boundTexture2 = LInfo->THandle->TextureID; + } + + if(LInfo->THandle->Flags & THANDLE_UPDATE) + { + THandle_Update(LInfo->THandle); + } + + shiftU2 = (GLfloat)LInfo->MinU - 8.0f; + shiftV2 = (GLfloat)LInfo->MinV - 8.0f; + } + + pPnt = Pnts; + + glBegin(GL_TRIANGLE_FAN); + + for(i = 0; i < NumPoints; i++) + { + zRecip = 1.0f / pPnt->z; + + tu = (pPnt->u * scaleU + shiftU); + tv = (pPnt->v * scaleV + shiftV); + + glColor4ub((GLubyte)pPnt->r, (GLubyte)pPnt->g, (GLubyte)pPnt->b, alpha); + + glMultiTexCoord4fARB(GL_TEXTURE0_ARB, tu * THandle->InvScale * zRecip, + tv * THandle->InvScale * zRecip, 0.0f, zRecip); + + if(LInfo) + { + lu = pPnt->u - shiftU2; + lv = pPnt->v - shiftV2; + + glMultiTexCoord4fARB(GL_TEXTURE1_ARB, lu * LInfo->THandle->InvScale * zRecip, + lv * LInfo->THandle->InvScale * zRecip, 0.0f, zRecip); + } + + glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip); + + pPnt++; + } + + glEnd(); + + if(LInfo != NULL) + { + glDisable(GL_TEXTURE_2D); + glActiveTextureARB(GL_TEXTURE0_ARB); + } +} + +// Entry point to render a world polygon, does some setup and then passed off control +// to a specific WorldPoly function (see above) depending upon whether multitexture is on or +// off +geBoolean DRIVERCC Render_WorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, + DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags) +{ + GLfloat shiftU, shiftV, scaleU, scaleV; + DRV_TLVertex *pPnt = Pnts; + GLubyte alpha; + BOOL Dynamic = 0; + + + if(Flags & DRV_RENDER_ALPHA) + { + alpha = (GLubyte)Pnts->a; + } + else + { + alpha = 255; + } + + + shiftU = TexInfo->ShiftU; + shiftV = TexInfo->ShiftV; + scaleU = 1.0f / TexInfo->DrawScaleU; + scaleV = 1.0f / TexInfo->DrawScaleV; + + if(boundTexture != THandle->TextureID) + { + glBindTexture(GL_TEXTURE_2D, THandle->TextureID); + boundTexture = THandle->TextureID; + } + + if(THandle->Flags & THANDLE_UPDATE) + { + THandle_Update(THandle); + } + + if(LInfo != NULL) + { + OGLDRV.SetupLightmap(LInfo, &Dynamic); + + if(Dynamic || LInfo->THandle->Flags & THANDLE_UPDATE_LM) + { + THandle_DownloadLightmap(LInfo); + + if(Dynamic) + { + LInfo->THandle->Flags |= THANDLE_UPDATE_LM; + } + else + { + LInfo->THandle->Flags &= ~THANDLE_UPDATE_LM; + } + } + } + + + if(multitexture) + { + // Hooray!! + Render_WorldPolyMultitexture(Pnts, NumPoints, THandle, LInfo, shiftU, shiftV, + scaleU, scaleV, alpha); + } + else + { + // Hiss! Boo! + Render_WorldPolyRegular(Pnts, NumPoints, THandle, LInfo, shiftU, shiftV, + scaleU, scaleV, alpha); + } + + OGLDRV.NumRenderedPolys++; + + return GE_TRUE; +} + + +// Render a generic plain ol' polygon using Gouraud smooth shading and no texture map. +geBoolean DRIVERCC Render_GouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags) +{ + GLint i; + GLfloat zRecip; + DRV_TLVertex *pPnt = Pnts; + GLubyte alpha; + + if(Flags & DRV_RENDER_ALPHA) + { + alpha = (GLubyte)Pnts->a; + } + else + { + alpha = 255; + } + + glDisable(GL_TEXTURE_2D); + + glBegin(GL_TRIANGLE_FAN); + + for(i = 0; i < NumPoints; i++) + { + zRecip = 1.0f / pPnt->z; + + glColor4ub((GLubyte)pPnt->r, (GLubyte)pPnt->g, (GLubyte)pPnt->b, alpha); + + glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip); + + pPnt++; + } + + glEnd(); + + glEnable(GL_TEXTURE_2D); + + OGLDRV.NumRenderedPolys++; + + return GE_TRUE; +} + + +// Render a non-world polygon (such as on an actor). +geBoolean DRIVERCC Render_MiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, + geRDriver_THandle *THandle, uint32 Flags) +{ + GLint i; + GLfloat zRecip; + DRV_TLVertex *pPnt = Pnts; + GLubyte alpha; + + + if(Flags & DRV_RENDER_ALPHA) + { + alpha = (GLubyte)Pnts->a; + } + else + { + alpha = 255; + } + + if(boundTexture != THandle->TextureID) + { + glBindTexture(GL_TEXTURE_2D, THandle->TextureID); + boundTexture = THandle->TextureID; + } + + if(THandle->Flags & THANDLE_UPDATE) + { + THandle_Update(THandle); + } + + if(Flags & DRV_RENDER_NO_ZMASK) + { + glDisable(GL_DEPTH_TEST); + } + + glBegin(GL_TRIANGLE_FAN); + + for(i = 0; i < NumPoints; i++) + { + zRecip = 1.0f / pPnt->z; + + glColor4ub((GLubyte)pPnt->r, (GLubyte)pPnt->g, (GLubyte)pPnt->b, alpha); + + glTexCoord4f(pPnt->u * zRecip, pPnt->v * zRecip, 0.0f, zRecip); + + glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip); + + pPnt++; + } + + glEnd(); + + if(Flags & DRV_RENDER_NO_ZMASK) + { + glEnable(GL_DEPTH_TEST); + } + + return GE_TRUE; +} + + +// Render a 2D decal graphic... +// Notes: unfortunately traditional thru-the-API framebuffer access for OpenGL is +// ridculously slow with most ICDs. +// So I've implemented decals as clamped textures on polygons. +// This works rather well... usually... and it is fast. However, it has drawbacks.... +// 1) Extra use of texture ram to hold decals +// 2) May look shoddy under some situations on cards with 256x256 texture maximums +// (3DFX Voodoo springs to mind) +// Reason: If they only support 256x256, large decals like the GTest bitmap font may +// be sampled down to 256x256 and then restreched when drawing. I haven't tested this +// against such cards, due to lack of any access to one, but my guess is the resulting +// image wont look so hot. +// +// In the future, may want to add platform-specific framebuffer access (GDI, X11, etc) as +// allowed. But...for Windows, DirectDraw isn't supported, and to the best of my knowledge, +// GDI is only reliably supported when not using a double-buffer. Joy. +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) +{ + RECT tmpRect, *srcRect; + GLint width, height; + GLfloat uClamp, vClamp; + GLfloat uDiff = 1.0f, vDiff = 1.0f; + + if(!SRect) + { + tmpRect.left = 0; + tmpRect.right = THandle->Width; + tmpRect.top = 0; + tmpRect.bottom = THandle->Height; + + srcRect = &tmpRect; + width = (THandle->Width); + height = (THandle->Height); + } + else + { + srcRect = SRect; + width = (srcRect->right - srcRect->left); + height = (srcRect->bottom - srcRect->top); + } + + if(x + width <= 0 || y + height <= 0 || x >= ClientWindow.Width || y >= ClientWindow.Height) + { + return GE_TRUE; + } + + if(x + width >= (ClientWindow.Width - 1)) + { + srcRect->right -= ((x + width) - (ClientWindow.Width - 1)); + } + + if(y + height >= (ClientWindow.Height - 1)) + { + srcRect->bottom -= ((y + height) - (ClientWindow.Height - 1)); + } + + if(x < 0) + { + srcRect->left += -x; + x = 0; + } + + if(y < 0) + { + srcRect->top += -y; + y = 0; + } + + if(boundTexture != THandle->TextureID) + { + glBindTexture(GL_TEXTURE_2D, THandle->TextureID); + boundTexture = THandle->TextureID; + } + + if(THandle->Flags & THANDLE_UPDATE) + { + THandle_Update(THandle); + } + + glDisable(GL_DEPTH_TEST); + + glColor4f(1.0, 1.0, 1.0, 1.0); + + glShadeModel(GL_FLAT); + + if(THandle->Data[1] == NULL) + { + uClamp = width / (GLfloat)THandle->PaddedWidth; + vClamp = height / (GLfloat)THandle->PaddedHeight; + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadIdentity(); + glTranslatef(srcRect->left / (GLfloat)THandle->PaddedWidth, + srcRect->top / (GLfloat)THandle->PaddedHeight, 0.0f); + + glBegin(GL_QUADS); + + glTexCoord2f(0.0f, 0.0); + glVertex2i(x, y); + + glTexCoord2f(uClamp, 0.0f); + glVertex2i(x + width, y); + + glTexCoord2f(uClamp, vClamp); + glVertex2i(x + width, y + height); + + glTexCoord2f(0.0f, vClamp); + glVertex2i(x, y + height); + + glEnd(); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + } + else + { + + glPixelStorei(GL_UNPACK_ROW_LENGTH, THandle->Width); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, srcRect->left); + glPixelStorei(GL_UNPACK_SKIP_ROWS, srcRect->top); + + glPixelZoom(1.0, -1.0); + + if(width <= maxTextureSize && height <= maxTextureSize && + width == SnapToPower2(width) && height == SnapToPower2(height)) + { + // Last chance to avoid the dreaded glDrawPixels...Yes, this is faster + // than glDrawPixels on the ICD's I've tested. Go figure. + // (Could add a more complex texture upload/clamp system for + // width/heights other than powers of 2, but for now, + // this is enough complexity...Sorry, 3DFX) + + if(decalTexObj == -1) + { + glGenTextures(1, &decalTexObj); + } + + glBindTexture(GL_TEXTURE_2D, decalTexObj); + boundTexture = decalTexObj; + + glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, THandle->Data[1]); + + glBegin(GL_QUADS); + + glTexCoord2f(0.0f, 0.0); + glVertex2i(x, y); + + glTexCoord2f(1.0f, 0.0f); + glVertex2i(x + width, y); + + glTexCoord2f(1.0f, 1.0f); + glVertex2i(x + width, y + height); + + glTexCoord2f(0.0f, 1.0f); + glVertex2i(x, y + height); + + glEnd(); + } + else + { + glPixelZoom(1.0, -1.0); + + glRasterPos2i(x, y); + glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, THandle->Data[1]); + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + } + + glShadeModel(GL_SMOOTH); + + glEnable(GL_DEPTH_TEST); + + return GE_TRUE; +} + + +geBoolean DRIVERCC BeginScene(geBoolean Clear, geBoolean ClearZ, RECT *WorldRect) +{ + + if(Clear) + { + glClear(GL_COLOR_BUFFER_BIT); + } + + if(ClearZ) + { + glClear(GL_DEPTH_BUFFER_BIT); + } + + OGLDRV.NumRenderedPolys = 0; + + return GE_TRUE; +} + + +geBoolean DRIVERCC EndScene(void) +{ + FlipGLBuffers(); + + return GE_TRUE; +} + + +geBoolean DRIVERCC BeginWorld(void) +{ + RenderMode = RENDER_WORLD; + + OGLDRV.NumWorldPixels = 0; + OGLDRV.NumWorldSpans = 0; + + return TRUE; +} + + +geBoolean DRIVERCC EndWorld(void) +{ + RenderMode = RENDER_NONE; + + + return TRUE; +} + + +geBoolean DRIVERCC BeginMeshes(void) +{ + RenderMode = RENDER_MESHES; + + return TRUE; +} + + +geBoolean DRIVERCC EndMeshes(void) +{ + RenderMode = RENDER_NONE; + + return TRUE; +} + + +geBoolean DRIVERCC BeginModels(void) +{ + RenderMode = RENDER_MODELS; + + return TRUE; +} + + +geBoolean DRIVERCC EndModels(void) +{ + RenderMode = RENDER_NONE; + + return TRUE; +} \ No newline at end of file diff --git a/G3D/Engine/Drivers/OpenGl/Render.h b/G3D/Engine/Drivers/OpenGl/Render.h new file mode 100644 index 0000000..0549af1 --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/Render.h @@ -0,0 +1,65 @@ +/****************************************************************************************/ +/* Render.h */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Polygon rasterization functions for OpenGL driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#ifndef RENDER_H +#define RENDER_H + +#include "DCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + RENDER_UNKNOWN_MODE, + RENDER_MISC_TEX_POLY_MODE, + RENDER_MISC_GOURAD_POLY_MODE, + RENDER_LINES_POLY_MODE, + RENDER_WORLD_TRANSPARENT_POLY_MODE, + RENDER_WORLD_POLY_MODE, + RENDER_LIGHTMAP_POLY_MODE, + RENDER_LIGHTMAP_FOG_POLY_MODE, + RENDER_DECAL_MODE, +}; + +extern uint32 PolyMode; +extern DRV_CacheInfo CacheInfo; +extern GLint decalTexObj; + +void Render_SetHardwareMode(int32 NewMode, uint32 NewFlags); +geBoolean DRIVERCC Render_GouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags); +geBoolean DRIVERCC Render_WorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +geBoolean DRIVERCC Render_MiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags); +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y); +geBoolean DRIVERCC BeginScene(geBoolean Clear, geBoolean ClearZ, RECT *WorldRect); +geBoolean DRIVERCC EndScene(void); +geBoolean DRIVERCC BeginWorld(void); +geBoolean DRIVERCC EndWorld(void); +geBoolean DRIVERCC BeginMeshes(void); +geBoolean DRIVERCC EndMeshes(void); +geBoolean DRIVERCC BeginModels(void); +geBoolean DRIVERCC EndModels(void); + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/OpenGl/THandle.c b/G3D/Engine/Drivers/OpenGl/THandle.c new file mode 100644 index 0000000..de55b7c --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/THandle.c @@ -0,0 +1,492 @@ +/****************************************************************************************/ +/* THandle.c */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Texture handle manager for OpenGL driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#include +#include + +#include "THandle.h" +#include "OglDrv.h" +#include "Render.h" + + +geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; + + +// Init THandle system (do nothing, for now) +geBoolean THandle_Startup(void) +{ + + return GE_TRUE; +} + + +// Find an empty texture handle +geRDriver_THandle *FindTextureHandle() +{ + int32 i; + geRDriver_THandle *THandle; + + THandle = TextureHandles; + + for(i = 0; i < MAX_TEXTURE_HANDLES; i++, THandle++) + { + if(!THandle->Active) + { + memset(THandle, 0, sizeof(geRDriver_THandle)); + + THandle->Active = GE_TRUE; + + return THandle; + } + } + + return NULL; +} + + +// Cleanup a texture handle. Remove texture from texture memory and free up related +// system memory. +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle) +{ + GLint i; + + + if(!THandle->Active) + { + return GE_FALSE; + } + + glDeleteTextures(1, &THandle->TextureID); + + for(i = 0; i < THANDLE_MAX_MIP_LEVELS; i++) + { + if(THandle->Data[i] != NULL) + { + free(THandle->Data[i]); + THandle->Data[i] = NULL; + } + } + + memset(THandle, 0, sizeof(geRDriver_THandle)); + + return GE_TRUE; +} + + +// Cleanup all currently in-use texture handles +geBoolean FreeAllTextureHandles(void) +{ + int32 i; + geRDriver_THandle *pTHandle; + + pTHandle = TextureHandles; + + + for(i = 0; i < MAX_TEXTURE_HANDLES; i++, pTHandle++) + { + if(!pTHandle->Active) + { + continue; + } + + THandle_Destroy(pTHandle); + } + + glDeleteTextures(1, &decalTexObj); + decalTexObj = -1; + + return GE_TRUE; +} + + +// Create a new texture handle... +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, + const geRDriver_PixelFormat *PixelFormat) +{ + int32 SWidth, SHeight; + geRDriver_THandle *THandle; + GLubyte Log; + + + THandle = FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "OGL_THandleCreate: No more handles left."); + goto ExitWithError; + } + + if(PixelFormat->Flags & RDRIVER_PF_3D) + { + char errMsg[64]; + + if(Width > maxTextureSize) + { + sprintf(errMsg, "OGL_THandleCreate: Width > GL_MAX_TEXTURE_SIZE (%d)", maxTextureSize); + SetLastDrvError(DRV_ERROR_GENERIC, errMsg); + goto ExitWithError; + } + + if (Height > maxTextureSize) + { + sprintf(errMsg, "OGL_THandleCreate: Height > GL_MAX_TEXTURE_SIZE (%d)", maxTextureSize); + SetLastDrvError(DRV_ERROR_GENERIC, errMsg); + goto ExitWithError; + } + + SWidth = SnapToPower2(Width); + SHeight = SnapToPower2(Height); + + if (Width != SWidth) + { + SetLastDrvError(DRV_ERROR_GENERIC, "OGL_THandleCreate: Not a power of 2."); + goto ExitWithError; + } + + if (Height != SHeight) + { + SetLastDrvError(DRV_ERROR_GENERIC, "OGL_THandleCreate: Not a power of 2."); + goto ExitWithError; + } + } + + THandle->MipLevels = NumMipLevels; + THandle->Width = Width; + THandle->Height = Height; + THandle->PixelFormat = *PixelFormat; + THandle->Flags = 0; + + Log = (uint8)GetLog(Width, Height); + + if(THandle->PixelFormat.Flags & RDRIVER_PF_2D) + { + THandle->PaddedWidth = SnapToPower2(THandle->Width); + THandle->PaddedHeight = SnapToPower2(THandle->Height); + } + else if(THandle->PixelFormat.Flags & RDRIVER_PF_3D) + { + THandle->InvScale = 1.0f / (GLfloat)((1<Flags |= THANDLE_UPDATE_LM; + THandle->InvScale = 1.0f / (GLfloat)((1<TextureID); + + return THandle; + + ExitWithError: + { + return NULL; + } +} + + +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info) +{ + + if(!THandle->Active) + { + return GE_FALSE; + } + + Info->Width = THandle->Width >> MipLevel; + Info->Height = THandle->Height >> MipLevel; + Info->Stride = Info->Width; + Info->Flags = 0; + Info->PixelFormat = THandle->PixelFormat; + + if(THandle->PixelFormat.Flags & RDRIVER_PF_CAN_DO_COLORKEY) + { + Info->Flags = RDRIVER_THANDLE_HAS_COLORKEY; + Info->ColorKey = 1; + } + else + { + Info->Flags = 0; + Info->ColorKey = 0; + } + + return GE_TRUE; +} + + +// Lock a texture for editing by the engine +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Data) +{ + + // If we've already got data in system mem, return it to the engine as-is + if(THandle->Data[MipLevel] != NULL) + { + THandle->Flags |= (THANDLE_LOCKED << MipLevel); + *Data = THandle->Data[MipLevel] ; + return GE_TRUE; + } + + // Otherwise, grab a new block of memory for the engine to draw on... + if(THandle->PixelFormat.PixelFormat == GE_PIXELFORMAT_32BIT_ABGR) + { + GLint mipWidth, mipHeight; + + if(MipLevel == 0) + { + mipWidth = THandle->Width; + mipHeight = THandle->Height; + } + else + { + mipWidth = (THandle->Width / (int)pow(2.0, (double)MipLevel)); + mipHeight = (THandle->Height / (int)pow(2.0, (double)MipLevel)); + } + + THandle->Data[MipLevel] = (GLubyte *)malloc(mipWidth * mipHeight * 4); + } + else if(THandle->PixelFormat.PixelFormat == GE_PIXELFORMAT_24BIT_RGB) + { + THandle->Data[MipLevel] = (GLubyte *)malloc(THandle->Width * THandle->Height * 3); + } + else + { + *Data = NULL; + return GE_FALSE; + } + + + THandle->Flags |= (THANDLE_LOCKED << MipLevel); + *Data = THandle->Data[MipLevel]; + + return GE_TRUE; +} + + +// Unlocks a texture locked for editing, and sets the texture to be uploaded next time +// it needs to be visible. +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel) +{ + + if(!(THandle->Flags & (THANDLE_LOCKED << MipLevel))) + { + return GE_FALSE; + } + + if(THandle->Data == NULL) + { + return GE_FALSE; + } + + THandle->Flags &=~(THANDLE_LOCKED << MipLevel); + + // Don't update on mips other than level 0. We ignore the engine-created mips. + // Somewhat inefficient (since mips will be generated twice), but good visual results. + // Would be nice if you could tell the engine not to bother with mipping + if(MipLevel == 0) + { + THandle->Flags |= THANDLE_UPDATE; + } + + return GE_TRUE; +} + + +// Do an actual card upload (well, at least tell the OpenGL driver you'd like one when it +// gets a chance) of a texture. Called from the Render_* functions when they require +// use of a texture that is marked for updating (THANDLE_UPDATE) +void THandle_Update(geRDriver_THandle *THandle) +{ + + if(THandle->PixelFormat.Flags & RDRIVER_PF_2D) + { + if(THandle->PixelFormat.PixelFormat == GE_PIXELFORMAT_24BIT_RGB) + { + if(THandle->Width <= maxTextureSize && THandle->Height <= maxTextureSize) + { + GLubyte *dest; + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 0.5f); + + dest = malloc(THandle->PaddedWidth * THandle->PaddedHeight * 4); + + CkBlit24_32(dest, THandle->PaddedWidth, THandle->PaddedHeight, THandle->Data[0], + THandle->Width, THandle->Height); + + glTexImage2D(GL_TEXTURE_2D, 0, 4, THandle->PaddedWidth, THandle->PaddedHeight, + 0, GL_RGBA, GL_UNSIGNED_BYTE, dest); + + free(dest); + } + else + { + if(THandle->Data[1] != NULL) + { + free(THandle->Data[1]); + } + + THandle->Data[1] = malloc(THandle->Width * THandle->Height * 4); + + CkBlit24_32(THandle->Data[1], THandle->Width, THandle->Height, THandle->Data[0], + THandle->Width, THandle->Height); + } + } + } + else + { +#ifdef USE_LINEAR_INTERPOLATION + #ifdef TRILINEAR_INTERPOLATION + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + #else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + #endif +#else + #ifdef TRILINEAR_INTERPOLATION + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + #else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + #endif +#endif + + if(THandle->PixelFormat.PixelFormat == GE_PIXELFORMAT_32BIT_ABGR) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0f); + + gluBuild2DMipmaps(GL_TEXTURE_2D, 4, THandle->Width, THandle->Height, GL_RGBA, + GL_UNSIGNED_BYTE, THandle->Data[0]); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 0.0f); + + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, THandle->Width, THandle->Height, + GL_RGB, GL_UNSIGNED_BYTE, THandle->Data[0]); + } + } + + THandle->Flags &= ~THANDLE_UPDATE; +} + + +// Take engine supplied lightmap raw-RGB data and put it into a texture handle. +void THandle_DownloadLightmap(DRV_LInfo *LInfo) +{ + GLubyte *tempBits; + + THandle_Lock(LInfo->THandle, 0, (void**)&tempBits); + + memcpy(tempBits, LInfo->RGBLight[0], LInfo->THandle->Width * LInfo->THandle->Height * 3); + + THandle_UnLock(LInfo->THandle, 0); +} + + +// Reset the THandle system +geBoolean DRIVERCC DrvResetAll(void) +{ + + return FreeAllTextureHandles(); +} + + +S32 SnapToPower2(S32 Width) +{ + if(Width > 1 && Width <= 2) + { + Width = 2; + } + else if(Width > 2 && Width <= 4) + { + Width = 4; + } + else if(Width > 4 && Width <= 8) + { + Width = 8; + } + else if(Width > 8 && Width <= 16) + { + Width =16; + } + else if(Width > 16 && Width <= 32) + { + Width = 32; + } + else if(Width > 32 && Width <= 64) + { + Width = 64; + } + else if(Width > 64 && Width <= 128) + { + Width = 128; + } + else if(Width > 128 && Width <= 256) + { + Width = 256; + } + else if(Width > 256 && Width <= 512) + { + Width = 512; + } + else if(Width > 512 && Width <= 1024) + { + Width = 1024; + } + else if(Width > 1024 && Width <= 2048) + { + Width = 2048; + } + + return Width; +} + + +uint32 Log2(uint32 P2) +{ + uint32 p = 0; + int32 i = 0; + + for (i = P2; i > 0; i>>=1) + p++; + + return (p-1); +} + + +int32 GetLog(int32 Width, int32 Height) +{ + int32 LWidth = SnapToPower2(max(Width, Height)); + + return Log2(LWidth); +} diff --git a/G3D/Engine/Drivers/OpenGl/THandle.h b/G3D/Engine/Drivers/OpenGl/THandle.h new file mode 100644 index 0000000..c360667 --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/THandle.h @@ -0,0 +1,69 @@ +/****************************************************************************************/ +/* THandle.h */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Texture handle manager for OpenGL driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#ifndef THANDLE_H +#define THANDLE_H + +#include +#include +#include + +#include "DCommon.h" +#include "OglMisc.h" + +#define MAX_TEXTURE_HANDLES 20000 +#define THANDLE_MAX_MIP_LEVELS 16 + +// THandle flags +#define THANDLE_UPDATE (1<<0) // Force a thandle to be uploaded to the card +#define THANDLE_TRANS (1<<2) // Texture has transparency +#define THANDLE_LOCKED (1<<3) // THandle is currently locked (invalid for rendering etc) +#define THANDLE_UPDATE_LM (1<<4) // THandle is a lightmap that needs updating + +typedef struct geRDriver_THandle +{ + GLboolean Active; + GLint Width, Height, MipLevels; + GLint PaddedWidth, PaddedHeight; + geRDriver_PixelFormat PixelFormat; + GLuint Flags; + GLint TextureID; + GLubyte *Data[THANDLE_MAX_MIP_LEVELS]; + GLfloat InvScale; +} geRDriver_THandle; + +extern geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; + +geBoolean FreeAllTextureHandles(void); +geBoolean DRIVERCC DrvResetAll(void); +geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geBoolean DRIVERCC THandle_Destroy(geRDriver_THandle *THandle); +geBoolean DRIVERCC THandle_Lock(geRDriver_THandle *THandle, int32 MipLevel, void **Data); +geBoolean DRIVERCC THandle_UnLock(geRDriver_THandle *THandle, int32 MipLevel); +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info); +void THandle_Update(geRDriver_THandle *THandle); +void THandle_DownloadLightmap(DRV_LInfo *LInfo); + +int32 GetLog(int32 Width, int32 Height); +uint32 Log2(uint32 P2); +S32 SnapToPower2(S32 Width); + +geBoolean THandle_Startup(void); + +#endif diff --git a/G3D/Engine/Drivers/OpenGl/Win32.c b/G3D/Engine/Drivers/OpenGl/Win32.c new file mode 100644 index 0000000..66d33ad --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/Win32.c @@ -0,0 +1,323 @@ +/****************************************************************************************/ +/* Win32.c */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Win32-specific functionality for OpenGL driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#include +#include + +#include "Win32.h" +#include "OglDrv.h" + + +HWND originalWnd = NULL; +WNDPROC originalWndProc = NULL; +HDC hDC = NULL; +HGLRC hRC = NULL; +GLboolean fullscreen = GE_FALSE; + + +static LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) +{ + switch(iMessage) + { + case WM_DESTROY: + break; + + default: + if(originalWndProc != NULL) + { + return originalWndProc(hWnd, iMessage, wParam, lParam); + } + } + + return 0; +} + + +void WindowSetup(DRV_DriverHook *Hook) +{ + HINSTANCE hInstance; + WNDCLASS wc; + RECT wndRect; + DWORD style = 0; + char className[256]; + + + hInstance = (HINSTANCE)GetWindowLong(Hook->hWnd, GWL_HINSTANCE); + memset(className, 0, sizeof(className)); + GetClassName(Hook->hWnd, className, 256); + GetClassInfo(hInstance, className, &wc); + GetWindowRect(Hook->hWnd, &wndRect); + + originalWnd = Hook->hWnd; + + strcat(className, "_r"); + + wc.lpszClassName = className; + wc.style |= CS_OWNDC; + + originalWndProc = wc.lpfnWndProc; + wc.lpfnWndProc = WndProc; + + if(Hook->Width != -1 && Hook->Height != -1) + { + style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + } + + RegisterClass(&wc); + + Hook->hWnd = CreateWindowEx( + 0, + wc.lpszClassName, + wc.lpszClassName, + style, + wndRect.left, + wndRect.top, + wndRect.right - wndRect.left, + wndRect.bottom - wndRect.top, + NULL, + NULL, + hInstance, + NULL); + + if(Hook->Width != -1 && Hook->Height != -1) + { + SetWindowPos(originalWnd, HWND_BOTTOM, 0, 0, Hook->Width, Hook->Height, 0); + SetWindowPos(Hook->hWnd, HWND_TOP, 0, 0, Hook->Width, Hook->Height, 0); + } + + ShowWindow(originalWnd, SW_HIDE); + ShowWindow(Hook->hWnd, SW_SHOW); +} + + +void WindowCleanup() +{ + HINSTANCE hInstance; + char className[256]; + + if(ClientWindow.hWnd != NULL) + { + if(hDC != NULL && hRC != NULL) + { + wglMakeCurrent(hDC, NULL); + wglDeleteContext(hRC); + } + + ReleaseDC(ClientWindow.hWnd, hDC); + } + + if(fullscreen) + { + ChangeDisplaySettings(NULL, 0); + fullscreen = GE_FALSE; + } + + if(ClientWindow.hWnd != NULL) + { + hInstance = (HINSTANCE)GetWindowLong(ClientWindow.hWnd, GWL_HINSTANCE); + memset(className, 0, sizeof(className)); + GetClassName(ClientWindow.hWnd, className, 256); + + UnregisterClass(className, hInstance); + DestroyWindow(ClientWindow.hWnd); + + if(originalWnd != NULL) + { + ShowWindow(originalWnd, SW_SHOW); + } + } +} + + +void FlipGLBuffers() +{ + SwapBuffers(hDC); +} + + +geBoolean SetFullscreen(DRV_DriverHook *Hook) +{ + GLuint modeCount, refresh = 0; + GLboolean foundMatch = GE_FALSE; + DEVMODE devMode, bestMode; + + devMode.dmSize = sizeof(DEVMODE); + devMode.dmPelsWidth = Hook->Width; + devMode.dmPelsHeight = Hook->Height; + + modeCount = 0; + + while(EnumDisplaySettings(NULL, modeCount++, &devMode)) + { + if(devMode.dmBitsPerPel != COLOR_DEPTH) + { + continue; + } + + if((GLint)devMode.dmPelsWidth == Hook->Width && + (GLint)devMode.dmPelsHeight == Hook->Height) + { + if(devMode.dmDisplayFrequency >= refresh) + { + bestMode = devMode; + foundMatch = GE_TRUE; + } + } + } + + + if(foundMatch) + { + if(ChangeDisplaySettings(&bestMode, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL) + { + fullscreen = GE_TRUE; + return GE_TRUE; + } + } + + + return GE_FALSE; +} + + +void SetGLPixelFormat(DRV_DriverHook *Hook) +{ + GLint nPixelFormat; + static PIXELFORMATDESCRIPTOR pfd; + + memset(&pfd, 0x00, sizeof(pfd)); + + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; + pfd.dwLayerMask = PFD_MAIN_PLANE; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = COLOR_DEPTH; + pfd.cDepthBits = ZBUFFER_DEPTH; + pfd.cAccumBits = 0; + pfd.cStencilBits = 0; + + hDC = GetDC(Hook->hWnd); + + if(hDC != NULL) + { + if(GetPixelFormat(hDC) <= 0) + { + nPixelFormat = ChoosePixelFormat(hDC, &pfd); + SetPixelFormat(hDC, nPixelFormat, &pfd); + } + + hRC = wglCreateContext(hDC); + wglMakeCurrent(hDC, hRC); + } +} + + +GLint EnumNativeModes(DRV_ENUM_MODES_CB *Cb, void *Context) +{ + DEVMODE devMode; + GLint modeCount, modeListCount; + char resolution[16]; + GLint idx = 0; + MODELIST *modeList = NULL; + + modeCount = 0; + + memset(&devMode, 0x00, sizeof(DEVMODE)); + devMode.dmSize = sizeof(DEVMODE); + + while(EnumDisplaySettings(NULL, modeCount, &devMode)) + { + modeCount++; + + if(devMode.dmBitsPerPel != COLOR_DEPTH) + { + continue; + } + + if(ChangeDisplaySettings(&devMode, CDS_TEST) != DISP_CHANGE_SUCCESSFUL) + { + continue; + } + } + + modeList = (MODELIST *)malloc(modeCount * sizeof(MODELIST)); + memset(modeList, 0x00, modeCount * sizeof(MODELIST)); + modeListCount = modeCount; + modeCount = 0; + + memset(&devMode, 0x00, sizeof(DEVMODE)); + devMode.dmSize = sizeof(DEVMODE); + + while(EnumDisplaySettings(NULL, modeCount, &devMode)) + { + GLboolean found = GE_FALSE; + GLint count; + + modeCount++; + + if(devMode.dmBitsPerPel != COLOR_DEPTH) + { + continue; + } + + if(ChangeDisplaySettings(&devMode, CDS_TEST) == DISP_CHANGE_SUCCESSFUL) + { + for(count = 0; count < modeListCount; count++) + { + if(modeList[count].width == devMode.dmPelsWidth && + modeList[count].height == devMode.dmPelsHeight) + { + found = GE_TRUE; + break; + } + } + + if(!found) + { + sprintf(resolution, "%dx%d", devMode.dmPelsWidth, devMode.dmPelsHeight); + + if(!Cb(modeCount + 1, resolution, devMode.dmPelsWidth, devMode.dmPelsHeight, Context)) + { + free(modeList); + return modeCount; + } + + for(count = 0; count < modeListCount; count++) + { + if(modeList[count].width == 0 && modeList[count].height == 0) + { + modeList[count].width = devMode.dmPelsWidth; + modeList[count].height = devMode.dmPelsHeight; + break; + } + } + } + } + + modeCount++; + } + + free(modeList); + + Cb(modeCount + 1, "WindowMode", -1, -1, Context); + + return modeCount; +} + diff --git a/G3D/Engine/Drivers/OpenGl/Win32.h b/G3D/Engine/Drivers/OpenGl/Win32.h new file mode 100644 index 0000000..4b7694f --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/Win32.h @@ -0,0 +1,42 @@ +/****************************************************************************************/ +/* Win32.h */ +/* */ +/* Author: George McBay (gfm@my-deja.com) */ +/* Description: Win32-specific functionality for OpenGL driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* */ +/****************************************************************************************/ + +#ifndef WIN32_H +#define WIN32_H + +#include + +#include "DCommon.h" + +struct +{ + GLuint width; + GLuint height; + GLuint refresh; +} typedef MODELIST; + + +void WindowSetup(DRV_DriverHook *Hook); +void SetGLPixelFormat(DRV_DriverHook *Hook); +void WindowCleanup(); +void FlipGLBuffers(); +geBoolean SetFullscreen(DRV_DriverHook *Hook); +GLint EnumNativeModes(DRV_ENUM_MODES_CB *Cb, void *Context); + +#endif diff --git a/G3D/Engine/Drivers/OpenGl/glext.h b/G3D/Engine/Drivers/OpenGl/glext.h new file mode 100644 index 0000000..a506c25 --- /dev/null +++ b/G3D/Engine/Drivers/OpenGl/glext.h @@ -0,0 +1,255 @@ +#ifndef __glext_h_ +#define __glext_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright 1992-1999 Silicon Graphics, Inc. +** All Rights Reserved. +** +** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.; +** the contents of this file may not be disclosed to third parties, copied or +** duplicated in any form, in whole or in part, without the prior written +** permission of Silicon Graphics, Inc. +** +** RESTRICTED RIGHTS LEGEND: +** Use, duplication or disclosure by the Government is subject to restrictions +** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data +** and Computer Software clause at DFARS 252.227-7013, and/or in similar or +** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished - +** rights reserved under the Copyright Laws of the United States. +*/ + +#ifndef APIENTRY +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#define GL_ARB_multitexture 1 +#define GL_EXT_abgr 1 +#define GL_EXT_bgra 1 +#define GL_EXT_clip_volume_hint 1 +#define GL_EXT_compiled_vertex_array 1 +#define GL_EXT_cull_vertex 1 +#define GL_EXT_packed_pixels 1 +#define GL_EXT_point_parameters 1 +#define GL_EXT_stencil_wrap 1 +#define GL_EXT_texture_env_add 1 +#define GL_EXT_texture_env_combine 1 +#define GL_EXT_vertex_array 1 +#define GL_NV_texgen_reflection 1 +#define GL_NV_texture_env_combine4 1 +#define GL_WIN_swap_hint 1 + +/* EXT_abgr */ +#define GL_ABGR_EXT 0x8000 + +/* EXT_packed_pixels */ +#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 + +/* EXT_vertex_array */ +#define GL_VERTEX_ARRAY_EXT 0x8074 +#define GL_NORMAL_ARRAY_EXT 0x8075 +#define GL_COLOR_ARRAY_EXT 0x8076 +#define GL_INDEX_ARRAY_EXT 0x8077 +#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 +#define GL_EDGE_FLAG_ARRAY_EXT 0x8079 +#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A +#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B +#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C +#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D +#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E +#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F +#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 +#define GL_COLOR_ARRAY_SIZE_EXT 0x8081 +#define GL_COLOR_ARRAY_TYPE_EXT 0x8082 +#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 +#define GL_COLOR_ARRAY_COUNT_EXT 0x8084 +#define GL_INDEX_ARRAY_TYPE_EXT 0x8085 +#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 +#define GL_INDEX_ARRAY_COUNT_EXT 0x8087 +#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A +#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B +#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C +#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D +#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E +#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F +#define GL_COLOR_ARRAY_POINTER_EXT 0x8090 +#define GL_INDEX_ARRAY_POINTER_EXT 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 + +/* EXT_bgra */ +#define GL_BGR_EXT 0x80E0 +#define GL_BGRA_EXT 0x80E1 + +/* EXT_clip_volume_hint */ +#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 + +/* EXT_point_parameters */ +#define GL_POINT_SIZE_MIN_EXT 0x8126 +#define GL_POINT_SIZE_MAX_EXT 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 +#define GL_DISTANCE_ATTENUATION_EXT 0x8129 + +/* EXT_compiled_vertex_array */ +#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 +#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 + +/* EXT_cull_vertex */ +#define GL_CULL_VERTEX_EXT 0x81AA +#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB +#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC + +/* ARB_multitexture */ +#define GL_ACTIVE_TEXTURE_ARB 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 +#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 +#define GL_TEXTURE0_ARB 0x84C0 +#define GL_TEXTURE1_ARB 0x84C1 +#define GL_TEXTURE2_ARB 0x84C2 +#define GL_TEXTURE3_ARB 0x84C3 +#define GL_TEXTURE4_ARB 0x84C4 +#define GL_TEXTURE5_ARB 0x84C5 +#define GL_TEXTURE6_ARB 0x84C6 +#define GL_TEXTURE7_ARB 0x84C7 +#define GL_TEXTURE8_ARB 0x84C8 +#define GL_TEXTURE9_ARB 0x84C9 +#define GL_TEXTURE10_ARB 0x84CA +#define GL_TEXTURE11_ARB 0x84CB +#define GL_TEXTURE12_ARB 0x84CC +#define GL_TEXTURE13_ARB 0x84CD +#define GL_TEXTURE14_ARB 0x84CE +#define GL_TEXTURE15_ARB 0x84CF +#define GL_TEXTURE16_ARB 0x84D0 +#define GL_TEXTURE17_ARB 0x84D1 +#define GL_TEXTURE18_ARB 0x84D2 +#define GL_TEXTURE19_ARB 0x84D3 +#define GL_TEXTURE20_ARB 0x84D4 +#define GL_TEXTURE21_ARB 0x84D5 +#define GL_TEXTURE22_ARB 0x84D6 +#define GL_TEXTURE23_ARB 0x84D7 +#define GL_TEXTURE24_ARB 0x84D8 +#define GL_TEXTURE25_ARB 0x84D9 +#define GL_TEXTURE26_ARB 0x84DA +#define GL_TEXTURE27_ARB 0x84DB +#define GL_TEXTURE28_ARB 0x84DC +#define GL_TEXTURE29_ARB 0x84DD +#define GL_TEXTURE30_ARB 0x84DE +#define GL_TEXTURE31_ARB 0x84DF + +/* EXT_stencil_wrap */ +#define GL_INCR_WRAP_EXT 0x8507 +#define GL_DECR_WRAP_EXT 0x8508 + +/* NV_texgen_reflection */ +#define GL_NORMAL_MAP_NV 0x8511 +#define GL_REFLECTION_MAP_NV 0x8512 + +/* EXT_texture_env_combine */ +#define GL_COMBINE_EXT 0x8570 +#define GL_COMBINE_RGB_EXT 0x8571 +#define GL_COMBINE_ALPHA_EXT 0x8572 +#define GL_RGB_SCALE_EXT 0x8573 +#define GL_ADD_SIGNED_EXT 0x8574 +#define GL_INTERPOLATE_EXT 0x8575 +#define GL_CONSTANT_EXT 0x8576 +#define GL_PRIMARY_COLOR_EXT 0x8577 +#define GL_PREVIOUS_EXT 0x8578 +#define GL_SOURCE0_RGB_EXT 0x8580 +#define GL_SOURCE1_RGB_EXT 0x8581 +#define GL_SOURCE2_RGB_EXT 0x8582 +#define GL_SOURCE0_ALPHA_EXT 0x8588 +#define GL_SOURCE1_ALPHA_EXT 0x8589 +#define GL_SOURCE2_ALPHA_EXT 0x858A +#define GL_OPERAND0_RGB_EXT 0x8590 +#define GL_OPERAND1_RGB_EXT 0x8591 +#define GL_OPERAND2_RGB_EXT 0x8592 +#define GL_OPERAND0_ALPHA_EXT 0x8598 +#define GL_OPERAND1_ALPHA_EXT 0x8599 +#define GL_OPERAND2_ALPHA_EXT 0x859A + +/* NV_texture_env_combine4 */ +#define GL_COMBINE4_NV 0x8503 +#define GL_SOURCE3_RGB_NV 0x8583 +#define GL_SOURCE3_ALPHA_NV 0x858B +#define GL_OPERAND3_RGB_NV 0x8593 +#define GL_OPERAND3_ALPHA_NV 0x859B + +/*************************************************************/ + +/* EXT_vertex_array */ +typedef void (APIENTRY * PFNGLARRAYELEMENTEXTPROC) (GLint i); +typedef void (APIENTRY * PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRY * PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRY * PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); +typedef void (APIENTRY * PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params); +typedef void (APIENTRY * PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRY * PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRY * PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRY * PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + +/* ARB_multitexture */ +typedef void (APIENTRY * PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target); +typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum target); + +/* EXT_compiled_vertex_array */ +typedef void (APIENTRY * PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); +typedef void (APIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void); + +/* EXT_cull_vertex */ +typedef void (APIENTRY * PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble* params); +typedef void (APIENTRY * PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat* params); + +/* WIN_swap_hint */ +typedef void (APIENTRY * PFNGLADDSWAPHINTRECTWINPROC) (GLint x, GLint y, GLsizei width, GLsizei height); + +/* EXT_point_parameter */ +typedef void (APIENTRY * PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRY * PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); + +#ifdef __cplusplus +} +#endif + +#endif /* __glext_h_ */ diff --git a/G3D/Engine/Drivers/SoftDrv/3dnowspan.h b/G3D/Engine/Drivers/SoftDrv/3dnowspan.h new file mode 100644 index 0000000..9cebe05 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/3dnowspan.h @@ -0,0 +1,83 @@ +/****************************************************************************************/ +/* 3dnowspan.h */ +/* */ +/* Author: Ken Baird */ +/* Description: Headers for 3dnow assembly calls */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +typedef struct EdgeAsmTag EdgeAsm; +typedef struct EdgeAsmFPUTag EdgeAsmFPU; + +//3dnow based non world faces +//DRV_RENDER_NO_ZMASK +extern void DrawScanLineGouraudNoZBufferZWrite_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +extern void DrawScanLineGouraudNoZBufferZWriteTrans_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//solid color +extern void DrawScanLineGouraudNoZBufferZWriteSolid_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); + +//DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE +extern void DrawScanLineGouraudNoZ_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +extern void DrawScanLineGouraudNoZTrans_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//solid color +extern void DrawScanLineGouraudNoZSolid_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); + +//DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudNoZAlphaTex_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_NO_ZMASK | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudNoZBufferZWriteAlphaTex_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_NO_ZMASK | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudZBufferNoZWriteAlphaTex_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_ALPHA +extern void DrawScanLineGouraudZBufferAlphaTex_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); + +//DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudNoZAlphaARGB_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_NO_ZMASK | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudNoZBufferZWriteAlphaARGB_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_NO_ZMASK | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudZBufferNoZWriteAlphaARGB_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_ALPHA +extern void DrawScanLineGouraudZBufferAlphaARGB_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); + +//!(DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE) +extern void DrawScanLineGouraudZBuffer_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +extern void DrawScanLineGouraudZBufferTrans_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//solid color +extern void DrawScanLineGouraudZBufferSolid_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); + +//DRV_RENDER_NO_ZWRITE +extern void DrawScanLineGouraudZBufferNoZWrite_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +extern void DrawScanLineGouraudZBufferNoZWriteTrans_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); +//solid color +extern void DrawScanLineGouraudZBufferNoZWriteSolid_Asm3DNow(EdgeAsm *pLeft, EdgeAsm *pRight); + + +//world perspective correct faces +extern void DrawSpan32_AsmLit3DNow(int32 x1, int32 x2, int32 y); +extern void DrawSpan32_AsmLitZWrite3DNow(int32 x1, int32 x2, int32 y); +extern void DrawSpan32_AsmLitZBuffer3DNow(int32 x1, int32 x2, int32 y); +extern void DrawSpan32_AsmGouraud3DNow(int32 x1, int32 x2, int32 y, geFloat r1, geFloat g1, geFloat b1, geFloat r2, geFloat g2, geFloat b2); +extern void DrawSpan32_AsmGouraudZWrite3DNow(int32 x1, int32 x2, int32 y, geFloat r1, geFloat g1, geFloat b1, geFloat r2, geFloat g2, geFloat b2); +extern void DrawSpan32_AsmGouraudZBuffer3DNow(int32 x1, int32 x2, int32 y, geFloat r1, geFloat g1, geFloat b1, geFloat r2, geFloat g2, geFloat b2); +extern void DrawSpan32_AsmGouraudZBufferAlphaARGB3DNow(int32 x1, int32 x2, int32 y, geFloat r1, geFloat g1, geFloat b1, geFloat r2, geFloat g2, geFloat b2); +extern void DrawSpan32_AsmGouraudZBufferVertexAlpha3DNow(int32 x1, int32 x2, int32 y, geFloat r1, geFloat g1, geFloat b1, geFloat r2, geFloat g2, geFloat b2); + +typedef struct EdgeAsmWorldTag EdgeAsmWorld; + +extern void Femms3DNow(void); +extern void StepWorld3DNow(EdgeAsmWorld *edge); \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv/REGISTER.H b/G3D/Engine/Drivers/SoftDrv/REGISTER.H new file mode 100644 index 0000000..1c999e3 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/REGISTER.H @@ -0,0 +1,64 @@ +/****************************************************************************************/ +/* register.h */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: Texture Handle code header file */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef REGISTER_H +#define REGISTER_H + +#include + +#include "ddraw.h" + +#include "DCommon.h" + +#define MAX_TEXTURE_HANDLES 15000 + +// THandle flags +#define THANDLE_UPDATE (1<<0) // Force a thandle to be uploaded to the card +#define THANDLE_TRANS (1<<2) // Texture has transparency +#define THANDLE_LOCKED (1<<3) // THandle is currently locked (invalid for rendering etc) + +typedef struct geRDriver_THandle +{ + int32 Active, Width, Height, MipLevels; + geRDriver_PixelFormat PixelFormat; + uint16 *BitPtr[16];//8 or 16 + geRDriver_THandle *PalHandle; + geRDriver_THandle *AlphaHandle; + + uint32 Flags; +} geRDriver_THandle; + +extern geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; + +geBoolean DRIVERCC DrvResetAll(void); +geRDriver_THandle *DRIVERCC CreateTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geBoolean DRIVERCC DestroyTexture(geRDriver_THandle *THandle); + +geBoolean DRIVERCC LockTextureHandle(geRDriver_THandle *THandle, int32 MipLevel, void **Data); +geBoolean DRIVERCC UnLockTextureHandle(geRDriver_THandle *THandle, int32 MipLevel); +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info); + +geBoolean DRIVERCC SetPalette(geRDriver_THandle *THandle, geRDriver_THandle *PalHandle); +geRDriver_THandle *DRIVERCC GetPalette(geRDriver_THandle *THandle); +geBoolean DRIVERCC SetAlpha(geRDriver_THandle *THandle, geRDriver_THandle *PalHandle); +geRDriver_THandle *DRIVERCC GetAlpha(geRDriver_THandle *THandle); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv/RENDER.H b/G3D/Engine/Drivers/SoftDrv/RENDER.H new file mode 100644 index 0000000..45afb39 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/RENDER.H @@ -0,0 +1,128 @@ +/****************************************************************************************/ +/* render.h */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: header for render.c */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef RENDER_H +#define RENDER_H + +#include + +#include "DCommon.h" +#include "Span.h" +#include "Register.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int32 Fixed16; + +#define ZBUFFER_PREC (65536.0f * 65536.0f) +//#define ZBUFFER_PREC (32768.0f * 65536.0f) + +extern int32 SpanMode; +extern int32 PolyMode; +extern BOOL PolyIsTrans; + +extern BOOL PolyVisible; +extern int32 ActuallVisible; +extern int32 NumPixels; + +extern int32 SMIN, SMAX; + +extern uint8 GMipLevel; // Miplevel passed by the latest rendering routine +extern int32 GMipLevel4, GMipLevel20, GMipLevel4_8; +extern int32 GLMapAdd; +extern DRV_LInfo *GLInfo; +extern DRV_Bitmap *GBitmap; +extern geRDriver_THandle *GTexture; +extern uint16 *pScrPtr16bpp; + +extern int32 GLightWidth; +extern uint8 *GLightData; + +extern int32 DeltaX, Remaining, N_Runs, PixelCount; +extern uint16 *Source, *Dest; +extern int32 U2, V2, StepU, StepV; +extern geFloat UDivZ, VDivZ, Zi, Z, Dx, Dy, PixelEnd; +extern int32 TxWhole, TyWhole, TxFract, TyFract; +extern geFloat UDivZnStepX, VDivZnStepX, ZinStepX; +extern int32 Junk[2]; + +extern geFloat Real16 ; +extern geFloat Real65536; + +extern int32 U, V; + +extern int32 GW, GWMask; +extern int32 GH, GHMask; +extern uint8 *GBitPtr; +extern uint16 *GBitPtr16; + +// 16bit zbuffer +extern uint16 *ZBuffer; + +extern geFloat UDivZStepX; +extern geFloat UDivZStepY; +extern geFloat VDivZStepX; +extern geFloat VDivZStepY; + +extern geFloat UDivZOrigin; +extern geFloat VDivZOrigin; +extern geFloat UDivZ16StepX, VDivZ16StepX, Zi16StepX; +extern geFloat UDivZ32StepX, VDivZ32StepX, Zi32StepX; + +extern geFloat ZiStepX; +extern geFloat ZiStepY; +extern geFloat ZiOrigin; + +extern Fixed16 UAdjust; +extern Fixed16 VAdjust; +extern Fixed16 UAdjustL; +extern Fixed16 VAdjustL; +extern Fixed16 UAdjust1; +extern Fixed16 VAdjust1; +extern Fixed16 UAdjust2; +extern Fixed16 VAdjust2; + +extern Fixed16 MaxU; +extern Fixed16 MaxV; + +#define ZBUFFER_SHIFT 21 +#define ZBUFFER_RIGHT_SHIFT 10 + +// 16bit zbuffer +extern uint16 *ZBuffer; + +#ifdef __cplusplus +} +#endif + +BOOL RenderInit(DRV_Window *Window); +BOOL RenderShutdown(void); +void ClearZBuffer(DRV_Window *Window); + +// Render funtions +BOOL DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags); +BOOL DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags); +BOOL DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, uint32 Flags); +BOOL DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y); + +#endif diff --git a/G3D/Engine/Drivers/SoftDrv/SAL.H b/G3D/Engine/Drivers/SoftDrv/SAL.H new file mode 100644 index 0000000..0432496 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/SAL.H @@ -0,0 +1,308 @@ +/****************************************************************************************/ +/* sal.h */ +/* */ +/* Description: GDI dib handling code */ +/* */ +/* Code fragments contributed by John Miles */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#ifndef SAL_VERSION + +#define SAL_VERSION "1.00" +#define SAL_VERSION_DATE "23-May-96" + +#endif + +#ifndef SAL_H +#define SAL_H + +#ifdef WIN32 + #define IS_WIN32 1 +#endif + +#ifdef _WIN32 + #define IS_WIN32 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// +// If compiling SAL library, use __declspec(dllexport) for both +// declarations and definitions +// +// If compiling SAL application, use __declspec(dllimport) for +// declarations -- definitions don't matter +// +// (DOS, other system definitions to be added later) +// +/* +#ifdef IS_WIN32 + + #define SALEXPORT WINAPI + + #ifdef BUILD_SAL + #define DXDEC __declspec(dllexport) + #define DXDEF __declspec(dllexport) + #else + #define DXDEC __declspec(dllimport) + #endif + +#else + + #define SALEXPORT + #define WINAPI + +#endif +*/ + +#define SALEXPORT WINAPI +#define DXDEC +#define DXDEF + +// +// Misc. constant definitions +// + +// +// General type definitions for portability +// + +#ifndef US_TYPEDEFS +#define US_TYPEDEFS + + typedef unsigned char U8 ; + typedef unsigned short U16; + typedef unsigned long U32; + typedef char C8 ; + typedef signed char S8 ; + typedef signed short S16; + typedef signed long S32; + +#endif + +#ifndef YES +#define YES 1 +#endif + +#ifndef NO +#define NO 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define SAL_FULLSCREEN 0 // Set fullscreen DDraw mode +#define SAL_WINDOW 1 // Set DIB windowed mode +#define SAL_TRY_FULLSCREEN 2 // Try fullscreen, fall back to DIB + +#define SAL_FRONT_SURFACE 0 +#define SAL_BACK_SURFACE 1 + +// +// Preference names and default values +// + +#define SAL_ALLOW_FRONT_LOCK 0 // Disregard request for front surface lock +#define DEFAULT_AFL NO + +#define SAL_BUFFER_IF_NO_LFB 1 // Use system RAM page buffer if no LFB available +#define DEFAULT_BINL YES + +#define SAL_DOS_MONO_DEBUG 2 // Set up monochrome TTY debug monitor for DOS +#define DEFAULT_DMD YES + +#define SAL_MAX_VIDEO_PAGES 3 // Allocate up to 3 video pages if possible +#define DEFAULT_MVP 3 + +#define SAL_ALLOW_WINDOW_RESIZE 4 // Allow window to be resized +#define DEFAULT_AWR YES + +#define SAL_PREVENT_ALT_MENU_POPUP 5 // Do not allow ALT to pause app +#define DEFAULT_PAMP YES + +#define SAL_ALWAYS_ON_TOP 6 // App has normal window Z order +#define DEFAULT_SAOT NO + +#define SAL_MAXIMIZE_TO_FULLSCREEN 7 // Maximize button switches to FS +#define DEFAULT_MTF YES + +#define N_SAL_PREFS 8 // # of preference types + +// +// Structures +// + +typedef struct +{ + U32 r; + U32 g; + U32 b; + S32 alpha; +} +SAL_RGB32; + +typedef struct +{ + S32 x0; + S32 y0; + S32 x1; + S32 y1; +} +SAL_REGION; + +typedef struct +{ + S32 x; + S32 y; + S32 width; + S32 height; +} +SAL_WINAREA; + +// +// Function pointer types +// + +typedef void (SALEXPORT * SALFOCUSCB) (S32 status); +typedef void (SALEXPORT * SALEXITCB) (void); + +// +// Miscellaneous/support services (not system-specific) +// + +DXDEC void __cdecl SAL_debug_printf (char *fmt, ...); + +DXDEC S32 WINAPI SAL_get_preference (U32 number); + +DXDEC S32 WINAPI SAL_set_preference (U32 number, + S32 value); + +// +// General services (not system-specific) +// + +DXDEC void WINAPI SAL_set_palette_entry (S32 index, + SAL_RGB32 *entry, + S32 wait_flag); + +DXDEC void WINAPI SAL_get_palette_entry (S32 index, + SAL_RGB32 *entry); + +DXDEC void WINAPI SAL_set_palette_range (S32 index, + S32 num_entries, + SAL_RGB32 *entry_list, + S32 wait_flag); + +DXDEC void WINAPI SAL_get_palette_range (S32 index, + S32 num_entries, + SAL_RGB32 *entry_list); + +DXDEC void WINAPI SAL_get_pixel_format (S32 *pixel_pitch, + S32 *bytes_per_pixel, + S32 *R_shift, + U32 *R_mask, + S32 *R_width, + S32 *G_shift, + U32 *G_mask, + S32 *G_width, + S32 *B_shift, + U32 *B_mask, + S32 *B_width); + + +DXDEC void WINAPI SAL_flip_surface (void); +DXDEF void WINAPI SAL_blit_surface (void); + +DXDEC void WINAPI SAL_wipe_surface (S32 surface, + U32 color); + +DXDEC void WINAPI SAL_lock_surface (S32 surface, + U8 **ptr, + S32 *pitch); + +DXDEC void WINAPI SAL_release_surface (S32 surface, + S32 perform_flip); + +DXDEC void WINAPI SAL_lock_region (S32 surface, + SAL_REGION region, + U8 **ptr, + S32 *pitch); + +DXDEC void WINAPI SAL_release_region (S32 surface, + SAL_REGION region); + +// +// Mouse services +// + +DXDEC void WINAPI SAL_show_system_mouse (void); +DXDEC void WINAPI SAL_hide_system_mouse (void); + +DXDEC void WINAPI SAL_constrain_mouse (void); +DXDEC void WINAPI SAL_unconstrain_mouse (void); + +// +// System-specific functions for Win32 version +// + +#ifdef IS_WIN32 + + DXDEC S32 WINAPI SAL_startup (BOOL FileLog); + DXDEC void WINAPI SAL_shutdown (void); + + DXDEC BOOL WINAPI SAL_set_main_window(HWND hWindow); + // CHANGE! (12/18/96) + // Must have a menu in my app. + DXDEC HWND WINAPI SAL_create_main_window (const char *MenuName); + + DXDEC S32 WINAPI SAL_set_display_mode (S32 display_size_X, + S32 display_size_Y, + S32 display_bpp, + S32 initial_window_mode, + S32 allow_mode_switch); + + DXDEC S32 WINAPI SAL_window_status (void); + DXDEC void WINAPI SAL_window_area (SAL_WINAREA *area); + DXDEC void WINAPI SAL_client_area (SAL_WINAREA *area); + DXDEC S32 WINAPI SAL_set_window_area (SAL_WINAREA *area); + DXDEC S32 WINAPI SAL_is_app_active (void); + DXDEC SALFOCUSCB WINAPI SAL_register_focus_callback (SALFOCUSCB fn); + DXDEC WNDPROC WINAPI SAL_register_WNDPROC (WNDPROC fn); + + DXDEC void WINAPI SAL_serve_message_queue (void); + + DXDEC void __cdecl SAL_error_box (C8 *caption, + C8 *fmt, ...); + // CHANGE! (12/18/96) John Pollard + DXDEC void WINAPI SAL_GetBackBufferDC(HDC *dc); + DXDEC void WINAPI SAL_ReleaseBackBufferDC(HDC dc); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Engine/Drivers/SoftDrv/SCENE.H b/G3D/Engine/Drivers/SoftDrv/SCENE.H new file mode 100644 index 0000000..08acafe --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/SCENE.H @@ -0,0 +1,46 @@ +/****************************************************************************************/ +/* scene.h */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: scene header */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SCENE_H +#define SCENE_H + +#include + +#include "DCommon.h" + +#define RENDER_NONE 0 +#define RENDER_WORLD 1 +#define RENDER_MESHES 2 +#define RENDER_MODELS 3 + +extern int32 RenderMode; + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *WorldRect); +BOOL DRIVERCC EndScene(void); +BOOL DRIVERCC BeginWorld(void); +BOOL DRIVERCC EndWorld(void); +BOOL DRIVERCC BeginMeshes(void); +BOOL DRIVERCC EndMeshes(void); +BOOL DRIVERCC BeginModels(void); +BOOL DRIVERCC EndModels(void); + +#endif + diff --git a/G3D/Engine/Drivers/SoftDrv/SOFTDRV.H b/G3D/Engine/Drivers/SoftDrv/SOFTDRV.H new file mode 100644 index 0000000..e361f3a --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/SOFTDRV.H @@ -0,0 +1,104 @@ +/****************************************************************************************/ +/* softdrv.h */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: header for softdrv */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SOFTDRV_H +#define SOFTDRV_H + +#include "DCommon.h" +#include "ddraw.h" + +#ifdef __cplusplus +extern "C" DRV_Window ClientWindow; +#else +extern DRV_Window ClientWindow; +#endif + +extern DRV_Driver SOFTDRV; +extern DRV_CacheInfo CacheInfo; + +enum VidSurfFlags +{ + SYSTEM =1, //store buffer in system + VIDEO =2, //or video ram + HARDWARE =4, //refresh choices + DMABLT =8, + FASTBLT =16, + SAFEBLT =32, + FLIP =64, + DMAPAGELOCKREQUIRED =128,//pagelock for dma req + DMAASYNCH =256,//can do asynch dma + STRETCHMODE =512,//stretch to fit + MODEXMODE =1024 +}; + +typedef struct VidModeListTag +{ + uint32 width; + uint32 height; + uint32 pitch; + uint32 flags; //capabilities + uint32 current; //caps in use + uint32 bpp; +} VidModeList; + +typedef struct VidEnumInfoTag +{ + DDDEVICEIDENTIFIER DeviceInfo; + DDDEVICEIDENTIFIER DeviceInfoHost; + GUID *DeviceGuid; + VidModeList VidModes[128]; //let's be safe + int NumVidModes; + int CurrentVidMode; + uint32 bpp; //bytes per pixel +} VidEnumInfo; + +typedef struct CPUInfoTag +{ + uint32 MaxCPUIDVal; + char VendorString[16]; + char ProcName[48]; + uint32 ProcType; + uint32 ProcFamily; + uint32 ProcModel; + uint32 ProcStepping; + uint32 ProcSpeed; + BOOL HasRDTSC; + BOOL HasMMX; + BOOL Has3DNow; + BOOL HasFCMOV; +} CPUInfo; + +BOOL DRIVERCC DrvShutdown(void); +void DRIVERCC ErrorBox(char *Str); +void SetLastDrvError(S32 Error, char *ErrorStr); + +#ifdef __cplusplus +extern "C" { +#endif + +void ErrorPrintf(char *text, ...); +void DumpErrorLogToFile(char *fname); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv/SPAN.H b/G3D/Engine/Drivers/SoftDrv/SPAN.H new file mode 100644 index 0000000..cf29411 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/SPAN.H @@ -0,0 +1,59 @@ +/****************************************************************************************/ +/* span.h */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: Header for span.c and important defines */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SPAN_H +#define SPAN_H + +#include "basetype.h" + +#define MAXSPANS 25000 +#define MAXSCANLINES 768 + +typedef struct SList +{ + uint8 Used; + int32 Min, Max; + geFloat z1, z2; // So we can spit z spans out for other spans that need to be occluded + uint32 Flags; + struct SList *Last; + struct SList *Next; +} SList; + +typedef struct +{ + SList *First; + SList *Current; +} SpanMinMax; + +extern int32 NumCachedAlphaPolys; +extern int32 NumCachedAlphaSpans; + +SList *NewSList(void); +void FreeSList(SList *s); +void ResetSList(void); +void ResetSpans(uint32 Rows); + +extern SpanMinMax SMinMax[MAXSCANLINES]; +extern SList ScanHash[MAXSPANS]; // hash table for SList +extern int32 CurrentSList; + + +#endif diff --git a/G3D/Engine/Drivers/SoftDrv/SYSTEM.H b/G3D/Engine/Drivers/SoftDrv/SYSTEM.H new file mode 100644 index 0000000..db9e446 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/SYSTEM.H @@ -0,0 +1,31 @@ +/****************************************************************************************/ +/* system.h */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: header for system.c */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SYSTEM_H +#define SYSTEM_H + +#include +#include + +BOOL SysInit(void); +BOOL SysShutdown(void); + +#endif diff --git a/G3D/Engine/Drivers/SoftDrv/SoftDrv.dsp b/G3D/Engine/Drivers/SoftDrv/SoftDrv.dsp new file mode 100644 index 0000000..e7e030a --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/SoftDrv.dsp @@ -0,0 +1,304 @@ +# Microsoft Developer Studio Project File - Name="SoftDrv" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=SoftDrv - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SoftDrv.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SoftDrv.mak" CFG="SoftDrv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SoftDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "SoftDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Source/Engine/Drivers/SoftDrv", EVPBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SoftDrv - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /X /I "..\..\.." /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\..\Sdk\Dx6SDK\Include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 /nologo /dll /machine:I386 /nodefaultlib + +!ELSEIF "$(CFG)" == "SoftDrv - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /X /I "..\..\.." /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\..\Sdk\Dx6SDK\Include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "SoftDrv - Win32 Release" +# Name "SoftDrv - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\3dnowspan.h +# End Source File +# Begin Source File + +SOURCE=.\amdspan.asm + +!IF "$(CFG)" == "SoftDrv - Win32 Release" + +# Begin Custom Build +InputPath=.\amdspan.asm + +".\amdspan.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ..\..\..\..\masm\bin\ml -c -I ..\..\..\..\masm\include -coff amdspan.asm + +# End Custom Build + +!ELSEIF "$(CFG)" == "SoftDrv - Win32 Debug" + +# Begin Custom Build +InputPath=.\amdspan.asm + +".\amdspan.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ..\..\..\..\masm\bin\ml -c -I ..\..\..\..\masm\include -coff amdspan.asm + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\dmodes.c +# End Source File +# Begin Source File + +SOURCE=.\dmodes.h +# End Source File +# Begin Source File + +SOURCE=.\drawspan.c +# End Source File +# Begin Source File + +SOURCE=.\drawspan.h +# End Source File +# Begin Source File + +SOURCE=.\register.c +# End Source File +# Begin Source File + +SOURCE=.\Register.h +# End Source File +# Begin Source File + +SOURCE=.\render.c +# End Source File +# Begin Source File + +SOURCE=.\Render.h +# End Source File +# Begin Source File + +SOURCE=.\Sal.h +# End Source File +# Begin Source File + +SOURCE=.\scene.c +# End Source File +# Begin Source File + +SOURCE=.\Scene.h +# End Source File +# Begin Source File + +SOURCE=.\softdrv.c +# End Source File +# Begin Source File + +SOURCE=.\Softdrv.h +# End Source File +# Begin Source File + +SOURCE=.\span.c +# End Source File +# Begin Source File + +SOURCE=.\Span.h +# End Source File +# Begin Source File + +SOURCE=.\system.c +# End Source File +# Begin Source File + +SOURCE=.\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Math\Vec3d.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Math\Vec3d.h +# End Source File +# Begin Source File + +SOURCE=.\W32sal.cpp +# End Source File +# Begin Source File + +SOURCE=.\x86span555.c +# End Source File +# Begin Source File + +SOURCE=.\x86span555.h +# End Source File +# Begin Source File + +SOURCE=.\x86span565.c +# End Source File +# Begin Source File + +SOURCE=.\x86span565.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Math\Xform3d.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Math\Xform3d.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Winspool.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Comdlg32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Gdi32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Kernel32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Libcmt.lib + +!IF "$(CFG)" == "SoftDrv - Win32 Release" + +!ELSEIF "$(CFG)" == "SoftDrv - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Libcmtd.lib + +!IF "$(CFG)" == "SoftDrv - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "SoftDrv - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Oldnames.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Shell32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\User32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Uuid.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Advapi32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Winmm.lib +# End Source File +# End Group +# End Target +# End Project diff --git a/G3D/Engine/Drivers/SoftDrv/SoftDrv.mak b/G3D/Engine/Drivers/SoftDrv/SoftDrv.mak new file mode 100644 index 0000000..f706f17 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/SoftDrv.mak @@ -0,0 +1,319 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on SoftDrv.dsp +!IF "$(CFG)" == "" +CFG=SoftDrv - Win32 Debug +!MESSAGE No configuration specified. Defaulting to SoftDrv - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "SoftDrv - Win32 Release" && "$(CFG)" != "SoftDrv - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SoftDrv.mak" CFG="SoftDrv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SoftDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "SoftDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SoftDrv - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +ALL : "$(OUTDIR)\SoftDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\dmodes.obj" + -@erase "$(INTDIR)\drawspan.obj" + -@erase "$(INTDIR)\register.obj" + -@erase "$(INTDIR)\render.obj" + -@erase "$(INTDIR)\scene.obj" + -@erase "$(INTDIR)\softdrv.obj" + -@erase "$(INTDIR)\span.obj" + -@erase "$(INTDIR)\system.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\Vec3d.obj" + -@erase "$(INTDIR)\W32sal.obj" + -@erase "$(INTDIR)\x86span555.obj" + -@erase "$(INTDIR)\x86span565.obj" + -@erase "$(INTDIR)\Xform3d.obj" + -@erase "$(OUTDIR)\SoftDrv.dll" + -@erase "$(OUTDIR)\SoftDrv.exp" + -@erase "$(OUTDIR)\SoftDrv.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MT /W3 /GX /O2 /X /I "..\..\.." /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\..\Sdk\Dx6SDK\Include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV_EXPORTS" /Fp"$(INTDIR)\SoftDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\SoftDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:no /pdb:"$(OUTDIR)\SoftDrv.pdb" /machine:I386 /nodefaultlib /out:"$(OUTDIR)\SoftDrv.dll" /implib:"$(OUTDIR)\SoftDrv.lib" +LINK32_OBJS= \ + "$(INTDIR)\dmodes.obj" \ + "$(INTDIR)\drawspan.obj" \ + "$(INTDIR)\register.obj" \ + "$(INTDIR)\render.obj" \ + "$(INTDIR)\scene.obj" \ + "$(INTDIR)\softdrv.obj" \ + "$(INTDIR)\span.obj" \ + "$(INTDIR)\system.obj" \ + "$(INTDIR)\Vec3d.obj" \ + "$(INTDIR)\W32sal.obj" \ + "$(INTDIR)\x86span555.obj" \ + "$(INTDIR)\x86span565.obj" \ + "$(INTDIR)\Xform3d.obj" \ + "..\..\..\..\MSDev60\lib\Winspool.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmt.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\MSDev60\lib\Winmm.lib" \ + ".\amdspan.obj" + +"$(OUTDIR)\SoftDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "SoftDrv - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\SoftDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\dmodes.obj" + -@erase "$(INTDIR)\drawspan.obj" + -@erase "$(INTDIR)\register.obj" + -@erase "$(INTDIR)\render.obj" + -@erase "$(INTDIR)\scene.obj" + -@erase "$(INTDIR)\softdrv.obj" + -@erase "$(INTDIR)\span.obj" + -@erase "$(INTDIR)\system.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(INTDIR)\Vec3d.obj" + -@erase "$(INTDIR)\W32sal.obj" + -@erase "$(INTDIR)\x86span555.obj" + -@erase "$(INTDIR)\x86span565.obj" + -@erase "$(INTDIR)\Xform3d.obj" + -@erase "$(OUTDIR)\SoftDrv.dll" + -@erase "$(OUTDIR)\SoftDrv.exp" + -@erase "$(OUTDIR)\SoftDrv.ilk" + -@erase "$(OUTDIR)\SoftDrv.lib" + -@erase "$(OUTDIR)\SoftDrv.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /X /I "..\..\.." /I "..\..\..\Support" /I "..\\" /I "..\..\..\Math" /I "..\..\..\Bitmap" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\..\Sdk\Dx6SDK\Include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV_EXPORTS" /Fp"$(INTDIR)\SoftDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\SoftDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:yes /pdb:"$(OUTDIR)\SoftDrv.pdb" /debug /machine:I386 /nodefaultlib /out:"$(OUTDIR)\SoftDrv.dll" /implib:"$(OUTDIR)\SoftDrv.lib" /pdbtype:sept +LINK32_OBJS= \ + "$(INTDIR)\dmodes.obj" \ + "$(INTDIR)\drawspan.obj" \ + "$(INTDIR)\register.obj" \ + "$(INTDIR)\render.obj" \ + "$(INTDIR)\scene.obj" \ + "$(INTDIR)\softdrv.obj" \ + "$(INTDIR)\span.obj" \ + "$(INTDIR)\system.obj" \ + "$(INTDIR)\Vec3d.obj" \ + "$(INTDIR)\W32sal.obj" \ + "$(INTDIR)\x86span555.obj" \ + "$(INTDIR)\x86span565.obj" \ + "$(INTDIR)\Xform3d.obj" \ + "..\..\..\..\MSDev60\lib\Winspool.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmtd.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\MSDev60\lib\Winmm.lib" \ + ".\amdspan.obj" + +"$(OUTDIR)\SoftDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("SoftDrv.dep") +!INCLUDE "SoftDrv.dep" +!ELSE +!MESSAGE Warning: cannot find "SoftDrv.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "SoftDrv - Win32 Release" || "$(CFG)" == "SoftDrv - Win32 Debug" +SOURCE=.\amdspan.asm + +!IF "$(CFG)" == "SoftDrv - Win32 Release" + +InputPath=.\amdspan.asm + +".\amdspan.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + < +#include +#include +#include +#include + +#include "sal.h" + +#include +#include +#include +#include +#include + + +//#ifdef SAL_USE_D3D +// #include "d3dhal.h" +//#endif + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ SAL statics and globals ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +// +// Common variables +// + +static S32 desktop_w; // Windows desktop width, height +static S32 desktop_h; + +static S32 cursor_state; // Copy of Windows mouse hide/show state +static S32 show_count; // System mouse cursor show count + +static char debug_log_filename[256]; +static S32 log_to_file; // TRUE if user wants debug log + +static S32 app_minimized; // TRUE if this SAL app has been minimized +static S32 app_active; // TRUE if this SAL app has input focus +static S32 app_terminated; // TRUE if app has received its quit message + +static SALEXITCB exit_callback; // Address of mandatory exit callback +static SALFOCUSCB focus_callback; // Address of focus callback, if any +static WNDPROC window_callback; // Address of WNDPROC, if any +static WNDPROC OldWindowProc; +static HANDLE hSem; // Semaphore to limit instances + +static S32 mode_change_request; // TRUE to toggle window/fullscreen + +static HINSTANCE hAppInstance; // Application instance handle +static HINSTANCE hDLLInstance; // DLL instance handle +static char szMyAppName[512]; // Application name +static HWND hWnd; // Handle to application window +static HANDLE hHook; // Handle to Windows hook object + +static S32 SAL_preference[N_SAL_PREFS]; // Preferences array + +static S32 mode_change_allowed; // TRUE if window/fullscreen toggle allowed +static S32 current_window_mode; // SAL_FULLSCREEN / SAL_WINDOW +static S32 current_bpp; // Mode info set by last call to +static S32 current_size_X; // SAL_set_display_mode +static S32 current_size_Y; + +static LOGPALETTE *pLogPal; // LOGPALETTE structure +static BITMAPINFO *pbmi; // BITMAPINFO structure +static BITMAPINFOHEADER *pbmih; // Pointer to pbmi header + +static SAL_RGB32 palette_state[256]; // Current state of all DAC registers + +// +// CreateDIBSection() (windowed mode) variables and related data +// + +static SAL_WINAREA area; // Location/size of window client area + +static S32 desktop_bpp; // Windows video mode BPP +static U32 desktop_R_bitmask; // Desktop high-color pixel format +static U32 desktop_G_bitmask; +static U32 desktop_B_bitmask; + +static U32 DIB_R_bitmask; // DIB high-color pixel format +static U32 DIB_G_bitmask; +static U32 DIB_B_bitmask; + +static U32 DIB_R_Shift; +static U32 DIB_G_Shift; +static U32 DIB_B_Shift; + +static S32 DIB_active; // CreateDIBSection() active if TRUE + +static U8 *lpDIBBuffer; // DIB image buffer +static HBITMAP hDIB; // Handle returned from CreateDIBSection +static HPALETTE hPalette; // Handle to palette if 8-bit mode in use + +static S32 palette_change_request; // TRUE to signal palette update + +static RECT original_window_rect; // Default size of DIB window +static SAL_WINAREA original_area; // Default size of client area +static LONG OldWindowLong_GWL_STYLE; // Old Window GWL_STYLE +static LONG OldWindowLong_GWL_EXSTYLE; // Old Window GWL_STYLE + +static RECT unconstrained_rect; // Default area of mouse constraint +static S32 constrain_state; // 1 if mouse limited to window area +static S32 constrain_request; // 1 if mouse should be constrained at next movement + +static HDC Context; +static HBITMAP DefaultBitmap; + +extern "C" long FAR PASCAL MyWndProc(HWND hWindow, UINT message, //) + WPARAM wParam, LPARAM lParam); + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ DLLMain() function to acquire DLL instance handle, etc. ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,//) + DWORD fdwReason, + LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + hDLLInstance = hinstDLL; + } + + return TRUE; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Serve Windows message queue, returning 0 if WM_QUIT message received ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +void serve_queue(void) +{ + /* + MSG msg; + + if (app_terminated) + { + return; + } + + // + // Serve message queue + // + + while (PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE)) + { + if (!GetMessage(&msg, NULL, 0, 0 )) + { + app_active = FALSE; + app_terminated = TRUE; + + (exit_callback)(); + + // + // Return statement should not be reached + // + + return; + } + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + */ +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Return rectangle containing client-area boundaries in screenspace ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +RECT *client_screen_rect(void) +{ + static RECT rect; + POINT ul,lr; + + GetClientRect(hWnd, &rect); + + ul.x = rect.left; + ul.y = rect.top; + lr.x = rect.right; + lr.y = rect.bottom; + + ClientToScreen(hWnd, &ul); + ClientToScreen(hWnd, &lr); + + SetRect(&rect, ul.x, ul.y, + lr.x-1, lr.y-1); + + return ▭ +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Mouse/keyboard event management ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +void MOUSE_event(unsigned long wParam, unsigned long lParam) +{ +} + +void KEYDOWN_event(unsigned long wParam, unsigned long lParam) +{ +} + +void KEYUP_event(unsigned long wParam, unsigned long lParam) +{ +} + +void CHAR_event(unsigned long wParam, unsigned long lParam) +{ +} + + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Shut down CreateDIBSection() services ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +void DIB_shutdown(void) +{ + if (constrain_state) + { + #ifndef DISABLED_BEHAVIOR + ClipCursor(&unconstrained_rect); + #endif + constrain_request = 0; + } + + if (DIB_active && SAL_is_app_active()) + { + SAL_wipe_surface(SAL_BACK_SURFACE, 0); + SAL_flip_surface(); + } + + if (hDIB != NULL) + { + DeleteObject(hDIB); + hDIB = NULL; + } + + if (hPalette != NULL) + { + DeleteObject(hPalette); + hPalette = NULL; + } + /* + // + // Make sure we restore the old hWnd parms + // + SetWindowLong(hWnd, + GWL_STYLE, + OldWindowLong_GWL_STYLE); + SetWindowLong(hWnd, + GWL_EXSTYLE, + OldWindowLong_GWL_EXSTYLE); + SetWindowPos(hWnd, + HWND_TOP, + original_area.x, + original_area.y, + original_area.width, + original_area.height, + SWP_NOCOPYBITS | SWP_NOZORDER); + + ShowWindow(hWnd, SW_SHOWNORMAL); + */ + DIB_active = 0; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Start up CreateDIBSection() services for windowed display ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +S32 DIB_startup(S32 display_size_X,//) + S32 display_size_Y, + S32 display_bpp) +{ + HDC hdc; + COLORREF color,save; + RECT window_rect; + + area.x = 0; + area.y = 0; + area.width = display_size_X; + area.height = display_size_Y; + original_area = area; + + GetWindowRect(hWnd, &window_rect); + original_window_rect = window_rect; + + OldWindowLong_GWL_STYLE = GetWindowLong(hWnd, GWL_STYLE); + OldWindowLong_GWL_EXSTYLE = GetWindowLong(hWnd, GWL_EXSTYLE); + + display_size_X = area.width; + display_size_Y = area.height; + + // Get desktop size + // + /* + desktop_w = GetSystemMetrics(SM_CXSCREEN); + desktop_h = GetSystemMetrics(SM_CYSCREEN); + + // + // Enable caption menu and user preferences + // + + SetWindowLong(hWnd, + GWL_STYLE, + GetWindowLong(hWnd, GWL_STYLE) & ~WS_POPUP); + + SetWindowLong(hWnd, + GWL_STYLE, + GetWindowLong(hWnd, GWL_STYLE) | (WS_OVERLAPPED | + WS_CAPTION | + WS_SYSMENU | + WS_MINIMIZEBOX)); + + if (SAL_get_preference(SAL_ALLOW_WINDOW_RESIZE)) + { + SetWindowLong(hWnd, + GWL_STYLE, + GetWindowLong(hWnd, GWL_STYLE) | WS_THICKFRAME | + WS_MAXIMIZEBOX); + } + + if (SAL_get_preference(SAL_ALWAYS_ON_TOP)) + { + SetWindowLong(hWnd, + GWL_EXSTYLE, + GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_TOPMOST); + } + else + { + SetWindowLong(hWnd, + GWL_EXSTYLE, + GetWindowLong(hWnd, GWL_EXSTYLE) & ~WS_EX_TOPMOST); + } + + // + // If area not already established, center window's client area on + // desktop, and size it to correspond to the display size for optimum + // performance (no stretching needed) + // + + //if (area.width == -1) + { + area.width = display_size_X; + area.height = display_size_Y; + + area.x = ((desktop_w - area.width ) / 2); + area.y = ((desktop_h - area.height) / 2); + } + + // + // Calculate adjusted position of window + // + // Do not allow overall window size to exceed desktop size; keep + // dividing height and width by 2 until entire window fits + // + // If window is offscreen (or almost entirely offscreen), center it + // + + do + { + retry = 0; + + window_rect.left = area.x; + window_rect.right = area.x + area.width - 1; + window_rect.top = area.y; + window_rect.bottom = area.y + area.height - 1; + + AdjustWindowRectEx(&window_rect, + GetWindowLong(hWnd, GWL_STYLE), + (GetMenu(hWnd) != NULL), + GetWindowLong(hWnd, GWL_EXSTYLE)); + + if ((window_rect.right - window_rect.left + 1) > desktop_w) + { + area.width >>= 1; + area.x = ((desktop_w - area.width ) / 2); + retry = 1; + } + + if ((window_rect.bottom - window_rect.top + 1) > desktop_h) + { + area.height >>= 1; + area.y = ((desktop_h - area.height) / 2); + retry = 1; + } + + if ((window_rect.left >= (desktop_w-16)) || + (window_rect.top >= (desktop_h-16)) || + (window_rect.right <= 16) || + (window_rect.bottom <= 16)) + { + area.x = ((desktop_w - area.width ) / 2); + area.y = ((desktop_h - area.height) / 2); + retry = 1; + } + } + while (retry); + + // + // Save window and client areas for restoration if maximize button pressed + // + + original_window_rect = window_rect; + original_area = area; + + // + // Set window size and position + // + + SetWindowPos(hWnd, + HWND_TOP, + window_rect.left, + window_rect.top, + window_rect.right - window_rect.left + 1, + window_rect.bottom - window_rect.top + 1, + SWP_NOCOPYBITS | SWP_NOZORDER); + + GetClientRect(hWnd, + &client_rect); + + SAL_debug_printf("SAL: Window at (%d,%d), client size = (%d,%d)\n", + window_rect.left, + window_rect.top, + client_rect.right, + client_rect.bottom); + + // + // Make window visible + // + + ShowWindow(hWnd, SW_SHOWNORMAL); + + // + // If mouse is constrained, limit its travel to the window area + // + + */ + + if (constrain_state) + { + constrain_request = 1; + } + + // + // Init DIB globals + // + + hDIB = NULL; + lpDIBBuffer = NULL; + hPalette = NULL; + + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biWidth = (display_size_X); + pbmih->biHeight = -(display_size_Y); + pbmih->biPlanes = 1; + pbmih->biBitCount = (U16) display_bpp; + pbmih->biSizeImage = 0; + pbmih->biXPelsPerMeter = 0; + pbmih->biYPelsPerMeter = 0; + pbmih->biClrUsed = 0; + pbmih->biClrImportant = 0; + + // + // Get Windows desktop display format (and masks, in high-color modes) + // + + hdc = GetDC(hWnd); + + desktop_bpp = GetDeviceCaps(hdc, BITSPIXEL) * + GetDeviceCaps(hdc, PLANES); + + SAL_debug_printf("SAL: Desktop = %dx%d, %d BPP\n",desktop_w, + desktop_h, + desktop_bpp); + + if(desktop_bpp > 8) + { + HBITMAP TempBmp; + BITMAPINFO TempInfo; + OSVERSIONINFO WinVer; + + memset(&WinVer, 0, sizeof(OSVERSIONINFO)); + WinVer.dwOSVersionInfoSize =sizeof(OSVERSIONINFO); + + GetVersionEx(&WinVer); + if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + TempBmp =CreateCompatibleBitmap(hdc, 8, 8); + if(TempBmp) + { + memset(&TempInfo, 0, sizeof(BITMAPINFO)); + TempInfo.bmiHeader.biSize =sizeof(BITMAPINFO); + TempInfo.bmiHeader.biBitCount =(U16)desktop_bpp; + TempInfo.bmiHeader.biCompression =BI_BITFIELDS; + + if(GetDIBits(hdc, TempBmp, 0, 0, NULL, &TempInfo, DIB_RGB_COLORS)) + { + desktop_R_bitmask =*((U32 *)&TempInfo.bmiColors[0]); + desktop_G_bitmask =*((U32 *)&TempInfo.bmiColors[1]); + desktop_B_bitmask =*((U32 *)&TempInfo.bmiColors[2]); + + SAL_debug_printf("(%x-%x-%x)\n", desktop_R_bitmask, desktop_G_bitmask, desktop_B_bitmask); + } + DeleteObject(TempBmp); + } + } + else + { + save = GetPixel(hdc,0,0); + + SetPixel(hdc,0,0,RGB(0x08,0x08,0x08)); + + color = GetPixel(hdc,0,0) & 0xffffff; + + SAL_debug_printf("SAL: Desktop pixel format = 0x%X ",color); + + switch (color) + { + // + // 0x000000 = 5-5-5 + // + + case 0x000000: + + SAL_debug_printf("(5-5-5)\n"); + + desktop_R_bitmask = 0x007c00; + desktop_G_bitmask = 0x0003e0; + desktop_B_bitmask = 0x00001f; + break; + + // + // 0x000800 = 5-6-5 + // + + case 0x000800: + + SAL_debug_printf("(5-6-5)\n"); + + desktop_R_bitmask = 0x00f800; + desktop_G_bitmask = 0x0007e0; + desktop_B_bitmask = 0x00001f; + break; + + // + // 0x080808 = 8-8-8 + // + + case 0x080808: + + SAL_debug_printf("(8-8-8)\n"); + + desktop_R_bitmask = 0xff0000; + desktop_G_bitmask = 0x00ff00; + desktop_B_bitmask = 0x0000ff; + break; + + default: + + SAL_debug_printf("(Unsupported, using 5-6-5)\n"); + + if ((desktop_bpp == 15) || (desktop_bpp == 16)) + { + desktop_R_bitmask = 0x00f800; + desktop_G_bitmask = 0x0007e0; + desktop_B_bitmask = 0x00001f; + } + break; + } + + SetPixel(hdc,0,0,save); + } + } + ReleaseDC(hWnd, hdc); + + // + // If DIB and desktop are both in 15/16-BPP mode, set DIB to desktop + // pixel format for maximum throughput + // + // Otherwise, set DIB to 5-6-5 mode if 16BPP DIB requested, or 8-8-8 mode + // if 24BPP DIB requested + // + // Finally, if 8BPP DIB requested, create GDI palette object based on + // current logical palette + // + + switch (display_bpp) + { + case 8: + + pbmih->biCompression = BI_RGB; + + hPalette = CreatePalette(pLogPal); + palette_change_request = TRUE; + break; + + case 16: + + pbmih->biCompression = BI_BITFIELDS; + + if ((desktop_bpp == 15) || (desktop_bpp == 16)) + { + *(U32 *) (&(pbmi->bmiColors[0])) = desktop_R_bitmask; + *(U32 *) (&(pbmi->bmiColors[1])) = desktop_G_bitmask; + *(U32 *) (&(pbmi->bmiColors[2])) = desktop_B_bitmask; + DIB_R_bitmask = desktop_R_bitmask; + DIB_G_bitmask = desktop_G_bitmask; + DIB_B_bitmask = desktop_B_bitmask; + + } + else + { + *(U32 *) (&(pbmi->bmiColors[0])) = 0x00f800; + *(U32 *) (&(pbmi->bmiColors[1])) = 0x0007e0; + *(U32 *) (&(pbmi->bmiColors[2])) = 0x00001f; + DIB_R_bitmask = 0x00f800; + DIB_G_bitmask = 0x0007e0; + DIB_B_bitmask = 0x00001f; + } + break; + + case 24: + + pbmih->biCompression = BI_BITFIELDS; + + *(U32 *) (&(pbmi->bmiColors[0])) = 0xff0000; + *(U32 *) (&(pbmi->bmiColors[1])) = 0x00ff00; + *(U32 *) (&(pbmi->bmiColors[2])) = 0x0000ff; + DIB_R_bitmask = 0xff0000; + DIB_G_bitmask = 0x00ff00; + DIB_B_bitmask = 0x0000ff; + break; + } + + // + // Allocate the DIB section ("back buffer") + // + + hdc = GetDC(hWnd); + + hDIB = CreateDIBSection(hdc, // Device context + pbmi, // BITMAPINFO structure + DIB_RGB_COLORS, // Color data type + (void **) &lpDIBBuffer, // Address of image map pointer + NULL, // File + 0); // Bitmap file offset + + ReleaseDC(hWnd, hdc); + + if (hDIB == NULL) + { + SAL_error_box(NULL,"CreateDIBSection() failed\n"); + DIB_shutdown(); + return FALSE; + } + + // + // Set global flag to indicate CreateDIBSection() is active + // + + DIB_active = 1; + + return TRUE; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Copy current contents of DIB buffer to output window ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +void DIB_refresh_surface(void) +{ + HDC hdc; + + hdc = GetDC(hWnd); + + // + // Select palette if desktop running in 8-bit mode + // + // If palette has changed, realize it + // + + if (desktop_bpp == 8) + { + SelectPalette(hdc, + hPalette, + 0); + + if (palette_change_request) + { + palette_change_request = 0; + RealizePalette(hdc); + } + } + + // + // Disable Boolean operations during stretching + // + + SetStretchBltMode(hdc, COLORONCOLOR); + + // + // Stretch bitmap to conform to the size of the output window + // + /* + StretchDIBits(hdc, // Destination DC + 0, // Destination X + 0, // Destination Y + area.width, // Destination (client area) width + area.height, // Destination (client area) height + 0, // Source X + 0, // Source Y + current_size_X, // Source (back buffer) width + current_size_Y, // Source (back buffer) height + lpDIBBuffer, // Pointer to source (back buffer) + pbmi, // Bitmap info for back buffer + DIB_RGB_COLORS, // Bitmap contains index values + SRCCOPY); // Do normal copy with stretching + */ + StretchDIBits(hdc, // Destination DC + 0, // Destination X + 0, // Destination Y + current_size_X, // Destination (client area) width + current_size_Y, // Destination (client area) height + 0, // Source X + 0, // Source Y + current_size_X, // Source (back buffer) width + current_size_Y, // Source (back buffer) height + lpDIBBuffer, // Pointer to source (back buffer) + pbmi, // Bitmap info for back buffer + DIB_RGB_COLORS, // Bitmap contains index values + SRCCOPY); // Do normal copy with stretching + + ReleaseDC(hWnd, hdc); +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Flip CreateDIBSection() surface (simulated by StretchDIB()) ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +void DIB_flip_surface(void) +{ + //while (1) + //{ + //serve_queue(); + + if (!SAL_is_app_active()) + { + Sleep(10); + } + else + { + DIB_refresh_surface(); + //break; + } + //} +} + +DXDEF void WINAPI SAL_blit_surface(void) +{ + DIB_flip_surface(); +} +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Wipe CreateDIBSection() surface ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +void DIB_wipe_surface (S32 surface,//) + U32 color) +{ + memset(lpDIBBuffer, + color, + current_size_X * current_size_Y * (current_bpp / 8)); +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Return pointer to CreateDIBSection() surface ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +void DIB_lock_surface (S32 surface,//) + U8 **ptr, + S32 *pitch) +{ + if (ptr != NULL) + { + *ptr = lpDIBBuffer; + } + + if (pitch != NULL) + { + *pitch = current_size_X * (current_bpp / 8); + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Release pointer to CreateDIBSection() surface ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +void DIB_release_surface (S32 surface,//) + S32 perform_flip) +{ + if (perform_flip) + { + SAL_flip_surface(); + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Start up SAL services ÛÛ +//ÛÛ ÛÛ +//ÛÛ Initialize preferences ÛÛ +//ÛÛ ÛÛ +//ÛÛ Non-zero: Success ÛÛ +//ÛÛ 0: Failure ÛÛ +//ÛÛ -1: Attempt to launch multiple instances ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF S32 WINAPI SAL_startup(BOOL FileLog) +{ + log_to_file = FileLog; + strcpy(debug_log_filename, "debug.txt"); + + app_active = FALSE; // App not activated yet + app_terminated = FALSE; // App not terminated yet + app_minimized = FALSE; // App not minimized by default + + show_count = 0; // Mouse cursor show count + cursor_state = 1; // (Windows cursor is on by default) + constrain_state = 0; // Mouse is not constrained to window + constrain_request = 0; // Mouse should not be constrained at next movement + + area.width = -1; + + focus_callback = NULL; + window_callback = NULL; + hWnd = NULL; + hHook = NULL; + mode_change_request = FALSE; + hSem = NULL; + + DIB_active = FALSE; + + mode_change_allowed = FALSE; + current_window_mode = SAL_FULLSCREEN; + current_bpp = 0; + current_size_X = 0; + current_size_Y = 0; + + palette_change_request = FALSE; + + // + // Get original mouse constraint area (normally entire screen) + // + #ifndef DISABLED_BEHAVIOR + GetClipCursor(&unconstrained_rect); + #endif + // + // Allocate palette and bitmap structures at startup time to avoid + // memory fragmentation during mode switches + // + // Clear palette structure to black to avoid screen flash when + // setting initial mode + // + + pLogPal = (LOGPALETTE *) + malloc (sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256)); + + if (pLogPal == NULL) + { + return 0; + } + + memset(pLogPal,0, sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256)); + + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = 256; + + pbmi = (BITMAPINFO *) + malloc(sizeof (BITMAPINFOHEADER) + (sizeof (RGBQUAD) * 256)); + + if (pbmi == NULL) + { + free(pLogPal); + return 0; + } + + memset(pbmi, 0, sizeof (BITMAPINFOHEADER) + (sizeof (RGBQUAD) * 256)); + + pbmih = &(pbmi->bmiHeader); + + return TRUE; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ System Abstraction Layer exit function ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_shutdown(void) +{ +// if (OldWindowProc) +// { +// SetWindowLong( hWnd, GWL_WNDPROC, (LONG)OldWindowProc); +// OldWindowProc = NULL; +// } + + if (DIB_active) + { + DIB_shutdown(); + } + + if (pbmi != NULL) + { + free(pbmi); + pbmi = NULL; + } + + if (pLogPal != NULL) + { + free(pLogPal); + pLogPal = NULL; + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Set SAL operational preferences and policies ÛÛ +//ÛÛ ÛÛ +//ÛÛ May be called by applications which need to alter the default ÛÛ +//ÛÛ behavior of the SAL system ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF S32 WINAPI SAL_set_preference(U32 number, S32 value) +{ + S32 old; + + old = SAL_preference[number]; + + SAL_preference[number] = value; + + return old; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Get SAL operational preferences and policies ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF S32 WINAPI SAL_get_preference(U32 number) +{ + return SAL_preference[number]; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Monochrome debug printf() function ÛÛ +//ÛÛ ÛÛ +//ÛÛ Text written to logfile if WIN.INI / DOS environment option enabled ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void __cdecl SAL_debug_printf(char *fmt, ...) +{ + static char work_string[4096]; + FILE *log; + + if ((fmt == NULL) || (strlen(fmt) > sizeof(work_string))) + { + strcpy(work_string, "(String missing or too large)"); + } + else + { + va_list ap; + + va_start(ap, + fmt); + + vsprintf(work_string, + fmt, + ap); + + va_end (ap); + } + + if (log_to_file) + { + log = fopen(debug_log_filename,"a+t"); + + if (log != NULL) + { + fprintf(log,"%s\n",work_string); + fclose(log); + } + } + + OutputDebugString(work_string); +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Message box display function ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void __cdecl SAL_error_box(C8 *caption, C8 *fmt, ...) +{ + static char work_string[4096]; + S32 restore_cursor; + + restore_cursor = cursor_state; + + if (!cursor_state) + { + #ifndef DISABLED_BEHAVIOR + ShowCursor(1); + #endif + } + + if ((fmt == NULL) || (strlen(fmt) > sizeof(work_string))) + { + strcpy(work_string, "(String missing or too large)"); + } + else + { + va_list ap; + + va_start(ap, + fmt); + + vsprintf(work_string, + fmt, + ap); + + va_end (ap); + } + + SAL_debug_printf("%s\n",work_string); + + // + // If DirectDraw active, display GDI surface for dialog box + // + + // + // If in 8-bpp mode, save current palette and switch to standard palette + // + + if (caption == NULL) + { + MessageBox(hWnd, + work_string, + "SAL Error", + MB_OK); + } + else + { + MessageBox(hWnd, + work_string, + caption, + MB_OK); + } + + if (!restore_cursor) + { + #ifndef DISABLED_BEHAVIOR + ShowCursor(0); + #endif + } +} + +DXDEF BOOL WINAPI SAL_set_main_window(HWND hWindow) +{ + hWnd = hWindow; + + app_active = TRUE; + +// OldWindowProc = (WNDPROC)SetWindowLong( hWnd, GWL_WNDPROC, (LONG)MyWndProc); + +// if (!OldWindowProc) +// return FALSE; + + return TRUE; +} +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Set display mode and window size ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF S32 WINAPI SAL_set_display_mode (S32 display_size_X,//) + S32 display_size_Y, + S32 display_bpp, + S32 initial_window_mode, + S32 allow_mode_switch) +{ + S32 result; + + // + // Shut down current video mode + // + + if (DIB_active) + { + DIB_shutdown(); + } + + // + // Hide or show mouse cursor, as appropriate + // + + if (show_count < 1) + { + // + // Hide mouse cursor if it's currently visible + // + + if (cursor_state) + { + cursor_state = 0; + #ifndef DISABLED_BEHAVIOR + ShowCursor(0); + #endif + + } + } + else + { + // + // Show mouse cursor if it's currently hidden + // + + if (!cursor_state) + { + cursor_state = 1; + #ifndef DISABLED_BEHAVIOR + ShowCursor(1); + #endif + } + } + + // + // Start up new video mode + // + + if (initial_window_mode == SAL_FULLSCREEN) + { + // + // SAL_FULLSCREEN: Set up fullscreen video mode using DirectDraw + // + + } + else if (initial_window_mode == SAL_WINDOW) + { + // + // SAL_WINDOW: Set up window using CreateDIBSection() + // + + result = DIB_startup(display_size_X, + display_size_Y, + display_bpp); + } + else if (initial_window_mode == SAL_TRY_FULLSCREEN) + { + assert(0); + + // + // SAL_TRY_FULLSCREEN: Use DirectDraw if possible/available, otherwise + // fall back automatically to CreateDIBSection() + // + + } + else + { + // + // Unknown window mode, return failure + // + + return FALSE; + } + + // + // If successful, update global variables to reflect new video mode + // + + if (result) + { + mode_change_allowed = allow_mode_switch; + current_window_mode = initial_window_mode; + current_bpp = display_bpp; + current_size_X = display_size_X; + current_size_Y = display_size_Y; + } + + return result; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Return current window mode ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF S32 WINAPI SAL_window_status (void) +{ + return current_window_mode; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Return area of client window in screen coordinates ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_client_area (SAL_WINAREA *area) +{ + RECT *rect; + + if (DIB_active) + { + rect = client_screen_rect(); + + area->x = rect->left; + area->y = rect->top; + area->width = rect->right - rect->left + 1; + area->height = rect->bottom - rect->top + 1; + } + +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Return area of entire window in screen coordinates ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_window_area (SAL_WINAREA *area) +{ + RECT window_rect; + + if (DIB_active) + { + GetWindowRect(hWnd, &window_rect); + + area->x = window_rect.left; + area->y = window_rect.top; + area->width = window_rect.right - window_rect.left + 1; + area->height = window_rect.bottom - window_rect.top + 1; + } + +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Return TRUE if app has input focus ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF S32 WINAPI SAL_is_app_active (void) +{ + return app_active; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Register app function to be called when focus gained or lost ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF SALFOCUSCB WINAPI SAL_register_focus_callback (SALFOCUSCB fn) +{ + SALFOCUSCB old; + + old = focus_callback; + + focus_callback = fn; + + return old; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Register application WNDPROC function ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF WNDPROC WINAPI SAL_register_WNDPROC (WNDPROC fn) +{ + WNDPROC old; + + old = window_callback; + + window_callback = fn; + + return old; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Service Windows message queue, handling any mode change request ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_serve_message_queue(void) +{ + S32 result; + + serve_queue(); + + if (mode_change_request && mode_change_allowed) + { + mode_change_request = 0; + + result = SAL_set_display_mode( + current_size_X, + current_size_Y, + current_bpp, + current_window_mode ^ (SAL_FULLSCREEN ^ SAL_WINDOW), + TRUE); + + // + // If window mode toggle did not succeed, restore original mode + // + + if (!result) + { + SAL_debug_printf("SAL: SAL_set_display_mode() failed, restoring old mode\n"); + + SAL_set_display_mode( + current_size_X, + current_size_Y, + current_bpp, + current_window_mode, + TRUE); + } + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Set a single palette entry ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_set_palette_entry (S32 index,//) + SAL_RGB32 *entry, + S32 wait_flag) +{ + // + // If we're not in 8BPP mode, bail out + // + + if (current_bpp != 8) + { + return; + } + + // + // Update global palette state + // + + palette_state[index] = *entry; + + pLogPal->palPalEntry[index].peRed = pbmi->bmiColors[index].rgbRed = (unsigned char) entry->r; + pLogPal->palPalEntry[index].peGreen = pbmi->bmiColors[index].rgbGreen = (unsigned char) entry->g; + pLogPal->palPalEntry[index].peBlue = pbmi->bmiColors[index].rgbBlue = (unsigned char) entry->b; + pLogPal->palPalEntry[index].peFlags = NULL; + + // + // Update DirectDraw palette, if appropriate + // + + + if (DIB_active) + { + if (hPalette != NULL) + { + DeleteObject(hPalette); + } + + hPalette = CreatePalette(pLogPal); + + palette_change_request = TRUE; + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Retrieve a single palette entry ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_get_palette_entry (S32 index,//) + SAL_RGB32 *entry) +{ + *entry = palette_state[index]; +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Set a range of palette entries ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_set_palette_range (S32 index,//) + S32 num_entries, + SAL_RGB32 *entry_list, + S32 wait_flag) +{ + S32 i; + S32 j; + + // + // If we're not in 8BPP mode, bail out + // + + if (current_bpp != 8) + { + return; + } + + // + // Update global palette state + // + + for (i=0; i < num_entries; i++) + { + palette_state[index+i] = entry_list[i]; + } + + for (i=0, j=index; i < num_entries; i++, j++) + { + pLogPal->palPalEntry[j].peRed = pbmi->bmiColors[j].rgbRed = (unsigned char) entry_list[i].r; + pLogPal->palPalEntry[j].peGreen = pbmi->bmiColors[j].rgbGreen = (unsigned char) entry_list[i].g; + pLogPal->palPalEntry[j].peBlue = pbmi->bmiColors[j].rgbBlue = (unsigned char) entry_list[i].b; + pLogPal->palPalEntry[j].peFlags = NULL; + } + + // + // Update DirectDraw palette, if appropriate + // + + + if (DIB_active) + { + if (hPalette != NULL) + { + DeleteObject(hPalette); + } + + hPalette = CreatePalette(pLogPal); + + palette_change_request = TRUE; + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Retrieve a range of palette entries ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_get_palette_range (S32 index,//) + S32 num_entries, + SAL_RGB32 *entry_list) +{ + for (int i=0; i < num_entries; i++) + { + entry_list[i] = palette_state[index+i]; + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Make back surface visible ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_flip_surface (void) +{ + if (DIB_active) + { + DIB_flip_surface(); + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Clear a surface to a desired color ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_wipe_surface (S32 surface,//) + U32 color) +{ + if (DIB_active) + { + DIB_wipe_surface(surface, color); + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Request a pointer to a surface's memory block ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_lock_surface (S32 surface,//) + U8 **ptr, + S32 *pitch) +{ + if (DIB_active) + { + DIB_lock_surface(surface, ptr, pitch); + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Release surface memory pointer, optionally performing page flip ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_release_surface (S32 surface,//) + S32 perform_flip) +{ + if (DIB_active) + { + DIB_release_surface(surface, perform_flip); + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Request a pointer to a region of surface memory ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_lock_region (S32 surface,//) + SAL_REGION region, + U8 **ptr, + S32 *pitch) +{ + +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Release surface region pointer ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_release_region (S32 surface,//) + SAL_REGION region) +{ +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Show system mouse cursor ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_show_system_mouse (void) +{ + ++show_count; + + if (show_count == 1) + { + // + // Show count has become 1, so show mouse cursor if it's currently + // hidden + // + + if (!cursor_state) + { + cursor_state = 1; + #ifndef DISABLED_BEHAVIOR + ShowCursor(1); + #endif + } + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Hide system mouse cursor ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_hide_system_mouse (void) +{ + --show_count; + + if (show_count == 0) + { + // + // Show count has become 0, so hide mouse cursor if it's currently + // visible + // + + if (cursor_state) + { + cursor_state = 0; + #ifndef DISABLED_BEHAVIOR + ShowCursor(0); + #endif + } + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Constrain mouse to limits of client area window in DIB mode ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_constrain_mouse(void) +{ + constrain_state = 1; + + if (DIB_active) + { + constrain_request = 1; + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Unconstrain mouse ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_unconstrain_mouse(void) +{ + constrain_state = 0; + + if (DIB_active) + { + #ifndef DISABLED_BEHAVIOR + ClipCursor(&unconstrained_rect); + #endif + constrain_request = 0; + } +} + +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ +//ÛÛ ÛÛ +//ÛÛ Get pixel format in current mode ÛÛ +//ÛÛ ÛÛ +//ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ + +DXDEF void WINAPI SAL_get_pixel_format(S32 *pixel_pitch, //) + S32 *bytes_per_pixel, + S32 *R_shift, + U32 *R_mask, + S32 *R_width, + S32 *G_shift, + U32 *G_mask, + S32 *G_width, + S32 *B_shift, + U32 *B_mask, + S32 *B_width) + +{ + S32 red_shift; + U32 red_mask; + S32 red_width; + S32 grn_shift; + U32 grn_mask; + S32 grn_width; + S32 blu_shift; + U32 blu_mask; + S32 blu_width; + S32 i; + + // + // Handle palettized (8 BPP) modes + // + // Write 8-bit pixel pitch and visible bytes/pixel fields + // If we're in 8BPP mode, exit without altering RGB fields + // + + if (current_bpp == 8) + { + if (pixel_pitch != NULL) *pixel_pitch = 1; + if (bytes_per_pixel != NULL) *bytes_per_pixel = 1; + + return; + } + + // + // Handle hi-color (16+ BPP) modes + // + // If using DirectDraw, do a GetPixelFormat() call + // + // If using CreateDIBSection(), return mask values used to create DIB + // + + if (DIB_active) + { + if (pixel_pitch != NULL) *pixel_pitch = (current_bpp / 8); + if (bytes_per_pixel != NULL) *bytes_per_pixel = (current_bpp / 8); + + red_mask = DIB_R_bitmask; + grn_mask = DIB_G_bitmask; + blu_mask = DIB_B_bitmask; + } + + // + // Derive shift, width values from masks + // + + for (i=31; i >= 0; i--) + { + if (red_mask & (1 << i)) + { + red_shift = i; + } + + if (grn_mask & (1 << i)) + { + grn_shift = i; + } + + if (blu_mask & (1 << i)) + { + blu_shift = i; + } + } + + for (i=0; i <= 31; i++) + { + if (red_mask & (1 << i)) + { + red_width = i - red_shift + 1; + } + + if (grn_mask & (1 << i)) + { + grn_width = i - grn_shift + 1; + } + + if (blu_mask & (1 << i)) + { + blu_width = i - blu_shift + 1; + } + } + // + // Pass all requested values back to the caller + // + + if (R_shift != NULL) *R_shift = red_shift; + if (G_shift != NULL) *G_shift = grn_shift; + if (B_shift != NULL) *B_shift = blu_shift; + + if (R_mask != NULL) *R_mask = red_mask; + if (G_mask != NULL) *G_mask = grn_mask; + if (B_mask != NULL) *B_mask = blu_mask; + + if (R_width != NULL) *R_width = red_width; + if (G_width != NULL) *G_width = grn_width; + if (B_width != NULL) *B_width = blu_width; +} + +DXDEF HBITMAP WINAPI GetDIBHandle(void) +{ + return hDIB; +} + +DXDEF void WINAPI SAL_GetBackBufferDC(HDC *dc) +{ + if (DIB_active) + { + *dc = CreateCompatibleDC ( 0 ); + DefaultBitmap = SelectBitmap ( *dc, hDIB ); + } +} + +DXDEF void WINAPI SAL_ReleaseBackBufferDC(HDC dc) +{ + + if (DIB_active) + { + SelectBitmap ( dc, DefaultBitmap ); + DeleteDC ( dc ); + DeleteObject ( DefaultBitmap ); + } +} diff --git a/G3D/Engine/Drivers/SoftDrv/amdspan.asm b/G3D/Engine/Drivers/SoftDrv/amdspan.asm new file mode 100644 index 0000000..26e5ba4 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/amdspan.asm @@ -0,0 +1,13922 @@ +;****************************************************************************************/ +;* amdspan.asm */ +;* */ +;* Author: Ken Baird */ +;* Description: 3dnow render assembly */ +;* */ +;* The contents of this file are subject to the Genesis3D Public License */ +;* Version 1.01 (the "License"); you may not use this file except in */ +;* compliance with the License. You may obtain a copy of the License at */ +;* http://www.genesis3d.com */ +;* */ +;* Software distributed under the License is distributed on an "AS IS" */ +;* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +;* the License for the specific language governing rights and limitations */ +;* under the License. */ +;* */ +;* The Original Code is Genesis3D, released March 25, 1999. */ +;* Copyright (C) 1999 WildTangent Inc All Rights Reserved */ +;* */ +;****************************************************************************************/ +TITLE amdspan.asm +.586 +.K3D +.model FLAT,C +option language:c + +assume ds:FLAT,es:FLAT,ss:FLAT +assume fs:nothing,gs:nothing + +OPTION OLDSTRUCTS + + +EXTERNDEF GBitPtr:DWORD +EXTERNDEF ABitPtr:DWORD +EXTERNDEF SolidColor:DWORD +EXTERNDEF pTex:DWORD +EXTERNDEF ClientWindow:DWORD +EXTERNDEF Dest:DWORD +EXTERNDEF NumASpans:DWORD +EXTERNDEF RemainingCount:DWORD +EXTERNDEF UDivZStepX:DWORD +EXTERNDEF VDivZStepX:DWORD +EXTERNDEF ZiStepX:DWORD +EXTERNDEF UDivZStepY:DWORD +EXTERNDEF VDivZStepY:DWORD +EXTERNDEF ZiStepY:DWORD +EXTERNDEF UDivZ16StepX:DWORD +EXTERNDEF VDivZ16StepX:DWORD +EXTERNDEF Zi16StepX:DWORD +EXTERNDEF ZiOrigin:DWORD +EXTERNDEF FloatTemp:DWORD +EXTERNDEF GLMapMulU:DWORD +EXTERNDEF UAdjust:DWORD +EXTERNDEF UAdjustL:DWORD +EXTERNDEF TexPal:DWORD +EXTERNDEF ATexPal:DWORD +EXTERNDEF U1:DWORD +EXTERNDEF UFixed:DWORD +EXTERNDEF MaxU:DWORD +EXTERNDEF MaxV:DWORD +EXTERNDEF QFixedScaleLUT:DWORD +EXTERNDEF GMipLevel4_8:DWORD +EXTERNDEF GMipLevel20:DWORD +EXTERNDEF GLMapAdd:DWORD +EXTERNDEF GLightWidth:DWORD +EXTERNDEF GLightData:DWORD +EXTERNDEF ZBuffer:DWORD +EXTERNDEF Zero:QWORD +EXTERNDEF UV16:QWORD +EXTERNDEF UVLeft:QWORD +EXTERNDEF UVLeft2:QWORD +EXTERNDEF UVLeftW:QWORD +EXTERNDEF UVDivZ16StepX:QWORD +EXTERNDEF UVDivZStepX:QWORD +EXTERNDEF UVDivZStepY:QWORD +EXTERNDEF ARL:QWORD +EXTERNDEF GBL:QWORD +EXTERNDEF Q128:QWORD +EXTERNDEF WrapMask:QWORD +EXTERNDEF QFixedScale16:QWORD +EXTERNDEF QFixedScale:QWORD +EXTERNDEF UVDivZOrigin:QWORD +EXTERNDEF UVR:QWORD +EXTERNDEF ZIR:QWORD +EXTERNDEF UVZ:QWORD +EXTERNDEF GLMapMulUV:QWORD +EXTERNDEF UVL16:QWORD +EXTERNDEF UV162:QWORD +EXTERNDEF UV16V:QWORD +EXTERNDEF QShiftV:QWORD +EXTERNDEF LMapMask8:QWORD +EXTERNDEF UVAdjustL:QWORD +EXTERNDEF UVAdjust:QWORD +EXTERNDEF UVAdjust2:QWORD +EXTERNDEF QGMip20:QWORD +EXTERNDEF QGMip4_8:QWORD +EXTERNDEF QDibCan:QWORD +EXTERNDEF QZCan:QWORD +EXTERNDEF QDibOrCan:QWORD +EXTERNDEF QZOrCan:QWORD +EXTERNDEF QZVal:QWORD +EXTERNDEF QZDelta:QWORD +EXTERNDEF QZOut:QWORD +EXTERNDEF QDibOut:QWORD +EXTERNDEF SCan:QWORD +EXTERNDEF QZVal32_0:QWORD +EXTERNDEF QZVal32_1:QWORD +EXTERNDEF QZBufferPrec:QWORD +EXTERNDEF pZBufferPtr:DWORD +EXTERNDEF QNegAlpha:QWORD +EXTERNDEF RGBADelta:QWORD +EXTERNDEF VertAlpha:QWORD + +DRV_Window struc + hWnd dd ? + Buffer dd ? + BWidth dd ? + Height dd ? + PixelPitch dd ? + BytesPerPixel dd ? + R_shift dd ? + G_shift dd ? + B_shift dd ? + R_mask dd ? + G_mask dd ? + B_mask dd ? + R_width dd ? + G_width dd ? + B_width dd ? +DRV_Window ends + +EdgeAsm struc + X dd ? + yf dd ? + Height dd ? + xf dd ? + uf dd ? + vf dd ? + zf dd ? + rf dd ? + gf dd ? + bf dd ? + xstep dd ? + ustep dd ? + vstep dd ? + zstep dd ? + rstep dd ? + gstep dd ? + bstep dd ? +EdgeAsm ends + +;include listing.inc +;include amd3d.inc +include stdcall.inc + + + +_TEXT$01 SEGMENT PARA USE32 PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + + +;here's the standard 32 bit pal based combine with lightmap polydraw +;it's your basic subdivided affine mapper with an mmx combine +;no z operations in this loop +;prefetching is useless +;you might think doing pmulhw is a better idea rather than the +;additional shifts it takes to use pmullw... +;trouble is the lack of unsigned word ops + +cProc DrawSpan32_AsmLit3DNow, 12, + + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle ReturnLit + + + mov eax, y + + mov edx,x1 + mov ebx,offset ClientWindow + + shl edx, 2 + imul eax, [ebx].PixelPitch + + mov edi,[ebx].Buffer + + add edx,eax + mov eax,ecx + + add edi, edx + + shr ecx,4 + and eax,15 + jnz @f + dec ecx + mov eax,16 +@@: + + mov [NumASpans],ecx + mov [RemainingCount],eax + +; prefetch [GBitPtr] + ; mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 + movd mm0,x1 ; |x | | | | | | | + movq mm2,[UVDivZStepX] ; |x | |UZdX | | | | | + + movd mm1,y ; |x |y |UZdX | | | | | + movq mm3,[UVDivZStepY] ; |x |y |UZdX |UZdY | | | | + + punpckldq mm0,mm0 ; x|x |y |UZdX |UZdY | | | | + punpckldq mm1,mm1 ; x|x y|y UZdX|VZdX |UZdY | | | | + +; prefetch [GBitPtr+32] + + pi2fd mm0,mm0 + pi2fd mm1,mm1 + + pfmul mm2,mm0 ; x|x y|y UZX|VZX UZdY|VZdY | | | | + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZdY|VZdY |ZdX | | | + + pfmul mm3,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZdX | | | + movq mm6,[UVDivZOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZdX | |UZO | + +; prefetch [GBitPtr+64] + + movd mm5,[ZiStepY] ; x|x y|y UZX|VZX UZY|VZY |ZdX |ZdY |UZO | + pfmul mm4,mm0 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY |UZO | + + pfmul mm5,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO | + movd mm7,[ZiOrigin] + + pfadd mm6,mm2 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZXS|VZXS | + pfadd mm4,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZXS|VZXS | + +; prefetch [GBitPtr+96] + + pfadd mm6,mm3 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZ|VZ | + pfadd mm4,mm5 ; x|x y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ | + + movd mm7,[Zi16StepX] + + pfrcp mm0,mm4 ; ZL|ZL y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ | + movq mm1,mm6 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |Zi |ZY UZ|VZ | + + pfadd mm4,mm7 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ | + pfmul mm1,mm0 ; ZL|ZL UL|VL UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ | + +; prefetch [GBitPtr+128] + + pfrcp mm2,mm4 ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZ|VZ | + pfadd mm6,[UVDivZ16StepX] ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZR|VZR | + + pfmul mm2,mm6 ; ZL|ZL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR | + movq mm0,mm1 ; UL|VL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR | + + movq mm3,mm2 ; ULi|VLi UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR | + pfmul mm0,[QFixedScale] ; UL6|VL6 UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR | + + pfmul mm3,[QFixedScale] ; UL6|VL6 UL|VL UR6|UR6 UR6|UR6 |ZRi |ZY UZR|VZR | + pf2id mm0,mm0 ;UL6i|VL6i UL|VL UR6|VR6 UR6|VR6 |ZRi |ZY UZR|VZR | + + pf2id mm3,mm3 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR | +; prefetch [GBitPtr+160] + + test ecx,ecx + jz HandleLeftoverPixelsLit + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm7,[QFixedScale] + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm7,[UVAdjustL] + movq [UVL16],mm7 + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + +; prefetch [GBitPtr+192] + + cmp ebx,MaxU + jle TryClampU0Litp + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Litp + +TryClampU0Litp: + cmp ebx,0 + jge NoClampU0Litp + mov dword ptr[UVL16+4],0 +NoClampU0Litp: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Litp + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Litp + +TryClampV0Litp: + cmp eax,0 + jge NoClampV0Litp + mov dword ptr[UVL16],0 + +NoClampV0Litp: + +; prefetch [GBitPtr+224] + + movq mm7,[UVL16] + movq mm5,[UVL16] + + movq [UVLeftW],mm3 + psrad mm7,[QGMip4_8] + + psrld mm5,[QGMip20] + pand mm7,[LMapMask8] + + movq [UVL16],mm5 + movq mm3,mm7 + + punpckhwd mm7,mm7 + mov eax,dword ptr[UVL16] + +; prefetch [GLightData] + punpckldq mm7,mm7 + + movq mm5,[Zero] + imul eax,[GLightWidth] + + movq [UVZ],mm6 + punpcklwd mm3,mm3 + + add eax,dword ptr[UVL16+4] + movq mm6,[Zero] + + lea eax,[2*eax+eax] + + punpckldq mm3,mm3 + add eax,[GLightData] + + ;bilininterpolate to get good color + punpcklbw mm6,[eax+3] + mov ecx,[GLightWidth] + + punpcklbw mm5,[eax] + psrlw mm6,8 + + add eax,ecx + psrlw mm5,8 + + movq [UVLeft],mm2 + psubw mm6,mm5 + + movq mm2,[Zero] + psllw mm5,8 + + add eax,ecx + pmullw mm6,mm7 + + add eax,ecx + paddw mm6,mm5 + + movq mm5,[Zero] + punpcklbw mm2,[eax+3] + + punpcklbw mm5,[eax] + psrlw mm2,8 +; prefetch [GBitPtr+256] + + psrlw mm5,8 + psubw mm2,mm5 + + psllw mm5,8 + + pmullw mm2,mm7 + movq mm7,mm6 + + paddw mm2,mm5 + psrlw mm6,8 + + psrlw mm2,8 + + pfrcp mm5,mm4 + + psubw mm2,mm6 + + pmullw mm2,mm3 + + movq mm3,[UVLeftW] + + paddw mm7,mm2 + + psrlw mm7,8 + + movq mm2,mm7 + movq mm6,[UVZ] + + psllq mm2,16 + + punpckhwd mm7,mm2 + + psrlq mm2,16 + + punpckldq mm7,mm2 + + psllq mm7,8 + movq mm2,[UVLeft] + + movq [ARL],mm7 + + +SpanLoopLit: + ;use float uv for lightmap uv + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfmul mm7,mm2 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm5,[QFixedScale] + + pfmul mm7,[QFixedScale] + pf2id mm5,mm5 + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust] + + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust2] + + movq [UVL16],mm7 + movq [UVLeft],mm5 + + movd mm7,[Zi16StepX] + movq mm0,mm5 + + pfmul mm1,[QFixedScale16] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + ;right side stuff becomes left ; ULw|VLw DU16|DV16 UL|VL URw|VRw |ZLi |ZY UZL|VZL | + pfadd mm4,mm7 ;ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZL|VZL | + + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm7,[UVAdjustL] + movq [UV16],mm5 + + pfadd mm6,[UVDivZ16StepX] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm7,[UVL16] + + psrlq mm5,[QShiftV] + movq [UVL16],mm7 + + movq [UV16V],mm5 + + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU0Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Lit + +TryClampU0Lit: + cmp ebx,0 + jge NoClampU0Lit + mov dword ptr[UVL16+4],0 +NoClampU0Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Lit + +TryClampV0Lit: + cmp eax,0 + jge NoClampV0Lit + mov dword ptr[UVL16],0 + +NoClampV0Lit: + movq mm7,[UVL16] + movq mm5,[UVL16] + + movq [UVLeftW],mm3 + psrad mm7,[QGMip4_8] + + psrld mm5,[QGMip20] + pand mm7,[LMapMask8] + + movq [UVL16],mm5 + movq mm3,mm7 + + punpckhwd mm7,mm7 + mov eax,dword ptr[UVL16] + + movq mm5,[Zero] + imul eax,[GLightWidth] + + movq [UVZ],mm6 + punpcklwd mm3,mm3 + + add eax,dword ptr[UVL16+4] + movq mm6,[Zero] + + punpckldq mm7,mm7 + lea eax,[2*eax+eax] + + punpckldq mm3,mm3 + add eax,[GLightData] + + mov ecx,[GLightWidth] + + ;bilininterpolate to get good color + punpcklbw mm6,[eax+3] + punpcklbw mm5,[eax] + + psrlw mm6,8 + add eax,ecx + + psrlw mm5,8 + + movq [UVLeft],mm2 + psubw mm6,mm5 + + movq mm2,[Zero] + psllw mm5,8 + + add eax,ecx + pmullw mm6,mm7 + + add eax,ecx + paddw mm6,mm5 + + movq mm5,[Zero] + punpcklbw mm2,[eax+3] + + punpcklbw mm5,[eax] + psrlw mm2,8 + + psrlw mm5,8 + mov eax,dword ptr[UV16V] + + psubw mm2,mm5 + + mov ebx,dword ptr[UV16+4] + psllw mm5,8 + + mov esi,GBitPtr + pmullw mm2,mm7 + + paddw mm2,mm5 + movq mm7,mm6 + + psrlw mm2,8 + psrlw mm6,8 + + add esi,eax + shr ebx,16 + + psubw mm2,mm6 + add esi,ebx + + movq [ZIR],mm4 + pmullw mm2,mm3 + + xor eax,eax + mov ecx,TexPal + + paddw mm7,mm2 + + pfrcp mm5,mm4 + + psrlw mm7,8 + + movq mm2,mm7 + + psllq mm2,16 + + punpckhwd mm7,mm2 + + psrlq mm2,16 + + punpckldq mm7,mm2 + + movq mm4,[ARL] + psllq mm7,8 + + movq mm6,[ARL] + psrlw mm4,4 + + movq [ARL],mm7 + movq mm3,mm7 + + psrlw mm3,4 + + psubw mm3,mm4 + +; movq mm3,[Zero] + + + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movq [UVR],mm5 + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrlq mm4,[QShiftV] + + mov ebx,dword ptr[UV16+4] + movq [UV16V],mm4 + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + psrlw mm2,8 + + shr ebx,16 + add esi,ebx + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + add esi,edx + pmullw mm7,mm2 + + xor eax,eax + movq mm4,mm0 + + psrlw mm7,8 + + mov al,byte ptr[esi] + paddw mm6,mm3 + + pand mm4,[WrapMask] + movq mm2,mm6 + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlw mm2,8 + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + psrlq mm4,[QShiftV] + mov ebx,dword ptr[UV16+4] + + movq [UV16V],mm4 + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + paddd mm0,mm1 + + pmullw mm5,mm2 + mov esi,GBitPtr + + movq mm2,mm6 + psrlw mm5,8 + + + shr ebx,16 + psrlw mm2,8 + + add esi,edx + movq mm4,mm0 + + packuswb mm7,mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + add esi,ebx + + movq [edi],mm7 + xor eax,eax + + pand mm4,[WrapMask] + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + mov esi,GBitPtr + + mov ebx,dword ptr[UV16+4] + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + psrlw mm7,8 + shr ebx,16 + + movq mm4,mm0 + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + psrlw mm2,8 + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + movq mm2,mm6 + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+8],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + psrlw mm2,8 + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + psrlw mm7,8 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + psrlw mm2,8 + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + movq mm2,mm6 + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+16],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + psrlw mm2,8 + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + psrlw mm7,8 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + psrlw mm2,8 + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + movq mm2,mm6 + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+24],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + psrlw mm2,8 + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + psrlw mm7,8 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + psrlw mm2,8 + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + movq mm2,mm6 + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+32],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + psrlw mm2,8 + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + psrlw mm7,8 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + psrlw mm2,8 + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + movq mm2,mm6 + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + psrlw mm2,8 + + movq [edi+40],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + paddw mm6,mm3 + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + psrlw mm7,8 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + psrlw mm2,8 + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + movq mm2,mm6 + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + psrlw mm2,8 + + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+48],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + psrlw mm7,8 + + shr ebx,16 + + add esi,edx + psrlw mm2,8 + + add esi,ebx + + mov al,byte ptr[esi] + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + pmullw mm5,mm2 + psrlw mm5,8 + + packuswb mm7,mm5 + + movq [edi+56],mm7 + + ; get corrected right side deltas ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm4,[ZIR] + movq mm6,[UVZ] + + movq mm2,[UVR] + movq mm0,[UVLeftW] ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm1,[UVLeft] ; ULw|VLw UL|VL argb|ARGBagAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + punpckldq mm2,mm2 ; ULw|VLw UL|VL ZRi|ZRi agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + pfmul mm2,mm6 ; ULw|VLw UL|VL UR|VR agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + add edi,64 ; move screen pointer to start of next aspan + + movq mm3,mm2 + pfmul mm3,[QFixedScale] + + pf2id mm3,mm3 + + dec [NumASpans] ; dec num affine spans + jnz SpanLoopLit + +HandleLeftoverPixelsLit: + + + mov esi,GBitPtr + + cmp [RemainingCount],0 + jz ReturnLit + + mov eax,[RemainingCount] + mov dword ptr[ZIR],eax + mov dword ptr[ZIR+4],eax + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfsub mm6,[UVDivZ16StepX] + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + + pfmul mm5,[QFixedScale] + pi2fd mm3,[ZIR] + + pfmul mm7,[QFixedScale] + pfmul mm3,[UVDivZStepX] + + pf2id mm5,mm5 + pfadd mm3,mm6 + + pi2fd mm2,[ZIR] + movd mm6,[Zi16StepX] + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + pfsub mm4,mm6 + + movd mm6,[ZiStepX] + mov ebx,[RemainingCount] + + pfmul mm2,mm6 + + shl ebx,3 + + pfadd mm2,mm4 + paddd mm5,[UVAdjust] + + movq [UVL16],mm7 + pfrcp mm2,mm2 + + paddd mm5,[UVAdjust2] + pfmul mm2,mm3 + + movq [UVLeft],mm5 + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + pfmul mm1,qword ptr[QFixedScaleLUT+ebx] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm0,mm5 + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq [UV16],mm5 + movq mm7,[UVAdjustL] + + psrlq mm5,[QShiftV] + paddd mm7,[UVL16] + + movq [UV16V],mm5 + movq [UVL16],mm7 + + +OnePixelSpanLit: + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU1Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU1Lit + +TryClampU1Lit: + cmp ebx,0 + jge NoClampU1Lit + mov dword ptr[UVL16+4],0 +NoClampU1Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV1Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV1Lit + +TryClampV1Lit: + cmp eax,0 + jge NoClampV1Lit + mov dword ptr[UVL16],0 + +NoClampV1Lit: + movq mm7,[UVL16] + movq mm5,[UVL16] + + psrad mm7,[QGMip4_8] + psrld mm5,[QGMip20] + + pand mm7,[LMapMask8] + movq [UVL16],mm5 + + movq mm3,mm7 + punpckhwd mm7,mm7 + + mov eax,dword ptr[UVL16] + movq mm5,[Zero] + + imul eax,[GLightWidth] + punpcklwd mm3,mm3 + + add eax,dword ptr[UVL16+4] + movq mm6,[Zero] + + punpckldq mm7,mm7 + lea eax,[2*eax+eax] + + punpckldq mm3,mm3 + add eax,[GLightData] + + ;bilininterpolate to get good color + punpcklbw mm6,[eax+3] + mov ecx,[GLightWidth] + + psrlw mm6,8 + punpcklbw mm5,[eax] + + add eax,ecx + psrlw mm5,8 + + movq mm2,[Zero] + psubw mm6,mm5 + + add eax,ecx + psllw mm5,8 + + add eax,ecx + pmullw mm6,mm7 ; B|B + + punpcklbw mm2,[eax+3] + paddw mm6,mm5 + + psrlw mm2,8 + movq mm5,[Zero] + + mov ebx,dword ptr[UV16+4] + punpcklbw mm5,[eax] + + mov eax,dword ptr[UV16V] + psrlw mm5,8 + + mov esi,GBitPtr + psubw mm2,mm5 + + shr ebx,16 + psllw mm5,8 + + add esi,eax + pmullw mm2,mm7 + + movq mm7,mm6 + paddw mm2,mm5 + + psrlw mm6,8 + psrlw mm2,8 + + mov ecx,TexPal + psubw mm2,mm6 + + add esi,ebx + pmullw mm2,mm3 + + xor eax,eax + paddw mm7,mm2 + + psrlw mm7,8 + + movq mm2,mm7 ;make ABGR ARGB + + psllq mm2,16 + + punpckhwd mm7,mm2 ;BAGB + + psrlq mm2,16 + + punpckldq mm7,mm2 + +LeftoverLoopLit: + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm6,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + punpcklbw mm6,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + mov ebx,dword ptr[UV16+4] + + psrlq mm4,[QShiftV] + pmullw mm6,mm7 + + shr ebx,16 + + movq [UV16V],mm4 + add esi,ebx + + psrlw mm6,8 + + mov edx,dword ptr[UV16V] + add esi,edx + packuswb mm6,mm6 + + xor eax,eax + movd [edi],mm6 + + add edi,4 + + dec [RemainingCount] + jge LeftoverLoopLit + +ReturnLit: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawSpan32_AsmLit3DNow +endProc DrawSpan32_AsmLit3DNow + + + +;32 bit gouraud perspective mapper +;this needs serious cleaning... the clamping is useless +;this big stack hurts + +cProc DrawSpan32_AsmGouraud3DNow, 36, + + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle ReturnLit + +; femms + +; inc ecx + mov eax, y + mov edx,x1 + mov ebx,offset ClientWindow + shl edx, 2 + imul eax, [ebx].PixelPitch + mov edi,[ebx].Buffer + add edx,eax + mov eax,ecx + add edi, edx + mov edx,ecx + + shr ecx,4 + and eax,15 + jnz @f + dec ecx + mov eax,16 +@@: + + mov [NumASpans],ecx + mov [RemainingCount],eax + + ;grab the left side lights + movd mm5,r1 + movd mm4,b1 + +; punpckldq mm5,qword ptr[Zero] + movd mm6,g1 + + pf2id mm5,mm5 + punpckldq mm4,mm6 + + pf2id mm4,mm4 + packssdw mm4,mm5 + + psllw mm4,7 + + movq [ARL],mm4 + + ; mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 + movd mm0,x1 ; |x | | | | | | | + movq mm2,[UVDivZStepX] ; |x | UZdX|VZdX | | | | | + + movd mm1,y ; |x |y UZdX|VZdX | | | | | + movq mm3,[UVDivZStepY] ; |x |y UZdX|VZdXUZdY|VZdY | | | | + + punpckldq mm0,mm0 ; x|x |y UZdX|VZdXUZdY|VZdY | | | | + punpckldq mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | | | | + + movd mm7,edx ; x|x y|y UZdX|VZdXUZdY|VZdY | | | |wid + movd mm5,b2 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + + pi2fd mm0,mm0 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + movd mm6,b1 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + + pi2fd mm7,mm7 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + punpckldq mm5,qword ptr[g2] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + + pi2fd mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + punpckldq mm6,qword ptr[g1] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b g|b |wid + + pfmul mm2,mm0 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b |wid + pfrcp mm7,mm7 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b dw|dw + + pfsub mm5,mm6 ; x|x y|y UZX|VZX UZdY|VZdY | gd|bd g|b dw|dw + movd mm4,[r1] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|b dw|dw + + movd mm6,[r2] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|r dw|dw + pfmul mm3,mm1 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd g|r dw|dw + + pfsub mm6,mm4 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd dw|dw + pfmul mm7,[Q128] ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd DW|DW + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZY|VZY |ZdX gd|bd x|rd DW|DW + pfmul mm5,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZdX GD|BD x|rd DW|DW + + pfmul mm4,mm0 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|rd DW|DW + pfmul mm6,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|RD DW|DW + + pf2id mm5,mm5 + pf2id mm6,mm6 + + packssdw mm5,mm6 + movq [RGBADelta],mm5 + + movd mm5,[ZiStepY] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY x|RD DW|DW + movq mm6,[UVDivZOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY UZO|VZO DW|DW + + pfmul mm5,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO DW|DW + movd mm7,[ZiOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO |ZO + + pfadd mm6,mm2 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZXS|VZXS |ZO + pfadd mm4,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZXS|VZXS |ZO + + pfadd mm6,mm3 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZ|VZ |ZO + pfadd mm4,mm5 ; x|x y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZO + + movd mm7,[Zi16StepX] ; x|x y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + pfrcp mm0,mm4 ; ZL|ZL y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + + movq mm1,mm6 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + pfadd mm4,mm7 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfmul mm1,mm0 ; ZL|ZL UL|VL UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + pfrcp mm2,mm4 ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfadd mm6,[UVDivZ16StepX] ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm2,mm6 ; ZL|ZL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + + movq mm0,mm1 ; UL|VL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + movq mm3,mm2 ; ULi|VLi UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + + pfmul mm0,[QFixedScale] ; UL6|VL6 UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm3,[QFixedScale] ; UL6|VL6 UL|VL UR6|UR6 UR6|UR6 |ZRi |ZY UZR|VZR |ZdX16 + + pf2id mm0,mm0 ;UL6i|VL6i UL|VL UR6|VR6 UR6|VR6 |ZRi |ZY UZR|VZR |ZdX16 + pf2id mm3,mm3 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR |ZdX16 + + + test ecx,ecx + jz HandleLeftoverPixelsLit + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm7,[QFixedScale] + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm7,[UVAdjustL] + movq [UVL16],mm7 + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + + cmp ebx,MaxU + jle TryClampU0Litp + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Litp + +TryClampU0Litp: + cmp ebx,0 + jge NoClampU0Litp + mov dword ptr[UVL16+4],0 +NoClampU0Litp: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Litp + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Litp + +TryClampV0Litp: + cmp eax,0 + jge NoClampV0Litp + mov dword ptr[UVL16],0 + +NoClampV0Litp: + + pfrcp mm5,mm4 + +SpanLoopLit: + ;use float uv for lightmap uv + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfmul mm7,mm2 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm5,[QFixedScale] + + pfmul mm7,[QFixedScale] + pf2id mm5,mm5 + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust] + + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust2] + + movq [UVL16],mm7 + movq [UVLeft],mm5 + + movd mm7,[Zi16StepX] + movq mm0,mm5 + + pfmul mm1,[QFixedScale16] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + ;right side stuff becomes left ; ULw|VLw DU16|DV16 UL|VL URw|VRw |ZLi |ZY UZL|VZL | + pfadd mm4,mm7 ;ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZL|VZL | + + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm7,[UVAdjustL] + movq [UV16],mm5 + + pfadd mm6,[UVDivZ16StepX] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm7,[UVL16] + + psrlq mm5,[QShiftV] + movq [UVL16],mm7 + + movq [UV16V],mm5 + + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU0Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Lit + +TryClampU0Lit: + cmp ebx,0 + jge NoClampU0Lit + mov dword ptr[UVL16+4],0 +NoClampU0Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Lit + +TryClampV0Lit: + cmp eax,0 + jge NoClampV0Lit + mov dword ptr[UVL16],0 + +NoClampV0Lit: + movq [UVLeftW],mm3 + mov eax,dword ptr[UV16V] + mov ebx,dword ptr[UV16+4] + movq [ZIR],mm4 + mov esi,GBitPtr + shr ebx,16 + movq [UVZ],mm6 + add esi,eax + add esi,ebx + movq [UVLeft],mm2 + + mov ecx,TexPal + pfrcp mm5,mm4 + movq mm3,[RGBADelta] + xor eax,eax + movq mm6,[ARL] + + + + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movq [UVR],mm5 + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrlq mm4,[QShiftV] + + mov ebx,dword ptr[UV16+4] + movq [UV16V],mm4 + + mov edx,dword ptr[UV16V] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + shr ebx,16 + add esi,ebx + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + psllw mm7,1 + add esi,edx + + pmulhw mm7,mm6 + paddw mm6,mm3 + + xor eax,eax + movq mm4,mm0 + + mov al,byte ptr[esi] + + pand mm4,[WrapMask] + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + psrlq mm4,[QShiftV] + mov ebx,dword ptr[UV16+4] + + movq [UV16V],mm4 + psllw mm5,1 + + mov edx,dword ptr[UV16V] + paddd mm0,mm1 + + pmulhw mm5,mm6 + paddw mm6,mm3 + + shr ebx,16 + mov esi,GBitPtr + + add esi,edx + movq mm4,mm0 + + packuswb mm7,mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + add esi,ebx + + movq [edi],mm7 + xor eax,eax + + pand mm4,[WrapMask] + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + mov esi,GBitPtr + + mov ebx,dword ptr[UV16+4] + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+8],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+16],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+24],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+32],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+40],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+48],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + + add esi,edx + + add esi,ebx + + mov al,byte ptr[esi] + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + psllw mm5,1 + + pmulhw mm5,mm6 + paddw mm6,mm3 + + packuswb mm7,mm5 + movq [ARL],mm6 + + movq [edi+56],mm7 + + ; get corrected right side deltas ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm4,[ZIR] + movq mm6,[UVZ] + + movq mm2,[UVR] + movq mm0,[UVLeftW] ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm1,[UVLeft] ; ULw|VLw UL|VL argb|ARGBagAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + punpckldq mm2,mm2 ; ULw|VLw UL|VL ZRi|ZRi agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + pfmul mm2,mm6 ; ULw|VLw UL|VL UR|VR agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + add edi,64 ; move screen pointer to start of next aspan + + movq mm3,mm2 + pfmul mm3,[QFixedScale] + + pf2id mm3,mm3 + + dec [NumASpans] ; dec num affine spans + jnz SpanLoopLit + +HandleLeftoverPixelsLit: + + + mov esi,GBitPtr + + + cmp [RemainingCount],0 + jz ReturnLit + + mov eax,[RemainingCount] + mov dword ptr[ZIR],eax + mov dword ptr[ZIR+4],eax + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfsub mm6,[UVDivZ16StepX] + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + + pfmul mm5,[QFixedScale] + pi2fd mm3,[ZIR] + + pfmul mm7,[QFixedScale] + pfmul mm3,[UVDivZStepX] + + pf2id mm5,mm5 + pfadd mm3,mm6 + + pi2fd mm2,[ZIR] + movd mm6,[Zi16StepX] + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + pfsub mm4,mm6 + + movd mm6,[ZiStepX] + mov ebx,[RemainingCount] + + pfmul mm2,mm6 + + shl ebx,3 + + pfadd mm2,mm4 + paddd mm5,[UVAdjust] + + movq [UVL16],mm7 + pfrcp mm2,mm2 + + paddd mm5,[UVAdjust2] + pfmul mm2,mm3 + + movq [UVLeft],mm5 + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + pfmul mm1,qword ptr[QFixedScaleLUT+ebx] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm0,mm5 + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq [UV16],mm5 + movq mm7,[UVAdjustL] + + psrlq mm5,[QShiftV] + paddd mm7,[UVL16] + + movq [UV16V],mm5 + movq [UVL16],mm7 + + +OnePixelSpanLit: + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU1Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU1Lit + +TryClampU1Lit: + cmp ebx,0 + jge NoClampU1Lit + mov dword ptr[UVL16+4],0 +NoClampU1Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV1Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV1Lit + +TryClampV1Lit: + cmp eax,0 + jge NoClampV1Lit + mov dword ptr[UVL16],0 + +NoClampV1Lit: + mov ebx,dword ptr[UV16+4] + mov eax,dword ptr[UV16V] + + mov esi,GBitPtr + shr ebx,16 + add esi,eax + add esi,ebx + mov ecx,TexPal + xor eax,eax + movq mm6,[ARL] + +LeftoverLoopLit: + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + mov ebx,dword ptr[UV16+4] + + psrlq mm4,[QShiftV] + + shr ebx,16 + psllw mm7,1 + + movq [UV16V],mm4 + add esi,ebx + + mov edx,dword ptr[UV16V] + pmulhw mm7,mm6 + + add esi,edx + packuswb mm7,mm7 + + xor eax,eax + movd [edi],mm7 + + add edi,4 + + dec [RemainingCount] + jge LeftoverLoopLit + +ReturnLit: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawSpan32_AsmGouraud3DNow +endProc DrawSpan32_AsmGouraud3DNow + + +;affine gouraud mapper... will probably be phased out + +cProc DrawScanLineGouraudNoZ_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnNoZ + + mov edi,[ebx].X +; inc edx + + femms + +; prefetch [GBitPtr] + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,2 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + movq [UV16],mm0 + packssdw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + add edi,[Dest] + + psrlq mm0,[QShiftV] + psllw mm5,7 + + shr ebx,16 + mov esi,GBitPtr + + movq [UV16V],mm0 + add esi,ebx + + mov ecx,TexPal + mov eax,dword ptr[UV16V] + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopNoZ: + mov al,byte ptr[esi] + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + mov ebx,dword ptr[UV16+4] + + psrlq mm0,[QShiftV] + + shr ebx,16 + psllw mm7,1 + + movq [UV16V],mm0 + add esi,ebx + + mov ebp,dword ptr[UV16V] + pmulhw mm7,mm5 + + add esi,ebp + packuswb mm7,mm7 + + xor eax,eax + movd [edi],mm7 + + paddw mm5,mm3 + add edi,4 + + dec edx + jge GouraudLoopNoZ + + pop ebp + + femms + +GouraudReturnNoZ: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudNoZ_Asm3DNow +endProc DrawScanLineGouraudNoZ_Asm3DNow + + + +;does true 32 bit alpha blending... not your greyscale +;junk like hardware... I mean true 32 bit alpha +;looks bad without filtering though + +cProc DrawScanLineGouraudNoZAlphaTex_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnNoZAlphaTex + + mov edi,[ebx].X +; inc edx + + femms + +; prefetch [GBitPtr] + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,2 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + movq [UV16],mm0 + packssdw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + add edi,[Dest] + + psrlq mm0,[QShiftV] + psllw mm5,7 + + shr ebx,16 + mov esi,GBitPtr + + movq [UV16V],mm0 + add esi,ebx + + mov ecx,TexPal + mov eax,dword ptr[UV16V] + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopNoZAlphaTex: + mov al,byte ptr[esi] + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + sub esi,GBitPtr + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + mov ebx,dword ptr[UV16+4] + + psrlq mm0,[QShiftV] + + add esi,ABitPtr + + shr ebx,16 + + mov al,byte ptr[esi] + psllw mm7,1 + + movq [UV16V],mm0 + mov esi,ebx + + movd mm0,[edi] + + mov ebx,ATexPal + + mov ebp,dword ptr[UV16V] + pmulhw mm7,mm5 + + movd mm4,[ebx+eax*4] + add esi,ebp + + punpcklbw mm0,[Zero] + + movq mm6,[QNegAlpha] + + punpcklbw mm4,[Zero] + + add esi,GBitPtr + + pmullw mm7,mm4 + psubw mm6,mm4 + + paddw mm5,mm3 + pmullw mm0,mm6 + + add edi,4 + paddw mm0,mm7 + + psrlw mm0,8 + + packuswb mm0,mm0 + + movd [edi-4],mm0 + + dec edx + jge GouraudLoopNoZAlphaTex + + pop ebp + + femms + +GouraudReturnNoZAlphaTex: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudNoZAlphaTex_Asm3DNow +endProc DrawScanLineGouraudNoZAlphaTex_Asm3DNow + + +;same with z + +cProc DrawScanLineGouraudZBufferAlphaTex_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnZBufferAlphaTex + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + movq mm0,mm7 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movq mm7,mm0 + + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,1 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + add [pZBufferPtr],edi + packssdw mm5,mm6 + + movq [UV16],mm0 + shl edi,1 + + movd mm4,[ecx].zf + psllw mm5,7 + + movd mm6,[ebx].zf + mov ebx,dword ptr[UV16+4] + + pfsub mm4,mm6 + add edi,[Dest] + + psrlq mm0,[QShiftV] + pfmul mm4,mm7 + + mov esi,GBitPtr + pf2id mm6,mm6 + + movq [UV16V],mm0 + shr ebx,16 + + mov eax,dword ptr[UV16V] + add esi,ebx + + mov ecx,TexPal + pf2id mm4,mm4 + + movq [ARL],mm1 + add esi,eax + + movq [UVR],mm3 + + xor eax,eax + push ebp + +GouraudLoopZBufferAlphaTex: + mov al,byte ptr[esi] + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + sub esi,GBitPtr + paddd mm2,[ARL] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + mov ebx,dword ptr[UV16+4] + + psrlq mm0,[QShiftV] + + add esi,ABitPtr + + shr ebx,16 + + mov al,byte ptr[esi] + psllw mm7,1 + + movq [UV16V],mm0 + mov esi,ebx + + mov ebx,ATexPal + mov ebp,dword ptr[UV16V] + + movd mm1,[ebx+eax*4] + pmulhw mm7,mm5 + + movq mm3,[QNegAlpha] + add esi,ebp + + punpcklbw mm1,[Zero] + movd eax,mm6 + + add esi,GBitPtr + shr eax,16 + + mov ebx,pZBufferPtr + paddd mm6,mm4 + + paddw mm5,[UVR] + add edi,4 + + cmp word ptr[ebx],ax + + jg SkipPixelZBufferAlphaTex + + movd mm0,[edi-4] + pmullw mm7,mm1 + + punpcklbw mm0,[Zero] + psubw mm3,mm1 + + pmullw mm0,mm3 + + mov word ptr[ebx],ax + paddw mm0,mm7 + + psrlw mm0,8 + + packuswb mm0,mm0 + + movd [edi-4],mm0 + +SkipPixelZBufferAlphaTex: + + add [pZBufferPtr],2 + xor eax,eax + + dec edx + jge GouraudLoopZBufferAlphaTex + + pop ebp + + femms + +GouraudReturnZBufferAlphaTex: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudZBufferAlphaTex_Asm3DNow +endProc DrawScanLineGouraudZBufferAlphaTex_Asm3DNow + + + +;same with zwrite + +cProc DrawScanLineGouraudNoZBufferZWriteAlphaTex_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnNoZBufferZWriteAlphaTex + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + movq mm0,mm7 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movq mm7,mm0 + + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,1 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + add [pZBufferPtr],edi + packssdw mm5,mm6 + + movq [UV16],mm0 + shl edi,1 + + movd mm4,[ecx].zf + psllw mm5,7 + + movd mm6,[ebx].zf + mov ebx,dword ptr[UV16+4] + + pfsub mm4,mm6 + add edi,[Dest] + + psrlq mm0,[QShiftV] + pfmul mm4,mm7 + + mov esi,GBitPtr + pf2id mm6,mm6 + + movq [UV16V],mm0 + shr ebx,16 + + mov eax,dword ptr[UV16V] + add esi,ebx + + mov ecx,TexPal + pf2id mm4,mm4 + + movq [ARL],mm1 + add esi,eax + + movq [UVR],mm3 + + xor eax,eax + push ebp + +GouraudLoopNoZBufferZWriteAlphaTex: + mov al,byte ptr[esi] + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + sub esi,GBitPtr + paddd mm2,[ARL] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + mov ebx,dword ptr[UV16+4] + + psrlq mm0,[QShiftV] + + add esi,ABitPtr + + shr ebx,16 + + mov al,byte ptr[esi] + psllw mm7,1 + + movq [UV16V],mm0 + mov esi,ebx + + mov ebx,ATexPal + mov ebp,dword ptr[UV16V] + + movd mm1,[ebx+eax*4] + pmulhw mm7,mm5 + + movq mm3,[QNegAlpha] + add esi,ebp + + punpcklbw mm1,[Zero] + movd eax,mm6 + + add esi,GBitPtr + shr eax,16 + + mov ebx,pZBufferPtr + paddd mm6,mm4 + + paddw mm5,[UVR] + add edi,4 + + movd mm0,[edi-4] + pmullw mm7,mm1 + + punpcklbw mm0,[Zero] + psubw mm3,mm1 + + pmullw mm0,mm3 + + mov word ptr[ebx],ax + paddw mm0,mm7 + + psrlw mm0,8 + + packuswb mm0,mm0 + + movd [edi-4],mm0 + + add [pZBufferPtr],2 + xor eax,eax + + dec edx + jge GouraudLoopNoZBufferZWriteAlphaTex + + pop ebp + + femms + +GouraudReturnNoZBufferZWriteAlphaTex: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudNoZBufferZWriteAlphaTex_Asm3DNow +endProc DrawScanLineGouraudNoZBufferZWriteAlphaTex_Asm3DNow + + +;zmask but no zwrite + +cProc DrawScanLineGouraudZBufferNoZWriteAlphaTex_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnZBufferNoZWriteAlphaTex + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + movq mm0,mm7 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movq mm7,mm0 + + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,1 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + add [pZBufferPtr],edi + packssdw mm5,mm6 + + movq [UV16],mm0 + shl edi,1 + + movd mm4,[ecx].zf + psllw mm5,7 + + movd mm6,[ebx].zf + mov ebx,dword ptr[UV16+4] + + pfsub mm4,mm6 + add edi,[Dest] + + psrlq mm0,[QShiftV] + pfmul mm4,mm7 + + mov esi,GBitPtr + pf2id mm6,mm6 + + movq [UV16V],mm0 + shr ebx,16 + + mov eax,dword ptr[UV16V] + add esi,ebx + + mov ecx,TexPal + pf2id mm4,mm4 + + movq [ARL],mm1 + add esi,eax + + movq [UVR],mm3 + + xor eax,eax + push ebp + +GouraudLoopZBufferNoZWriteAlphaTex: + mov al,byte ptr[esi] + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + sub esi,GBitPtr + paddd mm2,[ARL] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + mov ebx,dword ptr[UV16+4] + + psrlq mm0,[QShiftV] + + add esi,ABitPtr + + shr ebx,16 + + mov al,byte ptr[esi] + psllw mm7,1 + + movq [UV16V],mm0 + mov esi,ebx + + mov ebx,ATexPal + mov ebp,dword ptr[UV16V] + + movd mm1,[ebx+eax*4] + pmulhw mm7,mm5 + + movq mm3,[QNegAlpha] + add esi,ebp + + punpcklbw mm1,[Zero] + movd eax,mm6 + + add esi,GBitPtr + shr eax,16 + + mov ebx,pZBufferPtr + paddd mm6,mm4 + + paddw mm5,[UVR] + add edi,4 + + cmp word ptr[ebx],ax + + jg SkipPixelZBufferNoZWriteAlphaTex + + movd mm0,[edi-4] + pmullw mm7,mm1 + + punpcklbw mm0,[Zero] + psubw mm3,mm1 + + pmullw mm0,mm3 + + paddw mm0,mm7 + + psrlw mm0,8 + + packuswb mm0,mm0 + + movd [edi-4],mm0 + +SkipPixelZBufferNoZWriteAlphaTex: + + add [pZBufferPtr],2 + xor eax,eax + + dec edx + jge GouraudLoopZBufferNoZWriteAlphaTex + + pop ebp + + femms + +GouraudReturnZBufferNoZWriteAlphaTex: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudZBufferNoZWriteAlphaTex_Asm3DNow +endProc DrawScanLineGouraudZBufferNoZWriteAlphaTex_Asm3DNow + + + +;solid color gouraud (no texture) + +cProc DrawScanLineGouraudNoZSolid_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnSolidNoZ + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,SolidColor + movd mm0,edx + + punpcklbw mm1,[Zero] + pi2fd mm0,mm0 + + movd mm3,[ecx].bf + pfrcp mm0,mm0 + + punpckldq mm3,qword ptr[ecx].gf + movq mm7,mm0 + + movd mm4,[ecx].rf + movd mm5,[ebx].bf + + pfmul mm7,[Q128] + punpckldq mm5,qword ptr[ebx].gf + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + pf2id mm6,mm6 + + pf2id mm4,mm4 + pf2id mm3,mm3 + + shl edi,2 + packssdw mm3,mm4 + + packssdw mm5,mm6 + + add edi,[Dest] + + psllw mm5,7 + +GouraudLoopSolidNoZ: + movq mm7,mm1 + paddw mm5,mm3 + + psllw mm7,1 + + pmulhw mm7,mm5 + add edi,4 + + packuswb mm7,mm7 + movd [edi-4],mm7 + + dec edx + jge GouraudLoopSolidNoZ + + femms + +GouraudReturnSolidNoZ: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudNoZSolid_Asm3DNow +endProc DrawScanLineGouraudNoZSolid_Asm3DNow + + +;same with z + +cProc DrawScanLineGouraudZBufferSolid_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnSolidZBuffer + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,SolidColor + movd mm0,edx + + punpcklbw mm1,[Zero] + pi2fd mm0,mm0 + + movd mm3,[ecx].bf + pfrcp mm0,mm0 + + punpckldq mm3,qword ptr[ecx].gf + movq mm7,mm0 + + movd mm4,[ecx].rf + movd mm5,[ebx].bf + + pfmul mm7,[Q128] + punpckldq mm5,qword ptr[ebx].gf + + movd mm6,[ebx].rf + pfsub mm3,mm5 + + movd mm2,[ecx].zf + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movd mm7,[ebx].zf + + pf2id mm6,mm6 + pfsub mm2,mm7 + + pf2id mm4,mm4 + pfmul mm2,mm0 + + pf2id mm3,mm3 + shl edi,1 + + packssdw mm3,mm4 + add [pZBufferPtr],edi + + packssdw mm5,mm6 + shl edi,1 + + add edi,[Dest] + mov ebx,pZBufferPtr + + pf2id mm6,mm6 + psllw mm5,7 + + pf2id mm7,mm7 + +GouraudLoopSolidZBuffer: + movq mm4,mm1 + paddw mm5,mm3 + + psllw mm4,1 + movd eax,mm7 + + pmulhw mm4,mm5 + + shr eax,16 + add edi,4 + + cmp word ptr[ebx],ax + jg SkipPixelGouraudSolidZBuffer + + packuswb mm4,mm4 + movd [edi-4],mm4 + + mov word ptr[ebx],ax + +SkipPixelGouraudSolidZBuffer: + add ebx,2 + paddd mm7,mm6 + dec edx + jge GouraudLoopSolidZBuffer + + femms + +GouraudReturnSolidZBuffer: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudZBufferSolid_Asm3DNow +endProc DrawScanLineGouraudZBufferSolid_Asm3DNow + + +; same with zmask no zwrite + +cProc DrawScanLineGouraudZBufferNoZWriteSolid_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnSolidZBufferNoZWrite + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,SolidColor + movd mm0,edx + + punpcklbw mm1,[Zero] + pi2fd mm0,mm0 + + movd mm3,[ecx].bf + pfrcp mm0,mm0 + + punpckldq mm3,qword ptr[ecx].gf + movq mm7,mm0 + + movd mm4,[ecx].rf + movd mm5,[ebx].bf + + pfmul mm7,[Q128] + punpckldq mm5,qword ptr[ebx].gf + + movd mm6,[ebx].rf + pfsub mm3,mm5 + + movd mm2,[ecx].zf + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movd mm7,[ebx].zf + + pf2id mm6,mm6 + pfsub mm2,mm7 + + pf2id mm4,mm4 + pfmul mm2,mm0 + + pf2id mm3,mm3 + shl edi,1 + + packssdw mm3,mm4 + add [pZBufferPtr],edi + + packssdw mm5,mm6 + shl edi,1 + + add edi,[Dest] + mov ebx,pZBufferPtr + + pf2id mm6,mm6 + psllw mm5,7 + + pf2id mm7,mm7 + +GouraudLoopSolidZBufferNoZWrite: + movq mm4,mm1 + paddw mm5,mm3 + + psllw mm4,1 + movd eax,mm7 + + pmulhw mm4,mm5 + + shr eax,16 + add edi,4 + + cmp word ptr[ebx],ax + jg SkipPixelGouraudSolidZBufferNoZWrite + + packuswb mm4,mm4 + movd [edi-4],mm4 + +SkipPixelGouraudSolidZBufferNoZWrite: + add ebx,2 + paddd mm7,mm6 + dec edx + jge GouraudLoopSolidZBufferNoZWrite + + femms + +GouraudReturnSolidZBufferNoZWrite: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudZBufferNoZWriteSolid_Asm3DNow +endProc DrawScanLineGouraudZBufferNoZWriteSolid_Asm3DNow + + +;same with zwrite only + +cProc DrawScanLineGouraudNoZBufferZWriteSolid_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnSolidNoZBufferZWrite + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,SolidColor + movd mm0,edx + + punpcklbw mm1,[Zero] + pi2fd mm0,mm0 + + movd mm3,[ecx].bf + pfrcp mm0,mm0 + + punpckldq mm3,qword ptr[ecx].gf + movq mm7,mm0 + + movd mm4,[ecx].rf + movd mm5,[ebx].bf + + pfmul mm7,[Q128] + punpckldq mm5,qword ptr[ebx].gf + + movd mm6,[ebx].rf + pfsub mm3,mm5 + + movd mm2,[ecx].zf + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movd mm7,[ebx].zf + + pf2id mm6,mm6 + pfsub mm2,mm7 + + pf2id mm4,mm4 + pfmul mm2,mm0 + + pf2id mm3,mm3 + shl edi,1 + + packssdw mm3,mm4 + add [pZBufferPtr],edi + + packssdw mm5,mm6 + shl edi,1 + + add edi,[Dest] + mov ebx,pZBufferPtr + + pf2id mm6,mm6 + psllw mm5,7 + + pf2id mm7,mm7 + +GouraudLoopSolidNoZBufferZWrite: + movq mm4,mm1 + paddw mm5,mm3 + + psllw mm4,1 + movd eax,mm7 + + pmulhw mm4,mm5 + + shr eax,16 + add edi,4 + + cmp word ptr[ebx],ax + jg SkipPixelGouraudSolidNoZBufferZWrite + + packuswb mm4,mm4 + movd [edi-4],mm4 + + mov word ptr[ebx],ax + +SkipPixelGouraudSolidNoZBufferZWrite: + add ebx,2 + paddd mm7,mm6 + dec edx + jge GouraudLoopSolidNoZBufferZWrite + + femms + +GouraudReturnSolidNoZBufferZWrite: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudNoZBufferZWriteSolid_Asm3DNow +endProc DrawScanLineGouraudNoZBufferZWriteSolid_Asm3DNow + + +;affine color keyed + +cProc DrawScanLineGouraudNoZTrans_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnNoZTrans + + mov edi,[ebx].X +; inc edx + + femms + +; prefetch [GBitPtr] + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,2 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + movq [UV16],mm0 + packssdw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + add edi,[Dest] + + psrlq mm0,[QShiftV] + psllw mm5,7 + + shr ebx,16 + mov esi,GBitPtr + + movq [UV16V],mm0 + add esi,ebx + + mov ecx,TexPal + mov eax,dword ptr[UV16V] + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopNoZTrans: + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + mov al,byte ptr[esi] + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + mov esi,GBitPtr + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + mov ebx,dword ptr[UV16+4] + psrlq mm0,[QShiftV] + + shr ebx,16 + movq [UV16V],mm0 + + add esi,ebx + mov ebp,dword ptr[UV16V] + + add esi,ebp + + cmp al,0ffh + je SkipPixelGouraudNoZTrans + + ;ouch register contention from hell + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + psllw mm7,1 + pmulhw mm7,mm5 + packuswb mm7,mm7 + movd [edi],mm7 + +SkipPixelGouraudNoZTrans: + + add edi,4 + xor eax,eax + + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm6,mm4 + paddw mm5,mm3 + + dec edx + jge GouraudLoopNoZTrans + + pop ebp + + femms + +GouraudReturnNoZTrans: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudNoZTrans_Asm3DNow +endProc DrawScanLineGouraudNoZTrans_Asm3DNow + + +;affine textured with zbuffering and gouraud + +cProc DrawScanLineGouraudZBuffer_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnZBuffer + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + movq mm0,mm7 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movq mm7,mm0 + + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,1 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + add [pZBufferPtr],edi + packssdw mm5,mm6 + + movq [UV16],mm0 + shl edi,1 + + movd mm4,[ecx].zf + psllw mm5,7 + + movd mm6,[ebx].zf + mov ebx,dword ptr[UV16+4] + + pfsub mm4,mm6 + add edi,[Dest] + + psrlq mm0,[QShiftV] + pfmul mm4,mm7 + + mov esi,GBitPtr + pf2id mm6,mm6 + + movq [UV16V],mm0 + shr ebx,16 + + mov eax,dword ptr[UV16V] + add esi,ebx + + mov ecx,TexPal + pf2id mm4,mm4 + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopZBuffer: + mov al,byte ptr[esi] + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + movd eax,mm6 + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + shr eax,16 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm6,mm4 + + mov ebx,dword ptr[UV16+4] + + psrlq mm0,[QShiftV] + + shr ebx,16 + psllw mm7,1 + + movq [UV16V],mm0 + add esi,ebx + + mov ebp,dword ptr[UV16V] + pmulhw mm7,mm5 + + mov ebx,pZBufferPtr + add esi,ebp + + packuswb mm7,mm7 + paddw mm5,mm3 + + cmp word ptr[ebx],ax + jg SkipPixelGouraudZBuffer + + movd [edi],mm7 + mov word ptr[ebx],ax + +SkipPixelGouraudZBuffer: + + add edi,4 + xor eax,eax + + add [pZBufferPtr],2 + + dec edx + jge GouraudLoopZBuffer + + pop ebp + + femms + +GouraudReturnZBuffer: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudZBuffer_Asm3DNow +endProc DrawScanLineGouraudZBuffer_Asm3DNow + + +;same with no zwrite + +cProc DrawScanLineGouraudZBufferNoZWrite_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnZBufferNoZWrite + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + movq mm0,mm7 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movq mm7,mm0 + + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,1 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + add [pZBufferPtr],edi + packssdw mm5,mm6 + + movq [UV16],mm0 + shl edi,1 + + movd mm4,[ecx].zf + psllw mm5,7 + + movd mm6,[ebx].zf + mov ebx,dword ptr[UV16+4] + + pfsub mm4,mm6 + add edi,[Dest] + + psrlq mm0,[QShiftV] + pfmul mm4,mm7 + + mov esi,GBitPtr + pf2id mm6,mm6 + + movq [UV16V],mm0 + shr ebx,16 + + mov eax,dword ptr[UV16V] + add esi,ebx + + mov ecx,TexPal + pf2id mm4,mm4 + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopZBufferNoZWrite: + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov al,byte ptr[esi] + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov esi,GBitPtr + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + movd eax,mm6 + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + shr eax,16 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm6,mm4 + + mov ebx,dword ptr[UV16+4] + + psrlq mm0,[QShiftV] + + shr ebx,16 + psllw mm7,1 + + movq [UV16V],mm0 + add esi,ebx + + mov ebp,dword ptr[UV16V] + pmulhw mm7,mm5 + + mov ebx,pZBufferPtr + add esi,ebp + + packuswb mm7,mm7 + paddw mm5,mm3 + + cmp word ptr[ebx],ax + jg SkipPixelGouraudZBufferNoZWrite + + movd [edi],mm7 + +SkipPixelGouraudZBufferNoZWrite: + + add edi,4 + xor eax,eax + + add [pZBufferPtr],2 + + dec edx + jge GouraudLoopZBufferNoZWrite + + pop ebp + + femms + +GouraudReturnZBufferNoZWrite: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudZBufferNoZWrite_Asm3DNow +endProc DrawScanLineGouraudZBufferNoZWrite_Asm3DNow + + +;same with z write only (no compare) + +cProc DrawScanLineGouraudNoZBufferZWrite_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnNoZBufferZWrite + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + movq mm0,mm7 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movq mm7,mm0 + + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,1 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + add [pZBufferPtr],edi + packssdw mm5,mm6 + + movq [UV16],mm0 + shl edi,1 + + movd mm4,[ecx].zf + psllw mm5,7 + + movd mm6,[ebx].zf + mov ebx,dword ptr[UV16+4] + + pfsub mm4,mm6 + add edi,[Dest] + + psrlq mm0,[QShiftV] + pfmul mm4,mm7 + + mov esi,GBitPtr + pf2id mm6,mm6 + + movq [UV16V],mm0 + shr ebx,16 + + mov eax,dword ptr[UV16V] + add esi,ebx + + mov ecx,TexPal + pf2id mm4,mm4 + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopNoZBufferZWrite: + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov al,byte ptr[esi] + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov esi,GBitPtr + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + movd eax,mm6 + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + shr eax,16 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm6,mm4 + + mov ebx,dword ptr[UV16+4] + + psrlq mm0,[QShiftV] + + shr ebx,16 + psllw mm7,1 + + movq [UV16V],mm0 + add esi,ebx + + mov ebp,dword ptr[UV16V] + pmulhw mm7,mm5 + + mov ebx,pZBufferPtr + add esi,ebp + + packuswb mm7,mm7 + paddw mm5,mm3 + + movd [edi],mm7 + mov word ptr[ebx],ax + + add edi,4 + xor eax,eax + + add [pZBufferPtr],2 + + dec edx + jge GouraudLoopNoZBufferZWrite + + pop ebp + + femms + +GouraudReturnNoZBufferZWrite: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudNoZBufferZWrite_Asm3DNow +endProc DrawScanLineGouraudNoZBufferZWrite_Asm3DNow + + +;affine textured, gouraud, colorkeyed, zbuffered + +cProc DrawScanLineGouraudZBufferTrans_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnZBufferTrans + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + movq mm0,mm7 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movq mm7,mm0 + + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,1 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + add [pZBufferPtr],edi + packssdw mm5,mm6 + + movq [UV16],mm0 + shl edi,1 + + movd mm4,[ecx].zf + psllw mm5,7 + + movd mm6,[ebx].zf + mov ebx,dword ptr[UV16+4] + + pfsub mm4,mm6 + add edi,[Dest] + + psrlq mm0,[QShiftV] + pfmul mm4,mm7 + + mov esi,GBitPtr + pf2id mm6,mm6 + + movq [UV16V],mm0 + shr ebx,16 + + mov eax,dword ptr[UV16V] + add esi,ebx + + mov ecx,TexPal + pf2id mm4,mm4 + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopZBufferTrans: + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + mov al,byte ptr[esi] + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + mov esi,GBitPtr + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + mov ebx,dword ptr[UV16+4] + psrlq mm0,[QShiftV] + + shr ebx,16 + movq [UV16V],mm0 + + add esi,ebx + mov ebp,dword ptr[UV16V] + + add esi,ebp + + cmp al,0ffh + je SkipPixelGouraudZBufferTrans + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + movd eax,mm6 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + shr eax,16 + + mov ebx,pZBufferPtr + psllw mm7,1 + + pmulhw mm7,mm5 + + packuswb mm7,mm7 + + cmp word ptr[ebx],ax + jg SkipPixelGouraudZBufferTrans + + movd [edi],mm7 + mov word ptr[ebx],ax + +SkipPixelGouraudZBufferTrans: + + add edi,4 + xor eax,eax + + add [pZBufferPtr],2 + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm6,mm4 + paddw mm5,mm3 + + dec edx + jge GouraudLoopZBufferTrans + + pop ebp + + femms + +GouraudReturnZBufferTrans: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudZBufferTrans_Asm3DNow +endProc DrawScanLineGouraudZBufferTrans_Asm3DNow + + +;same with zwrite only + +cProc DrawScanLineGouraudNoZBufferZWriteTrans_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnTransNoZBufferZWrite + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + movq mm0,mm7 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movq mm7,mm0 + + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,1 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + add [pZBufferPtr],edi + packssdw mm5,mm6 + + movq [UV16],mm0 + shl edi,1 + + movd mm4,[ecx].zf + psllw mm5,7 + + movd mm6,[ebx].zf + mov ebx,dword ptr[UV16+4] + + pfsub mm4,mm6 + add edi,[Dest] + + psrlq mm0,[QShiftV] + pfmul mm4,mm7 + + mov esi,GBitPtr + pf2id mm6,mm6 + + movq [UV16V],mm0 + shr ebx,16 + + mov eax,dword ptr[UV16V] + add esi,ebx + + mov ecx,TexPal + pf2id mm4,mm4 + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopTransNoZBufferZWrite: + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + mov al,byte ptr[esi] + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + mov esi,GBitPtr + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + mov ebx,dword ptr[UV16+4] + psrlq mm0,[QShiftV] + + shr ebx,16 + movq [UV16V],mm0 + + add esi,ebx + mov ebp,dword ptr[UV16V] + + add esi,ebp + + cmp al,0ffh + je SkipPixelGouraudTransNoZBufferZWrite + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + movd eax,mm6 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + shr eax,16 + + mov ebx,pZBufferPtr + psllw mm7,1 + + pmulhw mm7,mm5 + + packuswb mm7,mm7 + + cmp word ptr[ebx],ax + jg SkipPixelGouraudTransNoZBufferZWrite + + movd [edi],mm7 + mov word ptr[ebx],ax + +SkipPixelGouraudTransNoZBufferZWrite: + + add edi,4 + xor eax,eax + + add [pZBufferPtr],2 + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm6,mm4 + paddw mm5,mm3 + + dec edx + jge GouraudLoopTransNoZBufferZWrite + + pop ebp + + femms + +GouraudReturnTransNoZBufferZWrite: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudNoZBufferZWriteTrans_Asm3DNow +endProc DrawScanLineGouraudNoZBufferZWriteTrans_Asm3DNow + + +;zmask no z write + +cProc DrawScanLineGouraudZBufferNoZWriteTrans_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnTransZBufferNoZWrite + + mov edi,[ebx].X +; inc edx + + femms + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + movq mm0,mm7 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + movq mm7,mm0 + + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,1 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + add [pZBufferPtr],edi + packssdw mm5,mm6 + + movq [UV16],mm0 + shl edi,1 + + movd mm4,[ecx].zf + psllw mm5,7 + + movd mm6,[ebx].zf + mov ebx,dword ptr[UV16+4] + + pfsub mm4,mm6 + add edi,[Dest] + + psrlq mm0,[QShiftV] + pfmul mm4,mm7 + + mov esi,GBitPtr + pf2id mm6,mm6 + + movq [UV16V],mm0 + shr ebx,16 + + mov eax,dword ptr[UV16V] + add esi,ebx + + mov ecx,TexPal + pf2id mm4,mm4 + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopTransZBufferNoZWrite: + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + mov al,byte ptr[esi] + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + mov esi,GBitPtr + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + mov ebx,dword ptr[UV16+4] + psrlq mm0,[QShiftV] + + shr ebx,16 + movq [UV16V],mm0 + + add esi,ebx + mov ebp,dword ptr[UV16V] + + add esi,ebp + + cmp al,0ffh + je SkipPixelGouraudTransZBufferNoZWrite + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + movd eax,mm6 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + shr eax,16 + + mov ebx,pZBufferPtr + psllw mm7,1 + + pmulhw mm7,mm5 + + packuswb mm7,mm7 + + cmp word ptr[ebx],ax + jg SkipPixelGouraudTransZBufferNoZWrite + + movd [edi],mm7 + +SkipPixelGouraudTransZBufferNoZWrite: + + add edi,4 + xor eax,eax + + add [pZBufferPtr],2 + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm6,mm4 + paddw mm5,mm3 + + dec edx + jge GouraudLoopTransZBufferNoZWrite + + pop ebp + + femms + +GouraudReturnTransZBufferNoZWrite: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudZBufferNoZWriteTrans_Asm3DNow +endProc DrawScanLineGouraudZBufferNoZWriteTrans_Asm3DNow + + +;zbuffered lightmap combine routine +;the zbuffering in the inner loop uses a method i came up +;with that I call the trashcan method. It always does a +;write, but uses flags to look up a pointer, either to junk +;or to a real zbuffer. Same for the screen write +;it's very bizzare, but it's quick. no jumps +;all the zbuffering for perspective correct stuff suffers +;from inaccuracy when the z delta is negative +;this is probably more signed unsigned mmx problems messing +;with me. I haven't had time to fix it yet + +cProc DrawSpan32_AsmLitZBuffer3DNow, 12, + + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return128z + +; femms + +; inc ecx + mov ebx,offset ClientWindow + mov eax, y + mov edi,[ebx].Buffer + mov esi,x1 + imul eax, [ebx].PixelPitch + shl esi,2 + mov edx,ZBuffer + add eax,esi + add edi, eax + shr eax,1 +; inc eax +; inc eax + add edx,eax + mov [Dest],edx + mov eax,offset QZCan + mov ebx,offset SCan + mov [eax],ebx + mov [eax+4],edx + mov eax,offset QDibCan + mov [eax],ebx + mov [eax+4],edi + mov ebx,offset QDibCan + mov eax,offset QDibOrCan + mov [eax],ebx + mov [eax+4],ebx + mov ebx,offset QZCan + mov eax,offset QZOrCan + mov [eax],ebx + mov [eax+4],ebx + + + mov eax,ecx + shr ecx,4 + and eax,15 + jnz @f + dec ecx + mov eax,16 +@@: + + mov [NumASpans],ecx + mov [RemainingCount],eax + ; mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 + movd mm0,x1 ; |x | | | | | | | + movq mm2,[UVDivZStepX] ; |x | |UZdX | | | | | + + movd mm1,y ; |x |y |UZdX | | | | | + movq mm3,[UVDivZStepY] ; |x |y |UZdX |UZdY | | | | + + punpckldq mm0,mm0 ; x|x |y |UZdX |UZdY | | | | + punpckldq mm1,mm1 ; x|x y|y UZdX|VZdX |UZdY | | | | + + pi2fd mm0,mm0 + pi2fd mm1,mm1 + + pfmul mm2,mm0 ; x|x y|y UZX|VZX UZdY|VZdY | | | | + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZdY|VZdY |ZdX | | | + + punpckldq mm4,mm4 + pfmul mm4,[QZBufferPrec] + pf2id mm4,mm4 + movq [QZDelta],mm4 + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZdY|VZdY |ZdX | | | + pfmul mm3,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZdX | | | + movq mm6,[UVDivZOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZdX | |UZO | + + movd mm5,[ZiStepY] ; x|x y|y UZX|VZX UZY|VZY |ZdX |ZdY |UZO | + pfmul mm4,mm0 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY |UZO | + + pfmul mm5,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO | + movd mm7,[ZiOrigin] + + pfadd mm6,mm2 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZXS|VZXS | + pfadd mm4,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZXS|VZXS | + + pfadd mm6,mm3 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZ|VZ | + pfadd mm4,mm5 ; x|x y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ | + + movq mm7,mm4 + movq mm1,[QZDelta] + punpckldq mm7,mm7 + pfmul mm7,[QZBufferPrec] + pf2id mm7,mm7 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + paddd mm7,mm1 + movq [QZVal32_0],mm0 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + movq [QZVal32_1],mm0 + pslld mm1,2 + movd mm7,[Zi16StepX] + movq [QZDelta],mm1 + + pfrcp mm0,mm4 ; ZL|ZL y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ | + movq mm1,mm6 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |Zi |ZY UZ|VZ | + + pfadd mm4,mm7 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ | + pfmul mm1,mm0 ; ZL|ZL UL|VL UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ | + + pfrcp mm2,mm4 ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZ|VZ | + pfadd mm6,[UVDivZ16StepX] ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZR|VZR | + + pfmul mm2,mm6 ; ZL|ZL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR | + movq mm0,mm1 ; UL|VL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR | + + movq mm3,mm2 ; ULi|VLi UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR | + pfmul mm0,[QFixedScale] ; UL6|VL6 UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR | + + pfmul mm3,[QFixedScale] ; UL6|VL6 UL|VL UR6|UR6 UR6|UR6 |ZRi |ZY UZR|VZR | + pf2id mm0,mm0 ;UL6i|VL6i UL|VL UR6|VR6 UR6|VR6 |ZRi |ZY UZR|VZR | + + pf2id mm3,mm3 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR | + + test ecx,ecx + jz HandleLeftoverPixels128z + +SpanLoop128z: + ;use float uv for lightmap uv + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm5,[QFixedScale] + + pfmul mm7,[QFixedScale] + pf2id mm5,mm5 + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust] + + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust2] + + movq [UVL16],mm7 + movq [UVLeft],mm5 + + movd mm7,[Zi16StepX] + movq mm0,mm5 + + pfmul mm1,[QFixedScale16] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + ;right side stuff becomes left ; ULw|VLw DU16|DV16 UL|VL URw|VRw |ZLi |ZY UZL|VZL | + pfadd mm4,mm7 ;ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZL|VZL | + + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm7,[UVAdjustL] + movq [UV16],mm5 + + pfadd mm6,[UVDivZ16StepX] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm7,[UVL16] + + psrlq mm5,[QShiftV] + movq [UVL16],mm7 + + movq [UV16V],mm5 + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU0128z + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0128z + +TryClampU0128z: + cmp ebx,0 + jge NoClampU0128z + mov dword ptr[UVL16+4],0 +NoClampU0128z: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0128z + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0128z + +TryClampV0128z: + cmp eax,0 + jge NoClampV0128z + mov dword ptr[UVL16],0 + +NoClampV0128z: + movq mm7,[UVL16] + movq mm5,[UVL16] + + movq [UVLeftW],mm3 + psrad mm7,[QGMip4_8] + + psrld mm5,[QGMip20] + pand mm7,[LMapMask8] + + movq [UVL16],mm5 + movq mm3,mm7 + + punpckhwd mm7,mm7 + mov eax,dword ptr[UVL16] + + movq mm5,[Zero] + imul eax,[GLightWidth] + + movq [UVZ],mm6 + punpcklwd mm3,mm3 + + add eax,dword ptr[UVL16+4] + movq mm6,[Zero] + + punpckldq mm7,mm7 + lea eax,[2*eax+eax] + + punpckldq mm3,mm3 + add eax,[GLightData] + + ;bilininterpolate to get good color + punpcklbw mm6,[eax+3] + mov ecx,[GLightWidth] + + punpcklbw mm5,[eax] + psrlw mm6,8 + + psrlw mm5,8 + add eax,ecx + + psubw mm6,mm5 + add eax,ecx + + movq [UVLeft],mm2 + psllw mm5,8 + + add eax,ecx + + movq mm2,[Zero] + pmullw mm6,mm7 ; B|B + + punpcklbw mm2,[eax+3] + paddw mm6,mm5 + + psrlw mm2,8 + movq mm5,[Zero] + + mov ebx,dword ptr[UV16+4] + punpcklbw mm5,[eax] + + mov eax,dword ptr[UV16V] + psrlw mm5,8 + + psubw mm2,mm5 + mov esi,GBitPtr + + psllw mm5,8 + pmullw mm2,mm7 + + movq mm7,mm6 + paddw mm2,mm5 + + psrlw mm6,8 + psrlw mm2,8 + + add esi,eax + psubw mm2,mm6 + + shr ebx,16 + pmullw mm2,mm3 + + pfrcp mm5,mm4 + paddw mm7,mm2 + + movq [ZIR],mm4 + psrlw mm7,8 + + xor eax,eax + movq mm2,mm7 ;make ABGR ARGB + + mov ecx,TexPal + psllq mm2,16 + + push ebp + punpckhwd mm7,mm2 ;BAGB + + mov ebp,[Dest] + psrlq mm2,16 + + add esi,ebx + punpckldq mm7,mm2 + + + ;grab zbuffer values + movq mm2,[QZVal32_0] + movq mm3,[QZVal32_1] + + movq mm6,mm7 + psrld mm2,17 + + psrld mm3,17 +; psllq mm6,8 +; psrlw mm6,8 + + packssdw mm2,mm3 + + pslld mm2,1 + movq [QZVal],mm2 + + + movq mm2,[QZVal] + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + pcmpgtw mm2,[ebp] + + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrlw mm2,15 + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psllw mm2,2 + + psrlq mm4,[QShiftV] + movq [GBL],mm2 + + movq [UV16V],mm4 + movq mm3,mm2 + + movq [UVR],mm5 + punpcklwd mm3,[Zero] + + mov edx,dword ptr[UV16V] + paddd mm3,[QZOrCan] + + mov ebx,dword ptr[UV16+4] + movq [QZOut],mm3 + + movq mm3,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + punpcklwd mm3,[Zero] + + mov edi,dword ptr[QZOut] + paddd mm3,[QDibOrCan] + + shr ebx,16 + movq [QDibOut],mm3 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + mov edi,dword ptr[edi] + + xor eax,eax + add esi,edx + + pmullw mm7,mm6 + mov ax,word ptr[QZVal] + + paddd mm0,mm1 + mov word ptr[edi],ax + + mov edi,dword ptr[QDibOut] + add esi,ebx + + mov edi,dword ptr[edi] + + psrlw mm7,8 + xor eax,eax + + packuswb mm7,mm7 + mov al,byte ptr[esi] + + movd [edi],mm7 + movq mm4,mm0 + + pand mm4,[WrapMask] + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + movq [UV16],mm4 + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + psrlq mm4,[QShiftV] + mov ebx,dword ptr[UV16+4] + + movq [UV16V],mm4 + pmullw mm7,mm6 + + mov edx,dword ptr[UV16V] + + shr ebx,16 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + + mov edi,dword ptr[edi] + paddd mm0,mm1 + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+2] + + add esi,ebx + mov word ptr[edi+2],ax + + xor eax,eax + mov edi,dword ptr[QDibOut+4] + + mov al,byte ptr[esi] + movq mm4,mm0 + + mov edi,dword ptr[edi] + pand mm4,[WrapMask] + + mov esi,GBitPtr + movd [edi+4],mm7 + + movq mm3,mm2 + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + psrlq mm4,[QShiftV] + + punpckhwd mm3,[Zero] + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + paddd mm3,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm3 + + movq mm3,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpckhwd mm3,[Zero] + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov ax,word ptr[QZVal+4] + paddd mm3,[QDibOrCan] + + mov word ptr[edi+4],ax + movq [QDibOut],mm3 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + mov edx,dword ptr[UV16V] + + movd [edi+8],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + movq [UV16],mm4 + mov al,byte ptr[esi] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+6] + + add esi,ebx + mov word ptr[edi+6],ax + + ;regrab z + movq mm2,[QZVal32_0] + movq mm3,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm3,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm3 + + psrld mm2,17 + psrld mm3,17 + + packssdw mm2,mm3 + xor eax,eax + + pslld mm2,1 + + mov edi,dword ptr[QDibOut+4] + + movq [QZVal],mm2 + + mov al,byte ptr[esi] + movq mm4,mm0 + + mov edi,dword ptr[edi] + pand mm4,[WrapMask] + + pcmpgtw mm2,[ebp+8] + movd [edi+12],mm7 + + movq [UV16],mm4 + + psrlw mm2,15 + mov esi,GBitPtr + + psrlq mm4,[QShiftV] + + psllw mm2,2 + movq mm3,mm2 + + movq [UV16V],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + punpcklwd mm3,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm3,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm3 + + movq mm3,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpcklwd mm3,[Zero] + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov ax,word ptr[QZVal] + paddd mm3,[QDibOrCan] + + mov word ptr[edi+8],ax + movq [QDibOut],mm3 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[edi] + + movd [edi+16],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+2] + + add esi,ebx + mov word ptr[edi+10],ax + + xor eax,eax + mov edi,dword ptr[QDibOut+4] + + mov al,byte ptr[esi] + movq mm4,mm0 + + mov edi,dword ptr[edi] + pand mm4,[WrapMask] + + mov esi,GBitPtr + movd [edi+20],mm7 + + movq mm3,mm2 + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + psrlq mm4,[QShiftV] + + punpckhwd mm3,[Zero] + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + paddd mm3,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm3 + + movq mm3,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpckhwd mm3,[Zero] + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov ax,word ptr[QZVal+4] + paddd mm3,[QDibOrCan] + + mov word ptr[edi+12],ax + movq [QDibOut],mm3 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + + mov edx,dword ptr[UV16V] + + movd [edi+24],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+6] + + add esi,ebx + mov word ptr[edi+14],ax + + ;regrab z + movq mm2,[QZVal32_0] + movq mm3,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm3,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm3 + + psrld mm2,17 + psrld mm3,17 + + packssdw mm2,mm3 + xor eax,eax + + pslld mm2,1 + + mov edi,dword ptr[QDibOut+4] + + movq [QZVal],mm2 + mov edi,dword ptr[edi] + + mov al,byte ptr[esi] + movq mm4,mm0 + + pand mm4,[WrapMask] + pcmpgtw mm2,[ebp+16] + + movd [edi+28],mm7 + movq [UV16],mm4 + + psrlw mm2,15 + mov esi,GBitPtr + + psrlq mm4,[QShiftV] + + psllw mm2,2 + movq mm3,mm2 + + movq [UV16V],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + punpcklwd mm3,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm3,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm3 + + movq mm3,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpcklwd mm3,[Zero] + mov edi,dword ptr[edi] + + mov ax,word ptr[QZVal] + paddd mm3,[QDibOrCan] + psrlw mm7,8 + + mov word ptr[edi+16],ax + movq [QDibOut],mm3 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + mov edx,dword ptr[UV16V] + + movd [edi+32],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+2] + + add esi,ebx + mov word ptr[edi+18],ax + + xor eax,eax + mov edi,dword ptr[QDibOut+4] + + mov al,byte ptr[esi] + movq mm4,mm0 + mov edi,dword ptr[edi] + + pand mm4,[WrapMask] + + mov esi,GBitPtr + movd [edi+36],mm7 + + movq mm3,mm2 + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + psrlq mm4,[QShiftV] + + punpckhwd mm3,[Zero] + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + paddd mm3,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm3 + + movq mm3,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpckhwd mm3,[Zero] + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov ax,word ptr[QZVal+4] + paddd mm3,[QDibOrCan] + + mov word ptr[edi+20],ax + movq [QDibOut],mm3 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + mov edx,dword ptr[UV16V] + + movd [edi+40],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+6] + + add esi,ebx + mov word ptr[edi+22],ax + + ;regrab z + movq mm2,[QZVal32_0] + movq mm3,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm3,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm3 + + psrld mm2,17 + psrld mm3,17 + + packssdw mm2,mm3 + xor eax,eax + + pslld mm2,1 + + mov edi,dword ptr[QDibOut+4] + + movq [QZVal],mm2 + mov edi,dword ptr[edi] + + mov al,byte ptr[esi] + movq mm4,mm0 + + pand mm4,[WrapMask] + pcmpgtw mm2,[ebp+24] + + movd [edi+44],mm7 + movq [UV16],mm4 + + psrlw mm2,15 + mov esi,GBitPtr + + psrlq mm4,[QShiftV] + + psllw mm2,2 + movq mm3,mm2 + + movq [UV16V],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + punpcklwd mm3,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm3,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm3 + + movq mm3,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpcklwd mm3,[Zero] + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov ax,word ptr[QZVal] + paddd mm3,[QDibOrCan] + + mov word ptr[edi+24],ax + movq [QDibOut],mm3 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + mov edx,dword ptr[UV16V] + + movd [edi+48],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+2] + + add esi,ebx + mov word ptr[edi+26],ax + + xor eax,eax + mov edi,dword ptr[QDibOut+4] + + mov al,byte ptr[esi] + movq mm4,mm0 + + mov edi,dword ptr[edi] + pand mm4,[WrapMask] + + mov esi,GBitPtr + movd [edi+52],mm7 + + movq mm3,mm2 + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + psrlq mm4,[QShiftV] + + punpckhwd mm3,[Zero] + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + paddd mm3,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm3 + + movq mm3,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpckhwd mm3,[Zero] + mov edi,dword ptr[edi] + + mov ax,word ptr[QZVal+4] + paddd mm3,[QDibOrCan] + psrlw mm7,8 + + mov word ptr[edi+28],ax + movq [QDibOut],mm3 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + mov edx,dword ptr[UV16V] + + movd [edi+56],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + pmullw mm7,mm6 + + psrlw mm7,8 + + mov edi,dword ptr[QZOut+4] + + xor eax,eax + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+6] + + mov word ptr[edi+30],ax + + mov edi,dword ptr[QDibOut+4] + + pop ebp + mov edi,dword ptr[edi] + + ;regrab z + movq mm2,[QZVal32_0] + movq mm3,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm3,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm3 + + movd [edi+60],mm7 + + + + ; get corrected right side deltas ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm4,[ZIR] + movq mm6,[UVZ] + + movq mm2,[UVR] + movq mm0,[UVLeftW] ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm1,[UVLeft] ; ULw|VLw UL|VL argb|ARGBagAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + punpckldq mm2,mm2 ; ULw|VLw UL|VL ZRi|ZRi agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + pfmul mm2,mm6 ; ULw|VLw UL|VL UR|VR agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + mov eax,offset QZCan + add dword ptr[Dest],32 + + add dword ptr[eax+4],32 + mov eax,offset QDibCan + + add dword ptr[eax+4],64 + + + movq mm3,mm2 + pfmul mm3,[QFixedScale] + + pf2id mm3,mm3 + + dec [NumASpans] ; dec num affine spans + jnz SpanLoop128z + +HandleLeftoverPixels128z: + + + + mov esi,GBitPtr + + + cmp [RemainingCount],0 + jz FPUReturn128z + + mov eax,[RemainingCount] + mov dword ptr[ZIR],eax + mov dword ptr[ZIR+4],eax + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfsub mm6,[UVDivZ16StepX] + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + + pfmul mm5,[QFixedScale] + pi2fd mm3,[ZIR] + + pfmul mm7,[QFixedScale] + pfmul mm3,[UVDivZStepX] + + pf2id mm5,mm5 + pfadd mm3,mm6 + + pi2fd mm2,[ZIR] + movd mm6,[Zi16StepX] + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + pfsub mm4,mm6 + + paddd mm5,[UVAdjust] + + movd mm6,[ZiStepX] + mov ebx,[RemainingCount] + + pfmul mm2,mm6 + + shl ebx,3 + + pfadd mm2,mm4 + punpckldq mm4,mm4 + + movq [UVL16],mm7 + pfrcp mm2,mm2 + + pfmul mm4,[QZBufferPrec] + + paddd mm5,[UVAdjust2] + pfmul mm2,mm3 + + movq [UVLeft],mm5 + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + pfmul mm1,qword ptr[QFixedScaleLUT+ebx] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm0,mm5 + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq [UV16],mm5 + movq mm7,[UVAdjustL] + + psrlq mm5,[QShiftV] + paddd mm7,[UVL16] + + movq [UV16V],mm5 + movq [UVL16],mm7 + +OnePixelSpan128z: + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU1128z + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU1128z + +TryClampU1128z: + cmp ebx,0 + jge NoClampU1128z + mov dword ptr[UVL16+4],0 +NoClampU1128z: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV1128z + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV1128z + +TryClampV1128z: + cmp eax,0 + jge NoClampV1128z + mov dword ptr[UVL16],0 + +NoClampV1128z: + movq mm7,[UVL16] + movq mm5,[UVL16] + + psrad mm7,[QGMip4_8] + psrld mm5,[QGMip20] + + pand mm7,[LMapMask8] + movq [UVL16],mm5 + + movq mm3,mm7 + punpckhwd mm7,mm7 + + mov eax,dword ptr[UVL16] + movq mm5,[Zero] + + imul eax,[GLightWidth] + punpcklwd mm3,mm3 + + add eax,dword ptr[UVL16+4] + movq mm6,[Zero] + + punpckldq mm7,mm7 + lea eax,[2*eax+eax] + + punpckldq mm3,mm3 + add eax,[GLightData] + + ;bilininterpolate to get good color + punpcklbw mm6,[eax+3] + mov ecx,[GLightWidth] + + punpcklbw mm5,[eax] + psrlw mm6,8 + + psrlw mm5,8 + add eax,ecx + + psubw mm6,mm5 + add eax,ecx + + psllw mm5,8 + movq mm2,[Zero] + add eax,ecx + + pmullw mm6,mm7 ; B|B + punpcklbw mm2,[eax+3] + + paddw mm6,mm5 + movq mm5,[Zero] + + mov ebx,dword ptr[UV16+4] + punpcklbw mm5,[eax] + + psrlw mm2,8 + psrlw mm5,8 + + mov eax,dword ptr[UV16V] + psubw mm2,mm5 + + psllw mm5,8 + pmullw mm2,mm7 + + movq mm7,mm6 + paddw mm2,mm5 + + psrlw mm6,8 + psrlw mm2,8 + + mov esi,GBitPtr + psubw mm2,mm6 + + shr ebx,16 + pmullw mm2,mm3 + + add esi,eax + paddw mm7,mm2 + + psrlw mm7,8 + + add esi,ebx + movq mm2,mm7 ;make ABGR ARGB + + mov ecx,TexPal + psllq mm2,16 + + mov eax,offset QDibCan + punpckhwd mm7,mm2 ;BAGB + + psrlq mm2,16 + push ebp + + mov edi,dword ptr[eax+4] + punpckldq mm7,mm2 + + mov ebp,dword ptr[Dest] + movd mm3,dword ptr[ZiStepX] + + xor eax,eax + +LeftoverLoop128z: + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + pf2id mm2,mm4 + + mov al,byte ptr[esi] + movq mm5,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + pfadd mm4,mm3 + mov esi,GBitPtr + + pand mm5,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrld mm2,16 + + movd mm6,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + movd eax,mm2 + + movq [UV16],mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + xor eax,0 + + punpcklbw mm6,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + mov ebx,dword ptr[UV16+4] + + psrlq mm5,[QShiftV] + + shr ebx,16 + + movq [UV16V],mm5 + add esi,ebx + + mov edx,dword ptr[UV16V] + pmullw mm6,mm7 + + add esi,edx + cmp ax,word ptr[ebp] + jl SkipPixelLitZ + + psrlw mm6,8 + + + mov word ptr[ebp],ax + packuswb mm6,mm6 + + movd [edi],mm6 + +SkipPixelLitZ: + + add edi,4 + xor eax,eax + add ebp,2 + + dec [RemainingCount] + jge LeftoverLoop128z + + pop ebp + +FPUReturn128z: + + +; femms +Return128z: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawSpan32_AsmLitZBuffer3DNow +endProc DrawSpan32_AsmLitZBuffer3DNow + + + +;this is the most used routine likely. +;lightmap combine, zwrite + +cProc DrawSpan32_AsmLitZWrite3DNow, 12, + + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle ReturnLit + +; femms + +; inc ecx + mov ebx,offset ClientWindow + mov eax, y + mov edi,[ebx].Buffer + mov esi,x1 + imul eax, [ebx].PixelPitch + shl esi,2 + mov edx,ZBuffer + add eax,esi + add edi, eax + shr eax,1 + add edx,eax + mov [Dest],edx + + + mov eax,ecx + shr ecx,4 + and eax,15 + jnz @f + dec ecx + mov eax,16 +@@: + + mov [NumASpans],ecx + mov [RemainingCount],eax + ; mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 + movd mm0,x1 ; |x | | | | | | | + movq mm2,[UVDivZStepX] ; |x | |UZdX | | | | | + + movd mm1,y ; |x |y |UZdX | | | | | + movq mm3,[UVDivZStepY] ; |x |y |UZdX |UZdY | | | | + + punpckldq mm0,mm0 ; x|x |y |UZdX |UZdY | | | | + punpckldq mm1,mm1 ; x|x y|y UZdX|VZdX |UZdY | | | | + + pi2fd mm0,mm0 + pi2fd mm1,mm1 + + pfmul mm2,mm0 ; x|x y|y UZX|VZX UZdY|VZdY | | | | + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZdY|VZdY |ZdX | | | + + punpckldq mm4,mm4 + pfmul mm4,[QZBufferPrec] + pf2id mm4,mm4 + movq [QZDelta],mm4 + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZdY|VZdY |ZdX | | | + pfmul mm3,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZdX | | | + movq mm6,[UVDivZOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZdX | |UZO | + + movd mm5,[ZiStepY] ; x|x y|y UZX|VZX UZY|VZY |ZdX |ZdY |UZO | + pfmul mm4,mm0 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY |UZO | + + pfmul mm5,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO | + movd mm7,[ZiOrigin] + + pfadd mm6,mm2 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZXS|VZXS | + pfadd mm4,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZXS|VZXS | + + pfadd mm6,mm3 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZ|VZ | + pfadd mm4,mm5 ; x|x y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ | + +; movq mm7,mm4 +; movq mm1,[QZDelta] +; punpckldq mm7,mm7 +; pfmul mm7,[QZBufferPrec] +; pf2id mm7,mm7 +; movq mm0,mm7 +; paddd mm7,mm1 +; movq [QZVal32_0],mm0 +; paddd mm7,mm1 +; movq [QZVal32_1],mm7 +; pslld mm1,2 +; movd mm7,[Zi16StepX] +; movq [QZDelta],mm1 + + movq mm7,mm4 + movq mm1,[QZDelta] + punpckldq mm7,mm7 + pfmul mm7,[QZBufferPrec] + pf2id mm7,mm7 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + paddd mm7,mm1 + movq [QZVal32_0],mm0 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + movq [QZVal32_1],mm0 + pslld mm1,2 + movd mm7,[Zi16StepX] + movq [QZDelta],mm1 + + pfrcp mm0,mm4 ; ZL|ZL y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ | + movq mm1,mm6 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |Zi |ZY UZ|VZ | + + pfadd mm4,mm7 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ | + pfmul mm1,mm0 ; ZL|ZL UL|VL UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ | + + pfrcp mm2,mm4 ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZ|VZ | + pfadd mm6,[UVDivZ16StepX] ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZR|VZR | + + pfmul mm2,mm6 ; ZL|ZL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR | + movq mm0,mm1 ; UL|VL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR | + + movq mm3,mm2 ; ULi|VLi UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR | + pfmul mm0,[QFixedScale] ; UL6|VL6 UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR | + + pfmul mm3,[QFixedScale] ; UL6|VL6 UL|VL UR6|UR6 UR6|UR6 |ZRi |ZY UZR|VZR | + pf2id mm0,mm0 ;UL6i|VL6i UL|VL UR6|VR6 UR6|VR6 |ZRi |ZY UZR|VZR | + + pf2id mm3,mm3 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR | + + test ecx,ecx + jz HandleLeftoverPixelsLit + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm7,[QFixedScale] + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm7,[UVAdjustL] + movq [UVL16],mm7 + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + +; prefetch [Dest] + + cmp ebx,MaxU + jle TryClampU0Litp + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Litp + +TryClampU0Litp: + cmp ebx,0 + jge NoClampU0Litp + mov dword ptr[UVL16+4],0 +NoClampU0Litp: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Litp + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Litp + +TryClampV0Litp: + cmp eax,0 + jge NoClampV0Litp + mov dword ptr[UVL16],0 + +NoClampV0Litp: + + prefetch [GLightData] + + movq mm7,[UVL16] + movq mm5,[UVL16] + + movq [UVLeftW],mm3 + psrad mm7,[QGMip4_8] + + psrld mm5,[QGMip20] + pand mm7,[LMapMask8] + + movq [UVL16],mm5 + movq mm3,mm7 + + punpckhwd mm7,mm7 + mov eax,dword ptr[UVL16] + + movq mm5,[Zero] + imul eax,[GLightWidth] + + movq [UVZ],mm6 + punpcklwd mm3,mm3 + + add eax,dword ptr[UVL16+4] + movq mm6,[Zero] + + punpckldq mm7,mm7 + lea eax,[2*eax+eax] + + punpckldq mm3,mm3 + add eax,[GLightData] + + ;bilininterpolate to get good color + punpcklbw mm6,[eax+3] + mov ecx,[GLightWidth] + + psrlw mm6,8 + punpcklbw mm5,[eax] + + add eax,ecx + psrlw mm5,8 + + movq [UVLeft],mm2 + psubw mm6,mm5 + + movq mm2,[Zero] + psllw mm5,8 + + add eax,ecx + pmullw mm6,mm7 + + add eax,ecx + paddw mm6,mm5 + + movq mm5,[Zero] + punpcklbw mm2,[eax+3] + + punpcklbw mm5,[eax] + psrlw mm2,8 + + psrlw mm5,8 +; prefetch [GBitPtr+256] + + psubw mm2,mm5 + + psllw mm5,8 + + pmullw mm2,mm7 + movq mm7,mm6 + + paddw mm2,mm5 + psrlw mm6,8 + + psrlw mm2,8 + pfrcp mm5,mm4 + + psubw mm2,mm6 + + pmullw mm2,mm3 + + movq mm3,[UVLeftW] + paddw mm7,mm2 + + psrlw mm7,8 + + movq mm2,mm7 + + psllq mm2,16 + + punpckhwd mm7,mm2 + + psrlq mm2,16 + + punpckldq mm7,mm2 + + psllq mm7,8 + + movq mm2,[UVLeft] + + movq [ARL],mm7 + + movq mm6,[UVZ] + +SpanLoopLit: + ;use float uv for lightmap uv + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfmul mm7,mm2 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm5,[QFixedScale] + + pfmul mm7,[QFixedScale] + pf2id mm5,mm5 + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust] + + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust2] + + movq [UVL16],mm7 + movq [UVLeft],mm5 + + movd mm7,[Zi16StepX] + movq mm0,mm5 + + pfmul mm1,[QFixedScale16] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + ;right side stuff becomes left ; ULw|VLw DU16|DV16 UL|VL URw|VRw |ZLi |ZY UZL|VZL | + pfadd mm4,mm7 ;ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZL|VZL | + + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm7,[UVAdjustL] + movq [UV16],mm5 + + pfadd mm6,[UVDivZ16StepX] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm7,[UVL16] + + psrlq mm5,[QShiftV] + movq [UVL16],mm7 + + movq [UV16V],mm5 + + prefetch [edi] + + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU0Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Lit + +TryClampU0Lit: + cmp ebx,0 + jge NoClampU0Lit + mov dword ptr[UVL16+4],0 +NoClampU0Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Lit + +TryClampV0Lit: + cmp eax,0 + jge NoClampV0Lit + mov dword ptr[UVL16],0 + +NoClampV0Lit: + movq mm7,[UVL16] + movq mm5,[UVL16] + + movq [UVLeftW],mm3 + psrad mm7,[QGMip4_8] + + psrld mm5,[QGMip20] + pand mm7,[LMapMask8] + + movq [UVL16],mm5 + movq mm3,mm7 + + punpckhwd mm7,mm7 + mov eax,dword ptr[UVL16] + + movq mm5,[Zero] + imul eax,[GLightWidth] + + movq [UVZ],mm6 + punpcklwd mm3,mm3 + + add eax,dword ptr[UVL16+4] + movq mm6,[Zero] + + punpckldq mm7,mm7 + lea eax,[2*eax+eax] + + punpckldq mm3,mm3 + add eax,[GLightData] + + mov ecx,[GLightWidth] + + ;bilininterpolate to get good color + punpcklbw mm6,[eax+3] + + punpcklbw mm5,[eax] + psrlw mm6,8 + + psrlw mm5,8 + add eax,ecx + + movq [UVLeft],mm2 + psubw mm6,mm5 + + movq mm2,[Zero] + psllw mm5,8 + + add eax,ecx + pmullw mm6,mm7 + + add eax,ecx + paddw mm6,mm5 + + movq mm5,[Zero] + punpcklbw mm2,[eax+3] + + punpcklbw mm5,[eax] + psrlw mm2,8 + + psrlw mm5,8 + + mov eax,dword ptr[UV16V] + psubw mm2,mm5 + + psllw mm5,8 + pmullw mm2,mm7 + + movq mm7,mm6 + paddw mm2,mm5 + + psrlw mm6,8 + psrlw mm2,8 + + mov ebx,dword ptr[UV16+4] + psubw mm2,mm6 + + mov esi,GBitPtr + pmullw mm2,mm3 + + shr ebx,16 + paddw mm7,mm2 + + add esi,eax + psrlw mm7,8 + + pfrcp mm5,mm4 + movq mm2,mm7 + + add esi,ebx + psllq mm2,16 + + movq [ZIR],mm4 + punpckhwd mm7,mm2 + + psrlq mm2,16 + xor eax,eax + + punpckldq mm7,mm2 + mov ecx,TexPal + + movq mm4,[ARL] + psllq mm7,8 + + prefetch [ecx] + + movq mm6,[ARL] + psrlw mm4,4 + + movq [ARL],mm7 + movq mm3,mm7 + + psrlw mm3,4 + psubw mm3,mm4 + + push ebp + mov ebp,[Dest] + + prefetch [ebp] + + ;grab zbuffer values + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + psrld mm2,17 + psrld mm7,17 + + prefetch [esi] + + packssdw mm2,mm7 + + pslld mm2,1 + movq [ebp],mm2 + + + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movq [UVR],mm5 + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrlq mm4,[QShiftV] + + prefetch [ecx+32] + + mov ebx,dword ptr[UV16+4] + movq [UV16V],mm4 + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + psrlw mm2,8 + + shr ebx,16 + add esi,ebx + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + add esi,edx + pmullw mm7,mm2 + prefetch [esi] + + xor eax,eax + movq mm4,mm0 + + psrlw mm7,8 + + mov al,byte ptr[esi] + paddw mm6,mm3 + + pand mm4,[WrapMask] + movq mm2,mm6 + + prefetch [edi+32] + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlw mm2,8 + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + psrlq mm4,[QShiftV] + mov ebx,dword ptr[UV16+4] + + movq [UV16V],mm4 + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + paddd mm0,mm1 + + pmullw mm5,mm2 + mov esi,GBitPtr + + movq mm2,mm6 + psrlw mm5,8 + + shr ebx,16 + psrlw mm2,8 + + add esi,edx + movq mm4,mm0 + + packuswb mm7,mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + add esi,ebx + + movq [edi],mm7 + prefetch [esi] + xor eax,eax + + pand mm4,[WrapMask] + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + mov esi,GBitPtr + + mov ebx,dword ptr[UV16+4] + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + shr ebx,16 + + movq mm2,mm6 + add esi,edx + + psrlw mm7,8 + add esi,ebx + + movq mm4,mm0 + psrlw mm2,8 + + pand mm4,[WrapMask] + mov al,byte ptr[esi] + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + movq mm2,mm6 + + prefetch [ebp+32] + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+8],mm7 + prefetch [esi] + xor eax,eax + + psrlq mm4,[QShiftV] + psrlw mm2,8 + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + shr ebx,16 + + movq mm2,mm6 + add esi,edx + + psrlw mm7,8 + add esi,ebx + + movq mm4,mm0 + psrlw mm2,8 + + pand mm4,[WrapMask] + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+16],mm7 + xor eax,eax + + prefetch [esi] + + ;regrab z + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm7,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + pslld mm2,1 + + movq [ebp+8],mm2 + movq mm2,mm6 + + psrlq mm4,[QShiftV] + psrlw mm2,8 + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + shr ebx,16 + + movq mm2,mm6 + add esi,edx + + psrlw mm7,8 + add esi,ebx + + movq mm4,mm0 + psrlw mm2,8 + + pand mm4,[WrapMask] + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + movq mm2,mm6 + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+24],mm7 + prefetch [esi] + xor eax,eax + + psrlq mm4,[QShiftV] + psrlw mm2,8 + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + shr ebx,16 + + movq mm2,mm6 + add esi,edx + + psrlw mm7,8 + add esi,ebx + + movq mm4,mm0 + psrlw mm2,8 + + pand mm4,[WrapMask] + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+32],mm7 + xor eax,eax + + prefetch [esi] + + ;regrab z + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm7,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + pslld mm2,1 + + movq [ebp+16],mm2 + + psrlq mm4,[QShiftV] + movq mm2,mm6 + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + psrlw mm2,8 + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + shr ebx,16 + + movq mm2,mm6 + add esi,edx + + psrlw mm7,8 + add esi,ebx + + movq mm4,mm0 + psrlw mm2,8 + + pand mm4,[WrapMask] + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + movq mm2,mm6 + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + psrlw mm2,8 + + movq [edi+40],mm7 + prefetch [esi] + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + paddw mm6,mm3 + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + shr ebx,16 + + movq mm2,mm6 + add esi,edx + + psrlw mm7,8 + add esi,ebx + + movq mm4,mm0 + psrlw mm2,8 + + pand mm4,[WrapMask] + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + paddw mm6,mm3 + + movq [UV16V],mm4 + pmullw mm5,mm2 + + mov ebx,dword ptr[UV16+4] + + psrlw mm5,8 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+48],mm7 + xor eax,eax + prefetch [esi] + + ;regrab z + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm7,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + pslld mm2,1 + + movq [ebp+24],mm2 + + + psrlq mm4,[QShiftV] + movq mm2,mm6 + + mov al,byte ptr[esi] + psrlw mm2,8 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + mov esi,GBitPtr + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + movq [UV16V],mm4 + paddw mm6,mm3 + + pmullw mm7,mm2 + xor eax,eax + + mov edx,dword ptr[UV16V] + movq mm2,mm6 + + shr ebx,16 + + add esi,edx + psrlw mm2,8 + + add esi,ebx + + mov al,byte ptr[esi] + + psrlw mm7,8 + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + pmullw mm5,mm2 + add dword ptr[Dest],32 + + psrlw mm5,8 + + packuswb mm7,mm5 + pop ebp + + movq [edi+56],mm7 + + ;regrab z + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm7,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + ; get corrected right side deltas ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm4,[ZIR] + movq mm6,[UVZ] + + movq mm2,[UVR] + movq mm0,[UVLeftW] ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm1,[UVLeft] ; ULw|VLw UL|VL argb|ARGBagAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + punpckldq mm2,mm2 ; ULw|VLw UL|VL ZRi|ZRi agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + pfmul mm2,mm6 ; ULw|VLw UL|VL UR|VR agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + add edi,64 ; move screen pointer to start of next aspan + + movq mm3,mm2 + pfmul mm3,[QFixedScale] + + pf2id mm3,mm3 + + dec [NumASpans] ; dec num affine spans + jnz SpanLoopLit + +HandleLeftoverPixelsLit: + + + mov esi,GBitPtr + + + mov eax,[RemainingCount] + mov dword ptr[ZIR],eax + mov dword ptr[ZIR+4],eax + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfsub mm6,[UVDivZ16StepX] + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + + pfmul mm5,[QFixedScale] + pi2fd mm3,[ZIR] + + pfmul mm7,[QFixedScale] + pfmul mm3,[UVDivZStepX] + + pf2id mm5,mm5 + pfadd mm3,mm6 + + pi2fd mm2,[ZIR] + movd mm6,[Zi16StepX] + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + pfsub mm4,mm6 + + movd mm6,[ZiStepX] + mov ebx,[RemainingCount] + + pfmul mm2,mm6 + + shl ebx,3 + + pfadd mm2,mm4 + paddd mm5,[UVAdjust] + + movq [UVL16],mm7 + pfrcp mm2,mm2 + + paddd mm5,[UVAdjust2] + pfmul mm2,mm3 + + punpckldq mm4,mm4 + + movq [UVLeft],mm5 + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + pfmul mm4,[QZBufferPrec] + pfmul mm1,qword ptr[QFixedScaleLUT+ebx] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm0,mm5 + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq [UV16],mm5 + movq mm7,[UVAdjustL] + + psrlq mm5,[QShiftV] + paddd mm7,[UVL16] + + movq [UV16V],mm5 + movq [UVL16],mm7 + + +OnePixelSpanLit: + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU1Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU1Lit + +TryClampU1Lit: + cmp ebx,0 + jge NoClampU1Lit + mov dword ptr[UVL16+4],0 +NoClampU1Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV1Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV1Lit + +TryClampV1Lit: + cmp eax,0 + jge NoClampV1Lit + mov dword ptr[UVL16],0 + +NoClampV1Lit: + movq mm7,[UVL16] + movq mm5,[UVL16] + + psrad mm7,[QGMip4_8] + psrld mm5,[QGMip20] + + pand mm7,[LMapMask8] + movq [UVL16],mm5 + + movq mm3,mm7 + punpckhwd mm7,mm7 + + mov eax,dword ptr[UVL16] + movq mm5,[Zero] + + imul eax,[GLightWidth] + punpcklwd mm3,mm3 + + add eax,dword ptr[UVL16+4] + movq mm6,[Zero] + + punpckldq mm7,mm7 + lea eax,[2*eax+eax] + + punpckldq mm3,mm3 + add eax,[GLightData] + + ;bilininterpolate to get good color + punpcklbw mm6,[eax+3] + mov ecx,[GLightWidth] + + punpcklbw mm5,[eax] + psrlw mm6,8 + + psrlw mm5,8 + add eax,ecx + + movq mm2,[Zero] + psubw mm6,mm5 + + add eax,ecx + psllw mm5,8 + + add eax,ecx + pmullw mm6,mm7 ; B|B + + punpcklbw mm2,[eax+3] + paddw mm6,mm5 + + psrlw mm2,8 + movq mm5,[Zero] + + mov ebx,dword ptr[UV16+4] + punpcklbw mm5,[eax] + + mov eax,dword ptr[UV16V] + psrlw mm5,8 + + mov esi,GBitPtr + psubw mm2,mm5 + + shr ebx,16 + psllw mm5,8 + + add esi,eax + pmullw mm2,mm7 + + movq mm7,mm6 + paddw mm2,mm5 + + psrlw mm6,8 + psrlw mm2,8 + + add esi,ebx + mov ecx,TexPal + + psubw mm2,mm6 + xor eax,eax + + pmullw mm2,mm3 + + paddw mm7,mm2 + + psrlw mm7,8 + + movq mm2,mm7 ;make ABGR ARGB + + psllq mm2,16 + + punpckhwd mm7,mm2 ;BAGB + + psrlq mm2,16 + push ebp + + punpckldq mm7,mm2 + + mov ebp,dword ptr[Dest] + movd mm3,dword ptr[ZiStepX] + + xor eax,eax + +LeftoverLoopLit: + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + pf2id mm2,mm4 + + mov al,byte ptr[esi] + movq mm5,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + pfadd mm4,mm3 + mov esi,GBitPtr + + pand mm5,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrlq mm2,16 + + movd mm6,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + movd eax,mm2 + + movq [UV16],mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + xor eax,0 + + punpcklbw mm6,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + mov word ptr[ebp],ax + + mov ebx,dword ptr[UV16+4] + add ebp,2 + + psrlq mm5,[QShiftV] + + shr ebx,16 + + movq [UV16V],mm5 + pmullw mm6,mm7 + + add esi,ebx + mov edx,dword ptr[UV16V] + psrlw mm6,8 + + add esi,edx + packuswb mm6,mm6 + + xor eax,eax + movd [edi],mm6 + + add edi,4 + + dec [RemainingCount] + jge LeftoverLoopLit + + pop ebp + +ReturnLit: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawSpan32_AsmLitZWrite3DNow +endProc DrawSpan32_AsmLitZWrite3DNow + + +;perspective correct gouraud with zwrite + +cProc DrawSpan32_AsmGouraudZWrite3DNow, 36, + + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle ReturnLit + +; femms + +; inc ecx + mov eax,y + mov edx,x1 + mov ebx,offset ClientWindow + shl edx,2 + imul eax,[ebx].PixelPitch + mov edi,[ebx].Buffer + mov esi,ZBuffer + add edx,eax + mov eax,ecx + add edi,edx + shr edx,1 + add esi,edx + mov [Dest],esi + mov edx,ecx + + shr ecx,4 + and eax,15 + jnz @f + dec ecx + mov eax,16 +@@: + + mov [NumASpans],ecx + mov [RemainingCount],eax + + ;grab the left side lights + movd mm5,r1 + movd mm4,b1 + +; punpckldq mm5,qword ptr[Zero] + movd mm6,g1 + + pf2id mm5,mm5 + punpckldq mm4,mm6 + + pf2id mm4,mm4 + packssdw mm4,mm5 + + psllw mm4,7 + + movq [ARL],mm4 + + ; mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 + movd mm0,x1 ; |x | | | | | | | + movq mm2,[UVDivZStepX] ; |x | UZdX|VZdX | | | | | + + movd mm1,y ; |x |y UZdX|VZdX | | | | | + movq mm3,[UVDivZStepY] ; |x |y UZdX|VZdXUZdY|VZdY | | | | + + punpckldq mm0,mm0 ; x|x |y UZdX|VZdXUZdY|VZdY | | | | + punpckldq mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | | | | + + movd mm7,edx ; x|x y|y UZdX|VZdXUZdY|VZdY | | | |wid + movd mm5,b2 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + + pi2fd mm0,mm0 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + movd mm6,b1 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + + pi2fd mm7,mm7 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + punpckldq mm5,qword ptr[g2] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + + pi2fd mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + punpckldq mm6,qword ptr[g1] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b g|b |wid + + pfmul mm2,mm0 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b |wid + pfrcp mm7,mm7 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b dw|dw + + pfsub mm5,mm6 ; x|x y|y UZX|VZX UZdY|VZdY | gd|bd g|b dw|dw + movd mm4,[r1] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|b dw|dw + + movd mm6,[r2] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|r dw|dw + pfmul mm3,mm1 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd g|r dw|dw + + pfsub mm6,mm4 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd dw|dw + pfmul mm7,[Q128] ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd DW|DW + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZY|VZY |ZdX gd|bd x|rd DW|DW + + punpckldq mm4,mm4 + pfmul mm4,[QZBufferPrec] + pf2id mm4,mm4 + movq [QZDelta],mm4 + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZY|VZY |ZdX gd|bd x|rd DW|DW + pfmul mm5,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZdX GD|BD x|rd DW|DW + + pfmul mm4,mm0 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|rd DW|DW + pfmul mm6,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|RD DW|DW + + pf2id mm5,mm5 + pf2id mm6,mm6 + + packssdw mm5,mm6 + movq [RGBADelta],mm5 + + movd mm5,[ZiStepY] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY x|RD DW|DW + movq mm6,[UVDivZOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY UZO|VZO DW|DW + + pfmul mm5,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO DW|DW + movd mm7,[ZiOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO |ZO + + pfadd mm6,mm2 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZXS|VZXS |ZO + pfadd mm4,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZXS|VZXS |ZO + + pfadd mm6,mm3 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZ|VZ |ZO + pfadd mm4,mm5 ; x|x y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZO + + movq mm7,mm4 + movq mm1,[QZDelta] + punpckldq mm7,mm7 + pfmul mm7,[QZBufferPrec] + pf2id mm7,mm7 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + paddd mm7,mm1 + movq [QZVal32_0],mm0 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + movq [QZVal32_1],mm0 + pslld mm1,2 + movd mm7,[Zi16StepX] + movq [QZDelta],mm1 + + pfrcp mm0,mm4 ; ZL|ZL y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + + movq mm1,mm6 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + pfadd mm4,mm7 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfmul mm1,mm0 ; ZL|ZL UL|VL UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + pfrcp mm2,mm4 ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfadd mm6,[UVDivZ16StepX] ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm2,mm6 ; ZL|ZL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + + movq mm0,mm1 ; UL|VL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + movq mm3,mm2 ; ULi|VLi UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + + pfmul mm0,[QFixedScale] ; UL6|VL6 UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm3,[QFixedScale] ; UL6|VL6 UL|VL UR6|UR6 UR6|UR6 |ZRi |ZY UZR|VZR |ZdX16 + + pf2id mm0,mm0 ;UL6i|VL6i UL|VL UR6|VR6 UR6|VR6 |ZRi |ZY UZR|VZR |ZdX16 + pf2id mm3,mm3 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR |ZdX16 + + + test ecx,ecx + jz HandleLeftoverPixelsLit + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm7,[QFixedScale] + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm7,[UVAdjustL] + movq [UVL16],mm7 + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + + cmp ebx,MaxU + jle TryClampU0Litp + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Litp + +TryClampU0Litp: + cmp ebx,0 + jge NoClampU0Litp + mov dword ptr[UVL16+4],0 +NoClampU0Litp: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Litp + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Litp + +TryClampV0Litp: + cmp eax,0 + jge NoClampV0Litp + mov dword ptr[UVL16],0 + +NoClampV0Litp: + + pfrcp mm5,mm4 + +SpanLoopLit: + ;use float uv for lightmap uv + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfmul mm7,mm2 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm5,[QFixedScale] + + pfmul mm7,[QFixedScale] + pf2id mm5,mm5 + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust] + + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust2] + + movq [UVL16],mm7 + movq [UVLeft],mm5 + + movd mm7,[Zi16StepX] + movq mm0,mm5 + + pfmul mm1,[QFixedScale16] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + ;right side stuff becomes left ; ULw|VLw DU16|DV16 UL|VL URw|VRw |ZLi |ZY UZL|VZL | + pfadd mm4,mm7 ;ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZL|VZL | + + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm7,[UVAdjustL] + movq [UV16],mm5 + + pfadd mm6,[UVDivZ16StepX] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm7,[UVL16] + + psrlq mm5,[QShiftV] + movq [UVL16],mm7 + + movq [UV16V],mm5 + + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU0Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Lit + +TryClampU0Lit: + cmp ebx,0 + jge NoClampU0Lit + mov dword ptr[UVL16+4],0 +NoClampU0Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Lit + +TryClampV0Lit: + cmp eax,0 + jge NoClampV0Lit + mov dword ptr[UVL16],0 + +NoClampV0Lit: + movq [UVLeftW],mm3 + mov eax,dword ptr[UV16V] + mov ebx,dword ptr[UV16+4] + movq [ZIR],mm4 + mov esi,GBitPtr + shr ebx,16 + movq [UVZ],mm6 + add esi,eax + add esi,ebx + movq [UVLeft],mm2 + + mov ecx,TexPal + pfrcp mm5,mm4 + movq mm3,[RGBADelta] + xor eax,eax + movq mm6,[ARL] + + push ebp + mov ebp,[Dest] + + ;grab zbuffer values + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + + pslld mm2,1 + movq [ebp],mm2 + + + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movq [UVR],mm5 + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrlq mm4,[QShiftV] + + mov ebx,dword ptr[UV16+4] + movq [UV16V],mm4 + + mov edx,dword ptr[UV16V] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + shr ebx,16 + add esi,ebx + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + psllw mm7,1 + add esi,edx + + pmulhw mm7,mm6 + paddw mm6,mm3 + + xor eax,eax + movq mm4,mm0 + + mov al,byte ptr[esi] + + pand mm4,[WrapMask] + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + psrlq mm4,[QShiftV] + mov ebx,dword ptr[UV16+4] + + movq [UV16V],mm4 + psllw mm5,1 + + mov edx,dword ptr[UV16V] + paddd mm0,mm1 + + pmulhw mm5,mm6 + paddw mm6,mm3 + + shr ebx,16 + mov esi,GBitPtr + + add esi,edx + movq mm4,mm0 + + packuswb mm7,mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + add esi,ebx + + movq [edi],mm7 + xor eax,eax + + pand mm4,[WrapMask] + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + mov esi,GBitPtr + + mov ebx,dword ptr[UV16+4] + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+8],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+16],mm7 + xor eax,eax + + ;regrab z + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm7,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + pslld mm2,1 + + movq [ebp+8],mm2 + + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+24],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+32],mm7 + xor eax,eax + + ;regrab z + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm7,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + pslld mm2,1 + + movq [ebp+16],mm2 + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+40],mm7 + xor eax,eax + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + paddd mm0,mm1 + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + movq mm4,mm0 + + add esi,edx + + pand mm4,[WrapMask] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + mov esi,GBitPtr + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + paddd mm0,mm1 + + psrlq mm4,[QShiftV] + psllw mm5,1 + + movq [UV16V],mm4 + pmulhw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + paddw mm6,mm3 + + mov edx,dword ptr[UV16V] + movq mm4,mm0 + + shr ebx,16 + pand mm4,[WrapMask] + + add esi,edx + packuswb mm7,mm5 + + movq [UV16],mm4 + add esi,ebx + + movq [edi+48],mm7 + xor eax,eax + + ;regrab z + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm7,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + pslld mm2,1 + + movq [ebp+24],mm2 + + psrlq mm4,[QShiftV] + + mov al,byte ptr[esi] + mov esi,GBitPtr + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + mov ebx,dword ptr[UV16+4] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + movq [UV16V],mm4 + psllw mm7,1 + + pmulhw mm7,mm6 + xor eax,eax + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + + add esi,edx + + add esi,ebx + + mov al,byte ptr[esi] + + movd mm5,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + punpcklbw mm5,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + psllw mm5,1 + + pmulhw mm5,mm6 + pop ebp + paddw mm6,mm3 + + packuswb mm7,mm5 + movq [ARL],mm6 + + movq [edi+56],mm7 + ;regrab z + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm7,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + ; get corrected right side deltas ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm4,[ZIR] + movq mm6,[UVZ] + + movq mm2,[UVR] + movq mm0,[UVLeftW] ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm1,[UVLeft] ; ULw|VLw UL|VL argb|ARGBagAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + punpckldq mm2,mm2 ; ULw|VLw UL|VL ZRi|ZRi agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + pfmul mm2,mm6 ; ULw|VLw UL|VL UR|VR agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + add edi,64 ; move screen pointer to start of next aspan + add [Dest],32 + + movq mm3,mm2 + pfmul mm3,[QFixedScale] + + pf2id mm3,mm3 + + dec [NumASpans] ; dec num affine spans + jnz SpanLoopLit + +HandleLeftoverPixelsLit: + + + mov esi,GBitPtr + + + cmp [RemainingCount],0 + jz ReturnLit + + mov eax,[RemainingCount] + mov dword ptr[ZIR],eax + mov dword ptr[ZIR+4],eax + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfsub mm6,[UVDivZ16StepX] + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + + pfmul mm5,[QFixedScale] + pi2fd mm3,[ZIR] + + pfmul mm7,[QFixedScale] + pfmul mm3,[UVDivZStepX] + + pf2id mm5,mm5 + pfadd mm3,mm6 + + pi2fd mm2,[ZIR] + movd mm6,[Zi16StepX] + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + pfsub mm4,mm6 + + movd mm6,[ZiStepX] + mov ebx,[RemainingCount] + + pfmul mm2,mm6 + + shl ebx,3 + + pfadd mm2,mm4 + paddd mm5,[UVAdjust] + + punpckldq mm4,mm4 + + movq [UVL16],mm7 + pfrcp mm2,mm2 + + pfmul mm4,[QZBufferPrec] + + paddd mm5,[UVAdjust2] + pfmul mm2,mm3 + + movq [UVLeft],mm5 + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + pfmul mm1,qword ptr[QFixedScaleLUT+ebx] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm0,mm5 + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq [UV16],mm5 + movq mm7,[UVAdjustL] + + psrlq mm5,[QShiftV] + paddd mm7,[UVL16] + + movq [UV16V],mm5 + movq [UVL16],mm7 + + +OnePixelSpanLit: + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU1Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU1Lit + +TryClampU1Lit: + cmp ebx,0 + jge NoClampU1Lit + mov dword ptr[UVL16+4],0 +NoClampU1Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV1Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV1Lit + +TryClampV1Lit: + cmp eax,0 + jge NoClampV1Lit + mov dword ptr[UVL16],0 + +NoClampV1Lit: + mov ebx,dword ptr[UV16+4] + mov eax,dword ptr[UV16V] + + mov esi,GBitPtr + shr ebx,16 + add esi,eax + add esi,ebx + mov ecx,TexPal + xor eax,eax + movq mm6,[ARL] + push ebp + mov ebp,dword ptr[Dest] + movd mm3,dword ptr[ZiStepX] + +LeftoverLoopLit: + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + pf2id mm2,mm4 + + mov al,byte ptr[esi] + movq mm5,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + pfadd mm4,mm3 + mov esi,GBitPtr + + pand mm5,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrlq mm2,16 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + movd eax,mm2 + + movq [UV16],mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + xor eax,0 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + mov word ptr[ebp],ax + + mov ebx,dword ptr[UV16+4] + + psrlq mm5,[QShiftV] + + shr ebx,16 + psllw mm7,1 + + movq [UV16V],mm5 + add esi,ebx + + mov edx,dword ptr[UV16V] + pmulhw mm7,mm6 + + add esi,edx + packuswb mm7,mm7 + + xor eax,eax + movd [edi],mm7 + + add edi,4 + add ebp,2 + + dec [RemainingCount] + jge LeftoverLoopLit + + pop ebp + +ReturnLit: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawSpan32_AsmGouraudZWrite3DNow +endProc DrawSpan32_AsmGouraudZWrite3DNow + + + +;same with zbuffer + +cProc DrawSpan32_AsmGouraudZBuffer3DNow, 36, + + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle ReturnLit + +; femms + +; inc ecx + mov ebx,offset ClientWindow + mov eax, y + mov edi,[ebx].Buffer + mov esi,x1 + imul eax, [ebx].PixelPitch + shl esi,2 + mov edx,ZBuffer + add eax,esi + add edi, eax + shr eax,1 + add edx,eax + mov [Dest],edx + mov eax,offset QZCan + mov ebx,offset SCan + mov [eax],ebx + mov [eax+4],edx + mov eax,offset QDibCan + mov [eax],ebx + mov [eax+4],edi + mov ebx,offset QDibCan + mov eax,offset QDibOrCan + mov [eax],ebx + mov [eax+4],ebx + mov ebx,offset QZCan + mov eax,offset QZOrCan + mov [eax],ebx + mov [eax+4],ebx + mov edx,ecx + mov eax,ecx + + shr ecx,4 + and eax,15 + jnz @f + dec ecx + mov eax,16 +@@: + + mov [NumASpans],ecx + mov [RemainingCount],eax + + ;grab the left side lights + movd mm5,r1 + movd mm4,b1 + +; punpckldq mm5,qword ptr[Zero] + movd mm6,g1 + + pf2id mm5,mm5 + punpckldq mm4,mm6 + + pf2id mm4,mm4 + packssdw mm4,mm5 + +; psllw mm4,7 + + movq [ARL],mm4 + + ; mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 + movd mm0,x1 ; |x | | | | | | | + movq mm2,[UVDivZStepX] ; |x | UZdX|VZdX | | | | | + + movd mm1,y ; |x |y UZdX|VZdX | | | | | + movq mm3,[UVDivZStepY] ; |x |y UZdX|VZdXUZdY|VZdY | | | | + + punpckldq mm0,mm0 ; x|x |y UZdX|VZdXUZdY|VZdY | | | | + punpckldq mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | | | | + + movd mm7,edx ; x|x y|y UZdX|VZdXUZdY|VZdY | | | |wid + movd mm5,b2 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + + pi2fd mm0,mm0 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + movd mm6,b1 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + + pi2fd mm7,mm7 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + punpckldq mm5,qword ptr[g2] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + + pi2fd mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + punpckldq mm6,qword ptr[g1] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b g|b |wid + + pfmul mm2,mm0 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b |wid + pfrcp mm7,mm7 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b dw|dw + + pfsub mm5,mm6 ; x|x y|y UZX|VZX UZdY|VZdY | gd|bd g|b dw|dw + movd mm4,[r1] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|b dw|dw + + movd mm6,[r2] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|r dw|dw + pfmul mm3,mm1 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd g|r dw|dw + + pfsub mm6,mm4 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd dw|dw + pfmul mm7,[Q128] ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd DW|DW + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZY|VZY |ZdX gd|bd x|rd DW|DW + + punpckldq mm4,mm4 + pfmul mm4,[QZBufferPrec] + pf2id mm4,mm4 + movq [QZDelta],mm4 + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZdY|VZdY |ZdX | | | + pfmul mm5,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZdX GD|BD x|rd DW|DW + + pfmul mm4,mm0 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|rd DW|DW + pfmul mm6,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|RD DW|DW + + pf2id mm5,mm5 + pf2id mm6,mm6 + + packssdw mm5,mm6 + movq [RGBADelta],mm5 + + movd mm5,[ZiStepY] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY x|RD DW|DW + movq mm6,[UVDivZOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY UZO|VZO DW|DW + + pfmul mm5,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO DW|DW + movd mm7,[ZiOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO |ZO + + pfadd mm6,mm2 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZXS|VZXS |ZO + pfadd mm4,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZXS|VZXS |ZO + + pfadd mm6,mm3 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZ|VZ |ZO + pfadd mm4,mm5 ; x|x y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZO + + movq mm7,mm4 + movq mm1,[QZDelta] + punpckldq mm7,mm7 + pfmul mm7,[QZBufferPrec] + pf2id mm7,mm7 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + paddd mm7,mm1 + movq [QZVal32_0],mm0 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + movq [QZVal32_1],mm0 + pslld mm1,2 + movd mm7,[Zi16StepX] + movq [QZDelta],mm1 + + pfrcp mm0,mm4 ; ZL|ZL y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + + movq mm1,mm6 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + pfadd mm4,mm7 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfmul mm1,mm0 ; ZL|ZL UL|VL UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + pfrcp mm2,mm4 ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfadd mm6,[UVDivZ16StepX] ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm2,mm6 ; ZL|ZL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + + movq mm0,mm1 ; UL|VL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + movq mm3,mm2 ; ULi|VLi UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + + pfmul mm0,[QFixedScale] ; UL6|VL6 UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm3,[QFixedScale] ; UL6|VL6 UL|VL UR6|UR6 UR6|UR6 |ZRi |ZY UZR|VZR |ZdX16 + + pf2id mm0,mm0 ;UL6i|VL6i UL|VL UR6|VR6 UR6|VR6 |ZRi |ZY UZR|VZR |ZdX16 + pf2id mm3,mm3 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR |ZdX16 + + + test ecx,ecx + jz HandleLeftoverPixelsLit + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm7,[QFixedScale] + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm7,[UVAdjustL] + movq [UVL16],mm7 + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + + cmp ebx,MaxU + jle TryClampU0Litp + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Litp + +TryClampU0Litp: + cmp ebx,0 + jge NoClampU0Litp + mov dword ptr[UVL16+4],0 +NoClampU0Litp: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Litp + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Litp + +TryClampV0Litp: + cmp eax,0 + jge NoClampV0Litp + mov dword ptr[UVL16],0 + +NoClampV0Litp: + + pfrcp mm5,mm4 + +SpanLoopLit: + ;use float uv for lightmap uv + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfmul mm7,mm2 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm5,[QFixedScale] + + pfmul mm7,[QFixedScale] + pf2id mm5,mm5 + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust] + + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust2] + + movq [UVL16],mm7 + movq [UVLeft],mm5 + + movd mm7,[Zi16StepX] + movq mm0,mm5 + + pfmul mm1,[QFixedScale16] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + ;right side stuff becomes left ; ULw|VLw DU16|DV16 UL|VL URw|VRw |ZLi |ZY UZL|VZL | + pfadd mm4,mm7 ;ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZL|VZL | + + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm7,[UVAdjustL] + movq [UV16],mm5 + + pfadd mm6,[UVDivZ16StepX] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm7,[UVL16] + + psrlq mm5,[QShiftV] + movq [UVL16],mm7 + + movq [UV16V],mm5 + + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU0Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Lit + +TryClampU0Lit: + cmp ebx,0 + jge NoClampU0Lit + mov dword ptr[UVL16+4],0 +NoClampU0Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Lit + +TryClampV0Lit: + cmp eax,0 + jge NoClampV0Lit + mov dword ptr[UVL16],0 + +NoClampV0Lit: + movq [UVLeftW],mm3 + mov eax,dword ptr[UV16V] + mov ebx,dword ptr[UV16+4] + movq [ZIR],mm4 + mov esi,GBitPtr + shr ebx,16 + movq [UVZ],mm6 + add esi,eax + add esi,ebx + movq [UVLeft],mm2 + + mov ecx,TexPal + pfrcp mm5,mm4 + movq mm3,[RGBADelta] + xor eax,eax + movq mm6,[ARL] + + push ebp + mov ebp,[Dest] + + ;grab zbuffer values + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + + pslld mm2,1 + movq [QZVal],mm2 + + + movq mm2,[QZVal] + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + pcmpgtw mm2,[ebp] + mov esi,GBitPtr + + psrlw mm2,15 + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + psllw mm2,2 + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movq [GBL],mm2 + psrlq mm4,[QShiftV] + + movq mm7,mm2 + movq [UV16V],mm4 + + punpcklwd mm7,[Zero] + movq [UVR],mm5 + + paddd mm7,[QZOrCan] + mov edx,dword ptr[UV16V] + + movq [QZOut],mm7 + mov ebx,dword ptr[UV16+4] + + movq mm7,mm2 + mov edi,dword ptr[QZOut] + + punpcklwd mm7,[Zero] + shr ebx,16 + + paddd mm7,[QDibOrCan] + mov edi,dword ptr[edi] + + movq [QDibOut],mm7 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + add esi,edx + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + xor eax,eax + + pmullw mm7,mm6 + mov ax,word ptr[QZVal] + + paddd mm0,mm1 + mov word ptr[edi],ax + + mov edi,dword ptr[QDibOut] + add esi,ebx + + mov edi,dword ptr[edi] + paddw mm6,mm3 + + psrlw mm7,8 + xor eax,eax + + packuswb mm7,mm7 + mov al,byte ptr[esi] + + movd [edi],mm7 + movq mm4,mm0 + + pand mm4,[WrapMask] + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + movq [UV16],mm4 + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + psrlq mm4,[QShiftV] + mov ebx,dword ptr[UV16+4] + + movq [UV16V],mm4 + pmullw mm7,mm6 + + mov edx,dword ptr[UV16V] + paddw mm6,mm3 + + shr ebx,16 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + + mov edi,dword ptr[edi] + paddd mm0,mm1 + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+2] + + add esi,ebx + mov word ptr[edi+2],ax + + xor eax,eax + mov edi,dword ptr[QDibOut+4] + + mov al,byte ptr[esi] + movq mm4,mm0 + + mov edi,dword ptr[edi] + pand mm4,[WrapMask] + + mov esi,GBitPtr + movd [edi+4],mm7 + + movq mm7,mm2 + movq [UV16],mm4 + + punpckhwd mm7,[Zero] + psrlq mm4,[QShiftV] + + paddd mm7,[QZorCan] + movq [UV16V],mm4 + + movq [QZOut],mm7 + mov ebx,dword ptr[UV16+4] + + movq mm7,mm2 + mov edi,dword ptr[QZOut] + + punpckhwd mm7,[Zero] + mov edi,dword ptr[edi] + + paddd mm7,[QDibOrCan] + paddd mm0,mm1 + + movq [QDibOut],mm7 + mov edx,dword ptr[UV16V] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + xor eax,0 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + mov ax,word ptr[QZVal+4] + + pmullw mm7,mm6 + mov word ptr[edi+4],ax + + psrlw mm7,8 + mov edi,dword ptr[QDibOut] + + paddw mm6,mm3 + + packuswb mm7,mm7 + mov edi,dword ptr[edi] + + movq mm4,mm0 + movd [edi+8],mm7 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + movq [UV16],mm4 + mov al,byte ptr[esi] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + shr ebx,16 + + paddw mm6,mm3 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+6] + + add esi,ebx + mov word ptr[edi+6],ax + + mov edi,dword ptr[QDibOut+4] + xor eax,eax + + mov edi,dword ptr[edi] + mov al,byte ptr[esi] + + movd [edi+12],mm7 + movq mm4,mm0 + + ;regrab z + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm7,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + pand mm4,[WrapMask] + + pslld mm2,1 + movq [UV16],mm4 + + movq [QZVal],mm2 + mov esi,GBitPtr + + pcmpgtw mm2,[ebp+8] + psrlq mm4,[QShiftV] + + + psrlw mm2,15 + movq [UV16V],mm4 + + + psllw mm2,2 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + movq mm4,mm2 + mov ebx,dword ptr[UV16+4] + + punpcklwd mm4,[Zero] + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + paddd mm4,[QZorCan] + pmullw mm7,mm6 + + movq [QZOut],mm4 + mov edi,dword ptr[QZOut] + + movq mm4,mm2 + xor eax,eax + + paddw mm6,mm3 + + punpcklwd mm4,[Zero] + mov edi,dword ptr[edi] + + psrlw mm7,8 + + mov ax,word ptr[QZVal] + paddd mm4,[QDibOrCan] + + mov word ptr[edi+8],ax + movq [QDibOut],mm4 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[edi] + + movd [edi+16],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + paddw mm6,mm3 + + add esi,edx + xor eax,eax + + mov edi,dword ptr[edi] + movq mm4,mm0 + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + pand mm4,[WrapMask] + + mov ax,word ptr[QZVal+2] + movq [UV16],mm4 + + add esi,ebx + psrlq mm4,[QShiftV] + + mov word ptr[edi+10],ax + movq [UV16V],mm4 + + xor eax,eax + mov edi,dword ptr[QDibOut+4] + + mov al,byte ptr[esi] + mov edi,dword ptr[edi] + + mov esi,GBitPtr + movd [edi+20],mm7 + + movq mm4,mm2 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + punpckhwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm4,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpckhwd mm4,[Zero] + + paddw mm6,mm3 + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov ax,word ptr[QZVal+4] + paddd mm4,[QDibOrCan] + + mov word ptr[edi+12],ax + movq [QDibOut],mm4 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + + mov edx,dword ptr[UV16V] + + movd [edi+24],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + paddw mm6,mm3 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+6] + + add esi,ebx + mov word ptr[edi+14],ax + + ;regrab z + movq mm2,[QZVal32_0] + movq mm4,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm4,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm4 + + psrld mm2,17 + psrld mm4,17 + + packssdw mm2,mm4 + xor eax,eax + + pslld mm2,1 + + mov edi,dword ptr[QDibOut+4] + + movq [QZVal],mm2 + mov edi,dword ptr[edi] + + mov al,byte ptr[esi] + movq mm4,mm0 + + pand mm4,[WrapMask] + pcmpgtw mm2,[ebp+16] + + movd [edi+28],mm7 + movq [UV16],mm4 + + psrlw mm2,15 + mov esi,GBitPtr + + psrlq mm4,[QShiftV] + + psllw mm2,2 + movq [UV16V],mm4 + movq mm4,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + punpcklwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm4,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpcklwd mm4,[Zero] + + paddw mm6,mm3 + mov edi,dword ptr[edi] + + mov ax,word ptr[QZVal] + paddd mm4,[QDibOrCan] + psrlw mm7,8 + + mov word ptr[edi+16],ax + movq [QDibOut],mm4 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + mov edx,dword ptr[UV16V] + + movd [edi+32],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + paddw mm6,mm3 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + + movq mm4,mm0 + mov edi,dword ptr[edi] + + pand mm4,[WrapMask] + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + + movq [UV16],mm4 + mov ax,word ptr[QZVal+2] + + psrlq mm4,[QShiftV] + add esi,ebx + + movq [UV16V],mm4 + mov word ptr[edi+18],ax + + xor eax,eax + mov edi,dword ptr[QDibOut+4] + + mov al,byte ptr[esi] + mov edi,dword ptr[edi] + + mov esi,GBitPtr + movd [edi+36],mm7 + + movq mm4,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + punpckhwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm4,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpckhwd mm4,[Zero] + + paddw mm6,mm3 + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov ax,word ptr[QZVal+4] + paddd mm4,[QDibOrCan] + + mov word ptr[edi+20],ax + movq [QDibOut],mm4 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + mov edx,dword ptr[UV16V] + + movd [edi+40],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + paddw mm6,mm3 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+6] + + add esi,ebx + mov word ptr[edi+22],ax + + ;regrab z + movq mm2,[QZVal32_0] + movq mm4,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm4,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm4 + + psrld mm2,17 + psrld mm4,17 + + packssdw mm2,mm4 + xor eax,eax + + pslld mm2,1 + + mov edi,dword ptr[QDibOut+4] + + movq [QZVal],mm2 + mov edi,dword ptr[edi] + + mov al,byte ptr[esi] + movq mm4,mm0 + + pand mm4,[WrapMask] + pcmpgtw mm2,[ebp+24] + + movd [edi+44],mm7 + movq [UV16],mm4 + + psrlw mm2,15 + mov esi,GBitPtr + + psrlq mm4,[QShiftV] + + psllw mm2,2 + movq [UV16V],mm4 + + movq mm4,mm2 + + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + punpcklwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm4,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpcklwd mm4,[Zero] + + paddw mm6,mm3 + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov ax,word ptr[QZVal] + paddd mm4,[QDibOrCan] + + mov word ptr[edi+24],ax + movq [QDibOut],mm4 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + mov edx,dword ptr[UV16V] + + movd [edi+48],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + psrlw mm7,8 + + paddw mm6,mm3 + + mov esi,GBitPtr + mov edi,dword ptr[QZOut+4] + + add esi,edx + xor eax,eax + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+2] + + movq mm4,mm0 + add esi,ebx + + pand mm4,[WrapMask] + mov word ptr[edi+26],ax + + movq [UV16],mm4 + xor eax,eax + + psrlq mm4,[QShiftV] + mov edi,dword ptr[QDibOut+4] + + movq [UV16V],mm4 + mov al,byte ptr[esi] + + mov edi,dword ptr[edi] + + mov esi,GBitPtr + movd [edi+52],mm7 + + movq mm4,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + punpckhwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm4,mm2 + + pmullw mm7,mm6 + mov edi,dword ptr[QZOut] + + xor eax,eax + punpckhwd mm4,[Zero] + mov edi,dword ptr[edi] + + paddw mm6,mm3 + + mov ax,word ptr[QZVal+4] + paddd mm4,[QDibOrCan] + psrlw mm7,8 + + mov word ptr[edi+28],ax + movq [QDibOut],mm4 + + packuswb mm7,mm7 + mov edi,dword ptr[QDibOut] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + mov edx,dword ptr[UV16V] + + movd [edi+56],mm7 + movq mm4,mm0 + + shr ebx,16 + xor eax,eax + + pand mm4,[WrapMask] + add esi,edx + + paddd mm0,mm1 + add esi,ebx + + mov al,byte ptr[esi] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + pmullw mm7,mm6 + + paddw mm6,mm3 + psrlw mm7,8 + + mov edi,dword ptr[QZOut+4] + + xor eax,eax + mov edi,dword ptr[edi] + + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + mov ax,word ptr[QZVal+6] + + movq [ARL],mm6 + mov word ptr[edi+30],ax + + mov edi,dword ptr[QDibOut+4] + + pop ebp + mov edi,dword ptr[edi] + + ;regrab z + movq mm2,[QZVal32_0] + movq mm3,[QZVal32_1] + + paddd mm2,[QZDelta] + paddd mm3,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm3 + + movd [edi+60],mm7 + + ; get corrected right side deltas ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm4,[ZIR] + movq mm6,[UVZ] + + movq mm2,[UVR] + movq mm0,[UVLeftW] ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm1,[UVLeft] ; ULw|VLw UL|VL argb|ARGBagAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + punpckldq mm2,mm2 ; ULw|VLw UL|VL ZRi|ZRi agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + pfmul mm2,mm6 ; ULw|VLw UL|VL UR|VR agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + mov eax,offset QZCan + add dword ptr[Dest],32 + + add dword ptr[eax+4],32 + mov eax,offset QDibCan + + add dword ptr[eax+4],64 + + movq mm3,mm2 + pfmul mm3,[QFixedScale] + + pf2id mm3,mm3 + + dec [NumASpans] ; dec num affine spans + jnz SpanLoopLit + +HandleLeftoverPixelsLit: + + + mov esi,GBitPtr + + + cmp [RemainingCount],0 + jz ReturnLit + + mov eax,[RemainingCount] + mov dword ptr[ZIR],eax + mov dword ptr[ZIR+4],eax + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfsub mm6,[UVDivZ16StepX] + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + + pfmul mm5,[QFixedScale] + pi2fd mm3,[ZIR] + + pfmul mm7,[QFixedScale] + pfmul mm3,[UVDivZStepX] + + pf2id mm5,mm5 + pfadd mm3,mm6 + + pi2fd mm2,[ZIR] + movd mm6,[Zi16StepX] + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + pfsub mm4,mm6 + + movd mm6,[ZiStepX] + mov ebx,[RemainingCount] + + pfmul mm2,mm6 + + shl ebx,3 + + pfadd mm2,mm4 + paddd mm5,[UVAdjust] + + punpckldq mm4,mm4 + + movq [UVL16],mm7 + pfrcp mm2,mm2 + + pfmul mm4,[QZBufferPrec] + + paddd mm5,[UVAdjust2] + pfmul mm2,mm3 + + movq [UVLeft],mm5 + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + pfmul mm1,qword ptr[QFixedScaleLUT+ebx] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm0,mm5 + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq [UV16],mm5 + movq mm7,[UVAdjustL] + + psrlq mm5,[QShiftV] + paddd mm7,[UVL16] + + movq [UV16V],mm5 + movq [UVL16],mm7 + + +OnePixelSpanLit: + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU1Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU1Lit + +TryClampU1Lit: + cmp ebx,0 + jge NoClampU1Lit + mov dword ptr[UVL16+4],0 +NoClampU1Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV1Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV1Lit + +TryClampV1Lit: + cmp eax,0 + jge NoClampV1Lit + mov dword ptr[UVL16],0 + +NoClampV1Lit: + mov ebx,dword ptr[UV16+4] + mov eax,dword ptr[UV16V] + + mov esi,GBitPtr + shr ebx,16 + add esi,eax + add esi,ebx + mov ecx,TexPal + xor eax,eax + movq mm6,[ARL] + + mov eax,offset QDibCan + push ebp + + mov edi,dword ptr[eax+4] + mov ebp,dword ptr[Dest] + + movd mm3,dword ptr[ZiStepX] + xor eax,eax + +LeftoverLoopLit: + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + pf2id mm2,mm4 + + mov al,byte ptr[esi] + movq mm5,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + pfadd mm4,mm3 + + pand mm5,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrld mm2,16 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + movq [UV16],mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + movd eax,mm2 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + xor eax,0 + + mov ebx,dword ptr[UV16+4] + + psrlq mm5,[QShiftV] + + shr ebx,16 + + movq [UV16V],mm5 + add esi,ebx + + mov edx,dword ptr[UV16V] + pmullw mm7,mm6 + +; paddw mm6,mm3 no lerp for this... too much goin on + psrlw mm7,8 + + add esi,edx + cmp ax,word ptr[ebp] + jl SkipPixelLitZ + + packuswb mm7,mm7 + + movd [edi],mm7 + +SkipPixelLitZ: + + xor eax,eax + add edi,4 + add ebp,2 + + dec [RemainingCount] + jge LeftoverLoopLit + + pop ebp + +ReturnLit: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawSpan32_AsmGouraudZBuffer3DNow +endProc DrawSpan32_AsmGouraudZBuffer3DNow + + +;argb alpha (greyscale), affine, gouraud + +cProc DrawScanLineGouraudNoZAlphaARGB_Asm3DNow, 8, + + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov eax,[ebx].X + mov ecx,pRight + mov edx,[ecx].X + sub edx,eax + jle GouraudReturnNoZAlphaTex + + mov edi,[ebx].X +; inc edx + + femms + +; prefetch [GBitPtr] + + movd mm1,[ecx].vf + movd mm0,edx + + punpckldq mm1,qword ptr[ecx].uf + pi2fd mm0,mm0 + + movq mm7,[GBL] + movd mm2,[ebx].vf + + pfrcp mm0,mm0 + pfmul mm1,mm7 + + punpckldq mm2,qword ptr[ebx].uf + movd mm3,[ecx].bf + + pfmul mm2,mm7 + movq mm7,mm0 + + pfmul mm0,[QFixedScale] + pfsub mm1,mm2 + + punpckldq mm3,qword ptr[ecx].gf + pfmul mm1,mm0 + + movd mm4,[ecx].rf + + pfmul mm2,[QFixedScale] + pf2id mm1,mm1 + + movd mm5,[ebx].bf + pf2id mm2,mm2 + + punpckldq mm5,qword ptr[ebx].gf + pfmul mm7,[Q128] + + movd mm6,[ebx].rf + + pfsub mm3,mm5 + pfsub mm4,mm6 + + pfmul mm3,mm7 + pf2id mm5,mm5 + + pfmul mm4,mm7 + pf2id mm6,mm6 + + movq mm0,mm2 + pf2id mm4,mm4 + + pf2id mm3,mm3 + shl edi,2 + + pand mm0,[WrapMask] + packssdw mm3,mm4 + + movq [UV16],mm0 + packssdw mm5,mm6 + + mov ebx,dword ptr[UV16+4] + add edi,[Dest] + + psrlq mm0,[QShiftV] + psllw mm5,7 + + shr ebx,16 + mov esi,GBitPtr + + movq [UV16V],mm0 + add esi,ebx + + mov ecx,TexPal + mov eax,dword ptr[UV16V] + + add esi,eax + xor eax,eax + + push ebp + +GouraudLoopNoZAlphaTex: + mov al,byte ptr[esi] + movq mm0,mm2 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + +; sub esi,GBitPtr + paddd mm2,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + pand mm0,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + movq [UV16],mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + mov ebx,dword ptr[UV16+4] + movq mm4,mm7 + + psrlq mm0,[QShiftV] + psrlq mm4,48 + +; add esi,ABitPtr + movq mm6,mm4 + + shr ebx,16 + psllq mm6,16 + +; mov al,byte ptr[esi] + psllw mm7,1 + + por mm4,mm6 + movq [UV16V],mm0 + + mov esi,ebx + movd mm0,[edi] + + punpckldq mm4,mm4 +; mov ebx,ATexPal + + mov ebp,dword ptr[UV16V] + pmulhw mm7,mm5 + +; movd mm4,[ebx+eax*4] + add esi,ebp + + punpcklbw mm0,[Zero] + + movq mm6,[QNegAlpha] + + punpcklbw mm4,[Zero] + + add esi,GBitPtr + + pmullw mm7,mm4 + psubw mm6,mm4 + + paddw mm5,mm3 + pmullw mm0,mm6 + + add edi,4 + paddw mm0,mm7 + + psrlw mm0,8 + + packuswb mm0,mm0 + + movd [edi-4],mm0 + + dec edx + jge GouraudLoopNoZAlphaTex + + pop ebp + + femms + +GouraudReturnNoZAlphaTex: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawScanLineGouraudNoZAlphaARGB_Asm3DNow +endProc DrawScanLineGouraudNoZAlphaARGB_Asm3DNow + + + +;perspective correct, zbuffered, argb alpha, gouraud +;mean nasty function + +cProc DrawSpan32_AsmGouraudZBufferAlphaARGB3DNow, 36, + + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + dec ecx + sub ecx,eax + jle ReturnLit + +; femms + +; inc ecx + mov ebx,offset ClientWindow + mov eax, y + mov edi,[ebx].Buffer + mov esi,x1 + imul eax, [ebx].PixelPitch + shl esi,2 + mov edx,ZBuffer + add eax,esi + add edi, eax + shr eax,1 + add edx,eax + mov [Dest],edx + mov eax,offset QZCan + mov ebx,offset SCan + mov [eax],ebx + mov [eax+4],edx + mov eax,offset QDibCan + mov [eax],ebx + mov [eax+4],edi + mov ebx,offset QDibCan + mov eax,offset QDibOrCan + mov [eax],ebx + mov [eax+4],ebx + mov ebx,offset QZCan + mov eax,offset QZOrCan + mov [eax],ebx + mov [eax+4],ebx + mov edx,ecx + mov eax,ecx + + shr ecx,4 + and eax,15 + jnz @f + dec ecx + mov eax,16 +@@: + + mov [NumASpans],ecx + mov [RemainingCount],eax + + ;grab the left side lights + movd mm5,r1 + movd mm4,b1 + +; punpckldq mm5,qword ptr[Zero] + movd mm6,g1 + + pf2id mm5,mm5 + punpckldq mm4,mm6 + + pf2id mm4,mm4 + packssdw mm4,mm5 + +; psllw mm4,7 + + movq [ARL],mm4 + + ; mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 + movd mm0,x1 ; |x | | | | | | | + movq mm2,[UVDivZStepX] ; |x | UZdX|VZdX | | | | | + + movd mm1,y ; |x |y UZdX|VZdX | | | | | + movq mm3,[UVDivZStepY] ; |x |y UZdX|VZdXUZdY|VZdY | | | | + + punpckldq mm0,mm0 ; x|x |y UZdX|VZdXUZdY|VZdY | | | | + punpckldq mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | | | | + + movd mm7,edx ; x|x y|y UZdX|VZdXUZdY|VZdY | | | |wid + movd mm5,b2 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + + pi2fd mm0,mm0 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + movd mm6,b1 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + + pi2fd mm7,mm7 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + punpckldq mm5,qword ptr[g2] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + + pi2fd mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + punpckldq mm6,qword ptr[g1] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b g|b |wid + + pfmul mm2,mm0 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b |wid + pfrcp mm7,mm7 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b dw|dw + + pfsub mm5,mm6 ; x|x y|y UZX|VZX UZdY|VZdY | gd|bd g|b dw|dw + movd mm4,[r1] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|b dw|dw + + movd mm6,[r2] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|r dw|dw + pfmul mm3,mm1 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd g|r dw|dw + + pfsub mm6,mm4 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd dw|dw + pfmul mm7,[Q128] ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd DW|DW + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZY|VZY |ZdX gd|bd x|rd DW|DW + + punpckldq mm4,mm4 + pfmul mm4,[QZBufferPrec] + pf2id mm4,mm4 + movq [QZDelta],mm4 + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZdY|VZdY |ZdX | | | + pfmul mm5,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZdX GD|BD x|rd DW|DW + + pfmul mm4,mm0 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|rd DW|DW + pfmul mm6,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|RD DW|DW + + pf2id mm5,mm5 + pf2id mm6,mm6 + + packssdw mm5,mm6 + movq [RGBADelta],mm5 + + movd mm5,[ZiStepY] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY x|RD DW|DW + movq mm6,[UVDivZOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY UZO|VZO DW|DW + + pfmul mm5,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO DW|DW + movd mm7,[ZiOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO |ZO + + pfadd mm6,mm2 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZXS|VZXS |ZO + pfadd mm4,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZXS|VZXS |ZO + + pfadd mm6,mm3 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZ|VZ |ZO + pfadd mm4,mm5 ; x|x y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZO + + movq mm7,mm4 + movq mm1,[QZDelta] + punpckldq mm7,mm7 + pfmul mm7,[QZBufferPrec] + pf2id mm7,mm7 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + paddd mm7,mm1 + movq [QZVal32_0],mm0 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + movq [QZVal32_1],mm0 + pslld mm1,2 + movd mm7,[Zi16StepX] + movq [QZDelta],mm1 + + pfrcp mm0,mm4 ; ZL|ZL y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + + movq mm1,mm6 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + pfadd mm4,mm7 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfmul mm1,mm0 ; ZL|ZL UL|VL UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + pfrcp mm2,mm4 ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfadd mm6,[UVDivZ16StepX] ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm2,mm6 ; ZL|ZL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + + movq mm0,mm1 ; UL|VL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + movq mm3,mm2 ; ULi|VLi UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + + pfmul mm0,[QFixedScale] ; UL6|VL6 UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm3,[QFixedScale] ; UL6|VL6 UL|VL UR6|UR6 UR6|UR6 |ZRi |ZY UZR|VZR |ZdX16 + + pf2id mm0,mm0 ;UL6i|VL6i UL|VL UR6|VR6 UR6|VR6 |ZRi |ZY UZR|VZR |ZdX16 + pf2id mm3,mm3 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR |ZdX16 + + + test ecx,ecx + jz HandleLeftoverPixelsLit + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm7,[QFixedScale] + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm7,[UVAdjustL] + movq [UVL16],mm7 + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + + cmp ebx,MaxU + jle TryClampU0Litp + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Litp + +TryClampU0Litp: + cmp ebx,0 + jge NoClampU0Litp + mov dword ptr[UVL16+4],0 +NoClampU0Litp: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Litp + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Litp + +TryClampV0Litp: + cmp eax,0 + jge NoClampV0Litp + mov dword ptr[UVL16],0 + +NoClampV0Litp: + + pfrcp mm5,mm4 + +SpanLoopLit: + ;use float uv for lightmap uv + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfmul mm7,mm2 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm5,[QFixedScale] + + pfmul mm7,[QFixedScale] + pf2id mm5,mm5 + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust] + + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust2] + + movq [UVL16],mm7 + movq [UVLeft],mm5 + + movd mm7,[Zi16StepX] + movq mm0,mm5 + + pfmul mm1,[QFixedScale16] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + ;right side stuff becomes left ; ULw|VLw DU16|DV16 UL|VL URw|VRw |ZLi |ZY UZL|VZL | + pfadd mm4,mm7 ;ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZL|VZL | + + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm7,[UVAdjustL] + movq [UV16],mm5 + + pfadd mm6,[UVDivZ16StepX] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm7,[UVL16] + + psrlq mm5,[QShiftV] + movq [UVL16],mm7 + + movq [UV16V],mm5 + + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU0Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Lit + +TryClampU0Lit: + cmp ebx,0 + jge NoClampU0Lit + mov dword ptr[UVL16+4],0 +NoClampU0Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Lit + +TryClampV0Lit: + cmp eax,0 + jge NoClampV0Lit + mov dword ptr[UVL16],0 + +NoClampV0Lit: + movq [UVLeftW],mm3 + mov eax,dword ptr[UV16V] + mov ebx,dword ptr[UV16+4] + movq [ZIR],mm4 + mov esi,GBitPtr + shr ebx,16 + movq [UVZ],mm6 + add esi,eax + add esi,ebx + movq [UVLeft],mm2 + + mov ecx,TexPal + pfrcp mm5,mm4 +; movq mm3,[RGBADelta] + xor eax,eax + movq mm6,[ARL] + + push ebp + mov ebp,[Dest] + + ;grab zbuffer values + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + + pslld mm2,1 + movq [QZVal],mm2 + + + movq mm2,[QZVal] + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + pcmpgtw mm2,[ebp] + mov esi,GBitPtr + + psrlw mm2,15 + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + psllw mm2,2 + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movq [GBL],mm2 + psrlq mm4,[QShiftV] + + movq mm7,mm2 + movq [UV16V],mm4 + + punpcklwd mm7,[Zero] + movq [UVR],mm5 + + paddd mm7,[QZOrCan] + mov edx,dword ptr[UV16V] + + movq [QZOut],mm7 + mov ebx,dword ptr[UV16+4] + + movq mm7,mm2 + mov edi,dword ptr[QZOut] + + punpcklwd mm7,[Zero] + shr ebx,16 + + paddd mm7,[QDibOrCan] + mov edi,dword ptr[edi] + + movq [QDibOut],mm7 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + add esi,edx + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + xor eax,eax + movq mm3,mm7 + + pmullw mm7,mm6 + mov ax,word ptr[QZVal] + + psrlq mm3,48 + paddd mm0,mm1 + + mov word ptr[edi],ax + movq mm5,mm3 + + mov edi,dword ptr[QDibOut] + psllq mm5,16 + + add esi,ebx + por mm3,mm5 + + mov edi,dword ptr[edi] + punpckldq mm3,mm3 + paddw mm6,[RGBADelta] + + psrlw mm7,8 + + xor eax,eax + movq mm5,[QNegAlpha] + + pmullw mm7,mm3 + psubw mm5,mm3 + + movq mm3,[edi] + mov al,byte ptr[esi] + + punpcklbw mm3,[Zero] + movq mm4,mm0 + + pmullw mm3,mm5 + pand mm4,[WrapMask] + + paddw mm3,mm7 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + psrlw mm3,8 + movq [UV16],mm4 + + packuswb mm3,mm3 + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + movd [edi],mm3 + movq mm3,mm7 + + psrlq mm4,[QShiftV] + psrlq mm3,48 + + mov ebx,dword ptr[UV16+4] + movq mm5,mm3 + + movq [UV16V],mm4 + psllq mm5,16 + + pmullw mm7,mm6 + por mm3,mm5 + + mov edx,dword ptr[UV16V] + punpckldq mm3,mm3 + + mov edi,dword ptr[QZOut+4] + psrlw mm7,8 + + xor eax,eax + mov edi,dword ptr[edi] + + mov ax,word ptr[QZVal+2] + mov esi,GBitPtr + + movq mm5,[QNegAlpha] + pmullw mm7,mm3 + + mov word ptr[edi+2],ax + xor eax,eax + + mov edi,dword ptr[QDibOut+4] + shr ebx,16 + + mov edi,dword ptr[edi] + psubw mm5,mm3 + + paddw mm6,[RGBADelta] + add esi,ebx + + movq mm3,[edi+4] + add esi,edx + + punpcklbw mm3,[Zero] + mov al,byte ptr[esi] + + pmullw mm3,mm5 + paddd mm0,mm1 + + paddw mm3,mm7 + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + + psrlw mm3,8 + movq mm4,mm0 + + packuswb mm3,mm3 + pand mm4,[WrapMask] + + mov esi,GBitPtr + movd [edi+4],mm3 + + movq mm7,mm2 + movq [UV16],mm4 + + punpckhwd mm7,[Zero] + psrlq mm4,[QShiftV] + + paddd mm7,[QZorCan] + movq [UV16V],mm4 + + movq [QZOut],mm7 + mov ebx,dword ptr[UV16+4] + + movq mm7,mm2 + mov edi,dword ptr[QZOut] + + punpckhwd mm7,[Zero] + mov edi,dword ptr[edi] + + paddd mm7,[QDibOrCan] + paddd mm0,mm1 + + movq [QDibOut],mm7 + mov edx,dword ptr[UV16V] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + xor eax,0 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + mov ax,word ptr[QZVal+4] + + movq mm3,mm7 + pmullw mm7,mm6 + + psrlq mm3,48 + mov word ptr[edi+4],ax + + movq mm5,mm3 + psrlw mm7,8 + + psllq mm5,16 + mov edi,dword ptr[QDibOut] + + por mm3,mm5 + paddw mm6,[RGBADelta] + + punpckldq mm3,mm3 + mov edi,dword ptr[edi] + + movq mm5,[QNegAlpha] + + pmullw mm7,mm3 + psubw mm5,mm3 + + movq mm3,[edi+8] + movq mm4,mm0 + + punpcklbw mm3,[Zero] + shr ebx,16 + + pmullw mm3,mm5 + xor eax,eax + + paddw mm3,mm7 + pand mm4,[WrapMask] + + psrlw mm3,8 + add esi,edx + + packuswb mm3,mm3 + paddd mm0,mm1 + + movd [edi+8],mm3 + add esi,ebx + + movq [UV16],mm4 + mov al,byte ptr[esi] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + movq mm3,mm7 + mov ebx,dword ptr[UV16+4] + + psrlq mm3,48 + mov edx,dword ptr[UV16V] + + movq mm5,mm3 + pmullw mm7,mm6 + + psllq mm5,16 + shr ebx,16 + + por mm3,mm5 + xor eax,eax + + paddw mm6,[RGBADelta] + punpckldq mm3,mm3 + + mov edi,dword ptr[QZOut+4] + psrlw mm7,8 + + movq mm5,[QNegAlpha] + mov esi,edx + + pmullw mm7,mm3 + add esi,GBitPtr + + mov edi,dword ptr[edi] + psubw mm5,mm3 + + mov ax,word ptr[QZVal+6] + add esi,ebx + + mov word ptr[edi+6],ax + mov edi,dword ptr[QDibOut+4] + + xor eax,eax + mov edi,dword ptr[edi] + + mov al,byte ptr[esi] + movq mm3,[edi+12] + + movq mm4,mm0 + punpcklbw mm3,[Zero] + + ;regrab z + movq mm2,[QZVal32_0] + pmullw mm3,mm5 + + paddd mm2,[QZDelta] + paddw mm3,mm7 + + movq mm7,[QZVal32_1] + psrlw mm3,8 + + paddd mm7,[QZDelta] + packuswb mm3,mm3 + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + movd [edi+12],mm3 + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + pand mm4,[WrapMask] + + pslld mm2,1 + movq [UV16],mm4 + + movq [QZVal],mm2 + mov esi,GBitPtr + + pcmpgtw mm2,[ebp+8] + psrlq mm4,[QShiftV] + + + psrlw mm2,15 + movq [UV16V],mm4 + + + psllw mm2,2 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + movq mm4,mm2 + mov ebx,dword ptr[UV16+4] + + punpcklwd mm4,[Zero] + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + + paddd mm4,[QZorCan] + movq mm3,mm7 + + pmullw mm7,mm6 + psrlq mm3,48 + + movq [QZOut],mm4 + movq mm5,mm3 + + xor eax,eax + psllq mm5,16 + + mov edi,dword ptr[QZOut] + movq mm4,mm2 + + mov edi,dword ptr[edi] + por mm3,mm5 + + mov ax,word ptr[QZVal] + punpckldq mm3,mm3 + + mov word ptr[edi+8],ax + psrlw mm7,8 + + paddw mm6,[RGBADelta] + punpcklwd mm4,[Zero] + + paddd mm4,[QDibOrCan] + pmullw mm7,mm3 + + movq mm5,[QNegAlpha] + paddd mm0,mm1 + + movq [QDibOut],mm4 + psubw mm5,mm3 + + mov edi,dword ptr[QDibOut] + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[edi] + movq mm4,mm0 + + movq mm3,[edi+16] + shr ebx,16 + + punpcklbw mm3,[Zero] + xor eax,eax + + pand mm4,[WrapMask] + pmullw mm3,mm5 + + add esi,edx + paddw mm3,mm7 + + paddd mm0,mm1 + psrlw mm3,8 + + add esi,ebx + packuswb mm3,mm3 + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd [edi+16],mm3 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + movq mm3,mm7 + mov ebx,dword ptr[UV16+4] + + psrlq mm3,48 + mov edx,dword ptr[UV16V] + + movq mm5,mm3 + mov edi,dword ptr[QZOut+4] + + pmullw mm7,mm6 + mov edi,dword ptr[edi] + + psllq mm5,16 + mov ax,word ptr[QZVal+2] + + shr ebx,16 + mov word ptr[edi+10],ax + + por mm3,mm5 + xor eax,eax + + mov edi,dword ptr[QDibOut+4] + psrlw mm7,8 + + punpckldq mm3,mm3 + mov esi,GBitPtr + mov edi,dword ptr[edi] + + movq mm5,[QNegAlpha] + pmullw mm7,mm3 + + psubw mm5,mm3 + movq mm3,[edi+20] + + punpcklbw mm3,[Zero] + paddw mm6,[RGBADelta] + + pmullw mm3,mm5 + add esi,edx + + paddw mm3,mm7 + xor eax,eax + + psrlw mm3,8 + movq mm4,mm0 + + packuswb mm3,mm3 + + pand mm4,[WrapMask] + movd [edi+20],mm3 + + movq [UV16],mm4 + + add esi,ebx + psrlq mm4,[QShiftV] + + movq [UV16V],mm4 + + mov al,byte ptr[esi] + + + mov esi,GBitPtr + + movq mm4,mm2 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + punpckhwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm3,mm7 + movq mm4,mm2 + + mov edi,dword ptr[QZOut] + punpckhwd mm4,[Zero] + + mov edi,dword ptr[edi] + mov ax,word ptr[QZVal+4] + psrlq mm3,48 + + mov word ptr[edi+12],ax + pmullw mm7,mm6 + + movq mm5,mm3 + xor eax,eax + + psllq mm5,16 + paddd mm4,[QDibOrCan] + + por mm3,mm5 + paddw mm6,[RGBADelta] + movq [QDibOut],mm4 + + punpckldq mm3,mm3 + psrlw mm7,8 + + mov edi,dword ptr[QDibOut] + movq mm5,[QNegAlpha] + + pmullw mm7,mm3 + mov edi,dword ptr[edi] + + psubw mm5,mm3 + movq mm3,[edi+24] + + paddd mm0,mm1 + punpcklbw mm3,[Zero] + + pmullw mm3,mm5 + mov edx,dword ptr[UV16V] + + paddw mm3,mm7 + movq mm4,mm0 + + psrlw mm3,8 + shr ebx,16 + + packuswb mm3,mm3 + xor eax,eax + + pand mm4,[WrapMask] + movd [edi+24],mm3 + + add esi,edx + mov edi,dword ptr[QZOut+4] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + xor eax,eax + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ax,word ptr[QZVal+6] + movq mm3,mm7 + + mov ebx,dword ptr[UV16+4] + mov word ptr[edi+14],ax + + psrlq mm3,48 + mov edx,dword ptr[UV16V] + + movq mm5,mm3 + mov edi,dword ptr[QDibOut+4] + pmullw mm7,mm6 + + psllq mm5,16 + shr ebx,16 + + por mm3,mm5 + psrlw mm7,8 + + punpckldq mm3,mm3 + paddw mm6,[RGBADelta] + + movq mm5,[QNegAlpha] + pmullw mm7,mm3 + + mov edi,dword ptr[edi] + psubw mm5,mm3 + + + + movq mm3,[edi+28] + mov esi,GBitPtr + + punpcklbw mm3,[Zero] + add esi,edx + + pmullw mm3,mm5 + xor eax,eax + + paddw mm3,mm7 + add esi,ebx + + ;regrab z + movq mm2,[QZVal32_0] + psrlw mm3,8 + + movq mm4,[QZVal32_1] + packuswb mm3,mm3 + + paddd mm2,[QZDelta] + paddd mm4,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm4 + + psrld mm2,17 + psrld mm4,17 + + packssdw mm2,mm4 + xor eax,eax + + pslld mm2,1 + + + movq [QZVal],mm2 + + mov al,byte ptr[esi] + movq mm4,mm0 + + pand mm4,[WrapMask] + pcmpgtw mm2,[ebp+16] + + movd [edi+28],mm3 + movq [UV16],mm4 + + psrlw mm2,15 + mov esi,GBitPtr + + psrlq mm4,[QShiftV] + + psllw mm2,2 + movq [UV16V],mm4 + movq mm4,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + punpcklwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm3,mm7 + mov edi,dword ptr[QZOut] + + movq mm4,mm2 + mov edi,dword ptr[edi] + + psrlq mm3,48 + pmullw mm7,mm6 + + movq mm5,mm3 + xor eax,eax + + psllq mm5,16 + mov ax,word ptr[QZVal] + + por mm3,mm5 + punpcklwd mm4,[Zero] + mov word ptr[edi+16],ax + + punpckldq mm3,mm3 + paddw mm6,[RGBADelta] + + paddd mm4,[QDibOrCan] + psrlw mm7,8 + + movq [QDibOut],mm4 + movq mm5,[QNegAlpha] + + mov edi,dword ptr[QDibOut] + pmullw mm7,mm3 + + mov edi,dword ptr[edi] + psubw mm5,mm3 + mov edx,dword ptr[UV16V] + + movq mm3,[edi+32] + paddd mm0,mm1 + + punpcklbw mm3,[Zero] + shr ebx,16 + + pmullw mm3,mm5 + xor eax,eax + + paddw mm3,mm7 + add esi,edx + + psrlw mm3,8 + add esi,ebx + + movq mm4,mm0 + packuswb mm3,mm3 + + pand mm4,[WrapMask] + movd [edi+32],mm3 + + paddd mm0,mm1 + mov edi,dword ptr[QZOut+4] + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + movq mm3,mm7 + mov ebx,dword ptr[UV16+4] + + psrlq mm3,48 + mov edx,dword ptr[UV16V] + + movq mm5,mm3 + mov edi,dword ptr[edi] + + pmullw mm7,mm6 + mov ax,word ptr[QZVal+2] + + psllq mm5,16 + mov word ptr[edi+18],ax + + psrlw mm7,8 + mov edi,dword ptr[QDibOut+4] + + por mm3,mm5 + paddw mm6,[RGBADelta] + + punpckldq mm3,mm3 + mov edi,dword ptr[edi] + + shr ebx,16 + movq mm5,[QNegAlpha] + + pmullw mm7,mm3 + psubw mm5,mm3 + + movq mm3,[edi+36] + mov esi,GBitPtr + + punpcklbw mm3,[Zero] + add esi,edx + + pmullw mm3,mm5 + xor eax,eax + + paddw mm3,mm7 + movq mm4,mm0 + + psrlw mm3,8 + pand mm4,[WrapMask] + + packuswb mm3,mm3 + movq [UV16],mm4 + + add esi,ebx + psrlq mm4,[QShiftV] + + xor eax,eax + movq [UV16V],mm4 + + mov al,byte ptr[esi] + + mov esi,GBitPtr + movd [edi+36],mm3 + + movq mm4,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + punpckhwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm3,mm7 + movq mm4,mm2 + + mov edi,dword ptr[QZOut] + psrlq mm3,48 + + mov ax,word ptr[QZVal+4] + pmullw mm7,mm6 + + mov edi,dword ptr[edi] + movq mm5,mm3 + + punpckhwd mm4,[Zero] + mov word ptr[edi+20],ax + xor eax,eax + + paddd mm4,[QDibOrCan] + psllq mm5,16 + + movq [QDibOut],mm4 + por mm3,mm5 + + mov edi,dword ptr[QDibOut] + paddw mm6,[RGBADelta] + + punpckldq mm3,mm3 + + mov edi,dword ptr[edi] + psrlw mm7,8 + + movq mm5,[QNegAlpha] + pmullw mm7,mm3 + + mov edx,dword ptr[UV16V] + psubw mm5,mm3 + + movq mm3,[edi+40] + paddd mm0,mm1 + + punpcklbw mm3,[Zero] + movq mm4,mm0 + + pmullw mm3,mm5 + shr ebx,16 + + paddw mm3,mm7 + add esi,edx + + psrlw mm3,8 + add esi,ebx + + packuswb mm3,mm3 + xor eax,eax + + movd [edi+40],mm3 + paddd mm0,mm1 + + pand mm4,[WrapMask] + mov al,byte ptr[esi] + + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + movq [UV16V],mm4 + movq mm3,mm7 + + mov ebx,dword ptr[UV16+4] + psrlq mm3,48 + + mov edx,dword ptr[UV16V] + movq mm5,mm3 + + mov edi,dword ptr[QZOut+4] + pmullw mm7,mm6 + + mov edi,dword ptr[edi] + psllq mm5,16 + + mov ax,word ptr[QZVal+6] + psrlw mm7,8 + + mov word ptr[edi+22],ax + por mm3,mm5 + + mov edi,dword ptr[QDibOut+4] + shr ebx,16 + + punpckldq mm3,mm3 + paddw mm6,[RGBADelta] + + movq mm5,[QNegAlpha] + mov edi,dword ptr[edi] + + pmullw mm7,mm3 + psubw mm5,mm3 + + movq mm3,[edi+44] + mov esi,GBitPtr + + punpcklbw mm3,[Zero] + add esi,ebx + + pmullw mm3,mm5 + add esi,edx + + paddw mm3,mm7 + xor eax,eax + + ;regrab z + movq mm2,[QZVal32_0] + psrlw mm3,8 + + movq mm4,[QZVal32_1] + packuswb mm3,mm3 + + paddd mm2,[QZDelta] + paddd mm4,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm4 + + psrld mm2,17 + psrld mm4,17 + + packssdw mm2,mm4 + xor eax,eax + + pslld mm2,1 + + + movq [QZVal],mm2 + + mov al,byte ptr[esi] + movq mm4,mm0 + + pand mm4,[WrapMask] + pcmpgtw mm2,[ebp+24] + + movd [edi+44],mm3 + movq [UV16],mm4 + + psrlw mm2,15 + mov esi,GBitPtr + + psrlq mm4,[QShiftV] + + psllw mm2,2 + movq [UV16V],mm4 + + movq mm4,mm2 + + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + punpcklwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + movq [QZOut],mm4 + movq mm3,mm7 + + mov edi,dword ptr[QZOut] + movq mm4,mm2 + + mov ax,word ptr[QZVal] + psrlq mm3,48 + + mov edi,dword ptr[edi] + pmullw mm7,mm6 + + mov word ptr[edi+24],ax + movq mm5,mm3 + + punpcklwd mm4,[Zero] + xor eax,eax + + paddd mm4,[QDibOrCan] + psllq mm5,16 + + movq [QDibOut],mm4 + por mm3,mm5 + + paddw mm6,[RGBADelta] + punpckldq mm3,mm3 + + mov edi,dword ptr[QDibOut] + psrlw mm7,8 + + movq mm5,[QNegAlpha] + pmullw mm7,mm3 + + mov edi,dword ptr[edi] + psubw mm5,mm3 + + movq mm3,[edi+48] + paddd mm0,mm1 + + punpcklbw mm3,[Zero] + movq mm4,mm0 + + pmullw mm3,mm5 + shr ebx,16 + + mov edx,dword ptr[UV16V] + paddw mm3,mm7 + + pand mm4,[WrapMask] + psrlw mm3,8 + + movq [UV16],mm4 + packuswb mm3,mm3 + + xor eax,eax + add esi,edx + + movd [edi+48],mm3 + paddd mm0,mm1 + + add esi,ebx + mov al,byte ptr[esi] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + movq [UV16V],mm4 + movq mm3,mm7 + + mov ebx,dword ptr[UV16+4] + psrlq mm3,48 + + mov edx,dword ptr[UV16V] + movq mm5,mm3 + + mov edi,dword ptr[QZOut+4] + pmullw mm7,mm6 + + mov ax,word ptr[QZVal+2] + psllq mm5,16 + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov word ptr[edi+26],ax + por mm3,mm5 + + mov edi,dword ptr[QDibOut+4] + shr ebx,16 + + punpckldq mm3,mm3 + paddw mm6,[RGBADelta] + + movq mm5,[QNegAlpha] + pmullw mm7,mm3 + + mov edi,dword ptr[edi] + psubw mm5,mm3 + + movq mm3,[edi+52] + mov esi,GBitPtr + + punpcklbw mm3,[Zero] + movq mm4,mm0 + + pmullw mm3,mm5 + add esi,edx + + paddw mm3,mm7 + xor eax,eax + + pand mm4,[WrapMask] + psrlw mm3,8 + + movq [UV16],mm4 + packuswb mm3,mm3 + + psrlq mm4,[QShiftV] + add esi,ebx + + movq [UV16V],mm4 + xor eax,eax + + + movd [edi+52],mm3 + mov al,byte ptr[esi] + + mov esi,GBitPtr + movq mm4,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + punpckhwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + movq mm3,mm7 + + mov edi,dword ptr[QZOut] + movq mm4,mm2 + + mov ax,word ptr[QZVal+4] + psrlq mm3,48 + + mov edi,dword ptr[edi] + pmullw mm7,mm6 + + mov word ptr[edi+28],ax + movq mm5,mm3 + + xor eax,eax + psllq mm5,16 + + punpckhwd mm4,[Zero] + psrlw mm7,8 + + paddd mm4,[QDibOrCan] + por mm3,mm5 + + paddw mm6,[RGBADelta] + punpckldq mm3,mm3 + + movq mm5,[QNegAlpha] + pmullw mm7,mm3 + + movq [QDibOut],mm4 + psubw mm5,mm3 + + mov edi,dword ptr[QDibOut] + paddd mm0,mm1 + + mov edi,dword ptr[edi] + movq mm4,mm0 + + movq mm3,[edi+56] + shr ebx,16 + + punpcklbw mm3,[Zero] + + mov edx,dword ptr[UV16V] + pmullw mm3,mm5 + + pand mm4,[WrapMask] + paddw mm3,mm7 + + add esi,edx + psrlw mm3,8 + + add esi,ebx + packuswb mm3,mm3 + + paddd mm0,mm1 + mov al,byte ptr[esi] + + movd [edi+56],mm3 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + xor eax,eax + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + mov edi,dword ptr[QZOut+4] + + mov ax,word ptr[QZVal+6] + movq mm3,mm7 + + mov edi,dword ptr[edi] + pmullw mm7,mm6 + + mov word ptr[edi+30],ax + psrlq mm3,48 + + mov edi,dword ptr[QDibOut+4] + movq mm5,mm3 + + paddw mm6,[RGBADelta] + psllq mm5,16 + + mov edi,dword ptr[edi] + psrlw mm7,8 + + movq [ARL],mm6 + por mm3,mm5 + + pop ebp + punpckldq mm3,mm3 + + movq mm5,[QNegAlpha] + + pmullw mm7,mm3 + psubw mm5,mm3 + + ;regrab z + movq mm2,[QZVal32_0] + movq mm3,[edi+60] + + movq mm4,[QZVal32_1] + punpcklbw mm3,[Zero] + + paddd mm2,[QZDelta] + pmullw mm3,mm5 + + paddd mm4,[QZDelta] + paddw mm3,mm7 + + movq [QZVal32_0],mm2 + psrlw mm3,8 + + movq [QZVal32_1],mm4 + packuswb mm3,mm3 + + movd [edi+60],mm3 + + ; get corrected right side deltas ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm4,[ZIR] + movq mm6,[UVZ] + + movq mm2,[UVR] + movq mm0,[UVLeftW] ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm1,[UVLeft] ; ULw|VLw UL|VL argb|ARGBagAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + punpckldq mm2,mm2 ; ULw|VLw UL|VL ZRi|ZRi agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + pfmul mm2,mm6 ; ULw|VLw UL|VL UR|VR agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + mov eax,offset QZCan + add dword ptr[Dest],32 + + add dword ptr[eax+4],32 + mov eax,offset QDibCan + + add dword ptr[eax+4],64 + + movq mm3,mm2 + pfmul mm3,[QFixedScale] + + pf2id mm3,mm3 + + dec [NumASpans] ; dec num affine spans + jnz SpanLoopLit + +HandleLeftoverPixelsLit: + + + mov esi,GBitPtr + + + cmp [RemainingCount],0 + jz ReturnLit + + mov eax,[RemainingCount] + mov dword ptr[ZIR],eax + mov dword ptr[ZIR+4],eax + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfsub mm6,[UVDivZ16StepX] + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + + pfmul mm5,[QFixedScale] + pi2fd mm3,[ZIR] + + pfmul mm7,[QFixedScale] + pfmul mm3,[UVDivZStepX] + + pf2id mm5,mm5 + pfadd mm3,mm6 + + pi2fd mm2,[ZIR] + movd mm6,[Zi16StepX] + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + pfsub mm4,mm6 + + movd mm6,[ZiStepX] + mov ebx,[RemainingCount] + + pfmul mm2,mm6 + + shl ebx,3 + + pfadd mm2,mm4 + paddd mm5,[UVAdjust] + + punpckldq mm4,mm4 + + movq [UVL16],mm7 + pfrcp mm2,mm2 + + pfmul mm4,[QZBufferPrec] + + paddd mm5,[UVAdjust2] + pfmul mm2,mm3 + + movq [UVLeft],mm5 + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + pfmul mm1,qword ptr[QFixedScaleLUT+ebx] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm0,mm5 + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq [UV16],mm5 + movq mm7,[UVAdjustL] + + psrlq mm5,[QShiftV] + paddd mm7,[UVL16] + + movq [UV16V],mm5 + movq [UVL16],mm7 + + +OnePixelSpanLit: + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU1Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU1Lit + +TryClampU1Lit: + cmp ebx,0 + jge NoClampU1Lit + mov dword ptr[UVL16+4],0 +NoClampU1Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV1Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV1Lit + +TryClampV1Lit: + cmp eax,0 + jge NoClampV1Lit + mov dword ptr[UVL16],0 + +NoClampV1Lit: + mov ebx,dword ptr[UV16+4] + mov eax,dword ptr[UV16V] + + mov esi,GBitPtr + shr ebx,16 + add esi,eax + add esi,ebx + mov ecx,TexPal + xor eax,eax + movq mm6,[ARL] + + mov eax,offset QDibCan + push ebp + + mov edi,dword ptr[eax+4] + mov ebp,dword ptr[Dest] + + movq [UVZ],mm1 ;using this for a step temp + + movd mm3,dword ptr[ZiStepX] + xor eax,eax + +LeftoverLoopLit: + paddd mm0,[UVZ] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + pf2id mm2,mm4 + + mov al,byte ptr[esi] + movq mm5,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + pfadd mm4,mm3 + + pand mm5,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrld mm2,16 + + movq [UV16],mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + psrlq mm5,[QShiftV] + movd eax,mm2 + + movq [UV16V],mm5 + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + xor eax,0 + movq mm5,mm7 + + mov ebx,dword ptr[UV16+4] + psrlq mm5,48 + + shr ebx,16 + movq mm1,mm5 + + add esi,ebx + psllq mm1,16 + + mov edx,dword ptr[UV16V] + por mm5,mm1 + + pmullw mm7,mm6 + punpckldq mm5,mm5 + + psrlw mm7,8 + movq mm1,[QNegAlpha] + + pmullw mm7,mm5 + psubw mm1,mm5 + + movq mm5,[edi] + paddw mm6,[RGBADelta] + + punpcklbw mm5,[Zero] + add esi,edx + + pmullw mm5,mm1 + cmp ax,word ptr[ebp] + jl SkipPixelLitZ + + paddw mm5,mm7 + psrlw mm5,8 + packuswb mm5,mm5 + + movd [edi],mm5 + +SkipPixelLitZ: + + xor eax,eax + add edi,4 + add ebp,2 + + dec [RemainingCount] + jge LeftoverLoopLit + + pop ebp + +ReturnLit: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawSpan32_AsmGouraudZBufferAlphaARGB3DNow +endProc DrawSpan32_AsmGouraudZBufferAlphaARGB3DNow + + + +; non interpolated alpha at the verts + +cProc DrawSpan32_AsmGouraudZBufferVertexAlpha3DNow, 36, + + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + dec ecx + sub ecx,eax + jle ReturnLit + +; femms + +; inc ecx + mov ebx,offset ClientWindow + mov eax, y + mov edi,[ebx].Buffer + mov esi,x1 + imul eax, [ebx].PixelPitch + shl esi,2 + mov edx,ZBuffer + add eax,esi + add edi, eax + shr eax,1 + add edx,eax + mov [Dest],edx + mov eax,offset QZCan + mov ebx,offset SCan + mov [eax],ebx + mov [eax+4],edx + mov eax,offset QDibCan + mov [eax],ebx + mov [eax+4],edi + mov ebx,offset QDibCan + mov eax,offset QDibOrCan + mov [eax],ebx + mov [eax+4],ebx + mov ebx,offset QZCan + mov eax,offset QZOrCan + mov [eax],ebx + mov [eax+4],ebx + mov edx,ecx + mov eax,ecx + + shr ecx,4 + and eax,15 + jnz @f + dec ecx + mov eax,16 +@@: + + mov [NumASpans],ecx + mov [RemainingCount],eax + + ;grab the left side lights + movd mm5,r1 + movd mm4,b1 + +; punpckldq mm5,qword ptr[Zero] + movd mm6,g1 + + pf2id mm5,mm5 + punpckldq mm4,mm6 + + pf2id mm4,mm4 + packssdw mm4,mm5 + +; psllw mm4,7 + + movq [ARL],mm4 + + ; mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 + movd mm0,x1 ; |x | | | | | | | + movq mm2,[UVDivZStepX] ; |x | UZdX|VZdX | | | | | + + movd mm1,y ; |x |y UZdX|VZdX | | | | | + movq mm3,[UVDivZStepY] ; |x |y UZdX|VZdXUZdY|VZdY | | | | + + punpckldq mm0,mm0 ; x|x |y UZdX|VZdXUZdY|VZdY | | | | + punpckldq mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | | | | + + movd mm7,edx ; x|x y|y UZdX|VZdXUZdY|VZdY | | | |wid + movd mm5,b2 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + + pi2fd mm0,mm0 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b | |wid + movd mm6,b1 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + + pi2fd mm7,mm7 ; x|x y|y UZdX|VZdXUZdY|VZdY | |b |b |wid + punpckldq mm5,qword ptr[g2] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + + pi2fd mm1,mm1 ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b |b |wid + punpckldq mm6,qword ptr[g1] ; x|x y|y UZdX|VZdXUZdY|VZdY | g|b g|b |wid + + pfmul mm2,mm0 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b |wid + pfrcp mm7,mm7 ; x|x y|y UZX|VZX UZdY|VZdY | g|b g|b dw|dw + + pfsub mm5,mm6 ; x|x y|y UZX|VZX UZdY|VZdY | gd|bd g|b dw|dw + movd mm4,[r1] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|b dw|dw + + movd mm6,[r2] ; x|x y|y UZX|VZX UZdY|VZdY |r gd|bd g|r dw|dw + pfmul mm3,mm1 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd g|r dw|dw + + pfsub mm6,mm4 ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd dw|dw + pfmul mm7,[Q128] ; x|x y|y UZX|VZX UZY|VZY |r gd|bd x|rd DW|DW + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZY|VZY |ZdX gd|bd x|rd DW|DW + + punpckldq mm4,mm4 + pfmul mm4,[QZBufferPrec] + pf2id mm4,mm4 + movq [QZDelta],mm4 + + movd mm4,[ZiStepX] ; x|x y|y UZX|VZX UZdY|VZdY |ZdX | | | + pfmul mm5,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZdX GD|BD x|rd DW|DW + + pfmul mm4,mm0 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|rd DW|DW + pfmul mm6,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZX GD|BD x|RD DW|DW + + pf2id mm5,mm5 + pf2id mm6,mm6 + + packssdw mm5,mm6 + movq [RGBADelta],mm5 + + movd mm5,[ZiStepY] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY x|RD DW|DW + movq mm6,[UVDivZOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZdY UZO|VZO DW|DW + + pfmul mm5,mm1 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO DW|DW + movd mm7,[ZiOrigin] ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZO|VZO |ZO + + pfadd mm6,mm2 ; x|x y|y UZX|VZX UZY|VZY |ZX |ZY UZXS|VZXS |ZO + pfadd mm4,mm7 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZXS|VZXS |ZO + + pfadd mm6,mm3 ; x|x y|y UZX|VZX UZY|VZY |ZXS |ZY UZ|VZ |ZO + pfadd mm4,mm5 ; x|x y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZO + + movq mm7,mm4 + movq mm1,[QZDelta] + punpckldq mm7,mm7 + pfmul mm7,[QZBufferPrec] + pf2id mm7,mm7 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + paddd mm7,mm1 + movq [QZVal32_0],mm0 + movq mm0,mm7 + paddd mm7,mm1 + punpckldq mm0,mm7 + movq [QZVal32_1],mm0 + pslld mm1,2 + movd mm7,[Zi16StepX] + movq [QZDelta],mm1 + + pfrcp mm0,mm4 ; ZL|ZL y|y UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + + movq mm1,mm6 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |Zi |ZY UZ|VZ |ZdX16 + pfadd mm4,mm7 ; ZL|ZL UZ|VZ UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfmul mm1,mm0 ; ZL|ZL UL|VL UZX|VZX UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + pfrcp mm2,mm4 ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZ|VZ |ZdX16 + + pfadd mm6,[UVDivZ16StepX] ; ZL|ZL UL|VL ZR|ZR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm2,mm6 ; ZL|ZL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + + movq mm0,mm1 ; UL|VL UL|VL UR|VR UZY|VZY |ZRi |ZY UZR|VZR |ZdX16 + movq mm3,mm2 ; ULi|VLi UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + + pfmul mm0,[QFixedScale] ; UL6|VL6 UL|VL UR|UR UR|UR |ZRi |ZY UZR|VZR |ZdX16 + pfmul mm3,[QFixedScale] ; UL6|VL6 UL|VL UR6|UR6 UR6|UR6 |ZRi |ZY UZR|VZR |ZdX16 + + pf2id mm0,mm0 ;UL6i|VL6i UL|VL UR6|VR6 UR6|VR6 |ZRi |ZY UZR|VZR |ZdX16 + pf2id mm3,mm3 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR |ZdX16 + + + test ecx,ecx + jz HandleLeftoverPixelsLit + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm7,[QFixedScale] + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm7,[UVAdjustL] + movq [UVL16],mm7 + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + + cmp ebx,MaxU + jle TryClampU0Litp + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Litp + +TryClampU0Litp: + cmp ebx,0 + jge NoClampU0Litp + mov dword ptr[UVL16+4],0 +NoClampU0Litp: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Litp + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Litp + +TryClampV0Litp: + cmp eax,0 + jge NoClampV0Litp + mov dword ptr[UVL16],0 + +NoClampV0Litp: + + pfrcp mm5,mm4 + +SpanLoopLit: + ;use float uv for lightmap uv + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfmul mm7,mm2 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + pfmul mm5,[QFixedScale] + + pfmul mm7,[QFixedScale] + pf2id mm5,mm5 + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust] + + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + paddd mm5,[UVAdjust2] + + movq [UVL16],mm7 + movq [UVLeft],mm5 + + movd mm7,[Zi16StepX] + movq mm0,mm5 + + pfmul mm1,[QFixedScale16] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + ;right side stuff becomes left ; ULw|VLw DU16|DV16 UL|VL URw|VRw |ZLi |ZY UZL|VZL | + pfadd mm4,mm7 ;ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZL|VZL | + + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm7,[UVAdjustL] + movq [UV16],mm5 + + pfadd mm6,[UVDivZ16StepX] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + paddd mm7,[UVL16] + + psrlq mm5,[QShiftV] + movq [UVL16],mm7 + + movq [UV16V],mm5 + + + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU0Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU0Lit + +TryClampU0Lit: + cmp ebx,0 + jge NoClampU0Lit + mov dword ptr[UVL16+4],0 +NoClampU0Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV0Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV0Lit + +TryClampV0Lit: + cmp eax,0 + jge NoClampV0Lit + mov dword ptr[UVL16],0 + +NoClampV0Lit: + movq [UVLeftW],mm3 + mov eax,dword ptr[UV16V] + mov ebx,dword ptr[UV16+4] + movq [ZIR],mm4 + mov esi,GBitPtr + shr ebx,16 + movq [UVZ],mm6 + add esi,eax + add esi,ebx + movq [UVLeft],mm2 + + mov ecx,TexPal + pfrcp mm5,mm4 +; movq mm3,[RGBADelta] + xor eax,eax + movq mm6,[ARL] + + push ebp + mov ebp,[Dest] + + ;grab zbuffer values + movq mm2,[QZVal32_0] + movq mm7,[QZVal32_1] + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + + pslld mm2,1 + movq [QZVal],mm2 + + + movq mm2,[QZVal] + paddd mm0,mm1 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + + mov al,byte ptr[esi] + movq mm4,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + pcmpgtw mm2,[ebp] + mov esi,GBitPtr + + psrlw mm2,15 + pand mm4,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + psllw mm2,2 + movq [UV16],mm4 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + + movq [GBL],mm2 + psrlq mm4,[QShiftV] + + movq mm7,mm2 + movq [UV16V],mm4 + + punpcklwd mm7,[Zero] + movq [UVR],mm5 + + paddd mm7,[QZOrCan] + mov edx,dword ptr[UV16V] + + movq [QZOut],mm7 + mov ebx,dword ptr[UV16+4] + + movq mm7,mm2 + mov edi,dword ptr[QZOut] + + punpcklwd mm7,[Zero] + shr ebx,16 + + paddd mm7,[QDibOrCan] + mov edi,dword ptr[edi] + + movq [QDibOut],mm7 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + add esi,edx + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + xor eax,eax + + pmullw mm7,mm6 + mov ax,word ptr[QZVal] + + paddd mm0,mm1 + + mov word ptr[edi],ax + + mov edi,dword ptr[QDibOut] + + add esi,ebx + + mov edi,dword ptr[edi] + paddw mm6,[RGBADelta] + + psrlw mm7,8 + + xor eax,eax + movq mm5,[QNegAlpha] + + pmullw mm7,qword ptr[VertAlpha] + psubw mm5,qword ptr[VertAlpha] + + movq mm3,[edi] + mov al,byte ptr[esi] + + punpcklbw mm3,[Zero] + movq mm4,mm0 + + pmullw mm3,mm5 + pand mm4,[WrapMask] + + paddw mm3,mm7 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + + psrlw mm3,8 + movq [UV16],mm4 + + packuswb mm3,mm3 + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + movd [edi],mm3 + + psrlq mm4,[QShiftV] + + mov ebx,dword ptr[UV16+4] + + movq [UV16V],mm4 + + pmullw mm7,mm6 + + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[QZOut+4] + psrlw mm7,8 + + xor eax,eax + mov edi,dword ptr[edi] + + mov ax,word ptr[QZVal+2] + mov esi,GBitPtr + + movq mm5,[QNegAlpha] + pmullw mm7,qword ptr[VertAlpha] + + mov word ptr[edi+2],ax + xor eax,eax + + mov edi,dword ptr[QDibOut+4] + shr ebx,16 + + mov edi,dword ptr[edi] + psubw mm5,qword ptr[VertAlpha] + + paddw mm6,[RGBADelta] + add esi,ebx + + movq mm3,[edi+4] + add esi,edx + + punpcklbw mm3,[Zero] + mov al,byte ptr[esi] + + pmullw mm3,mm5 + paddd mm0,mm1 + + paddw mm3,mm7 + packuswb mm7,mm7 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw ARGB|ARGB UZR|VZR AR|GB + + psrlw mm3,8 + movq mm4,mm0 + + packuswb mm3,mm3 + pand mm4,[WrapMask] + + mov esi,GBitPtr + movd [edi+4],mm3 + + movq mm7,mm2 + movq [UV16],mm4 + + punpckhwd mm7,[Zero] + psrlq mm4,[QShiftV] + + paddd mm7,[QZorCan] + movq [UV16V],mm4 + + movq [QZOut],mm7 + mov ebx,dword ptr[UV16+4] + + movq mm7,mm2 + mov edi,dword ptr[QZOut] + + punpckhwd mm7,[Zero] + mov edi,dword ptr[edi] + + paddd mm7,[QDibOrCan] + paddd mm0,mm1 + + movq [QDibOut],mm7 + mov edx,dword ptr[UV16V] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + xor eax,0 + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + mov ax,word ptr[QZVal+4] + + pmullw mm7,mm6 + + mov word ptr[edi+4],ax + + psrlw mm7,8 + + mov edi,dword ptr[QDibOut] + + paddw mm6,[RGBADelta] + + mov edi,dword ptr[edi] + + movq mm5,[QNegAlpha] + + pmullw mm7,qword ptr[VertAlpha] + psubw mm5,qword ptr[VertAlpha] + + movq mm3,[edi+8] + movq mm4,mm0 + + punpcklbw mm3,[Zero] + shr ebx,16 + + pmullw mm3,mm5 + xor eax,eax + + paddw mm3,mm7 + pand mm4,[WrapMask] + + psrlw mm3,8 + add esi,edx + + packuswb mm3,mm3 + paddd mm0,mm1 + + movd [edi+8],mm3 + add esi,ebx + + movq [UV16],mm4 + mov al,byte ptr[esi] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + shr ebx,16 + + xor eax,eax + + paddw mm6,[RGBADelta] + + mov edi,dword ptr[QZOut+4] + psrlw mm7,8 + + movq mm5,[QNegAlpha] + mov esi,edx + + pmullw mm7,qword ptr[VertAlpha] + add esi,GBitPtr + + mov edi,dword ptr[edi] + psubw mm5,qword ptr[VertAlpha] + + mov ax,word ptr[QZVal+6] + add esi,ebx + + mov word ptr[edi+6],ax + mov edi,dword ptr[QDibOut+4] + + xor eax,eax + mov edi,dword ptr[edi] + + mov al,byte ptr[esi] + movq mm3,[edi+12] + + movq mm4,mm0 + punpcklbw mm3,[Zero] + + ;regrab z + movq mm2,[QZVal32_0] + pmullw mm3,mm5 + + paddd mm2,[QZDelta] + paddw mm3,mm7 + + movq mm7,[QZVal32_1] + psrlw mm3,8 + + paddd mm7,[QZDelta] + packuswb mm3,mm3 + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm7 + + movd [edi+12],mm3 + + psrld mm2,17 + psrld mm7,17 + + packssdw mm2,mm7 + pand mm4,[WrapMask] + + pslld mm2,1 + movq [UV16],mm4 + + movq [QZVal],mm2 + mov esi,GBitPtr + + pcmpgtw mm2,[ebp+8] + psrlq mm4,[QShiftV] + + + psrlw mm2,15 + movq [UV16V],mm4 + + + psllw mm2,2 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + movq mm4,mm2 + mov ebx,dword ptr[UV16+4] + + punpcklwd mm4,[Zero] + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + + paddd mm4,[QZorCan] + + pmullw mm7,mm6 + + movq [QZOut],mm4 + + xor eax,eax + + mov edi,dword ptr[QZOut] + movq mm4,mm2 + + mov edi,dword ptr[edi] + + mov ax,word ptr[QZVal] + + mov word ptr[edi+8],ax + psrlw mm7,8 + + paddw mm6,[RGBADelta] + punpcklwd mm4,[Zero] + + paddd mm4,[QDibOrCan] + pmullw mm7,qword ptr[VertAlpha] + + movq mm5,[QNegAlpha] + paddd mm0,mm1 + + movq [QDibOut],mm4 + psubw mm5,qword ptr[VertAlpha] + + mov edi,dword ptr[QDibOut] + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[edi] + movq mm4,mm0 + + movq mm3,[edi+16] + shr ebx,16 + + punpcklbw mm3,[Zero] + xor eax,eax + + pand mm4,[WrapMask] + pmullw mm3,mm5 + + add esi,edx + paddw mm3,mm7 + + paddd mm0,mm1 + psrlw mm3,8 + + add esi,ebx + packuswb mm3,mm3 + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd [edi+16],mm3 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[QZOut+4] + + pmullw mm7,mm6 + mov edi,dword ptr[edi] + + mov ax,word ptr[QZVal+2] + + shr ebx,16 + mov word ptr[edi+10],ax + + xor eax,eax + + mov edi,dword ptr[QDibOut+4] + psrlw mm7,8 + + mov esi,GBitPtr + mov edi,dword ptr[edi] + + movq mm5,[QNegAlpha] + pmullw mm7,qword ptr[VertAlpha] + + psubw mm5,qword ptr[VertAlpha] + movq mm3,[edi+20] + + punpcklbw mm3,[Zero] + paddw mm6,[RGBADelta] + + pmullw mm3,mm5 + add esi,edx + + paddw mm3,mm7 + xor eax,eax + + psrlw mm3,8 + movq mm4,mm0 + + packuswb mm3,mm3 + + pand mm4,[WrapMask] + movd [edi+20],mm3 + + movq [UV16],mm4 + + add esi,ebx + psrlq mm4,[QShiftV] + + movq [UV16V],mm4 + + mov al,byte ptr[esi] + + + mov esi,GBitPtr + + movq mm4,mm2 + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + punpckhwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm4,mm2 + + mov edi,dword ptr[QZOut] + punpckhwd mm4,[Zero] + + mov edi,dword ptr[edi] + mov ax,word ptr[QZVal+4] + + mov word ptr[edi+12],ax + pmullw mm7,mm6 + + xor eax,eax + + paddd mm4,[QDibOrCan] + + paddw mm6,[RGBADelta] + movq [QDibOut],mm4 + + psrlw mm7,8 + + mov edi,dword ptr[QDibOut] + movq mm5,[QNegAlpha] + + pmullw mm7,qword ptr[VertAlpha] + mov edi,dword ptr[edi] + + psubw mm5,qword ptr[VertAlpha] + movq mm3,[edi+24] + + paddd mm0,mm1 + punpcklbw mm3,[Zero] + + pmullw mm3,mm5 + mov edx,dword ptr[UV16V] + + paddw mm3,mm7 + movq mm4,mm0 + + psrlw mm3,8 + shr ebx,16 + + packuswb mm3,mm3 + xor eax,eax + + pand mm4,[WrapMask] + movd [edi+24],mm3 + + add esi,edx + mov edi,dword ptr[QZOut+4] + + paddd mm0,mm1 + mov edi,dword ptr[edi] + add esi,ebx + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + xor eax,eax + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ax,word ptr[QZVal+6] + + mov ebx,dword ptr[UV16+4] + mov word ptr[edi+14],ax + + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[QDibOut+4] + pmullw mm7,mm6 + + shr ebx,16 + + psrlw mm7,8 + + paddw mm6,[RGBADelta] + + movq mm5,[QNegAlpha] + pmullw mm7,qword ptr[VertAlpha] + + mov edi,dword ptr[edi] + psubw mm5,qword ptr[VertAlpha] + + + + movq mm3,[edi+28] + mov esi,GBitPtr + + punpcklbw mm3,[Zero] + add esi,edx + + pmullw mm3,mm5 + xor eax,eax + + paddw mm3,mm7 + add esi,ebx + + ;regrab z + movq mm2,[QZVal32_0] + psrlw mm3,8 + + movq mm4,[QZVal32_1] + packuswb mm3,mm3 + + paddd mm2,[QZDelta] + paddd mm4,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm4 + + psrld mm2,17 + psrld mm4,17 + + packssdw mm2,mm4 + xor eax,eax + + pslld mm2,1 + + + movq [QZVal],mm2 + + mov al,byte ptr[esi] + movq mm4,mm0 + + pand mm4,[WrapMask] + pcmpgtw mm2,[ebp+16] + + movd [edi+28],mm3 + movq [UV16],mm4 + + psrlw mm2,15 + mov esi,GBitPtr + + psrlq mm4,[QShiftV] + + psllw mm2,2 + movq [UV16V],mm4 + movq mm4,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + punpcklwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + mov edi,dword ptr[QZOut] + + movq mm4,mm2 + mov edi,dword ptr[edi] + + pmullw mm7,mm6 + + xor eax,eax + + mov ax,word ptr[QZVal] + + punpcklwd mm4,[Zero] + mov word ptr[edi+16],ax + + paddw mm6,[RGBADelta] + + paddd mm4,[QDibOrCan] + psrlw mm7,8 + + movq [QDibOut],mm4 + movq mm5,[QNegAlpha] + + mov edi,dword ptr[QDibOut] + pmullw mm7,qword ptr[VertAlpha] + + mov edi,dword ptr[edi] + psubw mm5,qword ptr[VertAlpha] + mov edx,dword ptr[UV16V] + + movq mm3,[edi+32] + paddd mm0,mm1 + + punpcklbw mm3,[Zero] + shr ebx,16 + + pmullw mm3,mm5 + xor eax,eax + + paddw mm3,mm7 + add esi,edx + + psrlw mm3,8 + add esi,ebx + + movq mm4,mm0 + packuswb mm3,mm3 + + pand mm4,[WrapMask] + movd [edi+32],mm3 + + paddd mm0,mm1 + mov edi,dword ptr[QZOut+4] + + mov al,byte ptr[esi] + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[edi] + + pmullw mm7,mm6 + mov ax,word ptr[QZVal+2] + + mov word ptr[edi+18],ax + + psrlw mm7,8 + mov edi,dword ptr[QDibOut+4] + + paddw mm6,[RGBADelta] + + mov edi,dword ptr[edi] + + shr ebx,16 + movq mm5,[QNegAlpha] + + pmullw mm7,qword ptr[VertAlpha] + psubw mm5,qword ptr[VertAlpha] + + movq mm3,[edi+36] + mov esi,GBitPtr + + punpcklbw mm3,[Zero] + add esi,edx + + pmullw mm3,mm5 + xor eax,eax + + paddw mm3,mm7 + movq mm4,mm0 + + psrlw mm3,8 + pand mm4,[WrapMask] + + packuswb mm3,mm3 + movq [UV16],mm4 + + add esi,ebx + psrlq mm4,[QShiftV] + + xor eax,eax + movq [UV16V],mm4 + + mov al,byte ptr[esi] + + mov esi,GBitPtr + movd [edi+36],mm3 + + movq mm4,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + punpckhwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + movq mm4,mm2 + + mov edi,dword ptr[QZOut] + + mov ax,word ptr[QZVal+4] + pmullw mm7,mm6 + + mov edi,dword ptr[edi] + + punpckhwd mm4,[Zero] + mov word ptr[edi+20],ax + xor eax,eax + + paddd mm4,[QDibOrCan] + + movq [QDibOut],mm4 + + mov edi,dword ptr[QDibOut] + paddw mm6,[RGBADelta] + + + mov edi,dword ptr[edi] + psrlw mm7,8 + + movq mm5,[QNegAlpha] + pmullw mm7,qword ptr[VertAlpha] + + mov edx,dword ptr[UV16V] + psubw mm5,qword ptr[VertAlpha] + + movq mm3,[edi+40] + paddd mm0,mm1 + + punpcklbw mm3,[Zero] + movq mm4,mm0 + + pmullw mm3,mm5 + shr ebx,16 + + paddw mm3,mm7 + add esi,edx + + psrlw mm3,8 + add esi,ebx + + packuswb mm3,mm3 + xor eax,eax + + movd [edi+40],mm3 + paddd mm0,mm1 + + pand mm4,[WrapMask] + mov al,byte ptr[esi] + + movq [UV16],mm4 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[QZOut+4] + pmullw mm7,mm6 + + mov edi,dword ptr[edi] + + mov ax,word ptr[QZVal+6] + psrlw mm7,8 + + mov word ptr[edi+22],ax + + mov edi,dword ptr[QDibOut+4] + shr ebx,16 + + paddw mm6,[RGBADelta] + + movq mm5,[QNegAlpha] + mov edi,dword ptr[edi] + + pmullw mm7,qword ptr[VertAlpha] + psubw mm5,qword ptr[VertAlpha] + + movq mm3,[edi+44] + mov esi,GBitPtr + + punpcklbw mm3,[Zero] + add esi,ebx + + pmullw mm3,mm5 + add esi,edx + + paddw mm3,mm7 + xor eax,eax + + ;regrab z + movq mm2,[QZVal32_0] + psrlw mm3,8 + + movq mm4,[QZVal32_1] + packuswb mm3,mm3 + + paddd mm2,[QZDelta] + paddd mm4,[QZDelta] + + movq [QZVal32_0],mm2 + movq [QZVal32_1],mm4 + + psrld mm2,17 + psrld mm4,17 + + packssdw mm2,mm4 + xor eax,eax + + pslld mm2,1 + + + movq [QZVal],mm2 + + mov al,byte ptr[esi] + movq mm4,mm0 + + pand mm4,[WrapMask] + pcmpgtw mm2,[ebp+24] + + movd [edi+44],mm3 + movq [UV16],mm4 + + psrlw mm2,15 + mov esi,GBitPtr + + psrlq mm4,[QShiftV] + + psllw mm2,2 + movq [UV16V],mm4 + + movq mm4,mm2 + + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + punpcklwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + movq [QZOut],mm4 + + mov edi,dword ptr[QZOut] + movq mm4,mm2 + + mov ax,word ptr[QZVal] + + mov edi,dword ptr[edi] + pmullw mm7,mm6 + + mov word ptr[edi+24],ax + + punpcklwd mm4,[Zero] + xor eax,eax + + paddd mm4,[QDibOrCan] + + movq [QDibOut],mm4 + + paddw mm6,[RGBADelta] + + mov edi,dword ptr[QDibOut] + psrlw mm7,8 + + movq mm5,[QNegAlpha] + pmullw mm7,qword ptr[VertAlpha] + + mov edi,dword ptr[edi] + psubw mm5,qword ptr[VertAlpha] + + movq mm3,[edi+48] + paddd mm0,mm1 + + punpcklbw mm3,[Zero] + movq mm4,mm0 + + pmullw mm3,mm5 + shr ebx,16 + + mov edx,dword ptr[UV16V] + paddw mm3,mm7 + + pand mm4,[WrapMask] + psrlw mm3,8 + + movq [UV16],mm4 + packuswb mm3,mm3 + + xor eax,eax + add esi,edx + + movd [edi+48],mm3 + paddd mm0,mm1 + + add esi,ebx + mov al,byte ptr[esi] + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + psrlq mm4,[QShiftV] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + + movq [UV16V],mm4 + + mov ebx,dword ptr[UV16+4] + + mov edx,dword ptr[UV16V] + + mov edi,dword ptr[QZOut+4] + pmullw mm7,mm6 + + mov ax,word ptr[QZVal+2] + + mov edi,dword ptr[edi] + psrlw mm7,8 + + mov word ptr[edi+26],ax + + mov edi,dword ptr[QDibOut+4] + shr ebx,16 + + paddw mm6,[RGBADelta] + + movq mm5,[QNegAlpha] + pmullw mm7,qword ptr[VertAlpha] + + mov edi,dword ptr[edi] + psubw mm5,qword ptr[VertAlpha] + + movq mm3,[edi+52] + mov esi,GBitPtr + + punpcklbw mm3,[Zero] + movq mm4,mm0 + + pmullw mm3,mm5 + add esi,edx + + paddw mm3,mm7 + xor eax,eax + + pand mm4,[WrapMask] + psrlw mm3,8 + + movq [UV16],mm4 + packuswb mm3,mm3 + + psrlq mm4,[QShiftV] + add esi,ebx + + movq [UV16V],mm4 + xor eax,eax + + + movd [edi+52],mm3 + mov al,byte ptr[esi] + + mov esi,GBitPtr + movq mm4,mm2 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR |ARGB + + punpckhwd mm4,[Zero] + + mov ebx,dword ptr[UV16+4] + paddd mm4,[QZorCan] + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + movq [QZOut],mm4 + + mov edi,dword ptr[QZOut] + movq mm4,mm2 + + mov ax,word ptr[QZVal+4] + + mov edi,dword ptr[edi] + pmullw mm7,mm6 + + mov word ptr[edi+28],ax + + xor eax,eax + + punpckhwd mm4,[Zero] + psrlw mm7,8 + + paddd mm4,[QDibOrCan] + + paddw mm6,[RGBADelta] + + movq mm5,[QNegAlpha] + pmullw mm7,qword ptr[VertAlpha] + + movq [QDibOut],mm4 + psubw mm5,qword ptr[VertAlpha] + + mov edi,dword ptr[QDibOut] + paddd mm0,mm1 + + mov edi,dword ptr[edi] + movq mm4,mm0 + + movq mm3,[edi+56] + shr ebx,16 + + punpcklbw mm3,[Zero] + + mov edx,dword ptr[UV16V] + pmullw mm3,mm5 + + pand mm4,[WrapMask] + paddw mm3,mm7 + + add esi,edx + psrlw mm3,8 + + add esi,ebx + packuswb mm3,mm3 + + paddd mm0,mm1 + mov al,byte ptr[esi] + + movd [edi+56],mm3 + + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ARGB UZR|VZR AR|GB + xor eax,eax + + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw AR|GB UZR|VZR AR|GB + mov edi,dword ptr[QZOut+4] + + mov ax,word ptr[QZVal+6] + + mov edi,dword ptr[edi] + pmullw mm7,mm6 + + mov word ptr[edi+30],ax + + mov edi,dword ptr[QDibOut+4] + + paddw mm6,[RGBADelta] + + mov edi,dword ptr[edi] + psrlw mm7,8 + + movq [ARL],mm6 + + pop ebp + + movq mm5,[QNegAlpha] + + pmullw mm7,qword ptr[VertAlpha] + psubw mm5,qword ptr[VertAlpha] + + ;regrab z + movq mm2,[QZVal32_0] + movq mm3,[edi+60] + + movq mm4,[QZVal32_1] + punpcklbw mm3,[Zero] + + paddd mm2,[QZDelta] + pmullw mm3,mm5 + + paddd mm4,[QZDelta] + paddw mm3,mm7 + + movq [QZVal32_0],mm2 + psrlw mm3,8 + + movq [QZVal32_1],mm4 + packuswb mm3,mm3 + + movd [edi+60],mm3 + + ; get corrected right side deltas ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm4,[ZIR] + movq mm6,[UVZ] + + movq mm2,[UVR] + movq mm0,[UVLeftW] ; ULw|VLw DU16|DV16 argb|ARGBagAG|rbRB |ZRi aA|rR UZR|VZR aArR|gGbB + + movq mm1,[UVLeft] ; ULw|VLw UL|VL argb|ARGBagAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + punpckldq mm2,mm2 ; ULw|VLw UL|VL ZRi|ZRi agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + + pfmul mm2,mm6 ; ULw|VLw UL|VL UR|VR agAG|rbRB ZRi|ZRi aA|rR UZR|VZR aArR|gGbB + mov eax,offset QZCan + add dword ptr[Dest],32 + + add dword ptr[eax+4],32 + mov eax,offset QDibCan + + add dword ptr[eax+4],64 + + movq mm3,mm2 + pfmul mm3,[QFixedScale] + + pf2id mm3,mm3 + + dec [NumASpans] ; dec num affine spans + jnz SpanLoopLit + +HandleLeftoverPixelsLit: + + + mov esi,GBitPtr + + + cmp [RemainingCount],0 + jz ReturnLit + + mov eax,[RemainingCount] + mov dword ptr[ZIR],eax + mov dword ptr[ZIR+4],eax + + movq mm7,[GLMapMulUV] ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR LU|LV + movq mm5,mm1 + + pfsub mm6,[UVDivZ16StepX] + pfmul mm7,mm1 ;UL6i|VL6i UL|VL UR6i|VR6i URi|VRi |ZRi |ZY UZR|VZR ULL|VLL + + pfmul mm5,[QFixedScale] + pi2fd mm3,[ZIR] + + pfmul mm7,[QFixedScale] + pfmul mm3,[UVDivZStepX] + + pf2id mm5,mm5 + pfadd mm3,mm6 + + pi2fd mm2,[ZIR] + movd mm6,[Zi16StepX] + + pf2id mm7,mm7 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + pfsub mm4,mm6 + + movd mm6,[ZiStepX] + mov ebx,[RemainingCount] + + pfmul mm2,mm6 + + shl ebx,3 + + pfadd mm2,mm4 + paddd mm5,[UVAdjust] + + punpckldq mm4,mm4 + + movq [UVL16],mm7 + pfrcp mm2,mm2 + + pfmul mm4,[QZBufferPrec] + + paddd mm5,[UVAdjust2] + pfmul mm2,mm3 + + movq [UVLeft],mm5 + pfsubr mm1,mm2 ; ULw|VLw DU|DV UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + pfmul mm1,qword ptr[QFixedScaleLUT+ebx] ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq mm0,mm5 + pand mm5,[WrapMask] + pf2id mm1,mm1 ; ULw|VLw DU16|DV16 UR|VR URw|VRw |ZRi |ZY UZR|VZR | + + movq [UV16],mm5 + movq mm7,[UVAdjustL] + + psrlq mm5,[QShiftV] + paddd mm7,[UVL16] + + movq [UV16V],mm5 + movq [UVL16],mm7 + + +OnePixelSpanLit: + ; Clamp U/V + mov ebx,dword ptr[UVL16+4] + cmp ebx,MaxU + jle TryClampU1Lit + mov ecx,MaxU + mov dword ptr[UVL16+4],ecx + jmp NoClampU1Lit + +TryClampU1Lit: + cmp ebx,0 + jge NoClampU1Lit + mov dword ptr[UVL16+4],0 +NoClampU1Lit: + mov eax,dword ptr[UVL16] + cmp eax,MaxV + jle TryClampV1Lit + mov ecx,MaxV + mov dword ptr[UVL16],ecx + jmp NoClampV1Lit + +TryClampV1Lit: + cmp eax,0 + jge NoClampV1Lit + mov dword ptr[UVL16],0 + +NoClampV1Lit: + mov ebx,dword ptr[UV16+4] + mov eax,dword ptr[UV16V] + + mov esi,GBitPtr + shr ebx,16 + add esi,eax + add esi,ebx + mov ecx,TexPal + xor eax,eax + movq mm6,[ARL] + + mov eax,offset QDibCan + push ebp + + mov edi,dword ptr[eax+4] + mov ebp,dword ptr[Dest] + + movq [UVZ],mm1 ;using this for a step temp + + movd mm3,dword ptr[ZiStepX] + xor eax,eax + +LeftoverLoopLit: + paddd mm0,[UVZ] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw |ZRi |ZY UZR|VZR | + pf2id mm2,mm4 + + mov al,byte ptr[esi] + movq mm5,mm0 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw UL|VL |ZY UZR|VZR | + + mov esi,GBitPtr + pfadd mm4,mm3 + + pand mm5,[WrapMask] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + psrld mm2,16 + + movq [UV16],mm5 ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR | + movd mm7,[ecx+eax*4] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR |ARGB + + psrlq mm5,[QShiftV] + movd eax,mm2 + + movq [UV16V],mm5 + punpcklbw mm7,qword ptr[Zero] ; ULw|VLw DU16|DV16 UL|VL ULw|VLw ULw|VLw |ZY UZR|VZR AR|GB + + xor eax,0 + mov ebx,dword ptr[UV16+4] + + shr ebx,16 + + add esi,ebx + + mov edx,dword ptr[UV16V] + + pmullw mm7,mm6 + + psrlw mm7,8 + movq mm1,[QNegAlpha] + + pmullw mm7,qword ptr[VertAlpha] + psubw mm1,qword ptr[VertAlpha] + + movq mm5,[edi] + paddw mm6,[RGBADelta] + + punpcklbw mm5,[Zero] + add esi,edx + + pmullw mm5,mm1 + cmp ax,word ptr[ebp] + jl SkipPixelLitZ + + paddw mm5,mm7 + psrlw mm5,8 + packuswb mm5,mm5 + + movd [edi],mm5 + +SkipPixelLitZ: + + xor eax,eax + add edi,4 + add ebp,2 + + dec [RemainingCount] + jge LeftoverLoopLit + + pop ebp + +ReturnLit: + + pop edi + pop esi + pop ecx + pop ebx + + cRet DrawSpan32_AsmGouraudZBufferVertexAlpha3DNow +endProc DrawSpan32_AsmGouraudZBufferVertexAlpha3DNow + + +;put the machine into 3dnow mode + +cProc Femms3DNow, 0,<> + + femms + + cRet Femms3DNow +endProc Femms3DNow + + +;edge step for 3dnow + +cProc StepWorld3DNow, 4, + + + mov eax,edge + + movq mm0,qword ptr[eax+12] + movq mm1,qword ptr[eax+20] + + pfadd mm0,qword ptr[eax+28] + pfadd mm1,qword ptr[eax+36] + + movq qword ptr[eax+12],mm0 + pf2id mm0,mm0 + + movq qword ptr[eax+20],mm1 + pf2id mm1,mm1 + + mov edx,dword ptr[eax+4] + movq qword ptr[eax+52],mm1 + + inc edx + movd dword ptr[eax],mm0 + + mov dword ptr[eax+4],edx + psrlq mm0,32 + + mov edx,dword ptr[eax+8] + movd dword ptr[eax+48],mm0 + + dec edx + mov dword ptr[eax+8],edx + + + + cRet StepWorld3DNow +endProc StepWorld3DNow + + + +_TEXT$01 ends + +end + + diff --git a/G3D/Engine/Drivers/SoftDrv/dmodes.c b/G3D/Engine/Drivers/SoftDrv/dmodes.c new file mode 100644 index 0000000..ec81928 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/dmodes.c @@ -0,0 +1,1506 @@ +/****************************************************************************************/ +/* dmodes.c */ +/* */ +/* Author: Ken Baird */ +/* Description: Directdraw related stuff */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#define INITGUID +#include +#include "softdrv.h" +#include "ddraw.h" +#include + +LPDIRECTDRAW lpDD; // DirectDraw object +LPDIRECTDRAW4 lpDD4; +LPDIRECTDRAWSURFACE4 lpDDSPrimary; // DirectDraw primary surface +LPDIRECTDRAWSURFACE4 lpDDSBack; // DirectDraw back surface +BOOL bActive =TRUE; +BOOL bInitDone =FALSE; +BOOL bWindowed =FALSE; +HWND mhWnd =NULL; +static BOOL bDMA =FALSE; +static BOOL bHardBlt =FALSE; +static BOOL bDMAPageLock=FALSE; +BOOL bBackLocked =FALSE; +#ifdef STRICT +WNDPROC pOldWndProc; +#else +FARPROC pOldWndProc; +#endif +HINSTANCE ddrawinst; + +typedef HRESULT (WINAPI *LPDIRECTDRAWCREATE)( GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter ); + +extern int NumDevices; +typedef struct DecalDelayTag +{ + LPDIRECTDRAWSURFACE4 surf; + RECT srect; + S32 x; + S32 y; +} DecalDelay; + +static DecalDelay DecalQ[8192]; +static int NumDecalsQd; +char* MyErrorToString(HRESULT error); + +//these statics must be eliminated soon +static int CurrentModeWidth, CurrentModeHeight, CurrentModeDepth; + + +BOOL WINAPI DDrawDriverEnumCallbackEx(GUID *pGUID, LPSTR pDescription, LPSTR pName, LPVOID pContext, HMONITOR hm) +{ + LPDIRECTDRAWCREATE lpDDCreate; + LPDIRECTDRAW pDD; + LPDIRECTDRAW4 pDD4 =NULL; + HRESULT hRet; + VidEnumInfo *vinfo =&((VidEnumInfo *)pContext)[NumDevices]; + + ddrawinst =LoadLibrary("ddraw.dll"); + + if(!ddrawinst) + { + return DDENUMRET_CANCEL; + } + + lpDDCreate =(LPDIRECTDRAWCREATE)GetProcAddress(ddrawinst, "DirectDrawCreate"); + if(lpDDCreate) + { + hRet =lpDDCreate(NULL, &pDD, NULL); + } + else + { + return DDENUMRET_CANCEL; + } + vinfo->DeviceGuid =pGUID; + + if(hRet != DD_OK) + { + ErrorPrintf("DirectDrawCreate FAILED : DDrawDriverEnumCallbackEx\n"); + return DDENUMRET_CANCEL; + } + + hRet =pDD->lpVtbl->QueryInterface(pDD, &IID_IDirectDraw4, (LPVOID *)&pDD4); + if(hRet != DD_OK) + { + ErrorPrintf("QueryInterface FAILED : DDrawDriverEnumCallbackEx\n"); + return DDENUMRET_CANCEL; + } + + hRet =pDD4->lpVtbl->GetDeviceIdentifier(pDD4, &vinfo->DeviceInfo,0); + hRet =pDD4->lpVtbl->GetDeviceIdentifier(pDD4, &vinfo->DeviceInfoHost, DDGDI_GETHOSTIDENTIFIER); + + if(pDD4) + { + pDD4->lpVtbl->Release(pDD4); + } + + FreeLibrary(ddrawinst); + + if(NumDevices < 16) + { + NumDevices++; + } + else + { + return DDENUMRET_CANCEL; + } + return DDENUMRET_OK; +} + +BOOL WINAPI OldDDrawDriverEnumCallback(GUID *pGUID, LPSTR pDescription, LPSTR pName, LPVOID context) +{ + return (DDrawDriverEnumCallbackEx(pGUID, pDescription, pName, context, NULL)); +} + +HRESULT WINAPI ModeCallback(LPDDSURFACEDESC2 pdds, LPVOID lParam) +{ + VidEnumInfo *vinfo =(VidEnumInfo *)lParam; + + if(pdds->ddpfPixelFormat.dwRGBBitCount==vinfo->bpp) + { + vinfo->VidModes[vinfo->NumVidModes].width =pdds->dwWidth; + vinfo->VidModes[vinfo->NumVidModes].flags =0; + vinfo->VidModes[vinfo->NumVidModes].height =pdds->dwHeight; + vinfo->VidModes[vinfo->NumVidModes++].bpp =pdds->ddpfPixelFormat.dwRGBBitCount; + } + + return S_FALSE; +} + +void FreeDDraw(VidEnumInfo *vinfo) +{ + int x =0; + + if(lpDD4) + { + if(vinfo->VidModes[vinfo->CurrentVidMode].current & FLIP) + { + lpDDSBack =NULL; + } + else + { + if(lpDDSBack) + { + lpDDSBack->lpVtbl->Release(lpDDSBack); + lpDDSBack =NULL; + } + } + if(lpDDSPrimary) + { + lpDDSPrimary->lpVtbl->Release(lpDDSPrimary); + lpDDSPrimary =NULL; + } + lpDD4->lpVtbl->Release(lpDD4); + lpDD4 =NULL; + } + FreeLibrary(ddrawinst); +} + +HRESULT RestoreAll(void) +{ + HRESULT ddrval; + + ddrval =lpDD4->lpVtbl->SetCooperativeLevel(lpDD4, mhWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + if(ddrval!=DD_OK) + { + ErrorPrintf("Error During SetCooperativeLevel() in RestoreAll()\n%s\n", MyErrorToString(ddrval)); + return FALSE; + } + + ddrval =lpDD4->lpVtbl->SetDisplayMode(lpDD4, CurrentModeWidth, CurrentModeHeight, CurrentModeDepth, 0, 0); + if(ddrval!=DD_OK) + { + ErrorPrintf("Error During SetDisplayMode() in RestoreAll()\n%s\n", MyErrorToString(ddrval)); + return FALSE; + } + ddrval =lpDD4->lpVtbl->RestoreAllSurfaces(lpDD4); + if(ddrval!=DD_OK) + { + ErrorPrintf("Error During RestoreAllSurfaces() in RestoreAll()\n%s\n", MyErrorToString(ddrval)); + return FALSE; + } + return ddrval; +} + +void SetDDrawWindow(HWND hwnd) +{ + mhWnd =hwnd; +} + +BOOL LockDDrawBackBuffer(DRV_Window *cwnd, RECT *wrect) +{ + HRESULT ddrval; + DDSURFACEDESC2 ddsd; + + if(!bActive) + return TRUE; + + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + + lpDDSBack->lpVtbl->GetSurfaceDesc(lpDDSBack, &ddsd); + if(((int)ddsd.dwWidth < wrect->right) || ((int)ddsd.dwHeight < wrect->bottom)) + { + ErrorPrintf("ERROR: World render rect passed by the engine is larger than the drawing surface.\n"); + ErrorPrintf("WorldRect: %d, %d, %d, %d\n", wrect->left, wrect->top, wrect->right, wrect->bottom); + ErrorPrintf("Surface: %d, %d\n", ddsd.dwWidth, ddsd.dwHeight); + return FALSE; + } + + while(1) + { + ddrval =lpDDSBack->lpVtbl->Lock(lpDDSBack, wrect, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL); + if(ddrval==DD_OK) + { + break; + } + + if(ddrval==DDERR_SURFACELOST) + { + ddrval =RestoreAll(); + if(ddrval!=DD_OK ) + { + ErrorPrintf("Error During Lock() in LockDDrawBackBuffer()...\n"); + ErrorPrintf("DirectDraw Surfaces were lost and could not be restored : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + ErrorPrintf("Error During Lock() in LockDDrawBackBuffer() : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + SleepEx(5, FALSE); + } + cwnd->Buffer =(U8 *)ddsd.lpSurface; + cwnd->PixelPitch=ddsd.lPitch; + bBackLocked =TRUE; + return TRUE; +} + +BOOL UnlockDDrawBackBuffer(DRV_Window *cwnd, RECT *wrect) +{ + HRESULT ddrval =DD_OK; + + if(!bActive) + return TRUE; + + while(1) + { + ddrval =lpDDSBack->lpVtbl->Unlock(lpDDSBack, NULL); + if(ddrval==DD_OK) + break; + + if(ddrval==DDERR_SURFACELOST) + { + ddrval =RestoreAll(); + if(ddrval!=DD_OK ) + { + ErrorPrintf("Error During Unlock() in UnlockDDrawBackBuffer()...\n"); + ErrorPrintf("DirectDraw Surfaces were lost and could not be restored : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + ErrorPrintf("Error During Unlock() in UnlockDDrawBackBuffer() : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + SleepEx(5, FALSE); + } + bBackLocked =FALSE; + return TRUE; +} + +BOOL RefreshDDraw(DRV_Window *cwnd, VidModeList *cmode, RECT *src, RECT *dst) +{ + HRESULT ddrval; + DDSURFACEDESC2 ddsd; +// int i; + RECT rDest, rSrc; + + if(!bActive) + { + return TRUE; + } + + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + + lpDDSBack->lpVtbl->GetSurfaceDesc(lpDDSBack, &ddsd); + rDest.left =rDest.top =0; + rDest.right =ddsd.dwWidth-1; + rDest.bottom=ddsd.dwHeight-1; + + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + + lpDDSPrimary->lpVtbl->GetSurfaceDesc(lpDDSPrimary, &ddsd); + rSrc.left =rSrc.top =0; + rSrc.right =ddsd.dwWidth-1; + rSrc.bottom =ddsd.dwHeight-1; + + ddrval =DD_OK; + if((cmode->current & VIDEO) && (cmode->current & FASTBLT)) + { + while(1) + { + ddrval =lpDDSPrimary->lpVtbl->BltFast(lpDDSPrimary, 0, 0, lpDDSBack, NULL, 0); + if(ddrval==DD_OK) + { + break; + } + + if(ddrval==DDERR_SURFACELOST) + { + ddrval =RestoreAll(); + if(ddrval!=DD_OK) + { + ErrorPrintf("Error During BltFast() in RefreshDDraw()...\n"); + ErrorPrintf("DirectDraw Surfaces were lost and could not be restored : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + ErrorPrintf("Error During BltFast() in RefreshDDraw() : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + SleepEx(5, FALSE); + } + } + else if(cmode->current & FLIP) + { + while(1) + { + ddrval =lpDDSPrimary->lpVtbl->Flip(lpDDSPrimary, lpDDSBack, DDFLIP_NOVSYNC); + if(ddrval==DD_OK) + { + break; + } + + if(ddrval==DDERR_SURFACELOST) + { + ddrval =RestoreAll(); + if(ddrval!=DD_OK) + { + ErrorPrintf("Error During Flip() in RefreshDDraw()...\n"); + ErrorPrintf("DirectDraw Surfaces were lost and could not be restored : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + ErrorPrintf("Error During Flip() in RefreshDDraw() : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + SleepEx(5, FALSE); + } + } + else //safe blt + { + if(cmode->current & STRETCHMODE) + { + while(1) + { + ddrval =lpDDSPrimary->lpVtbl->Blt(lpDDSPrimary, NULL, lpDDSBack, NULL, 0, NULL); + if(ddrval==DD_OK) + break; + + if(ddrval==DDERR_SURFACELOST) + { + ddrval =RestoreAll(); + if(ddrval!=DD_OK) + { + ErrorPrintf("Error During StretchMode Blt() in RefreshDDraw()...\n"); + ErrorPrintf("DirectDraw Surfaces were lost and could not be restored : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + ErrorPrintf("Error During StretchMode Blt() in RefreshDDraw() : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + SleepEx(5, FALSE); + } + } + else + { + while(1) + { + ddrval =lpDDSPrimary->lpVtbl->Blt(lpDDSPrimary, NULL, lpDDSBack, NULL, 0, NULL); + if(ddrval==DD_OK) + break; + + if(ddrval==DDERR_SURFACELOST) + { + ddrval =RestoreAll(); + if(ddrval!=DD_OK) + { + ErrorPrintf("Error During Blt() in RefreshDDraw()...\n"); + ErrorPrintf("DirectDraw Surfaces were lost and could not be restored : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + ErrorPrintf("Error During Blt() in RefreshDDraw() : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + SleepEx(5, FALSE); + } + } + } +/* for(i=0;i < NumDecalsQd;i++) + { + if(DecalQ[i].srect.left == -1) + { + DDrawBlitDecalToFront(DecalQ[i].surf, NULL, DecalQ[i].x, DecalQ[i].y); + } + else + { + DDrawBlitDecalToFront(DecalQ[i].surf, &DecalQ[i].srect, DecalQ[i].x, DecalQ[i].y); + } + } + NumDecalsQd =0;*/ + return TRUE; +} + +//my best guess for best performance is fast, blt, flip +//dma is off for now because it ran horribly on the machine +//I tested it on. If people get 500mhz agp bus action in a few +//years it might be useful perhaps +geBoolean SetDDrawMode(U32 top, VidEnumInfo *vinfo) +{ + HRESULT ddrval; + DDSURFACEDESC2 ddsd; + DDSCAPS2 ddscaps; + + if(vinfo->VidModes[top].flags & STRETCHMODE) + { + if((vinfo->VidModes[top].width > 640) + ||((vinfo->VidModes[top].width == 640) + &&(vinfo->VidModes[top].height > 480))) + { + ddrval =lpDD4->lpVtbl->SetDisplayMode(lpDD4, vinfo->VidModes[top].width, vinfo->VidModes[top].height, vinfo->VidModes[top].bpp, 0, 0); + } + else + { + ddrval =lpDD4->lpVtbl->SetDisplayMode(lpDD4, 640, 480, vinfo->VidModes[top].bpp, 0, 0); + } + vinfo->VidModes[top].current |=STRETCHMODE; + } + else + { + ddrval =lpDD4->lpVtbl->SetDisplayMode(lpDD4, vinfo->VidModes[top].width, vinfo->VidModes[top].height, vinfo->VidModes[top].bpp, 0, 0); + } + if(ddrval != DD_OK) + { + return GE_FALSE; + } + CurrentModeHeight =vinfo->VidModes[top].height; + CurrentModeWidth =vinfo->VidModes[top].width; + CurrentModeDepth =vinfo->VidModes[top].bpp; + + if(!(vinfo->VidModes[top].flags & MODEXMODE)) + { + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS; + ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE | DDSCAPS_VIDEOMEMORY; + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSPrimary, NULL); + if(ddrval==DD_OK) + { + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps =DDSCAPS_SYSTEMMEMORY; + if(vinfo->VidModes[top].flags & STRETCHMODE) + { + if((vinfo->VidModes[top].width > 640) + ||((vinfo->VidModes[top].width == 640) + &&(vinfo->VidModes[top].height > 480))) + { + ddsd.dwHeight =640; + ddsd.dwWidth =480; + } + else + { + ddsd.dwHeight =vinfo->VidModes[top].height; + ddsd.dwWidth =vinfo->VidModes[top].width; + } + } + else + { + ddsd.dwHeight =vinfo->VidModes[top].height; + ddsd.dwWidth =vinfo->VidModes[top].width; + } + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSBack, NULL); + if(ddrval==DD_OK) + { + //need to grab pitch here since it can change + //depending on where the surface is created + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + lpDDSBack->lpVtbl->GetSurfaceDesc(lpDDSBack, &ddsd); + vinfo->VidModes[top].pitch =ddsd.lPitch; + + //both were created, make sure they are in vidram + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + lpDDSPrimary->lpVtbl->GetCaps(lpDDSPrimary, &ddscaps); + if(ddscaps.dwCaps & DDSCAPS_VIDEOMEMORY) + { + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + lpDDSBack->lpVtbl->GetCaps(lpDDSBack, &ddscaps); + if(ddscaps.dwCaps & DDSCAPS_VIDEOMEMORY) + { + //both are good to go + vinfo->VidModes[top].current |=VIDEO; + + //mark fastblt unless it's stretching + if(!(vinfo->VidModes[top].flags & STRETCHMODE)) + { + vinfo->VidModes[top].current |=FASTBLT; + } + } + } + } + } + else if(!(vinfo->VidModes[top].current & VIDEO) + && !(vinfo->VidModes[top].current & STRETCHMODE)) + { + if(lpDDSBack) lpDDSBack->lpVtbl->Release(lpDDSBack); + if(lpDDSPrimary) lpDDSPrimary->lpVtbl->Release(lpDDSPrimary); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS; + ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE; + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSPrimary, NULL); + if(ddrval==DD_OK) + { + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.dwHeight =vinfo->VidModes[top].height; + ddsd.dwWidth =vinfo->VidModes[top].width; + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSBack, NULL); + if(ddrval==DD_OK) + { + //need to grab pitch here since it can change + //depending on where the surface is created + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + lpDDSBack->lpVtbl->GetSurfaceDesc(lpDDSBack, &ddsd); + vinfo->VidModes[top].pitch =ddsd.lPitch; + + //both were created good enough + vinfo->VidModes[top].current |=SYSTEM|SAFEBLT; + } + } + } + } //flip + if((vinfo->VidModes[top].flags & MODEXMODE) || lpDDSBack==NULL) + { + if(lpDDSBack) lpDDSBack->lpVtbl->Release(lpDDSBack); + if(lpDDSPrimary) lpDDSPrimary->lpVtbl->Release(lpDDSPrimary); + + //try flip + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE | + DDSCAPS_COMPLEX | DDSCAPS_FLIP; + ddsd.dwBackBufferCount =1; + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSPrimary, NULL); + if(ddrval==DD_OK) + { + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + ddscaps.dwCaps =DDSCAPS_BACKBUFFER; + ddrval =lpDDSPrimary->lpVtbl->GetAttachedSurface(lpDDSPrimary, &ddscaps, &lpDDSBack); + if(ddrval==DD_OK) + { + //need to grab pitch here since it can change + //depending on where the surface is created + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + lpDDSBack->lpVtbl->GetSurfaceDesc(lpDDSBack, &ddsd); + vinfo->VidModes[top].pitch =ddsd.lPitch; + + vinfo->VidModes[top].current |=SYSTEM|FLIP; + } + } + } + + return GE_TRUE; +} + +//sort the passed in list of video modes, returning a sorted +//reliable list of resolutions and capabilities +//capabilities are tested for each mode and surface type +//to make a more reliable list than getcaps() can provide +void SortDDrawVideoModeList(VidEnumInfo *vinfo) +{ + int top, search; + VidModeList temp; + DDSURFACEDESC2 ddsd; + DDSCAPS2 ddscaps; + HRESULT ddrval; + + for(top=0;top < vinfo->NumVidModes;top++) + { + if(vinfo->VidModes[top].flags & MODEXMODE) + { + //modex can only flip I guess + vinfo->VidModes[top].flags |=(SYSTEM | FLIP); + } + else + { + vinfo->VidModes[top].flags |=SAFEBLT; //everyone has this but X + ddrval =lpDD4->lpVtbl->SetDisplayMode(lpDD4, vinfo->VidModes[top].width, vinfo->VidModes[top].height, vinfo->VidModes[top].bpp, 0, 0); + + //check fastblt, front and back + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS; + ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE | DDSCAPS_VIDEOMEMORY; + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSPrimary, NULL); + if(ddrval==DD_OK) + { + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.dwHeight =vinfo->VidModes[top].height; + ddsd.dwWidth =vinfo->VidModes[top].width; + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSBack, NULL); + if(ddrval==DD_OK) + { + //both were created, make sure they are + //in vidram + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + lpDDSPrimary->lpVtbl->GetCaps(lpDDSPrimary, &ddscaps); + if(ddscaps.dwCaps & DDSCAPS_VIDEOMEMORY) + { + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + lpDDSBack->lpVtbl->GetCaps(lpDDSBack, &ddscaps); + if(ddscaps.dwCaps & DDSCAPS_VIDEOMEMORY) + { + //both are good to go + vinfo->VidModes[top].flags |=VIDEO; + } + } + lpDDSBack->lpVtbl->Release(lpDDSBack); + } + lpDDSPrimary->lpVtbl->Release(lpDDSPrimary); + } + + if(bDMA) + { + //check dma capabilities + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS; + ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY; + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSPrimary, NULL); + if(ddrval==DD_OK) + { + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps =DDSCAPS_SYSTEMMEMORY; + ddsd.dwHeight =vinfo->VidModes[top].height; + ddsd.dwWidth =vinfo->VidModes[top].width; + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSBack, NULL); + if(ddrval==DD_OK) + { + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + lpDDSPrimary->lpVtbl->GetCaps(lpDDSPrimary, &ddscaps); + if(ddscaps.dwCaps & DDSCAPS_SYSTEMMEMORY) + { + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + lpDDSBack->lpVtbl->GetCaps(lpDDSBack, &ddscaps); + if(ddscaps.dwCaps & DDSCAPS_SYSTEMMEMORY) + { + //both are good to go + vinfo->VidModes[top].flags |=(SYSTEM|DMABLT); + } + } + lpDDSBack->lpVtbl->Release(lpDDSBack); + } + lpDDSPrimary->lpVtbl->Release(lpDDSPrimary); + } + } + + //check flip + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE | + DDSCAPS_COMPLEX | DDSCAPS_FLIP; + ddsd.dwBackBufferCount =1; + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDSPrimary, NULL); + if(ddrval==DD_OK) //make sure the backbuffer is really there + { + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + ddscaps.dwCaps =DDSCAPS_BACKBUFFER; + ddrval =lpDDSPrimary->lpVtbl->GetAttachedSurface(lpDDSPrimary, &ddscaps, &lpDDSBack); + if(ddrval==DD_OK) + { + //need to grab pitch here since it can change + //depending on where the surface is created + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + lpDDSBack->lpVtbl->GetSurfaceDesc(lpDDSBack, &ddsd); + vinfo->VidModes[top].pitch =ddsd.lPitch; + + vinfo->VidModes[top].flags |=(SYSTEM|FLIP); + lpDDSPrimary->lpVtbl->Release(lpDDSPrimary); + } + } + + if(bHardBlt) + { + vinfo->VidModes[top].flags |=HARDWARE; + } + } + } + + //drop in extra modes for stretching onto the end + //disable stretched modes for now +/* + search =vinfo->NumVidModes; + for(top=0;top < search;top++) + { + //that's a pretty big if + //DISABLE > 640 FOR NOW + if(((vinfo->VidModes[top].width < 640) + &&(vinfo->VidModes[top].height < 480)) + && !(vinfo->VidModes[top].flags & MODEXMODE)) + { + vinfo->VidModes[vinfo->NumVidModes] =vinfo->VidModes[top]; + vinfo->VidModes[vinfo->NumVidModes++].flags |=STRETCHMODE; + } + } +*/ + //sort + for(top=0;top < vinfo->NumVidModes-1;top++) + { + for(search=top+1;search < vinfo->NumVidModes;search++) + { + if(vinfo->VidModes[search].width < vinfo->VidModes[top].width) + { + temp =vinfo->VidModes[search]; + + vinfo->VidModes[search]=vinfo->VidModes[top]; + vinfo->VidModes[top] =temp; + } + } + } +} + +BOOL DoDDrawInit(HWND hwnd, VidEnumInfo *vinfo) +{ + LPDIRECTDRAWCREATE lpDDCreate; + HRESULT ddrval; + + bInitDone =FALSE; + ddrawinst =LoadLibrary("ddraw.dll"); + + if(!ddrawinst) + { + return FALSE; + } + SetDDrawWindow(hwnd); + + lpDDCreate =(LPDIRECTDRAWCREATE)GetProcAddress(ddrawinst, "DirectDrawCreate"); + if(lpDDCreate) + { + ddrval =lpDDCreate(NULL, &lpDD, NULL); + } + else + { + return DDENUMRET_CANCEL; + } + + if(ddrval!=DD_OK) + { + ErrorPrintf("Non Fatal Error During DirectDrawCreate() in DoDDrawInit()\n%s\n", MyErrorToString(ddrval)); + return FALSE; + } + + ddrval = lpDD->lpVtbl->QueryInterface(lpDD, &IID_IDirectDraw4, (LPVOID *)&lpDD4); + if(ddrval!=DD_OK) + { + ErrorPrintf("Non Fatal Error During QueryInterface() in DoDDrawInit()\n%s\n", MyErrorToString(ddrval)); + return FALSE; + } + + lpDD->lpVtbl->Release(lpDD); + lpDD =NULL; + + ddrval =lpDD4->lpVtbl->SetCooperativeLevel(lpDD4, mhWnd, + DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + if(ddrval!=DD_OK) + { + ErrorPrintf("Non Fatal Error During SetCooperativeLevel() in DoDDrawInit()\n%s\n", MyErrorToString(ddrval)); + return FALSE; + } + FreeLibrary(ddrawinst); + + bInitDone =TRUE; + NumDecalsQd =0; + return TRUE; +} + + +BOOL DoEnumeration(VidEnumInfo *vinfo) +{ + LPDIRECTDRAWCREATE lpDDCreate; + LPDIRECTDRAW pDD; + LPDIRECTDRAW4 pDD4 =NULL; + HRESULT hRet; + bInitDone =FALSE; + + + ddrawinst =LoadLibrary("ddraw.dll"); + + if(!ddrawinst) + { + return FALSE; + } + + lpDDCreate =(LPDIRECTDRAWCREATE)GetProcAddress(ddrawinst, "DirectDrawCreate"); + if(lpDDCreate) + { + hRet =lpDDCreate(NULL, &pDD, NULL); + } + else + { + return DDENUMRET_CANCEL; + } + + vinfo->DeviceGuid =NULL; + + if(hRet != DD_OK) + { + ErrorPrintf("Non Fatal Error During DirectDrawCreate() in DoEnumeration()\n%s\n", MyErrorToString(hRet)); + return DDENUMRET_CANCEL; + } + memset(&vinfo->DeviceInfo, 0, sizeof(vinfo->DeviceInfo)); + memset(&vinfo->DeviceInfoHost, 0, sizeof(vinfo->DeviceInfo)); + + hRet =pDD->lpVtbl->QueryInterface(pDD, &IID_IDirectDraw4, (LPVOID *)&pDD4); + if(hRet != DD_OK) + { + ErrorPrintf("Non Fatal Error During QueryInterface() in DoEnumeration()\n%s\n", MyErrorToString(hRet)); + return DDENUMRET_CANCEL; + } + + hRet =pDD4->lpVtbl->GetDeviceIdentifier(pDD4, &vinfo->DeviceInfo,0); + hRet =pDD4->lpVtbl->GetDeviceIdentifier(pDD4, &vinfo->DeviceInfoHost, DDGDI_GETHOSTIDENTIFIER); + + if(pDD4) + { + pDD4->lpVtbl->Release(pDD4); + } + + FreeLibrary(ddrawinst); + + if(NumDevices < 16) + { + NumDevices++; + } + else + { + return DDENUMRET_CANCEL; + } + return DDENUMRET_OK; + + return TRUE; +} + +BOOL DoModeEnumeration(VidEnumInfo *vinfo) +{ + LPDIRECTDRAWCREATE lpDDCreate; + HRESULT ddrval; + DDCAPS ddcaps; + + bInitDone =FALSE; + + ddrawinst =LoadLibrary("ddraw.dll"); + + if(!ddrawinst) + { + return FALSE; + } + + lpDDCreate =(LPDIRECTDRAWCREATE)GetProcAddress(ddrawinst, "DirectDrawCreate"); + if(lpDDCreate) + { + ddrval =lpDDCreate(NULL, &lpDD, NULL); + } + else + { + return DDENUMRET_CANCEL; + } + + if(ddrval != DD_OK) + { + ErrorPrintf("DirectDrawCreate FAILED : DoModeEnumeration\n%s\n", MyErrorToString(ddrval)); + return 0; + } + + ddrval = lpDD->lpVtbl->QueryInterface(lpDD, &IID_IDirectDraw4, (LPVOID *)&lpDD4); + if(ddrval != DD_OK) + { + ErrorPrintf("QueryInterface FAILED : DoModeEnumeration\n%s\n", MyErrorToString(ddrval)); + return 0; + } + + lpDD->lpVtbl->Release(lpDD); + lpDD =NULL; + + //test for general dma support + memset(&ddcaps, 0, sizeof(DDCAPS)); + ddcaps.dwSize =sizeof(ddcaps); + lpDD4->lpVtbl->GetCaps(lpDD4, &ddcaps, NULL); + + if(ddcaps.dwCaps & DDCAPS_CANBLTSYSMEM) + { + ErrorPrintf("System to video blits supported\n"); + if(ddcaps.dwVSBCaps & DDCAPS_BLTQUEUE) + { + ErrorPrintf("DMA Asynch Video to System blits supported\n"); + } + if(ddcaps.dwSSBCaps & DDCAPS_BLTQUEUE) + { + ErrorPrintf("DMA Asynch System to System blits supported\n"); + } + if(ddcaps.dwSVBCaps & DDCAPS_BLTQUEUE) + { + bDMA =TRUE; + + ErrorPrintf("DMA Asynch System to Video blits supported\n"); + if(ddcaps.dwCaps & DDCAPS2_NOPAGELOCKREQUIRED) + { + ErrorPrintf("DMA Asynch page lock not required\n"); + } + else + { + bDMAPageLock =TRUE; + ErrorPrintf("DMA Asynch page lock required\n"); + } + } + } + if(ddcaps.dwCaps2 & DDCAPS_BLT) + { + ErrorPrintf("Hardware Blt supported\n"); + bHardBlt =TRUE; + } + + //commented code below used for heavy mode testing +// ddrval =lpDD4->lpVtbl->SetCooperativeLevel(lpDD4, ActiveWnd, +// DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); +// if(ddrval != DD_OK) +// { +// return 0; +// } + lpDD4->lpVtbl->EnumDisplayModes(lpDD4, 0, NULL, (LPVOID)vinfo, ModeCallback); + +// SortDDrawVideoModeList(vinfo); + + lpDD4->lpVtbl->Release(lpDD4); + lpDD4 =NULL; + + FreeLibrary(ddrawinst); + + return TRUE; +} + +void GetDDrawPixelFormat(DRV_Window *cwnd) +{ + DDPIXELFORMAT ddpf; + U32 i, j; + + ddpf.dwSize =sizeof(ddpf); + lpDDSPrimary->lpVtbl->GetPixelFormat(lpDDSPrimary, &ddpf); + + if(!(ddpf.dwFlags & DDPF_RGB)) + { + return; + } + cwnd->BytesPerPixel =ddpf.dwRGBBitCount / 8; + cwnd->R_mask =ddpf.dwRBitMask; + cwnd->G_mask =ddpf.dwGBitMask; + cwnd->B_mask =ddpf.dwBBitMask; + + for(j=0,i=ddpf.dwRBitMask;!(i & 1);i>>=1,j++); + cwnd->R_shift =j; + + for(j=0,i=ddpf.dwGBitMask;!(i & 1);i>>=1,j++); + cwnd->G_shift =j; + + for(j=0,i=ddpf.dwBBitMask;!(i & 1);i>>=1,j++); + cwnd->B_shift =j; + + for(i=(ddpf.dwRBitMask>>cwnd->R_shift),cwnd->R_width=0;i;i >>= 1, cwnd->R_width++); + for(i=(ddpf.dwGBitMask>>cwnd->G_shift),cwnd->G_width=0;i;i >>= 1, cwnd->G_width++); + for(i=(ddpf.dwBBitMask>>cwnd->B_shift),cwnd->B_width=0;i;i >>= 1, cwnd->B_width++); +} + +LPDIRECTDRAWSURFACE4 DDrawLoadSurface(U32 dwWidth, U32 dwHeight, const void *pixels, const char *pal) +{ + LPDIRECTDRAWSURFACE4 lpDDS; + DDSURFACEDESC2 ddsd; + HRESULT ddrval; + int i; + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(DDSURFACEDESC2); + ddsd.dwFlags =DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_CKSRCBLT; + ddsd.ddsCaps.dwCaps =DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddsd.dwHeight =dwHeight; + ddsd.dwWidth =dwWidth; + + ddsd.ddckCKSrcBlt.dwColorSpaceLowValue =((((U8 *)pal)[765])<<16) + |((((U8 *)pal)[766])<<8) + |(((U8 *)pal)[767]); + ddsd.ddckCKSrcBlt.dwColorSpaceHighValue =((((U8 *)pal)[765])<<16) + |((((U8 *)pal)[766])<<8) + |(((U8 *)pal)[767]); + + + ddrval =lpDD4->lpVtbl->CreateSurface(lpDD4, &ddsd, &lpDDS, NULL); + + if(ddrval != DD_OK) + { + return NULL; + } + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(DDSURFACEDESC2); + ddrval =lpDDS->lpVtbl->Lock(lpDDS, NULL, &ddsd, DDLOCK_WAIT, NULL); + + if(ddrval != DD_OK) + { + lpDDS->lpVtbl->Release(lpDDS); + return NULL; + } + + for(i=0;i < (S32)(dwHeight * dwWidth);i++) + { + ((U32 *)ddsd.lpSurface)[i] =(((U8 *)pal)[(((U8 *)pixels)[i]) * 3])<<16 + |((((U8 *)pal)[((((U8 *)pixels)[i]) * 3)+1])<<8) + |((((U8 *)pal)[((((U8 *)pixels)[i]) * 3)+2])<<0); + } + + lpDDS->lpVtbl->Unlock(lpDDS, NULL); + + return lpDDS; +} + +char* MyErrorToString(HRESULT error) +{ + switch(error) { + case DD_OK: + /* Also includes D3D_OK and D3DRM_OK */ + return "No error.\0"; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized.\0"; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0"; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface.\0"; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface.\0"; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs.\0"; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0"; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0"; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation.\0"; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available.\0"; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process.\0"; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation.\0"; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive.\0"; + case DDERR_GENERIC: + return "Generic failure.\0"; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment.\0"; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created.\0"; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state.\0"; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface.\0"; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface.\0"; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect.\0"; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist.\0"; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0"; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode.\0"; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0"; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect.\0"; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified.\0"; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0"; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid.\0"; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked.\0"; + case DDERR_NO3D: + return "There is no 3D present.\0"; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0"; + case DDERR_NOBLTHW: + return "No blitter hardware present.\0"; + case DDERR_NOCLIPLIST: + return "No cliplist available.\0"; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object.\0"; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or available.\0"; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key\0"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color key.\0"; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0"; + case DDERR_NODC: + return "No DC was ever created for this surface.\0"; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware.\0"; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0"; + case DDERR_NOEMULATION: + return "Software emulation not available.\0"; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive mode.\0"; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported.\0"; + case DDERR_NOGDI: + return "There is no GDI present.\0"; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0"; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available.\0"; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination.\0"; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available.\0"; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface.\0"; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes.\0"; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0"; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available.\0"; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching.\0"; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0"; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0"; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0"; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface.\0"; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable.\0"; + case DDERR_NOTFOUND: + return "Requested item was not found.\0"; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, has been attempted.\0"; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface.\0"; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations.\0"; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0"; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated.\0"; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays.\0"; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays.\0"; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread.\0"; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface.\0"; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small.\0"; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to.\0"; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of.\0"; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread.\0"; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured.\0"; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.\0"; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached.\0"; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large.\0"; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large.\0"; + case DDERR_UNSUPPORTED: + return "Action not supported.\0"; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw.\0"; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress.\0"; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete.\0"; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode.\0"; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary.\0"; + default: + return "Unrecognized error value.\0"; + } +} + +BOOL DDrawBlitDecal(LPDIRECTDRAWSURFACE4 lpDDSDecal, RECT *SRect, S32 x, S32 y) +{ + HRESULT ddrval; + DDSURFACEDESC2 ddsd; + RECT rDest; + char szTemp[256]; + + //make sure the back buffer is unlocked (for stretch) +/* if(bBackLocked) + { + ddrval =lpDDSBack->lpVtbl->Unlock(lpDDSBack, NULL); + if(ddrval!=DD_OK && ddrval!=DDERR_NOTLOCKED) + { + ErrorPrintf(MyErrorToString(ddrval)); + return TRUE; + } + } + bBackLocked =FALSE; +*/ + + if(SRect) + { + rDest.left =x; + rDest.top =y; + rDest.right =x + (SRect->right - SRect->left); + rDest.bottom=y + (SRect->bottom- SRect->top); + } + else + { + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + lpDDSDecal->lpVtbl->GetSurfaceDesc(lpDDSDecal, &ddsd); + + rDest.left =x; + rDest.top =y; + rDest.right =x + ddsd.dwWidth; + rDest.bottom=y + ddsd.dwHeight; + } + + ddrval =DD_OK; + while(1) + { + if(SRect) + { + ddrval =lpDDSBack->lpVtbl->Blt(lpDDSBack, &rDest, lpDDSDecal, SRect, DDBLT_WAIT | DDBLT_KEYSRC, NULL); + } + else + { + ddrval =lpDDSBack->lpVtbl->Blt(lpDDSBack, &rDest, lpDDSDecal, NULL, DDBLT_WAIT | DDBLT_KEYSRC, NULL); + } + if(ddrval==DD_OK) + break; + + if(ddrval==DDERR_SURFACELOST) + { + ddrval =RestoreAll(); + if(ddrval!=DD_OK) + { + ErrorPrintf("Error During Blt() in DDrawBltDecal()...\n"); + ErrorPrintf("DirectDraw Surfaces were lost and could not be restored : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + ErrorPrintf("Error During Blt() in DDrawBltDecal() : %s\n", MyErrorToString(ddrval)); + if(SRect) + { + sprintf(szTemp, "SLeft:%d, STop:%d, SRight:%d, SBottom:%d\n", SRect->left, SRect->top, SRect->right, SRect->bottom); + ErrorPrintf(szTemp); + } + sprintf(szTemp, "DLeft:%d, DTop:%d, DRight:%d, DBottom:%d\n%x", rDest.left, rDest.top, rDest.right, rDest.bottom, (U32)lpDDSDecal); + ErrorPrintf(szTemp); + return FALSE; + } + } + return TRUE; +} + +BOOL DDrawBlitDecalToFront(LPDIRECTDRAWSURFACE4 lpDDSDecal, RECT *SRect, S32 x, S32 y) +{ + HRESULT ddrval; + DDSURFACEDESC2 ddsd; + RECT rDest; + char szTemp[256]; + + if(SRect) + { + rDest.left =x; + rDest.top =y; + rDest.right =x + (SRect->right - SRect->left); + rDest.bottom=y + (SRect->bottom- SRect->top); + } + else + { + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + lpDDSDecal->lpVtbl->GetSurfaceDesc(lpDDSDecal, &ddsd); + + rDest.left =x; + rDest.top =y; + rDest.right =x + ddsd.dwWidth; + rDest.bottom=y + ddsd.dwHeight; + } + + ddrval =DD_OK; + while(1) + { + if(SRect) + { + ddrval =lpDDSPrimary->lpVtbl->Blt(lpDDSPrimary, &rDest, lpDDSDecal, SRect, DDBLT_WAIT | DDBLT_KEYSRC, NULL); + } + else + { + ddrval =lpDDSPrimary->lpVtbl->Blt(lpDDSPrimary, &rDest, lpDDSDecal, NULL, DDBLT_WAIT | DDBLT_KEYSRC, NULL); + } + if(ddrval==DD_OK) + break; + + if(ddrval==DDERR_SURFACELOST) + { + ddrval =RestoreAll(); + if(ddrval!=DD_OK) + { + ErrorPrintf("Error During Blt() in DDrawBltDecalToFront()...\n"); + ErrorPrintf("DirectDraw Surfaces were lost and could not be restored : %s\n", MyErrorToString(ddrval)); + return FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + ErrorPrintf("Error During Blt() in DDrawBltDecalToFront() : %s\n", MyErrorToString(ddrval)); + if(SRect) + { + sprintf(szTemp, "SLeft:%d, STop:%d, SRight:%d, SBottom:%d\n", SRect->left, SRect->top, SRect->right, SRect->bottom); + ErrorPrintf(szTemp); + } + sprintf(szTemp, "DLeft:%d, DTop:%d, DRight:%d, DBottom:%d\n%x", rDest.left, rDest.top, rDest.right, rDest.bottom, (U32)lpDDSDecal); + ErrorPrintf(szTemp); + return FALSE; + } + } + return TRUE; +} + +BOOL DDrawBlitDecalDelayed(LPDIRECTDRAWSURFACE4 lpDDSDecal, RECT *SRect, S32 x, S32 y) +{ + DecalQ[NumDecalsQd].surf =lpDDSDecal; + if(SRect) + { + DecalQ[NumDecalsQd].srect =*SRect; + } + else + { + DecalQ[NumDecalsQd].srect.left =-1; + } + DecalQ[NumDecalsQd].x =x; + DecalQ[NumDecalsQd].y =y; + + if(NumDecalsQd < 8191) + { + NumDecalsQd++; + } + return TRUE; +} + +void ClearBackBuffer(DRV_Window *cwnd) +{ + DDBLTFX bfx; + + if(!bActive) + { + return; + } + + memset(&bfx, 0, sizeof(bfx)); + bfx.dwSize =sizeof(bfx); + bfx.dwFillColor =0; + + lpDDSBack->lpVtbl->Blt(lpDDSBack, NULL, NULL, NULL, DDBLT_COLORFILL, &bfx); +} + +geBoolean DRIVERCC DrvSetActive(geBoolean wParam) +{ + bActive =wParam; + + if(bInitDone && bActive) + { //regaining focus + ErrorPrintf("Regaining Focus\n"); + OutputDebugString("Regaining Focus\n"); + if(lpDDSPrimary->lpVtbl->IsLost(lpDDSPrimary)==DDERR_SURFACELOST) + { + if(RestoreAll()==DD_OK) + { + ErrorPrintf("Regained focus and restored all DirectDraw surfaces\n"); + OutputDebugString("Regained focus and restored all DirectDraw surfaces\n"); + ShowWindow(mhWnd, SW_SHOWNORMAL); //dx doesn't restore it + } + else + { + ErrorPrintf("Couldn't restore surfaces!\n"); + OutputDebugString("Couldn't restore surfaces!\n"); + } + } + else + { + ErrorPrintf("Regained focus, no surfaces lost\n"); + OutputDebugString("Regained focus, no surfaces lost\n"); + } + } + else + { + ErrorPrintf("Lost Focus\n"); + OutputDebugString("Lost Focus\n"); + } + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/SoftDrv/dmodes.h b/G3D/Engine/Drivers/SoftDrv/dmodes.h new file mode 100644 index 0000000..9a0e5a5 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/dmodes.h @@ -0,0 +1,42 @@ +/****************************************************************************************/ +/* dmodes.h */ +/* */ +/* Author: Ken Baird */ +/* Description: Directdraw related stuff */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "basetype.h" + +extern void GetDDrawPixelFormat(DRV_Window *cwnd); +extern LPDIRECTDRAWSURFACE4 DDrawLoadSurface(U32 dwWidth, U32 dwHeight, const void *pixels, const char *pal); +extern geBoolean LockDDrawBackBuffer(DRV_Window *cwnd, RECT *wrect); +extern geBoolean UnlockDDrawBackBuffer(DRV_Window *cwnd, RECT *wrect); +extern geBoolean RefreshDDraw(DRV_Window *cwnd, VidModeList *cmode, RECT *src, RECT *dst); +extern void ClearBackBuffer(DRV_Window *cwnd); +extern geBoolean DDrawBlitDecal(LPDIRECTDRAWSURFACE4 lpDDSDecal, RECT *SRect, S32 x, S32 y); +extern geBoolean DDrawBlitDecalDelayed(LPDIRECTDRAWSURFACE4 lpDDSDecal, RECT *SRect, S32 x, S32 y); +extern geBoolean DDrawBlitDecalToFront(LPDIRECTDRAWSURFACE4 lpDDSDecal, RECT *SRect, S32 x, S32 y); +extern geBoolean DRIVERCC DrvSetActive(geBoolean wParam); +extern void SetDDrawWindow(HWND hwnd); +extern geBoolean SetDDrawMode(U32 top, VidEnumInfo *vinfo); +extern geBoolean DoDDrawInit(HWND hwnd, VidEnumInfo *vinfo); +extern geBoolean DoModeEnumeration(VidEnumInfo *vinfo); +extern geBoolean DoEnumeration(VidEnumInfo *vinfo); +extern void GetDDrawPixelFormat(DRV_Window *cwnd); +extern void FreeDDraw(VidEnumInfo *vinfo); + +extern geBoolean bWindowed, bActive, bBackLocked; diff --git a/G3D/Engine/Drivers/SoftDrv/drawspan.c b/G3D/Engine/Drivers/SoftDrv/drawspan.c new file mode 100644 index 0000000..31073f4 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/drawspan.c @@ -0,0 +1,1263 @@ +/****************************************************************************************/ +/* drawspan.c */ +/* */ +/* Author: Ken Baird */ +/* Description: Mostly unused code, a few needed vars, some renderstates that can */ +/* be used for post poly zfill, and some z correctors with more accuracy */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +/* +Code fragments from Chris Hecker's texture mapping articles used with +permission. http://www.d6.com/users/checker +*/ + +#include +#include +#include + +#include "BaseType.h" +#include "Render.h" +#include "SoftDrv.h" +#include "drawspan.h" + + +double MipMagic, MipMagic2; + +int32 R1, B1, G1, R2, G2, B2; +int32 RR1, RR2, GG1, GG2, BB1, BB2; +int32 StepR, StepG, StepB; +int32 UDist, VDist; +int32 U1=0, V1=0, NumSpans=0; +int32 CKeyTest=0; + +geFloat FloatTemp, FTemp0, FTemp1, FTemp2; +geFloat FTemp3, FTemp4, FTemp5, FTemp6, FTemp7, FTemp8; +geFloat const One =1.0f; +geFloat const Two =2.0f; + +extern U32 UMask, VShift, VMask; +int32 ZDelta, ZVal; +geFloat ZBufferPrec = (geFloat)-ZBUFFER_PREC; +__int64 RedDelta, GreenDelta, BlueDelta; +uint32 NumASpans, RemainingCount; +double DeltaU, DeltaV; +uint32 UFixed, VFixed; +uint8 *pTex; + + + +void DrawSpan16_AsmX86FPU(int32 x1, int32 x2, int32 y) +{ + _asm + { + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + inc ecx + shr edi, 1 ; keep texture >>1 + mov pTex,edi + + fild [y] ; y + + mov edi, ClientWindow.Buffer + mov eax, y + imul eax, ClientWindow.Width + add eax, x1 + shl eax, 1 + add edi, eax + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [x1] ; x y + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + //need those fxch to line things up for loops (bad) + + fld1 ; 1 UZR ZRi VZR UL VL + + + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,16 + mov dword ptr[Bucket],ebx + + sub ecx,[VShift] + mov dword ptr[Bucket2],eax + + shr eax,cl + + push ebp + shr ebx,16 + + and eax,[GHMaskShifted] + mov esi,[pTex] + + and ebx,[GWMask] + add esi,eax + + mov ecx,[VShift] + add esi,ebx + + mov edx,dword ptr[Bucket2] + mov ebp,dword ptr[DeltaV] + + mov ebx,dword ptr[Bucket] + + //do 16 pixels + + add edx,ebp + mov ax,[2*esi] + + mov esi,edx + add ebx,dword ptr[DeltaU] + + shl esi,cl + and ebx,[GWMaskShifted] + + and esi,[GHMaskShifted16] + + add esi,ebx + mov [edi+0],ax + + shr esi,16 + add edx,ebp + + add esi,pTex + add ebx,dword ptr[DeltaU] + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+2],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+4],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+6],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+8],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+10],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+12],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+14],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+16],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+18],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+20],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+22],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+24],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+26],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+28],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + pop ebp + mov [edi+30],ax + + ;get corrected right side deltas; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 ; loop back + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + mov ecx,16 + add ebx,dword ptr[UAdjust2] + + sub ecx,[VShift] + add edx,dword ptr[VAdjust2] + +OnePixelSpan16: + push ebp + +LeftoverLoop16: + mov eax,edx + shr eax,cl + mov ebp,ebx + and eax,[GHMaskShifted] + shr ebp,16 + and ebp,[GWMask] + add eax,ebp + add eax,esi + mov ax,[2*eax] + mov [edi],ax + add ebx,dword ptr[DeltaU] + add edi,2 + add edx,dword ptr[DeltaV] + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + } +} + +void DrawSpan16_8AsmLitX86FPU(int32 x1, int32 x2, int32 y) +{ + _asm + { + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + inc ecx + shr edi, 1 ; keep texture >>1 + mov pTex,edi + + fild [y] ; y + + mov edi, ClientWindow.Buffer + mov eax, y + imul eax, ClientWindow.Width + add eax, x1 + shl eax, 1 + add edi, eax + mov eax,ecx + shr ecx,3 + and eax,7 + _emit 75h + _emit 06h + dec ecx + mov eax,8 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [x1] ; x y + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + //need those fxch to line things up for loops (bad) + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + fld1 ; 1 UZR ZRi VZR UL VL + + // Cache U1/V1 + mov ebx,dword ptr[UFixed] + + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + + mov eax,dword ptr[VFixed] + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,16 + mov dword ptr[Bucket],ebx + + sub ecx,[VShift] + mov dword ptr[Bucket2],eax + + shr eax,cl + + push ebp + shr ebx,16 + + and eax,[GHMaskShifted] + mov esi,[pTex] + + and ebx,[GWMask] + add esi,eax + + mov ecx,[VShift] + add esi,ebx + + mov edx,dword ptr[Bucket2] + mov ebp,dword ptr[DeltaV] + + mov ebx,dword ptr[Bucket] + + //do 8 pixels + + add edx,ebp + mov ax,[2*esi] + + mov esi,edx + add ebx,dword ptr[DeltaU] + + shl esi,cl + and ebx,[GWMaskShifted] + + and esi,[GHMaskShifted16] + + add esi,ebx + mov [edi+0],ax + + shr esi,16 + add edx,ebp + + add esi,pTex + add ebx,dword ptr[DeltaU] + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+2],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+4],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+6],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+8],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+10],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + and ebx,[GWMaskShifted] + mov [edi+12],ax + + shl esi,cl + add edx,ebp + + and esi,[GHMaskShifted16] + + add esi,ebx + shr esi,16 + + add ebx,dword ptr[DeltaU] + add esi,pTex + + mov ax,[2*esi] + mov esi,edx + + pop ebp + mov [edi+14],ax + + ;get corrected right side deltas; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,16 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 ; loop back + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + // Cache U1/V1 + mov ebx,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + mov ecx,16 + add ebx,dword ptr[UAdjust2] + + sub ecx,[VShift] + add edx,dword ptr[VAdjust2] + +// mov dword ptr[Bucket],ebx +// mov dword ptr[Bucket2],eax + +OnePixelSpan16: + push ebp + +LeftoverLoop16: + mov eax,edx + shr eax,cl + mov ebp,ebx + and eax,[GHMaskShifted] + shr ebp,16 + and ebp,[GWMask] + add eax,ebp + add eax,esi + mov ax,[2*eax] + mov [edi],ax + add ebx,dword ptr[DeltaU] + add edi,2 + add edx,dword ptr[DeltaV] + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + } +// LightCachedSpan16_AsmLerpLUT(x1, x2, y); +// LightCachedSpan16_AsmLerpFPU(x1, x2, y); +} + + diff --git a/G3D/Engine/Drivers/SoftDrv/drawspan.h b/G3D/Engine/Drivers/SoftDrv/drawspan.h new file mode 100644 index 0000000..c724801 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/drawspan.h @@ -0,0 +1,69 @@ +/****************************************************************************************/ +/* drawspan.h */ +/* */ +/* Author: Ken Baird */ +/* Description: header for span draw code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include "softdrv.h" +#include "basetype.h" + +typedef struct EdgeAsmFPUTag EdgeAsmFPU; + +extern uint16 *TDest, *pZBufferPtr, *Dest; +extern __int64 Red, Green; +extern geFloat Real65536; +extern double Bucket, Bucket2, Bucket3, Magic, RedMask, RedMask2; +extern uint32 UMask, VShift, VMask, TempPix, Blue; +static uint32 VStep, UStep, ZStep, u16, v16, z16, Z32; + +extern geFloat const Two, MiniRedMask, GreenMask; +extern geFloat const MiniRedMask2, GreenMask2, BlueMask; +extern geFloat FloatTemp, FTemp0, FTemp1, FTemp2; +extern geFloat FTemp3, FTemp4, FTemp5, FTemp6, FTemp7, FTemp8; + +extern int32 GHMaskShifted, GHMaskShifted16, GWMaskShifted, GWMask, widTemp; +extern uint8 *GBitPtrHalf; +extern double MipMagic; +extern double MipMagic2; + +extern uint32 NumASpans, RemainingCount; +extern double DeltaU, DeltaV, DeltaW; +extern uint32 UFixed, VFixed, WLeft; +extern uint8 *pTex; + +extern int32 R1, B1, G1, R2, G2, B2; +extern int32 RR1, RR2, GG1, GG2, BB1, BB2; +extern int32 StepR, StepG, StepB; +extern int32 UDist, VDist; +extern int32 U1, V1, CKeyTest; +extern geFloat GLMapMulU; //lightscale +extern geFloat GLMapMulV; //lightscale +extern int32 ZDelta, ZVal; +extern geFloat ZBufferPrec; +extern __int64 RedDelta, GreenDelta, BlueDelta; + + +//555 +#define REDMASK2 0x7c007c00; +#define GREENMASK2 0x03e003e0; +#define BLUEMASK2 0x001f001f; + +//565 +#define REDMASK 0xf800f800; +#define GREENMASK 0x07e007e0; +#define BLUEMASK 0x001f001f; diff --git a/G3D/Engine/Drivers/SoftDrv/mssccprj.scc b/G3D/Engine/Drivers/SoftDrv/mssccprj.scc new file mode 100644 index 0000000..44c8175 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/mssccprj.scc @@ -0,0 +1,4 @@ +SCC = This is a Source Code Control file + +[SoftDrv.mak] +SCC_Project_Name = "$/Genesis10/Source/Engine/Drivers/SoftDrv", JSQBAAAA diff --git a/G3D/Engine/Drivers/SoftDrv/register.c b/G3D/Engine/Drivers/SoftDrv/register.c new file mode 100644 index 0000000..9d2acc6 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/register.c @@ -0,0 +1,401 @@ +/****************************************************************************************/ +/* register.c */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: Texture Handle related code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "SoftDrv.h" +#include "DCommon.h" +#include "Register.h" +#include "Sal.h" +#include "ddraw.h" + +geRDriver_THandle TextureHandles[MAX_TEXTURE_HANDLES]; + +S32 SnapToPower2(S32 Width); +S32 Log2(S32 P2); + +extern CPUInfo ProcessorInfo; + +//======================================================================================== +// FindTextureHandle +//======================================================================================== +geRDriver_THandle *FindTextureHandle() +{ + int32 i; + geRDriver_THandle *THandle; + + THandle = TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, THandle++) + { + if (!THandle->Active) + { + memset(THandle, 0, sizeof(geRDriver_THandle)); + + THandle->Active = GE_TRUE; + + return THandle; + } + } + + return NULL; +} + +//======================================================================================== +// FreeTextureHandle +//======================================================================================== +geBoolean FreeTextureHandle(geRDriver_THandle *THandle) +{ + int k; + + assert(THandle); +//<> assert(THandle->Active == GE_TRUE); + + if( ! THandle->Active ) + { + return GE_FALSE; + } + + if(THandle->PalHandle) + { + FreeTextureHandle(THandle->PalHandle); + } + + if(THandle->AlphaHandle) + { + FreeTextureHandle(THandle->AlphaHandle); + } + + for(k=0;k < THandle->MipLevels;k++) + { + if(!ProcessorInfo.Has3DNow) + { + if(THandle->BitPtr[k]) + { + free(THandle->BitPtr[k]); + } + } + THandle->BitPtr[k] =NULL; + } + + memset(THandle, 0, sizeof(geRDriver_THandle)); + + return GE_TRUE; +} + +//================================================================================== +// FreeAllTextureHandles +//================================================================================== +geBoolean FreeAllTextureHandles(void) +{ + int32 i; + geRDriver_THandle *pTHandle; + + pTHandle = TextureHandles; + +#ifdef _DEBUG + OutputDebugString("FreeAllTextureHandles\n"); +#endif + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pTHandle++) + { + if (!pTHandle->Active) + { + continue; + } + + FreeTextureHandle(pTHandle); + } + + return GE_TRUE; +} + +geRDriver_THandle *DRIVERCC CreateTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) +{ + int32 i, SWidth, SHeight; // Snapped to power of 2 width/height + geRDriver_THandle *THandle; + + assert(PixelFormat); + + THandle = FindTextureHandle(); + + if (!THandle) + { + SetLastDrvError(DRV_ERROR_GENERIC, "SOFT_CreateTexture: No more handles left."); + goto ExitWithError; + } + + if(PixelFormat->Flags & RDRIVER_PF_3D) + { + if (Width > 256) + { + SetLastDrvError(DRV_ERROR_GENERIC, "SOFT_CreateTexture: Width > 256."); + goto ExitWithError; + } + + if (Height > 256) + { + SetLastDrvError(DRV_ERROR_GENERIC, "SOFT_CreateTexture: Height > 256."); + goto ExitWithError; + } + SWidth = SnapToPower2(Width); + SHeight = SnapToPower2(Height); + + if (Width != SWidth) + { + SetLastDrvError(DRV_ERROR_GENERIC, "SOFT_CreateTexture: Not a power of 2."); + goto ExitWithError; + } + + if (Height != SHeight) + { + SetLastDrvError(DRV_ERROR_GENERIC, "SOFT_CreateTexture: Not a power of 2."); + goto ExitWithError; + } + } + + THandle->MipLevels =NumMipLevels; + THandle->Width =Width; + THandle->Height =Height; + THandle->PixelFormat =*PixelFormat; + THandle->Flags =0; + + for(i=0;i < NumMipLevels;i++) + { + if(PixelFormat->Flags & RDRIVER_PF_PALETTE) + { + if( PixelFormat->PixelFormat == GE_PIXELFORMAT_32BIT_ARGB || + PixelFormat->PixelFormat == GE_PIXELFORMAT_32BIT_XRGB ) // <> CB added XRGB + { + THandle->BitPtr[i] =(U16 *)malloc(sizeof(U32) * Width * Height); + } + else + { + SetLastDrvError(DRV_ERROR_GENERIC, "SOFT_CreateTexture: Bad Pal format."); + goto ExitWithError; + } + } + else + { + switch (PixelFormat->PixelFormat) + { + case GE_PIXELFORMAT_16BIT_565_RGB: + { + THandle->BitPtr[i] =(U16 *)malloc(sizeof(U16) * Width * Height); + break; + } + + case GE_PIXELFORMAT_16BIT_555_RGB: + { + THandle->BitPtr[i] =(U16 *)malloc(sizeof(U16) * Width * Height); + break; + } + + case GE_PIXELFORMAT_8BIT: + { + THandle->BitPtr[i] =(U16 *)malloc(sizeof(U8) * Width * Height); + break; + } + + case GE_PIXELFORMAT_24BIT_RGB: + { + THandle->BitPtr[i] =(U16 *)malloc((sizeof(U8)*3) * Width * Height); + break; + } + + default: + { + SetLastDrvError(DRV_ERROR_GENERIC, "SOFT_Create3DTexture: Invalid pixel format."); + goto ExitWithError; +// THandle->BitPtr[i] =(U16 *)malloc(sizeof(U16) * Width * Height); +// break; + } + } + + if ( PixelFormat->Flags & RDRIVER_PF_CAN_DO_COLORKEY ) + { + THandle->Flags |= THANDLE_TRANS; + } + } + } + + return THandle; + + ExitWithError: + { + return NULL; + } +} + +geBoolean DRIVERCC THandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info) +{ + assert(THandle); + assert(Info); +#ifdef _DEBUG + if ( ! THandle->Active ) + return GE_FALSE; +#endif + + Info->Width = THandle->Width >> MipLevel; + Info->Height = THandle->Height >> MipLevel; + Info->Stride = Info->Width; + Info->Flags = 0; + Info->PixelFormat =THandle->PixelFormat; + + if ( ProcessorInfo.Has3DNow ) + Info->ColorKey = 255; + else + Info->ColorKey = 1; + + if ( THandle->Flags & THANDLE_TRANS ) + { + Info->Flags |= RDRIVER_THANDLE_HAS_COLORKEY; + } + + return GE_TRUE; +} + +//can be used to null out the pal (cant assert on palhandle) +geBoolean DRIVERCC SetPalette(geRDriver_THandle *THandle, geRDriver_THandle *PalHandle) +{ + assert(THandle); + + THandle->PalHandle =PalHandle; + + return GE_TRUE; +} + +//can be used to null out the pal (cant assert on palhandle) +geRDriver_THandle *DRIVERCC GetPalette(geRDriver_THandle *THandle) +{ + assert(THandle); +#ifdef _DEBUG + if ( ! THandle->Active ) + return GE_FALSE; +#endif + + return THandle->PalHandle; +} + +geBoolean DRIVERCC SetAlpha(geRDriver_THandle *THandle, geRDriver_THandle *AHandle) +{ + assert(THandle); +#ifdef _DEBUG + if ( ! THandle->Active ) + return GE_FALSE; +#endif + + if(THandle->PixelFormat.Flags & RDRIVER_PF_HAS_ALPHA) + { + if(AHandle->PixelFormat.Flags & RDRIVER_PF_ALPHA) + { + THandle->AlphaHandle =AHandle; + return GE_TRUE; + } + } + return GE_FALSE; +} + +geRDriver_THandle *DRIVERCC GetAlpha(geRDriver_THandle *THandle) +{ + assert(THandle); +#ifdef _DEBUG + if ( ! THandle->Active ) + return GE_FALSE; +#endif + + return THandle->AlphaHandle; +} + +geBoolean DRIVERCC DestroyTexture(geRDriver_THandle *THandle) +{ + return FreeTextureHandle(THandle); +} + +geBoolean DRIVERCC LockTextureHandle(geRDriver_THandle *THandle, int32 MipLevel, void **Data) +{ + assert(THandle); + assert(MipLevel <= THandle->MipLevels && MipLevel >= 0); +#ifdef _DEBUG + if ( ! THandle->Active ) + return GE_FALSE; + if ( ! THandle->BitPtr[MipLevel] ) + return GE_FALSE; +#endif + + THandle->Flags |=(THANDLE_LOCKED << MipLevel); + *Data =(uint16*)THandle->BitPtr[MipLevel]; + + return GE_TRUE; +} + +geBoolean DRIVERCC UnLockTextureHandle(geRDriver_THandle *THandle, int32 MipLevel) +{ + assert(THandle); + if (!(THandle->Flags & (THANDLE_LOCKED << MipLevel))) + return GE_FALSE; + + THandle->Flags &=~(THANDLE_LOCKED << MipLevel); // This mip is now unlocked + THandle->Flags |=THANDLE_UPDATE; // Mark it for updating... + + return GE_TRUE; +} + +BOOL DRIVERCC DrvResetAll(void) +{ + return FreeAllTextureHandles(); +} + + +static int Brighten(int Color) +{ + Color =(int)((geFloat)Color * 1.5f); + + return((Color > 255)? 255 : Color); +} + + +S32 SnapToPower2(S32 Width) +{ + if (Width > 1 && Width <= 2) Width = 2; + else if (Width > 2 && Width <= 4) Width = 4; + else if (Width > 4 && Width <= 8) Width = 8; + else if (Width > 8 && Width <= 16) Width =16; + else if (Width > 16 && Width <= 32) Width = 32; + else if (Width > 32 && Width <= 64) Width = 64; + else if (Width > 64 && Width <= 128) Width = 128; + else if (Width > 128 && Width <= 256) Width = 256; + + return Width; +} + +S32 Log2(S32 P2) +{ + S32 p = 0; + S32 i = 0; + + for (i = P2; (i&1) == 0; i>>=1) + p++; + + return p; +} diff --git a/G3D/Engine/Drivers/SoftDrv/render.c b/G3D/Engine/Drivers/SoftDrv/render.c new file mode 100644 index 0000000..7f94465 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/render.c @@ -0,0 +1,3418 @@ +/****************************************************************************************/ +/* render.c */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: Poly raster calls and data structures */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +/* +Code fragments from Chris Hecker's texture mapping articles used with +permission. http://www.d6.com/users/checker +*/ + +#include +#include +#include +#include + +#include "SoftDrv.h" +#include "DCommon.h" +#include "Render.h" +#include "Span.h" +#include "Scene.h" +#include "Sal.h" +#include "Register.h" +#include "3dnowspan.h" +#include "x86span565.h" +#include "x86span555.h" +#include "XForm3d.h" +#include "Vec3d.h" +#include "dmodes.h" + + + + +extern CPUInfo ProcessorInfo; + +typedef struct EdgeAsmWorldTag +{ + int X, y, Height; + geFloat x, r, g, b; + geFloat xstep, rstep, gstep, bstep; + U32 R, G, B, X2, pad; //x2 for clip check +} EdgeAsmWorld; + +typedef struct EdgeAsmTag +{ + int X, y, Height; + geFloat x, u, v, z, r, g, b; + geFloat xstep, ustep, vstep, zstep; + geFloat rstep, gstep, bstep; +} EdgeAsm; + +typedef struct EdgeAsmFPUTag +{ + int X, y, Height; + geFloat x, u, v, z, r, g, b; + geFloat xstep, ustep, vstep, zstep; + geFloat rstep, gstep, bstep; + U32 R, G, B; +} EdgeAsmFPU; + +//globals used in span rendering routines +__int64 Bucket, Bucket2, Bucket3, Magic, Red, Green; +uint32 Blue, UMask, VShift, VMask, widTemp, TDest, TempPix; + +geFloat BlueMask =0x001f001f; +geFloat GreenMask =0x07e007e0; +geFloat MiniRedMask =0xf800f800; +double RedMask =0xf800f800; +geFloat GreenMask2 =0x03e003e0; +geFloat MiniRedMask2=0x7c007c00; +double RedMask2 =0x7c007c00; + + +S32 SpanMode; +S32 PolyMode; +BOOL PolyIsTrans; +BOOL bStipple; + +BOOL PolyVisible; +S32 ActuallVisible; +S32 NumPixels; + +S32 SMIN, SMAX; +U8 GMipLevel; // Miplevel passed by the latest rendering routine +int32 GMipLevel4, GMipLevel20, GMipLevel4_8; +S32 GLMapAdd; + +DRV_LInfo *GLInfo; +DRV_Bitmap *GBitmap; +geRDriver_THandle *GTexture; + +U16 *pScrPtr16bpp; +U32 *pScrPtr32bpp; +extern U16 *pZBufferPtr=0; + +int32 GLightWidth; +uint8 *GLightData; + +int32 DeltaX, Remaining, N_Runs, PixelCount; +uint16 *Source, *Dest; +int32 U2, V2, StepU, StepV; +geFloat UDivZ, VDivZ, Zi, Z, Dx, Dy, PixelEnd; +int32 TxWhole, TyWhole, TxFract, TyFract; +geFloat UDivZnStepX, VDivZnStepX, ZinStepX; +int32 Junk[2]; + +geFloat Real16 = 16.0f; +geFloat Real65536 = (geFloat)65536; + +int32 U, V; + +S32 GW, GWMask, GWMaskShifted; +S32 GH, GHMask, GHMaskShifted, GHMaskShifted16; +__int64 QNegAlpha =0x00ff00ff00ff00ff; +U32 SolidColor =0xffffffff; +U8 *GBitPtr; +U8 *GBitPtrHalf; +U8 *ABitPtr; +U16 *GBitPtr16; +U8 *TexPal; +U8 *ATexPal; +__int64 UV16=0, UVLeft=0, UVLeftW=0; +__int64 UVDivZ16StepX=0, ARL=0, GBL=0; +__int64 WrapMask=0; +__int64 UVLeft2=0; +__int64 UVDivZOrigin=0, UVR=0; +__int64 ZIR=0, RGBADelta=0; +__int64 UVDivZStepX=0, UVDivZStepY; +__int64 Zero=0, UVZ=0, UVAdjustL=0; +__int64 GLMapMulUV=0, UVL16=0, UV162=0; +__int64 LMapMask8=0x000000ff000000ff; +__int64 UVAdjust=0, UVAdjust2=0; +__int64 QGMip20=0, QGMip4_8=0; +__int64 QDibCan=0, QZCan=0, VertAlpha=0; +__int64 QDibOrCan=0, QZOrCan=0; +__int64 QZVal=0, QZDelta=0, UV16V=0; +__int64 QZOut=0, QDibOut=0, QShiftV=0; +__int64 QZVal32_0=0, QZVal32_1=0; +geFloat QFixedScaleLUT[34]={ 0.0f, 0.0f, 65536.0f, 65536.0f, 32768.0f, 32768.0f, + 21845.3333f, 21845.3333f, 16384.0f, 16384.0f, + 13107.2f, 13107.2f, 10922.6666f, 10922.6666f, + 9362.2857f, 9362.2857f, 8192.0f, 8192.0f, + 7281.7777f, 7281.7777f, 6553.6f, 6553.6f, + 5957.8181f, 5957.8181f, 5461.3333f, 5461.3333f, + 5041.2307f, 5041.2307f, 4681.1428f, 4681.1428f, + 4369.0666f, 4369.0666f, 4096.0f, 4096.0f }; +int SCan[16]; //for zbuffer fake ptr +geFloat GLMapMulU; //lightscale +geFloat GLMapMulV; //lightscale + +// 16bit zbuffer +U16 *ZBuffer; +uint16 *ZBufLine; + +// Gradients info +geFloat UDivZStepX; +geFloat UDivZStepY; +geFloat VDivZStepX; +geFloat VDivZStepY; + +geFloat UDivZOrigin; +geFloat VDivZOrigin; +geFloat UDivZ16StepX, VDivZ16StepX, Zi16StepX; +geFloat UDivZ32StepX, VDivZ32StepX, Zi32StepX; + +geFloat ZiStepX; +geFloat ZiStepY; +geFloat ZiOrigin; + +GInfo *GlobalInfo; + +Fixed16 UAdjust; +Fixed16 VAdjust; +Fixed16 UAdjustL; +Fixed16 VAdjustL; +Fixed16 UAdjust1; +Fixed16 VAdjust1; +Fixed16 UAdjust2; +Fixed16 VAdjust2; + +Fixed16 MaxU; +Fixed16 MaxV; + +//magic numbers for geFloat to int conversion +//only works on values between -4194304 and 4194303 +geFloat FistMagic=12582912.0f; +geFloat FistTruncate=0.5f; + + +void TmapTriangle_32(DRV_TLVertex *verts); +void TmapTriangle_16(DRV_TLVertex *verts); + +typedef void (* MapperPtr) (EdgeAsm *, EdgeAsm *); + +static MapperPtr CurMapper; + +typedef void (* MapperPtrFPU) (EdgeAsmFPU *, EdgeAsmFPU *); + +static MapperPtrFPU CurMapperFPU; + +typedef void (* MapperPtrWorld) (int32 x1, int32 x2, int32 y, geFloat r1, geFloat g1, geFloat b1, geFloat r2, geFloat g2, geFloat b2); + +static MapperPtrWorld CurMapperWorld; + +typedef void (* MapperPtrWorldFPU) (int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2); + +static MapperPtrWorldFPU CurMapperWorldFPU; + +static geVec3d TVectU, TVectV; +static geVec3d TVectUL, TVectVL; + +static void CalcGradients(S32 MipLevel, geFloat DrawScaleU, geFloat DrawScaleV) +{ + geFloat MipScale; + geVec3d SOrigin; + geFloat t, dsui, dsvi; + Fixed16 UAdjust1L, VAdjust1L; + int GW_log2; + geVec3d Temp =GlobalInfo->Pov; + geFloat distinv, ZScaleInv; + + distinv =1.0f / (GlobalInfo->ZScale * (GlobalInfo->PlaneDist - geVec3d_DotProduct(&Temp, &GlobalInfo->PlaneNormal))); + ZScaleInv =1.0f / GlobalInfo->ZScale; + dsui =1.0f / DrawScaleU; + dsvi =1.0f / DrawScaleV; + + MipScale =(1.0f / (geFloat)(1 << MipLevel)); + + geXForm3d_Rotate(&GlobalInfo->CXForm, &GlobalInfo->VecU, &TVectUL); + geXForm3d_Rotate(&GlobalInfo->CXForm, &GlobalInfo->VecV, &TVectVL); + geVec3d_Scale(&TVectUL, dsui, &TVectU); + geVec3d_Scale(&TVectVL, dsvi, &TVectV); + + t =GlobalInfo->XScaleInv * ZScaleInv * MipScale; + + UDivZStepX =TVectU.X * t; + VDivZStepX =TVectV.X * t; + + t =GlobalInfo->YScaleInv * ZScaleInv * MipScale; + + UDivZStepY =-TVectU.Y * t; + VDivZStepY =-TVectV.Y * t; + + GLMapMulU =DrawScaleU; + GLMapMulV =DrawScaleV; + + *((geFloat *)(&GLMapMulUV)) =DrawScaleV; + *(((geFloat *)((&GLMapMulUV)))+1) =DrawScaleU; + + UDivZOrigin =TVectU.Z * ZScaleInv * MipScale + - GlobalInfo->XCenter * UDivZStepX + - GlobalInfo->YCenter * UDivZStepY; + + VDivZOrigin =TVectV.Z * ZScaleInv * MipScale + - GlobalInfo->XCenter * VDivZStepX + - GlobalInfo->YCenter * VDivZStepY; + + geVec3d_Scale(&GlobalInfo->CPov, MipScale, &SOrigin); + + t =65536.0f * MipScale; + UAdjust1 =((Fixed16)(geVec3d_DotProduct(&SOrigin, &TVectU) * 65536.0f + 0.5f)); + UAdjust1L =((Fixed16)(geVec3d_DotProduct(&SOrigin, &TVectUL) * 65536.0f + 0.5f)); + UAdjust2 =((GlobalInfo->TexMinsX << 16) >> MipLevel); + + VAdjust1 =((Fixed16)(geVec3d_DotProduct(&SOrigin, &TVectV) * 65536.0f + 0.5f)); + VAdjust1L =((Fixed16)(geVec3d_DotProduct(&SOrigin, &TVectVL) * 65536.0f + 0.5f)); + VAdjust2 =((GlobalInfo->TexMinsY << 16) >> MipLevel); + + UAdjustL =UAdjust1L - UAdjust2; + VAdjustL =VAdjust1L - VAdjust2; + + UAdjust2 =(int)(((geFloat)UAdjust2) * dsui); + VAdjust2 =(int)(((geFloat)VAdjust2) * dsvi); + + *((int *)(&UVAdjustL)) =VAdjustL; + *(((int *)((&UVAdjustL)))+1)=UAdjustL; + + UAdjust =UAdjust1 - UAdjust2; + VAdjust =VAdjust1 - VAdjust2; + + *((int *)(&UVAdjust)) =VAdjust; + *(((int *)((&UVAdjust)))+1) =UAdjust; + + UAdjust1 +=(Fixed16)(GlobalInfo->TexShiftX * t); + VAdjust1 +=(Fixed16)(GlobalInfo->TexShiftY * t); + UAdjust2 +=(Fixed16)(GlobalInfo->TexShiftX * t); + VAdjust2 +=(Fixed16)(GlobalInfo->TexShiftY * t); + + *((int *)(&UVAdjust2)) =VAdjust2; + *(((int *)((&UVAdjust2)))+1)=UAdjust2; + + MaxU =(((int)((GlobalInfo->TexWidth << 16) * dsui)) >> MipLevel); + MaxV =(((int)((GlobalInfo->TexHeight << 16) * dsvi)) >> MipLevel); + + *((int *)(&WrapMask)) =GWMask<<16; + *(((int *)((&WrapMask)))+1) =GWMask<<16; + + //find log2 of the texture width + for(GW_log2=1;((1<RPlaneNormal.X * GlobalInfo->XScaleInv * distinv; + ZiStepY =-GlobalInfo->RPlaneNormal.Y * GlobalInfo->YScaleInv * distinv; + ZiOrigin =GlobalInfo->RPlaneNormal.Z * distinv - + GlobalInfo->XCenter * ZiStepX - GlobalInfo->YCenter * ZiStepY; + + // Get 16 step Gradients + UDivZ16StepX =UDivZStepX * 16.0f; + VDivZ16StepX =VDivZStepX * 16.0f; + Zi16StepX =ZiStepX * 16.0f; + + *((U32 *)(&QZDelta)) =(U32)(ZiStepX * -ZBUFFER_PREC); + *(((U32 *)((&QZDelta)))+1) =(U32)(ZiStepX * -ZBUFFER_PREC); + + *(((geFloat *)((&UVDivZ16StepX)))+1) =UDivZ16StepX; + *((geFloat *)(&UVDivZ16StepX)) =VDivZ16StepX; + + *(((geFloat *)((&UVDivZStepX)))+1) =UDivZStepX; + *((geFloat *)(&UVDivZStepX)) =VDivZStepX; + + *(((geFloat *)((&UVDivZStepY)))+1) =UDivZStepY; + *((geFloat *)(&UVDivZStepY)) =VDivZStepY; + + *(((geFloat *)((&UVDivZOrigin)))+1) =UDivZOrigin; + *((geFloat *)(&UVDivZOrigin)) =VDivZOrigin; +} + + +BOOL DRIVERCC RenderGouraudPoly(DRV_TLVertex *Pnts, S32 NumPoints, U32 Flags) +{ + S32 i; + DRV_TLVertex TriVerts[3]; + + assert(NumPoints > 2); + + if(!bActive) + { + return GE_TRUE; + } + + if(ProcessorInfo.Has3DNow) + { + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapper =DrawScanLineGouraudNoZSolid_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudNoZBufferZWriteSolid_Asm3DNow; + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapper =DrawScanLineGouraudZBufferNoZWriteSolid_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudZBufferSolid_Asm3DNow; + } + } + + if(NumPoints==3) + { + TriVerts[2] =Pnts[0]; + TriVerts[1] =Pnts[1]; + TriVerts[0] =Pnts[2]; + + TmapTriangle_32(TriVerts); + } + else + { + for(i=0;i < NumPoints-2;i++) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1+i]; + TriVerts[2] =Pnts[2+i]; + + TmapTriangle_32(TriVerts); + } + } + return GE_TRUE; + } + else + { + if(ClientWindow.G_mask == 0x03e0) + { + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudNoZSolid_Asm555X86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWriteSolid_Asm555X86FPU; + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWriteSolid_Asm555X86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBufferSolid_Asm555X86FPU; + } + } + } + else + { + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudNoZSolid_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWriteSolid_AsmX86FPU; + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWriteSolid_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBufferSolid_AsmX86FPU; + } + } + } + if(NumPoints==3) + { + TriVerts[2] =Pnts[0]; + TriVerts[1] =Pnts[1]; + TriVerts[0] =Pnts[2]; + + TmapTriangle_16(TriVerts); + } + else + { + for(i=0;i < NumPoints-2;i++) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1+i]; + TriVerts[2] =Pnts[2+i]; + + TmapTriangle_16(TriVerts); + } + } + return GE_TRUE; + } +} + +void StepWorld(EdgeAsmWorld *edge) +{ + int r,g,b; + _asm + { + push ecx + push ebx + push esi + push edi + push edx + + mov eax,edge + fld [eax]EdgeAsmWorld.x ; x + fadd [eax]EdgeAsmWorld.xstep ; xd + fld [eax]EdgeAsmWorld.r ; r xd + fadd [eax]EdgeAsmWorld.rstep ; rd xd + fld [eax]EdgeAsmWorld.g ; g rd xd + fadd [eax]EdgeAsmWorld.gstep ; gd rd xd + fld [eax]EdgeAsmWorld.b ; b gd rd xd + fadd [eax]EdgeAsmWorld.bstep ; bd gd rd xd + fxch st(2) ; rd gd bd xd + fst [eax]EdgeAsmWorld.r + fadd [FistMagic] ; rdk gd bd xd + fxch st(2) ; bd gd rdk xd + fst [eax]EdgeAsmWorld.b + fadd [FistMagic] ; bdk gd rdk xd + fxch st(1) ; gd bdk rdk xd + fst [eax]EdgeAsmWorld.g + fadd [FistMagic] ; gdk bdk rdk xd + fxch st(2) ; rdk bdk gdk xd + fstp [r] ; bdk gdk xd + fstp [b] ; gdk xd + fstp [g] ; xd + + mov edx,[FistMagic] + mov ebx,[r] + + mov ecx,[g] + sub ebx,edx + + mov esi,[b] + sub ecx,edx + + sub esi,edx + and ebx,0fch + + fst [eax]EdgeAsmWorld.x ; xd + + and ecx,0fch + and esi,0fch + + fsub [FistTruncate] ; xdt + + mov [eax]EdgeAsmWorld.R,ebx + mov [eax]EdgeAsmWorld.G,ecx + + fadd [FistMagic] ; xnt + + mov [eax]EdgeAsmWorld.B,esi + + fstp [eax]EdgeAsmWorld.X + + sub [eax]EdgeAsmWorld.X,edx + + pop edx + pop edi + pop esi + pop ebx + pop ecx + } + edge->y++; + edge->Height--; +} + +void setup_edgeWorld(EdgeAsmWorld *edge, DRV_TLVertex *verts, int top, int end) +{ + int ey,ty; + geFloat yd; + + _asm + { + push ebx + mov eax,end + mov edx,top + + shl eax,2 + mov ebx,verts + + shl edx,2 + lea eax,[8*eax+eax] + lea edx,[8*edx+edx] + + fld [ebx+eax]DRV_TLVertex.y ; endy + fld [ebx+edx]DRV_TLVertex.y ; topy endy + fsub st(1),st ; topy yd + fld [ebx+eax]DRV_TLVertex.y ; endy topy yd + fadd [FistTruncate] + fadd [FistMagic] ; eyi topy yd + fxch st(2) ; yd topy eyi + fstp [yd] ; topy eyi + fadd [FistTruncate] + fadd [FistMagic] ; tyi eyi + fxch st(1) ; eyi tyi + fstp [ey] ; tyi + fld [ebx+edx]DRV_TLVertex.x ; x tyi + fxch st(1) ; tyi x + fstp [ty] ; x + fadd [FistMagic] ; xi + + mov ebx,[FistMagic] + mov eax,edge + + sub [ey],ebx + + fstp [eax]EdgeAsm.X + + sub [ty],ebx + + sub [eax]EdgeAsm.X, ebx + pop ebx + } + + edge->Height =ey-ty; + +// yd =(edge->Height >0)? 1.0f/edge->Height : 1; + yd =(edge->Height >0)? 1.0f/(verts[end].y - verts[top].y) : 1; + edge->y =ty; + + edge->x =verts[top].x; + edge->xstep =(verts[end].x-edge->x)*yd; + + edge->r =verts[top].r; + edge->rstep =(verts[end].r-edge->r)*yd; + edge->R =(int)(verts[top].r)&0xfc; + + edge->g =verts[top].g; + edge->gstep =(verts[end].g-edge->g)*yd; + edge->G =(int)(verts[top].g)&0xfc; + + edge->b =verts[top].b; + edge->bstep =(verts[end].b-edge->b)*yd; + edge->B =(int)(verts[top].b)&0xfc; +} + +void AddSpanDraw(EdgeAsmWorld *pLeft, EdgeAsmWorld *pRight) +{ + int x1, x2, y; + BOOL Dynamic; + + x1 =pLeft->X2; + x2 =pRight->X2; + y =pLeft->y; + + if (!PolyVisible) + { + PolyVisible = 1; + ActuallVisible++; + + if (GLInfo) + { + if(ProcessorInfo.Has3DNow) + { + Femms3DNow(); + + SOFTDRV.SetupLightmap(GLInfo, &Dynamic); + + Femms3DNow(); + } + else + { + SOFTDRV.SetupLightmap(GLInfo, &Dynamic); + } + + GLightData = (uint8*)GLInfo->RGBLight[0]; + } + else + { + GLightData =NULL; + } + } + if(PolyIsTrans) + { + if(!(y & 1)) + { + return; + } + } + + NumPixels += x2 - x1 + 1; + + if(ProcessorInfo.Has3DNow) + { + switch(SpanMode) + { + case 0: + { + DrawSpan32_AsmLitZWrite3DNow(x1, x2, y); + break; + } + case 1: + { + DrawSpan32_AsmGouraudZWrite3DNow(x1, x2, y, pLeft->r, pLeft->g, pLeft->b, pRight->r, pRight->g, pRight->b); + break; + } + case 2: + { + DrawSpan32_AsmLitZBuffer3DNow(x1, x2, y); + break; + } + case 3: + { + DrawSpan32_AsmGouraudZBuffer3DNow(x1, x2, y, pLeft->r, pLeft->g, pLeft->b, pRight->r, pRight->g, pRight->b); + break; + } + } + } + else + { + pZBufferPtr =ZBufLine; + if(ClientWindow.G_mask == 0x03e0) + { + switch(SpanMode) + { + case 0: + { + DrawSpan16_AsmLitZWrite555X86FPU(x1, x2, y); + break; + } + case 1: + { + DrawSpan16_AsmGouraudZWrite555X86FPU(x1, x2, y, pLeft->R, pLeft->G, pLeft->B, pRight->R, pRight->G, pRight->B); + break; + } + case 2: + { + DrawSpan16_AsmLitZBuffer555X86FPU(x1, x2, y); + break; + } + case 3: + { + DrawSpan16_AsmGouraudZBuffer555X86FPU(x1, x2, y, pLeft->R, pLeft->G, pLeft->B, pRight->R, pRight->G, pRight->B); + break; + } + } + } + else + { + switch(SpanMode) + { + case 0: + { + DrawSpan16_AsmLitZWriteX86FPU(x1, x2, y); + break; + } + case 1: + { + DrawSpan16_AsmGouraudZWriteX86FPU(x1, x2, y, pLeft->R, pLeft->G, pLeft->B, pRight->R, pRight->G, pRight->B); + break; + } + case 2: + { + DrawSpan16_AsmLitZBufferX86FPU(x1, x2, y); + break; + } + case 3: + { + DrawSpan16_AsmGouraudZBufferX86FPU(x1, x2, y, pLeft->R, pLeft->G, pLeft->B, pRight->R, pRight->G, pRight->B); + break; + } + } + } + } +} + +void AddSpan(EdgeAsmWorld *pLeft, EdgeAsmWorld *pRight) +{ + S32 y, x1, x2; + SList *LineStart =NULL; + SList *Current; + + y =pLeft->y; + x1 =pLeft->X; + pLeft->X2 =x1; + x2 =pRight->X; + pRight->X2 =x2; + + assert(y >=0 && y < MAXSCANLINES); + + if(RenderMode == RENDER_MODELS) + { + AddSpanDraw(pLeft, pRight); + return; + } + + Current = SMinMax[y].First; + + // Check to see if there are spans + if (!Current) + { + SMinMax[y].First = NewSList(); // in the list yet... + (SMinMax[y].First)->Last = NULL; + (SMinMax[y].First)->Next = NULL; + (SMinMax[y].First)->Min = x1; + (SMinMax[y].First)->Max = x2; + } + else while (Current) + { + // See if this line is totally hidden... + if(x1 >= Current->Min && x2 <= Current->Max) + { + return; // Yep + } + + //if falls before the entire min, max + if(!LineStart) + { + if(Current == SMinMax[y].First) + { + if(x2 < Current->Min) + { + SList *NewMinMax =NewSList(); + NewMinMax->Next =Current; + NewMinMax->Last =NULL; + Current->Last =NewMinMax; + SMinMax[y].First =NewMinMax; + NewMinMax->Min =x1; + NewMinMax->Max =x2; + break; + } + } + + //if falls in the middle (but not touching) + if(Current->Next) + { + if(x1 > Current->Max && x2 < (Current->Next)->Min) + { + SList *NewMinMax =NewSList(); + NewMinMax->Next =Current->Next; + NewMinMax->Last =Current; + (Current->Next)->Last =NewMinMax; + Current->Next =NewMinMax; + NewMinMax->Min =x1; + NewMinMax->Max =x2; + break; + } + } + + //if it falls to the right of all spans + if(!Current->Next) + { + if(x1 > Current->Max) + { + SList *NewMinMax =NewSList(); + Current->Next =NewMinMax; + NewMinMax->Next =NULL; + NewMinMax->Last =Current; + NewMinMax->Min =x1; + NewMinMax->Max =x2; + break; + } + } + } + + //if we have already started crossing spans, and we find out + // that we are in front of a span, then we can bail out... + if (LineStart != NULL) + if (x2 < Current->Min) + break; + + // We now know that we have not fallen into any empty holes. + // We must now check to see what spans, we've crossed... + + // if split by a min/max + if (x1 < Current->Min && x2 > Current->Max) + { + pRight->X2 =Current->Min; + Current->Min =pLeft->X2 =x1; + + AddSpanDraw(pLeft, pRight); + + pLeft->X2 =x1 =Current->Max; + Current->Max =pRight->X2 =x2; + + if (LineStart!=NULL) + LineStart->Max =x2; + else + LineStart = Current; + + Current = Current->Next; + continue; + } + + if (x1 <= Current->Max && x2 > Current->Max) + { + pLeft->X2 =x1 =Current->Max;//+1; + Current->Max =pRight->X2 =x2; + LineStart = Current; + + Current = Current->Next; + + continue; + } + if (x1 < Current->Min && x2 >= Current->Min) + { + pRight->X2 =x2 =Current->Min; + pLeft->X2 =Current->Min =x1; + if (LineStart!=NULL) + LineStart->Max = Current->Max; + break; + } + Current = Current->Next; + } + + AddSpanDraw(pLeft, pRight); +} + +void SpanOutWorldTri(DRV_TLVertex *verts) +{ + int Top, Middle, Bottom, MiddleForCompare; + int MiddleIsLeft, BottomForCompare, Height; + geFloat Y0=verts[0].y, Y1=verts[1].y, Y2=verts[2].y; + EdgeAsmWorld TopToBottom, TopToMiddle, MiddleToBottom; + EdgeAsmWorld *pLeft, *pRight; + + // sort vertices in y + if(Y0 < Y1) + { + if(Y2 < Y0) + { + Top =2; + Middle =MiddleForCompare =0; + Bottom =BottomForCompare =1; + } + else + { + Top =0; + if(Y1 < Y2) + { + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =2; + } + else + { + Middle =MiddleForCompare =2; + Bottom =BottomForCompare =1; + } + } + } + else + { + if(Y2 < Y1) + { + Top =2; + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =0; + } + else + { + Top =1; + if(Y0 < Y2) + { + Middle =0; + Bottom =BottomForCompare =2; + MiddleForCompare =3; + } + else + { + BottomForCompare =3; + Middle =MiddleForCompare =2; + Bottom =0; + } + } + } + + setup_edgeWorld(&TopToBottom, verts, Top, Bottom); + setup_edgeWorld(&TopToMiddle, verts, Top, Middle); + setup_edgeWorld(&MiddleToBottom, verts, Middle, Bottom); + + if(BottomForCompare > MiddleForCompare) + { + MiddleIsLeft = 0; + pLeft = &TopToBottom; pRight = &TopToMiddle; + } + else + { + MiddleIsLeft = 1; + pLeft = &TopToMiddle; pRight = &TopToBottom; + } + + Height =TopToMiddle.Height; + + Dest =(U16 *)(ClientWindow.Buffer + (pLeft->y * ClientWindow.PixelPitch)); + ZBufLine =ZBuffer + (pLeft->y * ClientWindow.Width); + + pZBufferPtr =ZBufLine; + while(Height--) + { + if(bStipple) + { + if(pLeft->y & 1) + { + AddSpan(pLeft, pRight); + } + } + else + { + AddSpan(pLeft, pRight); + } + StepWorld(pLeft); + StepWorld(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + ZBufLine +=ClientWindow.Width; + pZBufferPtr =ZBufLine; + } + + Height =MiddleToBottom.Height; + + if(MiddleIsLeft) + { + pLeft =&MiddleToBottom; + pRight =&TopToBottom; + } + else + { + pLeft =&TopToBottom; + pRight =&MiddleToBottom; + } + + while(Height--) + { + if(bStipple) + { + if(pLeft->y & 1) + { + AddSpan(pLeft, pRight); + } + } + else + { + AddSpan(pLeft, pRight); + } + StepWorld(pLeft); + StepWorld(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + ZBufLine +=ClientWindow.Width; + pZBufferPtr =ZBufLine; + } +} + +void SpanOutWorldTri3DNow(DRV_TLVertex *verts) +{ + int Top, Middle, Bottom, MiddleForCompare; + int MiddleIsLeft, BottomForCompare, Height; + geFloat Y0=verts[0].y, Y1=verts[1].y, Y2=verts[2].y; + EdgeAsmWorld TopToBottom, TopToMiddle, MiddleToBottom; + EdgeAsmWorld *pLeft, *pRight; + + // sort vertices in y + if(Y0 < Y1) + { + if(Y2 < Y0) + { + Top =2; + Middle =MiddleForCompare =0; + Bottom =BottomForCompare =1; + } + else + { + Top =0; + if(Y1 < Y2) + { + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =2; + } + else + { + Middle =MiddleForCompare =2; + Bottom =BottomForCompare =1; + } + } + } + else + { + if(Y2 < Y1) + { + Top =2; + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =0; + } + else + { + Top =1; + if(Y0 < Y2) + { + Middle =0; + Bottom =BottomForCompare =2; + MiddleForCompare =3; + } + else + { + BottomForCompare =3; + Middle =MiddleForCompare =2; + Bottom =0; + } + } + } + + setup_edgeWorld(&TopToBottom, verts, Top, Bottom); + setup_edgeWorld(&TopToMiddle, verts, Top, Middle); + setup_edgeWorld(&MiddleToBottom, verts, Middle, Bottom); + + Femms3DNow(); + + if(BottomForCompare > MiddleForCompare) + { + MiddleIsLeft = 0; + pLeft = &TopToBottom; pRight = &TopToMiddle; + } + else + { + MiddleIsLeft = 1; + pLeft = &TopToMiddle; pRight = &TopToBottom; + } + + Height =TopToMiddle.Height; + + Dest =(U16 *)(ClientWindow.Buffer + (pLeft->y * ClientWindow.PixelPitch)); + + while(Height--) + { + AddSpan(pLeft, pRight); + + StepWorld3DNow(pLeft); + StepWorld3DNow(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + } + + Height =MiddleToBottom.Height; + + if(MiddleIsLeft) + { + pLeft =&MiddleToBottom; + pRight =&TopToBottom; + } + else + { + pLeft =&TopToBottom; + pRight =&MiddleToBottom; + } + + while(Height--) + { + AddSpan(pLeft, pRight); + + StepWorld3DNow(pLeft); + StepWorld3DNow(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + } + Femms3DNow(); +} + +void SpanOutWorldTriAlpha(DRV_TLVertex *verts) +{ + int Top, Middle, Bottom, MiddleForCompare; + int MiddleIsLeft, BottomForCompare, Height; + geFloat Y0=verts[0].y, Y1=verts[1].y, Y2=verts[2].y; + EdgeAsmWorld TopToBottom, TopToMiddle, MiddleToBottom; + EdgeAsmWorld *pLeft, *pRight; + + // sort vertices in y + if(Y0 < Y1) + { + if(Y2 < Y0) + { + Top =2; + Middle =MiddleForCompare =0; + Bottom =BottomForCompare =1; + } + else + { + Top =0; + if(Y1 < Y2) + { + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =2; + } + else + { + Middle =MiddleForCompare =2; + Bottom =BottomForCompare =1; + } + } + } + else + { + if(Y2 < Y1) + { + Top =2; + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =0; + } + else + { + Top =1; + if(Y0 < Y2) + { + Middle =0; + Bottom =BottomForCompare =2; + MiddleForCompare =3; + } + else + { + BottomForCompare =3; + Middle =MiddleForCompare =2; + Bottom =0; + } + } + } + + setup_edgeWorld(&TopToBottom, verts, Top, Bottom); + setup_edgeWorld(&TopToMiddle, verts, Top, Middle); + setup_edgeWorld(&MiddleToBottom, verts, Middle, Bottom); + + if(BottomForCompare > MiddleForCompare) + { + MiddleIsLeft = 0; + pLeft = &TopToBottom; pRight = &TopToMiddle; + } + else + { + MiddleIsLeft = 1; + pLeft = &TopToMiddle; pRight = &TopToBottom; + } + + Height =TopToMiddle.Height; + + Dest =(U16 *)(ClientWindow.Buffer + (pLeft->y * ClientWindow.PixelPitch)); + ZBufLine =ZBuffer + (pLeft->y * ClientWindow.Width); + + pZBufferPtr =ZBufLine; + while(Height--) + { + if(bStipple) + { + if(pLeft->y & 1) + { + CurMapperWorldFPU(pLeft->X, pRight->X, pLeft->y + , pLeft->R, pLeft->G, pLeft->B, + pRight->R, pRight->G, pRight->B); + } + } + else + { + CurMapperWorldFPU(pLeft->X, pRight->X, pLeft->y + , pLeft->R, pLeft->G, pLeft->B, + pRight->R, pRight->G, pRight->B); + } + StepWorld(pLeft); + StepWorld(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + ZBufLine +=ClientWindow.Width; + pZBufferPtr =ZBufLine; + } + + Height =MiddleToBottom.Height; + + if(MiddleIsLeft) + { + pLeft =&MiddleToBottom; + pRight =&TopToBottom; + } + else + { + pLeft =&TopToBottom; + pRight =&MiddleToBottom; + } + + while(Height--) + { + if(bStipple) + { + if(pLeft->y & 1) + { + CurMapperWorldFPU(pLeft->X, pRight->X, pLeft->y + , pLeft->R, pLeft->G, pLeft->B, + pRight->R, pRight->G, pRight->B); + } + } + else + { + CurMapperWorldFPU(pLeft->X, pRight->X, pLeft->y + , pLeft->R, pLeft->G, pLeft->B, + pRight->R, pRight->G, pRight->B); + } + StepWorld(pLeft); + StepWorld(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + ZBufLine +=ClientWindow.Width; + pZBufferPtr =ZBufLine; + } +} + +void SpanOutWorldTriAlpha3DNow(DRV_TLVertex *verts) +{ + int Top, Middle, Bottom, MiddleForCompare; + int MiddleIsLeft, BottomForCompare, Height; + geFloat Y0=verts[0].y, Y1=verts[1].y, Y2=verts[2].y; + EdgeAsmWorld TopToBottom, TopToMiddle, MiddleToBottom; + EdgeAsmWorld *pLeft, *pRight; + + // sort vertices in y + if(Y0 < Y1) + { + if(Y2 < Y0) + { + Top =2; + Middle =MiddleForCompare =0; + Bottom =BottomForCompare =1; + } + else + { + Top =0; + if(Y1 < Y2) + { + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =2; + } + else + { + Middle =MiddleForCompare =2; + Bottom =BottomForCompare =1; + } + } + } + else + { + if(Y2 < Y1) + { + Top =2; + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =0; + } + else + { + Top =1; + if(Y0 < Y2) + { + Middle =0; + Bottom =BottomForCompare =2; + MiddleForCompare =3; + } + else + { + BottomForCompare =3; + Middle =MiddleForCompare =2; + Bottom =0; + } + } + } + + setup_edgeWorld(&TopToBottom, verts, Top, Bottom); + setup_edgeWorld(&TopToMiddle, verts, Top, Middle); + setup_edgeWorld(&MiddleToBottom, verts, Middle, Bottom); + + Femms3DNow(); + + if(BottomForCompare > MiddleForCompare) + { + MiddleIsLeft = 0; + pLeft = &TopToBottom; pRight = &TopToMiddle; + } + else + { + MiddleIsLeft = 1; + pLeft = &TopToMiddle; pRight = &TopToBottom; + } + + Height =TopToMiddle.Height; + + Dest =(U16 *)(ClientWindow.Buffer + (pLeft->y * ClientWindow.PixelPitch)); + + while(Height--) + { + CurMapperWorld(pLeft->X, pRight->X, pLeft->y + , pLeft->r, pLeft->g, pLeft->b, + pRight->r, pRight->g, pRight->b); + + StepWorld3DNow(pLeft); + StepWorld3DNow(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + } + + Height =MiddleToBottom.Height; + + if(MiddleIsLeft) + { + pLeft =&MiddleToBottom; + pRight =&TopToBottom; + } + else + { + pLeft =&TopToBottom; + pRight =&MiddleToBottom; + } + + while(Height--) + { + CurMapperWorld(pLeft->X, pRight->X, pLeft->y + , pLeft->r, pLeft->g, pLeft->b, + pRight->r, pRight->g, pRight->b); + + StepWorld3DNow(pLeft); + StepWorld3DNow(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + } + Femms3DNow(); +} + +BOOL DRIVERCC RenderWorldPoly(DRV_TLVertex *Pnts, S32 NumPoints, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, U32 Flags) +{ + U8 MipLevel = 0; + int32 i; + DRV_TLVertex TriVerts[3]; + + if(!bActive) + { + return GE_TRUE; + } + + assert(THandle != NULL); + assert(Pnts != NULL); + assert(NumPoints > 2); + + GlobalInfo = SOFTDRV.GlobalInfo; + assert(GlobalInfo); + + // + // Get the mip level + // + { + geFloat du, dv, dx, dy, MipScale; + + du =Pnts[1].u - Pnts[0].u; + dv =Pnts[1].v - Pnts[0].v; + dx =Pnts[1].x - Pnts[0].x; + dy =Pnts[1].y - Pnts[0].y; + + du /=TexInfo->DrawScaleU; + dv /=TexInfo->DrawScaleV; + + MipScale =((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy)); + + if(MipScale <= 5) // 2, 6, 12 + { + MipLevel =0; + } + else if(MipScale <= 20) + { + MipLevel =1; + } + else if(MipScale <= 45) + { + MipLevel =2; + } + else + { + MipLevel =3; + } + } + + if(MipLevel >= THandle->MipLevels) + { + MipLevel =THandle->MipLevels-1; + } + + assert(THandle->BitPtr[MipLevel] != NULL); + + GW = THandle->Width >> MipLevel; + GH = THandle->Height >> MipLevel; + GWMask = GW-1; + GHMask = GH-1; + + CalcGradients(MipLevel, TexInfo->DrawScaleU, TexInfo->DrawScaleV); + + // Assign some global variables... + GTexture =THandle; + GLInfo =LInfo; + + if(ProcessorInfo.Has3DNow) + { + GBitPtr =(U8 *)THandle->BitPtr[MipLevel]; + TexPal =(U8 *)THandle->PalHandle->BitPtr[0]; + } + else + { + GBitPtr16 =THandle->BitPtr[MipLevel]; + GWMaskShifted=(GWMask<<16) |0xffff; + } + + GMipLevel = (U8)MipLevel; + GMipLevel4 = 4-MipLevel; + GMipLevel4_8 = GMipLevel4+8; + GMipLevel20 = 20-MipLevel; + + QGMip20 =GMipLevel20; + QGMip4_8=GMipLevel4_8; + + if(LInfo) + { + GLMapAdd = LInfo->Width*3 - 6; + GLightWidth = LInfo->Width; + + GLightData = (uint8*)LInfo->RGBLight[0]; + + if(RenderMode == RENDER_MODELS) + SpanMode = 2; + else + SpanMode = 0; + } + else + { + if(RenderMode == RENDER_MODELS) + SpanMode = 3; + else + SpanMode = 1; + } + + if(Flags & DRV_RENDER_ALPHA) + { + PolyIsTrans =GE_TRUE; + } + else + { + PolyIsTrans =FALSE; + } + + // Reset the polyvisible flag + PolyVisible = 0; + +/* if(THandle->PixelFormat.Flags & RDRIVER_PF_HAS_ALPHA) + { + PolyIsTrans =GE_TRUE; + } + else if(THandle->PalHandle) + { + PolyIsTrans =gePixelFormat_HasAlpha(THandle->PalHandle->PixelFormat.PixelFormat); + } + else + { + PolyIsTrans =GE_FALSE; + } +*/ + if(RenderMode == RENDER_WORLD || RenderMode == RENDER_MODELS) + { + assert(!(Flags & DRV_RENDER_ALPHA)); + if(NumPoints==3) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1]; + TriVerts[2] =Pnts[2]; + + if(ProcessorInfo.Has3DNow) + { + SpanOutWorldTri3DNow(TriVerts); + } + else + { + SpanOutWorldTri(TriVerts); + } + } + else + { + for(i=0;i < NumPoints-2;i++) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1+i]; + TriVerts[2] =Pnts[2+i]; + + if(ProcessorInfo.Has3DNow) + { + SpanOutWorldTri3DNow(TriVerts); + } + else + { + SpanOutWorldTri(TriVerts); + } + } + } + } + else + { + bStipple =GE_FALSE; + if(ProcessorInfo.Has3DNow) + { +/* if(LInfo) //lit alpha not done yet + { + //check for argb alpha faces (no seperate right now) + if(GTexture->PixelFormat.PixelFormat==GE_PIXELFORMAT_32BIT_ARGB) + { + CurMapperWorld =DrawSpan32_AsmGouraudZBufferAlphaARGB3DNow; + } + else + { + CurMapperWorld =DrawSpan32_AsmLitZBuffer3DNow; + } + } + else +*/ { + //vertex alpha overrides argb + if(Pnts[0].a < 255.0f) + { + i =(int)Pnts[0].a; + *((U32 *)(&VertAlpha)) =(i << 16) | i; + *(((U32 *)((&VertAlpha)))+1)=(i << 16) | i; + CurMapperWorld =DrawSpan32_AsmGouraudZBufferVertexAlpha3DNow; + } + else + { + //check for argb alpha faces (no seperate right now) + if(GTexture->PalHandle->PixelFormat.PixelFormat==GE_PIXELFORMAT_32BIT_ARGB) + { + CurMapperWorld =DrawSpan32_AsmGouraudZBufferAlphaARGB3DNow; + } + else + { + CurMapperWorld =DrawSpan32_AsmGouraudZBuffer3DNow; + } + } + } + if(NumPoints==3) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1]; + TriVerts[2] =Pnts[2]; + + SpanOutWorldTriAlpha3DNow(TriVerts); + } + else + { + for(i=0;i < NumPoints-2;i++) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1+i]; + TriVerts[2] =Pnts[2+i]; + + SpanOutWorldTriAlpha3DNow(TriVerts); + } + } + } + else + { +/* if(LInfo) //lit alpha not done yet + { + //check for argb alpha faces (no seperate right now) + if(GTexture->PixelFormat.PixelFormat==GE_PIXELFORMAT_32BIT_ARGB) + { + CurMapperWorld =DrawSpan32_AsmGouraudZBufferAlphaARGB3DNow; + } + else + { + CurMapperWorld =DrawSpan32_AsmLitZBuffer3DNow; + } + } + else +*/ + if(ClientWindow.G_mask == 0x03e0) + { + if(Pnts[0].a > 254.0f) + { + CurMapperWorldFPU =DrawSpan16_AsmGouraudZBufferTrans555X86FPU; + } + else + { + CurMapperWorldFPU =DrawSpan16_AsmGouraudZBuffer555X86FPU; + } + bStipple =GE_TRUE; + } + else + { + if(Pnts[0].a > 254.0f) + { + CurMapperWorldFPU =DrawSpan16_AsmGouraudZBufferTransX86FPU; + } + else + { + CurMapperWorldFPU =DrawSpan16_AsmGouraudZBufferX86FPU; + } + bStipple =GE_TRUE; + } + if(NumPoints==3) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1]; + TriVerts[2] =Pnts[2]; + + SpanOutWorldTriAlpha(TriVerts); + } + else + { + for(i=0;i < NumPoints-2;i++) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1+i]; + TriVerts[2] =Pnts[2+i]; + + SpanOutWorldTriAlpha(TriVerts); + } + } + } + + bStipple =GE_FALSE; + } + + return GE_TRUE; +} + +void Step(EdgeAsm *edge) +{ + _asm + { + mov eax,edge + fld [eax]EdgeAsm.x ; x + fadd [eax]EdgeAsm.xstep ; xd + fld [eax]EdgeAsm.u ; u xd + fadd [eax]EdgeAsm.ustep ; ud xd + fld [eax]EdgeAsm.v ; v ud xd + fadd [eax]EdgeAsm.vstep ; vd ud xd + fld [eax]EdgeAsm.z ; z vd ud xd + fadd [eax]EdgeAsm.zstep ; zd vd ud xd + fld [eax]EdgeAsm.r ; r zd vd ud xd + fadd [eax]EdgeAsm.rstep ; rd zd vd ud xd + fld [eax]EdgeAsm.g ; g rd zd vd ud xd + fadd [eax]EdgeAsm.gstep ; gd rd zd vd ud xd + fld [eax]EdgeAsm.b ; b gd rd zd vd ud xd + fadd [eax]EdgeAsm.bstep ; bd gd rd zd vd ud xd + fxch st(2) ; rd gd bd zd vd ud xd + fstp [eax]EdgeAsm.r ; gd bd zd vd ud xd + fstp [eax]EdgeAsm.g ; bd zd vd ud xd + fstp [eax]EdgeAsm.b ; zd vd ud xd + fstp [eax]EdgeAsm.z ; vd ud xd + fstp [eax]EdgeAsm.v ; ud xd + fstp [eax]EdgeAsm.u ; xd + fst [eax]EdgeAsm.x ; xd + fsub [FistTruncate] ; xdt + fadd [FistMagic] ; xnt + fstp [eax]EdgeAsm.X + + mov edx,[FistMagic] + sub [eax]EdgeAsm.X,edx + } + edge->y++; + edge->Height--; +} + +//special handling of colors for fpu blend +void StepFPU(EdgeAsmFPU *edge) +{ + int r,g,b; + _asm + { + push ecx + push ebx + push esi + + mov eax,edge + fld [eax]EdgeAsmFPU.x ; x + fadd [eax]EdgeAsmFPU.xstep ; xd + fld [eax]EdgeAsmFPU.u ; u xd + fadd [eax]EdgeAsmFPU.ustep ; ud xd + fld [eax]EdgeAsmFPU.v ; v ud xd + fadd [eax]EdgeAsmFPU.vstep ; vd ud xd + fld [eax]EdgeAsmFPU.z ; z vd ud xd + fadd [eax]EdgeAsmFPU.zstep ; zd vd ud xd + fld [eax]EdgeAsmFPU.r ; r zd vd ud xd + fadd [eax]EdgeAsmFPU.rstep ; rd zd vd ud xd + fld [eax]EdgeAsmFPU.g ; g rd zd vd ud xd + fadd [eax]EdgeAsmFPU.gstep ; gd rd zd vd ud xd + fld [eax]EdgeAsmFPU.b ; b gd rd zd vd ud xd + fadd [eax]EdgeAsmFPU.bstep ; bd gd rd zd vd ud xd + fxch st(2) ; rd gd bd zd vd ud xd + fst [eax]EdgeAsmFPU.r + fadd [FistMagic] ; rdk gd bd zd vd ud xd + fxch st(2) ; bd gd rdk zd vd ud xd + fst [eax]EdgeAsmFPU.b + fadd [FistMagic] ; bdk gd rdk zd vd ud xd + fxch st(1) ; gd bdk rdk zd vd ud xd + fst [eax]EdgeAsmFPU.g + fadd [FistMagic] ; gdk bdk rdk zd vd ud xd + fxch st(2) ; rdk bdk gdk zd vd ud xd + fstp [r] ; bdk gdk zd vd ud xd + fstp [b] ; gdk zd vd ud xd + fstp [g] ; zd vd ud xd + + mov edx,[FistMagic] + mov ebx,[r] + + fstp [eax]EdgeAsmFPU.z ; vd ud xd + + mov ecx,[g] + sub ebx,edx + + fstp [eax]EdgeAsmFPU.v ; ud xd + + mov esi,[b] + sub ecx,edx + + fstp [eax]EdgeAsmFPU.u ; xd + + sub esi,edx + and ebx,0fch + + fst [eax]EdgeAsmFPU.x ; xd + + and ecx,0fch + and esi,0fch + + fsub [FistTruncate] ; xdt + + mov [eax]EdgeAsmFPU.R,ebx + mov [eax]EdgeAsmFPU.G,ecx + + fadd [FistMagic] ; xnt + + mov [eax]EdgeAsmFPU.B,esi + + fstp [eax]EdgeAsmFPU.X + + sub [eax]EdgeAsmFPU.X,edx + + pop esi + pop ebx + pop ecx + } + edge->y++; + edge->Height--; +} + +void setup_edge(EdgeAsm *edge, DRV_TLVertex *verts, int top, int end) +{ + int ey,ty; + geFloat yd; + + _asm + { + push ebx + mov eax,end + mov edx,top + + shl eax,2 + mov ebx,verts + + shl edx,2 + lea eax,[8*eax+eax] + lea edx,[8*edx+edx] + + fld [ebx+eax]DRV_TLVertex.y ; endy + fld [ebx+edx]DRV_TLVertex.y ; topy endy + fsub st(1),st ; topy yd + fld [ebx+eax]DRV_TLVertex.y ; endy topy yd + fsub [FistTruncate] + fadd [FistMagic] ; eyi topy yd + fxch st(2) ; yd topy eyi + fstp [yd] ; topy eyi + fsub [FistTruncate] + fadd [FistMagic] ; tyi eyi + fxch st(1) ; eyi tyi + fstp [ey] ; tyi + fld [ebx+edx]DRV_TLVertex.x ; x tyi + fxch st(1) ; tyi x + fstp [ty] ; x + fsub [FistTruncate] + fadd [FistMagic] ; xi + + mov ebx,[FistMagic] + mov eax,edge + + sub [ey],ebx + + fstp [eax]EdgeAsm.X + + sub [ty],ebx + + sub [eax]EdgeAsm.X, ebx + pop ebx + } + + edge->Height =ey-ty; + + yd =(edge->Height >0)? 1.0f/edge->Height : 1; + edge->y =ty; + + edge->x =verts[top].x; + edge->xstep =(verts[end].x-edge->x)*yd; + + edge->u =verts[top].u; + edge->ustep =(verts[end].u-edge->u)*yd; + + edge->v =verts[top].v; + edge->vstep =(verts[end].v-edge->v)*yd; + + edge->z =(1.0f / verts[top].z) * (geFloat)ZBUFFER_PREC; + edge->zstep =(((1.0f / verts[end].z) * (geFloat)ZBUFFER_PREC)-edge->z)*yd; + + edge->r =verts[top].r; + edge->rstep =(verts[end].r-edge->r)*yd; + + edge->g =verts[top].g; + edge->gstep =(verts[end].g-edge->g)*yd; + + edge->b =verts[top].b; + edge->bstep =(verts[end].b-edge->b)*yd; +} + +void setup_edgeFPU(EdgeAsmFPU *edge, DRV_TLVertex *verts, int top, int end) +{ + int ey,ty; + geFloat yd; + + _asm + { + push ebx + mov eax,end + mov edx,top + + shl eax,2 + mov ebx,verts + + shl edx,2 + lea eax,[8*eax+eax] + lea edx,[8*edx+edx] + + fld [ebx+eax]DRV_TLVertex.y ; endy + fld [ebx+edx]DRV_TLVertex.y ; topy endy + fsub st(1),st ; topy yd + fld [ebx+eax]DRV_TLVertex.y ; endy topy yd + fsub [FistTruncate] + fadd [FistMagic] ; eyi topy yd + fxch st(2) ; yd topy eyi + fstp [yd] ; topy eyi + fsub [FistTruncate] + fadd [FistMagic] ; tyi eyi + fxch st(1) ; eyi tyi + fstp [ey] ; tyi + fld [ebx+edx]DRV_TLVertex.x ; x tyi + fxch st(1) ; tyi x + fstp [ty] ; x + fsub [FistTruncate] + fadd [FistMagic] ; xi + + mov ebx,[FistMagic] + mov eax,edge + + sub [ey],ebx + + fstp [eax]EdgeAsm.X + + sub [ty],ebx + + sub [eax]EdgeAsm.X, ebx + pop ebx + } + + edge->Height =ey-ty; + + yd =(edge->Height >0)? 1.0f/edge->Height : 1; + edge->y =ty; + + edge->x =verts[top].x; + edge->xstep =(verts[end].x-edge->x)*yd; + + edge->u =verts[top].u; + edge->ustep =(verts[end].u-edge->u)*yd; + + edge->v =verts[top].v; + edge->vstep =(verts[end].v-edge->v)*yd; + + edge->z =(1.0f / verts[top].z) * (geFloat)ZBUFFER_PREC; + edge->zstep =(((1.0f / verts[end].z) * (geFloat)ZBUFFER_PREC)-edge->z)*yd; + + edge->r =verts[top].r; + edge->rstep =(verts[end].r-edge->r)*yd; + edge->R =(int)(verts[top].r)&0xfc; + + edge->g =verts[top].g; + edge->gstep =(verts[end].g-edge->g)*yd; + edge->G =(int)(verts[top].g)&0xfc; + + edge->b =verts[top].b; + edge->bstep =(verts[end].b-edge->b)*yd; + edge->B =(int)(verts[top].b)&0xfc; +} + +//#define WIREFRAMEHACK + +void TmapTriangle_32(DRV_TLVertex *verts) +{ + int Top, Middle, Bottom, MiddleForCompare; + int MiddleIsLeft, BottomForCompare, Height; + EdgeAsm TopToBottom, TopToMiddle, MiddleToBottom; + EdgeAsm *pLeft, *pRight; + geFloat Y0=verts[0].y, Y1=verts[1].y, Y2=verts[2].y; + + // sort vertices in y + if(Y0 < Y1) + { + if(Y2 < Y0) + { + Top =2; + Middle =MiddleForCompare =0; + Bottom =BottomForCompare =1; + } + else + { + Top =0; + if(Y1 < Y2) + { + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =2; + } + else + { + Middle =MiddleForCompare =2; + Bottom =BottomForCompare =1; + } + } + } + else + { + if(Y2 < Y1) + { + Top =2; + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =0; + } + else + { + Top =1; + if(Y0 < Y2) + { + Middle =0; + Bottom =BottomForCompare =2; + MiddleForCompare =3; + } + else + { + BottomForCompare =3; + Middle =MiddleForCompare =2; + Bottom =0; + } + } + } + + setup_edge((EdgeAsm *)&TopToBottom, verts, Top, Bottom); + setup_edge((EdgeAsm *)&TopToMiddle, verts, Top, Middle); + setup_edge((EdgeAsm *)&MiddleToBottom, verts, Middle, Bottom); + + if(BottomForCompare > MiddleForCompare) + { + MiddleIsLeft = 0; + pLeft = &TopToBottom; pRight = &TopToMiddle; + } + else + { + MiddleIsLeft = 1; + pLeft = &TopToMiddle; pRight = &TopToBottom; + } + + Height =TopToMiddle.Height; + Dest =(U16 *)(ClientWindow.Buffer + (pLeft->y * ClientWindow.PixelPitch)); + ZBufLine =ZBuffer + (pLeft->y * ClientWindow.Width); + pZBufferPtr =ZBufLine; + +#ifdef WIREFRAMEHACK + Top=1; +#endif + + while(Height--) + { +#ifdef WIREFRAMEHACK + if(!Height || Top) + { + Top =0; + if(pLeft->X <= pRight->X) + { + memset(((U32 *)Dest)+pLeft->X, 0xff, (pRight->X - pLeft->X)<<2); + } + else + { + memset(((U32 *)Dest)+pRight->X, 0xff, (pLeft->X - pRight->X)<<2); + } + } + else + { + //uncomment for zbuffered wire +// if(*(ZBufLine + pLeft->X) > ((U16)pLeft->z)) +// { + *(((U32 *)Dest) + pLeft->X) =0xffffffff; +// } +// if(*(ZBufLine + pRight->X) > ((U16)pRight->z)) +// { + *(((U32 *)Dest) + pRight->X)=0xffffffff; +// } + } +#else + if(bStipple) + { + if(pLeft->y & 1) + { + if(pLeft->X <= pRight->X) + { + CurMapper(pLeft, pRight); + } + else + { + CurMapper(pRight, pLeft); + } + } + } + else + { + if(pLeft->X <= pRight->X) + { + CurMapper(pLeft, pRight); + } + else + { + CurMapper(pRight, pLeft); + } + } +#endif + Step(pLeft); + Step(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + ZBufLine +=ClientWindow.Width; + pZBufferPtr =ZBufLine; + } + + Height =MiddleToBottom.Height; + + if(MiddleIsLeft) + { + pLeft =&MiddleToBottom; + pRight =&TopToBottom; + } + else + { + pLeft =&TopToBottom; + pRight =&MiddleToBottom; + } + + while(Height--) + { +#ifdef WIREFRAMEHACK + if(!Height || Top) + { + Top =0; + if(pLeft->X <= pRight->X) + { + memset(((U32 *)Dest)+pLeft->X, 0xff, (pRight->X - pLeft->X)<<2); + } + else + { + memset(((U32 *)Dest)+pRight->X, 0xff, (pLeft->X - pRight->X)<<2); + } + } + else + { + //uncomment for zbuffered wire +// if(*(ZBufLine + pLeft->X) > ((U16)pLeft->z)) +// { + *(((U32 *)Dest) + pLeft->X) =0xffffffff; +// } +// if(*(ZBufLine + pRight->X) > ((U16)pRight->z)) +// { + *(((U32 *)Dest) + pRight->X)=0xffffffff; +// } + } +#else + if(bStipple) + { + if(pLeft->y & 1) + { + if(pLeft->X <= pRight->X) + { + CurMapper(pLeft, pRight); + } + else + { + CurMapper(pRight, pLeft); + } + } + } + else + { + if(pLeft->X <= pRight->X) + { + CurMapper(pLeft, pRight); + } + else + { + CurMapper(pRight, pLeft); + } + } +#endif + Step(pLeft); + Step(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + ZBufLine +=ClientWindow.Width; + pZBufferPtr =ZBufLine; + } +} + +//16 bit fpu version +void TmapTriangle_16(DRV_TLVertex *verts) +{ + int Top, Middle, Bottom, MiddleForCompare; + int MiddleIsLeft, BottomForCompare, Height; + EdgeAsmFPU TopToBottom, TopToMiddle, MiddleToBottom; + EdgeAsmFPU *pLeft, *pRight; + geFloat Y0=verts[0].y, Y1=verts[1].y, Y2=verts[2].y; + + // sort vertices in y + if(Y0 < Y1) + { + if(Y2 < Y0) + { + Top =2; + Middle =MiddleForCompare =0; + Bottom =BottomForCompare =1; + } + else + { + Top =0; + if(Y1 < Y2) + { + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =2; + } + else + { + Middle =MiddleForCompare =2; + Bottom =BottomForCompare =1; + } + } + } + else + { + if(Y2 < Y1) + { + Top =2; + Middle =MiddleForCompare =1; + Bottom =BottomForCompare =0; + } + else + { + Top =1; + if(Y0 < Y2) + { + Middle =0; + Bottom =BottomForCompare =2; + MiddleForCompare =3; + } + else + { + BottomForCompare =3; + Middle =MiddleForCompare =2; + Bottom =0; + } + } + } + + setup_edgeFPU(&TopToBottom, verts, Top, Bottom); + setup_edgeFPU(&TopToMiddle, verts, Top, Middle); + setup_edgeFPU(&MiddleToBottom, verts, Middle, Bottom); + + if(BottomForCompare > MiddleForCompare) + { + MiddleIsLeft = 0; + pLeft = &TopToBottom; pRight = &TopToMiddle; + } + else + { + MiddleIsLeft = 1; + pLeft = &TopToMiddle; pRight = &TopToBottom; + } + + Height =TopToMiddle.Height; + + Dest =(U16 *)(ClientWindow.Buffer + (pLeft->y * ClientWindow.PixelPitch)); + ZBufLine =ZBuffer + (pLeft->y * ClientWindow.Width); + + pZBufferPtr =ZBufLine; + while(Height--) + { + if(bStipple) + { + if(pLeft->y & 1) + { + if(pLeft->X <= pRight->X) + { + CurMapperFPU(pLeft, pRight); + } + else + { + CurMapperFPU(pRight, pLeft); + } + } + } + else + { + if(pLeft->X <= pRight->X) + { + CurMapperFPU(pLeft, pRight); + } + else + { + CurMapperFPU(pRight, pLeft); + } + } + StepFPU(pLeft); + StepFPU(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + ZBufLine +=ClientWindow.Width; + pZBufferPtr =ZBufLine; + } + + Height =MiddleToBottom.Height; + + if(MiddleIsLeft) + { + pLeft =&MiddleToBottom; + pRight =&TopToBottom; + } + else + { + pLeft =&TopToBottom; + pRight =&MiddleToBottom; + } + + while(Height--) + { + if(bStipple) + { + if(pLeft->y & 1) + { + if(pLeft->X <= pRight->X) + { + CurMapperFPU(pLeft, pRight); + } + else + { + CurMapperFPU(pRight, pLeft); + } + } + } + else + { + if(pLeft->X <= pRight->X) + { + CurMapperFPU(pLeft, pRight); + } + else + { + CurMapperFPU(pRight, pLeft); + } + } + StepFPU(pLeft); + StepFPU(pRight); + + Dest +=ClientWindow.PixelPitch / 2; + ZBufLine +=ClientWindow.Width; + pZBufferPtr =ZBufLine; + } +} + +BOOL DRIVERCC RenderMiscTexturePoly(DRV_TLVertex *Pnts, S32 NumPoints, geRDriver_THandle *THandle, U32 Flags) +{ + int i, GW_log2, MipLevel=0; + DRV_TLVertex TriVerts[3]; + + if(!bActive) + { + return GE_TRUE; + } + + assert(Pnts != NULL); + assert(NumPoints > 2); + + assert(THandle->BitPtr[MipLevel] != NULL); + + // Assign some global variables... + GMipLevel =(U8)MipLevel; + GW =THandle->Width >> MipLevel; + GH =THandle->Height >> MipLevel; + GWMask =GW-1; + GHMask =GH-1; + + if(THandle->Flags & THANDLE_TRANS) + { + PolyMode =1; + } + else + { + PolyMode =0; + } + + if(ProcessorInfo.Has3DNow) + { + *((int *)(&WrapMask)) =GHMask<<16; + *(((int *)((&WrapMask)))+1) =GWMask<<16; + + *((geFloat *)(&GBL)) =(geFloat)GH;//Mask; + *(((geFloat *)((&GBL)))+1) =(geFloat)GW;//Mask; + + //find log2 of the texture width + for(GW_log2=1;((1<PalHandle->BitPtr[0]; + GBitPtr = (U8 *)THandle->BitPtr[MipLevel]; + + bStipple =FALSE; + if(THandle->PixelFormat.Flags & RDRIVER_PF_HAS_ALPHA) + { + if(THandle->AlphaHandle) + { + ABitPtr =(U8 *)THandle->AlphaHandle->BitPtr[0]; + ATexPal =(U8 *)THandle->AlphaHandle->PalHandle->BitPtr[0]; + + CurMapper =DrawScanLineGouraudNoZAlphaTex_Asm3DNow; + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapper =DrawScanLineGouraudNoZAlphaTex_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudNoZBufferZWriteAlphaTex_Asm3DNow; + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapper =DrawScanLineGouraudZBufferNoZWriteAlphaTex_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudZBufferAlphaTex_Asm3DNow; + } + } + } + else + { + assert(THandle->PixelFormat.PixelFormat==GE_PIXELFORMAT_32BIT_ARGB); + CurMapper =DrawScanLineGouraudNoZAlphaARGB_Asm3DNow; +/* if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapper =DrawScanLineGouraudNoZAlphaTex_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudNoZBufferZWriteAlphaTex_Asm3DNow; + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapper =DrawScanLineGouraudZBufferNoZWriteAlphaTex_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudZBufferAlphaTex_Asm3DNow; + } + }*/ + } + } + else + { + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + if(PolyMode) + { + CurMapper =DrawScanLineGouraudNoZTrans_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudNoZ_Asm3DNow; + } + } + else + { + if(PolyMode) + { + CurMapper =DrawScanLineGouraudNoZBufferZWriteTrans_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudNoZBufferZWrite_Asm3DNow; + } + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + if(PolyMode) + { + CurMapper =DrawScanLineGouraudZBufferNoZWriteTrans_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudZBufferNoZWrite_Asm3DNow; + } + } + else + { + if(PolyMode) + { + CurMapper =DrawScanLineGouraudZBufferTrans_Asm3DNow; + } + else + { + CurMapper =DrawScanLineGouraudZBuffer_Asm3DNow; + } + } + } + } + if(NumPoints==3) + { + TriVerts[2] =Pnts[0]; + TriVerts[1] =Pnts[1]; + TriVerts[0] =Pnts[2]; + + TmapTriangle_32(TriVerts); + } + else + { + for(i=0;i < NumPoints-2;i++) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1+i]; + TriVerts[2] =Pnts[2+i]; + + TmapTriangle_32(TriVerts); + } + } + bStipple =FALSE; + return GE_TRUE; + } + else + { + for(GW_log2=1;((1<BitPtr[MipLevel]; + GBitPtrHalf =(U8 *)((U32)(GBitPtrHalf)>>1); + bStipple =FALSE; + + if(ClientWindow.G_mask == 0x03e0) + { + if(THandle->AlphaHandle) + { + bStipple =GE_TRUE; + /* if(bWindowed) + { + CurMapperFPU =DrawScanLineGouraudNoZAlphaTex_AsmX86FPU; + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudNoZAlphaTex_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWriteAlphaTex_AsmX86FPU; + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWriteAlphaTex_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBufferAlphaTex_AsmX86FPU; + } + } + } + else + {*/ + CurMapperFPU =DrawScanLineGouraudNoZTrans_Asm555X86FPU; + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudNoZTrans_Asm555X86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWriteTrans_Asm555X86FPU; + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWriteTrans_Asm555X86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBufferTrans_Asm555X86FPU; + } + } + // } + } + else + { + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + if(PolyMode) + { + CurMapperFPU =DrawScanLineGouraudNoZTrans_Asm555X86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZ_Asm555X86FPU; + } + } + else + { + if(PolyMode) + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWriteTrans_Asm555X86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWrite_Asm555X86FPU; + } + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + if(PolyMode) + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWriteTrans_Asm555X86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWrite_Asm555X86FPU; + } + } + else + { + if(PolyMode) + { + CurMapperFPU =DrawScanLineGouraudZBufferTrans_Asm555X86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBuffer_Asm555X86FPU; + } + } + } + } + } + else + { + if(THandle->AlphaHandle) + { + bStipple =GE_TRUE; + /* if(bWindowed) + { + CurMapperFPU =DrawScanLineGouraudNoZAlphaTex_AsmX86FPU; + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudNoZAlphaTex_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWriteAlphaTex_AsmX86FPU; + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWriteAlphaTex_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBufferAlphaTex_AsmX86FPU; + } + } + } + else + {*/ + CurMapperFPU =DrawScanLineGouraudNoZTrans_AsmX86FPU; + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudNoZTrans_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWriteTrans_AsmX86FPU; + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWriteTrans_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBufferTrans_AsmX86FPU; + } + } + // } + } + else + { + if(Flags & DRV_RENDER_NO_ZMASK) + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + if(PolyMode) + { + CurMapperFPU =DrawScanLineGouraudNoZTrans_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZ_AsmX86FPU; + } + } + else + { + if(PolyMode) + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWriteTrans_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudNoZBufferZWrite_AsmX86FPU; + } + } + } + else + { + if(Flags & DRV_RENDER_NO_ZWRITE) + { + if(PolyMode) + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWriteTrans_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBufferNoZWrite_AsmX86FPU; + } + } + else + { + if(PolyMode) + { + CurMapperFPU =DrawScanLineGouraudZBufferTrans_AsmX86FPU; + } + else + { + CurMapperFPU =DrawScanLineGouraudZBuffer_AsmX86FPU; + } + } + } + } + } + if(NumPoints==3) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1]; + TriVerts[2] =Pnts[2]; + TriVerts[0].u *=GWMask; + TriVerts[0].v *=GHMask; + TriVerts[1].u *=GWMask; + TriVerts[1].v *=GHMask; + TriVerts[2].u *=GWMask; + TriVerts[2].v *=GHMask; + + TmapTriangle_16(TriVerts); + } + else + { + for(i=0;i < NumPoints-2;i++) + { + TriVerts[0] =Pnts[0]; + TriVerts[1] =Pnts[1+i]; + TriVerts[2] =Pnts[2+i]; + + TriVerts[0].u *=GWMask; + TriVerts[0].v *=GHMask; + TriVerts[1].u *=GWMask; + TriVerts[1].v *=GHMask; + TriVerts[2].u *=GWMask; + TriVerts[2].v *=GHMask; + + TmapTriangle_16(TriVerts); + } + } + bStipple =FALSE; + return GE_TRUE; + } + +} + + +#if 0 +BOOL DRIVERCC BlitDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) +{ + S32 w, h, Width, Height, Stride; + + return GE_TRUE; + + if(x >= ClientWindow.PixelPitch) + return GE_TRUE; + if(y >= ClientWindow.Height) + return GE_TRUE; + + if(!THandle) + { + SetLastDrvError(DRV_ERROR_INVALID_PARMS, "SOFT_DrawDecal: NULL THandle parm."); + return FALSE; + } + + if(THandle->Id < 0 || THandle->Id > MAX_DECALS || !Decals[THandle->Id].Used) + { + SetLastDrvError(DRV_ERROR_GENERIC, "SOFT_DrawDecal: Invalid decal."); + return FALSE; + } + + if(ProcessorInfo.Has3DNow) + { + U8 *BitPtr; + U32 *pScrPtr2; + DRV_RGB *PalPtr =THandle->Palette; + + BitPtr =(U8 *)Decals[THandle->Id].BitPtr; + Width =Stride =Decals[THandle->Id].Width; + Height =Decals[THandle->Id].Height; + + if(SRect) + { + BitPtr += SRect->top*Width + SRect->left; + Height = SRect->bottom - SRect->top; + Width = SRect->right - SRect->left; + } + + if(x < 0) + { + if(x+Width <= 0) + return GE_TRUE; + BitPtr -= x; + Width += x; + x=0; + } + + if(y < 0) + { + if(y+Height <= 0) + return GE_TRUE; + BitPtr -= (y*Stride); + Height += y; + y=0; + } + + if(x + Width >= (ClientWindow.PixelPitch-1)) + Width -= (x+Width) - (ClientWindow.PixelPitch-1); + + if(y + Height >= (ClientWindow.Height-1)) + Height -= (y+Height) - (ClientWindow.Height-1); + + pScrPtr32bpp =(U32*)(ClientWindow.Buffer); + pScrPtr32bpp =&pScrPtr32bpp[y *ClientWindow.PixelPitch + x]; + pScrPtr2 =pScrPtr32bpp; + + Stride -= Width; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + U8 idx =*BitPtr++; + if(idx != 0xff) + *pScrPtr32bpp =*((U32 *)&PalPtr[idx]); + + pScrPtr32bpp++; + } + BitPtr +=Stride; + pScrPtr2+=ClientWindow.PixelPitch; + pScrPtr32bpp =pScrPtr2; + } + } + else + { + U16 *BitPtr; + U16 *pScrPtr2; + + BitPtr = Decals[THandle->Id].BitPtr; + Width = Stride = Decals[THandle->Id].Width; + Height = Decals[THandle->Id].Height; + + if(SRect) + { + BitPtr += SRect->top*Width + SRect->left; + Height = SRect->bottom - SRect->top; + Width = SRect->right - SRect->left; + } + + if(x < 0) + { + if(x+Width <= 0) + return GE_TRUE; + BitPtr -= x; + Width += x; + x=0; + } + + if(y < 0) + { + if(y+Height <= 0) + return GE_TRUE; + BitPtr -= (y*Stride); + Height += y; + y=0; + } + + if(x + Width >= (ClientWindow.PixelPitch-1)) + Width -= (x+Width) - (ClientWindow.PixelPitch-1); + + if(y + Height >= (ClientWindow.Height-1)) + Height -= (y+Height) - (ClientWindow.Height-1); + + pScrPtr16bpp = (U16*)(ClientWindow.Buffer); + pScrPtr16bpp = &pScrPtr16bpp[y *ClientWindow.PixelPitch + x]; + pScrPtr2 = pScrPtr16bpp; + + Stride -= Width; + + for (h=0; h< Height; h++) + { + for (w=0; w< Width; w++) + { + U16 Color = *BitPtr++; + if(Color != 0xffff) + *pScrPtr16bpp = Color; + + pScrPtr16bpp++; + } + BitPtr += Stride; + pScrPtr2 += ClientWindow.PixelPitch; + pScrPtr16bpp = pScrPtr2; + } + } + return GE_TRUE; +} +#endif + +static S32 BWidth, BHeight, BStride; +static S32 DrawWidth, DrawHeight; +static S32 EbpAdd, EdiAdd; +static U16 *BBitPtr16; +static U8 *BBitPtr; +extern VidModeList *cmode; +extern RECT FrontRect; + +BOOL DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) +{ + U32 *PalPtr; + + if(!bActive) + { + return GE_TRUE; + } + /* + if(SRect) + { + OutputDebugString("What the !?!?!\n"); + return DDrawBlitDecal(Decals[Bitmap->Id].Surface, SRect, x, y); + } + else + { + RECT SrcRect; + SrcRect.left=0; + SrcRect.top=0; + SrcRect.right=Bitmap->Width-1; + SrcRect.bottom=Bitmap->Height-1; + OutputDebugString("NULL rect2\n"); +// return DDrawBlitDecal(Decals[Bitmap->Id].Surface, &SrcRect, x, y); + DDrawBlitDecal(Decals[Bitmap->Id].Surface, &SrcRect, x, y); + + } + */ +// POINT uleft; +// uleft.x =x; +// uleft.y =y; + +/* if(!bWindowed) + { + if(cmode->flags & STRETCHMODE) + { + if(!PtInRect(&FrontRect, uleft)) + { + DDrawBlitDecalToFront(Decals[Bitmap->Id].Surface, SRect, x, y); + return GE_TRUE; + } + } + else if((!bBackLocked && !bWindowed)) + { + DDrawBlitDecalDelayed(Decals[Bitmap->Id].Surface, SRect, x, y); + return GE_TRUE; +// } + } +// return GE_TRUE; +*/ + + BWidth =THandle->Width; + BHeight =THandle->Height; + DrawWidth =THandle->Width; + DrawHeight =THandle->Height; + + if(ProcessorInfo.Has3DNow ) + { + BBitPtr =(U8 *)THandle->BitPtr[0]; + + if ( ! THandle->PalHandle ) + return 0; + + PalPtr =(U32 *)THandle->PalHandle->BitPtr[0]; + + if(SRect) + { + BBitPtr +=SRect->top * DrawWidth + SRect->left; + DrawHeight =(SRect->bottom - SRect->top); + DrawWidth =(SRect->right - SRect->left); + } + + if(x < 0) + { + if(x + DrawWidth <= 0) + { + return GE_TRUE; + } + BBitPtr -=x; + DrawWidth +=x; + x =0; + } + + if(y < 0) + { + if(y + DrawHeight <= 0) + { + return GE_TRUE; + } + BBitPtr -=y * BWidth; + DrawHeight +=y; + y =0; + } + + if(x >= ClientWindow.Width) + { + return GE_TRUE; + } + if(y >= ClientWindow.Height) + { + return GE_TRUE; + } + + if(x + DrawWidth >= (ClientWindow.Width-1)) + DrawWidth -= (x+DrawWidth) - (ClientWindow.Width-1); + + if(y + DrawHeight >= (ClientWindow.Height-1)) + DrawHeight -= (y+DrawHeight)- (ClientWindow.Height-1); + + if(DrawWidth <= 0) + return GE_TRUE; + + if(DrawHeight <= 0) + return GE_TRUE; + + pScrPtr32bpp =(U32 *)(ClientWindow.Buffer); + pScrPtr32bpp =&pScrPtr32bpp[y * ClientWindow.Width + x]; + + __asm + { + push ecx + push esi + push edi + push ebp + + mov ebx,PalPtr + + mov ebp, pScrPtr32bpp + mov edi, BBitPtr + + mov ecx, DrawWidth + + mov edx, ClientWindow.PixelPitch + shl ecx,2 + sub edx, ecx + mov EbpAdd, edx + + mov edx, BWidth + mov ecx, DrawHeight + sub edx, DrawWidth + mov EdiAdd, edx + + + NextHeight: + + push ecx + mov ecx, DrawWidth + + lea ebp,[4*ecx+ebp] + + add edi, ecx +// shl ecx, 2 +// add ebp, ecx + + neg ecx + + NextWidth: + xor eax,eax + mov al, [edi+ecx] + + cmp al,0ffh + je Skip + +// cmp al,01h +// je Skip + + mov eax,[ebx+eax*4] + + mov [ebp+ecx*4], eax + + Skip: + inc ecx + jnz NextWidth + + add ebp, EbpAdd + add edi, EdiAdd + + pop ecx + + sub ecx, 1 + jnz NextHeight + + pop ebp + pop edi + pop esi + pop ecx + } + } + else + { + BBitPtr16 =THandle->BitPtr[0]; + if(SRect) + { + BBitPtr16 +=SRect->top * DrawWidth + SRect->left; + DrawHeight =(SRect->bottom - SRect->top); + DrawWidth =(SRect->right - SRect->left); + } + + if(x < 0) + { + if(x + DrawWidth <= 0) + { + return GE_TRUE; + } + BBitPtr16 -=x; + DrawWidth +=x; + x =0; + } + + if(y < 0) + { + if(y + DrawHeight <= 0) + { + return GE_TRUE; + } + BBitPtr16 -=y*BWidth; + DrawHeight +=y; + y =0; + } + + if(x >= ClientWindow.Width) + { + return GE_TRUE; + } + if(y >= ClientWindow.Height) + { + return GE_TRUE; + } + + if(x + DrawWidth >= (ClientWindow.Width - 1)) + { + DrawWidth -=(x + DrawWidth) - (ClientWindow.Width - 1); + } + if(y + DrawHeight >= (ClientWindow.Height - 1)) + { + DrawHeight -=(y + DrawHeight) - (ClientWindow.Height - 1); + } + + if(DrawWidth <= 0) + { + return GE_TRUE; + } + if(DrawHeight <= 0) + { + return GE_TRUE; + } + + pScrPtr16bpp =(U16 *)(ClientWindow.Buffer); + pScrPtr16bpp =&pScrPtr16bpp[y * (ClientWindow.PixelPitch >> 1) + x]; + + __asm + { + push ecx + push esi + push edi + push ebp + + mov ebp, pScrPtr16bpp + mov edi, BBitPtr16 + + mov ecx, DrawWidth + + mov edx, ClientWindow.PixelPitch + sub edx, ecx + sub edx, ecx + mov EbpAdd, edx + + mov edx, BWidth + add edx, BWidth + sub edx, ecx + sub edx, ecx + mov EdiAdd, edx + + mov ecx, DrawHeight + + NextHeightA: + + push ecx + mov ecx, DrawWidth + + shl ecx, 1 + add ebp, ecx + add edi, ecx + + neg ecx + + NextWidthA: + mov ax, [edi+ecx] + + cmp ax, 0x1 + je SkipA + + mov [ebp+ecx], ax + + SkipA: + add ecx, 2 + jnz NextWidthA + + add ebp, EbpAdd + add edi, EdiAdd + + pop ecx + + sub ecx, 1 + jnz NextHeightA + + pop ebp + pop edi + pop esi + pop ecx + } + } + return GE_TRUE; +} + +static Fixed16 UStep, VStep, ZStep; +static int32 Length; +static uint16 Color; +static int32 ESPSave; + +void ClearZBuffer(DRV_Window *Window) +{ + //hahhah memcpy is faster than anything I can do + //return; + S32 ZBSize; +/* if(0 && ProcessorInfo.Has3DNow) + { + ZBSize =(Window->Width*Window->Height)>>5; + + _asm _emit 0x0f \ + _asm _emit 0x0e \ + _asm mov eax,[ZBuffer] + _asm mov ebx,[ZBuffer] + _asm mov ecx,dword ptr[ZBSize] +// _asm _emit 0x0f \ +// _asm _emit 0x0d \ +// _asm _emit 0x00 + _asm movq mm0,[Zero] + _asm movq mm1,[Zero] +// _asm movq mm2,[Zero] +// _asm movq mm3,[Zero] +// _asm movq mm4,[Zero] +// _asm movq mm5,[Zero] +// _asm movq mm6,[Zero] +// _asm movq mm7,[Zero] +// _asm _emit 0x0f \ +// _asm _emit 0x0d \ +// _asm _emit 0x40 \ +// _asm _emit 0x20 +ClearLoop3DNow: + _asm movq [eax],mm0 + _asm movq [ebx+32],mm1 +// _asm _emit 0x0f \ +// _asm _emit 0x0d \ +// _asm _emit 0x40 \ +// _asm _emit 0x40 + _asm movq [eax+8],mm0 + _asm movq [ebx+40],mm1 + _asm movq [eax+16],mm0 + _asm movq [ebx+48],mm1 + _asm movq [eax+24],mm0 + _asm movq [ebx+56],mm1 + _asm add eax,64 + _asm add ebx,64 +// _asm _emit 0x0f \ +// _asm _emit 0x0d \ +// _asm _emit 0x40 \ +// _asm _emit 0x60 + _asm dec ecx + _asm jnz ClearLoop3DNow + _asm _emit 0x0f \ + _asm _emit 0x0e \ + } + else if(0 && ProcessorInfo.HasMMX) + { + ZBSize =(Window->Width*Window->Height)>>4; + + _asm emms + _asm mov eax,[ZBuffer] + _asm mov ecx,dword ptr[ZBSize] + _asm movq mm0,[Zero] +ClearLoop: + _asm movq [eax],mm0 + _asm movq [eax+8],mm0 + _asm movq [eax+16],mm0 + _asm movq [eax+24],mm0 + _asm add eax,32 + _asm dec ecx + _asm jnz ClearLoop + _asm emms + } + else +*/ { + ZBSize = (Window->Width*Window->Height)<<1; + memset(ZBuffer, 0, ZBSize); + } +} + +//=========================================================================================== +// Render Sys init, de-init code +//=========================================================================================== +BOOL RenderInit(DRV_Window *Window) +{ +// U32 OldFlags =0; + + ZBuffer =(U16 *)malloc(ClientWindow.Width * ClientWindow.Height * 2); + +/* if(!VirtualProtect((U8 *)ZBuffer, + (ClientWindow.Width * ClientWindow.Height)*2, + PAGE_READWRITE | PAGE_NOCACHE, + &OldFlags)) + { + ErrorPrintf("Failed to set zbuffer page uncacheable\n"); + } +*/ + if(!ZBuffer) + { + SetLastDrvError(DRV_ERROR_NO_MEMORY, "SOFT_RenderInit: Not enough memory for ZBuffer."); + return FALSE; + } + + #define Mul(a) (uint32)((1.0f/(geFloat)(a))*65536*32768) + //#define Mul(a) ((uint32)((1.0f/(geFloat)(a))*(1<<31))) + + return GE_TRUE; +} + +BOOL RenderShutdown(void) +{ + if(ZBuffer) + { + free(ZBuffer); + ZBuffer =NULL; + } + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/SoftDrv/scene.c b/G3D/Engine/Drivers/SoftDrv/scene.c new file mode 100644 index 0000000..157aa27 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/scene.c @@ -0,0 +1,251 @@ +/****************************************************************************************/ +/* scene.c */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: Init and state related code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include + +#include "SoftDrv.h" +#include "DCommon.h" +#include "Render.h" +#include "Scene.h" +#include "Span.h" +#include "System.h" +#include "Sal.h" +#include "dmodes.h" + +S32 RenderMode = RENDER_NONE; + +VidModeList *cmode=NULL; + +//global rect!!!!! Will be dangerous future +RECT WorldRect; +RECT FrontRect; +U16 FPUCW, OldFPUCW; + +extern CPUInfo ProcessorInfo; + +void SetFPU24(void) +{ + _asm + { + fstcw [OldFPUCW] ; store copy of CW + mov ax, OldFPUCW ; get it in ax + and eax,0xFFFFFCFF +// or eax,0x0000600 + mov [FPUCW],ax ; store it + fldcw [FPUCW] ; load the FPU + } +} + +void RestoreFPU(void) +{ + _asm fldcw [OldFPUCW] ; restore the FPU +} + +BOOL DRIVERCC BeginScene(BOOL Clear, BOOL ClearZ, RECT *pWorldRect) +{ + if(ProcessorInfo.Has3DNow) + { + SetFPU24(); + } + + if (RenderMode != RENDER_NONE) + { + SetLastDrvError(DRV_ERROR_GENERIC, "Still in some other render mode."); + return FALSE; + } + + if(0 && pWorldRect) //offsets still relative to the top of the screen + { + WorldRect =*pWorldRect; + WorldRect.right; + WorldRect.bottom; + } + else //use full screen + { + WorldRect.left =WorldRect.top =0; + WorldRect.right =ClientWindow.Width - 1; + WorldRect.bottom=ClientWindow.Height - 1; + } + + if(!bWindowed) + { + if(cmode->flags & STRETCHMODE) + { + geFloat xstrch, ystrch; + + xstrch =640.0f / ((geFloat)ClientWindow.Width); + ystrch =480.0f / ((geFloat)ClientWindow.Height); + FrontRect.left =(int)(xstrch * (geFloat)WorldRect.left); + FrontRect.right =(int)(xstrch * (geFloat)WorldRect.right); + FrontRect.bottom=(int)(ystrch * (geFloat)WorldRect.bottom); + FrontRect.top =(int)(ystrch * (geFloat)WorldRect.top); + } + } + + NumPixels = 0; + + if(ClearZ) + { + ClearZBuffer(&ClientWindow); + } + if(Clear) + { + if(bWindowed) + { + SAL_wipe_surface(SAL_BACK_SURFACE, 0); + } + else + { + ClearBackBuffer(&ClientWindow); + } + } + + if(bWindowed) + { + SAL_lock_surface(SAL_BACK_SURFACE, &ClientWindow.Buffer, &ClientWindow.PixelPitch); + } + else + { + if(!LockDDrawBackBuffer(&ClientWindow, &WorldRect)) + { + SetLastDrvError(DRV_ERROR_INVALID_PARMS, "World rect invalid."); + DumpErrorLogToFile("softdrv.log"); + return FALSE; + } + } + assert(ClientWindow.Buffer); + + return TRUE; +} + +BOOL DRIVERCC EndScene(void) +{ + if (RenderMode != RENDER_NONE) + { + SetLastDrvError(DRV_ERROR_GENERIC, "Still in some other render mode."); + return FALSE; + } + if(bWindowed) + { + SAL_release_surface(SAL_BACK_SURFACE, FALSE); +// SAL_flip_surface(); + SAL_blit_surface(); + SAL_serve_message_queue(); + } + else + { + UnlockDDrawBackBuffer(&ClientWindow, &WorldRect); + RefreshDDraw(&ClientWindow, cmode, &WorldRect, &FrontRect); + } + +// SOFTDRV.NumWorldSpans = RegPixels; +// SOFTDRV.NumRenderedPolys = RGBPixels; + + if(ProcessorInfo.Has3DNow) + { + RestoreFPU(); + } + + return TRUE; +} + +static U32 OldFlags =0; + +BOOL DRIVERCC BeginWorld(void) +{ + if (RenderMode != RENDER_NONE && RenderMode != RENDER_WORLD) + { + SetLastDrvError(DRV_ERROR_GENERIC, "Still in some other render mode."); + return FALSE; + } + + ResetSpans(ClientWindow.Height); + + RenderMode = RENDER_WORLD; + +// if(!VirtualProtect((U8 *)ZBuffer, +// (ClientWindow.Width * ClientWindow.Height)*2, +// PAGE_READWRITE | PAGE_NOCACHE, +// &OldFlags)) +// { +// ErrorPrintf("Failed to set zbuffer page uncacheable\n"); +// } + + return TRUE; +} + +BOOL DRIVERCC EndWorld(void) +{ + RenderMode = RENDER_NONE; + +// if(!VirtualProtect((U8 *)ZBuffer, +// (ClientWindow.Width * ClientWindow.Height)*2, +// OldFlags, &OldFlags)) +// { +// ErrorPrintf("Failed to set zbuffer page cacheable\n"); +// } + return TRUE; +} + +BOOL DRIVERCC BeginMeshes(void) +{ + if (RenderMode != RENDER_NONE) + { + SetLastDrvError(DRV_ERROR_GENERIC, "Still in some other render mode."); + return FALSE; + } + + ResetSpans(ClientWindow.Height); + NumPixels = 0; + RenderMode = RENDER_MESHES; + + return TRUE; +} + +BOOL DRIVERCC EndMeshes(void) +{ + RenderMode = RENDER_NONE; + + return TRUE; +} + +BOOL DRIVERCC BeginModels(void) +{ + if (RenderMode != RENDER_NONE) + { + SetLastDrvError(DRV_ERROR_GENERIC, "Still in some other render mode."); + return FALSE; + } + ResetSpans(ClientWindow.Height); + NumPixels = 0; + + RenderMode = RENDER_MODELS; + + return TRUE; +} + +BOOL DRIVERCC EndModels(void) +{ + RenderMode = RENDER_NONE; + return TRUE; +} diff --git a/G3D/Engine/Drivers/SoftDrv/softdrv.c b/G3D/Engine/Drivers/SoftDrv/softdrv.c new file mode 100644 index 0000000..2feef96 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/softdrv.c @@ -0,0 +1,946 @@ +/****************************************************************************************/ +/* softdrv.c */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: Init, mode, and cpu identification code */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include +#include + +#include "SoftDrv.h" +#include "System.h" +#include "DCommon.h" +#include "Sal.h" + +#include "Register.h" +#include "Scene.h" +#include "Render.h" +#include "dmodes.h" + +static DRV_CacheInfo CacheInfo; +static VidEnumInfo VidInfo[16]; +static VidEnumInfo *VInfo; + +extern VidModeList *cmode; +extern DRV_Window ClientWindow ={ 0 }; +extern CPUInfo ProcessorInfo ={ 0 }; +extern int NumDevices =0; + +S32 LastError; +char LastErrorStr[200]; + +BOOL DRIVERCC EnumSubDrivers(DRV_ENUM_DRV_CB *Cb, void *Context); +BOOL DRIVERCC EnumModes(S32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context); +BOOL DRIVERCC SetDrvRenderState(S32 State, U32 Flag); +BOOL DRIVERCC GetDrvRenderState(S32 State, U32 *Flag); +BOOL DRIVERCC EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context); + +typedef unsigned __int64 QWORD; +//#define RDTSC _asm _emit 0fh _asm _emit 031h +#define CPUID _asm _emit 0fh _asm _emit 0a2h + +BOOL DRIVERCC ScreenShot(const char *Name); +static U32 GetCPUIDEAX(U32 funcNum); +static U32 GetCPUIDEDX(U32 funcNum); +static U32 GetCPUIDString(U32 funcNum, char *szId); +static void GetCPUIDStringAMD(U32 funcNum, char *szId); +//static QWORD GetRDTSC(void); +//static U32 GetRDTSCOverHead(void); +//static U32 GetProcessorSpeed(void); +static void GetCPUInfo(void); + +extern __int64 QZBufferPrec =0; +extern __int64 QFixedScale =0; +extern __int64 QFixedScale16 =0; +extern __int64 Q128 =0; +extern double Magic, MipMagic, MipMagic2; + +void SetupMiscConstants(void) +{ + *(((geFloat *)((&QZBufferPrec)))+1) =-ZBUFFER_PREC; + *((geFloat *)(&QZBufferPrec)) =-ZBUFFER_PREC; + + *(((geFloat *)((&QFixedScale16)))+1) =4096.0f; + *((geFloat *)(&QFixedScale16)) =4096.0f; + + *(((geFloat *)((&QFixedScale)))+1) =65536.0f; + *((geFloat *)(&QFixedScale)) =65536.0f; + + *((geFloat *)&Q128) =128.0f; + *(((geFloat *)((&Q128)))+1) =128.0f; + + Magic =ldexp(1.5, 60); + MipMagic =ldexp(1.5, 52-16); + MipMagic2 =ldexp(1.5, 52-12); +} + + +//big chunk of duplicated code to resetup stuff that +//gets nuked when the driver is freed +BOOL DRIVERCC DrvInit(DRV_DriverHook *Hook) +{ + RECT window_rect; //for resetting (thanks mike!) + BOOL result; + + VInfo =&VidInfo[Hook->Driver]; + VInfo->bpp =16; + + GetCPUInfo(); + + window_rect.left = -1; + window_rect.top = -1; + window_rect.right = -1; + window_rect.bottom = -1; + + SetLastError( ERROR_SUCCESS ); + + DoEnumeration(VInfo); + DoModeEnumeration(VInfo); + + //check for windowed mode + if(Hook->Mode==VInfo->NumVidModes) + { + bWindowed =TRUE; + + if (!SAL_startup(FALSE)) + { + SetLastDrvError(DRV_ERROR_INIT_ERROR, "SOFT_DrvInit: Could not initialize SAL."); + DumpErrorLogToFile("softdrv.log"); + return FALSE; + } + + result = GetClientRect(Hook->hWnd, &window_rect); + if( !result || window_rect.right == -1 || window_rect.bottom == -1 ) + { + // This means you probably passed in an illegal hwnd. + int err = GetLastError(); + assert( result ); + DumpErrorLogToFile("softdrv.log"); + return FALSE; + } + + SAL_set_main_window(Hook->hWnd); + ClientWindow.Width = (window_rect.right - window_rect.left); + ClientWindow.Height = (window_rect.bottom - window_rect.top); + + assert( ClientWindow.Width > 0 ); + assert( ClientWindow.Height > 0 ); + + if(ProcessorInfo.Has3DNow) + { + if(!SAL_set_display_mode(ClientWindow.Width, + ClientWindow.Height, + 32, + SAL_WINDOW, + TRUE)) + { + SetLastDrvError(DRV_ERROR_INIT_ERROR, "SOFT_DrvInit: Could not set display mode."); + DumpErrorLogToFile("softdrv.log"); + return FALSE; + } + } + else + { + if(!SAL_set_display_mode(ClientWindow.Width, + ClientWindow.Height, + 16, + SAL_WINDOW, + TRUE)) + { + SetLastDrvError(DRV_ERROR_INIT_ERROR, "SOFT_DrvInit: Could not set display mode."); + DumpErrorLogToFile("softdrv.log"); + return FALSE; + } + } + } + else + { + if(!DoDDrawInit(Hook->hWnd, VInfo)) + { + DumpErrorLogToFile("softdrv.log"); + return FALSE; + } + ClientWindow.Width = Hook->Width; + ClientWindow.Height = Hook->Height; + if(VInfo->VidModes[Hook->Mode].flags & STRETCHMODE) + { + if(VInfo->VidModes[Hook->Mode].width > 640) + { +// ClientWindow.Width =640; +// ClientWindow.Height =(((geFloat)ClientWindow.Width)/(geFloat)Hook->Width)*(geFloat)Hook->Height; + } + } + + if(!SetDDrawMode(Hook->Mode, VInfo)) + { + return FALSE; + } + ClientWindow.PixelPitch =VInfo->VidModes[Hook->Mode].pitch>>2; + cmode =&VInfo->VidModes[Hook->Mode]; + } + + if(!SysInit()) + { // LastDriverError should be set in here... + DumpErrorLogToFile("softdrv.log"); + return FALSE; // so just return false, and assume it's set + } + + SetLastDrvError(DRV_ERROR_NONE, "SOFT_DrvInit: No error."); + SetupMiscConstants(); + + return TRUE; +} + +BOOL DRIVERCC DrvShutdown(void) +{ + SysShutdown(); + + if(bWindowed) + { + SAL_shutdown(); + } + else + { + FreeDDraw(VInfo); + } + + DumpErrorLogToFile("softdrv.log"); + + return TRUE; +} + +void DRIVERCC ErrorBox(char *Str) +{ + DrvShutdown(); + DumpErrorLogToFile("softdrv.log"); +} + +BOOL DRIVERCC SetGamma(geFloat Gamma) +{ + return TRUE; +} + +BOOL DRIVERCC GetGamma(geFloat *Gamma) +{ + assert(Gamma); + + *Gamma = 1.0f; + + return TRUE; +} + +geBoolean DRIVERCC DrvUpdateWindow(void) +{ + return GE_TRUE; +} + +geBoolean DRIVERCC Drv_SetFogEnable(geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End) +{ + Enable,r,g,b,Start,End; + return GE_FALSE; +} + +DRV_Driver SOFTDRV = +{ + "Software driver. v"DRV_VMAJS"."DRV_VMINS". Copyright 1999, WildTangent Inc.; All Rights Reserved.", + DRV_VERSION_MAJOR, + DRV_VERSION_MINOR, + + DRV_ERROR_NONE, + NULL, + + EnumSubDrivers, + EnumModes, + EnumPixelFormats, + + DrvInit, + DrvShutdown, + DrvResetAll, + DrvUpdateWindow, + DrvSetActive, + + CreateTexture, + DestroyTexture, + + LockTextureHandle, + UnLockTextureHandle, + + SetPalette, + GetPalette, + SetAlpha, + GetAlpha, + + THandle_GetInfo, + + BeginScene, + EndScene, + BeginWorld, + EndWorld, + BeginMeshes, + EndMeshes, + BeginModels, + EndModels, + + RenderGouraudPoly, + RenderWorldPoly, + RenderMiscTexturePoly, + + DrawDecal, + + 0,0,0, + + &CacheInfo, + + ScreenShot, + + SetGamma, + GetGamma, + + Drv_SetFogEnable, + + NULL, + NULL, // Init to NULL, engine SHOULD set this (SetupLightmap) + NULL +}; + +DRV_EngineSettings EngineSettings; + +DllExport BOOL DriverHook(DRV_Driver **Driver) +{ + EngineSettings.CanSupportFlags = (DRV_SUPPORT_ALPHA|DRV_SUPPORT_COLORKEY); + EngineSettings.PreferenceFlags = (DRV_PREFERENCE_NO_MIRRORS | DRV_PREFERENCE_DRAW_WALPHA_IN_BSP); + + SOFTDRV.EngineSettings = &EngineSettings; + + *Driver = &SOFTDRV; + + // Make sure the error string ptr is not null, or invalid!!! + SOFTDRV.LastErrorStr = LastErrorStr; + + SetLastDrvError(DRV_ERROR_NONE, "SOFT_DRV: No error."); + + return TRUE; +} + +void SetLastDrvError(S32 Error, char *ErrorStr) +{ + LastError = Error; + + if (ErrorStr) + { + strcpy(LastErrorStr, ErrorStr); + } + else + LastErrorStr[0] = 0; + + SOFTDRV.LastErrorStr = LastErrorStr; + SOFTDRV.LastError = LastError; +} + +BOOL DRIVERCC ScreenShot(const char *Name) +{ + return FALSE; +} + +BOOL DRIVERCC EnumSubDrivers(DRV_ENUM_DRV_CB *Cb, void *Context) +{ + int i; + char szTemp[256]; + + NumDevices =0; + + GetCPUInfo(); + if (ProcessorInfo.Has3DNow) + { + DoEnumeration(VidInfo); + for(i=0;i < NumDevices;i++) + { + sprintf(szTemp, "Software AMD 3DNow!(tm) v"DRV_VMAJS"."DRV_VMINS"."); //, VidInfo[i].DeviceInfo.szDescription); + if(!Cb(i, szTemp, Context)) + { + return TRUE; + } + } + if(!NumDevices) + { + sprintf(szTemp, "Software AMD 3DNow!(tm) v"DRV_VMAJS"."DRV_VMINS"."); + if(!Cb(i, szTemp, Context)) + { + return TRUE; + } + } + } + return TRUE; +} + +BOOL DRIVERCC EnumModes(S32 Driver, char *DriverName, DRV_ENUM_MODES_CB *Cb, void *Context) +{ + int i; + RECT window_rect; //for resetting (thanks mike!) + char szTemp[256]; + + window_rect.left = -1; + window_rect.top = -1; + window_rect.right = -1; + window_rect.bottom = -1; + + SetLastError( ERROR_SUCCESS ); + VInfo =&VidInfo[Driver]; + VInfo->bpp =16; + + GetCPUInfo(); + if (!ProcessorInfo.Has3DNow) + return TRUE; + + if(NumDevices) + { + DoModeEnumeration(VInfo); + } + + for(i=0;i < VInfo->NumVidModes;i++) + { + if(VInfo->VidModes[i].flags & MODEXMODE) + { + sprintf(szTemp, "%dx%dx%d ModeX", VInfo->VidModes[i].width, VInfo->VidModes[i].height, VInfo->VidModes[i].bpp); + if(ProcessorInfo.Has3DNow) + { + //strcat(szTemp, " 3DNow!"); + } + Cb(i, szTemp, VInfo->VidModes[i].width, VInfo->VidModes[i].height, Context); + } + else if(VInfo->VidModes[i].flags & STRETCHMODE) + { + sprintf(szTemp, "%dx%dx%d Stretched", VInfo->VidModes[i].width, VInfo->VidModes[i].height, VInfo->VidModes[i].bpp); + if(ProcessorInfo.Has3DNow) + { + //strcat(szTemp, " 3DNow!"); + } + Cb(i, szTemp, VInfo->VidModes[i].width, VInfo->VidModes[i].height, Context); + } + else + { + sprintf(szTemp, "%dx%dx%d", VInfo->VidModes[i].width, VInfo->VidModes[i].height, VInfo->VidModes[i].bpp); + if(ProcessorInfo.Has3DNow) + { + //strcat(szTemp, " 3DNow!"); + } + Cb(i, szTemp, VInfo->VidModes[i].width, VInfo->VidModes[i].height, Context); + } + } + Cb(i, "Window Mode", -1, -1, Context); + + SetLastError( ERROR_SUCCESS ); + + return TRUE; +} + +geBoolean DRIVERCC EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context) +{ + geRDriver_PixelFormat Pixie; + + if(!cmode && !bWindowed) + { + //no mode set + return GE_FALSE; + } + else + { + if(ProcessorInfo.Has3DNow) + { + Pixie.PixelFormat =GE_PIXELFORMAT_8BIT; + Pixie.Flags =RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + Pixie.Flags =RDRIVER_PF_2D | RDRIVER_PF_CAN_DO_COLORKEY; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + Pixie.Flags =RDRIVER_PF_3D; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + Pixie.Flags =RDRIVER_PF_3D | RDRIVER_PF_ALPHA; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + Pixie.Flags =RDRIVER_PF_3D | RDRIVER_PF_HAS_ALPHA; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + + Pixie.PixelFormat =GE_PIXELFORMAT_32BIT_XRGB; + Pixie.Flags =RDRIVER_PF_PALETTE; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + + Pixie.PixelFormat =GE_PIXELFORMAT_32BIT_ARGB; + Pixie.Flags =RDRIVER_PF_PALETTE; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + + } + else + { + if(ClientWindow.G_mask == 0x3e0) //555 + { + Pixie.PixelFormat =GE_PIXELFORMAT_16BIT_555_RGB; + } + else + { + Pixie.PixelFormat =GE_PIXELFORMAT_16BIT_565_RGB; + } + + Pixie.Flags =RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + + Pixie.Flags =RDRIVER_PF_3D; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + + Pixie.Flags =RDRIVER_PF_2D; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + + Pixie.Flags =RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP | RDRIVER_PF_CAN_DO_COLORKEY; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + + Pixie.Flags =RDRIVER_PF_3D | RDRIVER_PF_CAN_DO_COLORKEY; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + + Pixie.Flags =RDRIVER_PF_2D | RDRIVER_PF_CAN_DO_COLORKEY; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + } + + Pixie.PixelFormat =GE_PIXELFORMAT_24BIT_RGB; + Pixie.Flags =RDRIVER_PF_LIGHTMAP; + if(!Cb(&Pixie, Context)) + { + return GE_TRUE; + } + } + return TRUE; +} + +BOOL DRIVERCC SetDrvRenderState(S32 State, U32 Flag) +{ + return TRUE; +} + +BOOL DRIVERCC GetDrvRenderState(S32 State, U32 *Flag) +{ + *Flag = 0; + return TRUE; +} + +int Flag_CPUID = FALSE; +int Flag_RDTSC = FALSE; + + +void Test_CPU_bits(void) +{ + Flag_CPUID = FALSE; + Flag_RDTSC = FALSE; +_asm + { + pushad // (1) play nice and save everything + pushfd // eax = ebx = extended flags + pop eax + mov ebx,eax + + xor eax,200000h // toggle bit 21 + + push eax // extended flags = eax + popfd + xor eax,ebx // if bit 21 r/w then eax <> 0 + + jz done // can't toggle id bit (21) no cpuid here + mov eax,1 // get standard features + mov Flag_CPUID,eax // (and set cpuid flag to true) + + CPUID + test edx,10h // is rdtsc available? + jz done + + mov Flag_RDTSC,1 +done: + popad // (1) restore everything + } +} + + + + +static U32 GetCPUIDEAX(U32 funcNum) +{ + U32 retval; + + Test_CPU_bits(); + if (Flag_CPUID) + { + __try + { + _asm + { + mov eax,funcNum + CPUID + mov retval,eax + } + }__except(EXCEPTION_EXECUTE_HANDLER) + { + retval =0; + } + } + else + { + retval = 0; + } + + return retval; +} + +static U32 GetCPUIDEDX(U32 funcNum) +{ + U32 retval; + + Test_CPU_bits(); + if (Flag_CPUID) + { + __try + { + _asm + { + mov eax,funcNum + CPUID + mov retval,edx + } + }__except(EXCEPTION_EXECUTE_HANDLER) + { + retval =0; + } + } + else + { + retval = 0; + } + + return retval; +} + +static U32 GetCPUIDString(U32 funcNum, char *szId) +{ + U32 retval; + + Test_CPU_bits(); + if (Flag_CPUID) + { + __try + { + _asm + { + mov eax,funcNum + CPUID + mov retval,eax + mov eax,szId + mov dword ptr[eax],ebx + mov dword ptr[eax+4],edx + mov dword ptr[eax+8],ecx + } + }__except(EXCEPTION_EXECUTE_HANDLER) + { + retval =0; + } + } + else + { + retval = 0; + } + + return retval; +} + +static void GetCPUIDStringAMD(U32 funcNum, char *szId) +{ + U32 retval; + + Test_CPU_bits(); + if (Flag_CPUID) + { + __try + { + _asm + { + mov eax,funcNum + CPUID + mov retval,eax + mov eax,szId + mov dword ptr[eax+4],ebx + mov dword ptr[eax+8],ecx + mov ebx,retval + mov dword ptr[eax+12],edx + mov dword ptr[eax],ebx + } + }__except(EXCEPTION_EXECUTE_HANDLER) + { + retval =0; + } + } + else + { + retval = 0; + } +} + +// For out of order processors, the cpuid does serliaization +// On all processors, additional overhead is added +/* +static QWORD GetRDTSC(void) +{ + QWORD clock; + + _asm + { + push ebx + push ecx + xor eax,eax + CPUID + RDTSC + mov dword ptr clock,eax + mov dword ptr clock+4,edx + xor eax,eax + CPUID + pop ecx + pop ebx + } + return clock; +} +*/ + +/* +static U32 GetRDTSCOverHead(void) +{ + U32 elap, MinOverhead =0xffffff; + QWORD start; + int x; + + for(x=0;x < 50;x++) + { + start =GetRDTSC(); + elap =(U32)(GetRDTSC() - start); + MinOverhead =min(MinOverhead, elap); + } + return MinOverhead; +} +*/ + +/* +static U32 GetProcessorSpeed(void) +{ + QWORD StartClock, ElapClock; + U32 StartTime, RetVal, times =0; + + // try to get rid of the variability + StartClock =GetRDTSC(); + StartTime =timeGetTime(); + + // this loop should take 1 sec +- 1 ms + while(timeGetTime() < StartTime + 250); + + ElapClock =GetRDTSC() - StartClock + 500000; + + // try to get rid of the variability + StartClock =GetRDTSC(); + StartTime =timeGetTime(); + + // this loop should take 1 sec +- 1 ms + while(timeGetTime() < StartTime + 1000); + + ElapClock =GetRDTSC() - StartClock + 500000; + RetVal =(U32)(ElapClock/1000000); + return RetVal; +} +*/ + +static char buffer[32768]; //this is ... cautious +static char buf3[4096]; + +void ErrorPrintf(char *text, ...) +{ + va_list argptr; + + va_start(argptr,text); + vsprintf(buf3, text,argptr); + va_end(argptr); + + strcat(buffer, buf3); +} + +void DumpErrorLogToFile(char *fname) +{ + FILE *f; + SYSTEMTIME Time; + + f =fopen(fname, "a+t"); + + if(f) + { + GetSystemTime(&Time); + + fprintf(f,"=================================================================\n"); + fprintf(f,"Time: %2i:%2i:%2i\n", Time.wHour, Time.wMinute, Time.wSecond); + fprintf(f,"Date: %2i-%2i-%4i\n", Time.wMonth, Time.wDay, Time.wYear); + + fwrite(buffer, 1, strlen(buffer), f); + fclose(f); + } +} + +static void GetCPUInfo(void) +{ + memset(&ProcessorInfo, 0, sizeof(ProcessorInfo)); + + ProcessorInfo.MaxCPUIDVal =GetCPUIDString(0, ProcessorInfo.VendorString); + ProcessorInfo.VendorString[13] =0; + if(strncmp(ProcessorInfo.VendorString, "AuthenticAMD", 12)==0) + { + U32 TypeFlags =GetCPUIDEAX(0x80000000); + if(TypeFlags) //extended functions supported + { + TypeFlags =GetCPUIDEDX(0x80000001); + GetCPUIDStringAMD(0x80000002, ProcessorInfo.ProcName); + GetCPUIDStringAMD(0x80000003, ProcessorInfo.ProcName+16); + GetCPUIDStringAMD(0x80000004, ProcessorInfo.ProcName+32); + ErrorPrintf("CPU Family: %s\n", ProcessorInfo.ProcName); + ProcessorInfo.HasMMX =TypeFlags & (1<<23); + ProcessorInfo.Has3DNow =TypeFlags & (1<<31); + ProcessorInfo.HasFCMOV =TypeFlags & (1<<16); + ProcessorInfo.HasRDTSC =TypeFlags & (1<<4); + } + else + { + U32 TypeFlags =GetCPUIDEDX(0x1); + ProcessorInfo.HasMMX =TypeFlags & (1<<23); + ProcessorInfo.HasFCMOV =((TypeFlags & (1<<15 | 1))==(1<<15 | 1))? TRUE : FALSE; + ProcessorInfo.HasRDTSC =TypeFlags & (1<<4); + } + TypeFlags =GetCPUIDEAX(1); + ProcessorInfo.ProcType =(TypeFlags>>12)&0x3; + ProcessorInfo.ProcFamily =(TypeFlags>>8)&0xf; + ProcessorInfo.ProcModel =(TypeFlags>>4)&0xf; + ProcessorInfo.ProcStepping =(TypeFlags)&0x7; + //ProcessorInfo.ProcSpeed =GetProcessorSpeed(); + } + else if(strncmp(ProcessorInfo.VendorString, "GenuineIntel", 12)==0) + { + U32 TypeFlags =GetCPUIDEDX(0x1); + ProcessorInfo.HasMMX =TypeFlags & (1<<23); + ProcessorInfo.HasFCMOV =((TypeFlags & (1<<15 | 1))==(1<<15 | 1))? TRUE : FALSE; + ProcessorInfo.HasRDTSC =TypeFlags & (1<<4); + + TypeFlags =GetCPUIDEAX(1); + ProcessorInfo.ProcType =(TypeFlags>>12)&0x3; + ProcessorInfo.ProcFamily =(TypeFlags>>8)&0xf; + ProcessorInfo.ProcModel =(TypeFlags>>4)&0xf; + ProcessorInfo.ProcStepping =(TypeFlags)&0x7; + //ProcessorInfo.ProcSpeed =GetProcessorSpeed(); + + ErrorPrintf("CPU Family: %d\n", ProcessorInfo.ProcFamily); + ErrorPrintf("CPU Model: %d\n", ProcessorInfo.ProcModel); + } + else + { + U32 TypeFlags =GetCPUIDEAX(0x80000000); + if(TypeFlags) //extended functions supported + { + TypeFlags =GetCPUIDEDX(0x80000001); + GetCPUIDStringAMD(0x80000002, ProcessorInfo.ProcName); + GetCPUIDStringAMD(0x80000003, ProcessorInfo.ProcName+16); + GetCPUIDStringAMD(0x80000004, ProcessorInfo.ProcName+32); + ErrorPrintf("CPU Family: %s\n", ProcessorInfo.ProcName); + ProcessorInfo.HasMMX =TypeFlags & (1<<23); + ProcessorInfo.Has3DNow =TypeFlags & (1<<31); + ProcessorInfo.HasFCMOV =TypeFlags & (1<<16); + ProcessorInfo.HasRDTSC =TypeFlags & (1<<4); + } + else + { + U32 TypeFlags =GetCPUIDEDX(0x1); + ProcessorInfo.HasMMX =TypeFlags & (1<<23); + ProcessorInfo.HasFCMOV =((TypeFlags & (1<<15 | 1))==(1<<15 | 1))? TRUE : FALSE; + ProcessorInfo.HasRDTSC =TypeFlags & (1<<4); + } + TypeFlags =GetCPUIDEAX(1); + ProcessorInfo.ProcType =(TypeFlags>>12)&0x3; + ProcessorInfo.ProcFamily =(TypeFlags>>8)&0xf; + ProcessorInfo.ProcModel =(TypeFlags>>4)&0xf; + ProcessorInfo.ProcStepping =(TypeFlags)&0x7; + //ProcessorInfo.ProcSpeed =GetProcessorSpeed(); + } + + ErrorPrintf("CPU Vendor String: %s\n", ProcessorInfo.VendorString); + ErrorPrintf("Processor Speed: %d\n", ProcessorInfo.ProcSpeed); + ErrorPrintf("Stepping: %d\n", ProcessorInfo.ProcStepping); + if(ProcessorInfo.HasMMX) + { + ErrorPrintf("MMX instructions detected\n"); + } + if(ProcessorInfo.Has3DNow) + { + if (VInfo!=NULL) + { + VInfo->bpp =32; + ErrorPrintf("3DNow instructions detected\n"); + } + } + if(ProcessorInfo.HasFCMOV) + { + ErrorPrintf("FCMOV feature detected\n"); + } + if(ProcessorInfo.HasRDTSC) + { + ErrorPrintf("Time Stamp Counter feature detected\n"); + } +} diff --git a/G3D/Engine/Drivers/SoftDrv/span.c b/G3D/Engine/Drivers/SoftDrv/span.c new file mode 100644 index 0000000..d4e376f --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/span.c @@ -0,0 +1,103 @@ +/****************************************************************************************/ +/* span.c */ +/* */ +/* Author: John Pollard, Ken Baird */ +/* Description: Span reject list type stuff */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include +#include + +#include "System.h" +#include "Span.h" +#include "Render.h" +#include "SoftDrv.h" +#include "Scene.h" +#include "3dnowspan.h" +#include "x86span565.h" +#include "x86span555.h" + + +SpanMinMax SMinMax[MAXSCANLINES]; // Linked list of spans for each scanline... +SList ScanHash[MAXSPANS]; // hash table for SList +int32 CurrentSList; // Current SUB in SList we are at... +int32 NumSpanPixels[MAXSCANLINES]; +extern CPUInfo ProcessorInfo; +extern BOOL bBackLocked; + +extern __int64 WrapMask, QFixedScale16; +extern __int64 GLMapMulUV, UVL16; +extern __int64 UVAdjust, UVAdjust2; +extern __int64 UVDivZ16StepX, ARL, GBL; +extern __int64 UVDivZOrigin, UVR; +extern __int64 QFixedScale, ZIR; +extern __int64 UVDivZStepX, UVDivZStepY; +extern uint8 *TexPal; + +extern BOOL LockDDrawBackBuffer(DRV_Window *cwnd, RECT *wrect); + +//*************************************************************************** +// Clears the index into the ScanHash array. This array is where I do all +// my SList allocating... +//*************************************************************************** +void ResetSList(void) +{ + CurrentSList = 0; +} + +//*************************************************************************** +// Makes a new valid SList in ScanHash, then updates the CurrentSList indexer. +//*************************************************************************** +SList *NewSList(void) +{ + + CurrentSList++; + + assert(CurrentSList < MAXSPANS); + + return &ScanHash[CurrentSList-1]; + + return NULL; +} + +// *************************************************************************** +// Just clears some variables so we know this SList is no longer used... +// *************************************************************************** +void FreeSList(SList *s) +{ + assert(s != NULL); + s->Used = 0; +} + +//================================================================================ +// Just clears the global span buckets... +//================================================================================ +void ResetSpans(uint32 Rows) +{ + uint32 i; + + for (i=0; i +#include + +//#define USE_CACHE + +#include "System.h" +#include "SoftDrv.h" +#include "DCommon.h" +#include "Render.h" +#include "Sal.h" +#include "dmodes.h" + + +BOOL SysInit(void) +{ + if(bWindowed) + { + SAL_get_pixel_format(&ClientWindow.PixelPitch, + &ClientWindow.BytesPerPixel, + &ClientWindow.R_shift, + &ClientWindow.R_mask, + &ClientWindow.R_width, + &ClientWindow.G_shift, + &ClientWindow.G_mask, + &ClientWindow.G_width, + &ClientWindow.B_shift, + &ClientWindow.B_mask, + &ClientWindow.B_width); + } + else + { + GetDDrawPixelFormat(&ClientWindow); + } + + if (!RenderInit(&ClientWindow)) + return FALSE; + + return TRUE; +} + +BOOL SysShutdown(void) +{ + RenderShutdown(); + + return TRUE; +} \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv/x86span555.c b/G3D/Engine/Drivers/SoftDrv/x86span555.c new file mode 100644 index 0000000..b978a24 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/x86span555.c @@ -0,0 +1,12561 @@ +/****************************************************************************************/ +/* x86span555.c */ +/* */ +/* Author: Ken Baird */ +/* Description: 555 assembly calls for tons of renderstates */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +//see notes in x86span565 + +/* +Code fragments from Chris Hecker's texture mapping articles used with +permission. http://www.d6.com/users/checker +*/ + + +#include "windows.h" //I really didn't want to do this +#include "softdrv.h" +#include "basetype.h" +#include "drawspan.h" +#include "render.h" + + +typedef struct EdgeAsmFPUTag +{ + int X, y, Height; + geFloat x, u, v, z, r, g, b; + geFloat xstep, ustep, vstep, zstep; + geFloat rstep, gstep, bstep; + uint32 R, G, B; +} EdgeAsmFPU; + + +void DrawScanLineGouraudNoZ_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fld dword ptr [ebx]EdgeAsmFPU.r ; RL VL16 UL16 + fld dword ptr [ebx]EdgeAsmFPU.g ; GL RL VL16 UL16 + fld dword ptr [ebx]EdgeAsmFPU.b ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,BLUEMASK2 + or edx,eax + + add TDest,2 + or edx,ebx + + mov ebx,pLeft + mov word ptr[ecx],dx + mov edx,[widTemp] + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(7) ; DW2 BD RI LG LB VSTP RL GI + fmulp st(1),st ; BI RI LG LB VSTP RL GI + frndint + fxch st(4) ; VSTP RI LG LB BI RL GI + fistp [VStep] ; RI LG LB BI RL GI + + push ebp + +PixieLoop: + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + mov esi,edi + + mov eax,edx + + shr edi,cl + add esi,[VStep] + + shr edx,16 + add eax,[UStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK2 + and eax,REDMASK2 + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK2 + + fxch st(3) ; LG2 LB2 BI RL2 GI + or edi,ebx + + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + rol edi,16 + add TDest,4 + + mov [ebp],edi + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZTrans_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov word ptr[TempPix],ax + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,BLUEMASK2 + or edx,eax + + add TDest,2 + or edx,ebx + + mov ebx,pLeft + cmp word ptr[TempPix],01h + je SkipSinglePixie + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov edx,[widTemp] + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(7) ; DW2 BD RI LG LB VSTP RL GI + fmulp st(1),st ; BI RI LG LB VSTP RL GI + frndint + fxch st(4) ; VSTP RI LG LB BI RL GI + fistp [VStep] ; RI LG LB BI RL GI + + push ebp + +PixieLoop: + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + mov esi,edi + + mov eax,edx + + shr edi,cl + add esi,[VStep] + + shr edx,16 + add eax,[UStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov [TempPix],eax + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK2 + and eax,REDMASK2 + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK2 + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + or edi,ebx + add TDest,4 + + cmp [TempPix],010001h + je SkipPixie + + mov [ebp],edi + +SkipPixie: + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBuffer_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK2 + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[eax],si + jg SkipSinglePixie + + or edx,ebx + mov word ptr[eax],si + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK2 + and eax,REDMASK2 + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK2 + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp word ptr[ecx],si + jg SkipPixie + + rol edi,16 + + mov [ecx],si + mov dword ptr[ebp],edi + mov [ecx+2],si +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop +// mov dword ptr[ebp],0ffffffffh + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferNoZWrite_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK2 + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[eax],si + jg SkipSinglePixie + + or edx,ebx + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK2 + and eax,REDMASK2 + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK2 + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp word ptr[ecx],si + jg SkipPixie + + rol edi,16 + + mov dword ptr[ebp],edi +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZBufferZWrite_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK2 + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + or edx,ebx + mov word ptr[eax],si + + mov word ptr[ecx],dx + + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK2 + and eax,REDMASK2 + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK2 + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + mov [ecx],si + rol edi,16 + + mov dword ptr[ebp],edi + mov [ecx+2],si + + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferTrans_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov word ptr[TempPix],ax + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK2 + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[TempPix],01h + je SkipSinglePixie + + cmp word ptr[eax],si + jg SkipSinglePixie + + or edx,ebx + mov word ptr[eax],si + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov [TempPix],eax + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK2 + and eax,REDMASK2 + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK2 + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp [TempPix],010001h + je SkipPixie + + rol edi,16 + + cmp word ptr[ecx],si + jg SkipPixie + + mov [ecx],si + mov dword ptr[ebp],edi + mov [ecx+2],si +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop +// mov dword ptr[ebp],0ffffffffh + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferNoZWriteTrans_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov word ptr[TempPix],ax + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK2 + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[TempPix],01h + je SkipSinglePixie + + cmp word ptr[eax],si + jg SkipSinglePixie + + or edx,ebx + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov [TempPix],eax + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK2 + and eax,REDMASK2 + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK2 + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp [TempPix],010001h + je SkipPixie + + rol edi,16 + + cmp word ptr[ecx],si + jg SkipPixie + + mov dword ptr[ebp],edi +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZBufferZWriteTrans_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov word ptr[TempPix],ax + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK2 + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[TempPix],01h + je SkipSinglePixie + + or edx,ebx + mov word ptr[eax],si + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov [TempPix],eax + + mov ebx,eax + and eax,REDMASK2 + + mov ecx,ebx + and ebx,GREENMASK2 + + mov dword ptr[Red],eax + and ecx,BLUEMASK2 + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK2 + and eax,REDMASK2 + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK2 + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp [TempPix],010001h + je SkipPixie + + mov [ecx],si + rol edi,16 + + mov dword ptr[ebp],edi + mov [ecx+2],si +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZSolid_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fild dword ptr [ebx]EdgeAsmFPU.B ; BL + fmul dword ptr[BlueMask] + fadd qword ptr[Magic] ; Bk + fild dword ptr [ebx]EdgeAsmFPU.G ; GL Bk + fmul dword ptr[GreenMask2] + fadd qword ptr[Magic] ; Gk Bk + fild dword ptr [ebx]EdgeAsmFPU.R ; RL Gk Bk + fmul dword ptr[MiniRedMask2] + fadd qword ptr[Magic] ; Rk Gk Bk + fxch st(2) ; Bk Gk Rk + fstp qword ptr[Bucket] ; Gk Rk + fstp qword ptr[Bucket2] ; Rk + + mov esi,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and esi,BLUEMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,REDMASK2 + or esi,eax + + add TDest,2 + or esi,ebx + + mov ebx,pLeft + mov word ptr[ecx],si + + mov ecx,pRight + dec edx + + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + shr edx,1 + fld1 + mov [widTemp],edx ; just for a temp + + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fidiv dword ptr [widTemp] ; WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL RR WID + fsub st(1),st ; RL RD WID + fild [ecx]EdgeAsmFPU.G ; GR RL RD WID + fild [ebx]EdgeAsmFPU.G ; GL GR RL RD WID + fsub st(1),st ; GL GD RL RD WID + fild [ecx]EdgeAsmFPU.B ; BR GL GD RL RD WID + fild [ebx]EdgeAsmFPU.B ; BL BR GL GD RL RD WID + fsub st(1),st ; BL BD GL GD RL RD WID + fxch st(5) ; RD BD GL GD RL BL WID + fmul st,st(6) ; RI BD GL GD RL BL WID + frndint + fxch st(3) ; GD BD GL RI RL BL WID + fmul st,st(6) ; GI BD GL RI RL BL WID + frndint + fxch st(6) ; WID BD GL RI RL BL GI + fmulp st(1),st ; BI GL RI RL BL GI + frndint + fld qword ptr[RedMask2] ; rm BI GL RI RL BL GI + fmul st(3),st ; rm BI GL RI RL BL GI + fmulp st(4),st ; BI GL RI RL BL GI + fld dword ptr[GreenMask2] ; gm BI GL RI RL BL GI + fmul st(2),st ; gm BI GL RI RL BL GI + fmulp st(6),st ; BI GL RI RL BL GI + fld dword ptr[BlueMask] ; bm BI GL RI RL BL GI + fmul st(1),st ; bm BI GL RI RL BL GI + fmulp st(5),st ; BI GL RI RL BL GI + +PixieLoop: + + fld st(3) ; r BI GL RI RL BL GI + fadd qword ptr[Magic] ; rk BI GL RI RL BL GI + fld st(2) ; g rk BI GL RI RL BL GI + fadd qword ptr[Magic] ; gk rk BI GL RI RL BL GI + fxch st(1) ; rk gk BI GL RI RL BL GI + fstp qword ptr[Bucket] ; gk BI GL RI RL BL GI + fstp qword ptr[Bucket2] ; BI GL RI RL BL GI + fld st(4) ; b BI GL RI RL BL GI + fadd qword ptr[Magic] ; bk BI GL RI RL BL GI + + mov ecx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; BI GL RI RL BL GI + fadd st(4),st ; BI GL RI RL BL2 GI + + and ecx,REDMASK2 + and eax,GREENMASK2 + + mov ebx,dword ptr[Bucket] + or ecx,eax + + fstp qword ptr[Bucket] ; GL RI RL BL2 GI + fadd st,st(4) ; GL2 RI RL BL2 GI + fstp qword ptr[Bucket2] ; RI RL BL2 GI + fadd st(1),st ; RI RL2 BL2 GI + fld qword ptr[Bucket2] ; GL2 RI RL2 BL2 GI + fld qword ptr[Bucket] ; BI GL2 RI RL2 BL2 GI + + and ebx,BLUEMASK2 + mov edi,TDest + + or ecx,ebx + add TDest,4 + + rol ecx,16 + + mov [edi],ecx + dec edx + + jnz PixieLoop + + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZBufferZWriteSolid_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fild dword ptr [ebx]EdgeAsmFPU.B ; BL + fmul dword ptr[BlueMask] + fadd qword ptr[Magic] ; Bk + fild dword ptr [ebx]EdgeAsmFPU.G ; GL Bk + fmul dword ptr[GreenMask2] + fadd qword ptr[Magic] ; Gk Bk + fild dword ptr [ebx]EdgeAsmFPU.R ; RL Gk Bk + fmul dword ptr[MiniRedMask2] + fadd qword ptr[Magic] ; Rk Gk Bk + fxch st(2) ; Bk Gk Rk + fstp qword ptr[Bucket] ; Gk Rk + fstp qword ptr[Bucket2] ; Rk + fld dword ptr[ebx]EdgeAsmFPU.z ; z + fistp [z16] ; + + mov esi,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and esi,BLUEMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,REDMASK2 + or esi,eax + + mov edi,[z16] + mov eax,pZBufferPtr + + add TDest,2 + or esi,ebx + + shr edi,16 + mov ebx,pLeft + + mov word ptr[eax],di + mov word ptr[ecx],si + + mov ecx,pRight + dec edx + + jz GouraudReturnNoZ + mov esi,edx + add pZBufferPtr,2 + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + shr edx,1 + fld1 + mov [widTemp],edx ; just for a temp + + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fidiv dword ptr [widTemp] ; WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL RR WID + fsub st(1),st ; RL RD WID + fild [ecx]EdgeAsmFPU.G ; GR RL RD WID + fild [ebx]EdgeAsmFPU.G ; GL GR RL RD WID + fsub st(1),st ; GL GD RL RD WID + fild [ecx]EdgeAsmFPU.B ; BR GL GD RL RD WID + fild [ebx]EdgeAsmFPU.B ; BL BR GL GD RL RD WID + fsub st(1),st ; BL BD GL GD RL RD WID + fxch st(5) ; RD BD GL GD RL BL WID + fmul st,st(6) ; RI BD GL GD RL BL WID + frndint + fxch st(3) ; GD BD GL RI RL BL WID + fmul st,st(6) ; GI BD GL RI RL BL WID + frndint + fxch st(6) ; WID BD GL RI RL BL GI + fmulp st(1),st ; BI GL RI RL BL GI + frndint + fld qword ptr[RedMask2] ; rm BI GL RI RL BL GI + fmul st(3),st ; rm BI GL RI RL BL GI + fmulp st(4),st ; BI GL RI RL BL GI + fld dword ptr[GreenMask2] ; gm BI GL RI RL BL GI + fmul st(2),st ; gm BI GL RI RL BL GI + fmulp st(6),st ; BI GL RI RL BL GI + fld dword ptr[BlueMask] ; bm BI GL RI RL BL GI + fmul st(1),st ; bm BI GL RI RL BL GI + fmulp st(5),st ; BI GL RI RL BL GI + fld [ecx]EdgeAsmFPU.z ; rz BI GL RI RL BL GI + fsub [ebx]EdgeAsmFPU.z ; zd BI GL RI RL BL GI + fld [ebx]EdgeAsmFPU.z ; lz zd BI GL RI RL BL GI + fistp [z16] ; zd BI GL RI RL BL GI + fistp [ZStep] ; BI GL RI RL BL GI + +PixieLoop: + + fld st(3) ; r BI GL RI RL BL GI + fadd qword ptr[Magic] ; rk BI GL RI RL BL GI + fld st(2) ; g rk BI GL RI RL BL GI + fadd qword ptr[Magic] ; gk rk BI GL RI RL BL GI + fxch st(1) ; rk gk BI GL RI RL BL GI + fstp qword ptr[Bucket] ; gk BI GL RI RL BL GI + + mov edi,[z16] + mov esi,pZBufferPtr + + shr edi,16 + mov ebx,[ZStep] + + mov word ptr[esi],di + add [z16],ebx + + fstp qword ptr[Bucket2] ; BI GL RI RL BL GI + fld st(4) ; b BI GL RI RL BL GI + fadd qword ptr[Magic] ; bk BI GL RI RL BL GI + + mov word ptr[esi+2],di + + mov ecx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; BI GL RI RL BL GI + fadd st(4),st ; BI GL RI RL BL2 GI + + and ecx,REDMASK2 + and eax,GREENMASK2 + + mov ebx,dword ptr[Bucket] + or ecx,eax + + fstp qword ptr[Bucket] ; GL RI RL BL2 GI + fadd st,st(4) ; GL2 RI RL BL2 GI + fstp qword ptr[Bucket2] ; RI RL BL2 GI + fadd st(1),st ; RI RL2 BL2 GI + fld qword ptr[Bucket2] ; GL2 RI RL2 BL2 GI + fld qword ptr[Bucket] ; BI GL2 RI RL2 BL2 GI + + and ebx,BLUEMASK2 + mov edi,TDest + + or ecx,ebx + add TDest,4 + + rol ecx,16 + + mov [edi],ecx + + add pZBufferPtr,4 + + dec edx + + jnz PixieLoop + + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferSolid_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fild dword ptr [ebx]EdgeAsmFPU.B ; BL + fmul dword ptr[BlueMask] + fadd qword ptr[Magic] ; Bk + fild dword ptr [ebx]EdgeAsmFPU.G ; GL Bk + fmul dword ptr[GreenMask2] + fadd qword ptr[Magic] ; Gk Bk + fild dword ptr [ebx]EdgeAsmFPU.R ; RL Gk Bk + fmul dword ptr[MiniRedMask2] + fadd qword ptr[Magic] ; Rk Gk Bk + fxch st(2) ; Bk Gk Rk + fstp qword ptr[Bucket] ; Gk Rk + fstp qword ptr[Bucket2] ; Rk + fld dword ptr[ebx]EdgeAsmFPU.z ; z + fistp [z16] ; + + mov esi,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and esi,BLUEMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,REDMASK2 + or esi,eax + + mov edi,[z16] + mov eax,pZBufferPtr + + add TDest,2 + or esi,ebx + + shr edi,16 + mov ebx,pLeft + + cmp word ptr[eax],di + jg SkipSinglePixie + + mov word ptr[eax],di + mov word ptr[ecx],si + +SkipSinglePixie: + mov ecx,pRight + add pZBufferPtr,2 + dec edx + + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + shr edx,1 + fld1 + mov [widTemp],edx ; just for a temp + + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fidiv dword ptr [widTemp] ; WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL RR WID + fsub st(1),st ; RL RD WID + fild [ecx]EdgeAsmFPU.G ; GR RL RD WID + fild [ebx]EdgeAsmFPU.G ; GL GR RL RD WID + fsub st(1),st ; GL GD RL RD WID + fild [ecx]EdgeAsmFPU.B ; BR GL GD RL RD WID + fild [ebx]EdgeAsmFPU.B ; BL BR GL GD RL RD WID + fsub st(1),st ; BL BD GL GD RL RD WID + fxch st(5) ; RD BD GL GD RL BL WID + fmul st,st(6) ; RI BD GL GD RL BL WID + frndint + fxch st(3) ; GD BD GL RI RL BL WID + fmul st,st(6) ; GI BD GL RI RL BL WID + frndint + fxch st(6) ; WID BD GL RI RL BL GI + fmulp st(1),st ; BI GL RI RL BL GI + frndint + fld qword ptr[RedMask2] ; rm BI GL RI RL BL GI + fmul st(3),st ; rm BI GL RI RL BL GI + fmulp st(4),st ; BI GL RI RL BL GI + fld dword ptr[GreenMask2] ; gm BI GL RI RL BL GI + fmul st(2),st ; gm BI GL RI RL BL GI + fmulp st(6),st ; BI GL RI RL BL GI + fld dword ptr[BlueMask] ; bm BI GL RI RL BL GI + fmul st(1),st ; bm BI GL RI RL BL GI + fmulp st(5),st ; BI GL RI RL BL GI + fld [ecx]EdgeAsmFPU.z ; rz BI GL RI RL BL GI + fsub [ebx]EdgeAsmFPU.z ; zd BI GL RI RL BL GI + fld [ebx]EdgeAsmFPU.z ; lz zd BI GL RI RL BL GI + fistp [z16] ; zd BI GL RI RL BL GI + fistp [ZStep] ; BI GL RI RL BL GI + +PixieLoop: + + fld st(3) ; r BI GL RI RL BL GI + fadd qword ptr[Magic] ; rk BI GL RI RL BL GI + fld st(2) ; g rk BI GL RI RL BL GI + fadd qword ptr[Magic] ; gk rk BI GL RI RL BL GI + fxch st(1) ; rk gk BI GL RI RL BL GI + fstp qword ptr[Bucket] ; gk BI GL RI RL BL GI + fstp qword ptr[Bucket2] ; BI GL RI RL BL GI + fld st(4) ; b BI GL RI RL BL GI + fadd qword ptr[Magic] ; bk BI GL RI RL BL GI + + mov ecx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; BI GL RI RL BL GI + fadd st(4),st ; BI GL RI RL BL2 GI + + and ecx,REDMASK2 + and eax,GREENMASK2 + + mov ebx,dword ptr[Bucket] + or ecx,eax + + fstp qword ptr[Bucket] ; GL RI RL BL2 GI + fadd st,st(4) ; GL2 RI RL BL2 GI + fstp qword ptr[Bucket2] ; RI RL BL2 GI + fadd st(1),st ; RI RL2 BL2 GI + fld qword ptr[Bucket2] ; GL2 RI RL2 BL2 GI + fld qword ptr[Bucket] ; BI GL2 RI RL2 BL2 GI + + and ebx,BLUEMASK2 + mov edi,TDest + + or ecx,ebx + add TDest,4 + + mov eax,[z16] + mov esi,pZBufferPtr + + shr eax,16 + mov ebx,[ZStep] + + cmp word ptr[esi],ax + jg SkipPixie + + mov word ptr[esi],ax + rol ecx,16 + + add [z16],ebx + mov word ptr[esi+2],ax + + mov [edi],ecx +SkipPixie: + add pZBufferPtr,4 + dec edx + + jnz PixieLoop + + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferNoZWriteSolid_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fild dword ptr [ebx]EdgeAsmFPU.B ; BL + fmul dword ptr[BlueMask] + fadd qword ptr[Magic] ; Bk + fild dword ptr [ebx]EdgeAsmFPU.G ; GL Bk + fmul dword ptr[GreenMask2] + fadd qword ptr[Magic] ; Gk Bk + fild dword ptr [ebx]EdgeAsmFPU.R ; RL Gk Bk + fmul dword ptr[MiniRedMask2] + fadd qword ptr[Magic] ; Rk Gk Bk + fxch st(2) ; Bk Gk Rk + fstp qword ptr[Bucket] ; Gk Rk + fstp qword ptr[Bucket2] ; Rk + fld dword ptr[ebx]EdgeAsmFPU.z ; z + fistp [z16] ; + + mov esi,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and esi,BLUEMASK2 + and eax,GREENMASK2 + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,REDMASK2 + or esi,eax + + mov edi,[z16] + mov eax,pZBufferPtr + + add TDest,2 + or esi,ebx + + shr edi,16 + mov ebx,pLeft + + cmp word ptr[eax],di + jg SkipSinglePixie + + mov word ptr[ecx],si + +SkipSinglePixie: + mov ecx,pRight + add pZBufferPtr,2 + dec edx + + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + shr edx,1 + fld1 + mov [widTemp],edx ; just for a temp + + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fidiv dword ptr [widTemp] ; WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL RR WID + fsub st(1),st ; RL RD WID + fild [ecx]EdgeAsmFPU.G ; GR RL RD WID + fild [ebx]EdgeAsmFPU.G ; GL GR RL RD WID + fsub st(1),st ; GL GD RL RD WID + fild [ecx]EdgeAsmFPU.B ; BR GL GD RL RD WID + fild [ebx]EdgeAsmFPU.B ; BL BR GL GD RL RD WID + fsub st(1),st ; BL BD GL GD RL RD WID + fxch st(5) ; RD BD GL GD RL BL WID + fmul st,st(6) ; RI BD GL GD RL BL WID + frndint + fxch st(3) ; GD BD GL RI RL BL WID + fmul st,st(6) ; GI BD GL RI RL BL WID + frndint + fxch st(6) ; WID BD GL RI RL BL GI + fmulp st(1),st ; BI GL RI RL BL GI + frndint + fld qword ptr[RedMask2] ; rm BI GL RI RL BL GI + fmul st(3),st ; rm BI GL RI RL BL GI + fmulp st(4),st ; BI GL RI RL BL GI + fld dword ptr[GreenMask2] ; gm BI GL RI RL BL GI + fmul st(2),st ; gm BI GL RI RL BL GI + fmulp st(6),st ; BI GL RI RL BL GI + fld dword ptr[BlueMask] ; bm BI GL RI RL BL GI + fmul st(1),st ; bm BI GL RI RL BL GI + fmulp st(5),st ; BI GL RI RL BL GI + fld [ecx]EdgeAsmFPU.z ; rz BI GL RI RL BL GI + fsub [ebx]EdgeAsmFPU.z ; zd BI GL RI RL BL GI + fld [ebx]EdgeAsmFPU.z ; lz zd BI GL RI RL BL GI + fistp [z16] ; zd BI GL RI RL BL GI + fistp [ZStep] ; BI GL RI RL BL GI + +PixieLoop: + + fld st(3) ; r BI GL RI RL BL GI + fadd qword ptr[Magic] ; rk BI GL RI RL BL GI + fld st(2) ; g rk BI GL RI RL BL GI + fadd qword ptr[Magic] ; gk rk BI GL RI RL BL GI + fxch st(1) ; rk gk BI GL RI RL BL GI + fstp qword ptr[Bucket] ; gk BI GL RI RL BL GI + fstp qword ptr[Bucket2] ; BI GL RI RL BL GI + fld st(4) ; b BI GL RI RL BL GI + fadd qword ptr[Magic] ; bk BI GL RI RL BL GI + + mov ecx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; BI GL RI RL BL GI + fadd st(4),st ; BI GL RI RL BL2 GI + + and ecx,REDMASK2 + and eax,GREENMASK2 + + mov ebx,dword ptr[Bucket] + or ecx,eax + + fstp qword ptr[Bucket] ; GL RI RL BL2 GI + fadd st,st(4) ; GL2 RI RL BL2 GI + fstp qword ptr[Bucket2] ; RI RL BL2 GI + fadd st(1),st ; RI RL2 BL2 GI + fld qword ptr[Bucket2] ; GL2 RI RL2 BL2 GI + fld qword ptr[Bucket] ; BI GL2 RI RL2 BL2 GI + + and ebx,BLUEMASK2 + mov edi,TDest + + or ecx,ebx + add TDest,4 + + mov eax,[z16] + mov esi,pZBufferPtr + + shr eax,16 + mov ebx,[ZStep] + + cmp word ptr[esi],ax + jg SkipPixie + + rol ecx,16 + add [z16],ebx + + mov [edi],ecx +SkipPixie: + add pZBufferPtr,4 + dec edx + + jnz PixieLoop + + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawSpan16_AsmLitZBuffer555X86FPU(int32 x1, int32 x2, int32 y) +{ + TDest =Dest; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + mov pTex,edi + + fild [y] ; y + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [x1] ; x y + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+0] + jle Skip0 + + mov [edi+0],ebp + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + +Skip0: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+4] + jle Skip1 + + mov [edi+4],ebp + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + +Skip1: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+8] + jle Skip2 + + mov [edi+8],ebp + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + +Skip2: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+12] + jle Skip3 + + mov [edi+12],ebp + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + +Skip3: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+16] + jle Skip4 + + mov [edi+16],ebp + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + +Skip4: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+20] + jle Skip5 + + mov [edi+20],ebp + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + +Skip5: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+24] + jle Skip6 + + mov [edi+24],ebp + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + +Skip6: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK2 + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+28] + jle Skip7 + + mov [edi+28],ebp + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + +Skip7: + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add [pZBufferPtr],32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK2 + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + cmp ax,word ptr[esi] + jle SkipLeftOver + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + +SkipLeftOver: + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawSpan16_AsmLitZWrite555X86FPU(int32 x1, int32 x2, int32 y) +{ + TDest =Dest; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + mov pTex,edi + + fild [y] ; y + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [x1] ; x y + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+0],ebp + + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+4],ebp + + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+8],ebp + + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+12],ebp + + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+16],ebp + + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+20],ebp + + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+24],ebp + + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,pTex + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + +// mov ecx,edx + xor eax,0 + + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +// add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK +// and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK2 + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+28],ebp + + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add pZBufferPtr,32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK2 + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawSpan16_AsmGouraudZBuffer555X86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2) +{ + RR1 =r1; + GG1 =g1; + BB1 =b1; + TDest =Dest; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + mov pTex,edi + + fild [y] ; y + mov [widTemp],ecx + + fild [x1] ; x y + fild [widTemp] + + fld1 + fdivrp st(1),st + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [r2] + fisub [r1] + fild [g2] + fisub [g1] + fild [b2] + fisub [b1] + fxch st(2) + fmul st,st(3) + fxch st(1) + fmul st,st(3) + fxch st(2) + fmul st,st(3) + frndint + fstp qword ptr[BlueDelta] + frndint + fstp qword ptr[RedDelta] + frndint + fstp qword ptr[GreenDelta] + fstp qword ptr[FTemp0] + + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+0] + jle Skip0 + + mov [edi+0],ebp + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + +Skip0: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+4] + jle Skip1 + + mov [edi+4],ebp + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + +Skip1: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+8] + jle Skip2 + + mov [edi+8],ebp + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + +Skip2: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+12] + jle Skip3 + + mov [edi+12],ebp + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + +Skip3: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+16] + jle Skip4 + + mov [edi+16],ebp + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + +Skip4: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+20] + jle Skip5 + + mov [edi+20],ebp + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + +Skip5: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+24] + jle Skip6 + + mov [edi+24],ebp + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + +Skip6: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fadd qword ptr[BlueDelta] + fistp dword ptr[BB1] + fadd qword ptr[GreenDelta] + fistp dword ptr[GG1] + fadd qword ptr[RedDelta] + fistp dword ptr[RR1] + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK2 + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+28] + jle Skip7 + + mov [edi+28],ebp + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + +Skip7: + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add [pZBufferPtr],32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK2 + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + cmp ax,word ptr[esi] + jle SkipLeftOver + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + +SkipLeftOver: + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + + +void DrawSpan16_AsmGouraudZWrite555X86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2) +{ + RR1 =r1; + GG1 =g1; + BB1 =b1; + TDest =Dest; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + mov pTex,edi + + fild [y] ; y + mov [widTemp],ecx + + fild [x1] ; x y + fild [widTemp] + + fld1 + fdivrp st(1),st + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [r2] + fisub [r1] + fild [g2] + fisub [g1] + fild [b2] + fisub [b1] + fxch st(2) + fmul st,st(3) + fxch st(1) + fmul st,st(3) + fxch st(2) + fmul st,st(3) + frndint + fstp qword ptr[BlueDelta] + frndint + fstp qword ptr[RedDelta] + frndint + fstp qword ptr[GreenDelta] + fstp qword ptr[FTemp0] + + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + + fild dword ptr[RR1] ; LR + fild dword ptr[GG1] ; LG LR + fild dword ptr[BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+0],ebp + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + + mov [edi+4],ebp + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+8],ebp + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+12],ebp + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+16],ebp + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+20],ebp + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+24],ebp + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fadd qword ptr[BlueDelta] + fistp dword ptr[BB1] + fadd qword ptr[GreenDelta] + fistp dword ptr[GG1] + fadd qword ptr[RedDelta] + fistp dword ptr[RR1] + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK2 + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+28],ebp + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add [pZBufferPtr],32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK2 + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + + +void DrawSpan16_AsmLit555X86FPU(int32 x1, int32 x2, int32 y) +{ + _asm + { + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + mov pTex,edi + + fild [y] ; y + + mov edi, ClientWindow.Buffer + mov eax, y + imul eax, ClientWindow.Width + add eax, x1 + shl eax, 1 + add edi, eax + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [x1] ; x y + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi],ebp + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+4],ebp + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+8],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+12],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+16],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+20],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+24],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK2 + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + + mov [edi+28],ebp ; store pixel 0 + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + + push ebp + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK2 + + or ebp,esi + + mov esi,pTex + + mov word ptr[edi-2],bp + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + } +} + +void DrawSpan16_AsmGouraudZBufferTrans555X86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2) +{ + RR1 =r1; + GG1 =g1; + BB1 =b1; + TDest =Dest; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + mov pTex,edi + + fild [y] ; y + mov [widTemp],ecx + + fild [x1] ; x y + fild [widTemp] + + fld1 + fdivrp st(1),st + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [r2] + fisub [r1] + fild [g2] + fisub [g1] + fild [b2] + fisub [b1] + fxch st(2) + fmul st,st(3) + fxch st(1) + fmul st,st(3) + fxch st(2) + fmul st,st(3) + frndint + fstp qword ptr[BlueDelta] + frndint + fstp qword ptr[RedDelta] + frndint + fstp qword ptr[GreenDelta] + fstp qword ptr[FTemp0] + + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + mov ebp,eax + add ebx,dword ptr[DeltaU] + + shr ebp,1 + and ecx,[GHMaskShifted16] + + rol eax,16 + mov [CKeyTest],ebp + + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip0 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+0] + jle Skip0 + + mov [edi+0],ebp + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + +Skip0: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip1 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+4] + jle Skip1 + + mov [edi+4],ebp + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + +Skip1: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip2 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+8] + jle Skip2 + + mov [edi+8],ebp + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + +Skip2: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip3 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+12] + jle Skip3 + + mov [edi+12],ebp + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + +Skip3: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip4 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+16] + jle Skip4 + + mov [edi+16],ebp + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + +Skip4: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip5 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+20] + jle Skip5 + + mov [edi+20],ebp + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + +Skip5: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK2 + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip6 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+24] + jle Skip6 + + mov [edi+24],ebp + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + +Skip6: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK2 + + and ebp,GREENMASK2 + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fadd qword ptr[BlueDelta] + fistp dword ptr[BB1] + fadd qword ptr[GreenDelta] + fistp dword ptr[GG1] + fadd qword ptr[RedDelta] + fistp dword ptr[RR1] + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK2 + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + + mov eax,[CKeyTest] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec eax + jl Skip7 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+28] + jle Skip7 + + mov [edi+28],ebp + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + +Skip7: + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add [pZBufferPtr],32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK2 + and ebp,GREENMASK2 + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + mov [CKeyTest],eax + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK2 + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK2 + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + dec [CKeyTest] + jl SkipLeftOver + + cmp ax,word ptr[esi] + jle SkipLeftOver + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + +SkipLeftOver: + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + diff --git a/G3D/Engine/Drivers/SoftDrv/x86span555.h b/G3D/Engine/Drivers/SoftDrv/x86span555.h new file mode 100644 index 0000000..9156283 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/x86span555.h @@ -0,0 +1,67 @@ +/****************************************************************************************/ +/* x86span555.h */ +/* */ +/* Author: Ken Baird */ +/* Description: header for x86 renderstates */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +typedef struct EdgeAsmTag EdgeAsm; +typedef struct EdgeAsmFPUTag EdgeAsmFPU; + +//x86 fpu based non world faces 555 +//DRV_RENDER_NO_ZMASK +extern void DrawScanLineGouraudNoZBufferZWrite_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +extern void DrawScanLineGouraudNoZBufferZWriteTrans_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +//solid color +extern void DrawScanLineGouraudNoZBufferZWriteSolid_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); + +//DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE +extern void DrawScanLineGouraudNoZ_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +extern void DrawScanLineGouraudNoZTrans_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +//solid color +extern void DrawScanLineGouraudNoZSolid_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); + +//DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudNoZAlphaTex_Asm555X86FPU(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_NO_ZMASK | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudNoZBufferZWriteAlphaTex_Asm555X86FPU(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_NO_ZMASK | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudZBufferNoZWriteAlphaTex_Asm555X86FPU(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_ALPHA +extern void DrawScanLineGouraudZBufferAlphaTex_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); + +//!(DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE) +extern void DrawScanLineGouraudZBuffer_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +extern void DrawScanLineGouraudZBufferTrans_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +//solid color +extern void DrawScanLineGouraudZBufferSolid_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); + +//DRV_RENDER_NO_ZWRITE +extern void DrawScanLineGouraudZBufferNoZWrite_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +extern void DrawScanLineGouraudZBufferNoZWriteTrans_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +//solid color +extern void DrawScanLineGouraudZBufferNoZWriteSolid_Asm555X86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); + + +//world perspective correct faces +void DrawSpan16_AsmLit555X86FPU(int32 x1, int32 x2, int32 y); +void DrawSpan16_AsmLitZWrite555X86FPU(int32 x1, int32 x2, int32 y); +void DrawSpan16_AsmLitZBuffer555X86FPU(int32 x1, int32 x2, int32 y); +void DrawSpan16_AsmGouraud555X86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2); +void DrawSpan16_AsmGouraudZWrite555X86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2); +void DrawSpan16_AsmGouraudZBuffer555X86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2); +void DrawSpan16_AsmGouraudZBufferTrans555X86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2); diff --git a/G3D/Engine/Drivers/SoftDrv/x86span565.c b/G3D/Engine/Drivers/SoftDrv/x86span565.c new file mode 100644 index 0000000..db37831 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/x86span565.c @@ -0,0 +1,13862 @@ +/****************************************************************************************/ +/* x86span565.c */ +/* */ +/* Author: Ken Baird */ +/* Description: 565 assembly calls for tons of renderstates */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +/* +Code fragments from Chris Hecker's texture mapping articles used with +permission. http://www.d6.com/users/checker +*/ + +/* +Alot of this code uses some really bizzare fpu tricks to do two +pixel blends at a time. I never got time to properly dword align +the perspective correct mappers. This would get us gains I think. +Unrolling is evil in here. This stuff shouldn't be unrolled +*/ +#include "windows.h" //I really didn't want to do this +#include "softdrv.h" +#include "basetype.h" +#include "drawspan.h" +#include "render.h" + +typedef struct EdgeAsmFPUTag +{ + int X, y, Height; + geFloat x, u, v, z, r, g, b; + geFloat xstep, ustep, vstep, zstep; + geFloat rstep, gstep, bstep; + uint32 R, G, B; +} EdgeAsmFPU; + + +#pragma warning (disable:4410) //illegal size for operand + +void DrawScanLineGouraudNoZ_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fld dword ptr [ebx]EdgeAsmFPU.r ; RL VL16 UL16 + fld dword ptr [ebx]EdgeAsmFPU.g ; GL RL VL16 UL16 + fld dword ptr [ebx]EdgeAsmFPU.b ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,BLUEMASK + or edx,eax + + add TDest,2 + or edx,ebx + + mov ebx,pLeft + mov word ptr[ecx],dx + mov edx,[widTemp] + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(7) ; DW2 BD RI LG LB VSTP RL GI + fmulp st(1),st ; BI RI LG LB VSTP RL GI + frndint + fxch st(4) ; VSTP RI LG LB BI RL GI + fistp [VStep] ; RI LG LB BI RL GI + + push ebp + +PixieLoop: + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + mov esi,edi + + mov eax,edx + + shr edi,cl + add esi,[VStep] + + shr edx,16 + add eax,[UStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK + and eax,REDMASK + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK + + fxch st(3) ; LG2 LB2 BI RL2 GI + or edi,ebx + + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + rol edi,16 + add TDest,4 + + mov [ebp],edi + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZTrans_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov word ptr[TempPix],ax + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,BLUEMASK + or edx,eax + + add TDest,2 + or edx,ebx + + mov ebx,pLeft + cmp word ptr[TempPix],01h + je SkipSinglePixie + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov edx,[widTemp] + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(7) ; DW2 BD RI LG LB VSTP RL GI + fmulp st(1),st ; BI RI LG LB VSTP RL GI + frndint + fxch st(4) ; VSTP RI LG LB BI RL GI + fistp [VStep] ; RI LG LB BI RL GI + + push ebp + +PixieLoop: + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + mov esi,edi + + mov eax,edx + + shr edi,cl + add esi,[VStep] + + shr edx,16 + add eax,[UStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov [TempPix],eax + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK + and eax,REDMASK + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + or edi,ebx + add TDest,4 + + cmp [TempPix],010001h + je SkipPixie + + mov [ebp],edi + +SkipPixie: + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBuffer_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[eax],si + jg SkipSinglePixie + + or edx,ebx + mov word ptr[eax],si + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK + and eax,REDMASK + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp word ptr[ecx],si + jg SkipPixie + + rol edi,16 + + mov [ecx],si + mov dword ptr[ebp],edi + mov [ecx+2],si +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferNoZWrite_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[eax],si + jg SkipSinglePixie + + or edx,ebx + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK + and eax,REDMASK + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp word ptr[ecx],si + jg SkipPixie + + rol edi,16 + + mov dword ptr[ebp],edi +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZBufferZWrite_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + or edx,ebx + mov word ptr[eax],si + + mov word ptr[ecx],dx + + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK + and eax,REDMASK + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + mov [ecx],si + rol edi,16 + + mov dword ptr[ebp],edi + mov [ecx+2],si + + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferTrans_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov word ptr[TempPix],ax + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[TempPix],01h + je SkipSinglePixie + + cmp word ptr[eax],si + jg SkipSinglePixie + + or edx,ebx + mov word ptr[eax],si + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov [TempPix],eax + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK + and eax,REDMASK + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp [TempPix],010001h + je SkipPixie + + rol edi,16 + + cmp word ptr[ecx],si + jg SkipPixie + + mov [ecx],si + mov dword ptr[ebp],edi + mov [ecx+2],si +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferNoZWriteTrans_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov word ptr[TempPix],ax + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[TempPix],01h + je SkipSinglePixie + + cmp word ptr[eax],si + jg SkipSinglePixie + + or edx,ebx + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov [TempPix],eax + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK + and eax,REDMASK + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp [TempPix],010001h + je SkipPixie + + rol edi,16 + + cmp word ptr[ecx],si + jg SkipPixie + + mov dword ptr[ebp],edi +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZBufferZWriteTrans_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fld dword ptr [ebx]EdgeAsmFPU.u ; UL + fmul [Real65536] ; UL16 + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 + fmul [Real65536] ; VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.G ; GL RL VL16 UL16 + fild dword ptr [ebx]EdgeAsmFPU.B ; BL GL RL VL16 UL16 + fxch st(4) ; UL16 GL RL VL16 BL + fistp [u16] ; GL RL VL16 BL + fxch st(2) ; VL16 RL GL BL + fistp [v16] ; RL GL BL + fld dword ptr[ebx]EdgeAsmFPU.z ; z RL GL BL + fistp [z16] ; RL GL BL + + mov [widTemp],edx + + mov ecx,[VShift] + mov ebx,[GHMaskShifted] + + mov esi,[GWMask] + mov edi,[v16] + + mov edx,dword ptr[u16] + + shr edi,cl + + shr edx,16 + xor eax,eax + + and edi,ebx + and edx,esi + + add edi,edx + + add edi,GBitPtrHalf + mov ax,word ptr[edi*2] + + mov word ptr[TempPix],ax + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fimul dword ptr[Red] ; R GL BL + fxch st(1) ; GL R BL + fimul dword ptr[Green] ; G R BL + fxch st(1) ; R G BL + fadd qword ptr[Magic] ; Rk G BL + fxch st(2) ; BL G Rk + fimul [Blue] ; B G Rk + fxch st(1) ; G B Rk + fadd qword ptr[Magic] ; Gk B Rk + fxch st(2) ; Rk B Gk + fstp qword ptr[Bucket] ; B Gk + fadd qword ptr[Magic] ; Bk Gk + fxch st(1) ; Gk Bk + fstp qword ptr[Bucket2] ; Bk + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and edx,REDMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + mov esi,[z16] + and ebx,BLUEMASK + + shr esi,16 + or edx,eax + + mov eax,pZBufferPtr + add TDest,2 + + cmp word ptr[TempPix],01h + je SkipSinglePixie + + or edx,ebx + mov word ptr[eax],si + + mov word ptr[ecx],dx + +SkipSinglePixie: + mov ebx,pLeft + mov edx,[widTemp] + add pZBufferPtr,2 + mov ecx,pRight + dec edx + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + mov [widTemp],edx ; just for a temp + shr edx,1 + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fild dword ptr [widTemp] ; WID + + mov [widTemp],edx ; Color interps doubled + + fld dword ptr [ecx]EdgeAsmFPU.u ; UR WID + fld dword ptr [ebx]EdgeAsmFPU.u ; UL UR WID + fsub st(1), st ; UL UD WID + fld dword ptr [ecx]EdgeAsmFPU.v ; VR UL UD WID + fxch st(1) ; UL VR UD WID + fmul [Real65536] ; UL16 VR UD WID + fld dword ptr [ebx]EdgeAsmFPU.v ; VL UL16 VR UD WID + fsub st(2), st ; VL UL16 VD UD WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR VL UL16 VD UD WID + fxch st(3) ; VD VL UL16 RR UD WID + fmul [Real65536] ; VD16 VL UL16 RR UD WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL VD16 VL UL16 RR UD WID + fsub st(4),st ; RL VD16 VL UL16 RD UD WID + fxch st(5) ; UD VD16 VL UL16 RD RL WID + fmul [Real65536] ; UD16 VD16 VL UL16 RD RL WID + fxch st(2) ; VL VD16 UD16 UL16 RD RL WID + fmul [Real65536] ; VL16 VD16 UD16 UL16 RD RL WID + fxch st(3) ; UL16 VD16 UD16 VL16 RD RL WID + fistp [u16] ; VD16 UD16 VL16 RD RL WID + fxch st(2) ; VL16 UD16 VD16 RD RL WID + fistp [v16] ; UD16 VD16 RD RL WID + fld1 ; 1 UD16 VD16 RD RL WID + fdivrp st(5),st ; UD16 VD16 RD RL DWID + + //let that cook + + fmul st,st(4) ; USTP VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.G ; RG USTP VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.G ; LG RG USTP VD16 RD RL DWID + fsub st(1),st ; LG GD USTP VD16 RD RL DWID + fxch st(2) ; USTP GD LG VD16 RD RL DWID + fistp [UStep] ; GD LG VD16 RD RL DWID + fild [ecx]EdgeAsmFPU.B ; RB GD LG VD16 RD RL DWID + fild [ebx]EdgeAsmFPU.B ; LB RB GD LG VD16 RD RL DWID + fsub st(1),st ; LB BD GD LG VD16 RD RL DWID + fxch st(4) ; VD16 BD GD LG LB RD RL DWID + fmul st,st(7) ; VSTP BD GD LG LB RD RL DWID + fxch st(7) ; DWID BD GD LG LB RD RL VSTP + fmul dword ptr[Two] ; DW2 BD GD LG LB RD RL VSTP + fxch st(7) ; VSTP BD GD LG LB RD RL DW2 + fxch st(5) ; RD BD GD LG LB VSTP RL DW2 + fmul st,st(7) ; RI BD GD LG LB VSTP RL DW2 + frndint + fxch st(2) ; GD BD RI LG LB VSTP RL DW2 + fmul st,st(7) ; GI BD RI LG LB VSTP RL DW2 + frndint + fxch st(1) ; BD GI RI LG LB VSTP RL DW2 + fmul st,st(7) ; BD GI RI LG LB VSTP RL DW2 + frndint + fxch st(5) ; VSTP GI RI LG LB BD RL DW2 + fistp [VStep] ; GI RI LG LB BD RL DW2 + fld [ecx]EdgeAsmFPU.z ; rz GI RI LG LB BD RL DW2 + fsub [ebx]EdgeAsmFPU.z ; zd GI RI LG LB BD RL DW2 + fxch st(7) ; DW2 GI RI LG LB BD RL zd + fmulp st(7),st ; GI RI LG LB BD RL zd + fld [ebx]EdgeAsmFPU.z ; lz GI RI LG LB BD RL zd + fxch st(7) ; zd GI RI LG LB BD RL lz + fistp [ZStep] ; GI RI LG LB BD RL lz + fxch st(6) ; lz RI LG LB BD RL GI + fistp [z16] ; RI LG LB BD RL GI + + push ebp + +PixieLoop: + mov ebx,[ZStep] + + add [z16],ebx + mov ecx,[VShift] + + mov edi,[z16] + + shr edi,16 + mov ebx,[GHMaskShifted] + + mov ebp,[GWMask] + mov edx,dword ptr[u16] + + mov word ptr[Z32],di + mov eax,edx + + shr edx,16 + mov edi,[v16] + + add eax,[UStep] + mov esi,edi + + shr edi,cl + add esi,[VStep] + + and edi,ebx + and edx,ebp + + add edi,edx + mov edx,eax + + add edi,GBitPtrHalf + add eax,[UStep] + + mov [u16],eax + mov ax,word ptr[edi*2] + + mov edi,esi + add esi,[VStep] + + shr edx,16 + mov [v16],esi + + shr edi,cl + and edx,ebp + + mov esi,GBitPtrHalf + and edi,ebx + + shl eax,16 + add esi,edx + + add esi,edi + + mov ax,word ptr[esi*2] + + mov [TempPix],eax + + mov ebx,eax + and eax,REDMASK + + mov ecx,ebx + and ebx,GREENMASK + + mov dword ptr[Red],eax + and ecx,BLUEMASK + + mov dword ptr[Green],ebx + mov dword ptr[Blue],ecx + + fild qword ptr[Red] ; r RI LG LB BI RL GI + fmul st,st(5) ; R RI LG LB BI RL GI + fild qword ptr[Green] ; g R RI LG LB BI RL GI + fmul st,st(3) ; G R RI LG LB BI RL GI + fxch st(6) ; RL R RI LG LB BI G GI + fadd st,st(2) ; RL2 R RI LG LB BI G GI + fxch st(3) ; LG R RI RL2 LB BI G GI + fadd st,st(7) ; LG2 R RI RL2 LB BI G GI + fxch st(6) ; G R RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Gk R RI RL2 LB BI LG2 GI + fxch st(1) ; R Gk RI RL2 LB BI LG2 GI + fadd qword ptr[Magic] ; Rk Gk RI RL2 LB BI LG2 GI + fxch st(1) ; Gk Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket] ; Rk RI RL2 LB BI LG2 GI + fstp qword ptr[Bucket2] ; RI RL2 LB BI LG2 GI + + mov edx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fild dword ptr[Blue] ; b RI RL2 LB BI LG2 GI + fmul st,st(3) ; B RI RL2 LB BI LG2 GI + fxch st(3) ; LB RI RL2 B BI LG2 GI + fadd st,st(4) ; LB2 RI RL2 B BI LG2 GI + fxch st(3) ; B RI RL2 LB2 BI LG2 GI + fadd qword ptr[Magic] ; Bk RI RL2 LB2 BI LG2 GI + + and edx,GREENMASK + and eax,REDMASK + + fstp qword ptr[Bucket] ; RI RL2 LB2 BI LG2 GI + fstp qword ptr[Bucket2] ; RL2 LB2 BI LG2 GI + + mov edi,edx + mov ebx,dword ptr[Bucket] + or edi,eax + mov ebp,TDest + and ebx,BLUEMASK + + fxch st(3) ; LG2 LB2 BI RL2 GI + fld qword ptr[Bucket2] ; RI LG2 LB2 BI RL2 GI + + mov si,word ptr[Z32] + add TDest,4 + + mov ecx,pZBufferPtr + or edi,ebx + + cmp [TempPix],010001h + je SkipPixie + + mov [ecx],si + rol edi,16 + + mov dword ptr[ebp],edi + mov [ecx+2],si +SkipPixie: + add pZBufferPtr,4 + dec [widTemp] + + jnz PixieLoop + + pop ebp + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZSolid_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fild dword ptr [ebx]EdgeAsmFPU.B ; BL + fmul dword ptr[BlueMask] + fadd qword ptr[Magic] ; Bk + fild dword ptr [ebx]EdgeAsmFPU.G ; GL Bk + fmul dword ptr[GreenMask] + fadd qword ptr[Magic] ; Gk Bk + fild dword ptr [ebx]EdgeAsmFPU.R ; RL Gk Bk + fmul dword ptr[MiniRedMask] + fadd qword ptr[Magic] ; Rk Gk Bk + fxch st(2) ; Bk Gk Rk + fstp qword ptr[Bucket] ; Gk Rk + fstp qword ptr[Bucket2] ; Rk + + mov esi,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and esi,BLUEMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,REDMASK + or esi,eax + + add TDest,2 + or esi,ebx + + mov ebx,pLeft + mov word ptr[ecx],si + + mov ecx,pRight + dec edx + + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + shr edx,1 + fld1 + mov [widTemp],edx ; just for a temp + + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fidiv dword ptr [widTemp] ; WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL RR WID + fsub st(1),st ; RL RD WID + fild [ecx]EdgeAsmFPU.G ; GR RL RD WID + fild [ebx]EdgeAsmFPU.G ; GL GR RL RD WID + fsub st(1),st ; GL GD RL RD WID + fild [ecx]EdgeAsmFPU.B ; BR GL GD RL RD WID + fild [ebx]EdgeAsmFPU.B ; BL BR GL GD RL RD WID + fsub st(1),st ; BL BD GL GD RL RD WID + fxch st(5) ; RD BD GL GD RL BL WID + fmul st,st(6) ; RI BD GL GD RL BL WID + frndint + fxch st(3) ; GD BD GL RI RL BL WID + fmul st,st(6) ; GI BD GL RI RL BL WID + frndint + fxch st(6) ; WID BD GL RI RL BL GI + fmulp st(1),st ; BI GL RI RL BL GI + frndint + fld qword ptr[RedMask] ; rm BI GL RI RL BL GI + fmul st(3),st ; rm BI GL RI RL BL GI + fmulp st(4),st ; BI GL RI RL BL GI + fld dword ptr[GreenMask] ; gm BI GL RI RL BL GI + fmul st(2),st ; gm BI GL RI RL BL GI + fmulp st(6),st ; BI GL RI RL BL GI + fld dword ptr[BlueMask] ; bm BI GL RI RL BL GI + fmul st(1),st ; bm BI GL RI RL BL GI + fmulp st(5),st ; BI GL RI RL BL GI + +PixieLoop: + + fld st(3) ; r BI GL RI RL BL GI + fadd qword ptr[Magic] ; rk BI GL RI RL BL GI + fld st(2) ; g rk BI GL RI RL BL GI + fadd qword ptr[Magic] ; gk rk BI GL RI RL BL GI + fxch st(1) ; rk gk BI GL RI RL BL GI + fstp qword ptr[Bucket] ; gk BI GL RI RL BL GI + fstp qword ptr[Bucket2] ; BI GL RI RL BL GI + fld st(4) ; b BI GL RI RL BL GI + fadd qword ptr[Magic] ; bk BI GL RI RL BL GI + + mov ecx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; BI GL RI RL BL GI + fadd st(4),st ; BI GL RI RL BL2 GI + + and ecx,REDMASK + and eax,GREENMASK + + mov ebx,dword ptr[Bucket] + or ecx,eax + + fstp qword ptr[Bucket] ; GL RI RL BL2 GI + fadd st,st(4) ; GL2 RI RL BL2 GI + fstp qword ptr[Bucket2] ; RI RL BL2 GI + fadd st(1),st ; RI RL2 BL2 GI + fld qword ptr[Bucket2] ; GL2 RI RL2 BL2 GI + fld qword ptr[Bucket] ; BI GL2 RI RL2 BL2 GI + + and ebx,BLUEMASK + mov edi,TDest + + or ecx,ebx + add TDest,4 + + rol ecx,16 + + mov [edi],ecx + dec edx + + jnz PixieLoop + + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudNoZBufferZWriteSolid_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fild dword ptr [ebx]EdgeAsmFPU.B ; BL + fmul dword ptr[BlueMask] + fadd qword ptr[Magic] ; Bk + fild dword ptr [ebx]EdgeAsmFPU.G ; GL Bk + fmul dword ptr[GreenMask] + fadd qword ptr[Magic] ; Gk Bk + fild dword ptr [ebx]EdgeAsmFPU.R ; RL Gk Bk + fmul dword ptr[MiniRedMask] + fadd qword ptr[Magic] ; Rk Gk Bk + fxch st(2) ; Bk Gk Rk + fstp qword ptr[Bucket] ; Gk Rk + fstp qword ptr[Bucket2] ; Rk + fld dword ptr[ebx]EdgeAsmFPU.z ; z + fistp [z16] ; + + mov esi,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and esi,BLUEMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,REDMASK + or esi,eax + + mov edi,[z16] + mov eax,pZBufferPtr + + add TDest,2 + or esi,ebx + + shr edi,16 + mov ebx,pLeft + + mov word ptr[eax],di + mov word ptr[ecx],si + + mov ecx,pRight + dec edx + + jz GouraudReturnNoZ + mov esi,edx + add pZBufferPtr,2 + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + shr edx,1 + fld1 + mov [widTemp],edx ; just for a temp + + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fidiv dword ptr [widTemp] ; WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL RR WID + fsub st(1),st ; RL RD WID + fild [ecx]EdgeAsmFPU.G ; GR RL RD WID + fild [ebx]EdgeAsmFPU.G ; GL GR RL RD WID + fsub st(1),st ; GL GD RL RD WID + fild [ecx]EdgeAsmFPU.B ; BR GL GD RL RD WID + fild [ebx]EdgeAsmFPU.B ; BL BR GL GD RL RD WID + fsub st(1),st ; BL BD GL GD RL RD WID + fxch st(5) ; RD BD GL GD RL BL WID + fmul st,st(6) ; RI BD GL GD RL BL WID + frndint + fxch st(3) ; GD BD GL RI RL BL WID + fmul st,st(6) ; GI BD GL RI RL BL WID + frndint + fxch st(6) ; WID BD GL RI RL BL GI + fmulp st(1),st ; BI GL RI RL BL GI + frndint + fld qword ptr[RedMask] ; rm BI GL RI RL BL GI + fmul st(3),st ; rm BI GL RI RL BL GI + fmulp st(4),st ; BI GL RI RL BL GI + fld dword ptr[GreenMask] ; gm BI GL RI RL BL GI + fmul st(2),st ; gm BI GL RI RL BL GI + fmulp st(6),st ; BI GL RI RL BL GI + fld dword ptr[BlueMask] ; bm BI GL RI RL BL GI + fmul st(1),st ; bm BI GL RI RL BL GI + fmulp st(5),st ; BI GL RI RL BL GI + fld [ecx]EdgeAsmFPU.z ; rz BI GL RI RL BL GI + fsub [ebx]EdgeAsmFPU.z ; zd BI GL RI RL BL GI + fld [ebx]EdgeAsmFPU.z ; lz zd BI GL RI RL BL GI + fistp [z16] ; zd BI GL RI RL BL GI + fistp [ZStep] ; BI GL RI RL BL GI + +PixieLoop: + + fld st(3) ; r BI GL RI RL BL GI + fadd qword ptr[Magic] ; rk BI GL RI RL BL GI + fld st(2) ; g rk BI GL RI RL BL GI + fadd qword ptr[Magic] ; gk rk BI GL RI RL BL GI + fxch st(1) ; rk gk BI GL RI RL BL GI + fstp qword ptr[Bucket] ; gk BI GL RI RL BL GI + + mov edi,[z16] + mov esi,pZBufferPtr + + shr edi,16 + mov ebx,[ZStep] + + mov word ptr[esi],di + add [z16],ebx + + fstp qword ptr[Bucket2] ; BI GL RI RL BL GI + fld st(4) ; b BI GL RI RL BL GI + fadd qword ptr[Magic] ; bk BI GL RI RL BL GI + + mov word ptr[esi+2],di + + mov ecx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; BI GL RI RL BL GI + fadd st(4),st ; BI GL RI RL BL2 GI + + and ecx,REDMASK + and eax,GREENMASK + + mov ebx,dword ptr[Bucket] + or ecx,eax + + fstp qword ptr[Bucket] ; GL RI RL BL2 GI + fadd st,st(4) ; GL2 RI RL BL2 GI + fstp qword ptr[Bucket2] ; RI RL BL2 GI + fadd st(1),st ; RI RL2 BL2 GI + fld qword ptr[Bucket2] ; GL2 RI RL2 BL2 GI + fld qword ptr[Bucket] ; BI GL2 RI RL2 BL2 GI + + and ebx,BLUEMASK + mov edi,TDest + + or ecx,ebx + add TDest,4 + + rol ecx,16 + + mov [edi],ecx + + add pZBufferPtr,4 + + dec edx + + jnz PixieLoop + + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferSolid_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fild dword ptr [ebx]EdgeAsmFPU.B ; BL + fmul dword ptr[BlueMask] + fadd qword ptr[Magic] ; Bk + fild dword ptr [ebx]EdgeAsmFPU.G ; GL Bk + fmul dword ptr[GreenMask] + fadd qword ptr[Magic] ; Gk Bk + fild dword ptr [ebx]EdgeAsmFPU.R ; RL Gk Bk + fmul dword ptr[MiniRedMask] + fadd qword ptr[Magic] ; Rk Gk Bk + fxch st(2) ; Bk Gk Rk + fstp qword ptr[Bucket] ; Gk Rk + fstp qword ptr[Bucket2] ; Rk + fld dword ptr[ebx]EdgeAsmFPU.z ; z + fistp [z16] ; + + mov esi,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and esi,BLUEMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,REDMASK + or esi,eax + + mov edi,[z16] + mov eax,pZBufferPtr + + add TDest,2 + or esi,ebx + + shr edi,16 + mov ebx,pLeft + + cmp word ptr[eax],di + jg SkipSinglePixie + + mov word ptr[eax],di + mov word ptr[ecx],si + +SkipSinglePixie: + mov ecx,pRight + add pZBufferPtr,2 + dec edx + + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + shr edx,1 + fld1 + mov [widTemp],edx ; just for a temp + + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fidiv dword ptr [widTemp] ; WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL RR WID + fsub st(1),st ; RL RD WID + fild [ecx]EdgeAsmFPU.G ; GR RL RD WID + fild [ebx]EdgeAsmFPU.G ; GL GR RL RD WID + fsub st(1),st ; GL GD RL RD WID + fild [ecx]EdgeAsmFPU.B ; BR GL GD RL RD WID + fild [ebx]EdgeAsmFPU.B ; BL BR GL GD RL RD WID + fsub st(1),st ; BL BD GL GD RL RD WID + fxch st(5) ; RD BD GL GD RL BL WID + fmul st,st(6) ; RI BD GL GD RL BL WID + frndint + fxch st(3) ; GD BD GL RI RL BL WID + fmul st,st(6) ; GI BD GL RI RL BL WID + frndint + fxch st(6) ; WID BD GL RI RL BL GI + fmulp st(1),st ; BI GL RI RL BL GI + frndint + fld qword ptr[RedMask] ; rm BI GL RI RL BL GI + fmul st(3),st ; rm BI GL RI RL BL GI + fmulp st(4),st ; BI GL RI RL BL GI + fld dword ptr[GreenMask] ; gm BI GL RI RL BL GI + fmul st(2),st ; gm BI GL RI RL BL GI + fmulp st(6),st ; BI GL RI RL BL GI + fld dword ptr[BlueMask] ; bm BI GL RI RL BL GI + fmul st(1),st ; bm BI GL RI RL BL GI + fmulp st(5),st ; BI GL RI RL BL GI + fld [ecx]EdgeAsmFPU.z ; rz BI GL RI RL BL GI + fsub [ebx]EdgeAsmFPU.z ; zd BI GL RI RL BL GI + fld [ebx]EdgeAsmFPU.z ; lz zd BI GL RI RL BL GI + fistp [z16] ; zd BI GL RI RL BL GI + fistp [ZStep] ; BI GL RI RL BL GI + +PixieLoop: + + fld st(3) ; r BI GL RI RL BL GI + fadd qword ptr[Magic] ; rk BI GL RI RL BL GI + fld st(2) ; g rk BI GL RI RL BL GI + fadd qword ptr[Magic] ; gk rk BI GL RI RL BL GI + fxch st(1) ; rk gk BI GL RI RL BL GI + fstp qword ptr[Bucket] ; gk BI GL RI RL BL GI + fstp qword ptr[Bucket2] ; BI GL RI RL BL GI + fld st(4) ; b BI GL RI RL BL GI + fadd qword ptr[Magic] ; bk BI GL RI RL BL GI + + mov ecx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; BI GL RI RL BL GI + fadd st(4),st ; BI GL RI RL BL2 GI + + and ecx,REDMASK + and eax,GREENMASK + + mov ebx,dword ptr[Bucket] + or ecx,eax + + fstp qword ptr[Bucket] ; GL RI RL BL2 GI + fadd st,st(4) ; GL2 RI RL BL2 GI + fstp qword ptr[Bucket2] ; RI RL BL2 GI + fadd st(1),st ; RI RL2 BL2 GI + fld qword ptr[Bucket2] ; GL2 RI RL2 BL2 GI + fld qword ptr[Bucket] ; BI GL2 RI RL2 BL2 GI + + and ebx,BLUEMASK + mov edi,TDest + + or ecx,ebx + add TDest,4 + + mov eax,[z16] + mov esi,pZBufferPtr + + shr eax,16 + mov ebx,[ZStep] + + cmp word ptr[esi],ax + jg SkipPixie + + mov word ptr[esi],ax + rol ecx,16 + + add [z16],ebx + mov word ptr[esi+2],ax + + mov [edi],ecx +SkipPixie: + add pZBufferPtr,4 + dec edx + + jnz PixieLoop + + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawScanLineGouraudZBufferNoZWriteSolid_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight) +{ + TDest =Dest; + Red =Green =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov ebx,pLeft + mov ecx,pRight + mov eax,[ebx]EdgeAsmFPU.X + mov edx,[ecx]EdgeAsmFPU.X + sub edx,eax + jle GouraudReturnNoZ + + mov esi,eax + inc edx + shl eax,1 + add TDest,eax + add pZBufferPtr,eax + test esi,1 //dword align left side + jz NoSinglePixie + + //odd sized spans write one pixel to dword align + fild dword ptr [ebx]EdgeAsmFPU.B ; BL + fmul dword ptr[BlueMask] + fadd qword ptr[Magic] ; Bk + fild dword ptr [ebx]EdgeAsmFPU.G ; GL Bk + fmul dword ptr[GreenMask] + fadd qword ptr[Magic] ; Gk Bk + fild dword ptr [ebx]EdgeAsmFPU.R ; RL Gk Bk + fmul dword ptr[MiniRedMask] + fadd qword ptr[Magic] ; Rk Gk Bk + fxch st(2) ; Bk Gk Rk + fstp qword ptr[Bucket] ; Gk Rk + fstp qword ptr[Bucket2] ; Rk + fld dword ptr[ebx]EdgeAsmFPU.z ; z + fistp [z16] ; + + mov esi,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + and esi,BLUEMASK + and eax,GREENMASK + + fstp qword ptr[Bucket] + + mov ecx,TDest + mov ebx,dword ptr[Bucket] + + and ebx,REDMASK + or esi,eax + + mov edi,[z16] + mov eax,pZBufferPtr + + add TDest,2 + or esi,ebx + + shr edi,16 + mov ebx,pLeft + + cmp word ptr[eax],di + jg SkipSinglePixie + + mov word ptr[ecx],si + +SkipSinglePixie: + mov ecx,pRight + add pZBufferPtr,2 + dec edx + + jz GouraudReturnNoZ + mov esi,edx + and esi,1 + sub edx,esi + jz GouraudReturnNoZ + +NoSinglePixie: + shr edx,1 + fld1 + mov [widTemp],edx ; just for a temp + + + ; try to keep fmul fxch pairs seperated to avoid stalling + ; calc this scanlines steps ; FPU Stack + ; st0 st1 st2 st3 st4 st5 st6 st7 + fidiv dword ptr [widTemp] ; WID + fild dword ptr [ecx]EdgeAsmFPU.R ; RR WID + fild dword ptr [ebx]EdgeAsmFPU.R ; RL RR WID + fsub st(1),st ; RL RD WID + fild [ecx]EdgeAsmFPU.G ; GR RL RD WID + fild [ebx]EdgeAsmFPU.G ; GL GR RL RD WID + fsub st(1),st ; GL GD RL RD WID + fild [ecx]EdgeAsmFPU.B ; BR GL GD RL RD WID + fild [ebx]EdgeAsmFPU.B ; BL BR GL GD RL RD WID + fsub st(1),st ; BL BD GL GD RL RD WID + fxch st(5) ; RD BD GL GD RL BL WID + fmul st,st(6) ; RI BD GL GD RL BL WID + frndint + fxch st(3) ; GD BD GL RI RL BL WID + fmul st,st(6) ; GI BD GL RI RL BL WID + frndint + fxch st(6) ; WID BD GL RI RL BL GI + fmulp st(1),st ; BI GL RI RL BL GI + frndint + fld qword ptr[RedMask] ; rm BI GL RI RL BL GI + fmul st(3),st ; rm BI GL RI RL BL GI + fmulp st(4),st ; BI GL RI RL BL GI + fld dword ptr[GreenMask] ; gm BI GL RI RL BL GI + fmul st(2),st ; gm BI GL RI RL BL GI + fmulp st(6),st ; BI GL RI RL BL GI + fld dword ptr[BlueMask] ; bm BI GL RI RL BL GI + fmul st(1),st ; bm BI GL RI RL BL GI + fmulp st(5),st ; BI GL RI RL BL GI + fld [ecx]EdgeAsmFPU.z ; rz BI GL RI RL BL GI + fsub [ebx]EdgeAsmFPU.z ; zd BI GL RI RL BL GI + fld [ebx]EdgeAsmFPU.z ; lz zd BI GL RI RL BL GI + fistp [z16] ; zd BI GL RI RL BL GI + fistp [ZStep] ; BI GL RI RL BL GI + +PixieLoop: + + fld st(3) ; r BI GL RI RL BL GI + fadd qword ptr[Magic] ; rk BI GL RI RL BL GI + fld st(2) ; g rk BI GL RI RL BL GI + fadd qword ptr[Magic] ; gk rk BI GL RI RL BL GI + fxch st(1) ; rk gk BI GL RI RL BL GI + fstp qword ptr[Bucket] ; gk BI GL RI RL BL GI + fstp qword ptr[Bucket2] ; BI GL RI RL BL GI + fld st(4) ; b BI GL RI RL BL GI + fadd qword ptr[Magic] ; bk BI GL RI RL BL GI + + mov ecx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; BI GL RI RL BL GI + fadd st(4),st ; BI GL RI RL BL2 GI + + and ecx,REDMASK + and eax,GREENMASK + + mov ebx,dword ptr[Bucket] + or ecx,eax + + fstp qword ptr[Bucket] ; GL RI RL BL2 GI + fadd st,st(4) ; GL2 RI RL BL2 GI + fstp qword ptr[Bucket2] ; RI RL BL2 GI + fadd st(1),st ; RI RL2 BL2 GI + fld qword ptr[Bucket2] ; GL2 RI RL2 BL2 GI + fld qword ptr[Bucket] ; BI GL2 RI RL2 BL2 GI + + and ebx,BLUEMASK + mov edi,TDest + + or ecx,ebx + add TDest,4 + + mov eax,[z16] + mov esi,pZBufferPtr + + shr eax,16 + mov ebx,[ZStep] + + cmp word ptr[esi],ax + jg SkipPixie + + rol ecx,16 + add [z16],ebx + + mov [edi],ecx +SkipPixie: + add pZBufferPtr,4 + dec edx + + jnz PixieLoop + + + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + fstp [u16] + fstp [v16] + +GouraudReturnNoZ: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawSpan16_AsmLitX86FPU(int32 x1, int32 x2, int32 y) +{ + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + mov pTex,edi + + fild [y] ; y + + mov edi, ClientWindow.Buffer + mov eax, y + imul eax, ClientWindow.Width + add eax, x1 + shl eax, 1 + add edi, eax + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [x1] ; x y + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi],ebp + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+4],ebp + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+8],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+12],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+16],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+20],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+24],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + + mov [edi+28],ebp ; store pixel 0 + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + + push ebp + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK + + or ebp,esi + + mov esi,pTex + + mov word ptr[edi-2],bp + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawSpan16_AsmLitZBufferX86FPU(int32 x1, int32 x2, int32 y) +{ + TDest =Dest; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + mov pTex,edi + + fild [y] ; y + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [x1] ; x y + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+0] + jle Skip0 + + mov dword ptr[edi],ebp + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + +Skip0: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+4] + jle Skip1 + + mov [edi+4],ebp + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + +Skip1: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+8] + jle Skip2 + + mov [edi+8],ebp + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + +Skip2: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+12] + jle Skip3 + + mov [edi+12],ebp + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + +Skip3: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+16] + jle Skip4 + + mov [edi+16],ebp + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + +Skip4: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+20] + jle Skip5 + + mov [edi+20],ebp + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + +Skip5: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+24] + jle Skip6 + + mov [edi+24],ebp + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + +Skip6: + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+28] + jle Skip7 + + mov dword ptr[edi+28],ebp + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + +Skip7: + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add [pZBufferPtr],32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + cmp ax,word ptr[esi] + jle SkipLeftOver + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + +SkipLeftOver: + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawSpan16_AsmLitZWriteX86FPU(int32 x1, int32 x2, int32 y) +{ + TDest =Dest; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] + mov pTex,edi + + fild [y] ; y + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [x1] ; x y + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+0],ebp + + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+4],ebp + + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+8],ebp + + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+12],ebp + + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+16],ebp + + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+20],ebp + + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov esi,pTex + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+24],ebp + + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + mov ecx,edx + + add ebx,dword ptr[DeltaU] + xor eax,0 + + and ebx,[GWMaskShifted] + and ecx,[GHMaskShifted16] + + mov esi,pTex + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + +// mov ecx,edx + xor eax,0 + + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +// add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK +// and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + mov [edi+28],ebp + + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add pZBufferPtr,32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + + mov ecx, GMipLevel4_8 + sar esi, cl + sar eax, cl + and esi, 0ffh + and eax, 0ffh + mov UDist, esi + mov VDist, eax + + mov esi,dword ptr[UFixed] + mov eax,dword ptr[VFixed] + mov ecx, GMipLevel20 + shr esi, cl + shr eax, cl + + imul eax, GLightWidth + add esi, eax + + mov edx, esi + shl esi, 1 + add edx, esi + + add edx, GLightData + + // Interpolate accross top + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R1], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G1], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B1], eax + + add edx, GLightWidth + add edx, GLightWidth + add edx, GLightWidth + + // Interpolate accross bottom + xor ecx, ecx + mov cl, [edx+3] + mov eax, ecx + mov cl, [edx+0] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [R2], eax + + xor ecx, ecx + mov cl, [edx+4] + mov eax, ecx + mov cl, [edx+1] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [G2], eax + + xor ecx, ecx + mov cl, [edx+5] + mov eax, ecx + mov cl, [edx+2] + sub eax, ecx + imul eax, UDist + shl ecx, 8 + add eax, ecx + mov [B2], eax + + // Interpolate down + mov eax, [R2] + sub eax, [R1] + imul eax, VDist + sar eax, 8 + add eax, [R1] + shr eax, 8 + and eax,0feh + + mov [RR1], eax + + mov eax, [G2] + sub eax, [G1] + imul eax, VDist + sar eax, 8 + add eax, [G1] + shr eax, 8 + and eax,0feh + + mov [GG1], eax + + mov eax, [B2] + sub eax, [B1] + imul eax, VDist + sar eax, 8 + add eax, [B1] + shr eax, 8 + and eax,0feh + + mov [BB1], eax + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawSpan16_AsmGouraudX86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2) +{ + RR1 =r1; + GG1 =g1; + BB1 =b1; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] +// inc ecx + mov pTex,edi + + fild [y] ; y + mov [widTemp],ecx + + mov edi, ClientWindow.Buffer + mov eax, y + + fild [x1] ; x y + fild [widTemp] + + imul eax, ClientWindow.Width + + fld1 + fdivrp st(1),st + + + add eax, x1 + shl eax, 1 + add edi, eax + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [r2] + fisub [r1] + fild [g2] + fisub [g1] + fild [b2] + fisub [b1] + fxch st(2) + fmul st,st(3) + fxch st(1) + fmul st,st(3) + fxch st(2) + fmul st,st(3) + frndint + fstp qword ptr[BlueDelta] + frndint + fstp qword ptr[RedDelta] + frndint + fstp qword ptr[GreenDelta] + fstp qword ptr[FTemp0] + + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi],ebp + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+4],ebp + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+8],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+12],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+16],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+20],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + mov [edi+24],ebp + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fadd qword ptr[BlueDelta] + fistp dword ptr[BB1] + fadd qword ptr[GreenDelta] + fistp dword ptr[GG1] + fadd qword ptr[RedDelta] + fistp dword ptr[RR1] + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + + mov [edi+28],ebp ; store pixel 0 + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + + push ebp + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK + + or ebp,esi + + mov esi,pTex + + mov word ptr[edi-2],bp + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawSpan16_AsmGouraudZBufferX86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2) +{ + RR1 =r1; + GG1 =g1; + BB1 =b1; + TDest =Dest; + Red =Green =Blue =0; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] +// inc ecx + mov pTex,edi + + fild [y] ; y + mov [widTemp],ecx + + fild [x1] ; x y + fild [widTemp] + + fld1 + fdivrp st(1),st + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [r2] + fisub [r1] + fild [g2] + fisub [g1] + fild [b2] + fisub [b1] + fxch st(2) + fmul st,st(3) + fxch st(1) + fmul st,st(3) + fxch st(2) + fmul st,st(3) + frndint + fstp qword ptr[BlueDelta] + frndint + fstp qword ptr[RedDelta] + frndint + fstp qword ptr[GreenDelta] + fstp qword ptr[FTemp0] + + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+0] + jle Skip0 + + mov [edi+0],ebp + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + +Skip0: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+4] + jle Skip1 + + mov [edi+4],ebp + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + +Skip1: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+8] + jle Skip2 + + mov [edi+8],ebp + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + +Skip2: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+12] + jle Skip3 + + mov [edi+12],ebp + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + +Skip3: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+16] + jle Skip4 + + mov [edi+16],ebp + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + +Skip4: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+20] + jle Skip5 + + mov [edi+20],ebp + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + +Skip5: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+24] + jle Skip6 + + mov [edi+24],ebp + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + +Skip6: + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fadd qword ptr[BlueDelta] + fistp dword ptr[BB1] + fadd qword ptr[GreenDelta] + fistp dword ptr[GG1] + fadd qword ptr[RedDelta] + fistp dword ptr[RR1] + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+28] + jle Skip7 + + mov [edi+28],ebp + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + +Skip7: + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add [pZBufferPtr],32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + cmp ax,word ptr[esi] + jle SkipLeftOver + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + +SkipLeftOver: + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + +//int32 bb1; +//__int64 rr1,gg1; + +void DrawSpan16_AsmGouraudZWriteX86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2) +{ + RR1 =r1; + GG1 =g1; + BB1 =b1; +// RR2 =r2; +// GG2 =g2; +// BB2 =b2; + TDest =Dest; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] +// inc ecx + mov pTex,edi + + fild [y] ; y + mov [widTemp],ecx + + fild [x1] ; x y + fild [widTemp] + + fld1 + fdivrp st(1),st + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [r2] + fisub [r1] + fild [g2] + fisub [g1] + fild [b2] + fisub [b1] + fxch st(2) + fmul st,st(3) + fxch st(1) + fmul st,st(3) + fxch st(2) + fmul st,st(3) + frndint + fstp qword ptr[BlueDelta] + frndint + fstp qword ptr[RedDelta] + frndint + fstp qword ptr[GreenDelta] + fstp qword ptr[FTemp0] + + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + rol eax,16 + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+0],ebp + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + + mov [edi+4],ebp + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+8],ebp + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+12],ebp + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+16],ebp + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+20],ebp + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+24],ebp + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + + mov ecx,edx + mov esi,pTex + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + and ebx,[GWMaskShifted] + xor eax,0 + + add ecx,ebx + + shr ecx,16 + add edx,dword ptr[DeltaV] + + rol eax,16 + mov ax,word ptr[2*ecx+esi] + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fadd qword ptr[BlueDelta] + fistp dword ptr[BB1] + fadd qword ptr[GreenDelta] + fistp dword ptr[GG1] + fadd qword ptr[RedDelta] + fistp dword ptr[RR1] + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + mov ecx,pZBufferPtr + + mov [edi+28],ebp + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add [pZBufferPtr],32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + +void DrawSpan16_AsmGouraudZBufferTransX86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2) +{ + RR1 =r1; + GG1 =g1; + BB1 =b1; + TDest =Dest; + _asm + { + push ebx + push ecx + push esi + push edi + + mov eax,x1 + mov ecx,x2 + sub ecx,eax + jle Return16 + + mov edi,[GBitPtr16] +// inc ecx + mov pTex,edi + + fild [y] ; y + mov [widTemp],ecx + + fild [x1] ; x y + fild [widTemp] + + fld1 + fdivrp st(1),st + + mov esi,x1 + mov edi,[TDest] + + shl esi,1 + mov eax,ecx + + add edi,esi + add pZBufferPtr,esi + + mov eax,ecx + shr ecx,4 + and eax,15 + _emit 75h + _emit 06h + dec ecx + mov eax,16 + + mov [NumASpans],ecx + mov [RemainingCount],eax + + fild [r2] + fisub [r1] + fild [g2] + fisub [g1] + fild [b2] + fisub [b1] + fxch st(2) + fmul st,st(3) + fxch st(1) + fmul st,st(3) + fxch st(2) + fmul st,st(3) + frndint + fstp qword ptr[BlueDelta] + frndint + fstp qword ptr[RedDelta] + frndint + fstp qword ptr[GreenDelta] + fstp qword ptr[FTemp0] + + + //decoder won't keep up with these huge instructions + //need to find some int instructions to cram in here somewhere + fld [UDivZStepY] ; UZdY x y + fld [UDivZStepX] ; UZdX UZdY x y + fmul st,st(2) ; UZX UZdY x y + fld [VDivZStepY] ; VZdY UZX UZdY x y + fld [VDivZStepX] ; VZdX VZdY UZX UZdY x y + fxch st(3) ; UZdy VZdY UZX VZdX x y + fmul st,st(5) ; UZY VZdY UZX VZdX x y + fxch st(2) ; UZX VZdY UZY VZdX x y + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX x y + fxch st(3) ; VZdX VZdY UZY UZXS x y + fmul st,st(4) ; VZX VZdY UZY UZXS x y + fxch st(2) ; UZY VZdY VZX UZXS x y + faddp st(3),st ; VZdY VZX UZ x y + fmul st,st(4) ; VZY VZX UZ x y + fxch st(1) ; VZX VZY UZ x y + fadd [VDivZOrigin] ; VZXS VZY UZ x y + fld [ZiStepX] ; ZdX VZXS VZY UZ x y + + //zbuffer step action + fld [ZiStepX] + fmul dword ptr[ZBufferPrec] + fmul dword ptr[Two] + fistp dword ptr[ZDelta] + + fmulp st(4),st ; VZXS VZY UZ ZX y + faddp st(1),st ; VZ UZ ZX y + fld [ZiStepY] ; ZdY VZ UZ ZX y + fmulp st(4),st ; VZ UZ ZX ZY + fxch st(2) ; ZX UZ VZ ZY + fadd [ZiOrigin] ; ZXS UZ VZ ZY + + //room for two cycles of int instructions here + + faddp st(3),st ; UZ VZ Zi + fld1 ; 1 UZ VZ Zi + fdiv st,st(3) ; ZL UZ VZ Zi + + //room for 18 cycles of int instructions here + + fld st ; ZL ZL UZ VZ Zi + fmul st,st(3) ; VL ZL UZ VZ Zi + fxch st(4) ; Zi ZL UZ VZ VL + + //zbuffer action + fld st + fmul dword ptr[ZBufferPrec] + fistp dword ptr[ZVal] + + fadd [Zi16StepX] ; ZRi ZL UZ VZ VL + fxch st(1) ; ZL ZRi UZ VZ VL + fmul st,st(2) ; UL ZRi UZ VZ VL + fxch st(3) ; VZ ZRi UZ UL VL + fadd [VDivZ16StepX] ; VZR ZRi UZ UL VL + fxch st(2) ; UZ ZRi VZR UL VL + fadd [UDivZ16StepX] ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + //room for 18 cycles of int stuff here + + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + //fmul stall one cycle + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + test ecx,ecx + jz HandleLeftoverPixels16 + +SpanLoop16: + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + fsubr st(5),st ; VR UZR ZRi VZR UL dV + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + fsubr st(5),st ; UR VR UZR ZRi VZR dU dV + fxch st(6) ; dV VR UZR ZRi VZR dU UR + fadd qword ptr[MipMagic2] ; dVk VR UZR ZRi VZR dU UR + fxch st(5) ; dU VR UZR ZRi VZR dVk UR + fadd qword ptr[MipMagic2] ; dUk VR UZR ZRi VZR dVk UR + fxch st(5) ; dVk VR UZR ZRi VZR dUk UR + fstp qword ptr[DeltaV] ; VR UZR ZRi VZR dUk UR + fxch st(5) ; UR UZR ZRi VZR dUk VR + //gotta do this to get em lined back up right + fxch st(4) ; dUk UZR ZRi VZR UR VR + fstp qword ptr[DeltaU] ; UZR ZRi VZR UR VR + + //right becomes left ; UZL ZLi VZL UL VL + fadd [UDivZ16StepX] ; UZR ZLi VZL UL VL + fxch st(1) ; ZLi UZR VZL UL VL + fadd [Zi16StepX] ; ZRi UZR VZL UL VL + fxch st(2) ; VZL UZR ZRi UL VL + fadd [VDivZ16StepX] ; VZR UZR ZRi UL VL + fxch st(2) ; ZRi UZR VZR UL VL + fxch st(1) ; UZR ZRi VZR UL VL + fld1 ; 1 UZR ZRi VZR UL VL + fdiv st,st(2) ; ZR UZR ZRi VZR UL VL + + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU016 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU016 + +TryClampU016: + cmp ebx,0 + jge NoClampU016 + mov dword ptr[UFixed],0 +NoClampU016: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV016 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV016 + +TryClampV016: + cmp eax,0 + jge NoClampV016 + mov dword ptr[VFixed],0 + +NoClampV016: + + fstp [FTemp0] ; UZR ZRi VZR UL VL + fstp [FTemp1] ; ZRi VZR UL VL + fstp [FTemp2] ; VZR UL VL + fstp [FTemp3] ; UL VL + fstp [FTemp4] ; VL + fstp [FTemp5] ; + + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + + mov ebx,dword ptr[U1] + mov eax,dword ptr[V1] + + add ebx,dword ptr[UAdjust2] + add eax,dword ptr[VAdjust2] + + mov ecx,[VShift] + mov dword ptr[Bucket],ebx + + shl eax,cl + + push ebp + + mov dword ptr[Bucket2],eax + mov ebp,dword ptr[DeltaV] + + and eax,[GHMaskShifted16] + and ebx,[GWMaskShifted] + + shl ebp,cl + add eax,ebx + + mov edx,dword ptr[Bucket2] + mov esi,pTex + + shr eax,16 + mov dword ptr[DeltaV],ebp + + mov ebx,dword ptr[Bucket] + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + mov ecx,edx + + mov ebp,eax + add ebx,dword ptr[DeltaU] + + shr ebp,1 + and ecx,[GHMaskShifted16] + + rol eax,16 + mov [CKeyTest],ebp + + and ebx,[GWMaskShifted] + + xor eax,0 + add ecx,ebx + + add edx,dword ptr[DeltaV] + mov esi,pTex + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov ecx,edx + + xor eax,0 + and ecx,[GHMaskShifted16] + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip0 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+0] + jle Skip0 + + mov [edi+0],ebp + mov word ptr[ecx+0],si + mov word ptr[ecx+2],si + +Skip0: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip1 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+4] + jle Skip1 + + mov [edi+4],ebp + mov word ptr[ecx+4],si + mov word ptr[ecx+6],si + +Skip1: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip2 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+8] + jle Skip2 + + mov [edi+8],ebp + mov word ptr[ecx+8],si + mov word ptr[ecx+10],si + +Skip2: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip3 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+12] + jle Skip3 + + mov [edi+12],ebp + mov word ptr[ecx+12],si + mov word ptr[ecx+14],si + +Skip3: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip4 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+16] + jle Skip4 + + mov [edi+16],ebp + mov word ptr[ecx+16],si + mov word ptr[ecx+18],si + +Skip4: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip5 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+20] + jle Skip5 + + mov [edi+20],ebp + mov word ptr[ecx+20],si + mov word ptr[ecx+22],si + +Skip5: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fxch st(1) + fadd qword ptr[GreenDelta] + fxch st(1) + fadd qword ptr[BlueDelta] + fxch st(2) + fadd qword ptr[RedDelta] + fxch st(2) + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + add ecx,ebx + and esi,GREENMASK + + shr ecx,16 + or ebp,esi + + xor eax,0 + mov esi,pTex + + rol ebp,16 + add edx,dword ptr[DeltaV] + + mov ax,word ptr[2*ecx+esi] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec [CKeyTest] + jl Skip6 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+24] + jle Skip6 + + mov [edi+24],ebp + mov word ptr[ecx+24],si + mov word ptr[ecx+26],si + +Skip6: + mov ecx,edx + + mov esi,pTex + xor eax,0 + + add ebx,dword ptr[DeltaU] + and ecx,[GHMaskShifted16] + + mov ebp,eax + and ebx,[GWMaskShifted] + + shr ebp,1 + add ecx,ebx + + rol eax,16 + add edx,dword ptr[DeltaV] + + shr ecx,16 + add ebx,dword ptr[DeltaU] + + mov ax,word ptr[2*ecx+esi] + mov [CKeyTest],ebp + + mov ecx,edx + xor eax,0 + + and ecx,[GHMaskShifted16] + mov esi,eax + + mov ebp,eax + and esi,REDMASK + + and ebp,GREENMASK + mov dword ptr[Red],esi + + mov dword ptr[Green],ebp + add ebx,dword ptr[DeltaU] +///////////////////////// + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and [CKeyTest],eax + + and ebp,BLUEMASK + and ebx,[GWMaskShifted] + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + fadd qword ptr[BlueDelta] + fistp dword ptr[BB1] + fadd qword ptr[GreenDelta] + fistp dword ptr[GG1] + fadd qword ptr[RedDelta] + fistp dword ptr[RR1] + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + fstp dword ptr[Bucket] + fstp dword ptr[Bucket2] + fstp dword ptr[Bucket] + + and esi,GREENMASK + + fld dword ptr[FTemp5] + fld dword ptr[FTemp4] + + or ebp,esi + + fld dword ptr[FTemp3] + fld dword ptr[FTemp2] + + rol ebp,16 + + fld dword ptr[FTemp1] + fld dword ptr[FTemp0] + + mov eax,[CKeyTest] + mov ecx,[ZVal] + + mov esi,[ZVal] + add ecx,[ZDelta] + + shr esi,16 + mov [ZVal],ecx + + dec eax + jl Skip7 + + mov ecx,pZBufferPtr + + cmp si,word ptr[ecx+28] + jle Skip7 + + mov [edi+28],ebp + mov word ptr[ecx+28],si + mov word ptr[ecx+30],si + +Skip7: + pop ebp + + + ; get corrected right side deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR UZR ZRi VZR UL VL + fld st ; ZR ZR UZR ZRi VZR UL VL + fmul st,st(4) ; VR ZR UZR ZRi VZR UL VL + fxch st(1) ; ZR VR UZR ZRi VZR UL VL + fmul st,st(2) ; UR VR UZR ZRi VZR UL VL + + add edi,32 ; move screen pointer to start of next aspan + add [pZBufferPtr],32 + dec [NumASpans] ; dec num affine spans + jnz SpanLoop16 + +HandleLeftoverPixels16: + + mov esi,[pTex] + + + cmp [RemainingCount],0 + jz FPUReturn16 + + //need one more stack spot + fstp dword ptr[FloatTemp] ; VR UZR ZRi VZR UL VL + fld st(4) ; UL VR UZR ZRi VZR UL VL + fmul [GLMapMulU] ; ULL VR UZR ZRi VZR UL VL + fld st(5) ; UL ULL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULk ULL VR UZR ZRi VZR UL VL + fxch st(1) ; ULL ULk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; ULLk ULk VR UZR ZRi VZR UL VL + fxch st(1) ; ULk ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; ULLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld st(5) ; VL VR UZR ZRi VZR UL VL + fmul [GLMapMulV] ; VLL VR UZR ZRi VZR UL VL + + add ebx,dword ptr[UAdjust] + add eax,dword ptr[UAdjustL] + + mov [U1],ebx + mov [UFixed],eax + + fld st(6) ; VL VLL VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLk VLL VR UZR ZRi VZR UL VL + fxch st(1) ; VLL VLk VR UZR ZRi VZR UL VL + fadd qword ptr[MipMagic] ; VLLk VLk VR UZR ZRi VZR UL VL + fxch st(1) ; VLk VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket] ; VLLk VR UZR ZRi VZR UL VL + fstp qword ptr[Bucket2] ; VR UZR ZRi VZR UL VL + + mov ebx,dword ptr[Bucket] + mov eax,dword ptr[Bucket2] + + fld dword ptr[FloatTemp] ; UR VR UZR ZRi VZR UL dV + + add ebx,dword ptr[VAdjust] + add eax,dword ptr[VAdjustL] + + mov [V1],ebx + mov [VFixed],eax + + dec [RemainingCount] + jz OnePixelSpan16 + + + //must get rid of this wasted time + fstp [FloatTemp] ; inv. inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. inv. UL VL + fstp [FloatTemp] ; inv. inv. UL VL + fstp [FloatTemp] ; inv. UL VL + fstp [FloatTemp] ; UL VL + fild [y] ; y UL VL + fild [x2] ; xr y UL VL + + fld [UDivZStepY] ; UZdY xr y UL VL + fld [UDivZStepX] ; UZdX UZdY xr y UL VL + fmul st,st(2) ; UZX UZdY xr y UL VL + fld [VDivZStepY] ; VZdY UZX UZdY xr y UL VL + fld [VDivZStepX] ; VZdX VZdY UZX UZdY xr y UL VL + fxch st(3) ; UZdy VZdY UZX VZdX xr y UL VL + fmul st,st(5) ; UZY VZdY UZX VZdX xr y UL VL + fxch st(2) ; UZX VZdY UZY VZdX xr y UL VL + fadd [UDivZOrigin] ; UZXS VZdY UZY VZdX xr y UL VL + fxch st(3) ; VZdX VZdY UZY UZXS xr y UL VL + fmul st,st(4) ; VZX VZdY UZY UZXS xr y UL VL + fxch st(2) ; UZY VZdY VZX UZXS xr y UL VL + faddp st(3),st ; VZdY VZX UZ xr y UL VL + fmul st,st(4) ; VZY VZX UZ xr y UL VL + fxch st(1) ; VZX VZY UZ xr y UL VL + fadd [VDivZOrigin] ; VZXS VZY UZ xr y UL VL + fld [ZiStepX] ; ZdX VZXS VZY UZ xr y UL VL + fmulp st(4),st ; VZXS VZY UZ ZX y UL VL + faddp st(1),st ; VZ UZ ZX y UL VL + fld [ZiStepY] ; ZdY VZ UZ ZX y UL VL + fmulp st(4),st ; VZ UZ ZX ZY UL VL + fxch st(2) ; ZX UZ VZ ZY UL VL + fadd [ZiOrigin] ; ZXS UZ VZ ZY UL VL + + faddp st(3),st ; UZ VZ Zi UL VL + fld1 ; 1 UZ VZ Zi UL VL + fdiv st,st(3) ; ZR UZ VZ Zi UL VL + + fld st ; ZR ZR UZ VZ Zi UL VL + fmul st,st(3) ; VR ZR UZ VZ Zi UL VL + fxch st(1) ; ZR VR UZ VZ Zi UL VL + fmul st,st(2) ; UR VR UZ VZ Zi UL VL + + //lazy idiv below... should 1/int mul mul + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + fsubr st(5),st ; UR VR inv. inv. inv. dU VL + fxch st(1) ; VR UR inv. inv. inv. dU VL + fsubr st(6),st ; VR UR inv. inv. inv. dU dV + fxch st(6) ; dV UR inv. inv. inv. dU VR + fidiv dword ptr[RemainingCount];dv UR inv. inv. inv. dU VR + fadd qword ptr[MipMagic] ; dvk UR inv. inv. inv. dU VR + fxch st(5) ; dU UR inv. inv. inv. dvk VR + fidiv dword ptr[RemainingCount];du UR inv. inv. inv. dvk VR + fadd qword ptr[MipMagic] ; duk UR inv. inv. inv. dvk VR + fxch st(5) ; dvk UR inv. inv. inv. duk VR + fstp qword ptr[DeltaV] ; UR inv. inv. inv. duk VR + fxch st(4) ; duk inv. inv. inv. UR VR + fstp qword ptr[DeltaU] ; inv. inv. inv. UR VR + fld st(1) ; inv. inv. inv. inv. UR VR + fld st(2) ; inv. inv. inv. inv. inv. UR VR + +OnePixelSpan16: + // Clamp U/V + mov ebx,[UFixed] + cmp ebx,MaxU + jle TryClampU116 + mov ecx,MaxU + mov dword ptr[UFixed],ecx + jmp NoClampU116 + +TryClampU116: + cmp ebx,0 + jge NoClampU116 + mov dword ptr[UFixed],0 +NoClampU116: + mov eax,[VFixed] + cmp eax,MaxV + jle TryClampV116 + mov ecx,MaxV + mov dword ptr[VFixed],ecx + jmp NoClampV116 + +TryClampV116: + cmp eax,0 + jge NoClampV116 + mov dword ptr[VFixed],0 + +NoClampV116: + + fstp [FTemp0] + fstp [FTemp1] + fstp [FTemp2] + fstp [FTemp3] + fstp [FTemp4] + fstp [FTemp5] + + mov ebx,dword ptr[U1] + mov edx,dword ptr[V1] + + fild [RR1] ; LR + fild [GG1] ; LG LR + fild [BB1] ; LB LG LR + + mov ecx,[VShift] + add edx,dword ptr[VAdjust2] + + add ebx,dword ptr[UAdjust2] + mov eax,dword ptr[DeltaV] + + shl eax,cl + mov esi,pTex + + shl edx,cl + mov dword ptr[DeltaV],eax + + mov eax,[ZDelta] + mov ecx,[ZVal] + + sar eax,1 + push ebp + + mov [ZDelta],eax + + +LeftoverLoop16: + mov eax,edx + and ebx,[GWMaskShifted] + + and eax,[GHMaskShifted16] + + add eax,ebx + add ebx,dword ptr[DeltaU] + + shr eax,16 + add edi,2 + + mov ax,word ptr[2*eax+esi] + add edx,dword ptr[DeltaV] + + xor eax,0 + + mov esi,eax + mov ebp,eax + + and esi,REDMASK + and ebp,GREENMASK + + mov dword ptr[Red],esi + mov dword ptr[Green],ebp + + fild qword ptr[Red] ; r LB LG LR + + mov ebp,eax + shr eax,1 + + fmul st,st(3) ; R LB LG LR + fild qword ptr[Green] ; g R LB LG LR + + and ebp,BLUEMASK + mov [CKeyTest],eax + + mov dword ptr[Blue],ebp + + fmul st,st(3) ; G R LB LG LR + fild [Blue] ; b G R LB LG LR + fmul st,st(3) ; B G R LB LG LR + fxch st(2) ; R G B LB LG LR + fadd qword ptr[Magic] ; Rk G B LB LG LR + fxch st(1) ; G Rk B LB LG LR + fadd qword ptr[Magic] ; Gk Rk B LB LG LR + fxch st(2) ; B Rk Gk LB LG LR + fadd qword ptr[Magic] ; Bk Rk Gk LB LG LR + fxch st(1) ; Rk Bk Gk LB LG LR + fstp qword ptr[Bucket] ; Bk Gk LB LG LR + fstp qword ptr[Bucket2] ; Gk LB LG LR + + mov eax,dword ptr[Bucket] + mov ebp,dword ptr[Bucket2] + + fstp qword ptr[Bucket] ; LB LG LR + + and eax,REDMASK + and ebp,BLUEMASK + + mov esi,dword ptr[Bucket] + or ebp,eax + + and esi,GREENMASK + mov eax,ecx + + or ebp,esi + + shr eax,16 + mov esi,pZBufferPtr + + dec [CKeyTest] + jl SkipLeftOver + + cmp ax,word ptr[esi] + jle SkipLeftOver + + mov word ptr[edi-2],bp + mov word ptr[esi],ax + +SkipLeftOver: + add ecx,[ZDelta] + mov esi,pTex + + add pZBufferPtr,2 + + dec [RemainingCount] + jge LeftoverLoop16 + + pop ebp + + +FPUReturn16: + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + +Return16: + pop edi + pop esi + pop ecx + pop ebx + } +} + + +#pragma warning (default:4410) //illegal size for operand diff --git a/G3D/Engine/Drivers/SoftDrv/x86span565.h b/G3D/Engine/Drivers/SoftDrv/x86span565.h new file mode 100644 index 0000000..1d3b08d --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv/x86span565.h @@ -0,0 +1,67 @@ +/****************************************************************************************/ +/* x86span565.h */ +/* */ +/* Author: Ken Baird */ +/* Description: header for x86 renderstates */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +typedef struct EdgeAsmTag EdgeAsm; +typedef struct EdgeAsmFPUTag EdgeAsmFPU; + +//x86 fpu based non world faces +//DRV_RENDER_NO_ZMASK +extern void DrawScanLineGouraudNoZBufferZWrite_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +extern void DrawScanLineGouraudNoZBufferZWriteTrans_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +//solid color +extern void DrawScanLineGouraudNoZBufferZWriteSolid_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); + +//DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE +extern void DrawScanLineGouraudNoZ_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +extern void DrawScanLineGouraudNoZTrans_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +//solid color +extern void DrawScanLineGouraudNoZSolid_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); + +//DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudNoZAlphaTex_AsmX86FPU(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_NO_ZMASK | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudNoZBufferZWriteAlphaTex_AsmX86FPU(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_NO_ZMASK | DRV_RENDER_ALPHA +extern void DrawScanLineGouraudZBufferNoZWriteAlphaTex_AsmX86FPU(EdgeAsm *pLeft, EdgeAsm *pRight); +//DRV_RENDER_ALPHA +extern void DrawScanLineGouraudZBufferAlphaTex_AsmX86FPU(EdgeAsm *pLeft, EdgeAsm *pRight); + +//!(DRV_RENDER_NO_ZMASK | DRV_RENDER_NO_ZWRITE) +extern void DrawScanLineGouraudZBuffer_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +extern void DrawScanLineGouraudZBufferTrans_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +//solid color +extern void DrawScanLineGouraudZBufferSolid_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); + +//DRV_RENDER_NO_ZWRITE +extern void DrawScanLineGouraudZBufferNoZWrite_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +extern void DrawScanLineGouraudZBufferNoZWriteTrans_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); +//solid color +extern void DrawScanLineGouraudZBufferNoZWriteSolid_AsmX86FPU(EdgeAsmFPU *pLeft, EdgeAsmFPU *pRight); + + +//world perspective correct faces +void DrawSpan16_AsmLitX86FPU(int32 x1, int32 x2, int32 y); +void DrawSpan16_AsmLitZWriteX86FPU(int32 x1, int32 x2, int32 y); +void DrawSpan16_AsmLitZBufferX86FPU(int32 x1, int32 x2, int32 y); +void DrawSpan16_AsmGouraudX86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2); +void DrawSpan16_AsmGouraudZWriteX86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2); +void DrawSpan16_AsmGouraudZBufferX86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2); +void DrawSpan16_AsmGouraudZBufferTransX86FPU(int32 x1, int32 x2, int32 y, int32 r1, int32 g1, int32 b1, int32 r2, int32 g2, int32 b2); \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv2/CPUInfo.c b/G3D/Engine/Drivers/SoftDrv2/CPUInfo.c new file mode 100644 index 0000000..d169239 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/CPUInfo.c @@ -0,0 +1,207 @@ +/****************************************************************************************/ +/* CPUInfo.C */ +/* */ +/* Author: Mike Sandige, Ken Baird */ +/* Description: simple cpu capabilities tests */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#define WIN32_LEAN_AND_MEAN +#pragma warning(disable : 4201 4214 4115) +#include // EXCEPTION_EXECUTE_HANDLER +#include // strnlen +#pragma warning(default : 4201 4214 4115; disable : 4514) + +#include "CPUInfo.h" + +#define CPUID _asm _emit 0fh _asm _emit 0a2h + +static int Flag_CPUID = TRUE; +static int Flag_RDTSC = TRUE; + + +void Test_CPU_bits(void) +{ + Flag_CPUID = FALSE; + Flag_RDTSC = FALSE; +_asm + { + pushad // (1) play nice and save everything + pushfd // eax = ebx = extended flags + pop eax + mov ebx,eax + + xor eax,200000h // toggle bit 21 + + push eax // extended flags = eax + popfd + xor eax,ebx // if bit 21 r/w then eax <> 0 + + jz done // can't toggle id bit (21) no cpuid here + mov eax,1 // get standard features + mov Flag_CPUID,eax // (and set cpuid flag to true) + + CPUID + test edx,10h // is rdtsc available? + jz done + + mov Flag_RDTSC,1 +done: + popad // (1) restore everything + } +} + + + + + +static uint32 CPUInfo_GetCPUIDEAX(uint32 funcNum) +{ + uint32 retval; + + Test_CPU_bits(); + if (Flag_CPUID) + { + __try + { + _asm + { + mov eax,funcNum + CPUID + mov retval,eax + } + }__except(EXCEPTION_EXECUTE_HANDLER) + { + retval =0; + } + } + else + { + retval = 0; + } + + return retval; +} + +static uint32 CPUInfo_GetCPUIDEDX(uint32 funcNum) +{ + uint32 retval; + + Test_CPU_bits(); + if (Flag_CPUID) + { + __try + { + _asm + { + mov eax,funcNum + CPUID + mov retval,edx + } + }__except(EXCEPTION_EXECUTE_HANDLER) + { + retval =0; + } + } + else + { + retval = 0; + } + + return retval; +} + + +static uint32 CPUInfo_GetCPUIDString(uint32 funcNum, char *szId) +{ + uint32 retval; + + Test_CPU_bits(); + if (Flag_CPUID) + { + __try + { + _asm + { + mov eax,funcNum + CPUID + mov retval,eax + mov eax,szId + mov dword ptr[eax],ebx + mov dword ptr[eax+4],edx + mov dword ptr[eax+8],ecx + } + }__except(EXCEPTION_EXECUTE_HANDLER) + { + retval =0; + } + } + else + { + retval = 0; + } + + return retval; +} + + +#define CPUINFO_VENDOR_STRING_LENGTH 16 +#define CPUINFO_AMD_ID_STRING "AuthenticAMD" +#define CPUINFO_INTEL_ID_STRING "GenuineIntel" + +geBoolean CPUInfo_TestFor3DNow(void) +{ + char VendorString[CPUINFO_VENDOR_STRING_LENGTH]; + + CPUInfo_GetCPUIDString(0, VendorString); + if(strncmp(VendorString, CPUINFO_AMD_ID_STRING,strlen(CPUINFO_AMD_ID_STRING))==0) + { + uint32 TypeFlags =CPUInfo_GetCPUIDEAX(0x80000000); + if(TypeFlags) //extended functions supported + { + TypeFlags =CPUInfo_GetCPUIDEDX(0x80000001); + if (TypeFlags & (1<<23)) + return GE_TRUE; + } + } + return GE_FALSE; +} + +geBoolean CPUInfo_TestForMMX(void) +{ + char VendorString[CPUINFO_VENDOR_STRING_LENGTH]; + + CPUInfo_GetCPUIDString(0, VendorString); + if(strncmp(VendorString, CPUINFO_AMD_ID_STRING,strlen(CPUINFO_AMD_ID_STRING))==0) + { + uint32 TypeFlags =CPUInfo_GetCPUIDEAX(0x80000000); + if(TypeFlags) //extended functions supported + { + TypeFlags =CPUInfo_GetCPUIDEDX(0x80000001); + if (TypeFlags & (1<<23)) + return GE_TRUE; + } + } + else if(strncmp(VendorString, CPUINFO_INTEL_ID_STRING, strlen(CPUINFO_INTEL_ID_STRING))==0) + { + uint32 TypeFlags =CPUInfo_GetCPUIDEDX(0x1); + if (TypeFlags & (1<<23)) + return GE_TRUE; + } + + return GE_FALSE; +} diff --git a/G3D/Engine/Drivers/SoftDrv2/CPUInfo.h b/G3D/Engine/Drivers/SoftDrv2/CPUInfo.h new file mode 100644 index 0000000..aee1bd9 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/CPUInfo.h @@ -0,0 +1,43 @@ +/****************************************************************************************/ +/* CPUInfo.H */ +/* */ +/* Author: Mike Sandige, Ken Baird */ +/* Description: simple cpu capabilities tests */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef CPUInfo_H +#define CPUInfo_H + +// Tests cpu for various features. + + +#include "basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +geBoolean CPUInfo_TestFor3DNow(void); +geBoolean CPUInfo_TestForMMX(void); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.c b/G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.c new file mode 100644 index 0000000..0e46142 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.c @@ -0,0 +1,891 @@ +/****************************************************************************************/ +/* DDRAWDisplay.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: display surface manager for full screen Direct Draw using a direct */ +/* draw surface for the the frame buffer */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#pragma warning(disable : 4201 4214 4115) +#include +#include +#include "ddraw.h" +#include +#pragma warning(default : 4201 4214 4115; disable : 4514) + +#include "DDRAWDisplay.h" + +#ifdef GENESIS_VERSION_2 +#include "errorlog.h" +#else +#define geErrorLog_AddString(Error,xx,yy) +#endif + + +#define DDRAWDISPLAY_DESCRIPTION_STRING "Software (Full Screen) " + +typedef struct +{ + LPDIRECTDRAW4 lpDD4; + HANDLE ddrawinst; +} DDRAWDisplay_DLLHooks; + +typedef struct DDRAWDisplay +{ + DDRAWDisplay_DLLHooks DLL; + + LPDIRECTDRAWSURFACE4 lpDDSPrimary; // DirectDraw primary surface + LPDIRECTDRAWSURFACE4 lpDDSBack; // DirectDraw back surface + BOOL bActive; + + int Width; + int Height; + int BitsPerPixel; + int ModeFlags; + + HWND hWnd; + geBoolean Locked; + uint8 *Buffer; + int32 Pitch; +} DDRAWDisplay; + +typedef HRESULT (WINAPI *LPDIRECTDRAWCREATE)( GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter ); + + +static geBoolean DDRAWDisplay_IsValid(DDRAWDisplay *D) +{ + if ( D == NULL ) + return GE_FALSE; + + if (D->DLL.ddrawinst == NULL ) + return GE_FALSE; + + if (D->DLL.lpDD4 == NULL) + return GE_FALSE; + + if (D->hWnd == NULL ) + return GE_FALSE; + + return GE_TRUE; +} + +static void DDRAWDisplay_UnloadDLL( DDRAWDisplay_DLLHooks *H ) +{ + assert( H != NULL ); + if (H->lpDD4) + { + H->lpDD4->lpVtbl->Release(H->lpDD4); + H->lpDD4 = NULL; + } + if (H->ddrawinst) + { + FreeLibrary(H->ddrawinst); + H->ddrawinst = NULL; + } +} + +static geBoolean DDRAWDisplay_LoadDLL( DDRAWDisplay_DLLHooks *H ) +{ + LPDIRECTDRAW lpDD = NULL; // DirectDraw object + LPDIRECTDRAWCREATE lpDDCreate = NULL; + HRESULT ddrval; + assert( H != NULL ); + + H->ddrawinst = NULL; + H->lpDD4 = NULL; + + + H->ddrawinst =LoadLibrary("ddraw.dll"); + + if(!H->ddrawinst) + { + geErrorLog_AddString(-1,"failed to load","ddraw.dll"); + goto LoadDLL_ERROR; + } + + lpDDCreate =(LPDIRECTDRAWCREATE)GetProcAddress(H->ddrawinst, "DirectDrawCreate"); + if(lpDDCreate) + { + ddrval =lpDDCreate(NULL, &(lpDD), NULL); + if((ddrval != DD_OK) || ((lpDD)==NULL)) + { + geErrorLog_AddString(-1,"ddraw lpDDCreate failed", geErrorLog_IntToString(ddrval)); + goto LoadDLL_ERROR; + } + } + else + { + geErrorLog_AddString(-1 ,"Unable to find DirectDrawCreate entry into ddraw.dll",NULL); + goto LoadDLL_ERROR; + } + + ddrval = lpDD->lpVtbl->QueryInterface(lpDD, &IID_IDirectDraw4, (LPVOID *)&(H->lpDD4)); + if(ddrval!=DD_OK) + { + geErrorLog_AddString(-1,"QueryInterface failed", geErrorLog_IntToString(ddrval)); + goto LoadDLL_ERROR; + } + + lpDD->lpVtbl->Release(lpDD); + lpDD =NULL; + + + return GE_TRUE; + + + LoadDLL_ERROR: + if (lpDD != NULL ) + { + lpDD->lpVtbl->Release(lpDD); + lpDD =NULL; + } + DDRAWDisplay_UnloadDLL(H); + return GE_FALSE; +} + +void DDRAWDisplay_GetDisplayFormat( const DDRAWDisplay *D, + int32 *Width, + int32 *Height, + int32 *BitsPerPixel, + uint32 *Flags) +{ + assert( D != NULL ); + assert( Width != NULL ); + assert( Height != NULL ); + assert( BitsPerPixel != NULL ); + assert( Flags != NULL ); + + *Width = D->Width; + *Height = D->Height; + *BitsPerPixel = D->BitsPerPixel; + *Flags = D->ModeFlags; +} + +void DDRAWDisplay_Destroy(DDRAWDisplay **pD) +{ + DDRAWDisplay *D; + + assert( pD ); + assert( DDRAWDisplay_IsValid(*pD)!=GE_FALSE ); + D = *pD; + + if (D->Locked == GE_TRUE) + DDRAWDisplay_Unlock(D); + + if (D->ModeFlags & FLIP) + { + D->lpDDSBack =NULL; + } + else + { + if(D->lpDDSBack) + { + D->lpDDSBack->lpVtbl->Release(D->lpDDSBack); + D->lpDDSBack =NULL; + } + } + if(D->lpDDSPrimary) + { + D->lpDDSPrimary->lpVtbl->Release(D->lpDDSPrimary); + D->lpDDSPrimary =NULL; + } + + DDRAWDisplay_UnloadDLL(&(D->DLL)); + + free(D); + *pD = NULL; +} + +static geBoolean DDRAWDisplay_RestoreAll(DDRAWDisplay *D) +{ + HRESULT ddrval; + assert( DDRAWDisplay_IsValid(D)!=GE_FALSE ); + + ddrval =D->DLL.lpDD4->lpVtbl->SetCooperativeLevel(D->DLL.lpDD4, D->hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + if(ddrval!=DD_OK) + { + geErrorLog_AddString(-1,"DDRAWDisplay_RestoreAll(): ddraw SetCooperativeLevel", geErrorLog_IntToString(ddrval)); + return GE_FALSE; + } + + ddrval =D->DLL.lpDD4->lpVtbl->SetDisplayMode(D->DLL.lpDD4, D->Width, D->Height, D->BitsPerPixel, 0, 0); + if(ddrval!=DD_OK) + { + geErrorLog_AddString(-1,"DDRAWDisplay_RestoreAll: ddraw SetDisplayMode", geErrorLog_IntToString(ddrval)); + return GE_FALSE; + } + ddrval =D->DLL.lpDD4->lpVtbl->RestoreAllSurfaces(D->DLL.lpDD4); + if(ddrval!=DD_OK) + { + geErrorLog_AddString(-1,"DDRAWDisplay_RestoreAll: ddraw RestoreAllSurfaces", geErrorLog_IntToString(ddrval)); + return GE_FALSE; + } + return GE_TRUE; +} + + +geBoolean DDRAWDisplay_Lock(DDRAWDisplay *D, uint8 **Buffer, int32 *Pitch) +{ + HRESULT ddrval; + DDSURFACEDESC2 ddsd; + RECT wrect; + int Forever = 1; + assert( DDRAWDisplay_IsValid(D)!=GE_FALSE ); + + if(!D->bActive) + return GE_TRUE; + // <> should probably be GE_FALSE, but this stays compatible with the existing convention + + assert( Buffer != NULL ); + assert( Pitch != NULL ); + + if (D->Locked != GE_FALSE) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Lock: already locked",NULL ); + return GE_FALSE; + } + + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + + D->lpDDSBack->lpVtbl->GetSurfaceDesc(D->lpDDSBack, &ddsd); + wrect.left = 0; + wrect.top = 0; + wrect.right = ddsd.dwWidth-1; + wrect.bottom = ddsd.dwHeight-1; + + while(Forever) + { + ddrval =D->lpDDSBack->lpVtbl->Lock(D->lpDDSBack, &wrect, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL); + if(ddrval==DD_OK) + { + break; + } + + if(ddrval==DDERR_SURFACELOST) + { + if (DDRAWDisplay_RestoreAll(D) == GE_FALSE) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Lock: lost ddraw surface", NULL); + return GE_FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Lock: was still drawing",geErrorLog_IntToString(ddrval)); + return GE_FALSE; + } + } + *Buffer = (uint8 *)ddsd.lpSurface; + *Pitch = ddsd.lPitch; + D->Locked = GE_TRUE; + D->Buffer = *Buffer; + D->Pitch = *Pitch; + return GE_TRUE; +} + +geBoolean DDRAWDisplay_Unlock(DDRAWDisplay *D) +{ + int Forever=1; + HRESULT ddrval =DD_OK; + assert( DDRAWDisplay_IsValid(D)!=GE_FALSE ); + + if(!D->bActive) + return GE_TRUE; + // <> should probably be GE_FALSE, but this stays compatible with the existing convention + + if (D->Locked != GE_TRUE) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Unlock: surface not locked",NULL); + return GE_FALSE; + } + + D->Locked = GE_FALSE; + + while(Forever) + { + ddrval =D->lpDDSBack->lpVtbl->Unlock(D->lpDDSBack, NULL); + if(ddrval==DD_OK) + break; + + #pragma message (" can you loose a locked surface?") + if(ddrval==DDERR_SURFACELOST) + { + if (DDRAWDisplay_RestoreAll(D) == GE_FALSE) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Unlock: surface lost\n",NULL); + return GE_FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Unlock: was still drawing.",geErrorLog_IntToString(ddrval)); + return GE_FALSE; + } + } + + D->Locked = GE_FALSE; + return GE_TRUE; +} + +geBoolean DDRAWDisplay_Blit(DDRAWDisplay *D) +{ + HRESULT ddrval; + DDSURFACEDESC2 ddsd; + RECT rDest, rSrc; + int Forever=1; + assert( DDRAWDisplay_IsValid(D)!=GE_FALSE ); + + if(!D->bActive) + { + return GE_TRUE; + } + + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + + D->lpDDSBack->lpVtbl->GetSurfaceDesc(D->lpDDSBack, &ddsd); + rDest.left =rDest.top =0; + rDest.right =ddsd.dwWidth-1; + rDest.bottom=ddsd.dwHeight-1; + + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + + D->lpDDSPrimary->lpVtbl->GetSurfaceDesc(D->lpDDSPrimary, &ddsd); + rSrc.left =rSrc.top =0; + rSrc.right =ddsd.dwWidth-1; + rSrc.bottom =ddsd.dwHeight-1; + + ddrval =DD_OK; + if((D->ModeFlags & VIDEO) && (D->ModeFlags & FASTBLT)) + { + while(Forever) + { + ddrval =D->lpDDSPrimary->lpVtbl->BltFast(D->lpDDSPrimary, 0, 0, D->lpDDSBack, NULL, 0); + if(ddrval==DD_OK) + { + break; + } + + if(ddrval==DDERR_SURFACELOST) + { + if (DDRAWDisplay_RestoreAll(D) == GE_FALSE) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Blit: lost surface",NULL); + return GE_FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Blit: was still drawing",NULL); + return GE_FALSE; + } + } + } + else if(D->ModeFlags & FLIP) + { + while(Forever) + { + ddrval =D->lpDDSPrimary->lpVtbl->Flip(D->lpDDSPrimary, D->lpDDSBack, DDFLIP_NOVSYNC); + if(ddrval==DD_OK) + { + break; + } + + if(ddrval==DDERR_SURFACELOST) + { + if (DDRAWDisplay_RestoreAll(D)==GE_FALSE) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Blit: lost surface",NULL); + return GE_FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Blit: was still drawing",NULL); + return GE_FALSE; + } + } + } + else //safe blt + { + while(Forever) + { + ddrval =D->lpDDSPrimary->lpVtbl->Blt(D->lpDDSPrimary, NULL, D->lpDDSBack, NULL, DDBLT_WAIT, NULL); + if(ddrval==DD_OK) + break; + + if(ddrval==DDERR_SURFACELOST) + { + if (DDRAWDisplay_RestoreAll(D)==GE_FALSE) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Blit: lost surface",NULL); + return GE_FALSE; + } + } + else if(ddrval!=DDERR_WASSTILLDRAWING) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Blit: was still drawing",NULL); + return GE_FALSE; + } + } + } + return GE_TRUE; +} + +//my best guess for best performance is fast, blt, flip +//dma is off for now because it ran horribly on the machine +//I tested it on. If people get 500mhz agp bus action in a few +//years it might be useful perhaps +static geBoolean DDRAWDisplay_SetMode(DDRAWDisplay *D, int width, int height, int bpp, uint32 flags) +{ + HRESULT ddrval; + DDSURFACEDESC2 ddsd; + DDSCAPS2 ddscaps; + + assert( DDRAWDisplay_IsValid(D)!=GE_FALSE ); + + + D->ModeFlags = 0; + + ddrval =D->DLL.lpDD4->lpVtbl->SetDisplayMode(D->DLL.lpDD4, width, height, bpp, 0, 0); + + D->Height =height; + D->Width =width; + D->BitsPerPixel =bpp; + + if(!(flags & MODEXMODE)) + { + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS; + ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE | DDSCAPS_VIDEOMEMORY; + + ddrval =D->DLL.lpDD4->lpVtbl->CreateSurface(D->DLL.lpDD4, &ddsd, &D->lpDDSPrimary, NULL); + if(ddrval==DD_OK) + { + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps =DDSCAPS_SYSTEMMEMORY; + //ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY; + ddsd.dwHeight =height; + ddsd.dwWidth =width; + + ddrval =D->DLL.lpDD4->lpVtbl->CreateSurface(D->DLL.lpDD4, &ddsd, &D->lpDDSBack, NULL); + if(ddrval==DD_OK) + { + + //both were created, make sure they are in vidram + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + D->lpDDSPrimary->lpVtbl->GetCaps(D->lpDDSPrimary, &ddscaps); + if(ddscaps.dwCaps & DDSCAPS_VIDEOMEMORY) + { + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + D->lpDDSBack->lpVtbl->GetCaps(D->lpDDSBack, &ddscaps); + if(ddscaps.dwCaps & DDSCAPS_VIDEOMEMORY) + { + + //both are good to go + D->ModeFlags |=VIDEO; + + //mark fastblt unless it's stretching + if(!(flags & STRETCHMODE)) + { + D->ModeFlags |=FASTBLT; + } + } + } + } + } + #pragma message ("this cant be set can it?") + else if(!(D->ModeFlags & VIDEO) + && !(D->ModeFlags & STRETCHMODE)) + { + if(D->lpDDSBack) D->lpDDSBack->lpVtbl->Release(D->lpDDSBack); + if(D->lpDDSPrimary) D->lpDDSPrimary->lpVtbl->Release(D->lpDDSPrimary); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS; + ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE; + + ddrval =D->DLL.lpDD4->lpVtbl->CreateSurface(D->DLL.lpDD4, &ddsd, &D->lpDDSPrimary, NULL); + if(ddrval==DD_OK) + { + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.dwHeight =height; + ddsd.dwWidth =width; + + ddrval =D->DLL.lpDD4->lpVtbl->CreateSurface(D->DLL.lpDD4, &ddsd, &D->lpDDSBack, NULL); + if(ddrval==DD_OK) + { + //both were created good enough + D->ModeFlags |=SYSTEM|SAFEBLT; + } + } + } + } //flip + if((flags & MODEXMODE) || D->lpDDSBack==NULL) + { + if(D->lpDDSBack) D->lpDDSBack->lpVtbl->Release(D->lpDDSBack); + if(D->lpDDSPrimary) D->lpDDSPrimary->lpVtbl->Release(D->lpDDSPrimary); + + //try flip + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags =DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE | + DDSCAPS_COMPLEX | DDSCAPS_FLIP; + ddsd.dwBackBufferCount =1; + + ddrval =D->DLL.lpDD4->lpVtbl->CreateSurface(D->DLL.lpDD4, &ddsd, &D->lpDDSPrimary, NULL); + if(ddrval==DD_OK) + { + memset(&ddscaps, 0, sizeof(DDSCAPS2)); + ddscaps.dwCaps =DDSCAPS_BACKBUFFER; + ddrval =D->lpDDSPrimary->lpVtbl->GetAttachedSurface(D->lpDDSPrimary, &ddscaps, &D->lpDDSBack); + if(ddrval==DD_OK) + { + D->ModeFlags |=SYSTEM|FLIP; + } + else + { + geErrorLog_AddString(-1,"Unable to create primary buffer",NULL); + return GE_FALSE; + } + } + } + return GE_TRUE; +} + + + + +DDRAWDisplay *DDRAWDisplay_Create(HWND hwnd, int Width, int Height, int BPP, uint32 Flags) +{ + DDRAWDisplay *D = NULL; + + HRESULT ddrval = 0; + + D = malloc(sizeof(DDRAWDisplay)); + if (D == NULL) + { + geErrorLog_AddString(-1,"Failed to create DDRAWDisplay object",NULL); + return NULL; + } + + memset(D,0,sizeof(DDRAWDisplay)); + + + if (DDRAWDisplay_LoadDLL(&(D->DLL))==GE_FALSE) + { + geErrorLog_AddString(-1,"failed to load ddraw dll",NULL); + goto Create_ERROR; + } + D->hWnd = hwnd; + D->bActive = GE_FALSE; + + ddrval =D->DLL.lpDD4->lpVtbl->SetCooperativeLevel(D->DLL.lpDD4, hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + if(ddrval!=DD_OK) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Create: failed to set cooperative level", geErrorLog_IntToString(ddrval)); + goto Create_ERROR; + } + + if (DDRAWDisplay_SetMode(D, Width, Height, BPP, Flags)==GE_FALSE) + { + geErrorLog_AddString(-1,"Failed to create buffers",NULL); + goto Create_ERROR; + } + + assert( DDRAWDisplay_IsValid(D)!=GE_FALSE ); + return D; + + Create_ERROR: + if (D) + { + DDRAWDisplay_UnloadDLL(&(D->DLL)); + free(D); + } + return NULL; +} + + + + +geBoolean DDRAWDisplay_GetPixelFormat( DDRAWDisplay *D, + //int32 *pixel_pitch, + int32 *bytes_per_pixel, + int32 *R_shift, + uint32 *R_mask, + int32 *R_width, + int32 *G_shift, + uint32 *G_mask, + int32 *G_width, + int32 *B_shift, + uint32 *B_mask, + int32 *B_width) +{ + DDPIXELFORMAT ddpf; + uint32 i, j; + + assert( DDRAWDisplay_IsValid(D)!=GE_FALSE ); + //assert( pixel_pitch != NULL ); + assert( bytes_per_pixel != NULL ); + assert( R_shift != NULL ); + assert( R_mask != NULL ); + assert( R_width != NULL ); + assert( G_shift != NULL ); + assert( G_mask != NULL ); + assert( G_width != NULL ); + assert( B_shift != NULL ); + assert( B_mask != NULL ); + assert( B_width != NULL ); + + ddpf.dwSize =sizeof(ddpf); + D->lpDDSPrimary->lpVtbl->GetPixelFormat(D->lpDDSPrimary, &ddpf); + + if(!(ddpf.dwFlags & DDPF_RGB)) + { + return GE_FALSE; + } + *bytes_per_pixel =ddpf.dwRGBBitCount / 8; + *R_mask =ddpf.dwRBitMask; + *G_mask =ddpf.dwGBitMask; + *B_mask =ddpf.dwBBitMask; + + for(j=0,i=ddpf.dwRBitMask;!(i & 1);i>>=1,j++); + *R_shift =j; + + for(j=0,i=ddpf.dwGBitMask;!(i & 1);i>>=1,j++); + *G_shift =j; + + for(j=0,i=ddpf.dwBBitMask;!(i & 1);i>>=1,j++); + *B_shift =j; + + for(i=(ddpf.dwRBitMask>>*R_shift),*R_width=0;i;i >>= 1, (*R_width)++); + for(i=(ddpf.dwGBitMask>>*G_shift),*G_width=0;i;i >>= 1, (*G_width)++); + for(i=(ddpf.dwBBitMask>>*B_shift),*B_width=0;i;i >>= 1, (*B_width)++); + return GE_TRUE; +} + + +geBoolean DDRAWDisplay_Wipe(DDRAWDisplay *D,uint32 color) +{ + DDSURFACEDESC2 ddsd; + int Width, Height; + + assert( DDRAWDisplay_IsValid(D)!=GE_FALSE ); + + if(!D->bActive) + { + return GE_FALSE; + } + + if (!D->Locked) + { + geErrorLog_AddString(-1,"DDRAWDisplay_Wipe: surface not locked",NULL ); + return GE_FALSE; + } + memset(&ddsd, 0, sizeof(DDSCAPS2)); + ddsd.dwSize =sizeof(ddsd); + ddsd.dwFlags=DDSD_HEIGHT | DDSD_WIDTH; + #pragma message ("this may not be necessary") + D->lpDDSBack->lpVtbl->GetSurfaceDesc(D->lpDDSBack, &ddsd); + + Width =ddsd.dwWidth; + Height =ddsd.dwHeight; + + memset(D->Buffer, color, (Height*D->Pitch)); + return GE_TRUE; +} + +geBoolean DDRAWDisplay_SetActive(DDRAWDisplay *D, geBoolean wParam) +{ + assert( D != NULL ); + + D->bActive =wParam; + + if(D->bActive) + { + if(D->lpDDSPrimary->lpVtbl->IsLost(D->lpDDSPrimary)==DDERR_SURFACELOST) + { + if(DDRAWDisplay_RestoreAll(D)!=GE_FALSE) + { + ShowWindow(D->hWnd, SW_SHOWNORMAL); //dx doesn't restore it + } + else + { + geErrorLog_AddString(-1,"DDRAWDisplay_SetActive: Couldn't restore surfaces",NULL); + return GE_FALSE; + } + } + } + return GE_TRUE; +} + +// ----------------------------------------------------------- + + +static HRESULT WINAPI DDRAWDisplay_ModeCallback(LPDDSURFACEDESC2 pdds, LPVOID lParam) +{ + DisplayModeInfo *Info =(DisplayModeInfo *)lParam; + + #pragma message ("only 16 bit display is supported") + if(pdds->ddpfPixelFormat.dwRGBBitCount==16) + { + DisplayModeInfo_AddEntry(Info, + pdds->dwWidth, + pdds->dwHeight, + pdds->ddpfPixelFormat.dwRGBBitCount, + pdds->ddpfPixelFormat.dwRGBBitCount); + } + return S_FALSE; +} + +geBoolean DDRAWDisplay_GetDescriptionString(char *DescriptionString, unsigned int DescriptionStringMaxLength) +{ + DDRAWDisplay_DLLHooks DLL={NULL,0}; + + DDDEVICEIDENTIFIER DDDeviceIdentifier; + HRESULT hRet; + + assert( DescriptionString != NULL ); + + if (DDRAWDisplay_LoadDLL(&DLL)==GE_FALSE) + { + geErrorLog_AddString(-1,"unable to load ddraw dll",NULL); + goto GetDescriptionString_ERROR; + } + + memset(&DDDeviceIdentifier, 0, sizeof(DDDeviceIdentifier)); + + hRet =DLL.lpDD4->lpVtbl->GetDeviceIdentifier(DLL.lpDD4, &DDDeviceIdentifier,0); + + if(hRet != DD_OK) + { + geErrorLog_AddString(-1,"DDRAWDisplay_GetDescriptionString: ddraw GetDeviceIdentifier() failed", NULL); + goto GetDescriptionString_ERROR; + } + + DDRAWDisplay_UnloadDLL(&DLL); + if (strlen(DDDeviceIdentifier.szDescription) + strlen(DDRAWDISPLAY_DESCRIPTION_STRING) >= DescriptionStringMaxLength) + { + geErrorLog_AddString(-1,"DDRAWDisplay_GetDescriptionString: description string too short",NULL); + goto GetDescriptionString_ERROR; + } + + strcpy(DescriptionString,DDRAWDISPLAY_DESCRIPTION_STRING); + //strcat(DescriptionString,DDDeviceIdentifier.szDescription); + + return GE_TRUE; + + //------ + GetDescriptionString_ERROR: + DDRAWDisplay_UnloadDLL(&DLL); + return GE_FALSE; +} + + +geBoolean DDRAWDisplay_GetDisplayInfo( char *DescriptionString, + unsigned int DescriptionStringMaxLength, + DisplayModeInfo *Info) +{ + DDDEVICEIDENTIFIER DDDeviceIdentifier; + DDRAWDisplay_DLLHooks DLL={NULL,0}; + HRESULT ddrval = 0; + + assert( Info != NULL ); + + if (DDRAWDisplay_LoadDLL( &DLL )==GE_FALSE) + { + geErrorLog_AddString(-1,"failed to load DDRAW dll",NULL); + return GE_FALSE; + } + + #if 0 + { + //test for general dma support + DDCAPS ddcaps; + memset(&ddcaps, 0, sizeof(DDCAPS)); + ddcaps.dwSize =sizeof(ddcaps); + DLL.lpDD4->lpVtbl->GetCaps(DLL.lpDD4, &ddcaps, NULL); + + if(ddcaps.dwCaps & DDCAPS_CANBLTSYSMEM) + { + //System to video blits supported + if(ddcaps.dwSVBCaps & DDCAPS_BLTQUEUE) + { + D->bDMA =TRUE; // DMA Asynch System to Video blits supported + } + } + } + #endif + + + #if 0 // need this? + ddrval =DLL.lpDD4->lpVtbl->SetCooperativeLevel(DLL.lpDD4, ActiveWnd, + DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + if(ddrval != DD_OK) + { + geErrorLog_Add(-1,"Failed to set Cooperative Level",NULL); + goto GetDisplayInfo_ERROR; + } + #endif + + memset(&DDDeviceIdentifier, 0, sizeof(DDDeviceIdentifier)); + + ddrval =DLL.lpDD4->lpVtbl->GetDeviceIdentifier(DLL.lpDD4, &DDDeviceIdentifier,0); + + if(ddrval != DD_OK) + { + geErrorLog_AddString(-1,"ddraw GetDeviceIdentifier() failed", NULL); + goto GetDisplayInfo_ERROR; + } + + if (strlen(DDDeviceIdentifier.szDescription) + strlen(DDRAWDISPLAY_DESCRIPTION_STRING) >= DescriptionStringMaxLength) + { + geErrorLog_AddString(-1,"description string too short",NULL); + goto GetDisplayInfo_ERROR; + } + + strcpy(DescriptionString,DDRAWDISPLAY_DESCRIPTION_STRING); +// strcat(DescriptionString,DDDeviceIdentifier.szDescription); + + + DLL.lpDD4->lpVtbl->EnumDisplayModes(DLL.lpDD4, 0, NULL, (LPVOID)Info, DDRAWDisplay_ModeCallback); + + DDRAWDisplay_UnloadDLL(&DLL); + return GE_TRUE; + + GetDisplayInfo_ERROR: + DDRAWDisplay_UnloadDLL(&DLL); + return GE_FALSE; + +} + + diff --git a/G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.h b/G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.h new file mode 100644 index 0000000..748c4d1 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/DDRAWDisplay.h @@ -0,0 +1,75 @@ +/****************************************************************************************/ +/* DDRAWDisplay.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: display surface manager for full screen Direct Draw using a direct */ +/* draw surface for the the frame buffer */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DDRAWDISPLAY_H +#define DDRAWDISPLAY_H + + +#include "basetype.h" +#include "DisplayModeInfo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DDRAWDisplay DDRAWDisplay; + +void DDRAWDisplay_GetDisplayFormat( const DDRAWDisplay *D, + int32 *Width, + int32 *Height, + int32 *BitsPerPixel, + uint32 *Flags); + +geBoolean DDRAWDisplay_GetDisplayInfo( char *DescriptionString, + unsigned int DescriptionStringMaxLength, + DisplayModeInfo *Info); + +geBoolean DDRAWDisplay_GetPixelFormat( DDRAWDisplay *D, + //int32 *pixel_pitch, + int32 *bytes_per_pixel, + int32 *R_shift, + uint32 *R_mask, + int32 *R_width, + int32 *G_shift, + uint32 *G_mask, + int32 *G_width, + int32 *B_shift, + uint32 *B_mask, + int32 *B_width); + +geBoolean DDRAWDisplay_Lock( DDRAWDisplay *D,uint8 **Buffer, int32 *Pitch); +geBoolean DDRAWDisplay_Unlock( DDRAWDisplay *D); +geBoolean DDRAWDisplay_Blit( DDRAWDisplay *D); +geBoolean DDRAWDisplay_Wipe( DDRAWDisplay *D,uint32 color); +geBoolean DDRAWDisplay_SetActive( DDRAWDisplay *D, geBoolean Active); +void DDRAWDisplay_Destroy( DDRAWDisplay **D); + +#ifdef _INC_WINDOWS +DDRAWDisplay *DDRAWDisplay_Create( HWND hwnd, int Width, int Height, int BBP, uint32 Flags); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/G3D/Engine/Drivers/SoftDrv2/DIBDisplay.c b/G3D/Engine/Drivers/SoftDrv2/DIBDisplay.c new file mode 100644 index 0000000..98989cd --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/DIBDisplay.c @@ -0,0 +1,834 @@ +/****************************************************************************************/ +/* DIBDisplay.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: display surface manager for windows with a DIB as the frame buffer */ +/* Code fragments contributed by John Miles */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#define WIN32_LEAN_AND_MEAN +#pragma warning(disable : 4201 4214 4115) +#include +#pragma warning(default : 4201 4214 4115; disable : 4514) + +#include "DIBDisplay.h" +#include "CPUInfo.h" +#include +#include // vsprintf() +#include // malloc(),free() + + +#ifdef GENESIS_VERSION_2 +#include "errorlog.h" +#else +#define geErrorLog_AddString(Error,xx,yy) +#define geErrorLog_Add(Error,xx) +#endif + + +#define DIBDISPLAY_DESCRIPTION_STRING "Software (Window)" + +typedef struct +{ + uint32 r; + uint32 g; + uint32 b; + int32 alpha; +} +DIBDisplay_RGB32; + + + // data needed for DIB section (and some cached info about bitmasks +typedef struct +{ + uint32 DIB_R_bitmask; // DIB high-color pixel format + uint32 DIB_G_bitmask; + uint32 DIB_B_bitmask; + + BITMAPINFO *pbmi; // BITMAPINFO structure + HBITMAP hDIB; // Handle returned from CreateDIBSection + + uint8 *lpDIBBuffer; // DIB image buffer +} DIBDisplay_DIBInfo; + + + +typedef struct DIBDisplay +{ + HWND hWnd; // Handle to application window + geBoolean Locked; // is display 'locked' + int32 BitsPerPixel; // Mode info set by last call to + int32 Pitch; // (BitsPerPixel/8) * Size_X + int32 Size_X; // size of window rounded up to the nearest multiple of 4 + int32 Size_Y; + uint32 Flags; // display flags (currently unused) + DIBDisplay_DIBInfo DIBInfo; +} DIBDisplay; + + +void DIBDisplay_GetDisplayFormat( const DIBDisplay *D, + int32 *Width, + int32 *Height, + int32 *BitsPerPixel, + uint32 *Flags) +{ + assert( D != NULL ); + assert( Width != NULL ); + assert( Height != NULL ); + assert( BitsPerPixel != NULL ); + assert( Flags != NULL ); + + *Width = D->Size_X; + *Height = D->Size_Y; + *BitsPerPixel = D->BitsPerPixel; + *Flags = D->Flags; +} + + +geBoolean DIBDisplay_GetDisplayInfo( char *DescriptionString, + unsigned int DescriptionStringMaxLength, + DisplayModeInfo *Info) +{ + int BitsPerPixel; + + assert( Info != NULL ); + assert( DescriptionString != NULL ); + assert( DescriptionStringMaxLength > 0 ); + if (strlen(DIBDISPLAY_DESCRIPTION_STRING) >= DescriptionStringMaxLength) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER,"DIBDisplay_GetDescriptionString: description string too short",NULL); + return GE_FALSE; + } + + strcpy(DescriptionString,DIBDISPLAY_DESCRIPTION_STRING); + +// if ( CPUInfo_TestFor3DNow()==GE_TRUE) +// BitsPerPixel = 32; +// else + BitsPerPixel = 16; + + if (DisplayModeInfo_AddEntry(Info,-1,-1,BitsPerPixel,0)==GE_FALSE) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE,"DIBDisplay_GetDescriptionString: unable to add mode entry",NULL); + return GE_FALSE; + } + return GE_TRUE; +} + + +//------------------------------------------------ +static void DIBDisplay_DebugPrintf(char *fmt, ...) +{ + static char work_string[4096]; + + if ((fmt == NULL) || (strlen(fmt) > sizeof(work_string))) + { + strcpy(work_string, "(String missing or too large)"); + } + else + { + va_list ap; + + va_start(ap,fmt); + + vsprintf(work_string, fmt, ap); + + va_end (ap); + } + + #if 0 // log to file + { + FILE *log; + log = fopen("DEBUG.LOG","a+t"); + + if (log != NULL) + { + fprintf(log,"%s\n",work_string); + fclose(log); + } + } + #endif + + OutputDebugString(work_string); +} + + +//------------------------------------------------ +#ifndef NDEBUG +static geBoolean DIBDisplay_IsValid(const DIBDisplay *D) +{ + if (D == NULL) + return GE_FALSE; + + if (D->DIBInfo.pbmi == NULL) + return GE_FALSE; + if (D->DIBInfo.hDIB == NULL) + return GE_FALSE; + if (D->DIBInfo.lpDIBBuffer == NULL) + return GE_FALSE; + + return GE_TRUE; +} +#endif + + +//------------------------------------------------ +static geBoolean DIBDisplay_FindDesktopRGBMasks( HDC hdc, + int32 desktop_bpp, + uint32 *desktop_R_bitmask, + uint32 *desktop_G_bitmask, + uint32 *desktop_B_bitmask) +{ + assert( hdc != NULL ); + assert( desktop_R_bitmask != NULL ); + assert( desktop_G_bitmask != NULL ); + assert( desktop_B_bitmask != NULL ); + + if(desktop_bpp > 8) + { + COLORREF color,save; + HBITMAP TempBmp; + OSVERSIONINFO WinVer; + + memset(&WinVer, 0, sizeof(OSVERSIONINFO)); + WinVer.dwOSVersionInfoSize =sizeof(OSVERSIONINFO); + + GetVersionEx(&WinVer); + if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + TempBmp =CreateCompatibleBitmap(hdc, 8, 8); + if(TempBmp) + { + BITMAPINFO *TempInfo; + int HeaderSize = sizeof(BITMAPINFO) + sizeof(RGBQUAD)*2; + TempInfo = malloc(HeaderSize); + if (TempInfo == NULL) + { + geErrorLog_Add(DIBDisplay_FindDesktopRGBMasks,"Failed to allocate header for NT mask test"); + DeleteObject(TempBmp); + return GE_FALSE; + } + memset(TempInfo, 0, HeaderSize); + TempInfo->bmiHeader.biSize =sizeof(BITMAPINFO); + TempInfo->bmiHeader.biBitCount =(uint16)desktop_bpp; + TempInfo->bmiHeader.biCompression =BI_BITFIELDS; + if(GetDIBits(hdc, TempBmp, 0, 0, NULL, TempInfo, DIB_RGB_COLORS)) + { + *desktop_R_bitmask =*((uint32 *)&TempInfo->bmiColors[0]); + *desktop_G_bitmask =*((uint32 *)&TempInfo->bmiColors[1]); + *desktop_B_bitmask =*((uint32 *)&TempInfo->bmiColors[2]); + DIBDisplay_DebugPrintf("(%x-%x-%x)\n", *desktop_R_bitmask, *desktop_G_bitmask, *desktop_B_bitmask); + } + else + { + free(TempInfo); + DeleteObject(TempBmp); + geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to get bit format from desktop compatible bitmap",NULL); + return GE_FALSE; + } + free(TempInfo); + DeleteObject(TempBmp); + } + else + { + geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to create desktop compatible bitmap",NULL); + return GE_FALSE; + } + // detect failure (Win2000 only?) + if (((*desktop_R_bitmask | *desktop_G_bitmask | *desktop_B_bitmask)&0x7FFF) != 0x7FFF) + { + SetLastError(0); + geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: GetDIBits didn't return proper masking information.",NULL); + return GE_FALSE; + } + + } + else + { + HDC hdc2; + + hdc2 = CreateDC("Display", NULL, NULL,NULL); + if (hdc2==NULL) + { + geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to create compatible hdc",NULL); + return GE_FALSE; + } + + save = GetPixel(hdc2,0,0); + if ( save == CLR_INVALID ) + { + geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to get pixel from desktop",NULL); + DeleteDC(hdc2); + return GE_FALSE; + } + + + if (SetPixel(hdc2,0,0,RGB(0x08,0x08,0x08))==-1) + { + geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to select bitmap",NULL); + DeleteDC(hdc2); + return GE_FALSE; + } + + color = GetPixel(hdc2,0,0) & 0xffffff; + if ( color == CLR_INVALID ) + { + geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to get test pixel from desktop",NULL); + DeleteDC(hdc2); + return GE_FALSE; + } + + SetPixel(hdc,0,0,save); // ignore an error here. + DeleteDC(hdc2); + + DIBDisplay_DebugPrintf("DIBDisplay: Desktop pixel format = 0x%X ",color); + + + switch (color) + { + case 0x000000: // 0x000000 = 5-5-5 + DIBDisplay_DebugPrintf("(5-5-5)\n"); + + *desktop_R_bitmask = 0x007c00; + *desktop_G_bitmask = 0x0003e0; + *desktop_B_bitmask = 0x00001f; + break; + + case 0x000800: // 0x000800 = 5-6-5 + DIBDisplay_DebugPrintf("(5-6-5)\n"); + + *desktop_R_bitmask = 0x00f800; + *desktop_G_bitmask = 0x0007e0; + *desktop_B_bitmask = 0x00001f; + break; + + case 0x080808: // 0x080808 = 8-8-8 + DIBDisplay_DebugPrintf("(8-8-8)\n"); + + *desktop_R_bitmask = 0xff0000; + *desktop_G_bitmask = 0x00ff00; + *desktop_B_bitmask = 0x0000ff; + break; + + default: + DIBDisplay_DebugPrintf("(Unsupported, using 5-6-5)\n"); + + if ((desktop_bpp == 15) || (desktop_bpp == 16)) + { + *desktop_R_bitmask = 0x00f800; + *desktop_G_bitmask = 0x0007e0; + *desktop_B_bitmask = 0x00001f; + } + else + { + geErrorLog_AddString(GE_ERR_DISPLAY_RESOURCE,"DIBDisplay_FindDesktopRGBMasks: Unsupported desktop format.",NULL); + return GE_FALSE; + } + break; + } + + } + } + return GE_TRUE; +} + + + + +//------------------------------------------------ +static void DIBDisplay_DestroyDIB(DIBDisplay_DIBInfo *DI) +{ + assert( DI != NULL ); + + if (DI->pbmi != NULL) + { + free(DI->pbmi); + DI->pbmi = NULL; + } + + if (DI->hDIB != NULL) + { + DeleteObject(DI->hDIB); + DI->hDIB = NULL; + } +} + +//------------------------------------------------ +static geBoolean DIBDisplay_CreateDIB( + int32 display_size_X, + int32 display_size_Y, + int32 display_bpp, + HWND hWnd, + DIBDisplay_DIBInfo *DI) +{ + HDC hdc; + BITMAPINFOHEADER *pbmih; // Pointer to pbmi header + uint32 desktop_R_bitmask; // Desktop high-color pixel format + uint32 desktop_G_bitmask; + uint32 desktop_B_bitmask; + int32 desktop_bpp; // Windows video mode BPP + + assert( display_size_X > 0 ); + assert( display_size_Y > 0 ); + assert( (display_bpp == 16) || (display_bpp == 24)); + assert( DI != NULL ); + + DI->hDIB = NULL; + DI->lpDIBBuffer = NULL; + + DI->pbmi = (BITMAPINFO *) + malloc(sizeof (BITMAPINFOHEADER) + (sizeof (RGBQUAD) * 256)); + + if (DI->pbmi == NULL) + { + // geErrorLog_AddString("failed to allocate bitmap header",NULL); + return GE_FALSE; + } + + memset(DI->pbmi, 0, sizeof (BITMAPINFOHEADER) + (sizeof (RGBQUAD) * 256)); + + pbmih = &(DI->pbmi->bmiHeader); + + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biWidth = display_size_X; + pbmih->biHeight = -(display_size_Y); + pbmih->biPlanes = 1; + pbmih->biBitCount = (uint16) display_bpp; + pbmih->biSizeImage = 0; + pbmih->biXPelsPerMeter = 0; + pbmih->biYPelsPerMeter = 0; + pbmih->biClrUsed = 0; + pbmih->biClrImportant = 0; + + // + // Get Windows desktop display format (and masks, in high-color modes) + // + + hdc = GetDC(hWnd); + if ( hdc == NULL ) + { + // geErrorLog_AddString("unable to get desktop HDC"); + return GE_FALSE; + } + + desktop_bpp = GetDeviceCaps(hdc, BITSPIXEL) * + GetDeviceCaps(hdc, PLANES); + + DIBDisplay_DebugPrintf("DIBDisplay: Desktop %d BPP\n", desktop_bpp); + + if (DIBDisplay_FindDesktopRGBMasks( hdc, + desktop_bpp, + &desktop_R_bitmask, + &desktop_G_bitmask, + &desktop_B_bitmask)==GE_FALSE) + { + //geErrorLog_AddString("unable to determine desktop bit format"); + //ReleaseDC(hWnd, hdc); + //return GE_FALSE; + desktop_R_bitmask = 0x00f800; + desktop_G_bitmask = 0x0007e0; + desktop_B_bitmask = 0x00001f; + } + + + // + // If DIB and desktop are both in 15/16-BPP mode, set DIB to desktop + // pixel format for maximum throughput + // + // Otherwise, set DIB to 5-6-5 mode if 16BPP DIB requested, or 8-8-8 mode + // if 24BPP DIB requested + // + // Finally, if 8BPP DIB requested, create GDI palette object based on + // current logical palette + // + + switch (display_bpp) + { + case 16: + + pbmih->biCompression = BI_BITFIELDS; + + if ((desktop_bpp == 15) || (desktop_bpp == 16)) + { + DI->DIB_R_bitmask = desktop_R_bitmask; + DI->DIB_G_bitmask = desktop_G_bitmask; + DI->DIB_B_bitmask = desktop_B_bitmask; + } + else + { + DI->DIB_R_bitmask = 0x00f800; + DI->DIB_G_bitmask = 0x0007e0; + DI->DIB_B_bitmask = 0x00001f; + } + break; + + case 24: + + pbmih->biCompression = BI_BITFIELDS; + DI->DIB_R_bitmask = 0xff0000; + DI->DIB_G_bitmask = 0x00ff00; + DI->DIB_B_bitmask = 0x0000ff; + break; + } + + *(uint32 *) (&(DI->pbmi->bmiColors[0])) = DI->DIB_R_bitmask; + *(uint32 *) (&(DI->pbmi->bmiColors[1])) = DI->DIB_G_bitmask; + *(uint32 *) (&(DI->pbmi->bmiColors[2])) = DI->DIB_B_bitmask; + + + // + // Allocate the DIB section ("back buffer") + // + + DI->hDIB = CreateDIBSection(hdc, // Device context + DI->pbmi, // BITMAPINFO structure + DIB_RGB_COLORS, // Color data type + (void **) &(DI->lpDIBBuffer), // Address of image map pointer + NULL, // File + 0); // Bitmap file offset + + ReleaseDC(hWnd, hdc); + + if (DI->hDIB == NULL) + { + //geErrorLog_AddString("CreateDIBSection failed"); + return GE_FALSE; + } + + return GE_TRUE; + +} + +//------------------------------------------------ +geBoolean DIBDisplay_Blit(DIBDisplay *D) +{ + HDC hdc; + assert( DIBDisplay_IsValid(D) != GE_FALSE ); + + hdc = GetDC(D->hWnd); + if (hdc == NULL) + { + //geErrorLog_AddString("Unable to get HDC for blit"); + return GE_FALSE; + } + + #if 0 + if (desktop_bpp == 8) + { + // + // Select palette if desktop running in 8-bit mode + // + // If palette has changed, realize it + // + + //probably want to set up a halftone palette, and dither down into the 8 bbp desktop. + + SelectPalette( hdc, hPalette, 0); + + if (palette_change_request != GE_FALSE) + { + palette_change_request = GE_FALSE; + RealizePalette(hdc); + } + } + #endif + + + // + // Disable Boolean operations during stretching + // + + if (SetStretchBltMode(hdc, COLORONCOLOR)==0) + { + //geErrorLog_AddString("unable to set stretch blit mode"); + return GE_FALSE; + } + + StretchDIBits(hdc, // Destination DC + 0, // Destination X + 0, // Destination Y + D->Size_X, // Destination (client area) width + D->Size_Y, // Destination (client area) height + 0, // Source X + 0, // Source Y + D->Size_X, // Source (back buffer) width + D->Size_Y, // Source (back buffer) height + D->DIBInfo.lpDIBBuffer, // Pointer to source (back buffer) + D->DIBInfo.pbmi, // Bitmap info for back buffer + DIB_RGB_COLORS, // Bitmap contains index values + SRCCOPY); // Do normal copy with stretching + + ReleaseDC(D->hWnd, hdc); + return GE_TRUE; +} + + +//------------------------------------------------ +geBoolean DIBDisplay_Wipe ( DIBDisplay *D, + uint32 color) +{ + assert( DIBDisplay_IsValid(D) != GE_FALSE ); + if (!D->Locked) + { + //gegeErrorLog_AddString(Add(,"Display must be locked to clear",NULL); + return GE_FALSE; + } + + if (color==0) + memset(D->DIBInfo.lpDIBBuffer, color, D->Size_Y * D->Pitch); + else + { + int i; + int16 *Ptr = (int16 *)D->DIBInfo.lpDIBBuffer; + int16 C = (int16)color; + for (i=(D->Size_X * D->Size_Y); i>0; i--) + { + *(Ptr++) = C; + } + } + + return GE_TRUE; +} + + + +//------------------------------------------------ +DIBDisplay *DIBDisplay_Create ( HWND hWindow, + int Width, + int Height, + int display_bpp, + uint32 Flags ) +{ + DIBDisplay *D; + RECT window_rect; + BOOL result; + Flags; Width; Height; // avoid unused formal parameter warnings + + assert( display_bpp > 0); + + D= malloc(sizeof(*D)); + if (D==NULL) + { + // errlogAdd("failed to allocate DIBDisplay object"); + return NULL; + } + + + result = GetClientRect(hWindow, &window_rect); + + if( !result ) + { + //errlogAdd("failed to get client rect"); + return NULL; + } + assert ( window_rect.left == 0 ); + assert ( window_rect.top == 0 ); + + #pragma message ("getting size from window!") + D->Size_X = ((window_rect.right - window_rect.left)+3)&~3; + D->Size_Y = (window_rect.bottom - window_rect.top); + + if ( D->Size_X <=0 ) + { + //errlogAdd("bad window client width"); + return NULL; + } + if ( D->Size_Y <=0 ) + { + //errlogAdd("bad widndow client height"); + return NULL; + } + + D->Locked = GE_FALSE; + D->BitsPerPixel = display_bpp; + D->Pitch = (D->BitsPerPixel / 8 ) * D->Size_X; + D->hWnd = hWindow; + + D->DIBInfo.pbmi = NULL; + D->DIBInfo.hDIB = NULL; + D->DIBInfo.lpDIBBuffer = NULL; + + if (DIBDisplay_CreateDIB(D->Size_X, D->Size_Y, display_bpp, + hWindow, + &(D->DIBInfo)) ==GE_FALSE) + { + // errlogAdd("failed to create Dib section") + DIBDisplay_Destroy(&D); + return NULL; + } + + return D; +} + + +//------------------------------------------------ +void DIBDisplay_Destroy(DIBDisplay **pD) +{ + DIBDisplay *D; + + assert( *pD != NULL ); + assert( pD != NULL ); + + D = *pD; + + assert( DIBDisplay_IsValid(D) != GE_FALSE ); + + DIBDisplay_DestroyDIB(&(D->DIBInfo)); + free( D ); + + *pD = NULL; +} + + + +//------------------------------------------------ +geBoolean DIBDisplay_Lock (DIBDisplay *D, + uint8 **ptr, + int32 *pitch) +{ + assert( DIBDisplay_IsValid(D) != GE_FALSE ); + assert( ptr != NULL ); + assert( pitch != NULL ); + assert( D->Locked == GE_FALSE ); + + *ptr = D->DIBInfo.lpDIBBuffer; + *pitch = D->Pitch; + + D->Locked = GE_TRUE; + return GE_TRUE; +} + + +geBoolean DIBDisplay_Unlock (DIBDisplay *D) +{ + assert( DIBDisplay_IsValid(D) != GE_FALSE ); + assert( D->Locked == GE_TRUE ); + D->Locked = GE_FALSE; + return GE_TRUE; +} + + +//------------------------------------------------ +geBoolean DIBDisplay_GetPixelFormat( const DIBDisplay *D, + //int32 *pixel_pitch, + int32 *bytes_per_pixel, + int32 *R_shift, + uint32 *R_mask, + int32 *R_width, + int32 *G_shift, + uint32 *G_mask, + int32 *G_width, + int32 *B_shift, + uint32 *B_mask, + int32 *B_width) +{ + int32 red_shift=0; + uint32 red_mask; + int32 red_width=0; + int32 grn_shift=0; + uint32 grn_mask; + int32 grn_width=0; + int32 blu_shift=0; + uint32 blu_mask; + int32 blu_width=0; + int32 i; + + assert( DIBDisplay_IsValid(D) != GE_FALSE ); + + //assert( pixel_pitch != NULL ); + assert( bytes_per_pixel != NULL ); + assert( R_shift != NULL ); + assert( R_mask != NULL ); + assert( R_width != NULL ); + assert( G_shift != NULL ); + assert( G_mask != NULL ); + assert( G_width != NULL ); + assert( B_shift != NULL ); + assert( B_mask != NULL ); + assert( B_width != NULL ); + + + + //*pixel_pitch = (D->BitsPerPixel / 8); + *bytes_per_pixel = (D->BitsPerPixel / 8); + + red_mask = D->DIBInfo.DIB_R_bitmask; + grn_mask = D->DIBInfo.DIB_G_bitmask; + blu_mask = D->DIBInfo.DIB_B_bitmask; + + // + // Derive shift, width values from masks + // + + for (i=31; i >= 0; i--) + { + if (red_mask & (1 << i)) + { + red_shift = i; + } + + if (grn_mask & (1 << i)) + { + grn_shift = i; + } + + if (blu_mask & (1 << i)) + { + blu_shift = i; + } + } + + for (i=0; i <= 31; i++) + { + if (red_mask & (1 << i)) + { + red_width = i - red_shift + 1; + } + + if (grn_mask & (1 << i)) + { + grn_width = i - grn_shift + 1; + } + + if (blu_mask & (1 << i)) + { + blu_width = i - blu_shift + 1; + } + } + // + // Pass all requested values back to the caller + // + + *R_shift = red_shift; + *G_shift = grn_shift; + *B_shift = blu_shift; + + *R_mask = red_mask; + *G_mask = grn_mask; + *B_mask = blu_mask; + + *R_width = red_width; + *G_width = grn_width; + *B_width = blu_width; + + return GE_TRUE; +} + + + + diff --git a/G3D/Engine/Drivers/SoftDrv2/DIBDisplay.h b/G3D/Engine/Drivers/SoftDrv2/DIBDisplay.h new file mode 100644 index 0000000..719e184 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/DIBDisplay.h @@ -0,0 +1,89 @@ +/****************************************************************************************/ +/* DIBDisplay.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: display surface manager for windows with a DIB as the frame buffer */ +/* Code fragments contributed by John Miles */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + + +#ifndef DIBDisplay_H +#define DIBDisplay_H + +#include "basetype.h" +#include "DisplayModeInfo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DIBDisplay DIBDisplay; + +geBoolean DIBDisplay_GetDisplayInfo( char *DescriptionString, + unsigned int DescriptionStringMaxLength, + DisplayModeInfo *Info); + +void DIBDisplay_GetDisplayFormat( const DIBDisplay *D, + int32 *Width, + int32 *Height, + int32 *BitsPerPixel, + uint32 *Flags); + +geBoolean DIBDisplay_GetPixelFormat ( const DIBDisplay *D, + //int32 *pixel_pitch, + int32 *bytes_per_pixel, + int32 *R_shift, + uint32 *R_mask, + int32 *R_width, + int32 *G_shift, + uint32 *G_mask, + int32 *G_width, + int32 *B_shift, + uint32 *B_mask, + int32 *B_width); + + +geBoolean DIBDisplay_Blit ( DIBDisplay *D); + +geBoolean DIBDisplay_Wipe ( DIBDisplay *D, + uint32 color); + +geBoolean DIBDisplay_Lock ( DIBDisplay *D, + uint8 **ptr, + int32 *pitch); + +geBoolean DIBDisplay_Unlock ( DIBDisplay *D); + +void DIBDisplay_Destroy ( DIBDisplay **pDIBDisplay); + + + +#ifdef _INC_WINDOWS +DIBDisplay *DIBDisplay_Create ( HWND hWindow, + int Width, + int Height, + int display_bpp, + uint32 Flags); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.c b/G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.c new file mode 100644 index 0000000..5f996b2 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.c @@ -0,0 +1,128 @@ +/****************************************************************************************/ +/* DisplayModeInfo.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: This is a simple container to hold information about available display*/ +/* modes for the software driver. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include +#include "DisplayModeInfo.h" + +#ifdef GENESIS_VERSION_2 +#include "errorlog.h" +#else +#define geErrorLog_AddString(Error,xx,yy) +#endif + + +#define DISPLAYMODES_MAX 16 + +typedef struct DisplayModeInfo_Data +{ + int Width; + int Height; + int BitsPerPixel; + uint32 Flags; +} DisplayModeInfo_Data; + + +typedef struct DisplayModeInfo +{ + DisplayModeInfo_Data Mode[DISPLAYMODES_MAX]; + int ModeCount; +} DisplayModeInfo; + + +DisplayModeInfo *DisplayModeInfo_Create(void) +{ + DisplayModeInfo *Info; + + Info = malloc(sizeof(*Info)); + if (Info == NULL) + { + geErrorLog_AddString(GE_ERR_MEMORY_RESOURCE,"DisplayModeInfo: unable to get memory for object",NULL); + return NULL; + } + Info-> ModeCount = 0; + return Info; +} + +void DisplayModeInfo_Destroy(DisplayModeInfo **Info) +{ + assert ( Info != NULL ); + assert (*Info != NULL ); + free ( *Info ); + *Info = NULL; +} + +int DisplayModeInfo_GetModeCount(DisplayModeInfo *Info) +{ + assert( Info != NULL ); + + return Info->ModeCount; +} + +geBoolean DisplayModeInfo_AddEntry(DisplayModeInfo *Info, + int Width, + int Height, + int BitsPerPixel, + uint32 Flags) +{ + assert( Info != NULL ); + + if (Info->ModeCountMode[Info->ModeCount].Width = Width; + Info->Mode[Info->ModeCount].Height = Height; + Info->Mode[Info->ModeCount].BitsPerPixel = BitsPerPixel; + Info->Mode[Info->ModeCount].Flags = Flags; + Info->ModeCount++; + return GE_TRUE; + } + else + { + geErrorLog_AddString(GE_ERR_INTERNAL_RESOURCE,"GE_DisplayModeInfo_AddEntry:Too many modes",NULL); + return GE_FALSE; + } +} + +geBoolean DisplayModeInfo_GetNth(DisplayModeInfo *Info, int Nth, + int *Width, + int *Height, + int *BitsPerPixel, + uint32 *Flags) +{ + assert( Info != NULL ); + assert( Width != NULL ); + assert( Height != NULL ); + assert( BitsPerPixel != NULL ); + assert( Flags != NULL ); + if ((Nth < 0) || (Nth > Info->ModeCount)) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER,"DisplayModeInfo_GetNth: bad mode index",geErrorLog_IntToString(Nth)); + return GE_FALSE; + } + + *Width = Info->Mode[Nth].Width; + *Height = Info->Mode[Nth].Height; + *BitsPerPixel = Info->Mode[Nth].BitsPerPixel; + *Flags = Info->Mode[Nth].Flags; + return GE_TRUE; +} + diff --git a/G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.h b/G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.h new file mode 100644 index 0000000..d9fedba --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/DisplayModeInfo.h @@ -0,0 +1,76 @@ +/****************************************************************************************/ +/* DisplayModeInfo.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: This is a simple container to hold information about available display*/ +/* modes for the software driver. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#ifndef DisplayModeInfo_H +#define DisplayModeInfo_H + +#include "basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +enum DisplayModeInfo_Flags +{ + SYSTEM =1, //store buffer in system + VIDEO =2, //or video ram + HARDWARE =4, //refresh choices + DMABLT =8, + FASTBLT =16, + SAFEBLT =32, + FLIP =64, + DMAPAGELOCKREQUIRED =128,//pagelock for dma req + DMAASYNCH =256,//can do asynch dma + STRETCHMODE =512,//stretch to fit + MODEXMODE =1024 +}; + +typedef struct DisplayModeInfo DisplayModeInfo; + +DisplayModeInfo * DisplayModeInfo_Create( void ); + +void DisplayModeInfo_Destroy( DisplayModeInfo **Info ); + +int DisplayModeInfo_GetModeCount( DisplayModeInfo *Info); + +geBoolean DisplayModeInfo_AddEntry( DisplayModeInfo *Info, + int Width, + int Height, + int BitsPerPixel, + uint32 Flags ); + +geBoolean DisplayModeInfo_GetNth( DisplayModeInfo *Info, + int Nth, + int *Width, + int *Height, + int *BitsPerPixel, + uint32 *Flags); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/G3D/Engine/Drivers/SoftDrv2/DrawDecal.c b/G3D/Engine/Drivers/SoftDrv2/DrawDecal.c new file mode 100644 index 0000000..d8a5a52 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/DrawDecal.c @@ -0,0 +1,310 @@ +/****************************************************************************************/ +/* DrawDecal.H */ +/* */ +/* Author: Ken Baird, Mike Sandige */ +/* Description: This is a simple 2d blitter for the Genesis3d software driver. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include "DrawDecal.h" +#include "SoftDrv.h" + +static int32 BWidth, BHeight, BStride; +static int32 DrawWidth, DrawHeight; +static int32 EbpAdd, EdiAdd; +static uint16 *BBitPtr16; +static uint8 *BBitPtr; +static uint16 *pScrPtr16bpp; +static uint32 *pScrPtr32bpp; + +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) +{ + + if(!SD_Active) + { + return GE_TRUE; + } + + BWidth =THandle->Width; + BHeight =THandle->Height; + DrawWidth =THandle->Width; + DrawHeight =THandle->Height; + + #if 0 + if(SD_ProcessorHas3DNow ) + { + U32 *PalPtr; + BBitPtr =(U8 *)THandle->BitPtr[0]; + + if ( ! THandle->PalHandle ) + return 0; + + PalPtr =(U32 *)THandle->PalHandle->BitPtr[0]; + + if(SRect) + { + BBitPtr +=SRect->top * DrawWidth + SRect->left; + DrawHeight =(SRect->bottom - SRect->top); + DrawWidth =(SRect->right - SRect->left); + } + + if(x < 0) + { + if(x + DrawWidth <= 0) + { + return GE_TRUE; + } + BBitPtr -=x; + DrawWidth +=x; + x =0; + } + + if(y < 0) + { + if(y + DrawHeight <= 0) + { + return GE_TRUE; + } + BBitPtr -=y * BWidth; + DrawHeight +=y; + y =0; + } + + if(x >= ClientWindow.Width) + { + return GE_TRUE; + } + if(y >= ClientWindow.Height) + { + return GE_TRUE; + } + + if(x + DrawWidth >= (ClientWindow.Width-1)) + DrawWidth -= (x+DrawWidth) - (ClientWindow.Width-1); + + if(y + DrawHeight >= (ClientWindow.Height-1)) + DrawHeight -= (y+DrawHeight)- (ClientWindow.Height-1); + + if(DrawWidth <= 0) + return GE_TRUE; + + if(DrawHeight <= 0) + return GE_TRUE; + + pScrPtr32bpp =(U32 *)(ClientWindow.Buffer); + pScrPtr32bpp =&pScrPtr32bpp[y * ClientWindow.Width + x]; + + __asm + { + push ecx + push esi + push edi + push ebp + + mov ebx,PalPtr + + mov ebp, pScrPtr32bpp + mov edi, BBitPtr + + mov ecx, DrawWidth + + mov edx, ClientWindow.PixelPitch + shl ecx,2 + sub edx, ecx + mov EbpAdd, edx + + mov edx, BWidth + mov ecx, DrawHeight + sub edx, DrawWidth + mov EdiAdd, edx + + + NextHeight: + + push ecx + mov ecx, DrawWidth + + lea ebp,[4*ecx+ebp] + + add edi, ecx +// shl ecx, 2 +// add ebp, ecx + + neg ecx + + NextWidth: + xor eax,eax + mov al, [edi+ecx] + + cmp al,0ffh + je Skip + +// cmp al,01h +// je Skip + + mov eax,[ebx+eax*4] + + mov [ebp+ecx*4], eax + + Skip: + inc ecx + jnz NextWidth + + add ebp, EbpAdd + add edi, EdiAdd + + pop ecx + + sub ecx, 1 + jnz NextHeight + + pop ebp + pop edi + pop esi + pop ecx + } + } + else + #endif + { + BBitPtr16 =THandle->BitPtr[0]; + if(SRect) + { + BBitPtr16 +=SRect->top * DrawWidth + SRect->left; + DrawHeight =(SRect->bottom - SRect->top); + DrawWidth =(SRect->right - SRect->left); + } + + if(x < 0) + { + if(x + DrawWidth <= 0) + { + return GE_TRUE; + } + BBitPtr16 -=x; + DrawWidth +=x; + x =0; + } + + if(y < 0) + { + if(y + DrawHeight <= 0) + { + return GE_TRUE; + } + BBitPtr16 -=y*BWidth; + DrawHeight +=y; + y =0; + } + + if(x >= ClientWindow.Width) + { + return GE_TRUE; + } + if(y >= ClientWindow.Height) + { + return GE_TRUE; + } + + if(x + DrawWidth >= (ClientWindow.Width - 1)) + { + DrawWidth -=(x + DrawWidth) - (ClientWindow.Width - 1); + } + if(y + DrawHeight >= (ClientWindow.Height - 1)) + { + DrawHeight -=(y + DrawHeight) - (ClientWindow.Height - 1); + } + + if(DrawWidth <= 0) + { + return GE_TRUE; + } + if(DrawHeight <= 0) + { + return GE_TRUE; + } + + pScrPtr16bpp =(U16 *)(ClientWindow.Buffer); + pScrPtr16bpp =&pScrPtr16bpp[y * (ClientWindow.PixelPitch >> 1) + x]; + + __asm + { + push ecx + push esi + push edi + push ebp + + mov ebp, pScrPtr16bpp + mov edi, BBitPtr16 + + mov ecx, DrawWidth + + mov edx, ClientWindow.PixelPitch + sub edx, ecx + sub edx, ecx + mov EbpAdd, edx + + mov edx, BWidth + add edx, BWidth + sub edx, ecx + sub edx, ecx + mov EdiAdd, edx + + mov ecx, DrawHeight + + NextHeightA: + + push ecx + mov ecx, DrawWidth + + shl ecx, 1 + add ebp, ecx + add edi, ecx + + neg ecx + + NextWidthA: + mov ax, [edi+ecx] + + cmp ax, 0x1 + je SkipA + + mov [ebp+ecx], ax + + SkipA: + add ecx, 2 + jnz NextWidthA + + add ebp, EbpAdd + add edi, EdiAdd + + pop ecx + + sub ecx, 1 + jnz NextHeightA + + pop ebp + pop edi + pop esi + pop ecx + } + } + return GE_TRUE; +} + + + diff --git a/G3D/Engine/Drivers/SoftDrv2/DrawDecal.h b/G3D/Engine/Drivers/SoftDrv2/DrawDecal.h new file mode 100644 index 0000000..18fbc95 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/DrawDecal.h @@ -0,0 +1,40 @@ +/****************************************************************************************/ +/* DrawDecal.H */ +/* */ +/* Author: Ken Baird, Mike Sandige */ +/* Description: This is a simple 2d blitter for the Genesis3d software driver. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef DRAWDECAL +#define DRAWDECAL + +#include "SWTHandle.h" // geRDriver_THandle, RECT. + +#ifdef __cplusplus +extern "C" { +#endif + + +geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y); + + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv2/SWTHandle.c b/G3D/Engine/Drivers/SoftDrv2/SWTHandle.c new file mode 100644 index 0000000..bf78474 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/SWTHandle.c @@ -0,0 +1,483 @@ +/****************************************************************************************/ +/* SWTHandle.C */ +/* */ +/* Author: Mike Sandige, John Pollard */ +/* Description: Manager for texture construction and available texture formats for */ +/* the software driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +#include // malloc, free +#include // memset +#include + +#include "SoftDrv.h" // SD_Display, ClientWindow. Could be cleaned up. +#include "SWTHandle.h" + +#ifdef GENESIS_VERSION_2 +#include "errorlog.h" +#else +#define geErrorLog_AddString(Error,xx,yy) +#endif + + +#define MAX_TEXTURE_HANDLES 15000 + +geRDriver_THandle SWTHandle_TextureHandles[MAX_TEXTURE_HANDLES]; + +static int32 SWTHandle_SnapToPower2(int32 Width) +{ + if (Width > 1 && Width <= 2) Width = 2; + else if (Width > 2 && Width <= 4) Width = 4; + else if (Width > 4 && Width <= 8) Width = 8; + else if (Width > 8 && Width <= 16) Width =16; + else if (Width > 16 && Width <= 32) Width = 32; + else if (Width > 32 && Width <= 64) Width = 64; + else if (Width > 64 && Width <= 128) Width = 128; + else if (Width > 128 && Width <= 256) Width = 256; + + return Width; +} + + +//======================================================================================== +// SWTHandle_FindTextureHandle +//======================================================================================== +static geRDriver_THandle *SWTHandle_FindTextureHandle() +{ + int32 i; + geRDriver_THandle *THandle; + + THandle = SWTHandle_TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, THandle++) + { + if (!THandle->Active) + { + memset(THandle, 0, sizeof(geRDriver_THandle)); + + THandle->Active = GE_TRUE; + + return THandle; + } + } + + return NULL; +} + +//======================================================================================== +// SWTHandle_FreeTextureHandle +//======================================================================================== +static geBoolean SWTHandle_FreeTextureHandle(geRDriver_THandle *THandle) +{ + int k; + + assert(THandle); + //<> assert(THandle->Active == GE_TRUE); + + if( ! THandle->Active ) + { + return GE_FALSE; + } + + if(THandle->PalHandle) + { + SWTHandle_FreeTextureHandle(THandle->PalHandle); + } + + if(THandle->AlphaHandle) + { + SWTHandle_FreeTextureHandle(THandle->AlphaHandle); + } + + for(k=0;k < THandle->MipLevels;k++) + { + if(THandle->BitPtr[k]) + { + free(THandle->BitPtr[k]); + } + THandle->BitPtr[k] =NULL; + } + + memset(THandle, 0, sizeof(geRDriver_THandle)); + + return GE_TRUE; +} + +//================================================================================== +// SWTHandle_FreeAllTextureHandles +//================================================================================== +geBoolean SWTHandle_FreeAllTextureHandles(void) +{ + int32 i; + geRDriver_THandle *pTHandle; + + pTHandle = SWTHandle_TextureHandles; + + for (i=0; i< MAX_TEXTURE_HANDLES; i++, pTHandle++) + { + if (!pTHandle->Active) + { + continue; + } + + SWTHandle_FreeTextureHandle(pTHandle); + } + + return GE_TRUE; +} + +geRDriver_THandle *DRIVERCC SWTHandle_CreateTexture(int32 Width, + int32 Height, + int32 NumMipLevels, + const geRDriver_PixelFormat *PixelFormat) +{ + int32 i, SWidth, SHeight; // Snapped to power of 2 width/height + geRDriver_THandle *THandle; + + assert(PixelFormat); + + THandle = SWTHandle_FindTextureHandle(); + + if (!THandle) + { + geErrorLog_AddString(GE_ERR_INTERNAL_RESOURCE, "SWTHandle_CreateTexture: No more handles left.",NULL); + goto ExitWithError; + } + + if(PixelFormat->Flags & RDRIVER_PF_3D) + { + if (Width > 256) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Width > 256.",NULL); + goto ExitWithError; + } + + if (Height > 256) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Height > 256.",NULL); + goto ExitWithError; + } + SWidth = SWTHandle_SnapToPower2(Width); + SHeight = SWTHandle_SnapToPower2(Height); + + if (Width != SWidth) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Not a power of 2.",NULL); + goto ExitWithError; + } + + if (Height != SHeight) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Not a power of 2.",NULL); + goto ExitWithError; + } + } + + THandle->MipLevels =NumMipLevels; + THandle->Width =Width; + THandle->Height =Height; + THandle->PixelFormat =*PixelFormat; + + for(i=0;i < NumMipLevels;i++) + { + if(PixelFormat->Flags & RDRIVER_PF_PALETTE) + { + + if( PixelFormat->PixelFormat == GE_PIXELFORMAT_32BIT_XRGB || + PixelFormat->PixelFormat == GE_PIXELFORMAT_32BIT_XBGR) + { + THandle->BitPtr[i] =(uint16 *)malloc(sizeof(U32) * Width * Height); + } + else + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_CreateTexture: Bad Pal format.",NULL); + goto ExitWithError; + } + } + else + { + switch (PixelFormat->PixelFormat) + { + case GE_PIXELFORMAT_16BIT_4444_ARGB: + { + THandle->BitPtr[i] =(uint16 *)malloc(sizeof(uint16) * Width * Height); + break; + } + + case GE_PIXELFORMAT_16BIT_565_RGB: + { + THandle->BitPtr[i] =(uint16 *)malloc(sizeof(uint16) * Width * Height); + break; + } + + case GE_PIXELFORMAT_16BIT_555_RGB: + { + THandle->BitPtr[i] =(uint16 *)malloc(sizeof(uint16) * Width * Height); + break; + } + + case GE_PIXELFORMAT_8BIT: + { + THandle->BitPtr[i] =(uint16 *)malloc(sizeof(uint8) * Width * Height); + break; + } + + case GE_PIXELFORMAT_24BIT_RGB: + { + THandle->BitPtr[i] =(uint16 *)malloc((sizeof(uint8)*3) * Width * Height); + break; + } + + default: + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SOFT_Create3DTexture: Invalid pixel format.",NULL); + goto ExitWithError; + } + } + + if ( PixelFormat->Flags & RDRIVER_PF_CAN_DO_COLORKEY ) + { + THandle->Flags |= THANDLE_TRANS; + } + + } + Width = Width / 2; + if (Width < 1) Width = 1; + Height = Height / 2; + if (Height < 1) Height = 1; + } + + return THandle; + + ExitWithError: + { + return NULL; + } +} + +geBoolean DRIVERCC SWTHandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info) +{ + assert(THandle); + assert(Info); + if ( ! THandle->Active ) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_GetInfo: Bad Texture Handle.",NULL); + return GE_FALSE; + } + + + Info->Width = THandle->Width >> MipLevel; + Info->Height = THandle->Height >> MipLevel; + Info->Stride = THandle->Width >> MipLevel; + Info->ColorKey = 1; + Info->Flags = GE_FALSE; + #pragma message ("is this right?") + Info->PixelFormat = THandle->PixelFormat; + if ( THandle->Flags & THANDLE_TRANS ) + { + #pragma message ("remember this") + Info->Flags = RDRIVER_THANDLE_HAS_COLORKEY; + } + return GE_TRUE; +} + +//can be used to null out the pal (cant assert on palhandle) +geBoolean DRIVERCC SWTHandle_SetPalette(geRDriver_THandle *THandle, geRDriver_THandle *PalHandle) +{ + assert(THandle); + + THandle->PalHandle =PalHandle; + + return GE_TRUE; +} + +//can be used to null out the pal (cant assert on palhandle) +geRDriver_THandle *DRIVERCC SWTHandle_GetPalette(geRDriver_THandle *THandle) +{ + assert(THandle); + if ( ! THandle->Active ) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_GetPalette: Bad Texture Handle.",NULL); + return GE_FALSE; + } + + return THandle->PalHandle; +} + +geBoolean DRIVERCC SWTHandle_SetAlpha(geRDriver_THandle *THandle, geRDriver_THandle *AHandle) +{ + assert(THandle); + if ( ! THandle->Active ) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_SetAlpha: Bad Texture Handle.",NULL); + return GE_FALSE; + } + + if(THandle->PixelFormat.Flags & RDRIVER_PF_HAS_ALPHA) + { + if(AHandle->PixelFormat.Flags & RDRIVER_PF_ALPHA) + { + THandle->AlphaHandle =AHandle; + return GE_TRUE; + } + } + return GE_FALSE; +} + +geRDriver_THandle *DRIVERCC SWTHandle_GetAlpha(geRDriver_THandle *THandle) +{ + assert(THandle); + if ( ! THandle->Active ) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_GetAlpha: Bad Texture Handle.",NULL); + return GE_FALSE; + } + + return THandle->AlphaHandle; +} + +geBoolean DRIVERCC SWTHandle_DestroyTexture(geRDriver_THandle *THandle) +{ + return SWTHandle_FreeTextureHandle(THandle); +} + +geBoolean DRIVERCC SWTHandle_LockTextureHandle(geRDriver_THandle *THandle, int32 MipLevel, void **Data) +{ + assert(THandle); + assert(MipLevel <= THandle->MipLevels && MipLevel >= 0); + if ( ! THandle->Active ) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_LockTextureHandle: Bad Texture Handle.",NULL); + return GE_FALSE; + } + if ( ! THandle->BitPtr[MipLevel] ) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_LockTextureHandle: Bad Texture Handle in Mip.",NULL); + return GE_FALSE; + } + + THandle->Flags |=(THANDLE_LOCKED << MipLevel); + *Data =(uint16*)THandle->BitPtr[MipLevel]; + + return GE_TRUE; +} + +geBoolean DRIVERCC SWTHandle_UnLockTextureHandle(geRDriver_THandle *THandle, int32 MipLevel) +{ + assert(THandle); + if (!(THandle->Flags & (THANDLE_LOCKED << MipLevel))) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER, "SWTHandle_UnLockTextureHandle: Texture Handle is not Locked.",NULL); + return GE_FALSE; + } + + + THandle->Flags &=~(THANDLE_LOCKED << MipLevel); // This mip is now unlocked + THandle->Flags |=THANDLE_UPDATE; // Mark it for updating... + + return GE_TRUE; +} + + + + +geBoolean DRIVERCC SWTHandle_EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context) +{ + geRDriver_PixelFormat PixelFormat; + + if(!SD_Display) + { + geErrorLog_AddString(GE_ERR_INTERNAL_RESOURCE, "SWTHandle_EnumPixelFormats: No Mode Set.",NULL); + return GE_FALSE; + } + + + PixelFormat.PixelFormat = GE_PIXELFORMAT_8BIT; + PixelFormat.Flags = RDRIVER_PF_3D; + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + PixelFormat.PixelFormat = GE_PIXELFORMAT_8BIT; + PixelFormat.Flags = RDRIVER_PF_3D| RDRIVER_PF_COMBINE_LIGHTMAP; + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + + PixelFormat.PixelFormat = GE_PIXELFORMAT_16BIT_4444_ARGB; + PixelFormat.Flags = RDRIVER_PF_3D; + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + PixelFormat.PixelFormat = GE_PIXELFORMAT_16BIT_4444_ARGB; + PixelFormat.Flags = RDRIVER_PF_3D | RDRIVER_PF_COMBINE_LIGHTMAP; + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + + PixelFormat.PixelFormat = GE_PIXELFORMAT_32BIT_XBGR; + PixelFormat.Flags = RDRIVER_PF_PALETTE; + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + + if(ClientWindow.G_mask == 0x3e0) //555 + { + PixelFormat.PixelFormat = GE_PIXELFORMAT_16BIT_555_RGB; + PixelFormat.Flags = RDRIVER_PF_2D; + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + PixelFormat.PixelFormat = GE_PIXELFORMAT_16BIT_555_RGB; + PixelFormat.Flags = RDRIVER_PF_2D| RDRIVER_PF_CAN_DO_COLORKEY; + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + } + else + { + PixelFormat.PixelFormat = GE_PIXELFORMAT_16BIT_565_RGB; + PixelFormat.Flags = RDRIVER_PF_2D; + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + PixelFormat.PixelFormat = GE_PIXELFORMAT_16BIT_565_RGB; + PixelFormat.Flags = RDRIVER_PF_2D| RDRIVER_PF_CAN_DO_COLORKEY; + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + } + + PixelFormat.PixelFormat = GE_PIXELFORMAT_24BIT_RGB; + PixelFormat.Flags = RDRIVER_PF_LIGHTMAP; + + if(!Cb(&PixelFormat, Context)) + { + return GE_TRUE; + } + + return GE_TRUE; +} \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv2/SWTHandle.h b/G3D/Engine/Drivers/SoftDrv2/SWTHandle.h new file mode 100644 index 0000000..b3ae7a5 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/SWTHandle.h @@ -0,0 +1,59 @@ +/****************************************************************************************/ +/* SWTHandle.H */ +/* */ +/* Author: Mike Sandige, John Pollard */ +/* Description: Manager for texture construction and available texture formats for */ +/* the software driver */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SWTHANDLE_H +#define SWTHANDLE_H + +#include "DCommon.h" +#include "PixelFormat.h" + +// THandle flags +#define THANDLE_UPDATE (1<<0) // Force a thandle to be uploaded to the card +#define THANDLE_TRANS (1<<2) // Texture has transparency +#define THANDLE_LOCKED (1<<3) // THandle is currently locked (invalid for rendering etc) + +typedef struct geRDriver_THandle +{ + int32 Active, Width, Height, MipLevels; + geRDriver_PixelFormat PixelFormat; + uint16 *BitPtr[16];//8 or 16 + geRDriver_THandle *PalHandle; + geRDriver_THandle *AlphaHandle; + + uint32 Flags; +} geRDriver_THandle; + +geBoolean DRIVERCC SWTHandle_EnumPixelFormats(DRV_ENUM_PFORMAT_CB *Cb, void *Context); +geBoolean SWTHandle_FreeAllTextureHandles(void); +geRDriver_THandle *DRIVERCC SWTHandle_CreateTexture(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat); +geBoolean DRIVERCC SWTHandle_DestroyTexture(geRDriver_THandle *THandle); + +geBoolean DRIVERCC SWTHandle_LockTextureHandle(geRDriver_THandle *THandle, int32 MipLevel, void **Data); +geBoolean DRIVERCC SWTHandle_UnLockTextureHandle(geRDriver_THandle *THandle, int32 MipLevel); +geBoolean DRIVERCC SWTHandle_GetInfo(geRDriver_THandle *THandle, int32 MipLevel, geRDriver_THandleInfo *Info); + +geBoolean DRIVERCC SWTHandle_SetPalette(geRDriver_THandle *THandle, geRDriver_THandle *PalHandle); +geRDriver_THandle *DRIVERCC SWTHandle_GetPalette(geRDriver_THandle *THandle); +geBoolean DRIVERCC SWTHandle_SetAlpha(geRDriver_THandle *THandle, geRDriver_THandle *PalHandle); +geRDriver_THandle *DRIVERCC SWTHandle_GetAlpha(geRDriver_THandle *THandle); + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv2/SoftDrv2.dsp b/G3D/Engine/Drivers/SoftDrv2/SoftDrv2.dsp new file mode 100644 index 0000000..bb3d37f --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/SoftDrv2.dsp @@ -0,0 +1,297 @@ +# Microsoft Developer Studio Project File - Name="SoftDrv2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=SoftDrv2 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SoftDrv2.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SoftDrv2.mak" CFG="SoftDrv2 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SoftDrv2 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "SoftDrv2 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Source/Engine/Drivers/SoftDrv2", QADCAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SoftDrv2 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV2_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /X /I "..\\" /I "..\..\..\\" /I "..\..\..\support" /I "..\..\..\math" /I "..\..\..\bitmap" /I "..\..\..\..\msdev60\include" /I "..\..\..\..\sdk\dx6sdk\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV2_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /x /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /machine:I386 /nodefaultlib /out:".\Release\Softdrv.dll" + +!ELSEIF "$(CFG)" == "SoftDrv2 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV2_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /X /I "..\\" /I "..\..\..\\" /I "..\..\..\support" /I "..\..\..\math" /I "..\..\..\bitmap" /I "..\..\..\..\msdev60\include" /I "..\..\..\..\sdk\dx6sdk\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV2_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /x /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /debug /machine:I386 /nodefaultlib /out:".\Debug\Softdrv.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "SoftDrv2 - Win32 Release" +# Name "SoftDrv2 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\CPUInfo.c +# End Source File +# Begin Source File + +SOURCE=.\DDRAWDisplay.c +# End Source File +# Begin Source File + +SOURCE=.\DIBDisplay.c +# End Source File +# Begin Source File + +SOURCE=.\display.c +# End Source File +# Begin Source File + +SOURCE=.\DisplayModeInfo.c +# End Source File +# Begin Source File + +SOURCE=.\DrawDecal.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Support\Ram.c +# End Source File +# Begin Source File + +SOURCE=.\softdrv.c +# End Source File +# Begin Source File + +SOURCE=.\span.c +# End Source File +# Begin Source File + +SOURCE=.\SpanBuffer.c +# End Source File +# Begin Source File + +SOURCE=.\SWTHandle.c +# End Source File +# Begin Source File + +SOURCE=.\TRaster.c +# End Source File +# Begin Source File + +SOURCE=.\Triangle.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\CPUInfo.h +# End Source File +# Begin Source File + +SOURCE=.\DDRAWDisplay.h +# End Source File +# Begin Source File + +SOURCE=.\DIBDisplay.h +# End Source File +# Begin Source File + +SOURCE=.\display.h +# End Source File +# Begin Source File + +SOURCE=.\DisplayModeInfo.h +# End Source File +# Begin Source File + +SOURCE=.\DrawDecal.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Support\Ram.h +# End Source File +# Begin Source File + +SOURCE=.\rop.h +# End Source File +# Begin Source File + +SOURCE=.\Softdrv.h +# End Source File +# Begin Source File + +SOURCE=.\Span.h +# End Source File +# Begin Source File + +SOURCE=.\Span_AffineLoop.h +# End Source File +# Begin Source File + +SOURCE=.\Span_Factory.h +# End Source File +# Begin Source File + +SOURCE=.\SpanBuffer.h +# End Source File +# Begin Source File + +SOURCE=.\SpanEdges_Factory.h +# End Source File +# Begin Source File + +SOURCE=.\SWTHandle.h +# End Source File +# Begin Source File + +SOURCE=.\traster.h +# End Source File +# Begin Source File + +SOURCE=.\triangle.h +# End Source File +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Winmm.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Comdlg32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Gdi32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Kernel32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Libcmt.lib + +!IF "$(CFG)" == "SoftDrv2 - Win32 Release" + +!ELSEIF "$(CFG)" == "SoftDrv2 - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Libcmtd.lib + +!IF "$(CFG)" == "SoftDrv2 - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "SoftDrv2 - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Oldnames.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Shell32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\User32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Uuid.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Advapi32.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\MSDev60\lib\Winspool.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\Sdk\Dx6sdk\Lib\dxguid.lib +# End Source File +# End Group +# Begin Source File + +SOURCE=.\SoftDrv2.mak +# End Source File +# End Target +# End Project diff --git a/G3D/Engine/Drivers/SoftDrv2/SoftDrv2.mak b/G3D/Engine/Drivers/SoftDrv2/SoftDrv2.mak new file mode 100644 index 0000000..6de566c --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/SoftDrv2.mak @@ -0,0 +1,292 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on SoftDrv2.dsp +!IF "$(CFG)" == "" +CFG=SoftDrv2 - Win32 Debug +!MESSAGE No configuration specified. Defaulting to SoftDrv2 - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "SoftDrv2 - Win32 Release" && "$(CFG)" != "SoftDrv2 - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SoftDrv2.mak" CFG="SoftDrv2 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SoftDrv2 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "SoftDrv2 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SoftDrv2 - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +ALL : "$(OUTDIR)\Softdrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\CPUInfo.obj" + -@erase "$(INTDIR)\DDRAWDisplay.obj" + -@erase "$(INTDIR)\DIBDisplay.obj" + -@erase "$(INTDIR)\display.obj" + -@erase "$(INTDIR)\DisplayModeInfo.obj" + -@erase "$(INTDIR)\DrawDecal.obj" + -@erase "$(INTDIR)\Ram.obj" + -@erase "$(INTDIR)\softdrv.obj" + -@erase "$(INTDIR)\span.obj" + -@erase "$(INTDIR)\SpanBuffer.obj" + -@erase "$(INTDIR)\SWTHandle.obj" + -@erase "$(INTDIR)\TRaster.obj" + -@erase "$(INTDIR)\Triangle.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\Softdrv.dll" + -@erase "$(OUTDIR)\Softdrv.exp" + -@erase "$(OUTDIR)\Softdrv.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MT /W3 /GX /O2 /X /I "..\\" /I "..\..\..\\" /I "..\..\..\support" /I "..\..\..\math" /I "..\..\..\bitmap" /I "..\..\..\..\msdev60\include" /I "..\..\..\..\sdk\dx6sdk\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV2_EXPORTS" /Fp"$(INTDIR)\SoftDrv2.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\SoftDrv2.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\Softdrv.pdb" /machine:I386 /nodefaultlib /out:"$(OUTDIR)\Softdrv.dll" /implib:"$(OUTDIR)\Softdrv.lib" +LINK32_OBJS= \ + "$(INTDIR)\CPUInfo.obj" \ + "$(INTDIR)\DDRAWDisplay.obj" \ + "$(INTDIR)\DIBDisplay.obj" \ + "$(INTDIR)\display.obj" \ + "$(INTDIR)\DisplayModeInfo.obj" \ + "$(INTDIR)\DrawDecal.obj" \ + "$(INTDIR)\Ram.obj" \ + "$(INTDIR)\softdrv.obj" \ + "$(INTDIR)\span.obj" \ + "$(INTDIR)\SpanBuffer.obj" \ + "$(INTDIR)\SWTHandle.obj" \ + "$(INTDIR)\TRaster.obj" \ + "$(INTDIR)\Triangle.obj" \ + "..\..\..\..\MSDev60\lib\Winmm.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmt.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\MSDev60\lib\Winspool.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\dxguid.lib" + +"$(OUTDIR)\Softdrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "SoftDrv2 - Win32 Debug" + +OUTDIR=. +INTDIR=.\Debug +# Begin Custom Macros +OutDir=. +# End Custom Macros + +ALL : "$(OUTDIR)\Debug\Softdrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\CPUInfo.obj" + -@erase "$(INTDIR)\DDRAWDisplay.obj" + -@erase "$(INTDIR)\DIBDisplay.obj" + -@erase "$(INTDIR)\display.obj" + -@erase "$(INTDIR)\DisplayModeInfo.obj" + -@erase "$(INTDIR)\DrawDecal.obj" + -@erase "$(INTDIR)\Ram.obj" + -@erase "$(INTDIR)\softdrv.obj" + -@erase "$(INTDIR)\span.obj" + -@erase "$(INTDIR)\SpanBuffer.obj" + -@erase "$(INTDIR)\SWTHandle.obj" + -@erase "$(INTDIR)\TRaster.obj" + -@erase "$(INTDIR)\Triangle.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\Debug\Softdrv.dll" + -@erase "$(OUTDIR)\Debug\Softdrv.ilk" + -@erase "$(OUTDIR)\Softdrv.exp" + -@erase "$(OUTDIR)\Softdrv.lib" + -@erase "$(OUTDIR)\Softdrv.pdb" + +"$(INTDIR)" : + if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)" + +CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /X /I "..\\" /I "..\..\..\\" /I "..\..\..\support" /I "..\..\..\math" /I "..\..\..\bitmap" /I "..\..\..\..\msdev60\include" /I "..\..\..\..\sdk\dx6sdk\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOFTDRV2_EXPORTS" /Fp"$(INTDIR)\SoftDrv2.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\SoftDrv2.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\Softdrv.pdb" /debug /machine:I386 /nodefaultlib /out:"$(OUTDIR)\Debug\Softdrv.dll" /implib:"$(OUTDIR)\Softdrv.lib" /pdbtype:sept +LINK32_OBJS= \ + "$(INTDIR)\CPUInfo.obj" \ + "$(INTDIR)\DDRAWDisplay.obj" \ + "$(INTDIR)\DIBDisplay.obj" \ + "$(INTDIR)\display.obj" \ + "$(INTDIR)\DisplayModeInfo.obj" \ + "$(INTDIR)\DrawDecal.obj" \ + "$(INTDIR)\Ram.obj" \ + "$(INTDIR)\softdrv.obj" \ + "$(INTDIR)\span.obj" \ + "$(INTDIR)\SpanBuffer.obj" \ + "$(INTDIR)\SWTHandle.obj" \ + "$(INTDIR)\TRaster.obj" \ + "$(INTDIR)\Triangle.obj" \ + "..\..\..\..\MSDev60\lib\Winmm.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmtd.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\MSDev60\lib\Winspool.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\dxguid.lib" + +"$(OUTDIR)\Debug\Softdrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("SoftDrv2.dep") +!INCLUDE "SoftDrv2.dep" +!ELSE +!MESSAGE Warning: cannot find "SoftDrv2.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "SoftDrv2 - Win32 Release" || "$(CFG)" == "SoftDrv2 - Win32 Debug" +SOURCE=.\CPUInfo.c + +"$(INTDIR)\CPUInfo.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\DDRAWDisplay.c + +"$(INTDIR)\DDRAWDisplay.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\DIBDisplay.c + +"$(INTDIR)\DIBDisplay.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\display.c + +"$(INTDIR)\display.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\DisplayModeInfo.c + +"$(INTDIR)\DisplayModeInfo.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\DrawDecal.c + +"$(INTDIR)\DrawDecal.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=..\..\..\Support\Ram.c + +"$(INTDIR)\Ram.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=.\softdrv.c + +"$(INTDIR)\softdrv.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\span.c + +"$(INTDIR)\span.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\SpanBuffer.c + +"$(INTDIR)\SpanBuffer.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\SWTHandle.c + +"$(INTDIR)\SWTHandle.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\TRaster.c + +"$(INTDIR)\TRaster.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Triangle.c + +"$(INTDIR)\Triangle.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/G3D/Engine/Drivers/SoftDrv2/Softdrv.h b/G3D/Engine/Drivers/SoftDrv2/Softdrv.h new file mode 100644 index 0000000..15b506b --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/Softdrv.h @@ -0,0 +1,47 @@ +/****************************************************************************************/ +/* SoftDrv.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: This is the API layer for the genesis software driver. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SOFTDRV_H +#define SOFTDRV_H + +#include "DCommon.h" +#include "Display.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +extern DRV_Window ClientWindow; + +extern Display *SD_Display; +extern geBoolean SD_ProcessorHas3DNow; +extern geBoolean SD_ProcessorHasMMX; +extern geBoolean SD_DIBDisplayMode; +extern geBoolean SD_Active; +extern DRV_Driver SOFTDRV; +extern int32 RenderMode; + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv2/Span.h b/G3D/Engine/Drivers/SoftDrv2/Span.h new file mode 100644 index 0000000..c21dfc8 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/Span.h @@ -0,0 +1,61 @@ +/****************************************************************************************/ +/* Span.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Span abstracts and contains all the various ROP functions. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SPAN_H +#define SPAN_H + +#include "basetype.h" +#include "rop.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (GENESISCC *Span_DrawFunction)(void); + +typedef enum +{ + GE_SPAN_DESTINATION_FORMAT_555, + GE_SPAN_DESTINATION_FORMAT_565, + + GE_SPAN_DESTINATION_FORMATS +} geSpan_DestinationFormat; + +typedef enum +{ + GE_SPAN_HARDWARE_INTEL, + GE_SPAN_HARDWARE_MMX, + GE_SPAN_HARDWARE_AMD, + + GE_SPAN_HARDWARE_VERSIONS +} geSpan_CPU; + +geBoolean GENESISCC Span_SetOutputMode( geSpan_DestinationFormat DestFormat, geSpan_CPU CPU); + +Span_DrawFunction GENESISCC Span_GetDrawFunction(geROP ROP); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/G3D/Engine/Drivers/SoftDrv2/SpanBuffer.c b/G3D/Engine/Drivers/SoftDrv2/SpanBuffer.c new file mode 100644 index 0000000..d2ce454 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/SpanBuffer.c @@ -0,0 +1,279 @@ +/****************************************************************************************/ +/* SpanBuffer.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: This is a raster-line based span buffer (like a z buffer but it works */ +/* with groups of horizontal pixels, rather than single pixels) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "SpanBuffer.h" +#include "Ram.h" + +#ifdef GENESIS_VERSION_2 +#include "errorlog.h" +#else +#define geErrorLog_AddString(Error,xx,yy) +#endif + +//#define SPAN_MAX_SPARES 25000 +//#define SPAN_MAX_LINES 768 +//#define RESOLUTION_X 640 +//#define RESOLUTION_Y 640 + +typedef struct SpanBuffer_Span SpanBuffer_Span; + +typedef struct SpanBuffer_Span +{ + int Min, Max; + SpanBuffer_Span *Next; +} SpanBuffer_Span; + +static SpanBuffer_Span **SpanBuffer_Lines; // list of spans for each scanline +static SpanBuffer_Span *SpanBuffer_Spares; // unused spans since last Clear +static int SpanBuffer_FirstSpare; // index of next spare span: SpanBuffer_Spares[SpanBuffer_FirstSpare] +static int SpanBuffer_LineCount; // number of lines in span buffer table. +static int SpanBuffer_MaxSpares; +SpanBuffer_ClipSegment *SpanBuffer_Segments; // epxorted list of clipped spans (segments) + + +void SpanBuffer_Destroy(void) +{ + if ( SpanBuffer_Lines != NULL ) + geRam_Free(SpanBuffer_Lines); + SpanBuffer_Lines = NULL; + + if ( SpanBuffer_Spares != NULL ) + geRam_Free(SpanBuffer_Spares); + SpanBuffer_Spares = NULL; + + if ( SpanBuffer_Segments != NULL ) + geRam_Free(SpanBuffer_Segments); + SpanBuffer_Segments = NULL; +} + +void SpanBuffer_Clear(void) +{ + int i; + assert(SpanBuffer_Lines!=NULL); + + for (i=0; i 0 ); + assert( Height > 0 ); + assert( MaxSpans > 0 ); + + SpanBuffer_Destroy(); + + SpanBuffer_MaxSpares = MaxSpans; + SpanBuffer_LineCount = Height; + + SpanBuffer_Lines = geRam_Allocate(sizeof(SpanBuffer_Span *) * Height); + if (SpanBuffer_Lines == NULL) + { + geErrorLog_AddString( GE_ERR_MEMORY_RESOURCE,"Unable to create span buffer table",NULL); + return GE_FALSE; + } + + SpanBuffer_Spares = geRam_Allocate(sizeof(SpanBuffer_Span) * MaxSpans); + if (SpanBuffer_Lines == NULL) + { + geErrorLog_AddString(GE_ERR_MEMORY_RESOURCE ,"Unable to create spare span list",NULL); + geRam_Free(SpanBuffer_Lines); + SpanBuffer_Lines = NULL; + return GE_FALSE; + } + + SpanBuffer_Segments = geRam_Allocate(sizeof(SpanBuffer_ClipSegment) * (Width/2) ); + if (SpanBuffer_Segments == NULL ) + { + geErrorLog_AddString( GE_ERR_MEMORY_RESOURCE,"Unable to create span buffer clip segment list",NULL); + geRam_Free(SpanBuffer_Lines); + SpanBuffer_Lines = NULL; + geRam_Free(SpanBuffer_Spares); + SpanBuffer_Spares = NULL; + return GE_FALSE; + } + SpanBuffer_Clear(); + return GE_TRUE; +} + +#if 0 // not used (yet) +geBoolean SpanBuffer_Visible(int Line, int Left, int Right) +{ + SpanBuffer_Span *S; + assert( Line>=0 ); + assert( Line< SpanBuffer_LineCount ); + assert( Right>=Left ); + // assumes that adjacent spans are always merged. + + S = SpanBuffer_Lines[Line]; + while (S) + { + if (LeftMin) + return GE_TRUE; + if (Right<=S->Max) + return GE_FALSE; + S=S->Next; + } + return GE_TRUE; +} +#endif + +int SpanBuffer_ClipAndAdd(int Line, int LeftStart, int Width) +{ + SpanBuffer_Span *LastSpan; + SpanBuffer_Span *NewSpan; + SpanBuffer_Span *Span; + SpanBuffer_ClipSegment *Segment; + int Left = LeftStart; + int Right = LeftStart + Width -1; + int SegmentCount = 0; + #pragma message("fix this off by one problem here and in the engine!") + if (Line>=SpanBuffer_LineCount) + return 0; + + assert( Line >= 0 ); + assert( Line< SpanBuffer_LineCount ); + assert( Width >= 0 ); + assert( LeftStart >=0 ); + + Segment = &(SpanBuffer_Segments[0]); + LastSpan = NULL; + Span = SpanBuffer_Lines[Line]; + + while (Span) + { + if (Left < Span->Min) + { // new span starts to left of this span + if (RightMin) + { // new span ends to left of this span + break; + } + else + { // new span ends in or to the right of this span + Segment->LeftOffset = Left - LeftStart; + Segment->Width = Span->Min - Left; + SegmentCount++; + Segment++; + // Stretch Span to Left. + Span->Min = Left; + if (LastSpan) + { + if (LastSpan->Max+1 == Span->Min) + { // collapse LastSpan with Span + LastSpan->Max = Span->Max; + LastSpan->Next = Span->Next; + Span = LastSpan; + // *Span is lost for this frame + } + } + } + } + if (Left <= Span->Max) + { + Left = Span->Max + 1; + if (Left > Right) + return SegmentCount; + } + LastSpan = Span; + Span = Span->Next; + } + + // add span + Segment->LeftOffset = Left - LeftStart; + Segment->Width = Right - Left + 1; + SegmentCount++; + + + if (LastSpan) + { + if (LastSpan->Max+1 == Left) + { // stretch LastSpan + LastSpan->Max = Right; + } + else + { + if (SpanBuffer_FirstSpareMin = Left; + NewSpan->Max = Right; + NewSpan->Next = Span; + LastSpan->Next = NewSpan; + } + } + else + { + if (SpanBuffer_FirstSpareMin = Left; + NewSpan->Max = Right; + NewSpan->Next = Span; + SpanBuffer_Lines[Line] = NewSpan; + } + + + return SegmentCount; +} + + +#if 0 +void SpanBuffer_Test() +{ + int Visible; + + SpanBufferReset(1); + Visible = SpanBuffer_Visible(0, 5,9 ); + + SpanBufferClipAndAdd(0,30,10); + Visible = SpanBuffer_Visible(0, 5,9 ); + Visible = SpanBuffer_Visible(0, 30,40); + Visible = SpanBuffer_Visible(0, 30,41); + Visible = SpanBuffer_Visible(0, 29,40); + + SpanBufferClipAndAdd(0,10,10); + Visible = SpanBuffer_Visible(0, 10,50); + Visible = SpanBuffer_Visible(0, 30,41); + Visible = SpanBuffer_Visible(0, 50,60); + Visible = SpanBuffer_Visible(0, 1,2); + Visible = SpanBuffer_Visible(0, 15,35); + Visible = SpanBuffer_Visible(0, 25,26); + + Visible = SpanBuffer_Visible(0, 10,20); + Visible = SpanBuffer_Visible(0, 30,40); + + + SpanBufferClipAndAdd(0,5,50); + Visible = SpanBuffer_Visible(0, 5,10); + Visible = SpanBuffer_Visible(0, 60,70); + Visible = SpanBuffer_Visible(0, 1,2); + + +} +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv2/SpanBuffer.h b/G3D/Engine/Drivers/SoftDrv2/SpanBuffer.h new file mode 100644 index 0000000..bbd8b60 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/SpanBuffer.h @@ -0,0 +1,62 @@ +/****************************************************************************************/ +/* SpanBuffer.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: This is a raster-line based span buffer (like a z buffer but it works */ +/* with groups of horizontal pixels, rather than single pixels) */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef SPANBUFFER_H +#define SPANBUFFER_H + +#include "basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ // This is a clipped segment of a span. + int LeftOffset; // offset from starting pixel from original span (LeftStart) + int Width; // width of this segment +} SpanBuffer_ClipSegment; + +// this array holds the resulting clipped spans (segments) that result from calling _ClipAndAdd() +extern SpanBuffer_ClipSegment *SpanBuffer_Segments; + + + // initializes the span buffer +geBoolean SpanBuffer_Create(int Width, int Height, int MaxSpans); + + // destroys the span buffer +void SpanBuffer_Destroy(void); + + // empties the span buffer +void SpanBuffer_Clear(void); + + // adds a new span. The span is specified by a starting pixel and a width(number of pixels) + // The return value is the number of clipped spans (segments) to draw. (0 if none) + // The clipped spans are put into the exported array (SpanBuffer_Segments[0..return value+1]) +int SpanBuffer_ClipAndAdd(int Line, int LeftStart, int Width); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/G3D/Engine/Drivers/SoftDrv2/SpanEdges_Factory.h b/G3D/Engine/Drivers/SoftDrv2/SpanEdges_Factory.h new file mode 100644 index 0000000..4fa59e6 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/SpanEdges_Factory.h @@ -0,0 +1,189 @@ +/****************************************************************************************/ +/* SpanEdges_Factory.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: This is a template to create multiple function with similar structure,*/ +/* but with slightly different options. This template creates */ +/* edge-spanning functions for walking the edges of triangles, generating*/ +/* spans for each scan line. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +// This generates various edge-spanning routines +// The flag bits are +// TMAP: indicates texture mapping is used. +// 1/Z, U/Z, V/Z are stepped and prepared for the span routine +// SBUF: indicates span buffering is used. SpanBuffer is queried and segments are generated. +// 1/Z, Y are stepped and prepared for the span routine +// LSHADE: indicates gouraud rgb lighting is used. +// R,G,B are stepped and prepared for the span routine +// ZBUF: indicates z buffering is used. +// 1/Z is stepped and prepared for the span routine +// Combinations generate the (minimal) combination of stepping and preparation + + +#ifndef SPANEDGES +error. must define SPANEDGES for function creation options. +#endif + +#define MAX_RGB_VALUE (255<0) + { + + #if SPANEDGES & SBUF + int Spans = SpanBuffer_ClipAndAdd(Triangle.Left.Y,Triangle.Left.X,Triangle.SpanWidth); + SpanBuffer_ClipSegment *Segment = &(SpanBuffer_Segments[0]); + for (;Spans>0; Spans--,Segment++) + { + Triangle.DestBits = ((DESTPIXEL *)Triangle.Left.Dest) + Segment->LeftOffset; + + #if SPANEDGES & TMAP + Triangle.ZMapBits = ((ZMAPPIXEL *)(Triangle.Left.Dest + Triangle.ZBufferAddressDelta)) + Segment->LeftOffset; + #endif + + #if (SPANEDGES & TMAP) || (SPANEDGES & ZBUF) + OneOverZ = Triangle.Left.OneOverZ + Triangle.Gradients.dOneOverZdX * Segment->LeftOffset; + #endif + + #if SPANEDGES & TMAP + UOverZ = Triangle.Left.UOverZ + Triangle.Gradients.dUOverZdX * Segment->LeftOffset; + VOverZ = Triangle.Left.VOverZ + Triangle.Gradients.dVOverZdX * Segment->LeftOffset; + #endif + + #if (SPANEDGES & LSHADE) + R = Triangle.Left.R + Triangle.Gradients.dRdX * Segment->LeftOffset; + if (R<0) R=0; if (R>MAX_RGB_VALUE) R=MAX_RGB_VALUE; + G = Triangle.Left.G + Triangle.Gradients.dGdX * Segment->LeftOffset; + if (G<0) G=0; if (G>MAX_RGB_VALUE) G=MAX_RGB_VALUE; + B = Triangle.Left.B + Triangle.Gradients.dBdX * Segment->LeftOffset; + if (B<0) B=0; if (B>MAX_RGB_VALUE) B=MAX_RGB_VALUE; + + #endif + + Triangle.SpanWidth = Segment->Width; + #if SPANEDGES & LMAP + if (!Triangle.IsLightMapSetup) + TRaster_LightMapSetup(); + #endif + TRaster_DrawSpan(); + } + + #else + Triangle.DestBits = (DESTPIXEL *)Triangle.Left.Dest; + + #if SPANEDGES & ZBUF + Triangle.ZMapBits = (ZMAPPIXEL *)(Triangle.Left.Dest + Triangle.ZBufferAddressDelta); + #endif + + #if SPANEDGES & TMAP + UOverZ = Triangle.Left.UOverZ; + VOverZ = Triangle.Left.VOverZ; + #endif + + #if (SPANEDGES & TMAP) || (SPANEDGES & ZBUF) + OneOverZ = Triangle.Left.OneOverZ; + #endif + + #if (SPANEDGES & LSHADE) + R = Triangle.Left.R; + if (R<0) R=0; if (R>MAX_RGB_VALUE) R=MAX_RGB_VALUE; + + G = Triangle.Left.G; + if (G<0) G=0; if (G>MAX_RGB_VALUE) G=MAX_RGB_VALUE; + + B = Triangle.Left.B; + if (B<0) B=0; if (B>MAX_RGB_VALUE) B=MAX_RGB_VALUE; + + #endif + + #if SPANEDGES & LMAP + if (!Triangle.IsLightMapSetup) + TRaster_LightMapSetup(); + #endif + TRaster_DrawSpan(); + #endif + + } + + // step left edge + Triangle.Left.X += Triangle.Left.XStep; + Triangle.Left.Dest += Triangle.Left.DestStep; + Triangle.Left.Height--; + Triangle.Left.ErrorTerm += Triangle.Left.Numerator; + + #if SPANEDGES & TMAP + Triangle.Left.UOverZ += Triangle.Left.UOverZStep; + Triangle.Left.VOverZ += Triangle.Left.VOverZStep; + #endif + + #if (SPANEDGES & TMAP) || (SPANEDGES & ZBUF) + Triangle.Left.OneOverZ += Triangle.Left.OneOverZStep; + #endif + + + #if SPANEDGES & LSHADE + Triangle.Left.R += Triangle.Left.RStep; + Triangle.Left.G += Triangle.Left.GStep; + Triangle.Left.B += Triangle.Left.BStep; + #endif + + #if SPANEDGES & SBUF + Triangle.Left.Y ++; + #endif + + if (Triangle.Left.ErrorTerm >= Triangle.Left.Denominator) + { + Triangle.Left.X++; + Triangle.Left.Dest+=sizeof(DESTPIXEL); + Triangle.Left.ErrorTerm -= Triangle.Left.Denominator; + + #if SPANEDGES & TMAP + Triangle.Left.UOverZ += Triangle.Left.dUOverZdX; + Triangle.Left.VOverZ += Triangle.Left.dVOverZdX; + #endif + + #if (SPANEDGES & TMAP) || (SPANEDGES & ZBUF) + Triangle.Left.OneOverZ += Triangle.Left.dOneOverZdX; + #endif + + + #if SPANEDGES & LSHADE + Triangle.Left.R += Triangle.Left.dRdX; + Triangle.Left.G += Triangle.Left.dGdX; + Triangle.Left.B += Triangle.Left.dBdX; + #endif + } + + // step right edge + Triangle.Right.X += Triangle.Right.XStep; + Triangle.Right.ErrorTerm += Triangle.Right.Numerator; + if (Triangle.Right.ErrorTerm >= Triangle.Right.Denominator) \ + { + Triangle.Right.X++; + Triangle.Right.ErrorTerm -= Triangle.Right.Denominator; + } + } +} + + +#undef SPANEDGES diff --git a/G3D/Engine/Drivers/SoftDrv2/Span_AffineLoop.h b/G3D/Engine/Drivers/SoftDrv2/Span_AffineLoop.h new file mode 100644 index 0000000..1db6cdf --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/Span_AffineLoop.h @@ -0,0 +1,179 @@ +/****************************************************************************************/ +/* Span_AffineLoop.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: This is a template to create multiple affine span line drawing */ +/* routines. See Span, Span_Factory */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +while(i-- > 0) + { + #if SPANROP & ZTEST + ZFromMap = *(ZMapBits); + if (ZFromMap > (Z>>16)) + #endif + { + #if SPANROP & ZSET + *(ZMapBits++) = (ZMAPPIXEL)(Z>>16); + #else + #if SPANROP & ZTEST + ZMapBits++; + #endif + #endif + + #if !(( SPANROP & AFLAT) || (SPANROP & AMAP)) // NO alpha + #if (SPANROP & TMAP) + #ifdef TEST_LIGHTMAP + Color = 0xFFFFFF; + #else + Color = Palette[*(TextureBits + ((U>>16)&UMask) + TOPDOWN_OR_BOTTOMUP(((V>>16)&VMask) << StrideShift))]; + #endif + #if SPANROP & D565 + #ifdef RGB + *(DestBits++) = (DESTPIXEL) ( ((((Color&0xFF)*R)>>15)&0xF800) | (((((Color&0xFF00)>>8)*G)>>20)&0x7E0) | ((((Color&0xFF0000)>>16)*B)>>26) ); + #else + *(DestBits++) = (DESTPIXEL) ( ((Color&0xF8)<<8) /*R*/ | ((Color&0xFC00)>>5) /*G*/ | ((Color&0xF80000)>>19)/*B*/ ); + #endif + #else + #ifdef RGB + *(DestBits++) = (DESTPIXEL) ( ((((Color&0xFF)*R)>>16)&0x7C00) | (((((Color&0xFF00)>>8)*G)>>21)&0x3E0) | ((((Color&0xFF0000)>>16)*B)>>26) ); + #else + *(DestBits++) = (DESTPIXEL) ( ((Color&0xF8)<<7) /*R*/ | ((Color&0xF800)>>6) /*G*/ | ((Color&0xF80000)>>19)/*B*/ ); + #endif + #endif + + #else + #if SPANROP & D565 + #ifdef RGB + *(DestBits++) = (DESTPIXEL) ( ((R>>(RGB_FXP_SHIFTER + 3))<<11) | ((G>>(RGB_FXP_SHIFTER + 2))<<5) | (B>>(RGB_FXP_SHIFTER + 3)) ); + #else + *(DestBits++) = (DESTPIXEL) Color; + #endif + #else + #ifdef RGB + *(DestBits++) = (DESTPIXEL)( ((R>>(RGB_FXP_SHIFTER + 3))<<10) | ((G>>(RGB_FXP_SHIFTER + 3))<<5) | (B>>(RGB_FXP_SHIFTER + 3)) ); + #else + *(DestBits++) = (DESTPIXEL) Color; + #endif + #endif + #endif + #endif + + #if (SPANROP & AFLAT) || (SPANROP & AMAP) // alpha map or alpha flat or both + { + int32 DColor,AR,AG,AB; + #if (SPANROP & AMAP) && (SPANROP & AFLAT) + int32 Alpha,OneMinusAlpha; + #endif + + DColor = *DestBits; + + #if SPANROP & TMAP + #if (SPANROP & AMAP) + Color = *( ((ALPHAMAPPIXEL *)TextureBits) + ((U>>16)&UMask) + TOPDOWN_OR_BOTTOMUP(((V>>16)&VMask) << StrideShift)); //4444 argb + #ifdef RGB // alpha map and rgb shading + AR = (((Color & 0xF00)>>8 ) * R) >>(4+RGB_FXP_SHIFTER); + AG = (((Color & 0x0F0)>>4 ) * G) >>(4+RGB_FXP_SHIFTER); + AB = ( (Color & 0x00F) * B) >>(4+RGB_FXP_SHIFTER); + #else // alpha map only + AR = ((Color & 0xF00)>>4 ) ; + AG = ((Color & 0x0F0) ) ; + AB = ((Color & 0x00F)<<4 ) ; + #endif + #if (SPANROP & AFLAT) + Alpha = ((Color>>12) * A)>>4; + OneMinusAlpha = 16-Alpha; + #else + A = (Color>>12); + OneMinusA = 16-A; + #endif + #else // texture map without alpha + Color = Palette[*(TextureBits + ((U>>16)&UMask) + TOPDOWN_OR_BOTTOMUP(((V>>16)&VMask) << StrideShift))]; + #ifdef RGB + AR = (( Color & 0xFF ) * R) >>(8+RGB_FXP_SHIFTER); + AG = (((Color & 0xFF00 )>>8 ) * G) >>(8+RGB_FXP_SHIFTER); + AB = (((Color & 0xFF0000)>>16) * B) >>(8+RGB_FXP_SHIFTER); + #else + AR = (Color & 0xFF ); + AG = (Color & 0xFF00 )>>8; + AB = (Color & 0xFF0000)>>16; + #endif + #endif + #else + // no texture + #ifdef RGB + AR = R >>RGB_FXP_SHIFTER; + AG = G >>RGB_FXP_SHIFTER; + AB = B >>RGB_FXP_SHIFTER; + #else + AR = (Color & 0xFF ); + AG = (Color & 0xFF00 )>>8; + AB = (Color & 0xFF0000)>>16; + #endif + #endif + + #if (SPANROP & AMAP) && (SPANROP & AFLAT) + #if SPANROP & D565 + AR = (((DColor&0xF800)>>8) * OneMinusAlpha) + (AR * Alpha); + AG = (((DColor&0x7E0)>>3) * OneMinusAlpha) + (AG * Alpha); + AB = (((DColor&0x1F)<<3) * OneMinusAlpha) + (AB * Alpha); + *(DestBits++) = (DESTPIXEL) ( ( (AR>>7)<<11) | ( (AG>>6)<<5 ) | (AB>>7) ); + #else + AR = (((DColor&0x7C00)>>7) * OneMinusAlpha) + (AR * Alpha); + AG = (((DColor&0x3E0)>>2) * OneMinusAlpha) + (AG * Alpha); + AB = (((DColor&0x1F)<<3) * OneMinusAlpha) + (AB * Alpha); + *(DestBits++) = (DESTPIXEL) ( ( (AR>>7)<<10) | ( (AG>>7)<<5 ) | (AB>>7) ); + #endif + #else + #if SPANROP & D565 + AR = (((DColor&0xF800)>>8) * OneMinusA) + (AR * A); + AG = (((DColor&0x7E0)>>3) * OneMinusA) + (AG * A); + AB = (((DColor&0x1F)<<3) * OneMinusA) + (AB * A); + *(DestBits++) = (DESTPIXEL) ( ( (AR>>7)<<11) | ( (AG>>6)<<5 ) | (AB>>7) ); + #else + AR = (((DColor&0x7C00)>>7) * OneMinusA) + (AR * A); + AG = (((DColor&0x3E0)>>2) * OneMinusA) + (AG * A); + AB = (((DColor&0x1F)<<3) * OneMinusA) + (AB * A); + *(DestBits++) = (DESTPIXEL) ( ( (AR>>7)<<10) | ( (AG>>7)<<5 ) | (AB>>7) ); + #endif + #endif + + } + #endif + + } + #if SPANROP & ZTEST + else + { + ZMapBits++; + DestBits++; + } + #endif + + #if SPANROP & TMAP + U += dU; + V += dV; + #endif + #ifdef RGB + R += dR; + G += dG; + B += dB; + #endif + #ifdef ZBUF + Z += dZ; + #endif + } \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv2/Span_Factory.h b/G3D/Engine/Drivers/SoftDrv2/Span_Factory.h new file mode 100644 index 0000000..65af2d6 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/Span_Factory.h @@ -0,0 +1,273 @@ +/****************************************************************************************/ +/* Span_Factory.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: This is a template to create multiple span line drawing */ +/* routines. See Span */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ + +// This generates various span drawing routines +// The flag bits are +// TMAP: indicates texture mapping is used. +// LSHADE: indicates gouraud rgb lighting is used. +// ZSET: indicates z buffer is to be set +// ZTEST: indicates z buffer is to be tested + + +// The idea is to break the span line into sub-spans that are perspective correct at the end points. The +// sub-span is affine mapped. So every few pixels a new sub-span end point is computed, and the point +// is connected with an affine mapper. The span is broken down into a series of sub-spans of a fixed length, +// and the last sub-span (what ever is left over). + +#ifndef SPANROP +#error must define SPANROP for function creation options. +#endif + + +#if (SPANROP & ZSET || (SPANROP & ZTEST)) + #define ZBUF // zbuffering used at all +#else + #undef ZBUF +#endif + +#if (SPANROP & LSHADE) || (SPANROP & LMAP) + #define RGB // pixels are rgb lit +#else + #undef RGB +#endif + +#if (SPANROP & TMAP) || (defined(ZBUF)) + #undef AFFINE +#else + #define AFFINE // break into subspans +#endif + +#if !( (SPANROP & LMAP) || ( (SPANROP & LSHADE ) || (SPANROP & LFLAT) ) ) + #error must define lighting +#endif + +#if (SPANROP & LMAP) && !(SPANROP & TMAP) + #error alpha map must accompany texture map +#endif + + +#if (SPANROP & AMAP) && !(SPANROP & TMAP) + #error alpha map is embedded in tmap +#endif + + +//void GENESISCC Span_C_xxx(void ) +{ + #ifndef AFFINE + int32 SubSpanOneOverZ; + int OneOverSubSpanWidth; + int SubSpanWidth = Triangle.Gradients.SubSpanWidth; + int SubSpanShift = Triangle.Gradients.SubSpanShift; + #endif + // int32 OneOverZ,UOverZ,VOverZ; // globals + // int32 R,G,B; // globals + // int32 URight,VRight; // globals + int i; + int W=Triangle.SpanWidth; + DESTPIXEL *DestBits = Triangle.DestBits; + + #if SPANROP & TMAP + int32 U, V; + int32 dU, dV; + int32 UMask = Triangle.UMask; + int32 VMask = Triangle.VMask; + TEXTUREPIXEL *TextureBits = Triangle.TextureBits; + #if !(SPANROP & AMAP) + uint32 *Palette = Triangle.Palette; + #endif + int32 StrideShift = Triangle.StrideShift; + int32 SubSpanUOverZ, SubSpanVOverZ; + #endif + #if (SPANROP & TMAP) || (SPANROP & LFLAT) + uint32 Color; + #endif + + #ifdef RGB + int32 dR, dG, dB; + #endif + + #if (defined(ZBUF) || (SPANROP & TMAP)) + int32 ZRight; + #endif + + #ifdef ZBUF + int32 Z, dZ; + ZMAPPIXEL *ZMapBits = Triangle.ZMapBits; + int32 ZScale = Triangle.Gradients.ZScale; + #endif + + #if SPANROP & ZTEST + ZMAPPIXEL ZFromMap; + #endif + + + #if SPANROP & LFLAT + #if SPANROP & D565 + Color = ( ((R>>(RGB_FXP_SHIFTER + 3))<<11) | ((G>>(RGB_FXP_SHIFTER + 2))<<5) | (B>>(RGB_FXP_SHIFTER + 3)) ); + #else + Color = ( ((R>>(RGB_FXP_SHIFTER + 3))<<10) | ((G>>(RGB_FXP_SHIFTER + 3))<<5) | (B>>(RGB_FXP_SHIFTER + 3)) ); + #endif + #endif + + #if SPANROP & LSHADE + dR = Triangle.Gradients.dRdX; + dG = Triangle.Gradients.dGdX; + dB = Triangle.Gradients.dBdX; + #endif + + if (Triangle.Gradients.Affine) + { + W = Triangle.SpanWidth; + #if SPANROP & TMAP + U = UOverZ; + V = VOverZ; + dU = Triangle.Gradients.dUOverZdX; + dV = Triangle.Gradients.dVOverZdX; + #endif + #ifdef ZBUF + Z = OneOverZ; + dZ = Triangle.Gradients.dOneOverZdX; + #endif + #if SPANROP & LMAP + { + URight = U; + VRight = V; + Span_LightMapSample(); + R=RRight;G=GRight;B=BRight; + OneOverSubSpanWidth = Triangle.SmallDivideTable[W]; + URight = U + W * dU; + VRight = V + W * dV; + } + #endif + goto AffineLoop; + } + +#ifndef AFFINE + // either ZBUF or TMAP + + ZRight = OOZ_MUL_PREP( (OOZ_NUMERATOR/( OOZ_DIV_PREP(OneOverZ)|0x1 ))); + + #if SPANROP & TMAP + URight = (ZRight * OZ_MUL_PREP(UOverZ)); + VRight = (ZRight * OZ_MUL_PREP(VOverZ)); + U = URight; + V = VRight; + #if SPANROP & LMAP + Span_LightMapSample(); + R=RRight;G=GRight;B=BRight; + #endif + #endif + + #ifdef ZBUF + Z = OOZ_MUL_Z(ZRight,ZScale); + #endif + + + if (W>SubSpanWidth) + { + SubSpanOneOverZ = Triangle.Gradients.dOneOverZdX << SubSpanShift; + #if SPANROP & TMAP + SubSpanUOverZ = Triangle.Gradients.dUOverZdX << SubSpanShift; + SubSpanVOverZ = Triangle.Gradients.dVOverZdX << SubSpanShift; + #endif + while(W > SubSpanWidth) + { + OneOverZ += SubSpanOneOverZ; + ZRight = OOZ_MUL_PREP( (OOZ_NUMERATOR/( OOZ_DIV_PREP(OneOverZ)|0x1 ))); + i = SubSpanWidth; + W -= SubSpanWidth; + + #if SPANROP & TMAP + UOverZ += SubSpanUOverZ; + URight = (ZRight * OZ_MUL_PREP(UOverZ)); + dU = (URight - U)>> SubSpanShift; + + VOverZ += SubSpanVOverZ; + VRight = (ZRight * OZ_MUL_PREP(VOverZ)); + dV = (VRight - V)>> SubSpanShift; + #endif + + #ifdef ZBUF + ZRight = OOZ_MUL_Z(ZRight,ZScale); + dZ = (ZRight - Z)>> SubSpanShift; + #endif + + #if SPANROP & LMAP + Span_LightMapSample(); + dR = (RRight - R)>> SubSpanShift; + dG = (GRight - G)>> SubSpanShift; + dB = (BRight - B)>> SubSpanShift; + #endif + + + #include "Span_AffineLoop.h" + } + } +#endif //AFFINE + + if (W>0) + { + #ifndef AFFINE + OneOverSubSpanWidth = Triangle.SmallDivideTable[W]; + OneOverZ += Triangle.Gradients.dOneOverZdX * W; + ZRight = OOZ_MUL_PREP( (OOZ_NUMERATOR/( OOZ_DIV_PREP(OneOverZ)|0x1 ))); + #endif + + #if SPANROP & TMAP + UOverZ += Triangle.Gradients.dUOverZdX * W; + URight = (ZRight * OZ_MUL_PREP(UOverZ)); + dU = ( ( ((URight - U)>>12) * (OneOverSubSpanWidth)))>>4; + + VOverZ += Triangle.Gradients.dVOverZdX * W; + VRight = (ZRight * OZ_MUL_PREP(VOverZ)); + dV = ( ( ((VRight - V)>>12) * (OneOverSubSpanWidth)))>>4; + #endif + + #ifdef ZBUF + ZRight = OOZ_MUL_Z(ZRight,ZScale); + dZ = ( ( ((ZRight - Z)>>12) * (OneOverSubSpanWidth)))>>4; + #endif + + AffineLoop: + + #if SPANROP & LMAP + Span_LightMapSample(); + dR = ( ( ((RRight - R)>>12) * (OneOverSubSpanWidth)))>>4; + dG = ( ( ((GRight - G)>>12) * (OneOverSubSpanWidth)))>>4; + dB = ( ( ((BRight - B)>>12) * (OneOverSubSpanWidth)))>>4; + #endif + + i=W; + #include "Span_AffineLoop.h" + } + + + +} + + +#undef SPANROP +#undef ZBUF +#undef RGB + + diff --git a/G3D/Engine/Drivers/SoftDrv2/TRaster.c b/G3D/Engine/Drivers/SoftDrv2/TRaster.c new file mode 100644 index 0000000..ad48179 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/TRaster.c @@ -0,0 +1,344 @@ +/****************************************************************************************/ +/* TRaster.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: API layer for Triangle Rasterizer */ +/* */ +/* Code fragments from Chris Hecker's texture mapping articles used with */ +/* permission. http://www.d6.com/users/checker */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include + +#include "TRaster.h" +#include "Triangle.h" +#include "span.h" +#include "spanbuffer.h" + +Span_DrawFunction TRaster_DrawSpan; // used to draw for current triangle +void GENESISCC TRaster_LightMapSetup(void); + +// Construct different edge-walkers depending on the various rops: + +//SPANEDGES OPTIONS: TMAP LSHADE ZBUF SBUF + +#define SPANEDGES LSHADE +static void GENESISCC TRaster_SpanEdges_LSHADE(int Height) + { + #include "SpanEdges_Factory.h" + } + +#define SPANEDGES LSHADE + ZBUF +static void GENESISCC TRaster_SpanEdges_LSHADE_ZBUF(int Height) + { + #include "SpanEdges_Factory.h" + } + +#define SPANEDGES TMAP + LSHADE +static void GENESISCC TRaster_SpanEdges_TMAP_LSHADE(int Height) + { + #include "SpanEdges_Factory.h" + } + +#define SPANEDGES TMAP + LSHADE + ZBUF +static void GENESISCC TRaster_SpanEdges_TMAP_LSHADE_ZBUF(int Height) + { + #include "SpanEdges_Factory.h" + } + +#define SPANEDGES TMAP + LMAP + ZBUF + SBUF +static void GENESISCC TRaster_SpanEdges_TMAP_LMAP_ZBUF_SBUF(int Height) + { + #include "SpanEdges_Factory.h" + } + +#define SPANEDGES TMAP + LSHADE + ZBUF + SBUF +static void GENESISCC TRaster_SpanEdges_TMAP_LSHADE_ZBUF_SBUF(int Height) + { + #include "SpanEdges_Factory.h" + } + +#define SPANEDGES TMAP + LMAP +static void GENESISCC TRaster_SpanEdges_TMAP_LMAP(int Height) + { + #include "SpanEdges_Factory.h" + } + +#define SPANEDGES TMAP + LMAP + ZBUF +static void GENESISCC TRaster_SpanEdges_TMAP_LMAP_ZBUF(int Height) + { + #include "SpanEdges_Factory.h" + } + + +typedef void ( GENESISCC *TRaster_SpanEdgesFunction)(int Height); + +typedef struct +{ + geROP ROP; + int Flags; + TRaster_SpanEdgesFunction SpanEdges; +} TRaster_RopInfo; + + +TRaster_RopInfo TRaster_RopTable[GE_ROP_END] = +// +{//ROP ID +{GE_ROP_LSHADE, LSHADE, TRaster_SpanEdges_LSHADE }, +{GE_ROP_LSHADE_ZSET, LSHADE | ZBUF | ZSET, TRaster_SpanEdges_LSHADE_ZBUF }, +{GE_ROP_LSHADE_ZTEST, LSHADE | ZBUF | ZTEST, TRaster_SpanEdges_LSHADE_ZBUF }, +{GE_ROP_LSHADE_ZTESTSET, LSHADE | ZBUF | ZTEST | ZSET, TRaster_SpanEdges_LSHADE_ZBUF }, +{GE_ROP_LSHADE_AFLAT, LSHADE | AFLAT, TRaster_SpanEdges_LSHADE_ZBUF }, +{GE_ROP_LSHADE_AFLAT_ZSET, LSHADE | AFLAT | ZBUF | ZSET, TRaster_SpanEdges_LSHADE_ZBUF }, +{GE_ROP_LSHADE_AFLAT_ZTEST, LSHADE | AFLAT | ZBUF | ZTEST, TRaster_SpanEdges_LSHADE_ZBUF }, +{GE_ROP_LSHADE_AFLAT_ZTESTSET, LSHADE | AFLAT | ZBUF | ZTEST | ZSET, TRaster_SpanEdges_LSHADE_ZBUF }, +{GE_ROP_TMAP_LSHADE, TMAP | LSHADE, TRaster_SpanEdges_TMAP_LSHADE }, +{GE_ROP_TMAP_LSHADE_ZSET, TMAP | LSHADE | ZBUF | ZSET, TRaster_SpanEdges_TMAP_LSHADE_ZBUF}, +{GE_ROP_TMAP_LSHADE_ZTEST, TMAP | LSHADE | ZBUF | ZTEST, TRaster_SpanEdges_TMAP_LSHADE_ZBUF}, +{GE_ROP_TMAP_LSHADE_ZTESTSET, TMAP | LSHADE | ZBUF | ZTEST | ZSET, TRaster_SpanEdges_TMAP_LSHADE_ZBUF}, +{GE_ROP_TMAP_LMAP_ZSET_SBUF, TMAP | LMAP | ZBUF | ZSET | SBUF, TRaster_SpanEdges_TMAP_LMAP_ZBUF_SBUF }, +{GE_ROP_TMAP_LSHADE_ZSET_SBUF, TMAP | LSHADE | ZBUF | ZSET | SBUF, TRaster_SpanEdges_TMAP_LSHADE_ZBUF_SBUF }, +{GE_ROP_TMAP_LMAP_ZTESTSET, TMAP | LMAP | ZBUF | ZTEST | ZSET, TRaster_SpanEdges_TMAP_LMAP_ZBUF }, +{GE_ROP_TMAP_LSHADE_AFLAT, TMAP | LSHADE | AFLAT , TRaster_SpanEdges_TMAP_LSHADE }, +{GE_ROP_TMAP_LSHADE_AFLAT_ZSET, TMAP | LSHADE | AFLAT | ZBUF | ZSET, TRaster_SpanEdges_TMAP_LSHADE_ZBUF }, +{GE_ROP_TMAP_LSHADE_AFLAT_ZTEST, TMAP | LSHADE | AFLAT | ZBUF | ZTEST, TRaster_SpanEdges_TMAP_LSHADE_ZBUF }, +{GE_ROP_TMAP_LSHADE_AFLAT_ZTESTSET, TMAP | LSHADE | AFLAT | ZBUF | ZTEST | ZSET, TRaster_SpanEdges_TMAP_LSHADE_ZBUF }, +{GE_ROP_TMAP_LSHADE_AMAP, TMAP | LSHADE | AMAP, TRaster_SpanEdges_TMAP_LSHADE }, +{GE_ROP_TMAP_LSHADE_AMAP_ZSET, TMAP | LSHADE | AMAP | ZBUF | ZSET, TRaster_SpanEdges_TMAP_LSHADE_ZBUF }, +{GE_ROP_TMAP_LSHADE_AMAP_ZTEST, TMAP | LSHADE | AMAP | ZBUF | ZTEST, TRaster_SpanEdges_TMAP_LSHADE_ZBUF }, +{GE_ROP_TMAP_LSHADE_AMAP_ZTESTSET, TMAP | LSHADE | AMAP | ZBUF | ZTEST | ZSET, TRaster_SpanEdges_TMAP_LSHADE_ZBUF }, +{GE_ROP_TMAP_LMAP_AMAP, TMAP | LMAP | AMAP, TRaster_SpanEdges_TMAP_LMAP }, +{GE_ROP_TMAP_LMAP_AMAP_ZSET, TMAP | LMAP | AMAP | ZBUF | ZSET, TRaster_SpanEdges_TMAP_LMAP_ZBUF }, +{GE_ROP_TMAP_LMAP_AMAP_ZTEST, TMAP | LMAP | AMAP | ZBUF | ZTEST, TRaster_SpanEdges_TMAP_LMAP_ZBUF }, +{GE_ROP_TMAP_LMAP_AMAP_ZTESTSET, TMAP | LMAP | AMAP | ZBUF | ZTEST | ZSET, TRaster_SpanEdges_TMAP_LMAP_ZBUF }, +{GE_ROP_TMAP_LMAP_AFLAT_ZTESTSET, TMAP | LMAP | AFLAT | ZBUF | ZTEST | ZSET, TRaster_SpanEdges_TMAP_LMAP_ZBUF }, +{GE_ROP_TMAP_LSHADE_AMAP_AFLAT, TMAP | LSHADE | AMAP | AFLAT, TRaster_SpanEdges_TMAP_LSHADE }, +{GE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZSET, TMAP | LSHADE | AMAP | AFLAT | ZBUF | ZSET, TRaster_SpanEdges_TMAP_LSHADE_ZBUF }, +{GE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZTEST, TMAP | LSHADE | AMAP | AFLAT | ZBUF | ZTEST, TRaster_SpanEdges_TMAP_LSHADE_ZBUF }, +{GE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZTESTSET,TMAP | LSHADE | AMAP | AFLAT | ZBUF | ZTEST | ZSET, TRaster_SpanEdges_TMAP_LSHADE_ZBUF }, + +}; + + + + +void GENESISCC TRaster_LightMapSetup(void) +{ + TRaster_Lightmap LM; + Triangle.IsLightMapSetup=GE_TRUE; + LM.MipIndex = Triangle.MipIndex; + + Triangle.LightMapSetup(&LM); + + Triangle.LightMapBits = (LIGHTMAPPIXEL *)LM.BitPtr; + Triangle.LightMapWidth = LM.Width; + Triangle.LightMapHeight = LM.Height; + + Triangle.LightMapShiftU = (int)(65536.0f * LM.LightMapShiftU); + Triangle.LightMapScaleU = (int)(256.0f * LM.LightMapScaleU); + + Triangle.LightMapShiftV = (int)(65536.0f * LM.LightMapShiftV); + Triangle.LightMapScaleV = (int)(256.0f * LM.LightMapScaleV); + + Triangle.LightMapStride = Triangle.LightMapWidth * 3; + Triangle.LightMapMaxU = (Triangle.LightMapWidth-1)<<16; + Triangle.LightMapMaxV = (Triangle.LightMapHeight-1)<<16; +} + + +void GENESISCC TRaster_Setup(int MaxAffineSize,geRDriver_THandle *Dest, geRDriver_THandle *ZBuffer, void (*LightMapSetup)(TRaster_Lightmap *LM)) +{ + int i; + + assert( MaxAffineSize > 0); + assert( MaxAffineSize < TRASTER_SMALL_DIVIDE_TABLESIZE); + assert( Dest != NULL ); + assert( LightMapSetup != NULL ); + + Triangle.MaxAffineSize = (geFloat)MaxAffineSize; + + + for (i=1; i=0 ) ; + assert( ROP <= GE_ROP_END ); + + Triangle.ROPFlags = TRaster_RopTable[ROP].Flags; + + assert( TRaster_RopTable[ROP].SpanEdges != NULL ); + assert( ((Triangle.ROPFlags & AFLAT) && (pVertices[0].a>=0.0f && pVertices[0].a<=255.1f)) || !(Triangle.ROPFlags & AFLAT)); + assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[0].r>=0.0f && pVertices[0].r<=255.1f)) || !(Triangle.ROPFlags & LSHADE)); + assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[1].r>=0.0f && pVertices[1].r<=255.1f)) || !(Triangle.ROPFlags & LSHADE)); + assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[2].r>=0.0f && pVertices[2].r<=255.1f)) || !(Triangle.ROPFlags & LSHADE)); + assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[0].g>=0.0f && pVertices[0].g<=255.1f)) || !(Triangle.ROPFlags & LSHADE)); + assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[1].g>=0.0f && pVertices[1].g<=255.1f)) || !(Triangle.ROPFlags & LSHADE)); + assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[2].g>=0.0f && pVertices[2].g<=255.1f)) || !(Triangle.ROPFlags & LSHADE)); + assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[0].b>=0.0f && pVertices[0].b<=255.1f)) || !(Triangle.ROPFlags & LSHADE)); + assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[1].b>=0.0f && pVertices[1].b<=255.1f)) || !(Triangle.ROPFlags & LSHADE)); + assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[2].b>=0.0f && pVertices[2].b<=255.1f)) || !(Triangle.ROPFlags & LSHADE)); + + if (Triangle.ROPFlags & TMAP) + { + int W,H; + assert( Texture != NULL ); + W = Texture->Width >> MipIndex; + H = Texture->Height >> MipIndex; + if (Triangle_GradientsCompute(&(Triangle.Gradients), + pVertices,(geFloat)(W),(geFloat)(H))==GE_FALSE) + return; // poly has no area. + + for(Triangle.StrideShift=1;((1<= 0 ); + assert( MipIndex < Texture->MipLevels ); + Triangle.MipIndex = MipIndex; + Triangle.TextureBits = (TEXTUREPIXEL *)Texture->BitPtr[MipIndex]; + if (Texture->PalHandle) + Triangle.Palette = (Triangle_PaletteEntry *)Texture->PalHandle->BitPtr[0]; + } + else + { + if (Triangle_GradientsCompute(&(Triangle.Gradients),pVertices,1.0f,1.0f)==GE_FALSE) + return; // poly has no area. + } + if (Triangle.ROPFlags & ZBUF) + { + assert(Triangle.ZMap != NULL ); + assert(Triangle.ZMap->Width == Triangle.DestMap->Width); + + Triangle.ZBufferAddressDelta = ((int)(Triangle.ZMap->BitPtr[0])) - ((int)(Triangle.DestMap->BitPtr[0])); + } + TRaster_DrawSpan = Span_GetDrawFunction(ROP); + A = (int32)(pVertices[0].a / (255.0f/16.0f) ); + OneMinusA = 16 - A; + + // sort vertices in y + if(Y0 < Y1) + { + if(Y2 < Y0) + { Top = 2; Middle = 0; Bottom = 1; SplitRight = 1; } + else + { + if(Y1 < Y2) + { Top = 0; Middle = 1; Bottom = 2; SplitRight = 1; } + else + { Top = 0; Middle = 2; Bottom = 1; SplitRight = 0; } + } + } + else + { + if(Y2 < Y1) + { Top = 2; Middle = 1; Bottom = 0; SplitRight = 0; } + else + { + if(Y0 < Y2) + { Top = 1; Middle = 0; Bottom = 2; SplitRight = 0; } + else + { Top = 1; Middle = 2; Bottom = 0; SplitRight = 1; } + } + } + + + Triangle_EdgeCompute(&TopToBottom, &(Triangle.Gradients),pVertices,Top, Bottom, SplitRight); + Triangle_EdgeCompute(&TopToSplit, &(Triangle.Gradients),pVertices,Top, Middle, !SplitRight); + Triangle_EdgeCompute(&SplitToBottom,&(Triangle.Gradients),pVertices,Middle,Bottom, !SplitRight); + + // to maximize mmx optimization, there is no floating point from this point on + if(SplitRight) + { + Triangle.Left = TopToBottom; + Triangle.Right = TopToSplit; + } + else + { + Triangle.Left = TopToSplit; + Triangle.Right = TopToBottom; + } + + DestPtr = ( uint32 )(Triangle.DestMap->BitPtr[0]); + DestWidth = TOPDOWN_OR_BOTTOMUP(Triangle.DestMap->Width); + Triangle.Left.Dest = DestPtr + ((Triangle.Left.X + Triangle.Left.Y * DestWidth)< //sprintf +#include //OutputDebugString() +#endif + +#include +#include // fabs +#include // memcpy +#include "swthandle.h" +#include "basetype.h" +#include "triangle.h" + + + +#ifndef USE_DIBS +#define DEST565 +#endif + + + + + +#define MAX(AA,BB) ((AA)>(BB)?(AA):(BB)) +#define MIN(AA,BB) ((AA)<(BB)?(AA):(BB)) + + +geBoolean GENESISCC Triangle_GradientsCompute( + Triangle_Gradients *G, + const DRV_TLVertex *pVertices, + geFloat TextureWidth, + geFloat TextureHeight) +{ + geFloat OneOverdX; + geFloat OneOverdY; + geFloat Denominator; + geFloat Width02 = pVertices[0].x-pVertices[2].x; + geFloat Height02 = pVertices[0].y-pVertices[2].y; + geFloat Width12 = pVertices[1].x-pVertices[2].x; + geFloat Height12 = pVertices[1].y-pVertices[2].y; + geFloat d02,d12; + geFloat Size; + assert( pVertices[0].z != 0.0f ); + assert( pVertices[1].z != 0.0f ); + assert( pVertices[2].z != 0.0f ); + + Denominator = ( (Width12 * Height02) - (Width02 * Height12)); + + + if (Denominator == 0.0f) + return GE_FALSE; + + OneOverdX = 1.0f / Denominator; + + OneOverdY = -OneOverdX; + + { + geFloat Right = MAX(pVertices[0].x,MAX(pVertices[1].x,pVertices[2].x)); + geFloat Left = MIN(pVertices[0].x,MIN(pVertices[1].x,pVertices[2].x)); + geFloat Top = MIN(pVertices[0].y,MIN(pVertices[1].y,pVertices[2].y)); + geFloat Bottom = MAX(pVertices[0].y,MAX(pVertices[1].y,pVertices[2].y)); + Size = MAX(Right-Left,Bottom-Top); + } + + if (Size < Triangle.MaxAffineSize) + G->Affine = 1; + else + G->Affine = 0; + + + if (Triangle.ROPFlags & (TMAP | ZBUF)) + { + geFloat zmax = MAX(pVertices[0].z,MAX(pVertices[1].z,pVertices[2].z)); + geFloat zmin = MIN(pVertices[0].z,MIN(pVertices[1].z,pVertices[2].z)); + // G->FZScale is used to scale the range of all the interpolators to fit nicely + // in the predeterminted fixed point ranges. These fixed point ranges are setup + // to minimize visible errors. + // The following code is unfortunate. Due to the limited range of the fixed + // point math, the FZScale has a limited ability to scale everything else. + // the following ranges are uesd to keep FZScale within known good boundries. + // It's still possible to break the rasterizer by using Z values that are too + // large or too small. + if (zmax-zmin > 255.0f ) + { + G->FZScale = zmin; + } + else + { + if (zmin<80.0f) + G->FZScale = zmin; + else + { + if (zmax>500.0f) zmax=500.0f; + G->FZScale = zmax; + } + } + #if 0 + {// debugging code: + char s[1000]; + sprintf(s,"z[0]=%f\t\tz[1]=%f\t\tz[2]=%f\t\tScale=%f\n", + pVertices[0].z,pVertices[1].z,pVertices[2].z,G->FZScale); + OutputDebugString(s); + } + #endif + if (!G->Affine) + { + G->OneOverZ[0] = G->FZScale/pVertices[0].z; + G->OneOverZ[1] = G->FZScale/pVertices[1].z; + G->OneOverZ[2] = G->FZScale/pVertices[2].z; + } + else + { + geFloat OneOverZScale = 1.0f / G->FZScale; + G->OneOverZ[0] = pVertices[0].z * OneOverZScale; + G->OneOverZ[1] = pVertices[1].z * OneOverZScale; + G->OneOverZ[2] = pVertices[2].z * OneOverZScale; + } + + d02 = G->OneOverZ[0] - G->OneOverZ[2]; + d12 = G->OneOverZ[1] - G->OneOverZ[2]; + G->FdOneOverZdX = OneOverdX * ((d12 * Height02) - (d02 * Height12)); + G->dOneOverZdY = OneOverdY * ((d12 * Width02 ) - (d02 * Width12 )); + + G->dOneOverZdX = FXFL_OOZ(G->FdOneOverZdX); + G->ZScale = FXFL_Z(G->FZScale); + } + + if (Triangle.ROPFlags & TMAP) + { + G->UOverZ[0] = ((pVertices[0].u * TextureWidth )+ 0.5f); + G->VOverZ[0] = ((pVertices[0].v * TextureHeight)+ 0.5f); + G->UOverZ[1] = ((pVertices[1].u * TextureWidth )+ 0.5f); + G->VOverZ[1] = ((pVertices[1].v * TextureHeight)+ 0.5f); + G->UOverZ[2] = ((pVertices[2].u * TextureWidth )+ 0.5f); + G->VOverZ[2] = ((pVertices[2].v * TextureHeight) + 0.5f); + + if (!G->Affine) + { + G->UOverZ[0] *= G->OneOverZ[0]; + G->VOverZ[0] *= G->OneOverZ[0]; + G->UOverZ[1] *= G->OneOverZ[1]; + G->VOverZ[1] *= G->OneOverZ[1]; + G->UOverZ[2] *= G->OneOverZ[2]; + G->VOverZ[2] *= G->OneOverZ[2]; + } + + + d02 = G->UOverZ[0] - G->UOverZ[2]; + d12 = G->UOverZ[1] - G->UOverZ[2]; + G->FdUOverZdX = OneOverdX * ((d12 * Height02) - (d02 * Height12)); + G->dUOverZdY = OneOverdY * ((d12 * Width02 ) - (d02 * Width12 )); + + d02 = G->VOverZ[0] - G->VOverZ[2]; + d12 = G->VOverZ[1] - G->VOverZ[2]; + G->FdVOverZdX = OneOverdX * ((d12 * Height02) - (d02 * Height12)); + G->dVOverZdY = OneOverdY * ((d12 * Width02 ) - (d02 * Width12)); + + G->dUOverZdX = FXFL_OZ(G->FdUOverZdX); + G->dVOverZdX = FXFL_OZ(G->FdVOverZdX); + } + + + if (Triangle.ROPFlags & LSHADE) + { + // can clamp these things higher to remove more small negative overruns. + d02 = (pVertices[0].r) - (pVertices[2].r); + d12 = (pVertices[1].r) - (pVertices[2].r); + G->FdRdX = OneOverdX * ((d12 * Height02) - (d02 * Height12)); + G->dRdY = OneOverdY * ((d12 * Width02) - (d02 * Width12)); + + d02 = (pVertices[0].g) - (pVertices[2].g); + d12 = (pVertices[1].g) - (pVertices[2].g); + G->FdGdX = OneOverdX * ((d12 * Height02) - (d02 * Height12)); + G->dGdY = OneOverdY * ((d12 * Width02) - (d02 * Width12)); + + d02 = (pVertices[0].b) - (pVertices[2].b); + d12 = (pVertices[1].b) - (pVertices[2].b); + G->FdBdX = OneOverdX * ((d12 * Height02) - (d02 * Height12)); + G->dBdY = OneOverdY * ((d12 * Width02) - (d02 * Width12)); + + G->dRdX = FXFL_RGB(G->FdRdX); + G->dGdX = FXFL_RGB(G->FdGdX); + G->dBdX = FXFL_RGB(G->FdBdX); + } + + if (!G->Affine) + { + geFloat ChangeIndicator = (geFloat)fabs(G->FdOneOverZdX) + (geFloat)fabs(G->dOneOverZdY); + + if (Triangle.ROPFlags & LMAP) + { + // can maybe infer from the lightmap density what's best to do here. + G->SubSpanWidth = 16; + G->SubSpanShift = 4; + } + else + { + if ( ChangeIndicator < 0.0005f) + { + G->SubSpanWidth = 128; + G->SubSpanShift = 7; + } + else if ( ChangeIndicator < 0.001f) + { + G->SubSpanWidth = 64; + G->SubSpanShift = 6; + } + else if ( ChangeIndicator < 0.005f) + { + G->SubSpanWidth = 32; + G->SubSpanShift = 5; + } + else + { + G->SubSpanWidth = 16; + G->SubSpanShift = 4; + } + } + } + else + { + G->dOneOverZdX = OOZ_FXP_TO_16_16(G->dOneOverZdX) * Z_FXP_TO_INT(G->ZScale); + G->dUOverZdX = OZ_FXP_TO_16_16 (G->dUOverZdX); + G->dVOverZdX = OZ_FXP_TO_16_16 (G->dVOverZdX); + } + + return GE_TRUE; +} + +void GENESISCC FloorDivMod( int32 Numerator, int32 Denominator, int32 *Floor, + int32 *Mod ) +{ + assert(Denominator > 0); // we assume it's positive + if(Numerator >= 0) + { + // positive case, C is okay + *Floor = Numerator / Denominator; + *Mod = Numerator % Denominator; + } + else + { + // Numerator is negative, do the right thing + *Floor = -((-Numerator) / Denominator); + *Mod = (-Numerator) % Denominator; + if(*Mod) + { + // there is a remainder + *Floor = *Floor -1; + *Mod = Denominator - *Mod; + } + } +} + +static int32 GENESISCC Ceil28_4( int32 Value ) +{ + int32 ReturnValue; + int32 Numerator = Value - 1 + 16; + if(Numerator >= 0) + { + ReturnValue = Numerator/16; + } + else + { + // deal with negative numerators correctly + ReturnValue = -((-Numerator)/16); + ReturnValue -= ((-Numerator) % 16) ? 1 : 0; + } + return ReturnValue; +} + +void GENESISCC Triangle_EdgeCompute( + Triangle_Edge *E, + const Triangle_Gradients *Gradients, + const DRV_TLVertex *pVertices, + int Top, + int Bottom, + int IsLeftEdge) +{ + int YEnd; + int TopY,BottomY,TopX=0,BottomX; + TopY = (int32)(pVertices[Top].y * 16.0f); + BottomY = (int32)(pVertices[Bottom].y * 16.0f); + E->Y = Ceil28_4( TopY ); + YEnd = Ceil28_4( BottomY ); + E->Height = YEnd - E->Y; + + if (!E->Height) + return; + + { + int32 dN = BottomY-TopY; + if (dN > 0) + { + int32 dM,InitialNumerator; + //int32 dM = (int32)(FWidth * 16.0f); + TopX = (int32)(pVertices[Top].x * 16.0f); + BottomX = (int32)(pVertices[Bottom].x * 16.0f); + dM = BottomX - TopX; + + InitialNumerator = dM*16*E->Y - dM*TopY + dN*TopX - 1 + dN*16; + FloorDivMod(InitialNumerator,dN*16,&(E->X),&(E->ErrorTerm)); + FloorDivMod(dM*16,dN*16,&(E->XStep),&(E->Numerator)); + E->Denominator = dN*16; + } + else + { + E->XStep=0; + E->X = (int)(pVertices[Top].x); + } + } + + if (IsLeftEdge) + { + geFloat XPrestep = E->X - (geFloat)TopX * (1.0f/16.0f); + geFloat YPrestep = E->Y - (geFloat)TopY * (1.0f/16.0f); + + if (Triangle.ROPFlags & (TMAP | ZBUF)) + { + E->OneOverZ = FXFL_OOZ(Gradients->OneOverZ[Top] + YPrestep * Gradients->dOneOverZdY + XPrestep * Gradients->FdOneOverZdX); + E->OneOverZStep = FXFL_OOZ(E->XStep * Gradients->FdOneOverZdX + Gradients->dOneOverZdY); + E->dOneOverZdX = Gradients->dOneOverZdX; + } + + if (Triangle.ROPFlags & TMAP) + { + E->UOverZ = FXFL_OZ(Gradients->UOverZ[Top] + YPrestep * Gradients->dUOverZdY + XPrestep * Gradients->FdUOverZdX); + E->UOverZStep = FXFL_OZ(E->XStep * Gradients->FdUOverZdX + Gradients->dUOverZdY); + E->dUOverZdX = Gradients->dUOverZdX; + + E->VOverZ = FXFL_OZ(Gradients->VOverZ[Top] + YPrestep * Gradients->dVOverZdY + XPrestep * Gradients->FdVOverZdX); + E->VOverZStep = FXFL_OZ(E->XStep * Gradients->FdVOverZdX + Gradients->dVOverZdY); + E->dVOverZdX = Gradients->dVOverZdX; + } + + if (Triangle.ROPFlags & LSHADE) + { + E->R = FXFL_RGB( (pVertices[Top].r) + 0.5f + YPrestep * Gradients->dRdY + XPrestep * Gradients->FdRdX); + E->RStep = FXFL_RGB(E->XStep * Gradients->FdRdX + Gradients->dRdY); + E->dRdX = Gradients->dRdX; + + E->G = FXFL_RGB( (pVertices[Top].g) + 0.5f + YPrestep * Gradients->dGdY + XPrestep * Gradients->FdGdX); + E->GStep = FXFL_RGB(E->XStep * Gradients->FdGdX + Gradients->dGdY); + E->dGdX = Gradients->dGdX; + + E->B = FXFL_RGB( (pVertices[Top].b) + 0.5f + YPrestep * Gradients->dBdY + XPrestep * Gradients->FdBdX); + E->BStep = FXFL_RGB(E->XStep * Gradients->FdBdX + Gradients->dBdY); + E->dBdX = Gradients->dBdX; + } + + if (Gradients->Affine) + { + if (Triangle.ROPFlags & (TMAP | ZBUF)) + { + E->OneOverZ = OOZ_FXP_TO_16_16( E->OneOverZ ) * Z_FXP_TO_INT(Gradients->ZScale); + E->OneOverZStep = OOZ_FXP_TO_16_16( E->OneOverZStep ) * Z_FXP_TO_INT(Gradients->ZScale); + } + if (Triangle.ROPFlags & TMAP) + { + E->UOverZ = OZ_FXP_TO_16_16 ( E->UOverZ ); + E->UOverZStep = OZ_FXP_TO_16_16 ( E->UOverZStep ); + E->VOverZ = OZ_FXP_TO_16_16 ( E->VOverZ ); + E->VOverZStep = OZ_FXP_TO_16_16 ( E->VOverZStep ); + } + } + } +} + + + + diff --git a/G3D/Engine/Drivers/SoftDrv2/display.c b/G3D/Engine/Drivers/SoftDrv2/display.c new file mode 100644 index 0000000..f84f6c6 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/display.c @@ -0,0 +1,271 @@ +/****************************************************************************************/ +/* Display.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Abstracts all low-level display surfaces into a single API */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#pragma warning(disable : 4201 4214 4115) +#include +#pragma warning(default : 4201 4214 4115; disable : 4514) +#include +#include "basetype.h" +#include "display.h" +#include "DIBDisplay.h" +#include "DDRAWDisplay.h" + +#ifdef GENESIS_VERSION_2 +#include "errorlog.h" +#else +#define geErrorLog_AddString(Error,xx,yy) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Display +{ + Display_Type DisplayType; + DIBDisplay *pDIBDisplay; + DDRAWDisplay *pDDRAWDisplay; +}Display; + +#pragma message ("BitsPerPixel should be a Bitmap Format") + +void Display_GetDisplayFormat( const Display *D, + Display_Type *DisplayType, + int32 *Width, + int32 *Height, + int32 *BitsPerPixel, + uint32 *Flags) +{ + assert( D != NULL ); + assert( DisplayType != NULL ); + assert( Width != NULL ); + assert( Height != NULL ); + assert( BitsPerPixel != NULL ); + assert( Flags != NULL ); + + *DisplayType = D->DisplayType; + if (D->DisplayType == DISPLAY_DIB_WINDOW) + { + DIBDisplay_GetDisplayFormat( D->pDIBDisplay, + Width, + Height, + BitsPerPixel, + Flags); + } + else + { + DDRAWDisplay_GetDisplayFormat( D->pDDRAWDisplay, + Width, + Height, + BitsPerPixel, + Flags); + } +} + + + +geBoolean Display_GetPixelFormat ( const Display *D, + //int32 *pixel_pitch, + int32 *bytes_per_pixel, + int32 *R_shift, + uint32 *R_mask, + int32 *R_width, + int32 *G_shift, + uint32 *G_mask, + int32 *G_width, + int32 *B_shift, + uint32 *B_mask, + int32 *B_width) +{ + assert( D != NULL); + if (D->DisplayType == DISPLAY_DIB_WINDOW) + { + return DIBDisplay_GetPixelFormat( D->pDIBDisplay, + //pixel_pitch, + bytes_per_pixel, + R_shift, R_mask, R_width, + G_shift, G_mask, G_width, + B_shift, B_mask, B_width); + } + else + { + return DDRAWDisplay_GetPixelFormat( D->pDDRAWDisplay, + //pixel_pitch, + bytes_per_pixel, + R_shift, R_mask, R_width, + G_shift, G_mask, G_width, + B_shift, B_mask, B_width); + } +} + + + +geBoolean Display_Blit ( Display *D ) +{ + assert( D != NULL); + if (D->DisplayType == DISPLAY_DIB_WINDOW) + { + return DIBDisplay_Blit( D->pDIBDisplay ); + } + else + { + return DDRAWDisplay_Blit( D->pDDRAWDisplay ); + } +} + +geBoolean Display_Wipe ( Display *D, + uint32 color) +{ + assert( D != NULL); + if (D->DisplayType == DISPLAY_DIB_WINDOW) + { + return DIBDisplay_Wipe( D->pDIBDisplay, color ); + } + else + { + return DDRAWDisplay_Wipe( D->pDDRAWDisplay, color ); + } +} + +#pragma message ("should the ptr argument to Display_Lock be a uint8?") + +geBoolean Display_Lock ( Display *D, + uint8 **ptr, + int32 *pitch) +{ + assert( D != NULL); + if (D->DisplayType == DISPLAY_DIB_WINDOW) + { + return DIBDisplay_Lock( D->pDIBDisplay, ptr, pitch ); + } + else + { + return DDRAWDisplay_Lock(D->pDDRAWDisplay,ptr,pitch); + } +} + +geBoolean Display_Unlock ( Display *D ) +{ + assert( D != NULL); + if (D->DisplayType == DISPLAY_DIB_WINDOW) + { + return DIBDisplay_Unlock( D->pDIBDisplay ); + } + else + { + return DDRAWDisplay_Unlock( D->pDDRAWDisplay); + } +} + +geBoolean Display_SetActive ( Display *D, geBoolean Active ) +{ + assert( D != NULL); + if (D->DisplayType == DISPLAY_DIB_WINDOW) + { + return GE_TRUE; + } + else + { + return DDRAWDisplay_SetActive(D->pDDRAWDisplay,Active); + } +} + +void Display_Destroy ( Display **pDisplay ) +{ + Display *D; + assert( pDisplay != NULL ); + D = *pDisplay; + assert( D != NULL); + if (D->DisplayType == DISPLAY_DIB_WINDOW) + { + DIBDisplay_Destroy( &(D->pDIBDisplay) ); + D->pDIBDisplay = NULL; + } + else + { + DDRAWDisplay_Destroy( &(D->pDDRAWDisplay) ); + D->pDDRAWDisplay = NULL; + } + free( D ); + *pDisplay = NULL; +} + + +Display *Display_Create ( HWND hWindow, + Display_Type DisplayType, + int32 RenderSizeAcross, + int32 RenderSizeDown, + int32 Display_BitsPerPixel, + uint32 Flags) +{ + Display *D; + D = malloc( sizeof( Display ) ); + assert( (DisplayType == DISPLAY_DIB_WINDOW) || (DisplayType == DISPLAY_DDRAW_FULLSCREEN)); + + if (D == NULL) + { + geErrorLog_AddString(GE_ERR_MEMORY_RESOURCE,"unable to create Display object",NULL); + return NULL; + } + + D->DisplayType = DisplayType; + D->pDIBDisplay = NULL; + D->pDDRAWDisplay = NULL; + + if (D->DisplayType == DISPLAY_DIB_WINDOW) + { + D->pDIBDisplay = DIBDisplay_Create( hWindow,RenderSizeAcross,RenderSizeDown,Display_BitsPerPixel,Flags ); + if (D->pDIBDisplay == NULL) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE,"Unable to create DIBDisplay object",NULL); + free(D); + return NULL; + } + } + else + { + D->pDDRAWDisplay = DDRAWDisplay_Create( hWindow,RenderSizeAcross,RenderSizeDown,Display_BitsPerPixel,Flags ); + if (D->pDDRAWDisplay == NULL) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE,"Unable to create DDRAWDisplay object",NULL); + free(D); + return NULL; + } + } + return D; +} + + +geBoolean Display_GetDisplayInfo( Display_Type DisplayType, + char *DescriptionString, + unsigned int DescriptionStringMaxLength, + DisplayModeInfo *Info) +{ + assert( (DisplayType == DISPLAY_DIB_WINDOW) || (DisplayType == DISPLAY_DDRAW_FULLSCREEN)); + if (DisplayType == DISPLAY_DDRAW_FULLSCREEN) + { + return DDRAWDisplay_GetDisplayInfo( DescriptionString, DescriptionStringMaxLength, Info); + } + else + { + return DIBDisplay_GetDisplayInfo( DescriptionString, DescriptionStringMaxLength, Info); + } +} \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv2/display.h b/G3D/Engine/Drivers/SoftDrv2/display.h new file mode 100644 index 0000000..bbcddfa --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/display.h @@ -0,0 +1,98 @@ +/****************************************************************************************/ +/* Display.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: Abstracts all low-level display surfaces into a single API */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +// Display +// display manager +// +// manages +// DIB format window displays +// DDRAW format fullscreen displays + + +#ifndef Display_H +#define Display_H + +#include "basetype.h" +#include "DisplayModeInfo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { DISPLAY_DIB_WINDOW, DISPLAY_DDRAW_FULLSCREEN, DISPLAY_COUNT } Display_Type; + +typedef struct Display Display; + +geBoolean Display_GetDisplayInfo( Display_Type DisplayType, + char *DescriptionString, + unsigned int DescriptionStringMaxLength, + DisplayModeInfo *Info); + +geBoolean Display_GetPixelFormat ( const Display *D, + //int32 *pixel_pitch, + int32 *bytes_per_pixel, + int32 *R_shift, + uint32 *R_mask, + int32 *R_width, + int32 *G_shift, + uint32 *G_mask, + int32 *G_width, + int32 *B_shift, + uint32 *B_mask, + int32 *B_width); + +void Display_GetDisplayFormat( const Display *D, + Display_Type *DisplayType, + int32 *Width, + int32 *Height, + int32 *BitsPerPixel, + uint32 *Flags); + +geBoolean Display_Blit ( Display *D); + +geBoolean Display_Wipe ( Display *D, + uint32 color); + +geBoolean Display_Lock ( Display *D, + uint8 **ptr, + int32 *pitch); + +geBoolean Display_Unlock ( Display *D); + +void Display_Destroy ( Display **pDisplay); + +geBoolean Display_SetActive ( Display *D, geBoolean Active ); + + +#ifdef _INC_WINDOWS +Display *Display_Create ( HWND hWindow, + Display_Type DisplayType, + int32 RenderSizeAcross, + int32 RenderSizeDown, + int32 Display_BitsPerPixel, + uint32 Display_Flags); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/G3D/Engine/Drivers/SoftDrv2/mssccprj.scc b/G3D/Engine/Drivers/SoftDrv2/mssccprj.scc new file mode 100644 index 0000000..39a8f66 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/mssccprj.scc @@ -0,0 +1,4 @@ +SCC = This is a Source Code Control file + +[SoftDrv2.mak] +SCC_Project_Name = "$/Genesis10/Source/Engine/Drivers/SoftDrv2", HBDCAAAA diff --git a/G3D/Engine/Drivers/SoftDrv2/rop.h b/G3D/Engine/Drivers/SoftDrv2/rop.h new file mode 100644 index 0000000..8ef624b --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/rop.h @@ -0,0 +1,78 @@ +/****************************************************************************************/ +/* ROP.H */ +/* */ +/* Author: Mike Sandige */ +/* Description: This defines the available rops for the software driver triangle */ +/* rasterizer. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/* Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#ifndef ROP_H +#define ROP_H + +#ifdef __cplusplus +extern "C" { +#endif + + +// light = gourad,map,flat,none(fullbright) +// alpha = none, map(only with a texture), flat +typedef enum { + +//ROP ID // texture light alpha z z span span priority + // test set test set +GE_ROP_LSHADE, // | - | g | - | - | - | - | - | m +GE_ROP_LSHADE_ZSET, // | - | g | - | - | + | - | - | m +GE_ROP_LSHADE_ZTEST, // | - | g | - | + | - | - | - | m +GE_ROP_LSHADE_ZTESTSET, // | - | g | - | + | + | - | - | h +GE_ROP_LSHADE_AFLAT, // | - | g | f | - | - | - | - | l +GE_ROP_LSHADE_AFLAT_ZSET, // | - | g | f | - | + | - | - | l +GE_ROP_LSHADE_AFLAT_ZTEST, // | - | g | f | + | - | - | - | l +GE_ROP_LSHADE_AFLAT_ZTESTSET, // | - | g | f | + | + | - | - | l +GE_ROP_TMAP_LSHADE, // | + | g | - | - | - | - | - | m +GE_ROP_TMAP_LSHADE_ZSET, // | + | g | - | - | + | - | - | m +GE_ROP_TMAP_LSHADE_ZTEST, // | + | g | - | + | - | - | - | m +GE_ROP_TMAP_LSHADE_ZTESTSET, // | + | g | - | + | + | - | - | h +GE_ROP_TMAP_LMAP_ZSET_SBUF, // | + | m | - | - | + | + | + | h +GE_ROP_TMAP_LSHADE_ZSET_SBUF, // | + | g | - | - | + | + | + | h +GE_ROP_TMAP_LMAP_ZTESTSET, // | + | m | - | + | + | - | - | h +GE_ROP_TMAP_LSHADE_AFLAT, // | + | g | f | - | - | - | - | l +GE_ROP_TMAP_LSHADE_AFLAT_ZSET, // | + | g | f | - | + | - | - | l +GE_ROP_TMAP_LSHADE_AFLAT_ZTEST, // | + | g | f | + | - | - | - | l +GE_ROP_TMAP_LSHADE_AFLAT_ZTESTSET, // | + | g | f | + | + | - | - | l +GE_ROP_TMAP_LSHADE_AMAP, // | + | g | m | - | - | - | - | m +GE_ROP_TMAP_LSHADE_AMAP_ZSET, // | + | g | m | - | + | - | - | m +GE_ROP_TMAP_LSHADE_AMAP_ZTEST, // | + | g | m | + | - | - | - | m +GE_ROP_TMAP_LSHADE_AMAP_ZTESTSET, // | + | g | m | + | + | - | - | m +GE_ROP_TMAP_LMAP_AMAP, // | + | m | m | - | - | - | - | l +GE_ROP_TMAP_LMAP_AMAP_ZSET, // | + | m | m | - | + | - | - | l +GE_ROP_TMAP_LMAP_AMAP_ZTEST, // | + | m | m | + | - | - | - | l +GE_ROP_TMAP_LMAP_AMAP_ZTESTSET, // | + | m | m | + | + | - | - | l +GE_ROP_TMAP_LMAP_AFLAT_ZTESTSET, // | + | m | f | + | + | - | - | h +GE_ROP_TMAP_LSHADE_AMAP_AFLAT, // | + | g | mf | - | - | - | - | m +GE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZSET, // | + | g | mf | - | + | - | - | m +GE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZTEST, // | + | g | mf | + | - | - | - | m +GE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZTESTSET, // | + | g | mf | + | + | - | - | m +GE_ROP_END, +} geROP; + + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/G3D/Engine/Drivers/SoftDrv2/softdrv.c b/G3D/Engine/Drivers/SoftDrv2/softdrv.c new file mode 100644 index 0000000..5395645 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/softdrv.c @@ -0,0 +1,1089 @@ +/****************************************************************************************/ +/* SoftDrv.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: This is the API layer for the genesis software driver. */ +/* */ +/* Copyright (c)1999, WildTangent, Inc. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#pragma warning(disable : 4201 4214 4115) +#include +#pragma warning(default : 4201 4214 4115; disable : 4514 4244) +#include +#include + +#include "SoftDrv.h" +#include "CPUInfo.h" +#include "DCommon.h" +#include "SpanBuffer.h" +#include "Span.h" +#include "ram.h" + +#include "SWTHandle.h" +#include "Display.h" +#include "TRaster.h" +#include "DrawDecal.h" + +#ifdef GENESIS_VERSION_2 +#include "errorlog.h" +#else +#define geErrorLog_AddString(Error,xx,yy) +#endif + +//#define SOFTDRV_MAX_SPANS 10000 +#define SOFTDRV_MAX_AVG_SPANS_PER_LINE (22) + +#define SOFTDRV_DESCRIPTION_LENGTH 256 +typedef struct +{ + char Description[SOFTDRV_DESCRIPTION_LENGTH]; + Display_Type DisplayType; + DisplayModeInfo *Info; +} SoftDrv_DisplayInfo; + +typedef struct SoftDrv +{ + int RefCount; + int DisplayCount; + int CurrentDisplayIndex; + geRDriver_THandle DrawBuffer; + geRDriver_THandle ZBuffer; + SoftDrv_DisplayInfo Display[DISPLAY_COUNT]; +} SoftDrv; + +static SoftDrv SoftDrv_Internals={GE_FALSE}; + + +int32 RenderMode = RENDER_NONE; +DRV_Window ClientWindow ={ 0 }; +Display *SD_Display = NULL; +geBoolean SD_ProcessorHas3DNow; +geBoolean SD_ProcessorHasMMX; +geBoolean SD_DIBDisplayMode = GE_FALSE; +geBoolean SD_Active = FALSE; +DRV_EngineSettings SD_EngineSettings= + { // to conform to DRV_Driver structure. + /*CanSupportFlags*/ (DRV_SUPPORT_ALPHA|DRV_SUPPORT_COLORKEY), + /*PreferenceFlags*/ (DRV_PREFERENCE_NO_MIRRORS | DRV_PREFERENCE_DRAW_WALPHA_IN_BSP) + }; + +DRV_CacheInfo SoftDrv_CacheInfo; + +S32 LastError; +char LastErrorStr[200]; + +void SoftDrv_LightMapSetupCallback(TRaster_Lightmap *LM); + +void SoftDrv_ClearZBuffer(DRV_Window *Window) +{ + int32 ZBSize; + + ZBSize = (Window->Width*Window->Height)<<1; + + +#pragma message ("clear z buffer to biggest z. was 0.") + memset(SoftDrv_Internals.ZBuffer.BitPtr[0], 0xFF, ZBSize); + +} + + +static void SoftDrv_DisplayInfoTable_Destroy( SoftDrv *S ) +{ + int i; + + S->RefCount--; + if (S->RefCount>0) + return; + + for (i=0; iDisplayCount; i++) + { + if (S->Display[i].Info != NULL) + { + DisplayModeInfo_Destroy( &(S->Display[i].Info) ); + S->Display[i].Info=NULL; + } + } + S->DisplayCount = 0; +} + +static geBoolean SoftDrv_DisplayInfoTable_Create( SoftDrv *S, geBoolean FillOutModes) +{ + char VersionString[SOFTDRV_DESCRIPTION_LENGTH]="v"DRV_VMAJS"."DRV_VMINS"."; + int i; + FillOutModes; // avoid unreference parameter warning + + assert( S != NULL ); + if (S->RefCount>0) + { + S->RefCount++; + return GE_TRUE; + } + else + S->RefCount=1; + + + S->DisplayCount = 0; + for (i=0; iDisplay[i].Info = DisplayModeInfo_Create(); + if (S->Display[i].Info == NULL) + { + SoftDrv_DisplayInfoTable_Destroy( S ); + geErrorLog_AddString(GE_ERR_MEMORY_RESOURCE,"SoftDrv_DisplayInfoTableCreate: unable to create table",NULL); + return GE_FALSE; + } + if (Display_GetDisplayInfo( i, + S->Display[i].Description, + SOFTDRV_DESCRIPTION_LENGTH-strlen(VersionString), + S->Display[i].Info) == GE_FALSE) + { + DisplayModeInfo_Destroy( &(S->Display[i].Info) ); + geErrorLog_AddString(GE_ERR_MEMORY_RESOURCE,"SoftDrv_DisplayInfoTableCreate: problem filling table. (continuing)",NULL); + S->Display[i].Info=NULL; + } + else + { + strcat(S->Display[i].Description,VersionString); + S->Display[i].DisplayType = i; + S->DisplayCount++; + } + } + return GE_TRUE; +} + +geBoolean DRIVERCC SoftDrv_SetActive(geBoolean Active) +{ + SD_Active = Active; + Display_SetActive(SD_Display,Active); + return TRUE; +} + + + +geBoolean DRIVERCC SoftDrv_Init(DRV_DriverHook *Hook) +{ + // hook->width, hook->height are ignored... + uint16 *ZBuffer=NULL; + + #pragma message ("fix to:") //geBoolean DRIVERCC SoftDrv_Init(Hwnd, char *DriverString, int Height, int Width, int BitsPerPixel, uint32 Flags) + + if (SoftDrv_DisplayInfoTable_Create(&(SoftDrv_Internals), GE_TRUE)==GE_FALSE) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE,"SoftDrv_Init: failed to get mode info",NULL); + return FALSE; + } + + if ((Hook->Driver<0) || (Hook->Driver>=SoftDrv_Internals.DisplayCount)) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER,"SoftDrv_Init: bad driver index",NULL); + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + return FALSE; + } + + +// VInfo =&(SoftDrv->VideoModeInfo[Hook->Driver]); + //VInfo->bpp =16; + + SD_ProcessorHas3DNow = CPUInfo_TestFor3DNow(); + SD_ProcessorHasMMX = CPUInfo_TestForMMX(); + + { + int Height, Width, BitsPerPixel; + uint32 Flags; + + if (DisplayModeInfo_GetNth( SoftDrv_Internals.Display[Hook->Driver].Info, + Hook->Mode, + &Width, + &Height, + &BitsPerPixel, + &Flags ) == GE_FALSE) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER,"SoftDrv_Init: unable to get mode info: bad mode index",NULL); + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + return FALSE; + } + + SD_Display = Display_Create( Hook->hWnd, + SoftDrv_Internals.Display[Hook->Driver].DisplayType, + Width, + Height, + BitsPerPixel, + Flags); + if (SD_Display == NULL) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE, "SoftDrv_Init: Could not initialize display",NULL); + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + return FALSE; + } + + if( 1 ) + { + int32 BitsPerPixel; + Display_Type DisplayType; + uint32 Flags; + + Display_GetDisplayFormat( SD_Display, + &DisplayType, + &(ClientWindow.Width), + &(ClientWindow.Height), + &BitsPerPixel, + &Flags); + + } + + } + + if (SpanBuffer_Create(ClientWindow.Width,ClientWindow.Height, ClientWindow.Height * SOFTDRV_MAX_AVG_SPANS_PER_LINE)==GE_FALSE) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE, "SoftDrv_Init: Could not create span buffer",NULL); + Display_Destroy(&SD_Display); + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + return FALSE; + } + + if (Display_GetPixelFormat( SD_Display, + //&ClientWindow.PixelPitch, + &ClientWindow.BytesPerPixel, + &ClientWindow.R_shift, + &ClientWindow.R_mask, + &ClientWindow.R_width, + &ClientWindow.G_shift, + &ClientWindow.G_mask, + &ClientWindow.G_width, + &ClientWindow.B_shift, + &ClientWindow.B_mask, + &ClientWindow.B_width)==GE_FALSE) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE, "SoftDrv_Init: Could not get display pixel format",NULL); + Display_Destroy(&SD_Display); + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + return FALSE; + } + + { + geSpan_DestinationFormat DestFormat; + switch( ClientWindow.R_width + ClientWindow.G_width + ClientWindow.B_width ) + { + case 15: DestFormat = GE_SPAN_DESTINATION_FORMAT_555; + break; + case 16: DestFormat = GE_SPAN_DESTINATION_FORMAT_565; + break; + default: + geErrorLog_AddString(GE_ERR_BAD_PARAMETER,"SoftDrv_Init: unsupported destination format",NULL); + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + return FALSE; + } + + if (Span_SetOutputMode( DestFormat, GE_SPAN_HARDWARE_INTEL ) == GE_FALSE) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE,"SoftDrv_Init: unable to set span drawing mode",NULL); + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + return FALSE; + } + } + + + { + U32 OldFlags =0; + + ZBuffer =(U16 *)geRam_Allocate(ClientWindow.Width * ClientWindow.Height * 2); + + if(!ZBuffer) + { + geErrorLog_AddString(GE_ERR_MEMORY_RESOURCE,"SoftDrv_Init: Not enought memory for ZBuffer",NULL); + Display_Destroy(&SD_Display); + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + return FALSE; + } + + if(!VirtualProtect((U8 *)ZBuffer, + (ClientWindow.Width * ClientWindow.Height)*2, + PAGE_READWRITE | PAGE_NOCACHE, + &OldFlags)) + { + // nothing to do on failure... + } + } + +#pragma message ("set up DRV_TLHandle for display and zbuffer") + + + // assume the window is active: + SoftDrv_SetActive(GE_TRUE); + + SoftDrv_Internals.DrawBuffer.Active=1; + SoftDrv_Internals.DrawBuffer.Width = ClientWindow.Width; + SoftDrv_Internals.DrawBuffer.Height = ClientWindow.Height; + SoftDrv_Internals.DrawBuffer.MipLevels = 1; + SoftDrv_Internals.DrawBuffer.BitPtr[0] = NULL; // not locked yet. (U16 *)(ClientWindow.Buffer); + SoftDrv_Internals.DrawBuffer.PalHandle = NULL; + SoftDrv_Internals.DrawBuffer.AlphaHandle = NULL; + SoftDrv_Internals.DrawBuffer.Flags = 0; + + SoftDrv_Internals.ZBuffer.Active=1; + SoftDrv_Internals.ZBuffer.Width = ClientWindow.Width; + SoftDrv_Internals.ZBuffer.Height = ClientWindow.Height; + SoftDrv_Internals.ZBuffer.MipLevels = 1; + SoftDrv_Internals.ZBuffer.BitPtr[0] = (U16 *)(ZBuffer); + SoftDrv_Internals.ZBuffer.PalHandle = NULL; + SoftDrv_Internals.ZBuffer.AlphaHandle = NULL; + SoftDrv_Internals.ZBuffer.Flags = 0; + + TRaster_Setup(32,&(SoftDrv_Internals.DrawBuffer),&(SoftDrv_Internals.ZBuffer),SoftDrv_LightMapSetupCallback); + + return TRUE; +} + +geBoolean DRIVERCC SoftDrv_Shutdown(void) +{ + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + + if (SD_Display) + Display_Destroy(&SD_Display); + SD_Display = NULL; + + if(SoftDrv_Internals.ZBuffer.BitPtr[0]!=NULL) + geRam_Free(SoftDrv_Internals.ZBuffer.BitPtr[0]); + SoftDrv_Internals.ZBuffer.BitPtr[0]=NULL; + SpanBuffer_Destroy(); + return TRUE; +} + +geBoolean DRIVERCC SoftDrv_SetGamma(geFloat Gamma) +{ + Gamma; + return TRUE; +} + +geBoolean DRIVERCC SoftDrv_GetGamma(geFloat *Gamma) +{ + assert(Gamma); + + *Gamma = 1.0f; + + return TRUE; +} + + +geBoolean DRIVERCC SoftDrv_SetRenderWindowRect(void) +{ + return GE_TRUE; +} + + +geBoolean DRIVERCC SoftDrv_BeginScene(geBoolean Clear, geBoolean ClearZ, RECT *pWorldRect) +{ + + pWorldRect; // unused. + + if (RenderMode != RENDER_NONE) + { + geErrorLog_AddString(GE_ERR_INTERNAL_RESOURCE,"SoftDrv_BeginScene: still in a render mode",geErrorLog_IntToString(RenderMode)); + return FALSE; + } + + memset(&SoftDrv_CacheInfo, 0, sizeof(DRV_CacheInfo)); + + + if (ClearZ) + { + SoftDrv_ClearZBuffer(&ClientWindow); + } + + + if(!Display_Lock(SD_Display,&(ClientWindow.Buffer), &(ClientWindow.PixelPitch))) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE ,"SoftDrv_BeginScene: failed to lock display buffer",NULL ); + return FALSE; + } + + if (Clear) + { + if (!Display_Wipe(SD_Display,0)) + { + geErrorLog_AddString( GE_ERR_SUBSYSTEM_FAILURE,"SoftDrv_BeginScene: failed to wipe display buffer",NULL ); + return FALSE; + } + } + SoftDrv_Internals.DrawBuffer.BitPtr[0] = (U16 *)(ClientWindow.Buffer); + return TRUE; +} + + +geBoolean DRIVERCC SoftDrv_EndScene(void) +{ + assert( RenderMode == RENDER_NONE ); + + + #if 0 + // useful to examine the zbuffer + { + int i; + unsigned short *b,*z; + b = (unsigned short *)ClientWindow.Buffer; + z = (unsigned short *)ZBuffer; + for (i=ClientWindow.Height * ClientWindow.Width; i>0; i--,b++,z++) + { + *b = *z; + } + } + #endif + + if (!Display_Unlock(SD_Display)) + { + geErrorLog_AddString( GE_ERR_SUBSYSTEM_FAILURE,"SoftDrv_EndScene: failed to unlock display buffer",NULL ); + return FALSE; + } + if (!Display_Blit(SD_Display)) + { + geErrorLog_AddString( GE_ERR_SUBSYSTEM_FAILURE,"SoftDrv_EndScene: failed to blit display buffer",NULL ); + return FALSE; + } + + // SOFTDRV.NumWorldSpans = RegPixels; + // SOFTDRV.NumRenderedPolys = RGBPixels; + + return TRUE; +} + + +geBoolean DRIVERCC SoftDrv_BeginWorld(void) +{ + assert( RenderMode == RENDER_NONE ); // or RENDER_WORLD? + SpanBuffer_Clear(); + RenderMode = RENDER_WORLD; + return TRUE; +} + +geBoolean DRIVERCC SoftDrv_EndRenderMode(void) // world,mesh,models +{ + assert( RenderMode != RENDER_NONE ); + RenderMode = RENDER_NONE; + return TRUE; +} + +geBoolean DRIVERCC SoftDrv_BeginMeshes(void) +{ + assert( RenderMode == RENDER_NONE); + RenderMode = RENDER_MESHES; + return TRUE; +} + +geBoolean DRIVERCC SoftDrv_BeginModels(void) +{ + assert( RenderMode == RENDER_NONE); + RenderMode = RENDER_MODELS; + return TRUE; +} + +// this is exported so that this driver source can double as a dll or statically linked. +DllExport geBoolean DriverHook(DRV_Driver **Driver) +{ + + *Driver = &SOFTDRV; + + // Make sure the error string ptr is not null, or invalid!!! + SOFTDRV.LastErrorStr = LastErrorStr; + + + return TRUE; +} + +GENESISAPI void * geEngine_SoftwareDriver(void) +{ + return (void *)DriverHook; +} + + +geBoolean DRIVERCC SoftDrv_ScreenShot(const char *Name) +{ + Name; + return FALSE; +} + +geBoolean DRIVERCC SoftDrv_EnumSubDrivers(DRV_ENUM_DRV_CB *Cb, void *Context) +{ + int i; + + if (SoftDrv_DisplayInfoTable_Create(&(SoftDrv_Internals), GE_FALSE)==GE_FALSE) + { + geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE,"SoftDrv_EnumSubDrivers: failed to get mode info",NULL); + return FALSE; + } + + for (i=0; i=SoftDrv_Internals.DisplayCount)) + { + geErrorLog_AddString(GE_ERR_BAD_PARAMETER,"SoftDrv_EnumModes: bad driver index",NULL); + SoftDrv_DisplayInfoTable_Destroy(&(SoftDrv_Internals)); + return FALSE; + } + + + Count = DisplayModeInfo_GetModeCount( SoftDrv_Internals.Display[Driver].Info ); + + for (i=0; i= MipCount) + { + MipLevel =MipCount-1; + } + return MipLevel; +} + + +geBoolean DRIVERCC SoftDrv_RenderGouraudPoly(DRV_TLVertex *Pnts, S32 NumPoints, U32 Flags) +{ + int i; + geROP ROP; + + if(!SD_Active) + { + return GE_TRUE; + } + + assert(Pnts != NULL); + assert(NumPoints > 2); + + ROP = SoftDrv_GouraudFlagsToRop[Flags & 0xF]; + for(i=0;i < NumPoints-2;i++) + { + DRV_TLVertex Pnts2[3]; + + if ( (((Pnts[i+1].x-Pnts[0].x) * (Pnts[i+2].y-Pnts[0].y)) - ((Pnts[i+1].y-Pnts[0].y)*(Pnts[i+2].x-Pnts[0].x)))<0.0f) + { + Pnts2[0] = Pnts[i+2]; + Pnts2[1] = Pnts[i+1]; + Pnts2[2] = Pnts[0]; + } + else + { + Pnts2[0] = Pnts[0]; + Pnts2[1] = Pnts[i+1]; + Pnts2[2] = Pnts[i+2]; + } + Pnts2[0].a = Pnts[0].a; + #ifdef GENESIS_VERSION_2 + #pragma message ("temporary:") + if( Pnts2[0].x < 0 ) Pnts2[0].x = 0 ; + if( Pnts2[1].x < 0 ) Pnts2[1].x = 0 ; + if( Pnts2[2].x < 0 ) Pnts2[2].x = 0 ; + if( Pnts2[0].y < 0 ) Pnts2[0].y = 0 ; + if( Pnts2[1].y < 0 ) Pnts2[1].y = 0 ; + if( Pnts2[2].y < 0 ) Pnts2[2].y = 0 ; + + if( Pnts2[0].x >= ClientWindow.Width ) Pnts2[0].x = ClientWindow.Width-1 ; + if( Pnts2[1].x >= ClientWindow.Width ) Pnts2[1].x = ClientWindow.Width-1 ; + if( Pnts2[2].x >= ClientWindow.Width ) Pnts2[2].x = ClientWindow.Width-1 ; + if( Pnts2[0].y >= ClientWindow.Height ) Pnts2[0].y = ClientWindow.Height-1 ; + if( Pnts2[1].y >= ClientWindow.Height ) Pnts2[1].y = ClientWindow.Height-1 ; + if( Pnts2[2].y >= ClientWindow.Height ) Pnts2[2].y = ClientWindow.Height-1 ; + #else + assert( Pnts2[0].x >= 0 ) ; + assert( Pnts2[1].x >= 0 ) ; + assert( Pnts2[2].x >= 0 ) ; + assert( Pnts2[0].y >= 0 ) ; + assert( Pnts2[1].y >= 0 ) ; + assert( Pnts2[2].y >= 0 ) ; + + assert( Pnts2[0].x < ClientWindow.Width ) ; + assert( Pnts2[1].x < ClientWindow.Width ) ; + assert( Pnts2[2].x < ClientWindow.Width ) ; + assert( Pnts2[0].y < ClientWindow.Height ) ; + assert( Pnts2[1].y < ClientWindow.Height ) ; + assert( Pnts2[2].y < ClientWindow.Height ) ; + #endif + + + TRaster_Rasterize( ROP ,NULL, 0, Pnts2 ); + } + + + return GE_TRUE; +} + + // Clean this up: +DRV_LInfo *SoftDrv_TempLInfo; +DRV_TexInfo *SoftDrv_TempTexInfo; + +void SoftDrv_LightMapSetupCallback(TRaster_Lightmap *LM) +{ + geBoolean Dynamic; + SOFTDRV.SetupLightmap(SoftDrv_TempLInfo, &Dynamic); + #pragma message ("SetupLightmap callback: can it fail?") + + { + geFloat MipScale; + geFloat ShiftU,ShiftV; + geFloat ScaleU,ScaleV; + geFloat LightMapShiftU,LightMapShiftV; + + ShiftU = SoftDrv_TempTexInfo->ShiftU; + ShiftV = SoftDrv_TempTexInfo->ShiftV; + MipScale = (geFloat)( 1<MipIndex); + ScaleU = (1.0f/SoftDrv_TempTexInfo->DrawScaleU); + ScaleV = (1.0f/SoftDrv_TempTexInfo->DrawScaleV); + + LightMapShiftU = ((geFloat)(SoftDrv_TempLInfo->MinU));// - 8.0f?; + LightMapShiftV = ((geFloat)(SoftDrv_TempLInfo->MinV));// - 8.0f?; + + LM->LightMapShiftU = (ShiftU+LightMapShiftU*ScaleU)/MipScale; + LM->LightMapScaleU = (1.0f/(16.0f * /*LogSize? */ ScaleU )) * MipScale; + + LM->LightMapShiftV = (ShiftV+LightMapShiftV*ScaleV)/MipScale; + LM->LightMapScaleV = (1.0f/(16.0f * /*LogSize? */ ScaleV )) *MipScale; + + + LM->BitPtr = (unsigned short *)SoftDrv_TempLInfo->RGBLight[0]; + LM->Height = SoftDrv_TempLInfo->Height; + LM->Width = SoftDrv_TempLInfo->Width; + } + + +} + + + +geBoolean DRIVERCC SoftDrv_RenderWorldPoly( DRV_TLVertex *Pnts, + S32 NumPoints, + geRDriver_THandle *THandle, + DRV_TexInfo *TexInfo, + DRV_LInfo *LInfo, + U32 Flags) +{ + int32 i; + geROP ROP; + int MipLevel; + + if(!SD_Active) + { + return GE_TRUE; + } + + // figure out which rop. Based on lightmap, pixel format, alpha, and RenderMode. Ick. + if (RenderMode==RENDER_WORLD )//&& (THandle->PixelFormat.PixelFormat !=GE_PIXELFORMAT_16BIT_4444_ARGB)) + { + // always z set but not test. + assert( !(Flags & DRV_RENDER_ALPHA) ); + assert( !(THandle->PixelFormat.PixelFormat ==GE_PIXELFORMAT_16BIT_4444_ARGB)); + + if (LInfo) + { + ROP = GE_ROP_TMAP_LMAP_ZSET_SBUF; + } + else + { + ROP = GE_ROP_TMAP_LSHADE_ZSET_SBUF; + } + } + else + { + if (LInfo) + { + if (THandle->PixelFormat.PixelFormat ==GE_PIXELFORMAT_16BIT_4444_ARGB) + { + ROP = GE_ROP_TMAP_LMAP_AMAP_ZTESTSET; + } + else if (Flags & DRV_RENDER_ALPHA) + { + ROP = GE_ROP_TMAP_LMAP_AFLAT_ZTESTSET; + } + else + { + // assert( Pnts.a == 255.0f ); + ROP = GE_ROP_TMAP_LMAP_ZTESTSET; + } + } + else + { + if (THandle->PixelFormat.PixelFormat ==GE_PIXELFORMAT_16BIT_4444_ARGB) + { + ROP = GE_ROP_TMAP_LSHADE_AMAP_ZTESTSET; + } + else if (Flags & DRV_RENDER_ALPHA) + { + ROP = GE_ROP_TMAP_LSHADE_AFLAT_ZTESTSET; + } + else + { + // assert( Pnts.a == 255.0f ); + ROP = GE_ROP_TMAP_LSHADE_ZTESTSET; + } + } + } + + assert(THandle != NULL); + assert(Pnts != NULL); + assert(NumPoints > 2); + { + DRV_TLVertex Pnts2[3]; + geFloat OOW,OOH; + geFloat ShiftU,ShiftV,ScaleU,ScaleV; + // this scaling work can be done once at texture setup time + ShiftU = TexInfo->ShiftU; + ShiftV = TexInfo->ShiftV; + ScaleU = 1.0f/TexInfo->DrawScaleU; + ScaleV = 1.0f/TexInfo->DrawScaleV; + OOW = 1.0f / (geFloat)THandle->Width; + OOH = 1.0f / (geFloat)THandle->Height; + + SoftDrv_TempTexInfo = TexInfo; + SoftDrv_TempLInfo = LInfo; + + Pnts2[0] = Pnts[0]; + Pnts2[0].u = (Pnts2[0].u*ScaleU+ShiftU)*OOW; + Pnts2[0].v = (Pnts2[0].v*ScaleV+ShiftV)*OOH; + + MipLevel = SoftDrv_ComputeMipLevel(Pnts,TexInfo->DrawScaleU,TexInfo->DrawScaleV,THandle->MipLevels,NumPoints); + + for(i=0;i < NumPoints-2;i++) + { + // these are all wound the same way (clockwise) + Pnts2[1] = Pnts[i+1]; + Pnts2[2] = Pnts[i+2]; + Pnts2[1].u = (Pnts2[1].u*ScaleU+ShiftU)*OOW; + Pnts2[1].v = (Pnts2[1].v*ScaleV+ShiftV)*OOH; + Pnts2[2].u = (Pnts2[2].u*ScaleU+ShiftU)*OOW; + Pnts2[2].v = (Pnts2[2].v*ScaleV+ShiftV)*OOH; + #ifdef GENESIS_VERSION_2 + #pragma message ("temporary:") + if( Pnts2[0].x < 0 ) Pnts2[0].x = 0 ; + if( Pnts2[1].x < 0 ) Pnts2[1].x = 0 ; + if( Pnts2[2].x < 0 ) Pnts2[2].x = 0 ; + if( Pnts2[0].y < 0 ) Pnts2[0].y = 0 ; + if( Pnts2[1].y < 0 ) Pnts2[1].y = 0 ; + if( Pnts2[2].y < 0 ) Pnts2[2].y = 0 ; + + if( Pnts2[0].x >= ClientWindow.Width ) Pnts2[0].x = ClientWindow.Width-1 ; + if( Pnts2[1].x >= ClientWindow.Width ) Pnts2[1].x = ClientWindow.Width-1 ; + if( Pnts2[2].x >= ClientWindow.Width ) Pnts2[2].x = ClientWindow.Width-1 ; + if( Pnts2[0].y >= ClientWindow.Height ) Pnts2[0].y = ClientWindow.Height-1 ; + if( Pnts2[1].y >= ClientWindow.Height ) Pnts2[1].y = ClientWindow.Height-1 ; + if( Pnts2[2].y >= ClientWindow.Height ) Pnts2[2].y = ClientWindow.Height-1 ; + #else + assert( Pnts2[0].x >= 0 ) ; + assert( Pnts2[1].x >= 0 ) ; + assert( Pnts2[2].x >= 0 ) ; + assert( Pnts2[0].y >= 0 ) ; + assert( Pnts2[1].y >= 0 ) ; + assert( Pnts2[2].y >= 0 ) ; + + assert( Pnts2[0].x < ClientWindow.Width ) ; + assert( Pnts2[1].x < ClientWindow.Width ) ; + assert( Pnts2[2].x < ClientWindow.Width ) ; + assert( Pnts2[0].y < ClientWindow.Height ) ; + assert( Pnts2[1].y < ClientWindow.Height ) ; + assert( Pnts2[2].y < ClientWindow.Height ) ; + #endif + + TRaster_Rasterize( ROP,THandle, MipLevel, Pnts2 ); + } + } + return GE_TRUE; +} + +geBoolean DRIVERCC SoftDrv_RenderMiscTexturePoly(DRV_TLVertex *Pnts, S32 NumPoints, geRDriver_THandle *THandle, U32 Flags) +{ + int i; + geROP ROP; + int MipLevel; + + if(!SD_Active) + { + return GE_TRUE; + } + + assert(Pnts != NULL); + assert(NumPoints > 2); + ROP = SoftDrv_MiscFlagsToRop[Flags & 0xF][(THandle->PixelFormat.PixelFormat==GE_PIXELFORMAT_16BIT_4444_ARGB)?1:0]; + // message ("Automatically make a 4444 from other formats?") + + for(i=0;i < NumPoints-2;i++) + { + DRV_TLVertex Pnts2[3]; + + if ( (((Pnts[i+1].x-Pnts[0].x) * (Pnts[i+2].y-Pnts[0].y)) - ((Pnts[i+1].y-Pnts[0].y)*(Pnts[i+2].x-Pnts[0].x)))<0.0f) + { + Pnts2[0] = Pnts[i+2]; + Pnts2[1] = Pnts[i+1]; + Pnts2[2] = Pnts[0]; + } + else + { + Pnts2[0] = Pnts[0]; + Pnts2[1] = Pnts[i+1]; + Pnts2[2] = Pnts[i+2]; + } + Pnts2[0].a = Pnts[0].a; + #ifdef GENESIS_VERSION_2 + #pragma message ("temporary:") + if( Pnts2[0].x < 0 ) Pnts2[0].x = 0 ; + if( Pnts2[1].x < 0 ) Pnts2[1].x = 0 ; + if( Pnts2[2].x < 0 ) Pnts2[2].x = 0 ; + if( Pnts2[0].y < 0 ) Pnts2[0].y = 0 ; + if( Pnts2[1].y < 0 ) Pnts2[1].y = 0 ; + if( Pnts2[2].y < 0 ) Pnts2[2].y = 0 ; + + if( Pnts2[0].x >= ClientWindow.Width ) Pnts2[0].x = ClientWindow.Width-1 ; + if( Pnts2[1].x >= ClientWindow.Width ) Pnts2[1].x = ClientWindow.Width-1 ; + if( Pnts2[2].x >= ClientWindow.Width ) Pnts2[2].x = ClientWindow.Width-1 ; + if( Pnts2[0].y >= ClientWindow.Height ) Pnts2[0].y = ClientWindow.Height-1 ; + if( Pnts2[1].y >= ClientWindow.Height ) Pnts2[1].y = ClientWindow.Height-1 ; + if( Pnts2[2].y >= ClientWindow.Height ) Pnts2[2].y = ClientWindow.Height-1 ; + #else + assert( Pnts2[0].x >= 0 ) ; + assert( Pnts2[1].x >= 0 ) ; + assert( Pnts2[2].x >= 0 ) ; + assert( Pnts2[0].y >= 0 ) ; + assert( Pnts2[1].y >= 0 ) ; + assert( Pnts2[2].y >= 0 ) ; + + assert( Pnts2[0].x < ClientWindow.Width ) ; + assert( Pnts2[1].x < ClientWindow.Width ) ; + assert( Pnts2[2].x < ClientWindow.Width ) ; + assert( Pnts2[0].y < ClientWindow.Height ) ; + assert( Pnts2[1].y < ClientWindow.Height ) ; + assert( Pnts2[2].y < ClientWindow.Height ) ; + #endif + + + if (THandle->MipLevels>1) + MipLevel = SoftDrv_ComputeMipLevel(Pnts,1.0f,1.0f,THandle->MipLevels,NumPoints); + else + MipLevel =0; + TRaster_Rasterize( ROP,THandle,MipLevel, Pnts2 ); + } + + + return GE_TRUE; +} + + +geBoolean DRIVERCC SoftDrv_ResetAll(void) +{ + return SWTHandle_FreeAllTextureHandles(); +} + +geBoolean DRIVERCC SoftDrv_SetFogEnable(geBoolean Enable, geFloat r, geFloat g, geFloat b, geFloat Start, geFloat End) +{ + Enable,r,g,b,Start,End; + return GE_FALSE; +} + + +DRV_Driver SOFTDRV = +{ + "Software driver. v"DRV_VMAJS"."DRV_VMINS". Copyright 1999, WildTangent, Inc.; All Rights Reserved.", + DRV_VERSION_MAJOR, + DRV_VERSION_MINOR, + + DRV_ERROR_NONE, + NULL, + + SoftDrv_EnumSubDrivers, + SoftDrv_EnumModes, + SWTHandle_EnumPixelFormats, + + SoftDrv_Init, + SoftDrv_Shutdown, + SoftDrv_ResetAll, + SoftDrv_SetRenderWindowRect, + SoftDrv_SetActive, + + SWTHandle_CreateTexture, + SWTHandle_DestroyTexture, + + SWTHandle_LockTextureHandle, + SWTHandle_UnLockTextureHandle, + + SWTHandle_SetPalette, + SWTHandle_GetPalette, + SWTHandle_SetAlpha, + SWTHandle_GetAlpha, + + SWTHandle_GetInfo, + + SoftDrv_BeginScene, + SoftDrv_EndScene, + + SoftDrv_BeginWorld, + SoftDrv_EndRenderMode, + SoftDrv_BeginMeshes, + SoftDrv_EndRenderMode, + SoftDrv_BeginModels, + SoftDrv_EndRenderMode, + + SoftDrv_RenderGouraudPoly, + SoftDrv_RenderWorldPoly, + SoftDrv_RenderMiscTexturePoly, + + DrawDecal, + + 0,0,0, + + &SoftDrv_CacheInfo, + + SoftDrv_ScreenShot, + + SoftDrv_SetGamma, + SoftDrv_GetGamma, + SoftDrv_SetFogEnable, + + &SD_EngineSettings, + NULL, // Init to NULL, engine SHOULD set this (SetupLightmap) + NULL +}; + + + diff --git a/G3D/Engine/Drivers/SoftDrv2/span.c b/G3D/Engine/Drivers/SoftDrv2/span.c new file mode 100644 index 0000000..865c1c6 --- /dev/null +++ b/G3D/Engine/Drivers/SoftDrv2/span.c @@ -0,0 +1,471 @@ +/****************************************************************************************/ +/* Span.C */ +/* */ +/* Author: Mike Sandige */ +/* Description: Span abstracts and contains all the various ROP functions. */ +/* */ +/* The contents of this file are subject to the Genesis3D Public License */ +/* Version 1.01 (the "License"); you may not use this file except in */ +/* compliance with the License. You may obtain a copy of the License at */ +/* http://www.genesis3d.com */ +/* */ +/* Software distributed under the License is distributed on an "AS IS" */ +/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ +/* the License for the specific language governing rights and limitations */ +/* under the License. */ +/* */ +/* The Original Code is Genesis3D, released March 25, 1999. */ +/*Genesis3D Version 1.1 released November 15, 1999 */ +/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */ +/* */ +/****************************************************************************************/ +#include +#include "span.h" +#include "Triangle.h" + + +int32 URight, VRight, RRight,GRight,BRight; // Globals for optimal access and sharing + // between the lighting sampler and the rop + // span functions + +void GENESISCC Span_LightMapSample(void); + + +typedef struct +{ + geROP ROP; + + Span_DrawFunction Active; + Span_DrawFunction Function[GE_SPAN_HARDWARE_VERSIONS][GE_SPAN_DESTINATION_FORMATS]; +} Span_FunctionTableEntry; + + +void GENESISCC Span_C_TMAP_LMAP_Z1(void); + +#define SPANROP LSHADE + void GENESISCC Span_C_LSHADE_555(void) { + #include "Span_Factory.h" + } + #define SPANROP LSHADE + D565 + void GENESISCC Span_C_LSHADE_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP LSHADE + ZSET + void GENESISCC Span_C_LSHADE_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP LSHADE + ZSET + D565 + void GENESISCC Span_C_LSHADE_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP LSHADE + ZTEST + void GENESISCC Span_C_LSHADE_ZTEST_555(void) { + #include "Span_Factory.h" + } + #define SPANROP LSHADE + ZTEST + D565 + void GENESISCC Span_C_LSHADE_ZTEST_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP LSHADE + ZTEST + ZSET + void GENESISCC Span_C_LSHADE_ZTEST_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP LSHADE + ZTEST + ZSET + D565 + void GENESISCC Span_C_LSHADE_ZTEST_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP LSHADE + AFLAT + void GENESISCC Span_C_LSHADE_AFLAT_555(void) { + #include "Span_Factory.h" + } + #define SPANROP LSHADE + AFLAT + D565 + void GENESISCC Span_C_LSHADE_AFLAT_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP LSHADE + AFLAT + ZSET + void GENESISCC Span_C_LSHADE_AFLAT_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP LSHADE + AFLAT + ZSET + D565 + void GENESISCC Span_C_LSHADE_AFLAT_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP LSHADE + AFLAT + ZTEST + void GENESISCC Span_C_LSHADE_AFLAT_ZTEST_555(void) { + #include "Span_Factory.h" + } + #define SPANROP LSHADE + AFLAT + ZTEST + D565 + void GENESISCC Span_C_LSHADE_AFLAT_ZTEST_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP LSHADE + AFLAT + ZTEST + ZSET + void GENESISCC Span_C_LSHADE_AFLAT_ZTEST_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP LSHADE + AFLAT + ZTEST + ZSET + D565 + void GENESISCC Span_C_LSHADE_AFLAT_ZTEST_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + void GENESISCC Span_C_TMAP_LSHADE_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + D565 + void GENESISCC Span_C_TMAP_LSHADE_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + ZSET + void GENESISCC Span_C_TMAP_LSHADE_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + ZSET + D565 + void GENESISCC Span_C_TMAP_LSHADE_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + ZTEST + void GENESISCC Span_C_TMAP_LSHADE_ZTEST_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + ZTEST + D565 + void GENESISCC Span_C_TMAP_LSHADE_ZTEST_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + ZTEST + ZSET + void GENESISCC Span_C_TMAP_LSHADE_ZTEST_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + ZTEST + ZSET + D565 + void GENESISCC Span_C_TMAP_LSHADE_ZTEST_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LMAP + ZSET + void GENESISCC Span_C_TMAP_LMAP_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LMAP + ZSET + D565 + void GENESISCC Span_C_TMAP_LMAP_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LMAP + ZTEST + ZSET + void GENESISCC Span_C_TMAP_LMAP_ZTEST_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LMAP + ZTEST + ZSET + D565 + void GENESISCC Span_C_TMAP_LMAP_ZTEST_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AFLAT + void GENESISCC Span_C_TMAP_LSHADE_AFLAT_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AFLAT + D565 + void GENESISCC Span_C_TMAP_LSHADE_AFLAT_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AFLAT + ZSET + void GENESISCC Span_C_TMAP_LSHADE_AFLAT_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AFLAT + ZSET + D565 + void GENESISCC Span_C_TMAP_LSHADE_AFLAT_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AFLAT + ZTEST + void GENESISCC Span_C_TMAP_LSHADE_AFLAT_ZTEST_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AFLAT + ZTEST + D565 + void GENESISCC Span_C_TMAP_LSHADE_AFLAT_ZTEST_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AFLAT + ZTEST + ZSET + void GENESISCC Span_C_TMAP_LSHADE_AFLAT_ZTEST_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AFLAT + ZTEST + ZSET + D565 + void GENESISCC Span_C_TMAP_LSHADE_AFLAT_ZTEST_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AMAP + void GENESISCC Span_C_TMAP_LSHADE_AMAP_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AMAP + D565 + void GENESISCC Span_C_TMAP_LSHADE_AMAP_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AMAP + ZSET + void GENESISCC Span_C_TMAP_LSHADE_AMAP_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AMAP + ZSET + D565 + void GENESISCC Span_C_TMAP_LSHADE_AMAP_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AMAP + ZTEST + void GENESISCC Span_C_TMAP_LSHADE_AMAP_ZTEST_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AMAP + ZTEST + D565 + void GENESISCC Span_C_TMAP_LSHADE_AMAP_ZTEST_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AMAP + ZTEST + ZSET + void GENESISCC Span_C_TMAP_LSHADE_AMAP_ZTEST_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AMAP + ZTEST + ZSET + D565 + void GENESISCC Span_C_TMAP_LSHADE_AMAP_ZTEST_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LMAP + AMAP + void GENESISCC Span_C_TMAP_LMAP_AMAP_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LMAP + AMAP + D565 + void GENESISCC Span_C_TMAP_LMAP_AMAP_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LMAP + AMAP + ZSET + void GENESISCC Span_C_TMAP_LMAP_AMAP_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LMAP + AMAP + ZSET + D565 + void GENESISCC Span_C_TMAP_LMAP_AMAP_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LMAP + AMAP + ZTEST + void GENESISCC Span_C_TMAP_LMAP_AMAP_ZTEST_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LMAP + AMAP + ZTEST + D565 + void GENESISCC Span_C_TMAP_LMAP_AMAP_ZTEST_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LMAP + AMAP + ZTEST + ZSET + void GENESISCC Span_C_TMAP_LMAP_AMAP_ZTEST_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LMAP + AMAP + ZTEST + ZSET + D565 + void GENESISCC Span_C_TMAP_LMAP_AMAP_ZTEST_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LMAP + AFLAT + ZTEST + ZSET + void GENESISCC Span_C_TMAP_LMAP_AFLAT_ZTEST_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LMAP + AFLAT + ZTEST + ZSET + D565 + void GENESISCC Span_C_TMAP_LMAP_AFLAT_ZTEST_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AMAP + AFLAT + void GENESISCC Span_C_TMAP_LSHADE_AMAP_AFLAT_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AMAP + AFLAT + D565 + void GENESISCC Span_C_TMAP_LSHADE_AMAP_AFLAT_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AMAP + AFLAT + ZSET + void GENESISCC Span_C_TMAP_LSHADE_AMAP_AFLAT_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AMAP + AFLAT + ZSET + D565 + void GENESISCC Span_C_TMAP_LSHADE_AMAP_AFLAT_ZSET_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AMAP + AFLAT + ZTEST + void GENESISCC Span_C_TMAP_LSHADE_AMAP_AFLAT_ZTEST_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AMAP + AFLAT + ZTEST + D565 + void GENESISCC Span_C_TMAP_LSHADE_AMAP_AFLAT_ZTEST_565(void) { + #include "Span_Factory.h" + } + +#define SPANROP TMAP + LSHADE + AMAP + AFLAT + ZTEST + ZSET + void GENESISCC Span_C_TMAP_LSHADE_AMAP_AFLAT_ZTEST_ZSET_555(void) { + #include "Span_Factory.h" + } + #define SPANROP TMAP + LSHADE + AMAP + AFLAT + ZTEST + ZSET + D565 + void GENESISCC Span_C_TMAP_LSHADE_AMAP_AFLAT_ZTEST_ZSET_565(void) { + #include "Span_Factory.h" + } + + +Span_FunctionTableEntry Span_FunctionTable[GE_ROP_END] = +{//ROP ID +{GE_ROP_LSHADE, NULL,{{Span_C_LSHADE_555,Span_C_LSHADE_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_LSHADE_ZSET, NULL,{{Span_C_LSHADE_ZSET_555,Span_C_LSHADE_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_LSHADE_ZTEST, NULL,{{Span_C_LSHADE_ZTEST_555,Span_C_LSHADE_ZTEST_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_LSHADE_ZTESTSET, NULL,{{Span_C_LSHADE_ZTEST_ZSET_555,Span_C_LSHADE_ZTEST_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_LSHADE_AFLAT, NULL,{{Span_C_LSHADE_AFLAT_555,Span_C_LSHADE_AFLAT_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_LSHADE_AFLAT_ZSET, NULL,{{Span_C_LSHADE_AFLAT_ZSET_555,Span_C_LSHADE_AFLAT_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_LSHADE_AFLAT_ZTEST, NULL,{{Span_C_LSHADE_AFLAT_ZTEST_555,Span_C_LSHADE_AFLAT_ZTEST_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_LSHADE_AFLAT_ZTESTSET, NULL,{{Span_C_LSHADE_AFLAT_ZTEST_ZSET_555,Span_C_LSHADE_AFLAT_ZTEST_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE, NULL,{{Span_C_TMAP_LSHADE_555,Span_C_TMAP_LSHADE_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_ZSET, NULL,{{Span_C_TMAP_LSHADE_ZSET_555,Span_C_TMAP_LSHADE_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_ZTEST, NULL,{{Span_C_TMAP_LSHADE_ZTEST_555,Span_C_TMAP_LSHADE_ZTEST_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_ZTESTSET, NULL,{{Span_C_TMAP_LSHADE_ZTEST_ZSET_555,Span_C_TMAP_LSHADE_ZTEST_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LMAP_ZSET_SBUF, NULL,{{Span_C_TMAP_LMAP_ZSET_555,Span_C_TMAP_LMAP_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_ZSET_SBUF, NULL,{{Span_C_TMAP_LSHADE_ZSET_555,Span_C_TMAP_LSHADE_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LMAP_ZTESTSET, NULL,{{Span_C_TMAP_LMAP_ZTEST_ZSET_555,Span_C_TMAP_LMAP_ZTEST_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AFLAT, NULL,{{Span_C_TMAP_LSHADE_AFLAT_555,Span_C_TMAP_LSHADE_AFLAT_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AFLAT_ZSET, NULL,{{Span_C_TMAP_LSHADE_AFLAT_ZSET_555,Span_C_TMAP_LSHADE_AFLAT_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AFLAT_ZTEST, NULL,{{Span_C_TMAP_LSHADE_AFLAT_ZTEST_555,Span_C_TMAP_LSHADE_AFLAT_ZTEST_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AFLAT_ZTESTSET, NULL,{{Span_C_TMAP_LSHADE_AFLAT_ZTEST_ZSET_555,Span_C_TMAP_LSHADE_AFLAT_ZTEST_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AMAP, NULL,{{Span_C_TMAP_LSHADE_AMAP_555,Span_C_TMAP_LSHADE_AMAP_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AMAP_ZSET, NULL,{{Span_C_TMAP_LSHADE_AMAP_ZSET_555,Span_C_TMAP_LSHADE_AMAP_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AMAP_ZTEST, NULL,{{Span_C_TMAP_LSHADE_AMAP_ZTEST_555,Span_C_TMAP_LSHADE_AMAP_ZTEST_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AMAP_ZTESTSET, NULL,{{Span_C_TMAP_LSHADE_AMAP_ZTEST_ZSET_555,Span_C_TMAP_LSHADE_AMAP_ZTEST_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LMAP_AMAP, NULL,{{Span_C_TMAP_LMAP_AMAP_555,Span_C_TMAP_LMAP_AMAP_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LMAP_AMAP_ZSET, NULL,{{Span_C_TMAP_LMAP_AMAP_ZSET_555,Span_C_TMAP_LMAP_AMAP_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LMAP_AMAP_ZTEST, NULL,{{Span_C_TMAP_LMAP_AMAP_ZTEST_555,Span_C_TMAP_LMAP_AMAP_ZTEST_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LMAP_AMAP_ZTESTSET, NULL,{{Span_C_TMAP_LMAP_AMAP_ZTEST_ZSET_555,Span_C_TMAP_LMAP_AMAP_ZTEST_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LMAP_AFLAT_ZTESTSET, NULL,{{Span_C_TMAP_LMAP_AFLAT_ZTEST_ZSET_555,Span_C_TMAP_LMAP_AFLAT_ZTEST_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AMAP_AFLAT, NULL,{{Span_C_TMAP_LSHADE_AMAP_AFLAT_555,Span_C_TMAP_LSHADE_AMAP_AFLAT_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZSET, NULL,{{Span_C_TMAP_LSHADE_AMAP_AFLAT_ZSET_555,Span_C_TMAP_LSHADE_AMAP_AFLAT_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZTEST, NULL,{{Span_C_TMAP_LSHADE_AMAP_AFLAT_ZTEST_555,Span_C_TMAP_LSHADE_AMAP_AFLAT_ZTEST_565},{NULL,NULL},{NULL,NULL}} }, +{GE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZTESTSET,NULL,{{Span_C_TMAP_LSHADE_AMAP_AFLAT_ZTEST_ZSET_555,Span_C_TMAP_LSHADE_AMAP_AFLAT_ZTEST_ZSET_565},{NULL,NULL},{NULL,NULL}} }, +}; + + +geBoolean GENESISCC Span_SetOutputMode( geSpan_DestinationFormat DestFormat, geSpan_CPU CPU) +{ + int i; + + assert( DestFormat >= 0 ); + assert( DestFormat < GE_SPAN_DESTINATION_FORMATS ); + assert( CPU >= 0 ); + assert( CPU < GE_SPAN_HARDWARE_VERSIONS ); + + for (i=0; i< GE_ROP_END; i++) + { + assert( Span_FunctionTable[i].ROP == i ); + Span_FunctionTable[i].Active = Span_FunctionTable[i].Function[GE_SPAN_HARDWARE_INTEL][DestFormat]; + if (Span_FunctionTable[i].Function[CPU][DestFormat]!=NULL) + Span_FunctionTable[i].Active = Span_FunctionTable[i].Function[CPU][DestFormat]; + } + return GE_TRUE; +} + +Span_DrawFunction GENESISCC Span_GetDrawFunction(geROP ROP) +{ + assert( ROP >= 0 ); + assert( ROP < GE_ROP_END ); + assert( Span_FunctionTable[ROP].ROP == ROP ); + assert( Span_FunctionTable[ROP].Active != NULL ); + + return Span_FunctionTable[ROP].Active; +} + + // Palette format is X B G R + // 16 bit 555 format is xRGB + #ifdef NOISE_FILTER + *(DestBits++) = (DESTPIXEL) ( (((((Color&0xFF)*R)+Triangle.RandomTable[Triangle.RandomTableIndex++])>>16)&0x7C00) + | ((((((Color&0xFF00)>>8)*G)+Triangle.RandomTable[Triangle.RandomTableIndex++])>>21)&0x3E0) + | (((((Color&0xFF0000)>>16)*B)+Triangle.RandomTable[Triangle.RandomTableIndex++])>>26) ); + #endif + + +void GENESISCC Span_LightMapSample(void) +{ // use bilinear filter to sample the lightmap + int32 LMU,LMV; + unsigned char *LM0,*LM1; + unsigned char *LM2,*LM3; + int C01,C23; + int UFract01,VFract01; + + LMU = ((URight - Triangle.LightMapShiftU)>>8) * Triangle.LightMapScaleU; + //LMU = (URight>>8)*Triangle.LightMapScaleU - Triangle.LightMapShiftU; + // Clamp LMU to stay bounded to lightmap (no tiling) + if (LMU<0) LMU=0; + if (LMU>Triangle.LightMapMaxU) LMU = Triangle.LightMapMaxU; + + LMV = ((VRight - Triangle.LightMapShiftV)>>8) * Triangle.LightMapScaleV; + //LMV = (VRight>>8)*Triangle.LightMapScaleV - Triangle.LightMapShiftV; + + // Clamp LMV to stay bounded to lightmap (no tiling) + if (LMV<0) LMV=0; + if (LMV>Triangle.LightMapMaxV) LMV = Triangle.LightMapMaxV; + + // address base corner into lightmap by LMU,LMV + LM0 = Triangle.LightMapBits + (3*(LMU>>16) + TOPDOWN_OR_BOTTOMUP((LMV>>16) * Triangle.LightMapStride)); + #pragma message ("is there a clamping problem here somewhere? see a hi-res lightmap only rendering...") + + #if 1 + // address other corners, clamping + if ((LMV>>16) < (Triangle.LightMapHeight-1)) + LM2 = LM0 + TOPDOWN_OR_BOTTOMUP(Triangle.LightMapStride); + else + LM2 = LM0; + if ((LMU>>16) < (Triangle.LightMapWidth-1)) + { + LM1 = LM0 + 3; + LM3 = LM2 + 3; + } + else + { + LM1 = LM0; + LM3 = LM2; + } + UFract01 = (LMU&0xFFFF); + VFract01 = (LMV&0xFFFF); + C01 = (*LM0) + ((( *LM1 - *LM0 ) * UFract01)>>16); + C23 = (*LM2) + ((( *LM3 - *LM2 ) * UFract01)>>16); + RRight =( C01 + ((( C23 - C01 ) * VFract01)>>16))<>16); + + LM2++; LM3++; + C23 = (*LM2) + ((( *LM3 - *LM2 ) * UFract01)>>16); + GRight =( C01 + ((( C23 - C01 ) * VFract01)>>16))<>16); + + LM2++; LM3++; + C23 = (*LM2) + ((( *LM3 - *LM2 ) * UFract01)>>16); + BRight =( C01 + ((( C23 - C01 ) * VFract01)>>16))<>OOZ_DIV_PRE_RSHIFT)]>>OOZ_MUL_PREP_RSHIFT} * {[U/z * 2^OZ_FXP_SHIFTER]>>OZ_MUL_PRE_PRSHIFT} + + U ={[(2^32)/((1/z * 2^26)>>8)]>>2} * {[U/z * 2^20]>>16} + ={[(2^32)/( 1/z * 2^18 ]>>2} * { U/z * 2^4 } + ={[ z * 2^14 ]>>2} * { U/z * 2^4 } + ={ z * 2^12 } * { U/z * 2^4 } + = (z*U/z) * 2^16 + = U * 2^16 + + + +*/ + + +#if OOZ_DIV_PREP_RSHIFT > 0 + #define OOZ_DIV_PREP(OOZ) ((OOZ)>>OOZ_DIV_PREP_RSHIFT) +#else + #define OOZ_DIV_PREP(OOZ) ((OOZ)<<(-OOZ_DIV_PREP_RSHIFT)) +#endif + +#if OZ_MUL_PREP_RSHIFT > 0 + #define OZ_MUL_PREP(OZ) ((OZ)>>OZ_MUL_PREP_RSHIFT) +#else + #define OZ_MUL_PREP(OZ) ((OZ)<<(-OZ_MUL_PREP_RSHIFT)) +#endif + +#if OOZ_MUL_PREP_RSHIFT > 0 + #define OOZ_MUL_PREP(OZ) ((OZ)>>OOZ_MUL_PREP_RSHIFT) +#else + #define OOZ_MUL_PREP(OZ) ((OZ)<<(-OOZ_MUL_PREP_RSHIFT)) +#endif + +#if (OOZ_MULTIPLY_PRECISION_BITS > 8) + #define OOZ_MUL_Z(OOZ,Z) ( ((OOZ)>>(OOZ_MULTIPLY_PRECISION_BITS-8)) * (Z) ) +#else + #define OOZ_MUL_Z(OOZ,Z) ( ((OOZ)<<(8-OOZ_MULTIPLY_PRECISION_BITS)) * (Z) ) +#endif + +#if (OOZ_MULTIPLY_PRECISION_BITS > 8) + #define GRADIENT_OOZ_MUL_Z(OOZ,Z) ( ((OOZ)>>(OOZ_FXPMULTIPLY_PRECISION_BITS-8)) * (Z) ) +#else + #define GRADIENT_OOZ_MUL_Z(OOZ,Z) ( ((OOZ)<<(8-OOZ_MULTIPLY_PRECISION_BITS)) * (Z) ) +#endif + +#if (OZ_MULTIPLY_SHIFTER <0) || (OOZ_MULTIPLY_SHIFTER<0) + error. +#endif + +#define USE_FIXED_POINT +#define DEST16BIT + +#ifdef USE_FIXED_POINT +#define FXFL int32 +#define FXFL_OOZ(XXX) ((int32)((XXX) * OOZ_FXP_MULTIPLIER)) +#define FXFL_OZ(XXX) ((int32)((XXX) * OZ_FXP_MULTIPLIER)) +#define FXFL_RGB(XXX) ((int32)((XXX) * RGB_FXP_MULTIPLIER)) +#define FXFL_Z(XXX) ((int32)((XXX) * Z_FXP_MULTIPLIER)) +#define OOZ_FXP_TO_16_16(XXX) ( (XXX)>>(OOZ_FXP_SHIFTER-16) ) +#define OZ_FXP_TO_16_16(XXX) ( (XXX)>>(OZ_FXP_SHIFTER-16) ) +#define Z_FXP_TO_INT(XXX) ( (XXX)>>Z_FXP_SHIFTER ) +#define RGB_FXP_TO_16_16(XXX) (XXX) +#else + error. +#endif + + +#define TEXTUREPIXEL unsigned char +#define LIGHTMAPPIXEL unsigned char +#ifdef DEST16BIT + #define DESTPIXEL unsigned short +#else + #define DESTPIXEL unsigned char +#endif +#define ZMAPPIXEL unsigned short +#define ALPHAMAPPIXEL unsigned short + +#define DESTPIXEL_SHIFTER (sizeof(DESTPIXEL)/2) +#ifdef USE_DIBS +#define TOPDOWN_OR_BOTTOMUP(XXX) (-(XXX)) // + for TOPDOWN, - for BOTTOMUP. +#else +#define TOPDOWN_OR_BOTTOMUP(XXX) ((XXX)) // + for TOPDOWN, - for BOTTOMUP. +#endif + +// ROP FLAGS +#define TMAP 0x1 +#define LSHADE 0x2 +#define LFLAT 0x4 +#define LMAP 0x8 +#define AFLAT 0x10 +#define AMAP 0x20 +#define ZSET 0x40 +#define ZTEST 0x80 +#define ZBUF 0x100 // any zbuffering +#define SBUF 0x200 +#define D565 0x200 // not really a rop flag, but used in generating spans + + + +#define TRASTER_SMALL_DIVIDE_TABLESIZE 129 + + + +typedef struct Triangle_Gradients +{ + geFloat OneOverZ[3]; // 1/Z per vtx (if Affine Z per vtx) Normalized! + // all Z's stored here are normalized to [0..1] see FZScale below + geFloat UOverZ[3]; // U/Z per vtx (if Affine U per vtx) + geFloat VOverZ[3]; // V/Z per vtx (if Affine V per vtx) + geFloat FdOneOverZdX; // d(1/Z)/dX (if Affine dZ/dX ) + geFloat dOneOverZdY; // d(1/Z)/dY (if Affine dZ/dY ) + geFloat FdUOverZdX; // d(U/Z)/dX (if Affine dU/dX ) + geFloat dUOverZdY; // d(U/Z)/dY (if Affine dU/dY ) + geFloat FdVOverZdX; // d(V/Z)/dX (if Affine dV/dX ) + geFloat dVOverZdY; // d(V/Z)/dY (if Affine dV/dY ) + + int SubSpanWidth; // maximum affine subdivision width for this poly (power of 2) + int SubSpanShift; // shift to divide by SubSpanLength 1< +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=D3DDrv - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "D3DDrv.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "D3DDrv.mak" CFG="D3DDrv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "D3DDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "D3DDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Genesis10/Source/Engine/Drivers/D3DDrv", DVPBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "D3DDrv - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W3 /GX /Ox /Ot /Ow /Og /Oi /Op /Ob2 /I "..\..\.." /I "..\\" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\Math" /I "..\..\..\Bitmap" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /FD /c +# SUBTRACT CPP /X /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /x /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib vfw32.lib dxguid.lib ddraw.lib d3dim.lib /nologo /dll /machine:I386 /out:"Release/WireDrv.dll" +# SUBTRACT LINK32 /nodefaultlib + +!ELSEIF "$(CFG)" == "D3DDrv - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /G5 /MTd /W3 /GX /Zi /Od /I "..\..\.." /I "..\..\..\Math" /I "..\\" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\Bitmap" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /YX /FD /GZ /c +# SUBTRACT CPP /X +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /x /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib vfw32.lib dxguid.lib ddraw.lib d3dim.lib /nologo /dll /debug /machine:I386 /out:"Debug/WireDrv.dll" /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "D3DDrv - Win32 Release" +# Name "D3DDrv - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\D3d_err.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_err.h +# End Source File +# Begin Source File + +SOURCE=.\D3d_fx.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_fx.h +# End Source File +# Begin Source File + +SOURCE=.\D3d_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3d_main.h +# End Source File +# Begin Source File + +SOURCE=.\D3dcache.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3dcache.h +# End Source File +# Begin Source File + +SOURCE=.\D3ddrv.cpp +# End Source File +# Begin Source File + +SOURCE=.\D3ddrv.h +# End Source File +# Begin Source File + +SOURCE=..\Dcommon.h +# End Source File +# Begin Source File + +SOURCE=.\DDMemMgr.c +# End Source File +# Begin Source File + +SOURCE=.\DDMemMgr.h +# End Source File +# Begin Source File + +SOURCE=.\Gspan.cpp +# End Source File +# Begin Source File + +SOURCE=.\Gspan.h +# End Source File +# Begin Source File + +SOURCE=.\Pcache.cpp +# End Source File +# Begin Source File + +SOURCE=.\Pcache.h +# End Source File +# Begin Source File + +SOURCE=.\Render.cpp +# End Source File +# Begin Source File + +SOURCE=.\Render.h +# End Source File +# Begin Source File + +SOURCE=.\Scene.cpp +# End Source File +# Begin Source File + +SOURCE=.\Scene.h +# End Source File +# Begin Source File + +SOURCE=.\THandle.cpp +# End Source File +# Begin Source File + +SOURCE=.\THandle.h +# End Source File +# Begin Source File + +SOURCE=.\tpage.cpp +# End Source File +# Begin Source File + +SOURCE=.\TPage.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Libraries" + +# PROP Default_Filter "" +# End Group +# End Target +# End Project diff --git a/G3D/Engine/Drivers/WireFrame/D3DDrv.dsw b/G3D/Engine/Drivers/WireFrame/D3DDrv.dsw new file mode 100644 index 0000000..262da56 --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3DDrv.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "D3DDrv"=.\D3DDrv.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/G3D/Engine/Drivers/WireFrame/D3DDrv.mak b/G3D/Engine/Drivers/WireFrame/D3DDrv.mak new file mode 100644 index 0000000..454edfc --- /dev/null +++ b/G3D/Engine/Drivers/WireFrame/D3DDrv.mak @@ -0,0 +1,284 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on D3DDrv.dsp +!IF "$(CFG)" == "" +CFG=D3DDrv - Win32 Debug +!MESSAGE No configuration specified. Defaulting to D3DDrv - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "D3DDrv - Win32 Release" && "$(CFG)" != "D3DDrv - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "D3DDrv.mak" CFG="D3DDrv - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "D3DDrv - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "D3DDrv - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "D3DDrv - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +ALL : "$(OUTDIR)\D3DDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\D3d_err.obj" + -@erase "$(INTDIR)\D3d_fx.obj" + -@erase "$(INTDIR)\D3d_main.obj" + -@erase "$(INTDIR)\D3dcache.obj" + -@erase "$(INTDIR)\D3ddrv.obj" + -@erase "$(INTDIR)\DDMemMgr.obj" + -@erase "$(INTDIR)\Gspan.obj" + -@erase "$(INTDIR)\Pcache.obj" + -@erase "$(INTDIR)\Render.obj" + -@erase "$(INTDIR)\Scene.obj" + -@erase "$(INTDIR)\THandle.obj" + -@erase "$(INTDIR)\tpage.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\D3DDrv.dll" + -@erase "$(OUTDIR)\D3DDrv.exp" + -@erase "$(OUTDIR)\D3DDrv.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MT /W3 /GX /O2 /X /I "..\..\.." /I "..\..\..\..\SdkDx6Sdk\Include" /I "..\\" /I "..\..\..\..\Sdk\Dx6Sdk\Include" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\Math" /I "..\..\..\Bitmap" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /Fp"$(INTDIR)\D3DDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\D3DDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:no /pdb:"$(OUTDIR)\D3DDrv.pdb" /machine:I386 /nodefaultlib /out:"$(OUTDIR)\D3DDrv.dll" /implib:"$(OUTDIR)\D3DDrv.lib" +LINK32_OBJS= \ + "$(INTDIR)\D3d_err.obj" \ + "$(INTDIR)\D3d_fx.obj" \ + "$(INTDIR)\D3d_main.obj" \ + "$(INTDIR)\D3dcache.obj" \ + "$(INTDIR)\D3ddrv.obj" \ + "$(INTDIR)\DDMemMgr.obj" \ + "$(INTDIR)\Gspan.obj" \ + "$(INTDIR)\Pcache.obj" \ + "$(INTDIR)\Render.obj" \ + "$(INTDIR)\Scene.obj" \ + "$(INTDIR)\THandle.obj" \ + "$(INTDIR)\tpage.obj" \ + "..\..\..\..\MSDev60\lib\Wininet.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmt.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\dxguid.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\ddraw.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\d3dim.lib" + +"$(OUTDIR)\D3DDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "D3DDrv - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\D3DDrv.dll" + + +CLEAN : + -@erase "$(INTDIR)\D3d_err.obj" + -@erase "$(INTDIR)\D3d_fx.obj" + -@erase "$(INTDIR)\D3d_main.obj" + -@erase "$(INTDIR)\D3dcache.obj" + -@erase "$(INTDIR)\D3ddrv.obj" + -@erase "$(INTDIR)\DDMemMgr.obj" + -@erase "$(INTDIR)\Gspan.obj" + -@erase "$(INTDIR)\Pcache.obj" + -@erase "$(INTDIR)\Render.obj" + -@erase "$(INTDIR)\Scene.obj" + -@erase "$(INTDIR)\THandle.obj" + -@erase "$(INTDIR)\tpage.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\D3DDrv.dll" + -@erase "$(OUTDIR)\D3DDrv.exp" + -@erase "$(OUTDIR)\D3DDrv.ilk" + -@erase "$(OUTDIR)\D3DDrv.lib" + -@erase "$(OUTDIR)\D3DDrv.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MTd /W3 /GX /Zi /Od /X /I "..\..\.." /I "..\..\..\Math" /I "..\\" /I "..\..\..\..\Sdk\Dx6Sdk\Include" /I "..\D3DDrv" /I "..\..\..\Support" /I "..\..\..\..\MsDev60\Include" /I "..\..\..\Bitmap" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "D3DDRV_EXPORTS" /Fp"$(INTDIR)\D3DDrv.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\D3DDrv.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=/nologo /dll /incremental:yes /pdb:"$(OUTDIR)\D3DDrv.pdb" /debug /machine:I386 /nodefaultlib /out:"$(OUTDIR)\D3DDrv.dll" /implib:"$(OUTDIR)\D3DDrv.lib" /pdbtype:sept +LINK32_OBJS= \ + "$(INTDIR)\D3d_err.obj" \ + "$(INTDIR)\D3d_fx.obj" \ + "$(INTDIR)\D3d_main.obj" \ + "$(INTDIR)\D3dcache.obj" \ + "$(INTDIR)\D3ddrv.obj" \ + "$(INTDIR)\DDMemMgr.obj" \ + "$(INTDIR)\Gspan.obj" \ + "$(INTDIR)\Pcache.obj" \ + "$(INTDIR)\Render.obj" \ + "$(INTDIR)\Scene.obj" \ + "$(INTDIR)\THandle.obj" \ + "$(INTDIR)\tpage.obj" \ + "..\..\..\..\MSDev60\lib\Wininet.lib" \ + "..\..\..\..\MSDev60\lib\Comdlg32.lib" \ + "..\..\..\..\MSDev60\lib\Gdi32.lib" \ + "..\..\..\..\MSDev60\lib\Kernel32.lib" \ + "..\..\..\..\MSDev60\lib\Libcmtd.lib" \ + "..\..\..\..\MSDev60\lib\Oldnames.lib" \ + "..\..\..\..\MSDev60\lib\Shell32.lib" \ + "..\..\..\..\MSDev60\lib\User32.lib" \ + "..\..\..\..\MSDev60\lib\Uuid.lib" \ + "..\..\..\..\MSDev60\lib\Advapi32.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\dxguid.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\ddraw.lib" \ + "..\..\..\..\Sdk\Dx6sdk\Lib\d3dim.lib" + +"$(OUTDIR)\D3DDrv.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("D3DDrv.dep") +!INCLUDE "D3DDrv.dep" +!ELSE +!MESSAGE Warning: cannot find "D3DDrv.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "D3DDrv - Win32 Release" || "$(CFG)" == "D3DDrv - Win32 Debug" +SOURCE=.\D3d_err.cpp + +"$(INTDIR)\D3d_err.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3d_fx.cpp + +"$(INTDIR)\D3d_fx.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3d_main.cpp + +"$(INTDIR)\D3d_main.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3dcache.cpp + +"$(INTDIR)\D3dcache.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\D3ddrv.cpp + +"$(INTDIR)\D3ddrv.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\DDMemMgr.c + +"$(INTDIR)\DDMemMgr.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Gspan.cpp + +"$(INTDIR)\Gspan.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Pcache.cpp + +"$(INTDIR)\Pcache.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Render.cpp + +"$(INTDIR)\Render.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\Scene.cpp + +"$(INTDIR)\Scene.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\THandle.cpp + +"$(INTDIR)\THandle.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\tpage.cpp + +"$(INTDIR)\tpage.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/G3D/Engine/Drivers/WireFrame/D3DDrv.ncb b/G3D/Engine/Drivers/WireFrame/D3DDrv.ncb new file mode 100644 index 0000000000000000000000000000000000000000..38431d254581ee0b63039b4f270efbbe23b7520b GIT binary patch literal 377856 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�Vm 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 Q6k4Fr0)-a%AGN@L0SGP%#sB~S literal 0 HcmV?d00001 diff --git a/G3D/Engine/Drivers/WireFrame/D3DDrv.opt b/G3D/Engine/Drivers/WireFrame/D3DDrv.opt new file mode 100644 index 0000000000000000000000000000000000000000..c952d50c6f892e6a9a02701b88e6a8aea902f56e GIT binary patch literal 48640 zcmeHQTXWmS6$UL!k!V|yEm=;SrbX4pPGXC?Fm__qbwd&qOBJkACpm-<|xM)RittebUGGhNOXx@)+_2KaEJJzju%F(Vg-r;`A6X z@DchdJ@D<>zzze`B;56_e@DlJcK(=Rbp9B)X6fh0U0JA_6cm*K4 z^SHkXyarqV=76sO7lE$>mjJSR9rqNF1~PyGWPy1g2V4foj&K$E1)u;d0!5$%yaAMf z3P5((a9;vyz;)mTa1(eFr~_{SWcUA)%94#gPm(cm3wKA_Ko57H#_`5PV>$4EX7VlL zy}zV?AEWU{rZq%&q}!4!wIo&2B!Qk(&<_<5k` z>idA6)OBZVR++1pg(*~5)N@Itp0yf=CF+V}tO>`h*9=F@J8BapNkwti61v->)@?`i z4BMKMgJOA7t{GNxRt{ZF_DJ!IQ>)2K@r$@*>}FH7ba?@x+@Lt)2zay_vL~7?+fkhj zdBre=Jdv5J*Yb->u~w;9vxQQ^UvcEgsZ za_8i!LRFrs(Px4aGr$Zm1Iz$3zzi@0%m6dM3@`)C05h=f80a67e)Im{za_1&8~bAH z5HLu$Xz9xn@>EmRR-rk}<&&?Sm#6HuH#ZR~7E`2j_yUJ%!q8~8Ok?@}S`<#m@x-QN zq9pZO!f_Jz^4nddE9*T9o2p^mU#y{5;{IZ&Gu?$sK{N}E?r=G`rFOe5^>SJkmM*$m zS2SUDN3ULnJY#m3dM&jPlzlc{-ik{~;&Qz5#zOT*DO(A$*D^&VOWE>La7~r+K_*jN ztW<-nl17UlTgX>3L9S9QUkkI<;?4p4FzjxJC<|-BV9l|YNTqF<3m9x1-rc~O@2c`b#P)i;1 z4V6?m7i5&|JTk7Qi*-%3JTz3Y*E6NSvyv|cR{0`&5o8zgX+Kl&uf=jI7r3NOQjP0D zOlvN;SKx}usyBSYa(*!vuk?}nH{i?uIz9k|>(EEvMd`7Q55iee`H)Cz?6&hO!b@aF za%^PxPxu?{(uN)Q`xR_RI*sh2xS=cm_CBs;N8ul2M-3>+YF$2s1Gr$Zm z1Iz$3zzi@0%m6dM3@`&vHUq5xvHrJ3tYrOfU+I5?kl+dnR~8ORu?r)Z{FiHac0JW< z-GMT#{VV+T#imbY=js)^?P$WS({w%CsuxB%I!=Ytt z)aki;Vl{>xc{@CkfEqe`YE5X#9WCO%myMR#$<2|Lu`bLN+i9xaPIg1U zb9eF+aNl{QN5_d7UGiHDpUPr;sp%Tilv;7?%p#l5Cu53&E@6$%pW|EOS>Ne%Ivh;B(9_CefR8pHmR zgJ{wZ^qRKV%UhKS!}z`G_gc2s{U`V8|3UVjCVt#Mf}0{d2lPv^*N12|vSXW*87ie! z+k+@Q5|yTLnE36e28*@7e_T;Lm6r3$1;bTMqhU3LTZ^)ZLPEA4^e+SR~^9U1)O z6N9`Z)>X}uu@<~-ZjSC<7@P<^drEou@B|I3tuC9O)jvhP zgY;7{8jX6Z7;ejUjn4l50`=p0%M%UZ$VyLMehHJ2$fSEvIIjKfc*#LSJUyZJdU_wh zWH=acck6R8yb{X7g1l&Z@;p7-XmDxNJWDls3;hMx-}c`nd0s`JO{;gL=G~Ekt+z4s z`&@hvm800gKofe~=~0gl$=%_In#*`oOcA~5n%n%~M8VJ;+qG9bIdkUB{mhar9d$KO zQ$1~UCd$l4nPilCg)AlM&;F|(f%qY{7sri}o + +